I got the problem that my buttons are not working. I have used JButtons before and hadn't had a problem with them before. Visually, the program looks as intended.
Can someone tell me why the button is not working? The class uses JDialog.
JButton cancel;
public CodeExample() {
setLayout(new FlowLayout(FlowLayout.RIGHT));
add(cancel = new JButton ("Cancel"));
setAlwaysOnTop(true);
setModal(true);
setVisible(true);
cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println("test");
}
});
}
As Roddy of the Frozen Peas already pointed out, the last thing you should do is to make the dialog visible.
The problem here are those two lines:
this.setModal(true);
this.setVisible(true);
If a dialog is modal, then setVisible will block until the dialog is not longer visible or disposed.
This means that everything after setVisible is executed after the user clicks on the red X to close the window. But at this point the dialog is not longer visible and you don't show the dialog again.
Related
I have this strange problem when I add buttons to the toolbar. I added action listener to one button added before the frame is shown and it works fine:
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
toolbar.add(new JButton("new button"));
}
});
I also added a piece of code that is supposed to add a new button after some plugins are loaded, and for some reason that piece of code does not work.
#Override
public void handle() {
System.out.println("Button added");
MainFrame frame = Application.getInstance().getMainFrame();
frame.getToolbar().add(new JButton("Plugin button"));
frame.getToolbar().revalidate();
frame.getToolbar().repaint();
System.out.println(frame.getToolbar().getComponents().length); // It is definitely being added, just not shown
}
The button is definitely being added, just not shown.
I would really appreciate any help since this thing is blocking me from progressing any further.
I found out what the problem was. The problem was that I instantiated MainFrame twice, first by calling Application constructor in main and then when calling Application.getInstance(), so all components added to the MainFrame were removed.
I wrote the following code to have a JPopupMenu that allows multiple selection of different items.
The problem is that, as soon as the mouse enters one of the displayed JCheckboxMenuItems, the JPopupMenu gets closed. This issue doesn't occur if I replace JCheckboxMenuItem with, for example, JLabel but, for sure, JLabel doesn't work for my purpose.
Any idea of what could trigger this issue? Any idea of how this problem can be resolved in a better way? I apologize for the newbie question but I'm not a java developer. Thanks in advance for any help.
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedborder(),"Select Layers");
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
for (MyAction layer : layers) {
JCheckBoxMenuItem box = new JCheckBoxMenuItem(layer);
box.setIcon(new SquareIcon(myColor));
panel.add(box);
}
JPopup popup = new JidePopup();
popup.add(panel)
JButton button = new JButton("Layers");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
popup.show(button,0,button.getHeight())
}
});
Thats in the nature of JPopupMenus. They disappear when the invoker component loses the focus. But I found a little trick here.
Create your own class and extend it from JPopupMenu. Then override the setVisible method that it will only forward true to the super class and create an own method that will setVisible of the super class to false.
public class StayOpenPopup extends JPopupMenu{
public void setVisible(boolean visible){
if(visible == true)
super.setVisible(visible);
}
public void disappear() {
super.setVisible(false);
}
}
Then use it like this in your code
[...]
StayOpenPopup popup = new StayOpenPopup();
popup.add(panel);
[...]
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(popup.isVisible())
popup.disappear();
else popup.show(button,0,button.getHeight());
}
});
Now one click on button will show it. And it will stay visible until next click on Button.
This is an interesting problem that didn't show up when I built the last JDialog, even though that one was way more complex than this. Anyways here is the code that causes the problem.
public class Test extends JDialog{
private final JButton cancel, ok;
private final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 50, 5));
public Test(JFrame parent) {
//Initialize the JDialog
super(parent, "Select Chapters");
setLayout(new BorderLayout());
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(JDialog.ModalityType.APPLICATION_MODAL);
setSize(300, 300);
setLocationRelativeTo(null);
cancel = new JButton("Cancel");
ok = new JButton("OK");
buttonPanel.add(cancel);
buttonPanel.add(ok);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
dispose();
}
});
}}
And the main method
Test test = new Test(new JFrame());
I put the event listener in the constructor for testing but the actual implementation is supposed to happen in another class. Which is why this is a problem. If I put the action listener before setVisible(true), then everything works as it should. But I can't do that since the event handler is to be implemented in another class. What is causing this problem and how do I resolve it?
Event handler in JDialog not working if placed after setVisible(true)
Correct, because the JDialog is modal, so the statement after the setVisible() is not executed until the dialog is closed.
There is no reason you can't add the ActionListener to the button before the dialog is made visible. It doesn't matter that the code is in a separate class. You just create an instance of that class in the constructor of the class where you create the button.
I put setVisible() in the other class after I implemented the listeners
You are still doing something wrong. The setVisible() should be in your main class where you set the dialog properties and create all the components and add the component to the dialog.
I'm not sure why you are doing. Your code can be something like:
cancel = new JButton("Cancel");
cancel.addActionListener( new SomeActionListenerClass() );
...
setVisible( true );
You need to place setVisible(true) at the end of your constructor because the dialog is modal and in that case setVisible(true) will not return until you call setVisible(false).
Quoting Java doc:https://docs.oracle.com/javase/7/docs/api/java/awt/Dialog.html#setVisible(boolean)
Notes for modal dialogs.
setVisible(true): If the dialog is not already visible, this call will
not return until the dialog is hidden by calling setVisible(false) or
dispose.
setVisible(false): Hides the dialog and then returns on
setVisible(true) if it is currently blocked.
It is OK to call this
method from the event dispatching thread because the toolkit ensures
that other events are not blocked while this method is blocked.
Currently I am calling a method (showFrames) which pops up a JFrame which contains many editable text fields. I am storing the value of these text fields in a list (editedFields) which I need to use in the calling method. My issue is that my calling method is not waiting for the user to select ok/cancel before continuing so the list is not populated when I am trying to take action on it. I tried to overcome this by using a modal dialog to no avail. the method is being called here...
...
showFrames(longToShortNameMap);
if (editedFields != null) {
for (JTextField field : editedFields) {
System.out.println(field.getText());
}
}
...
and the showFrames method is implemented as:
private static void showFrames(Map<String, String> longToShortNameMap) {
final ToolDialog frame = new ToolDialog("Data Changed");
frame.setVisible(true);
frame.setModal(true);
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(400, 500);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
JPanel panel = new JPanel(new GridLayout(0, 2));
JPanel buttonPanel = new JPanel(new GridLayout(2, 0));
List<String> keys = new ArrayList(longToShortNameMap.keySet());
final List<JTextField> textFields = new ArrayList<>();
for (String key : keys) {
JLabel label = new JLabel(key);
JTextField textField = new JTextField(longToShortNameMap.get(key));
panel.add(label);
panel.add(textField);
textFields.add(textField);
}
JButton okButton = new JButton("OK"); //added for ok button
okButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
editedFields = textFields;
frame.setVisible(false);
frame.dispose();
}
});
JButton cancelButton = new JButton("Cancel");//added for cancel button
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
frame.dispose();
}
});
okButton.setVisible(true);//added for ok button
cancelButton.setVisible(true);//added for cancel button
buttonPanel.add(okButton);//added for ok button
buttonPanel.add(cancelButton);//added for cancel button
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setVisible(true);
scrollPane.setSize(500, 500);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(buttonPanel, BorderLayout.SOUTH);
}
the current behavior I observe is that when the JFrame pops up, all the fields will immediately print out instead of waiting for the user to click "OK". Effectively this means I am receiving the default values in the text fields instead of the edited values.
Note: ToolDialog extends JDialog
The basic problem that you have is that you are instantiating the Dialog first, making it visible, and then adding fields to it.
That is essentially incorrect. All objects should be added to it while you are instantiating the Frame/Dialog, preferably in the constructor call. Then, you make it visible when everything is ready.
Of course, you can add a new field to the frame after showing it already, but that is typically done based on some event, for example, when user clicks "Add a new number", then you add new text fields, etc to it.
So, the fix for you is simple, move the logic that adds the buttons, the lists, the panels etc, to the constructor, and then make that window visible.
You have 2 different issues here :
Waiting for a dialog.
Displaying the dialog correctly.
1.- Waiting for a dialog.
You should use a JDialog instead of a JFrame to make the window modal.
The window is not modal because you are showing it before setting it to modal. See JDialog.setModal :
Note: changing modality of the visible dialog may have no effect until
it is hidden and then shown again.
You need to switch theese two lines :
frame.setVisible(true);
frame.setModal(true);
An alternate way is to synchronize with a countdown latch:
CountDownLatch latch = new CountDownLatch(1);
.......
showFrames(longToShortNameMap);
latch.await(); // suspends thread util dialog calls latch.countDown
if (editedFields != null) {
.......
/// Dialog code
latch.countDown(); // place it everywhere you are done with the dialog.
dispose();
2.- Displaying the dialog correctly.
Place frame.setVisible(true) as the last line of showFrames.
I have a JFrame which consists of some Swing components. One button has an ActionListener to add an extra button to the frame (so the user can add more information).
Now I want the window (jframe) to resize whenever a new component is added. Now the components get smaller whenever a new one is added, but the frame stays the same size.
Here is the code of the actionlistener:
addAnswerButtonMA.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
answerFieldsMA.add(new JTextField());
checkBoxesMA.add(new JCheckBox());
multipleanswerPanel.add(answerFieldsMA.get(answerFieldsMA.size() - 1));
multipleanswerPanel.add(checkBoxesMA.get(checkBoxesMA.size() - 1));
multipleanswerPanel.revalidate();
validate();
}
});
Some background (not sure if needed):
I'm making a quiz program, the administrator can add questions to the quiz by using a separate gui. If he wants to add a Multiple-answer question, he can add an extra answer by clicking the addAnswerbuttonMA to make an extra field and checkbox appear. The field represents the answer and the checkbox represents whether the answer is correct or not.
Packing the frame solves it.
addAnswerButtonMA.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
answerFieldsMA.add(new JTextField());
checkBoxesMA.add(new JCheckBox());
multipleanswerPanel.add(answerFieldsMA.get(answerFieldsMA.size() - 1));
multipleanswerPanel.add(checkBoxesMA.get(checkBoxesMA.size() - 1));
multipleanswerPanel.revalidate();
validate();
pack()
}
});