JFrame not working after first instantiation? - java

As part of a larger application, I am writing a settings class, which collects and stores user-defined settings. This class is a singleton, and is instantiated during application startup.
In order to accept user input, two different GUI frames are insantiated from within ConfigSettings.java, from a public static method, selectSettings(). Both are subclasses of JFrame. Here is the code for the instantiation of the file selection dialog:
private void selectFile() {
SelectFileGUI fileSelector = new SelectFileGUI();
fileSelector.setVisible(true);
synchronized(this) {
try {
wait();
} catch(Exception e) {
e.printStackTrace();
}
}
fileSelector.dispose();
}
This works fine when the application is initially run. However, at a later point the user may alter their selected settings, including selecting a new source file. This is done by calling selectSettings() again.
The issue I'm having is that any subsequent attempt to instantiate and display these GUI components again results in a new JFrame being displayed, but with a grey background, and no buttons or other components shown. While debugging I was also failing to create new instances of SelectFileGUI directly.
What could be causing this sort of behaviour?

I would check to see if the second time you call it you are using the GUI thread or calling from one of your own threads.
At the top of that method you can test for it (The AWT thread is pretty easily identifiable by name) and have it throw an exception so developers know not to call it on the wrong thread--or you can block their thread and do it in a worker thread.

I don't know what is causing this behavior but in your code the following simply cannot possibly be the right way to manage dialogs (more below):
fileSelector.setVisible(true);
synchronized(this) {
try {
wait();
} catch(Exception e) {
e.printStackTrace();
}
}
fileSelector.dispose();
Do you want your dialogs to be modal or not?
If you want them to be modal, then you simply make a blocking call like when you're invoking JColorChooser.showDialog(...) method and your return "value" is your color/file/whatever.
If you want them non-modal, then you use a callback to get your color/file. In the JColorChooser dialog example, you'd call the createDialog(...) method and use the ok/cancel listeners as callbacks.
I suggest you take a look at sun's tutorial, for example the one on color chooser, to see how to correctly display a modal (or non-modal) dialog:
http://java.sun.com/docs/books/tutorial/uiswing/components/colorchooser.html
Once again, that synchronized(this) { try { wait() ... } to manage something as simple as a file selector/dialog frame just cannot be correct.

Agree with BillK: sounds like you're calling it from outside the EDT first time around (so your call to wait() doesn't block the EDT), then from the EDT the second time around. See SwingUtilities.invokeAndWait() and/or Dialog.setModal().

The consensus here is that you are breaking the rules governing the use of the AWT painting thread (the Event Dispatch Thread).
A couple things to note:
If your code attempts to paint your GUI components outside this painting thread, the gray dialog could be the result of a deadlock between the EDT and the thread your application is using to paint.
If you do get into this situation, you will experience the inability to create new dialogs as described.
However, as you mention that you are debugging while experiencing this problem, it might be that you have paused the EDT through your IDE.
Take a look at this tutorial for some guidelines on how use threads in a client application.
To fully appreciate the issue, it would be nice to see some more code - pertinent parts of selectSettings(), for example.

Related

JavaFX - update label values from other thread

Helo guys!
I am new to JavaFX. I am writing really small application which simulates working of printer. Simulation is running on special thread called PrintingProcess (this process is doing only one thing - waits given time and then increment counter). I need to send this value to window, where labels should show how many pages was "printed". Is any way to do it? So far I wrote small singleton class to hold value.
[edit] I solved it using tasks :) thanks for help
You should use the Task.updateProgress method. Call it to specify the current percentage of pages printed. Override Task.call to perform the action which needs to run in another thread. This method should never manipulate a JavaFX component. You can then oerride methods such as Task.succeeded to implement the behaviour of your UI when the print job is over. Look at the doc of this class to fully take advantage of it.
Platform.runLater(new Runnable() {
#Override public void run() {
textLabel.setText(yourValue);
}
});
The example above is quite simple. You ask JavaFX a runnable as soon as it can. I don't know how that works exactly but that's the way to change UI components from a non-JavaFX thread.
You could pass textLabel variable to any thread with a custom class or a new anonymous thread.
EDIT:
I find Dici's answer more appropriate for your application. I wouldn't recommend putting this code in any loop incase you may still use this.

SecondaryLoop in JavaFX, like Swing?

I have a Java Swing app which I'm investigating if it is even possible to port to JavaFX. The app is a development environment and simulator for an internally used scripting language. The interesting thing about it is you can set breakpoints for this scripting language and step through it, like any programmer would expect for a language.
Now because the language in the simulator is interpreted, deep within the execution of the interpreter, when it hits a breakpoint, it can pop back to the gui with a Java Swing SecondaryLoop class. So when the breakpoint is hit, it calls secondaryLoop.enter(). The gui is then active for the user to inspect variables and gui components are active. When the user hits "Continue" in the program, it calls secondaryLoop.exit() to continue execution of the interpreter. It wouldn't really be feasible for the interpreter to unwind it's entire state to go back to the primary loop, and then take up where it left off at exactly the same point. That's why the SecondaryLoop is invaluable in making it work.
Is this possible in JavaFX?
Yes, it's possible. You need to use the enterNestedEventLoop and exitNestedEventLoop methods (they are inside the com.sun.javafx.tk.Toolkit class). See this usage example:
// Make sure to import the FX Toolkit first
import com.sun.javafx.tk.Toolkit;
// This object will be used as a unique identifier to the nested loop (to
// block the execution of the thread until exitNestedEventLoop is called)
final Object loopLock = new Object();
// Simulate a long process thread (DB call, download, etc)
Thread longProcess = new Thread(new Runnable()
{
#Override
public void run()
{
// Sleep for 12 seconds to simulate a long process
try
{
Thread.sleep(12000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
// Setup a result to pass back to the enterNestedLoop() caller
String result = "Result of this long process";
// We are now done. Call exitNestedEventLoop() to unblock
// the enterNestedLoop() caller. This needs to run from
// the FX Thread so use Platform.runLater()
Runnable fxRunner = new Runnable()
{
public void run()
{
try
{
Toolkit.getToolkit().exitNestedEventLoop(loopLock,
result);
} catch (Throwable t)
{
t.printStackTrace();
}
}
};
Platform.runLater(fxRunner);
}
});
// Start that long process from the FX Thread
longProcess.start();
// The next call will block until exitNestedEventLoop is called, however
// the FX Thread will continue processing UI requests
Object result = Toolkit.getToolkit().enterNestedEventLoop(loopLock);
// Next statement will print: "Result of this long process"
System.out.println("Result is: " + result);
Now, before you use this be warned of two important things:
The com.sun.javafx.tk.Toolkit class is not part of the public API, so Oracle reserves the right of removing it without notice. I've been using it just fine from Java 7 to 8u51 so they could stay there forever, change package/names or disappear completely (unlikely).
Nested loops (and Swing's secondary loops) are great for flexibility and small applications but overusing them often comes with a price. Nesting to many loops (huge stack trace) will often cause "strange" behaviour in your applications since initial parts of your code might end up waiting four or five things ahead completely unrelated to them. I've seen FX nested loops causing "empty" exceptions in FX WebEngine executeScript() calls and duplicating keyboard preprocessing (when pairing FX+Swing) among other problems.
That said I would recommend using the javafx.concurrent.Task instead (if it makes sense). Using the Task class will require a bit more effort but I think it's the correct way of doing things and will probably save you lots of maintenance time.
For extra reference about the FX Task class see this great article: http://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm
UPDATE: enterNestedEventLoop and exitNestedEventLoop will be part of the Java 9 public API (Platform class), more info in JDK-8090865
Hope this helps!

Java MVC Where/When to get my view on EDT and how my controller do actions on EDT?

So im quite new to MVC structure.And im really confused on where/when to add my Gui part on EDT.
This is where im really confused:
public class ECPS_MVC {
//edt?
EcpsView view =new EcpsView();//shoud i put it on edt here?? SwingUtilities... etc
//edt?
EcpsModel model =new EcpsModel();
EcpsController controler=new EcpsController(view,model);
}
I have seen question on how to start gui on edt when using mvc
How to Start a Java MVC Application With a Swing GUI
And answer suprised me.Why shoud be Model on edt as well?Is that really correct??I dont think so.
So question1- When is the best time to put my Gui on edt.When i create View?
question 2- Do i have to do updates from my controller like this?Each time? -
public void setIconLabel(final Icon icon) {
SwingUtilities.invokeLater(new Runnable() {//with swingutil on each method where i work with gui?
#Override
public void run() {
myLabel.setIcon(icon);
}
});
}
If you understand please point me right direction and if needed provide short example code.Thank you.
Anything that interacts or can change the UI in anyway MUST do so from within the context of the Event Dispatching Thread.
Swing, by design, is not thread safe. That is, there are no checks in the default libraries to make determinations about what thread the various models and components are been executed on, it is assumed the developer will already have made these determinations.
So question1- When is the best time to put my Gui on edt.When i create View?
Immediately. You have no way of knowing when a component may become realised (displayed on the screen and/or attached to a native peer)
question 2- Do i have to do updates from my controller like this?Each time? -
No, in fact, I'd be very worried if I found myself coding like this all time. Make the determination that the models and components MUST be executed within the context of the EDT and make whatever is interacting with these models and components meet these requirements.
This would mean, if you are loading data from a separate Thread, you would need to ensure that any time they update the model, they are synchronizing these updates to the EDT to ensure that if the model notifies the UI, it all occurs within the context of the EDT.
Don't make assumptions about the state of the model, statements like "I know..." will come back to haunt you, especially when some one else makes use of your API.
Unless you physically create the model yourself (outside the EDT) and guarantee it's isolation while it's being loaded, don't assume anything that is given to you isn't attached to the UI in some way.
An easier solution is to use a SwingWorker when you want to perform operations off the EDT, as it provides this synchronisation via it's publish/process/done methods

Implementing threading in Swing's EDT?

My project is built upon Java's Swing library. It spawns the EDT which displays my GUI (which works correctly).
The entrance to the program, which initializes the EDT:
public final class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Start());
}
class Start implements Runnable {
private Model model = new Model();
private Controller controller = new Controller(model);
private View view = new View(controller);
#Override
public void run() {
// Initialize the view and display its JFrame...
}
}
}
}
However, when a button / radio box / etc. is clicked within my GUI, the Controller class must perform an action on the model.
My questions are the following:
Should I wrap the controller's code in a new SwingWorker?
If no, should I wrap my model's code in a new SwingWorker?
If I wrap the controller's code with threads, do I need to synchronize the shared state variables within my model?
If my model, running on a new thread, notifies my GUI of changes, will this occur on the EDT or on the new thread?
For example:
public class Controller {
public void updateModel() {
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
model.somethingSomethingSomething();
}
}.execute();
}
}
public class Model {
public void somethingSomethingSomething() {
notifyListeners(); // This is going to notify whichever GUI
// is listening to the model.
// Does it have to be wrapped with Swing.invokeLater?
}
}
public class View {
// This function is called when the model notifies its listeners.
public void modelChangedNotifier() {
button.setText("THE MODEL HAS CHANGED"); // Does this occur on the EDT?
}
}
Instead of updating your model from doInBackground(), publish() interim results and update your model from process(), which executes on the EDT. In this example, JTable corresponds to your View and TableModel corresponds to your Model. Note that JTable listens to its own TableModel.
You can read about it here: Improve Application Performance With SwingWorker in Java SE 6. In short: all time consuming operations, which are not affected UI must be done in another thread. To show results of operation you must go back to EDT. For example, if you make database search, you should show a progress bar (usually infinite) and start the search using SwingWorker. To show search results in a table, you must be in EDT. Alternatively you can use foxtrot lib (it allows to make your code more Swing convenient without to redesign it).
If your controller code permanently updates the swing widgets you should execute it in EDT or at least perform these updates of UI in EDT (using SwingUtilities.invokeLater, chunk processing in SwingWorker or swing.Timer).
So your sample is wrong: model update should be up-to-date in EDT.
One alternative approach, from Java Concurrency in Practice 9.4.2, uses a "Split" or a "Shared Data Model". You update your Business Model on whatever thread you want, likely the long-running non-EDT thread. But then, instead of directly calling notifyListeners() and worrying about which thread you are on, simply call myComponent.repaint(), which will queue up a repaint request on the EDT.
Then, somewhere in your paintComponent() method, you explicitly grab all new data from the Model, typically in a method called modelToView()
commentTextArea.setText(myModel.getCommentText());
fooLabel.setText(myModel.getFooText());
...
The upsides are that threading is not an issue, and, at least to some minds, this "makes sense", and the model is nicely decoupled from the view. A downside is that you are resetting all the values every time. So if you have 100 JComponents, that's 100 things getting set. Also, the view is pretty tightly coupled to the model.
Working Code Examples
#MadProgrammer and #kleopatra are correct that, if the view directly contains the components that are being updated, you get an "infinite loop of doom". For proof, see
Demo_14716901_Fails
However, if the view is isolated from the components, you avoid the infinite loop. Normally, the higher level view would contain stuff like JSplitPanes, holding JScrollPanes, holding Boxes or more JPanels, holding the actual low level components. So this requirement, IMO, is not unreasonable.
Working code at Demo_14716901_Works
Some Comments Added for the Downvoters:
Some people want to defeat Swing. They are writing instrument control code or algorithms and just want to get their job done without worrying about the EDT, endless SwingWorkers and invokeLaters. This technique lets them get their job done. With the one important caveat noted, it works. (Personally, I understand and generally like Swing, but many don't).
While Swing components are nicely MVC, they are generally at far too micro a level. The "real" model is not a single String, it is dozens of values. The "real" view is not a single JLabel, it is many JPanels, each with many components, combined with scrollers, splitters, etc. This technique usually fits the real world better, allowing the programmer to think naturally at a higher level.
As far as "bad practice", take it up with Brian Goetz, Josh Bloch, etc. o.k., that's "appeal to authority", but it works for me. :-)

JLabel will not update unless something causes the method to hang

Firstly, apologies but it would be really hard to reconstruct a SSCCE for this, though I think I can explain the situation considerably well and get my question across,
My situation is as thus: I have a JLabel that serves as a status indicator (e.g. that will display "Loading..." or "Ready") and I call the setText method in a MouseAdapter before another method is called to do the actual action. However, the JLabel text never changes, unless I do something like call JOptionPane.showMessageDialog() in which case the text does update.
So, does anybody have any suggestions as to how I can resolve this situation without doing something like displaying a message box for (what would be) no reason whatsoever?
Thanks in advance
Make sure you don't run your task (your "Loading..." procedure) on the EDT (Event Dispatch Thread); if you do so, your GUI won't get updated.
You have to run your application code (unless it's very fast, say less than 100ms, no network access, no DB access, etc) on a separate thread. The SwingWorker (see javadocs) class might come handy for this purpose.
The EDT (e.g. code blocks inside user interface listeners) should only contain code for updating the GUI, operating on Swing components, etc. Everything else you should run on its own Runnable object.
--
EDIT: reponse to Andy's comment. Here's a raw example (written on the fly, it might have typos and such and might not run as-is) of how you can use the SwingWorker class
Put this in your mouse listener event or whatever makes your task start
//--- code up to this point runs on the EDT
SwingWorker<Boolean, Void> sw = new SwingWorker<Boolean, Void>()
{
#Override
protected Boolean doInBackground()//This is called when you .execute() the SwingWorker instance
{//Runs on its own thread, thus not "freezing" the interface
//let's assume that doMyLongComputation() returns true if OK, false if not OK.
//(I used Boolean, but doInBackground can return whatever you need, an int, a
//string, whatever)
if(doMyLongComputation())
{
doSomeExtraStuff();
return true;
}
else
{
doSomeExtraAlternativeStuff();
return false;
}
}
#Override
protected void done()//this is called after doInBackground() has finished
{//Runs on the EDT
//Update your swing components here
if(this.get())//here we take the return value from doInBackground()
yourLabel.setText("Done loading!");
else
yourLabel.setText("Nuclear meltdown in 1 minute...");
//progressBar.setIndeterminate(false);//decomment if you need it
//progressBar.setVisible(false);//decomment if you need it
myButton.setEnabled(true);
}
};
//---code under this point runs on the EDT
yourLabel.setText("Loading...");
//progressBar.setIndeterminate(true);//decomment if you need it
//progressBar.setVisible(true);//decomment if you need it
myButton.setEnabled(false);//Prevent the user from clicking again before task is finished
sw.execute();
//---Anything you write under here runs on the EDT concurrently to you task, which has now been launched
Do you call the setText() method from the EDT?

Categories

Resources