I'm trying to find a way how to update a panel content after changing a state variable.
Concretely in the example below, there is simple JPanel inside JFrame with two buttons. When the app starts, its state variable ("window") equals "home" so home button should be invisible. After clicking on the page button the state variable change and so both buttons visibility should change after frame repainting. (i.e. the page button should disappear and the home button should appear).
In this case, it is possible to solve it without the state variable just using setVisibility() method for buttons. But in my app, I would like to have more JComponetns connected to the state variable. Is there a way how to do it?
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class JPanelUpdateTest {
private JFrame frame;
private String window = "home";
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JPanelUpdateTest window = new JPanelUpdateTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public JPanelUpdateTest() {
initialize();
}
private void initialize() {
frame = new JFrame("JPanelUpdateTest");
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
JButton btnHome = new JButton("home");
btnHome.setVisible(window == "home" ? false : true);
btnHome.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
window = "page";
panel.revalidate();
frame.repaint();
}
});
panel.add(btnHome);
JButton btnPage = new JButton("page");
btnPage.setVisible(window == "page" ? false : true);
btnPage.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
window = "home";
panel.revalidate();
frame.repaint();
}
});
panel.add(btnPage);
}
}
The problem is that initialize is only being called once, at object creation, and it should only be called once, and because of this the setVisible(...) code is not being called from the ActionListeners. Instead you need to put the mechanisms for changing the views within the ActionListeners themselves, not just changing state, not unless you are using a "bound property" and PropertyChangeListeners.
Myself, I'd recommend using a CardLayout to assist you in your swapping, and rather than directly changing Strings, call a public method of your class -- planning for when and if the ActionListener (controller) code is ever removed from the view class.
Also, regarding:
btnPage.setVisible(window == "page" ? false : true);
don't compare Strings using == or !=. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two object references are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here.
Also, if all you want to do is change the text and behavior that a JButton is doing, then you can change this easily by using setText(...) to change only the text, and for a deeper change, call setAction(Action action) to change text and state.
Related
As for testing-reasons I tried to open a JDialog window with the panel and its contents of the main application frame. As I already had anything in there I wanted to see if I could simply set the JDialogs contentPane to the one I passed over. So in simplyfied form this came together:
testsforSO.java :
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testsforSO extends JFrame {
private static final long serialVersionUID = -3890178393751567629L;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
testsforSO frame = new testsforSO();
frame.setSize(300, 300);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public testsforSO() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("I am the Frame");
getContentPane().setLayout(new BorderLayout(0, 0));
JPanel panel = new JPanel();
panel.setLayout(null);
JButton btnRestart = new JButton("Restart");
btnRestart.setBounds(10, 10, 50, 50);
btnRestart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
testsforSO.main(null);
dispose();
}
});
panel.add(btnRestart);
getContentPane().add(panel);
repaint();
// -----------DELETE These comments-------------
// JDialog myDialg = new JDialog(this);
// myDialg.setContentPane(panel);
// myDialg.setVisible(true);
// myDialg.setSize(300,300);
// myDialg.setLocation(new Point(250, 250));
// myDialg.setTitle("I am Dialog from within the script");
myDialog.main(panel);
}
}
and myDialog.java :
import java.awt.Container;
import java.awt.EventQueue;
import javax.swing.JDialog;
public class myDialog extends JDialog {
private static final long serialVersionUID = 7079322237622743228L;
public static void main(Container myContainer) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
myDialog frame = new myDialog(myContainer);
frame.setVisible(true);
frame.setContentPane(myContainer);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public myDialog(Container myContainer) {
setContentPane(myContainer);
getContentPane().setLayout(null);
setBounds(200,200,200,200);
}
}
When starting the main frame I assumed it would contain the restarting button as well as the dialog does. But interestingly it was only the dialog with the button.
However when hitting it, the main frame properly restarted, a second dialog was set up and it contained the button again. This time however the main frame had the button as well, just without any function. Clicking on it does absolutely nothing.
Then I tried further and checked if that behaviour would change if I added the dialog directly into the main applications code (see the commented lines) and, starting the application once again only the dialog in its own class showed the button. Even hitting this one now restarted properly but the button won't show up on any other window except the lonely declared dialog.
What am I missing here and how could I refactor my code to work properly if even at all in this manner?
Understand that Swing components can only be present in one container, and while you may see the visual residue of a component in a container, the actual component is only present in the last container added to.
Myself, if I wanted dialog and jframe to have the same content pane components, I'd create a factory method to create the contentPane, and then use it to create two unique but identical contentPanes.
Also, I'd be remiss if I didn't mention something about your use of null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
For instance, when I ran your code, this is the dialog that I saw:
You hard coded the button's size to be too small to show its text on my platform. If you had used layout managers, and called pack() on the top-level window, the button would show appropriately.
When I was creating a bunch of JTextFields I saw that first one is selected. I want to deselect it, because I have focus listener and it's running automatically. Any clues?
SSCCE:
JTextField tf = new JTextField("hello");
tf.setForeground(Color.decode("0x8C8C8C")); // for nice comment inside the text field
textFieldKwotaWplacona.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e)
{
if(tf.getForeground() != Color.BLACK)
{
tf.setText("");
tf.setForeground(Color.BLACK);
}
} #Override
public void focusLost(FocusEvent arg0) {}});
//for deleting "nice comment" after click
tf.setBounds(//some bounds);
add(tf);
Repeat that process for another text field
EDIT2 :
actual code (I believe its sscce :P)
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class Main extends JFrame implements ActionListener
{
JTextField textFieldKwotaWplacona, textFieldOprocentowanie, textFieldDlugoscLokaty, textFieldKwotaOtrzymana;
Main()
{ setSize(500,300);
setLayout(null);
setTitle("Program do liczenia procentu składanego");
setDefaultCloseOperation(EXIT_ON_CLOSE);
textFieldKwotaWplacona = new JTextField("Ilość pieniędzy wpłaconych");
textFieldKwotaWplacona.setForeground(Color.decode("0x8C8C8C"));
textFieldKwotaWplacona.addActionListener(this);
textFieldKwotaWplacona.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e)
{
if(textFieldKwotaWplacona.getForeground() != Color.BLACK)
{
textFieldKwotaWplacona.setText("");
textFieldKwotaWplacona.setForeground(Color.BLACK);
}
} #Override
public void focusLost(FocusEvent arg0) {}});
textFieldKwotaWplacona.setBounds(10, 10, 100, 20);
add(textFieldKwotaWplacona);
textFieldOprocentowanie = new JTextField("Oprocentowanie");
textFieldOprocentowanie.setForeground(Color.decode("0x8C8C8C"));
textFieldOprocentowanie.addActionListener(this);
textFieldOprocentowanie.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e)
{
if(textFieldOprocentowanie.getForeground() != Color.BLACK)
{
textFieldOprocentowanie.setText("");
textFieldOprocentowanie.setForeground(Color.BLACK);
}
}
#Override
public void focusLost(FocusEvent arg0) {}});
textFieldOprocentowanie.setBounds(10, 40, 100, 20);
add(textFieldOprocentowanie);
}
#Override
public void actionPerformed(ActionEvent arg0)
{
// TODO Auto-generated method stub
}
public static void main(String[] args)
{
Main a=new Main();
a.setVisible(true);
}
}
I want to set focus to window or sth else, in order to prevent text from disappearing.
As discussed in the comments, I added a radio button to take the focus instead:
public class Main extends JFrame {
JTextField textFieldKwotaWplacona, textFieldOprocentowanie;
Main() {
setTitle("Program do liczenia procentu składanego");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
textFieldKwotaWplacona = new JTextField("Ilość pieniędzy wpłaconych");
textFieldKwotaWplacona.setForeground(Color.decode("0x8C8C8C"));
textFieldKwotaWplacona.addFocusListener(new FieldFocusListener(textFieldKwotaWplacona));
add(textFieldKwotaWplacona);
textFieldOprocentowanie = new JTextField("Oprocentowanie");
textFieldOprocentowanie.setForeground(Color.decode("0x8C8C8C"));
textFieldOprocentowanie.addFocusListener(new FieldFocusListener(textFieldOprocentowanie));
add(textFieldOprocentowanie);
JRadioButton btn = new JRadioButton("text");
add(btn);
pack();
btn.requestFocusInWindow();
}
private class FieldFocusListener extends FocusAdapter {
private JTextField field;
FieldFocusListener(JTextField field) {
this.field = field;
}
#Override
public void focusGained(FocusEvent e) {
if (field.getForeground() != Color.BLACK) {
field.setText("");
field.setForeground(Color.BLACK);
}
}
}
public static void main(String[] args) {
Main a = new Main();
a.setVisible(true);
}
}
Explanation
From the tutorial:
If you want to ensure that a particular component gains the focus the first time a window is activated, you can call the requestFocusInWindow method on the component after the component has been realized, but before the frame is displayed.
That means btn.requestFocusInWindow() must appear after pack() and before a.setVisible(true).
The reason you need another component to take the focus is that when a window is focused, a component inside it must gain the focus.
Notes:
If you want a better text field hint, see #camickr's answer.
Don't use null layout. Pick one that serves your GUI design (I picked FlowLayout just because it's fast to use, though probably not what you need).
Instead of setting the size of the frame, pack() after all components had been added.
Instead of creating the same focus listener for every text field, just create it as a class and reuse it. I show one way with passing the component to a constructor, but you can get rid of that and use e.getComponent() to get the text field instance.
In your constructor, you could use the method requestFocusInWindow().
This is what was working for me here-
After creating the JFrame, call frame.requestFocusinWindow();. This will make sure your text field is not focused.
Then, when you focus on the text field, the event is being fired.
tf.setForeground(Color.decode("0x8C8C8C")); // for nice comment inside the text field
Maybe you are trying to set a prompt for the text field that disappears when the text field gains focus?
If so, check out Text Field Prompt for a solution.
If not, then post a proper SSCCE, because I still can't guess what you are trying to do.
I want to display a TextField only when user has entered a value in Input field
Here is my code:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class PlayingAround {
JFrame frame;
JTextField display;
JTextField input;
public static void main(String[] args) {
PlayingAround obj = new PlayingAround();
obj.create();
}
private void create() {
frame = new JFrame();
display = new JTextField();
input = new JTextField();
display.setEditable(false);
display.setVisible(false);
input.addKeyListener(new Listener());
frame.add(BorderLayout.NORTH, display);
frame.add(BorderLayout.SOUTH, input);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Listener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
display.setVisible(true);
display.setText(input.getText());
}
}
}
But my problem is that the Display JTextField doesn't becomes visible until there are some events like Resizing the Window, Minimizing and maximizing the Window.
I tried calling frame.repaint() in the keyReleased Method but even it has not helped.
You should call revalidate() and repaint() on the container that holds the JTextField after placing the text field component in the container. The revalidate() call sends a request to the container's layout managers to re-layout its components. The repaint() then requests that the JVM request of the paint manager to redraw the newly laid out container and its child components. The repaint() is not always needed but is usually a good idea.
Also, don't use a KeyListener for this, but rather a DocumentListener on the first text component's Document. This way, if the user empties the first text component, you can make the second text component disappear if desired. Also, text can be entered without key presses, and you want to allow for that.
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.