java7 bug with JTextField when reopening JDialog that has been setVisible(false) - java

I have a strange issue with our application that only manifests itself in java7, everything worked flawlessy in java6.
I have a product-choosing JDialog that has a JTable, an ok button, a cancel button, a jtextfield for searching and a jcheckbox "keep window open".
The idea is, that if "keep window open" is selected, then a press to the ok button will not dispose the jdialog, but instead set a reopen-variable to true, and call setVisible(false).
Then I have the following code to reopen it:
while(SelectionDialog.isReopen()){
Product p1 = SelectionDialog.reopen();
if (p1 == null) return;
//Do stuff with product
}
In SelectionDialog:
public static SelectionDialog reopen = null; //Is instanciated to current jdialog if ok button is pressed and reopen-checkbox is selected. setvisible(false) is then called instead of dispose()
public static Product reopen() {
SelectionDialog.reopen.setVisible(true);
return SelectionDialog.returnedData;
}
The strange thing is, that when the JDialog is redisplayed, the jtextfield is not focusable/clickable. Everything else seems ok. If I then press the ok button and it reopens, the jtextfield is ok again, but if I press ok another time it is not focusable/clickable again.
The jtextfield displays text, but there is no blinking cursor when it does not work.So every other time the jtextfield simply doesn't work, and every other time it works.
All these methods return true for the jtextfield: isEnabled, isEditable, isDisplayable, isVisible, isFocusable, isOpaque, isShowing, isValid.
Calling updateUI on jtextfield in swingutilities.invokelater before setVisible(true) on jdialog does not solve the problem. Neither does requestfocusinwindow.
The only thing that seems to work to bring the jtextfield back from the dead is switching to another program, and then switching back to my java-program.
I have tested, and the problem persists in both jdk1.7.0_03 and 1.7.0_51.
I don't have this problem in java6 and before.
What can be causing the problem? (I have removed everything from "//Do stuff with product" in case this did something, but the problem persists).
And even if you don't know what causes the problem, does anyone have any suggestions to a workaround that may work?
UPDATE:
Thanx to MadProgrammers comments, it now works with the following code:
SwingUtilities.invokeLater(new ReopenProductList()); //Instead of while-loop
private class ReopenProductList implements Runnable{
public void run(){
if (SelectionDialog.isReopen()){
Product p1 = SelectionDialog.reopen();
if (p1 == null) return;
//Do stuff with product
SwingUtilities.invokeLater(new ReopenProductList());
}
}
}

Based on the description of the problem, it would appear that you are blocking the Event Dispatching Thread by using the while loop.
Having had a situation when testing Java 7 early on (it actually deadlocked on SwingUtiltiies.invokeLater). We never found the fault, as we re-wrote the entire action of code (the original was funky), it would suggest that the threading model,has changed between Java 6 & 7.
Try removing the while loop from the EDT

Related

actionPerformed has empty logic

I have a screen which has list. By right click, I can open a small pop up and add new records to the that list by choosing some record and clicking OK button from pop up.
OK button which is on pop up has an action listener like below:
okButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setVisible(false);
}
});
And that is all the actionPerformed method does and I do not understand how this method is adding new record to the list on main window. There should be another part of code which is connected to this part but I do not know what is that. Do you have any idea what I do not see on that logic?
The ActionListener is not empty and in fact it is changing the state of the window that holds the JButton, making it no longer visible.
No one can say with 100% confidence what logic is being used here since you've yet to show enough code for that, but our guess is that this button is being held within a modal JDialog -- a window that freezes code flow in the calling code once the dialog window is visible, and (here's the key) that releases the block on code flow once this dialog is no longer visible. So in this situation, making the dialog no longer visible will allow the calling code, the code that initially told the dialog to display itself, to resume flow of its logic. Presumably in the subsequent code, it will query the dialog for data that was entered, and extract it, again the details of which are in code not yet shown to us.

how to use ActionListeners in java properly

Through some searching, I made about ActionListeners and GUI. I think I have come to a conclusion that all the changes you do that affect the GUI, in the ActionListener, actually happen when ActionListener comes to it's end
I am currently making a memory game. In the action listener of a card button I first flip the image (that changes it's icon) and the I check if a have a match and in the case I don't have one I close the card(change icon).
Since those two happen in the same actionListener as a result if I dont have a match I only see the first card I pick and he second seems to no react to flip.
Sorry if it's confusing how I explain it. I think that the problem is the actionListener but maybe I am wrong. What would you suggest?
c.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae){
selectedCard = c;
String imgName = "Images/"+c.getId()+".jpg";
URL imageURL = this.getClass().getResource(imgName);
if (imageURL != null) {
ImageIcon icons = new ImageIcon(imageURL);
c.setIcon(icons);
}
c.setEnabled(false);
c.setDisabledIcon(c.getIcon());
pl.singlePlay(c);
if(pl.getMatch()==false){
for (Cards cd : cards){
if(cd.getMatched()==false){
cd.setEnabled(true);
cd.setIcon(icon);
}
}
}
});
I have come to a conclusion that all the changes you do that affect the GUI, in the ActionListener, actually happen when ActionListener comes to it's end
Yes, all code invoked from any listener executes on the Event Dispatch Thread (EDT). This thread is responsible for updating the GUI and so the GUI can't be updated until the code has finished executing. Read the section from the Swing tutorial on Concurrency for more information.
Since those two happen in the same actionListener
If you want to schedule animation, that is show one Icon and then seconds later show another Icon, then you can use a Swing Timer. The Timer allows you to schedule another event. The tutorial link from above also has a section on How to Use Swing Timers to get you started.

Updating JLabel with value

Each time the user presses a button a counter amountWrongGuessed gets incremented by 1. (works correctly with testing with System.prinln)
But how exactly do i get this to update in my label each time i press the button?
I have made a property that returns this value.
public int getAmountGuessed(){
return amountGuessed;
}
Next i try to get the value of the label, but the value always remains at 0.
lblAmountGuessDisplay = new JLabel(String.valueOf(hg.getAmountGuessed()));
private void UpdateComponents()
{
lblAmountGuessDisplay.setText(String.valueOf(hg.getAmountGuessed()));
}/*updateComponents*/
This example shows one way to update a label each time a button is clicked.
It might be a threading issue. Please take a look here.
I agree with Fredrick -- that you've not posted enough information for your question to be answerable and that it may be a reference issue -- that the JLabel you are changing is not the one that is displayed in the program. If you post more code, we'll have a better chance of giving your a decent answer. Also, this doesn't smell like a threading issue.
You need to add an ActionListener to your button. When the ActionListener is notified that the button is pressed, you can increment the counter and update the JLabel. The actionPerformed method will be triggered in the EDT, so you should be ok with threading.
lblAmountGuessDisplay.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent ae) {
hg.incrementAmountGuessed();
lblAmountGuessDisplay.setText(String.valueOf(hg.getAmountGuessed()));
}
}
You will probably need to implement the incrementAmountGuessed method (which may be the root of your problem in the first place).

Enabling/disabling an AWT Button

I wrote the following piece of code, which is supposed to return a panel with one checkbox and one button. The idea is that the button should be enabled only if the checkbox is checked.
It works, meaning that if the checkbox is not checked, and I try to push the button, nothing happens. However, the visual appearance of the button is wrong, it appears as disabled when it should appear as enabled, and vice-versa.
Any idea what's wrong with my code ?
Thanks a lot in advance
public Panel createCalibrationPanel(final ImagePlus imp) {
final Panel panel = new Panel();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createHorizontalStrut(20));
final Checkbox checkbox = new Checkbox(
"Use image spatial calibration for q scale", true);
final Button button = new Button("Set scale");
useCalibration = checkbox.getState();
button.setEnabled(checkbox.getState());
panel.add(checkbox);
panel.add(button);
checkbox.addItemListener(new ItemListener() {
public void itemStateChanged(final ItemEvent e) {
boolean state = checkbox.getState();
setUseCalibration(state);
button.setEnabled(state);
}
});
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
imp.unlock();
IJ.run(imp, "Set Scale...", "");
imp.lock();
}
});
return panel;
}
The logic controlling the button is correct. I modified your sample code and it works as you described. (This is the version I used: http://pastebin.com/f6cd6cfac, tested on Sun Java 6).
But, there are some other methods that you call, but which you haven't shown us: setUseCalibration, imp.unlock, and IJ.run. Are you sure they are returning correctly? You should remove the external calls from code, and add them back in one at time until you find which one(s) is causing the problem.
I was pretty sure you're doing everything correctly, and my test bore this out. I removed the image reference and the action code, and the button behaves as intended.
I'm running JDK 6 from Sun on Ubuntu Linux. But that shouldn't make any difference.
I wonder if imp.lock() is doing something heinous. If this is the kind of lock associated with synchronization and concurrent processing, it looks intuitively wrong, because you're keeping the poor imp locked up for most of the program's lifetime. In any case, you could have a look at what happens when you comment out the action code.
I can't reproduce the problem either using Sun Java 6 on 64 bit OpenSuse 11.0. However, this doesn't mean that the code is correct. It just happens to work for me on my machine, OS and JRE today.
From your description it sounded like button.setEnabled(state) wasn't updating the appearance of the button, so I wondered if adding a button.repaint() directly after the call would make it work? This is more of an experiment than a solution, as even if it works it doesn't explain why your original code runs for me and not for you.
Either way I suspect one of:
Something in the way that the code is called.
Something in the library code.
A bug in the JRE (if it's a Sun JRE you can search the bugs
database).
A threading problem (make sure that the AWT code runs on the
EventDispatchThread and synchronize on mutable data members that are shared between threads).

JFrame disappear behind applet's browser window

My app is a JApplet which opens a JFrame. the applet has a listener and a button, so that if the frame goes behind another window (looses focus), the user can simply click the button to get it to come to the front. frame.toFront(); This works fine.
But initially (in the applet's public void init() {}),
after calling frame.setVisible(true); I call frame.toFront(); to to make sure it starts in front. However, the frame then immediately goes behind the browser. Pressing the button calls it back, though.
I have tried a running a separate thread which repeatedly calls frame.toFront(); But as soon as this stops, the frame goes behind the browser anyways. Only when the button is pressed does it come to the front, and stay in front. Also, having a loop or time continually holding it in front is not a good option, because the user may need or want to have it go behind on purpose.
This "bug" is not present on the Mac (which runs Java 1.5), but on Windows (running 1.6) - including IE, FF, Chrome, Safari, but not Opera (strangely).
Possible cause and fix?
Have you tried setAlwaysOnTop(true) on the frame? I'm not sure however, if this is allowed on frames or windows created from an applet.
The setAlwaysOnTop(true) solves one problem, but create another, namely that now there is no way for the user to actually send the window to the back.
My sollution is a hack:
In the WindowListener attached to the JFrame, place this code:
#Override
public void windowDeactivated(WindowEvent e)
{
if(firstToBack) //firstToBack is an bloolean instance variable initialized to true
{
final JFrame f = frame;
new Thread() { public void run() {
try { Thread.sleep(300); } catch(InterruptedException ie) {}
f.toFront();
}}.start();
firstToBack = false;
}
}
This basically starts a new Thread first time, which waits a little and then calls the JFrame to the front. It only executes once, so the frame doesn't keep coming to the front every time the user sends it to the back. The 300 milliseconds is an arbitrary amount of time and perhaps not even necessary.
Perhaps someone can tell me why this works, but when the same kind of thread was started fron the applet's init() method, the window went to the back anyways, after the thread ended?

Categories

Resources