JDialog Freezes on Loss of Focus? - java

I have a program I'm working on that is supposed to facilitate the making of texture maps by allowing you to edit individual textures in the map. I have several places where I use JDialog's for things like input of the tile-size of a map, the initial size of a new map, and one that simply has a button on it that the user presses when he or she is done editing the selected textures with an external program (such as photoshop or paint.) However, any time one of these JDialog's is up, if the program loses focus it becomes completely unresponsive. Here's my code for the JDialog that pops up when you're editing selected textures externally:
JDialog editing = new JDialog(mainFrame, "Externally Editing");//mainFrame is the name of the JFrame containing everything.
JPanel pnl = new JPanel();
editing.setLayout(new BorderLayout());
pnl.setPreferredSize(new Dimension(150, 60));
editing.add(pnl);
editing.pack();
JButton button = new JButton("Done Editing");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
editng = false;//Obviously, a boolean that I have outside of this method.
}
});
pnl.add(button);
Thread.sleep(100);
editing.setVisible(true);
while(editng){System.out.print("");}//Doing nothing while the user is externally editing.. Unfortunately, if I don't have "System.out.print("");" it doesn't work.. Oh, Java..
new Thread(new Runnable(){public void run(){editing.dispose();}}).start();//Gotta dispose of it in a separate thread since AWT isn't Thread-safe... Ugh..
I would assume that it freezes in the AWT Thread that it creates/has for the JDialog, while my thread is just waiting for the button to be pressed.. Which can't happen because the JDialog is frozen.

Make your dialog modal. Your application will stop processing until the dialog is closed

Why this bogus roundabout? Simply dispose the dialog in the listener.

Related

Updating a JLabel within a JFrame

I've been searching around this site and the internet for hours trying to figure out how to fix this problem. I'm creating a game and it's my first time using graphics. I figured out how to create a JFrame, JPanel and JLabel, and the only problem I can't seem to get around is updating the JLabel. Let's say I start it out like this:
JLabel testing = new JLabel ("blah", JLabel.CENTER);
testing.setAlignmentX(0);
testing.setAlignmentY(0);
frame.add(testing);
I am able to change the text after a Thread.sleep(2500) by using testing.setText("hi");, but the previous state of the JLabel (which says blah) is still there. The "hi" just appears on top. I've tried testing.setVisible(false);, and so many other things but nothing is letting me display the JLabel, hide it, and then change it.
Any ideas what could be wrong?
Thanks
Don't sleep or otherwise block on the AWT Event Dispatch Thread (EDT).
Use javax.swing.Timer instead. Note: not any other class of the same name in a different package.
javax.swing.Timer timer =
new javax.swing.Timer(2500, event -> {
testing.setText("hi");
});
timer.setRepeats(false);
timer.start();

doClick() not disposing frame

I have a button with an action listener that disposes than reopens a frame. If I physically click the button it works as expected, the frame closes and the same one opens again.
I also have this action linked up with a doClick() in a timer. When the action occurs it opens a new frame without disposing of the other one. The timer works perfectly by itself.
What is the reason for this and how can I fix it? Is it a problem with the timer or calling it through the doClick?
I am relatively new to all this so this may be a simple question. Thanks
Button code:
frmStart s = new frmStart();
s.setVisible(true);
this.dispose();
doClick code (change is boolean):
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
if(change) {
btnReload.doClick();
}
}
}, 400);
With what you have provided, my best guess is to have you switch you Timer import from util.Timer to javax.swing.Timer
Then you would instantiate it like so:
Timer t = new Timer(400, (e)->{
if(change)
btnReload.doClick();
});
Then start it
t.start();
It isn't a good idea, and sometimes won't even work, to interact with swing objects outside the Swing Thread. When using javax.swing.Timer it runs the defined functionality within the Swing Thread
Dispose does not kill the frame. Quote:
Releases all of the native screen resources used by this Window, its
subcomponents, and all of its owned children. That is, the resources
for these Components will be destroyed, any memory they consume will
be returned to the OS, and they will be marked as undisplayable.
The frame itself is alive until the GC kicks in. And the GC does nothing because the timer is still active. So you should dispose the frame and then cancel the timer.

JButton needs to be clicked twice after JDialog

I've been struggling with some problem while creating my app based on Swing. I have a main JFrame which consists of:
JMenu
JPanel containing a JButton and a JLabel
JButton is linked with ActionListener. Clicking JMenu (MenuListener) brings up a JDialog with some form. The problem is, when the JDialog is closed (it doesn't make difference whether I do it with dispose() or rather showVisible(false)) I need to click the JButton two times before it triggers for the first time. From now it normally works with one click.
Every time the JDialog is in front, the problem appears.
PS. The JDialog is set to be modal, with JFrame as parent.
It sounds like a focus issue.
The first click restores focus to the app and the second clicks the button. Typically, I have seen this when the JDialog has the wrong parent and focus can not be returned.
Thank you for your answers.
I have considered posting some code, but it involves 4 classes so will be quite long.
I have also tried things with focus before, but nothing helped. What is interesting: if I display the JDialog by new myDialog.showVisible(true) it behaves like I've described. But if I use construction like this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JDialog.setVisible(true);
}
});
it closes normally and parent frame doesn't need to be clicked before responding, but on the other hand the displayed Dialog needs so. Additonally, what I do not understand, after opening the Dialog cursor is placed in the text field and I can write normally, but to click some button on it I must click once on the Dialog, only second and next clicks behave like I want to.
PS. Closing the dialog like in the second included example changes nothing.

Wait for Swing GUI to close before continuing

I am writing an app that requires the user to enter some data into a Swing GUI which the app will then use. After the user enters the data, there is no longer any need for the GUI as the app will then write some data to files.
The General idea is this:
launchGui();
closeGui();
continueWithComputation();
I understand that Swing uses a few threads in the background which I understand is why the program doesn't block until the GUI is closed.
Is it possible in any way to wait for the GUI to close (single JFrame closed with dispose()) before continuing with continueWithComputation()?
Wait for Swing GUI to close before continuing
Use a modal dialog. See the following for further details:
How to Make Dialogs
How to Use Modality in Dialogs
Is it possible in any way to wait for the GUI to close (single JFrame closed with dispose()) before continuing with continueWithComputation()?
user actions add WindowListener
from code to call JFrame#setVisible(false), then you can running continueWithComputation(), you have to close this JVM by System.exit(0), otherwise stays in PC's RAM untill restarted or power-off
I just had a similar problem, but without a closeGui() method and came up with this relatively short code snippet, using a WindowListener and some Java synchronization:
AtomicBoolean closed = new AtomicBoolean(false);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
synchronized(closed) {
closed.set(true);
closed.notify();
}
super.windowClosed(e);
}
} );
frame.setVisible(true);
synchronized(closed) {
while (!closed.get()) {
closed.wait();
}
}
// executes after the Frame has been disposed
My suggestion is to open the JFrame GUI as Modal and then everything will wait until it disappears from the screen. As JFrame cannot be set as modal you have to open the GUI frame as JDialog. I am using:
public class frameMain extends JDialog{
be sure that into the constructor you use:
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Wherever you need to start the GUI frame you should use:
frameMain frm= new frameMain ();
frm.setModal(true);
frm.setVisible(true);

Why setVisible doesn't work?

I have a swing GUI with border layout. in the NORTH I have added some component.
My label component which has GIF icon is invisible lblBusy.setVisible(false);
later a button make it visible like below. Why it does not show up?
btnDownload.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
lblBusy.setVisible(true);
btnCancel.setEnabled(true);
}
});
download = new Download(txtSource.getText(), new File(txtDestination.getText()), textAreaStatus);
download.start();
lblBusy.setVisible(false);
}
});
1) this is EventDispatchThread rellated issue, EDT quite guaranteed that all changes to the GUI would be done on one moment
2) you invoked ActionPerformed from JButton, and untill all events ended your GUI should be freeze or is unresponsible, same for JButton and JLabel in your case
3) better would be redirect reading for File contents to the Backgroung task e.g. SwingWorker or Runnable#Thread then JButton and JLabel will be changed and GUI would be during Background task responsible for Mouse or KeyBoard
or
4) dirty hack split to the two separated Action delayed by javax.swing.Timer, but in this case again untill all events ended your GUI will be freeze or is unresponsible
Most probably because the GUI was packed at a time the label was not visible, so no space was assigned to display it. For anything more definite, post an SSCCE.
It seems to me that you are writing lblBusy.setVisible(true); and after that lblBusy.setVisible(false); in the mouseClicked() method. Since you wanted to make it visible at the click of a button aren't you be using only lblBusy.setVisible(true);, instead of using both.
You can call lblBusy.setVisible(false); from the end of your Download Class though, once it's done doing what it does.
Regards

Categories