I have a Swing GUI that allows a user to add JTextFields to the GUI as needed. When I run this locally on the console (on ubuntu), everything works fine.. When I run the GUI from Cygwin on a Windows box using X11 forwarding, everything starts out fine, but when I click the "add" button to put a new JTextField on the GUI, the text field shows up as expected, but I can't click in it or modify it, etc., for a long time. In fact, I can't click in the original text fields either.. After a little more than 30 seconds, the text fields come back to life and work normally until I click "add" again.
I've included a SSCCE below that demonstrates the problem. Again, this only seems to happen when running with X11-forwarding, and if I run on the Ubuntu console directly, it works as expected, so I'm not sure if this will be reproduce-able for everyone else.
One last piece of information - in my real program, clicking the add button causes a JComboBox and two JTextFields to be added. The combo box is responsive right away, but all text fields on the GUI (new ones and old ones too) are not.
HmmFrame.java:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class HmmFrame extends JFrame
{
ArrayList< JTextField > fields;
JPanel mainPan;
JButton addButton;
HmmFrame()
{
super("Hmmm");
JTextField curField;
fields = new ArrayList< JTextField >();
setLayout(new FlowLayout());
mainPan = new JPanel(new FlowLayout());
this.add(mainPan);
addButton = new JButton("Add");
addButton.addActionListener(new HmmListener());
this.add(addButton);
curField = new JTextField("Try");
fields.add(curField);
updateGUI();
setVisible(true);
}
public void updateGUI()
{
mainPan.removeAll();
for (JTextField curField : fields)
{
mainPan.add(curField);
}
pack();
}
public class HmmListener implements ActionListener
{
public void actionPerformed(ActionEvent actEv)
{
JTextField curField;
curField = new JTextField("New One" + fields.size());
fields.add(curField);
updateGUI();
}
}
}
Hmm.java (driver)
public class Hmm
{
public static void main(String [] args)
{
HmmFrame hmmFrame;
hmmFrame = new HmmFrame();
}
}
Related
So I've made a basic UI that shows text fields that will alert the user if the contents is outside of given bounds by causing a label to appear below it. This occurs if the user hits return or Tabs away from the field.
There is also a button that will advance the program so long as all of the fields are correct. If they are not it will cause the text fields to 'flash' (animation background red back to white).
This works fine except for one little bug - if the user enters incorrect data and immediately clicks the button, without first leaving the field, the focus listener fires and adds the label below the text field, but the click button action never fires (no flash). This appears to be due to the FocusListener event calling revalidate() on the panel and or pack() on the enclosing jframe.
Here's a working minimal example to demonstrate the problem
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* Demonstration that running revalidate() or JFrame.pack() in FocusListener
* (on a textField) causes the action listener for a JButton to never fire.
*
* This is only a problem if the contents of the frame are changed (ie. only
* happens once when label is added).
*/
public final class App {
private App() {
JFrame jFrame = new JFrame();
JPanel main = new JPanel();
MyPanel myPanel = new MyPanel();
JButton button = new JButton("Click");
button.addActionListener(event->{
/* with the code as it is this will never print if
the button is pressed while textField has focus
and label is not yet displayed */
System.out.print("\n Click has been pressed");
});
main.add(myPanel);
main.add(button);
jFrame.add(main);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new App());
}
/**
* Creates a panel containing a text box.
* when this text box looses focus it causes
* a label to be added and the frame to resize (.pack())
*/
class MyPanel extends JPanel{
JLabel label;
JTextField textField;
public MyPanel(){
label = new JLabel("hello");
textField = new JTextField(10);
this.add(textField);
textField.addFocusListener(new Handler(this));
}
private class Handler implements FocusListener{
JPanel panel;
public Handler(JPanel panel){
this.panel = panel;
}
#Override
public void focusGained(FocusEvent e) {
}
#Override
public void focusLost(FocusEvent e) {
// if this line is removed
panel.add(label);
// if the below two lines are removed
// button ActionListener will fire
panel.revalidate();
SwingUtilities.getWindowAncestor(panel).pack(); // side note if this is called is revalidate() needed?
}
}
}
}
Any advice on how to fix this would be great. One thing to note is that in the real program the MyPanel class would be in its own file, if that affects any solutions.
Cheers.
=============== EDIT ======================
I was running it in my IDE (vscode) where the problem occured. When I compiled it and ran it from the terminal it worked fine. I presume its some quirk of the IDE.
I have a JComboBox that is editable. When the user enters a new item, I want that added to the list and display it as the selected item. I am able to add it to the list but I cannot seem to make it display as the selected item. By default I display an empty string ("") which is what the user would edit to add the new item.
public class EventComboBoxListener implements ActionListener {
private JComboBox<String> eventBox=null;
public EventComboBoxListener(JComboBox<String> event_) {
eventBox=event_;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Selected: " + eventBox.getSelectedItem());
System.out.println(", Position: " + eventBox.getSelectedIndex());
if (eventBox.getSelectedIndex() < 0) {
eventBox.addItem(eventBox.getSelectedItem().toString());
eventBox.setSelectedItem(eventBox.getSelectedItem().toString());
}
}
}
It doesn't make sense to me that I have to use setSelectedItem with the getSelectedItem. That it does not work is no surprise but I don't know what else to do. The newly added item shows up in the list as it should but how do I make it the selected item in the display at the same time? I can select it after but that should not be necessary.
Added MVCE:
Main
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
public class Test {
public static void main(String[] args) {
String[] list= {"","A","B","C"};
TestTableModel model=new TestTableModel(null,new String[] {"col1","col2"});
JTable table=new JTable(model);
JDialog dialog=new JDialog();
JScrollPane scroller=new JScrollPane(table);
JComboBox<String> box=new JComboBox<String>(list);
box.setEditable(true);
box.setSelectedIndex(0);
box.addActionListener(new EventComboBoxListener(box));
JTextField field=new JTextField();
field.setPreferredSize(new Dimension(75,30));
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setLayout(new FlowLayout());
dialog.setSize(new Dimension(400,100));
dialog.add(scroller);
dialog.pack();
dialog.setVisible(true);
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(box));
table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(field));
model.insertRow(0,new Object[] {"","placeholder"});
}
}
TestTableModel class
import javax.swing.table.DefaultTableModel;
public class TestTableModel extends DefaultTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
public TestTableModel(Object[][] data_,String[] columnNames_) {
super(data_,columnNames_);
}
}
First of all some comments about the MCVE (since you will be including one with every question in the future).
We expect the code so be in a single source file so we can easily copy/paste compile and test. We don't want 3 files lying around on our machine that we need clean up after testing.
Only relevant code directly related to the problem should be included. Why do you have the TestTableModel class. Are the "column names" relevant to the problem? The point is always test your MCVE using standard JDK classes when possible.
Regarding the EventComboListener class. Again, this can be added to the combo box by using and annoymouse inner class or a lambda. This keeps the code in a single class.
The newly added item shows up in the list as it should but how do I make it the selected item in the display at the same time?
I found that playing with your MCVE the ActionListener of the combo box is invoked at different times.
So my suggestion is to add the ActionListener to the editor of the combo box. Then we know for sure the ActionListener is only invoked when you press the Enter key. Once you press the Enter key the editor is stopped and the value is saved to the model.
So the logic would be something like:
//box.addActionListener(new EventComboBoxListener(box));
ComboBoxEditor editor = box.getEditor();
JTextField textField = (JTextField)editor.getEditorComponent();
textField.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
String item = textField.getText();
DefaultComboBoxModel model = (DefaultComboBoxModel)box.getModel();
if (model.getIndexOf(item) == -1)
{
box.addItem(item);
box.setSelectedIndex( box.getItemCount() - 1 );
}
}
});
So the trick is to set the select index (not the selected item). But first the logic checks to make sure the item has not already been added to the combo box.
I have a code that opens up a JOptionPane dialog box once the user hits a button. The first thing I want to do is close the first JFrame as soon as the user hits one of the buttons. I have tried doing this
setVisible(false); // Delete visibility
dispose(); //Delete window
but the original JFrame doesn't close as soon as a button is pressed. The goal is to have two buttons. When one is pressed, show a JOptionPane box, while simultaneously closing the first JFrame window. How can I do that? Next, after the ok is pushed in the new JOptionPane I wan't to stimulate what would be an action listener. I do this by calling the method
sinceyoupressedthecoolbutton();
right after my JOptionPane declaration. Here is where the second issue starts, it displays the JOptionPane perfectly, but doesn't go to the method
sinceyoupressedthecoolbutton();
I don't know if the problem is in the method calling or the content of the method. Basically, after ok is pressed on the JOptionPane, I wan't to move to another method, which opens a new JLabel.
Here is the code:
package Buttons;
import java.awt.Dimension;
import java.awt.FlowLayout; //layout proper
import java.awt.event.ActionListener; //Waits for users action
import java.awt.event.ActionEvent; //Users action
import javax.swing.JFrame; //Window
import javax.swing.JLabel;
import javax.swing.JButton; //BUTTON!!!
import javax.swing.JDialog;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane; //Standard dialogue box
public class ButtonClass extends JFrame {
private JButton regular;
private JButton custom;
public ButtonClass() { // Constructor
super("The title"); // Title
setLayout(new FlowLayout()); // Default layout
regular = new JButton("Regular Button");
add(regular);
custom = new JButton("Custom", b);
add(custom);
Handlerclass handler = new Handlerclass();
Otherhandlerclass original = new Otherhandlerclass();
regular.addActionListener(handler);
custom.addActionListener(original);
//THIS WAS MY FIRST PROBLEM, I WANT TO CLOSE THE FIRST JFRAME WINDOW AS THE USER HITS OK
setVisible(false); // Close the show message dialog box
dispose();
}
public class Handlerclass implements ActionListener { // This class is
// inside the other
// class
public void actionPerformed(ActionEvent eventvar) { // This will happen
// when button is
// clicked
JOptionPane.showMessageDialog(null, String.format("%s", eventvar.getActionCommand())); //opens a new window with the name of the button
}
}
public class Otherhandlerclass implements ActionListener {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,"Since you pressed that button, I will open a new window when you press ok, okay?");
//Code works up until here
sinceyoupressedthecoolbutton(); //THIS METHOD SHOULD OPEN A NEW WINDOW!
}
public void sinceyoupressedthecoolbutton() {
JDialog YES = new JDialog();
JLabel label = new JLabel("Here is that new window I promised you!");
add(label);
YES.setDefaultCloseOperation(JDialog.EXIT_ON_CLOSE);
YES.setSize(500, 500);
YES.setVisible(true);
}
public class okay implements ActionListener {
public void actionPerformed(ActionEvent ok) {
}
}
}
}
Help would be appreciated!
You're working in a Event Driven Environment, not a linear processing one. This means that you run some code and then wait (the waiting is done for you) for some event to occur and then you respond to it...
Nothing can happen till the user presses the custom button, so it's pointless trying to close the frame before then
When your Otherhandlerclass's actionPerformed is triggered, obviously you show the JOptionPane pane, this will block the flow of the execution until it's closed. At this point, you should have the opportunity to the dispose of the original window.
So instead of calling setVisible(false) and dispose in your constructor, it would be better to move it to Otherhandlerclass
public class Otherhandlerclass implements ActionListener {
public void actionPerformed(ActionEvent e) {
dispose();
JOptionPane.showMessageDialog(null, "Since you pressed that button, I will open a new window when you press ok, okay?");
sinceyoupressedthecoolbutton();
}
public void sinceyoupressedthecoolbutton() {
JDialog YES = new JDialog();
JLabel label = new JLabel("Here is that new window I promised you!");
YES.add(label);
YES.setSize(500, 500);
YES.setVisible(true);
}
public class okay implements ActionListener {
public void actionPerformed(ActionEvent ok) {
}
}
}
Having said that, I'd encourage you to have a read of The Use of Multiple JFrames, Good/Bad Practice? and maybe consider using something like How to Use CardLayout instead
I'm trying to program my first GUI-class in Java, using the Window Builder. Ok, the GUI is ready but has no functions yet (it contains 10 checkboxes (yes, they are all neccessary) and 2 buttons and a JTextField, so nothing special). So I just drag'n'dropped the checkboxes and button into the window, I haven't coded anything yet.
I have two classes:
GUI.java -> only for the layout
Main.java -> should get 'inputs' from GUI.java
Now the user should check or uncheck the checkboxes and then finally press a button.
But how do I 'read out' if a checkbox is checked or not - I have two classes?
I have to add that I'm a beginner to Java and especially to GUI-programming, but I just want to learn it. I would be happy to receive some help but NOT the complete code.
Basically you instantiate an object of your GUI from the Main.java. Then you have access to this GUI (assumed you have setter/getter-methods or the Components in the GUI are public). In the GUI constructor you call all builder methods, so when you then call new GUI() from Main.java, you got a) the GUI running and b) access to it from Main.java
For your specific question about the checkboxes, you can call
nameOfCheckbox.isSelected()
which returns a boolean wheter the checkbox is checked or not.
Viceversa: since your Main.java has (or should have) static methods (like the main-method), you can then simply call Main.anyMethodName() from GUI.java (assuming this anyMethod is static) and pass data from the "visual area" to the "logic area" (it is recommended to seperate this two componentes as good as possible).
I know you said you didn't want the full, code but this isn't really it, just a very basic working demo of what you want to do
Gui.java
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Gui {
JFrame frame;
JButton button;
JCheckBox checkBox;
JLabel label;
public Gui() {
frame = new JFrame("demo");
button = new JButton("is it checked?");
checkBox = new JCheckBox();
label = new JLabel("no");
JPanel panel = new JPanel();
panel.add(checkBox);
panel.add(button);
panel.add(label);
frame.add(panel);
frame.pack();
//frame.setSize(200, 60);
frame.setResizable(false);
frame.setLocation(400, 400);
frame.setVisible(true);
}
// method to add an action listener to the gui's
// private button
public void setButtonActionListener(ActionListener al) {
button.addActionListener(al);
}
// gui method to check if box is checked
public boolean isBoxChecked() {
return checkBox.isSelected();
}
// method to set lable
public void setText(String text) {
label.setText(text);
}
}
Main.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
public static void main(String[] args) {
// create an instance of your gui class
final Gui gui = new Gui();
// add the action listener to the button
// notice how we reference the gui here by running the methods in the
// gui class
// this action listener could be created in the gui
// class but in general you don't want to do that because actions will
// involve multiple classes
gui.setButtonActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
gui.setText((gui.isBoxChecked() ? "yes" : "no"));
}
});
}
}
Attach an ItemListener.
You can determine if the box is rising (unchecked to checked) or falling (checked to unchecked) with the following line in itemStateChanged(ItemEvent e)
boolean selected = e.getStateChange() == ItemEvent.SELECTED;
To determine whether it is checked when it is not changing, just use isSelected()
Either like that:
checkbox.isSelected();
Or this would be a way by an Itemlistener which will be called if there is a change:
checkbox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) {
foo = false;
} else {
foo = true;
}
}
});
You could expose all of your gui objects as fields in your gui class
public JTextField getNameTextField() {
return nameTextField;
}
public JCheckBox getCheckBox1() {
return checkBox1;
}
and then in main:
if (gui.getCheckBox1().isSelected())
// do stuff
Assuming your checkbox is an object named "myCheckBox", you can check if it's selected or not by using:
myCheckBox.isSelected()
Returns true if the checkbox is selected.
I reccomend you to check Java's tutorials on how to use the various GUI components, e.g:
http://docs.oracle.com/javase/tutorial/uiswing/components/button.html
I have two Jframes where frame1 has some text fields and when a button on frame1 is clicked, I open another JFrame which contains a search box and a JTable containing search results.
When I click on a result row on JTable, I want that particular values to be reflected in the frame1 text fields.
I tried passing the JFrame1's object as a parameter but I have no clear idea on how to achieve this.
Any help would be highly appreciated.
Thanks
First of all, your program design seems a bit off, as if you are using a JFrame for one of your windows where you should in fact be using a JDialog since it sounds as if one window should be dependent upon the other.
But regardless, you pass references of GUI objects the same as you would standard non-GUI Java code. If one window opens the other (the second often being the dialog), then the first window usually already holds a reference to the second window and can call methods off of it. The key often is when to have the first window call the second's methods to get its state. If the second is a modal dialog, then the when is easy -- immediately after the dialog returns which will be in the code immediately after you set the second dialog visible. If it is not a modal dialog, then you probably want to use a listener of some sort to know when to extract the information.
Having said this, the details will all depend on your program structure, and you'll need to tell us more about this if you want more specific help.
For a simple example that has one window open another, allows the user to enter text into the dialog windows JTextField, and then places the text in the first window's JTextField, please have a look at this:
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class WindowCommunication {
private static void createAndShowUI() {
JFrame frame = new JFrame("WindowCommunication");
frame.getContentPane().add(new MyFramePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// let's be sure to start Swing on the Swing event thread
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MyFramePanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton openDialogeBtn = new JButton("Open Dialog");
// here my main gui has a reference to the JDialog and to the
// MyDialogPanel which is displayed in the JDialog
private MyDialogPanel dialogPanel = new MyDialogPanel();
private JDialog dialog;
public MyFramePanel() {
openDialogeBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openTableAction();
}
});
field.setEditable(false);
field.setFocusable(false);
add(field);
add(openDialogeBtn);
}
private void openTableAction() {
// lazy creation of the JDialog
if (dialog == null) {
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
dialog = new JDialog(win, "My Dialog",
ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(dialogPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
}
dialog.setVisible(true); // here the modal dialog takes over
// this line starts *after* the modal dialog has been disposed
// **** here's the key where I get the String from JTextField in the GUI held
// by the JDialog and put it into this GUI's JTextField.
field.setText(dialogPanel.getFieldText());
}
}
class MyDialogPanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton okButton = new JButton("OK");
public MyDialogPanel() {
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
okButtonAction();
}
});
add(field);
add(okButton);
}
// to allow outside classes to get the text held by the JTextField
public String getFieldText() {
return field.getText();
}
// This button's action is simply to dispose of the JDialog.
private void okButtonAction() {
// win is here the JDialog that holds this JPanel, but it could be a JFrame or
// any other top-level container that is holding this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose();
}
}
}
You'd do a very similar technique to get information out of a JTable.
And again, if this information doesn't help you, then please tell us more about your program including showing us some of your code. The best code to show is a small compilable example, an SSCCE similar to what I've posted above.