GWT: How to put event in queue (equivalent to Swing invokeLater())? - java

Having the following szenario: blurring a textBox (input) writes text to my status-Box (in certain conditions), and clicking a button also writes text to the status-Box.
Now when clicking the button it will blur my textBox if it is focused and that will cause the status-Box to flicker as first the blurHandler will write its result and then the clickHandler.
As i want the result of the clickHandler to appear my idea is to let the blurHandler place an event at the end of the queue which checks whether a clickHandler has written a result before.
In Swing I would try SwingUtilities.invokeLater(Runnable).
The equivalent in GWT is said to be the Scheduler but those deferred or finally commands seems always to run after the current event and before the next.
So far i use Scheduler.scheduleFixedDelay with 100ms delay and hope it comes after the clickHanlder in each browser.
See similar problem with answer.
I think there must be a better solution for this.
How to really add an event to the end of the queue or is it impossible due to limitations of HTML?

Try:
Scheduler.get().scheduleDeferred(new Command() {
#Override
public void execute() {
.......
}
});
See
Class Scheduler

Related

Synchronous textArea.clear() followed by textArea.setText() does not clear text

When a button is clicked, I'd like to clear the textArea, do some work, then print results in the textArea, all in the same method, synchronously.
public void resetClicked(MouseEvent mouseEvent) {
textArea.clear();
String result = someSynchronousWork();
textArea.setText(result);
}
What happens is, the textArea is updated, but the clear action is not visible. The work takes several seconds. If I comment out everything except the textArea.clear(), it works.
As I mention in my comment, JavaFX doesn't render the next frame until a "pulse" occurs. This won't happen when you clear the text, run a long-running task, and then set the text all in one method; the pulse happens after all this occurs which means what gets rendered is the new text. Also, running a several-seconds-long task on the JavaFX Application Thread is not a good idea. All blocking and/or long-running tasks should be done on a background thread—otherwise your GUI becomes unresponsive (and your users become unhappy/nervous).
If this task is too simple to use a Task for then you could try a CompletableFuture, which may make it easier for you to invoke simple things asynchronously.
public void resetClicked(MouseEvent event) {
event.consume();
textArea.clear();
CompletableFuture.supplyAsync(this::someSynchronousWork)
.whenCompleteAsync((result, error) -> {
if (error != null) {
// notify user
} else {
textArea.setText(result);
}
}, Platform::runLater);
}
Depending on how you want to handle errors, you can do different things. For instance:
// can't ever be an error
supplyAsync(this::someSynchronousWork)
.thenAcceptAsync(textArea::setText, Platform::runLater);
// just want to show "Error" in text area on error
supplyAsync(this::someSynchronousWork)
.exceptionally(error -> "ERROR")
.thenAcceptAsync(textArea::setText, Platform::runLater);
Note: These examples will execute someSynchronousWork() using the common ForkJoinPool. You can customize this by passing an Executor to supplyAsync.
Note: You may want to disable some of the UI components (e.g. the button) while the task is running to prevent multiple tasks being launched at once. Enable the UI components when the task completes.
Also, you seem be using the onMouseClicked property of the Button to process actions. Consider using the onAction property instead; an onAction handler is notified for more than just mouse clicks (e.g. when the button has focus and Space or Enter is pressed).

label.setVisible(true) doesn't do anything until after process completes

I have a dialog containing several buttons. When a particular button is clicked, it's ActionListener iniates a process that takes several seconds to complete. During this time I want to provide some feedback to the user. To take a simple approach, I have a label in the dialog "Computing..." which is initially not visible. A code segment looks like this
button_OpenHoursReport.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lbl_Computing.setVisible(true);
new runAndRenderReport();
RunAndRenderReport.main(null);
lbl_Computing.setVisible(false);
}
});
The problem is, the lbl_Computing text does not become visible until the RunAndRenderReport is completed. Obviously, that's not much help to the user. Don't know where to go from here. Does this have to do with threads? If so, I could use some guidance on how to get started.
actionPerformed() is executed on the GUI-thread (EDT), so avoid executing intensive operations on it. Instead use SwingWorker.
See How SwingWorker works.
A trick which is much easier than using SwingWorker is to call paintImmediately on your label after calling setVisible(true). You should see the effects - immediately.
lbl_Computing.paintImmediately(0, 0, lbl_Computing.getWidth(), lbl_Computing.getHeight());
But SwingWorker is the way to go if you want your GUI to be responsive in other ways as well while the reporting is running.

Java Synchronization and writing in textpane

I want to write a program, which search some HTML addresses. I assume that one search will be going more than 1 minute. When I print the results to console everything is OK, but when I make a frame the results don't appear in textpane. Now I have two classes one to search and one for frame. I write the simply function in the frame class to check if adding text working:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String Txt=(String)jComboBox1.getSelectedItem();
jTextPane1.setText("");
addText(Txt);
SecondClass.find(Txt);
}
public void addText(String text){
StyledDocument doc = jTextPane1.getStyledDocument();
try{
doc.insertString(doc.getLength(), text, null);
}catch(Exception e) { System.out.println(e); }
}
And in SecondClass I write the same line to addText, but it is working only from frame class. The second problem is that if the search is going I cannot do anything in program and the text from frame class is see after search is finished. I want see text immediately after finding it like in console which is working and I want to have possibility to click this link before search is ended ( I don't implement clickable links yet and don't know how to do this). I think that I must synchronize the processes, but I don't know how to do this.
It sounds like you are doing the main downloading task on the special Swing event thread, which handles all the work for Swing components. This will prevent the GUI from responding properly.
This will happen 'by accident' if you do long-running actions within event handlers (e.g. when you press a JButton).
You need to do long-running tasks in a separate thread, then 'hand over' the data to the Swing thread to update the GUI, using SwingUtilities.invokeLater(runnable); Edited: or see Max's answer about SwingWorker.
For example, your worker thread would do something like this when it has some data ready, using an anonymous Runnable:
final String text = getText();
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
appendText(text);
}
});
where getText() just indicates some means of acquiring the downloaded text, and appendtext() is a method you will need to write to update your textpane.
Check out SwingWorker. It should help you with handling lengthy operation and managing intermediate results as well. There is a sample in this manual that illustrates use of publish() and process() methods to append intermediate text results to JTextArea.

Requesting user input from outside the GUI code, do I need Events or Action to communicate with the GUI in this case?

I'm writing a 2D polygon and physics editor, one functionality is to set a rotation limit for joints.
To use this functionality, the user clicks and drags a line between the joint points which need to receive the limit.
The logic of determining if the pick is valid happens outside of the GUI code.
If a pick is found, I wanted to pop up a JOptionPane.showInputDialog where the user can input the limit.
Thing is, if I do it directly, the program becomes unresponsive, I figure it's because of threading.
I's there a way to define an event listener the GUI can use that doesn't require an actual GUI component?
I want to send an event that also contains a reference to the target object to that component, then telling it that a valid pick has been made and user input is required, and then send the value back via a method of the target object.
I am very inexperienced with Swing.
My hunch is that I might be able to add an ActionListener to the main window, but I don't know how I could address that listener specifically.
As in, how would I need to define an Action that only gets processed by that particular listener?
If that is actually possible, of course.
So far I have only used listeners to let the GUI talk to the logic, not the other way around...
Edit:
The program becomes unresponsive the movement I call
result = JOptionPane.showInputDialog(this,"Enter Limit.");
That just breaks it. Can't even enter anything into the textbox, nor close it, etc.
I figure it's because it spawns a modal dialog that pauses some thread, and calling it from somewhere in the bowels of non GUI code is just not the thing I should do, but I'm too inexperienced to know another way...
Edit2:
I should add that I can use JOptionPane.showInputDialog without any problems if I spawn it, for example, after clicking a button or choosing a popup menu option.
In fact that's how I rename the items I am working with.
But I assume at that point, the dialog is being spawned inside the GUI thread, or this Event Dispatcher queue thing.
The problem with this though is, that this takes visible, interactive GUI components that fire that event.
What I'd like, however, is some sort of component that would spawn JOptionPane.showInputDialog just like a clicked button or context menu would, but without having to be interacted with by the user, but instead by the code.
I guess I could use invisible buttons and emulate mouseclick events, but that's pretty hacky...
Also, I tried spawning Threads and Runnables which spawned the JOptionPane.showInputDialog, but that didn't help either.
Unless I spawn the JOptionPane from a GUI source, everything stalls, and the dialog won't work.
The publisher will have a public add/remove listener, where the subscriber will add itself or be added via another channel to the EventListenerList in the publisher.
You can create your own listener interface that extends EventListener and a function to shoot an event. Below is an example:
import java.util.EventListener;
public interface MyEventListener extends EventListener {
public void myEventOccurred(MyEvent event);
}
You can then create your custom event class, "MyEvent" in the example above like:
import java.util.EventObject;
public class MyEvent extends EventObject {
// customer fields and methods here
public MyEvent(Object source) //more possible args here {
super(source);
//other things here to do what you want
}
}
Now you can have your subscriber implement MyEventListener and override the myEventOccurred(..) method.
Another approach would be to use the SwingWorker class to execute the logic of determining the pick in a dedicated thread without blocking the GUI dispatch thread, and use its callback method to execute the GUI action (open the input dialog).
See : http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
(This page has a better explanation of concept than I could write.)
It should be possible for your background thread to spawn a dialog with invokeAndWait():
final double[] result = new double[1];
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
result[0] = Double.parseDouble(
JOptionPane.showInputDialog("Enter value:"));
} catch(NumberFormatException e) {
result[0] = -1;
}
}
}
// ... do something with result[0]
Here I made the result an array just so that it can be final (accessible to the anonymous class) and also mutable.

Confusing Event Order in Java Swing Thread

i've panel which contains a text field for entering number and a submit button
sometimes new (updated) value can not be sent when i click the button (the previous value of the field is sent)
in the debug mode, i see that sometimes
AbstractButton.fireActionPerformed()
is called (which gets the value of the field at that time and then submits) by event dispatch thread before
JFormattedTextFiled.FocusLostHandler
and
JFormattedTextField.commitEdit()
(which updates the value of the field).
i think jbutton event should have never been called before the text field loses the focus and updates its value
any idea about the problem?
i'm using xp-sp2 and java 1.6.0_06-b02
As far as I know, Java makes no guarantees about the order of events (someone please correct me if I am wrong!). In any case, problems with the focusLost event seem to be normal. We naturally expect it to be processed before the focus actually shifts and events for the new control are initiated. This is not the case.
As the post by Catalina Island implies, the solution is to use "invokeLater". The code for your "submit" button should look something like this:
protected void buttonClick() {
Runnable doStuff = new Runnable() {
public void run() {
// Do whatever button processing is needed here
}
};
// Invoke later, so that any LostFocus event will have been processed first
SwingUtilities.invokeLater(doListSelection);
}
If you have many controls that do some processing, and many controls that could be losing the focus, there seems to be no "nice" solution. Frankly, this is a weakness in Swing: it should guarantee a logical order of events during a change of focus.
Sorry, I have re-read your question - I have misunderstood it previously.
I cannot tell you why the focus is not moved from the field, but we had a similar issue in our application, but with the JTable and edits were not committed to the CellRender despite that we have set all required table properties. We just had to move focus away from the table cell as the first action in our event listener
thanks for replies guys and excuse me starting the same therad in java forum (i was not aware of the rules): http://forums.sun.com/thread.jspa?threadID=5445465&tstart=0
anyway, actually i'm interested in the cause of the problem rather than the solution
there are two cases in the EventQueue
here are the events for case 1:
MouseEvent (MOUSE_RELEASED)
MouseEvent (MOUSE_CLICKED)
InvocationEvent
InvocationEvent
InvocationEvent
CausedFocusEvent (FOCUS_LOST; opposite: JButton; source: FormattedNumberField)
CausedFocusEvent (FOCUS_GAINED; opposite: FormattedNumberField; source: JButton)
InvocationEvent
MouseEvent (MOUSE_MOVED)
MouseEvent (MOUSE_EXITED)
and here are the events for case 2:
CausedFocusEvent (FOCUS_LOST; opposite: JButton; source: FormattedNumberField)
CausedFocusEvent (FOCUS_GAINED; opposite: FormattedNumberField; source: JButton)
InvocationEvent
InvocationEvent
...
MouseEvent (MOUSE_RELEASED)
MouseEvent (MOUSE_CLICKED)
InvocationEvent
InvocationEvent
...
MouseEvent (MOUSE_MOVED)
MouseEvent (MOUSE_EXITED)
maybe java does not guarantee the order of the events. if it's true it would be a common problem but it's an unusual and very rare situation. even i can't reproduce this problem in other gui panels. i wonder what may cause this problem.
When I write an event handler that does something with the value of another component, I reference it directly. If your 'LostFocus' handler must run before the contents are valid, and if we can't guarantee it will have run before the button action has started, it might be a good idea to move the code contained within the 'LostFocus' handler into a private method that can be accessed by that handler and the button action, so it can do the work itself. When 'LostFocus' eventually fires, it will be executed again, but this shouldn't matter.
I'm pretty sure the the EventQueue keeps things sequential, but I've seen the debugger change the apparent order when I forget to use invokeLater() from another thread.

Categories