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).
Related
I am having trouble getting message boxes and to a degree dialog boxes to show/function properly in Mac (v10.9.5).
I just updated the JRE and JDK to the latest version (8u31). A "java -version" from a terminal window shows that I am indeed using 8u31. (I was previously using 8u20, which exhibited the same behavior.)
The code below works perfectly in Windows and a couple of different versions of Linux that I tested, no issues. I just have issues on a Mac. I streamlined my code, which is SWT based, but this example uses Swing, to the following:
package myTest;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class EntryCode
{
public static EntryCode oEntryCode;
public EntryCode()
{
// TODO Auto-generated constructor stub
}
public static void main(String[] args)
{
oEntryCode = new EntryCode();
oEntryCode.open();
}
public void open()
{
JPanel panel = new JPanel();
panel.setMinimumSize(new Dimension(200,200));
JFrame frame = new JFrame("JOptionPane showMessageDialog component example");
System.out.println("open(): entry - With frame");
JOptionPane.showConfirmDialog(frame, "Wow, works on the Mac!", "Inside open()", JOptionPane.YES_NO_OPTION);
System.out.println("Point 1");
System.exit(0);
}
}
I see the first system out line, and the code hangs on the message box request. In the real code, I simply use a null as the first argument. The original version of this test code used a null too, just I was experimenting with specifying a component. I thought that might be the problem. It is not.
When displaying SWT dialog boxes, there is a tendency that clicking on a button will hang the interface. The hang is somewhere between the button being depressed and the event handler firing. The event handler never fires.
I did not include a dialog box here. I figure that since my confirmation/message box exhibits the same problem that solve one, get the other for free.
I did a search on Google for displaying java applications on a Mac, but nothing turned up.
I would think that updating the JRE/JDK to the latest version would solve any OS related issues.
I compile the code to a jar and use the following to run from a terminal window. I to press Ctrl+C to quite the hung app.
java -XstartOnFirstThread -jar myTest.jar
Thoughts?
UPDATE:
I deleted the original update but am leaving the original question, now that I understand the problem better.
The real problem is how to initiate a proper Mac OSX Cocoa restriction friendly SWT application, which uses dialog and message boxes. (To the best of my knowledge, the only way to display message boxes is to use JOptionPane.show*, which is a Swing thing, thereby sort of mixing Swing and SWT.
It is interesting to note that the problem always relates to buttons, be it on a dialog box (a purely SWT implementation) or message boxes. In the former, the issue is a hang calling the event handler and the latter displaying a message box (null first argument, as no Swing frame exists in a SWT application).
The problem may be that you are not starting the GUI in the EDT. Try this:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
oEntryCode = new EntryCode();
oEntryCode.open();
}
});
}
More info: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
Another issue is using -XstartOnFirstThread with Swing. Swing does the equivalent of what -XstartOnFirstThread is doing, but in its own way. You should not use -XstartOnFirstThread with Swing, just as it's not a good idea to mix SWT and Swing.
If you add SwingUtilities.invokeLater() and remove -XstartOnFirstThread, your example should run normally.
Not quite sure if this might be the error since I can't test it on my Mac at the moment. But you never setting visibility of the JFrame to true. When you pass the frame as a parameter to the JOptionPane the pane tries to show the pane in the frame.
So try :
public void open()
{
JFrame frame = new JFrame("JOptionPane showMessageDialog component example");
System.out.println("open(): entry - With frame");
frame.setSize(300,300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
JOptionPane.showConfirmDialog(frame, "Wow, works on the Mac!", "Inside open()", JOptionPane.YES_NO_OPTION);
System.out.println("Point 1");
System.exit(0);
}
Also why do you create the JPanel the panel is never used as far as I can see ?
Since the frame is not visible this could cause problems. Just a guess...
This would also explain why it looks like your application is "freezing". Its because it is waiting for you to make the selection in your JOptionPane but you can't make that selection because you can't see the JOptionPane.
I know you wrote you also tried with passing null as argument but I could think this could also cause problems when there is no other JFrame shown. As i said just a guess. Just try it out and come back here to provide further information.
EDIT
Just tested and looks like your code is fine. Your error has to lie in your mac or java setup.
EDIT 2
I think I found your answer. Looks like the startOnFirstThread is the problem here. I just tested via javac and java on command line. Have a look at this:
Swing stops working, because -XstartOnFirstThread implies that that
someone else (very likely the SWT) is going to come around, and start
pumping the event loop on thread 0 with CFRunLoop or the like
This could explain why your JOptionPane struggles to show up. (Taken from: here
Also a bit older but describes your problem:
The AWT problems generally come down to which thread the jvm was started on. When using the java launcher (as pde does) on Mac, java by default starts on the second thread (which is what AWT wants) unless you specify -XstartOnFirstThread (which is what SWT wants).
(https://bugs.eclipse.org/bugs/show_bug.cgi?id=212617)
I have a very simple, choose your path, Java game that I am working on in the NetBeans IDE. Basically what happens is the user will click one of the three buttons, and pre-made JLabel's which are set to "" (nothing) will be reset to whatever text I decide that label should then use. I do this by adding the code below.
private void option1ActionPerformed(java.awt.event.ActionEvent evt) {
jLabel6.setText("You go down the dark tunnel...");
}
Now all this works fine but I'd like a way to restart/reset my application by clicking a button labelled "restart". I don't mind if it has to close the application and then open it again or if it will simply reset all the JLabel's back to "". I just don't want to have to type out the code below for every single JLabel.
jLabel1.setText("");
jLabel2.setText("");
jLabel3.setText("");
I have done some research on this site and none of the code that people provide seems to work for my situation, either because it simply doesn't work or because I am doing something wrong. Any help would be greatly appreciated and please try and be specific because I am fairly new to writing Java and don't understand everything.
It would also work for me if someone could provide a way for me to close 1 window in an application instead of the whole thing, like when
System.exit(0);
is used.
First, I recommend importing the JLabel class specifically so you can write JLabel instead of javax.swing.JLabel:
import javax.swing.JLabel;
Instead of declaring each JLabel individually, create an Array of JLabels:
JLabel[] jLabels = new JLabel[N]; // where N is the number of JLabels
Whenever you need to access a JLabel, use:
jLabels[6].setText("You go down the dark tunnel...");
When you want to reset all the JLabels, use:
for (JLabel jLabel : jLabels) {
jLabel.setText("");
}
For more details on Arrays, read http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
If you are having your program as a executable jar file then you can use
public void restert(){
Runtime.getRuntime().exec("java -jar yourapp.jar");
System.exit(0);
}
If you want to know more about restarting java application you can go through this
Found the answer to my own question:
Thanks to Holger for suggesting "dispose". This is what I found worked.
private void restartButtonActionPerformed(ActionEvent evt) {
if(evt.getSource() == restartButton)
{
dispose();
MyGUI game = new MyGUI();
game.setVisible(true);
}
}
I have a JXTreeTable with an add button. The button works as expected: it adds a new node to the end, with values that (for the purpose of testing) are hard-coded into my program. The line:
modelSupport.fireChildAdded(new TreePath(root), noOfChildren-1, dataNode);
tells the JXTreeTable to recognise the update made to the TreeTableModel, and to refresh accordingly.
I then execute:
treeTable.changeSelection(treeTable.getRowCount()-1, 0, false, false);
to automatically select this new node. This works as expected, BUT I also expected it to automatically scroll to bring this new node into sight, which it does not. Instead, it scrolls to show only the penultimate node, leaving the new node hidden just slightly beyond view.
I've also tried using tricks to programmatically scroll to the final record. However, this code:
JScrollBar vertical = scrollPane.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum());
revealed the same problem.
Bizarrely, if I attach either of the above two blocks of code to a "Scroll to Bottom" button, and press this button manually after adding the new node, it all works fine! Please can anyone isolate the cause of this bug, or offer a fix/workaround?
JXTreeTable should have something like:
JXTreeTable.scrollPathToVisible(...)
Does this work for you?
EDIT:
I assume it works with your Button, because the Scrollpane is already "rendered/painted" with the new added node (when you click the button).based on this, the internal max/min calculation (e.g in scrollpane) can differ.
For anyone else having this problem, it seems to be caused by a peculiarity with the order in which GUI actions are executed (due in part to the need to be executed on the Dispatch thread).
From memory, this is how I solved it. (I haven't looked at the code in several months, so this code might not work perfectly, but you get the idea.)
Wrap the "vertical.setValue(vertical.getMaximum());" code in a SwingUtilities.invokeLater() method call. In other words:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JScrollBar vertical = scrollPane.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum());
}
});
*EDIT 2: I just discovered that this is a compiz+java GUI problem. It apparently happens where those two elements intersect.
I'm running the latest Ubuntu 11.04 (classic desktop, not Unity) with all updates. The problem happens with both Sun java and OpenJDK. It is related to using the Window-Rules Compiz plugin -- which I need to use.
As stated in comments below, I previously verified that my controls are added to the correct thread. Now I found that disabling the Compiz Window-Rules plugin resolves my issue. Since I need to use the plugin, I am looking for a solution.*
Original post: I am working on a Java swing application. It was built with NetBeans 6.9. It uses GridBagLayout manager. The look and feel is currently Nimbus (but that doesn't seem to have any effect on the issue I'm going to describe). Most users run the app on Linux. A few use Windows. Most of the time the app works fine. But at random times a view will open without some of the GUI buttons. For example, the Save and Cancel buttons might be missing. The other GUI elements will usually be present (although once I have heard that a view was completely empty with no GUI elements -- just an empty gray window).
If the user closes that view with the "X" in the upper corner and simply re-opens it, it will be drawn correctly. The missing buttons issue happens less than 1% of the time. The close/reopen sequence fixes it almost 100% of the time. (A second close/reopen may have been needed once, if I recall correctly.)
Typically, if some buttons are missing, the other elements are still drawn correctly. This does not affect the whole view (form). It seems to affect the lowermost panel, but I'm not sure if that is actually a repeatable pattern. It is very difficult to reproduce this. I use the software every day and I see this less than once a month. A few users see it more frequently, but it is still rare.
There are no error messages. I have no idea what to try next. This behavior has persisted across different computers, different Linux distros (although all are based on Debian), and many different code changes, including changing the layout manager. (We used the NetBeans GUI designer previously.) Any ideas?
EDIT: 2011.07.05
This is what the code looks like in general:
public void show_some_view() {
setTitle(...)
setLayout(new GridBagLayout());
JPanel butnPanel = new JPanel();
butnPanel.setLayout(new GridBagLayout());
try {
//add stuff to panels (butnPanel, etc.)
} catch (Exception e) {
Logger.log(e);
}
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
int[] wh = ApplicationContext.get().getDisplayWidthxHeight();
setSize(wh[0], wh[1]);
setFocusable(true);
setVisible(true);
}
But at random times a view will open without some of the GUI buttons.
Make sure you add the buttons to the GUI on the EDT. Read the section from the Swing tutorial on Concurrency for more information.
Make sure you add the buttons to the GUI BEFORE invoking setVisible(true);
I had the same problem: sometimes my JMenu wouldn't draw (also on Ubuntu 11.04).
I fixed it by just adding
menuBar.setVisible(false);
menuBar.setVisible(true);
To my code, right after I added it to my JFrame (Which was alreasy set to visible).
I know it's messy but it solved my problem so I'm fine with it.
Hope this helps!
This may be a stupid question, but I have to ask!
I have the following code snippets that are supposed to run their corresponding methods when the user interacts with objects.
For some reason, "foo" is never printed, but "bar" is.
myJSpinner1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
System.out.println("foo"); //"foo" is not printed
}
});
myJSpinner2.addChangeListener(new java.awt.event.ChangeListener() {
public void stateChanged(java.awt.event.ChangeEvent evt) {
System.out.println("bar"); //"bar" is printed
}
});
I get no exceptions or stack trace. What am I missing in the MouseListener one?
Thanks in advance.
EDIT: MouseEntered works perfectly on a JCheckBox implemented in exactly the same way!
JSpinner is a composite component consisting of a text field and 2 buttons. It's possible to add mouse listeners to all of those by iterating over the results of getComponents() and adding a listener to each.
However, in my experience, when something takes that much work, you're probably going about it the wrong way.
Why do you need the mouse-entered information for a JSpinner?
What do you want to do with this event?
Update:
If you're looking to supply information about all of the controls in your panel, you may want to look at using a glasspane to detect the component under the mouse.
A Well-behaved Glasspane by Alexander Potochkin is a good place to start.
This is a guess but I suspect you need to add a MouseListener to the JSpinner's editor (via a call to getEditor()). I imagine that the editor Component occupies all available space within the JSpinner and is therefore intercepting all MouseEvents.
This worked for me.
JSpinner spinner = new JSpinner();
((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().addMouseListener(
new java.awt.event.MouseAdapter() {
public void mouseClicked(final MouseEvent e) {
// add code here
}
});
I needed this in order to evoke a popup key dialog for added usability due to our software requirements.
Aditional to #Rapier answer...
If you change the Spinner using something like
yourOldSpinner = new JSpinner(new SpinnerModel(...))
you will lost your previosly MouseListener...
If you need to change something of SpinnerModel, Don't create a new, change its parameters instead! (if you do it, you will need to reassign the MouseListener again, because it will be lost when you assign a new SpinnerModel).
an example (I'm talking...):
((SpinnerNumberModel)yourOldSpinner.getModel()).setValue(size/3);
((SpinnerNumberModel)yourOldSpinner.getModel()).setMinimum(0);
((SpinnerNumberModel)yourOldSpinner.getModel()).setMaximum(isize/2);
((SpinnerNumberModel)yourOldSpinner.getModel()).setStepSize(1);