JTextField keyevent handling issue - jtextfield

Doesn't .getKeyCode( ) return the key's int value? Because I have set my JTextField to listen to a keylistener, and in the keytyped method, I check what key has been pressed. Here's a snippet of my code:
JTextField jtf = new JTextField( );
jtf.addKeyListener( this );
.
.
.
public void keyTyped( KeyEvent e )
{
if( e.getKeyCode( ) == KeyEvent.VK_ENTER ) System.out.println( "pressed enter" );
}
but everytime I type enter in the JTextField, nothing happens, ie nothing prints.

maybe you should check first if you event handler is actually get called when you pressed anything... or if your event handler is able to receive KeyEvents objects, i believe the problem lies there... for it to work, the component must have focus... Java Tutorial

I think you are comparing the wrong values. e.getKeyCode() returns the key, then i guess KeyEvent.VK_ENTER is something really different.

I just figured out a better way. you should put all your key methods inside an inner class just under your main class, Put your GUI construction code in a constructor method again out side of your main method. now. have you're inner method implement the KeyListener interface, and instantiate the three abstract methods associated with said interface, you're only using the keyTyped(KeyEvent e) method. inside that method, instantiate an int variable called keyHit and assign it to e.getKeyChar(); then put an if statement that states if(keyHit == '\n') the \n will corresopnd to the ENTER key,
I tried to post a template of the code Iused to get it to work, but It was a little long to go through and indent so if you're really need it i'll send it to you via some e-mail address or something

VK_ENTER corresponds to the int value of the enter key, seeing as how it is a constant. You should be using input and action maps from the swing class to listen for the key values when the JTextField is in focus as opposed to applying a key listener to the text field and listening for one key. Because an event is created (although may or may not be handled) every time a key is pressed, you should prevent the method from running when keys that aren't the enter key are pressed. Therefore preventing runtime errors and unnecessary method calls.

You have to implement KeyListener Inteface and override the keyTyped method in your class definition to use
jtf.addKeyListener(this).
Replace the above line with
jtf.addKeyListener(new KeyAdapter(){
#Override
public void keyTyped(KeyEvent e) {
if( e.getKeyCode( ) == KeyEvent.VK_ENTER )
System.out.println( "pressed enter" );
}
});

Related

initialize value of edit method in init method of form

I want to initialize a value of an edit method inside the init method of form, i wrote this:
[Form]
public class foo extends FormRun
{
str paymTermId;
public void init()
{
CustTable custTable = CustTable::find("DE-001");
paymTermId = custTable.paymTermId;
super();
}
edit str edtpaymTermId(boolean set, str _paymTermId)
{
if (set)
{
paymTermId= _paymTermId;
}
return paymTermId ;
}
}
But when i open the form the control remains empty.
any suggestions?
I tried to reproduce the issue, but was not successful. For me, when opening the form, the control shows a value.
A possible reason why it is not working for you could be that you open the form in the wrong company. In your code, you retrieve the value to display in the control from the payment term of customer DE-001. This customer exists in company USMF in the Contoso demo data and has payment term Net10. If the form is opened in this company, the value is shown in the control. If you are in another company (e.g. DAT), no value is shown.
I see 2 things that are wrong:
You are setting the value BEFORE super(). It should be after.
You SHOULDN'T initialize the value via field, you should do it calling edit method. Edit methods have a boolean SET parameter which can simulate a call for setting a value.

Using CEFSharp ILifeSpanHandler interface to Handle Popups

I have an issue with handling popups. I have implemented ILifeSpanHandler and OnBeforeBrowse (amoungst others) from the IRequestHandler.
How do I know in the ILifeSpanHandler what URL is being called? I am unable to get it in either the OnAfterCreated or OnBeforePopup. Currently I see it first in OnBeforeBrowse.
I have no code as my question is a "How to". In OnBeforePopup I have checked targetUrl however it seems to be there for decoration as I have read that it is not implemented anyway. I have also looked at the browner/chromiumWebBrowser objects, browser and newBroswer seem to be nothing. One would expect in OnAfterCreated chromiumWebBrowser would return an object but it is nothing in my case.
I am testing with the following
Public Sub OnAfterCreated(chromiumWebBrowser As IWebBrowser, browser As IBrowser) Implements ILifeSpanHandler.OnAfterCreated
Try
Debug.Print(vbNewLine)
Debug.Print("OnAfterCreated")
Debug.Print(String.Concat("OnAfterCreated - MainFrame.Url "), browser.MainFrame.Url)
Debug.Print("OnAfterCreated")
Debug.Print(vbNewLine)
Catch ex As Exception
End Try
End Sub
And I have the following
Public Function OnBeforePopup(chromiumWebBrowser As IWebBrowser, browser As IBrowser, frame As IFrame, targetUrl As String, targetFrameName As String, targetDisposition As WindowOpenDisposition, userGesture As Boolean, popupFeatures As IPopupFeatures, windowInfo As IWindowInfo, browserSettings As IBrowserSettings, ByRef noJavascriptAccess As Boolean, ByRef newBrowser As IWebBrowser) As Boolean Implements ILifeSpanHandler.OnBeforePopup
Try
Debug.Print(vbNewLine)
Debug.Print("OnBeforePopup")
Debug.Print(String.Concat("OnBeforePopup - targetUrl "), targetUrl)
Debug.Print(String.Concat("OnBeforePopup - browser.MainFrame.Url "), browser.MainFrame.Url)
Debug.Print(String.Concat("OnBeforePopup - chromiumWebBrowser.Address "), chromiumWebBrowser.Address)
Debug.Print("OnBeforePopup")
Debug.Print(vbNewLine)
Catch ex As Exception
End Try
Return False
End Function
I have seen different approaches in handling popups using ILifeSpanHandler interface. One approach that I've seen also here in Stack Overflow and was accepted as the correct answer to that particular question is to return true in the OnBeforePopup implementation of ILifeSpanHandler then pass the targetURL argument to a handler that creates the popup.
This approach is very unideal because you are destroying the link between the page that actually opened the popup and the popup itself. If you access via JavaScript the opener property of the window object inside the popup you would notice that it is null. And the page that opened the popup would never know that the popup was actually opened because returning true cancels the creation.
The other approach is to let Cef create the popup and the programmer just decides whether to show the browser as a popup window or a child to control (like in tabbed browsing). This is error-free and almost ideal. But the problem with this approach is that you are not able to listen to events such as FrameLoadStart, FrameLoadEnd, AddressChanged, TitleChanged, etc.
One approach that is tagged experimental by the Cef developers is to return a new IWebBrowser instance via newWebBrowser out parameter. This has so many many side effects. The page that opened the popup would, of course, recognize the popup as his although it was not the original browser (IBrowser) that it created. The page may just ignore it like btcclicks.com and in that case, there'd be no problem. But there are websites like drops.xyz that is so particular with his stuff and will discard everything that is not originally his. So this is a problem.
So what is the correct approach?
The ChromeWebBrowser control
Now I'm going to share with you an undocumented approach in handling popups. Speaking of ChromeWebBrowser control, it is very much of help that we know how it creates the webbrowser which, in reality, it doesn't. The control just hosts the webbrowser window handle. It has a private field called managedCefBrowserAdapter (ManagedCefBrowserAdapter class) that handles the actual creation of the web browser. ChromiumWEbBrowser implements the IWebBrowserInternal that has a method OnAfterBrowserCreated with a single parameter of type IBrowser. The control then invokes browser.GetHost().GetWindowHandle() to get the actual window handle (HWND) of the webbrowser it is being hosted. It is quite good.
The problem of the ChromeWebBrowser is that it won't have a constructor that accepts an IBrowser as an argument. It only has constructor that accepts HtmlString, string and IRequestContext arguments. These control waits for the
invocation of OnHandleCreated (a base class override) where it calls the managedCefBrowserAdapter.CreateBrowser after which it waits till its implementation of IWebBrowserInternal's OnAfterBrowserCreated is invoked.
Again, what is the approach that works?
Now, this approach that actually works is a product of long series of trial and error. One caution though is that I don't know why and how it works but I know it works.
First, I did not use ChromeWebBrowser. But I copied its code omitting the part where it creates .net control. In this case, I am targeting the browser's window handle (HWND) to be host by any object that exposes a HWND. Obviously I created a class (NativeCefWebBrowser) that uses the modified code. The ChromeWebBrowser orignal constructors were still there untouched becuase they are used to the create the parent webrowser. But I added one constructor that accept the following arguments: ICefBrowserParent parent (an interface I've created and IBrowser browser that receives the browser argument in the ILifeSpanHandler's OnBeforePopup. I also added a public method AttachBrowser that has a single parameter IBrowser that recieves the IBrowser argument in the ILifeSpanHandler's OnAfterCreated. It the browser that will be kept by CefNativeWebBrowser class.
Why didn't I keep the browser instance received form ILifeSpanHandler.OnBeforePopup but used the instance received from ILifeSpanHandler.OnAfterCreated when they are the same browser instance? This is one of those parts that I don't know why. One thing I noticed is that when I called browser.GetHost().GetWindowHandle() during ILiffeSpanHandler.OnBeforePopup, the first window handle I received was the different compared to when I invoked the method during ILifeSpanHandler.OnAfterCreatd. Because of that, I store the browser instance from the latter that I passed to the NativeCefWebBrowser.AttachBrowser for its safekeeping.
In the NativeCefWebBrowser(ICefBrowserParent parent, IBrowser browser) contructor, I set the private following fields to true: browsercreated, browserinitialized (chromewebbrwoser orginal fields) and isAttachingBrowser (added private field). You don't call the ManagedCefBrowserAdapter's CreateBrowser in this contructor in instead call its OnAfterBrowserCreated passing the browser instance. You don't much in this constructor as you will wait the ILifeSpanHandler implementor to pass you the browser instance it will receive during its OnAfterCreated method. Take note that when calling the ManagedCefBrowserAdapter's OnAfterBrowserCreated method, ManagedCefBrowserAdapter will still invoke IWebBrowserInternal implementation of OnAfterBrowserCreated that when happens you have to exit immediately when isAttachingBrowser is true as the following code will no sense no more.
After calling the NativeCefWebBrowser(ICefBrowserParent, IBroser) construct, you can normally set event listeners as you will normally do.
And that's it.
The following are parts of the code that I wrote
The ICefBrowserParent interface
public interface ICefBrowserParent
{
IntPtr Handle { get; }
Size ClientSize { get; }
bool Disposing { get; }
bool IsDisposed { get; }
bool InvokeRequired { get; }
IAsyncResult BeginInvoke(Delegate d);
object Invoke(Delegate d);
event EventHandler Resize;
}
As you would notice, the methods, properties and events in this interface are already implemented by the System.Windowns.Forms.Control class. So if you implementing this from class inhering Control class, you would not need to implement this anymore. This interface is only for non-Control class.
class NativeCefWebBrowser
{
public NativeCefWebBrowser(ICefBrowserParent, IBroser)
{
requestContext = browser.GetHost().RequestContext;
this.parent = parent; // added field
HasParent = true; // IWebBrowserInternal. I don't know what's this for
mustSetBounds = true; // added field
browserCreated = true;
isAttachingBrowser = true; // added field
InitializeFieldsAndCefIfRequired();
managedCefBrowserAdapter.OnAfterBrowserCreated(browser);
}
}
ILifeSpanHandler.OnBeforePopup(..., out IWebBrowser newWebBrowser)
{
CefNativeWebBrowser b = new CefNativeWebBrowser
(
parent, // defined else where
browser
);
// Attach event handlers
b.TitleChanged...;
newWebBrowser = b;
}
ILifeSpanHandler.OnAfterCreated(...)
{
((CefNativeWebBrowser)webBrowser).AttachBrowser(browser);
}

Where to place validation code

I've created a simple form with an enum field on a grid, dragged from the DataSource CompanyImage:
Table CompanyImage has an Index on this field named Brand in my example and AllowDuplicates is set to No :
And here is the form:
I've overridden the close() method of the form like this:
public void close()
{
CompanyImage_ds.write();
super();
}
An error is displayed when I close it saying that
"Cannot create a record in CompanyImage(CompanyImage). Legal entities: Example1.
The record already exists."
That's fine but I would like a way to stop closing the window when this happens. A validateWrite() would be nice but I am not really able to figure out where and what to write in order to accomplish this behavior.
I mean, how to check that new row is added and it contains a field that already exists in the table ?
You shouldn't have to force the write() method. Closing the form should already do it.
If you wish to check something to allow the form to be closed, the close() method is too late in execution. You should leverage the canClose() method.
You could override the validate method of the grid column. You would need to write some validation logic in that method but that would prevent the column from saving at all if validation failed.
public boolean validate()
{
boolean ret;
// write your own validation logic
if (validation logic is true)
{
ret = true;
}
return ret;
}

Table Update Event Handler

I am investigating the capabilities of the new delegate & event subscription pattern in AX 2012.
At the moment I am looking to detect when a particular field has been modified, for example when SalesTable.SalesStatus is changed to SalesStatus::Invoiced.
I have created the following post-event handler and attatched to the SalesTable.Update method;
public static void SalesTable_UpdatePosteventHandler(XppPrePostArgs _args)
{
Info("Sales Update Event Handler");
}
Now I know I can get the SalesTable from the _args, but how can I detect a field has changed? I could really use a before & after version, which makes me think I am subscribing to the wrong event here.
If the update method does not update the field, you can use a pre event handler on the update method. If you want to monitor the PriceGroup field on the CustTable table then create a class called CustTableEventHandler containing this method:
public static void preUpdateHandler(XppPrePostArgs _args)
{
CustTable custTable = _args.getThis();
if (custTable.PriceGroup != custTable.orig().PriceGroup)
info(strFmt("Change price group from '%1' to '%2'", custTable.orig().PriceGroup, custTable.PriceGroup));
}
A post event handler will not work, as orig() will return the changed record.
Also if the the record is updated using doUpdate your handler is not called.
You could also override the aosValidateUpdate on CustTable, which is called even if doUpdate is used. This method is always run on the AOS server.
public boolean aosValidateUpdate()
{
boolean ret = super();
if (this.PriceGroup != this.orig().PriceGroup)
info(strFmt("Change price group from '%1' to '%2'", this.orig().PriceGroup, this.PriceGroup));
return ret;
}
Yet another option would be a global change to the Application.eventUpdate method.
From the header of the method:
Serves as a callback that is called by the kernel when a record in a
table is updated, provided that the kernel has been set up to monitor
records in that table.
A developer can set up the kernel to call back on updates for a given
table by inserting a record into the DatabaseLog kernel table with all
fields set to relevant values, which includes the field logType set to
EventUpdate. It is possible to set up that the kernel should call back
whenever a record is updated or when a specific field is updated.This
is very similar to how logUpdate is called and set up. The call
of this method will be in the transaction in which the record is
updated.
This method is used by the alert rule notification system. I would recommend against this, unless it is a global change (like alert rules).
Alert rules can be extended as described here.

silently transfer keyPressEvent to one child , and make it focus?

When user types in a QWidget based window, I wanted a QLineEdit to process
all input keys,
so I tried the following two solution in keyPressEvent() of that QWidget:
A.
void Window::keyPressEvent (QKeyEvent *e)
{
switch (e->key())
{
// handle other short cuts
default:
QApplication::sendEvent (lineEdit , e);
break;
}
}
Well, this sometimes crashes the whole interface, especially when I resize window.
B.
void Window::keyPressEvent (QKeyEvent *e)
{
switch (e->key())
{
// handle other short cuts
default:
if ( ! lineEdit.hasFocus () )
{
lineEdit.setFocus ();
lineEdit.setText (e->key());
// i wanted to push the first key input to that QLineEdit , but how ?
// or i'll miss it
}
break;
}
}
Also I'm thinking about giving lineEdit focus all the time, but I can't do that as other events needed to be handled by the main UI.
Update
It won't crash when I filter key inputs, but why ?
default:
if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ||
(e->key() >= Qt::Key_A && e->key() <= Qt::Key_Z )
)
QApplication::sendEvent(filter , e);
break;
}
I believe you are running into a crash because you are using sendEvent to send an event object that you don't have control over.
I don't think the Qt event system expects you to grab its events and throw them in other directions, and it's likely that the event object is getting destroyed before the line edit expects. In the case where you're filtering out input keys, it's probably not crashing because the line edit doesn't care about those kinds of key strokes and isn't using the event object as much as it would otherwise.
If you really want to use the sendEvent() functionality, then I would suggest you create your own QKeyEvent on the stack and pass it to the sendEvent() function (as demonstrated here), or you can just do something like this:
lineEdit.setText( lineEdit.text() + event->text() );
When a widget does not handle an event, it forwards it to its parent. So using sendEvent() to forward to a child is dangerous, as it can make a recursion.
The easiest way of doing it would be to use QKeyEvent::text instead of QKeyEvent::key and you should be OK. You might also try to create a copy of QKeyEvent and pass it to your QLineEdit. Thos are rather hacks than solutions though. If you need shortcuts in main window while QLineEdit has focus (assuming it is in this window) you can use QShortcut with Qt::WidgetWithChildrenShortcut context - this way you can keep your LineEdit active at all times.

Resources