I have a JFrame that I want closed when the user clicks off of it. I have two JTextFields and a JButton (username, password, submit). When I give them all the FocusListener, anytime the user goes from one field to another the window closes. How can I allow the user to go from field to field and only close it if the user clicks anywhere OUT of the pop up window?
public class LoginForm {
static JTextField userName;
static JTextField password;
static JButton submit;
JFrame main;
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
UserSession session;
public LoginForm(){
Handler handle = new Handler(); //inner class
LoginFormFocusListener fl = new LoginFormFocusListener(); //inner class
main = new JFrame("Please Login");
main.setUndecorated(true);
main.setBounds((dim.width/2) - (500/2),(dim.height/2) - (150/2),500,150);
main.setVisible(true);
main.setAlwaysOnTop(true);
main.setResizable(false);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
userName = new JTextField(10);
password = new JTextField(10);
main.setLayout(new GridLayout(0,1));
JPanel panel = new JPanel();
main.add(panel);
panel.add(new JLabel("Username: "));
panel.add(userName);
panel.add(new JLabel("Password: "));
panel.add(password);
submit = new JButton("Submit");
panel.add(submit);
userName.addFocusListener(fl);
password.addFocusListener(fl);
submit.addFocusListener(fl);
submit.addActionListener(handle);
}
}
... (unimportant methods and "Handler" class omitted)
public class LoginFormFocusListener implements FocusListener{
public void focusGained(FocusEvent fe) {
System.out.println("focus gained...");
System.out.println("click off of this window to close...");
}
public void focusLost(FocusEvent fe){
System.out.println("focus lost...");
WindowEvent winEvt = new WindowEvent(main, 0);
winEvt.getWindow().dispose();
}
}
//test
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new LoginForm();
}
});
}
Don't use a FocusListener for this since these are for components that gain and lose the focus, not for top level windows. Perhaps use a WindowListener listening for the window is deactivated or iconified.
For example:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class WindowListenerFun {
public static void main(String[] args) {
JPanel panel = new JPanel();
panel.add(new JTextField(10));
panel.add(new JButton("button"));
JFrame frame = new JFrame("Bad Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent wEvt) {
((JFrame)wEvt.getSource()).dispose();
}
#Override
public void windowDeactivated(WindowEvent wEvt) {
((JFrame)wEvt.getSource()).dispose();
}
});
}
}
EDIT: I misread your code; the other answer is correct--you need to use a WindowFocusListener instead of a FocusListener.
public class Listener extends WindowAdapter
{
public void windowLostFocus(WindowEvent e)
{
Window w = e.getWindow();
e.setVisible(false);
e.dispose();
}
}
and
main.addWindowFocusListener(new Listener());
Edit2: replaced placeholder with window closing code.
Then you add a focus listener to individual menu components, it gets fired whenever a component loses focus. You only want it to get fired when the window loses focus, so add it to the window instead.
main.addWindowFocusListener(f1);
should fix your problem.
Related
ParentFrame shows ArrayList and one "ADD" Button. Once I click "ADD" Button on ParentFrame, then ChildFrame shows up.
On ChildFrame, I type in a String and click "OK" Button then it should transfer its String to ParentFrame. Finally ParentFrame should be repainted with newly added String.
I'm having trouble with repainting but also I might failed to send String from Child to Parent since Parent didn't get repainted.
I tried several things in two or three other points of view but following code seems like to work but......
I need your help!!
ParentFrame
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
#SuppressWarnings("serial")
public class parentFrame extends JFrame {
ArrayList<String> list = new ArrayList<>(){{add("test1"); add("test2");}};
JButton add;
JPanel big, small;
JLabel content;
childFrame addFrame;
public parentFrame() {
super("parent frame");
super.setLayout(new BorderLayout());
super.setSize(600,600);
big = new JPanel();
for(int i=0; i<list.size(); i++) {
content = new JLabel();
content.setText(list.get(i));
big.add(content);
}
super.add(big, BorderLayout.CENTER);
add = new JButton("ADD");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
addFrame = new childFrame();
/* By next 3 lines, I'm trying to transfer the value of childFrame's test to this parentFrame's list. */
list.add(addFrame.getTestString());
big.revalidate();
big.repaint();
}
});
super.add(add, BorderLayout.SOUTH);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new parentFrame();
}
}
2.ChildFrame
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
#SuppressWarnings("serial")
public class childFrame extends JFrame {
String test;
JTextField name;
JButton ok, cancel;
public childFrame() {
super("child frame");
super.setLayout(new BorderLayout());
super.setSize(400,200);
JPanel centerPanel = new JPanel(new GridLayout(1,1));
centerPanel.setSize(150, 100);
name = new JTextField();
centerPanel.add(name);
JPanel bottomPanel = new JPanel(new FlowLayout());
ok = new JButton("OK");
ok.addActionListener(new OKListener());
super.add(ok);
cancel = new JButton("CANCEL");
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
bottomPanel.add(cancel);
bottomPanel.add(ok);
super.add(centerPanel, BorderLayout.CENTER);
super.add(bottomPanel, BorderLayout.SOUTH);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class OKListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
test = name.getText();
dispose();
}
}
public String getTestString() {
return test;
}
}
Your problem is here:
public void actionPerformed(ActionEvent e) {
addFrame = new childFrame();
list.add(addFrame.getTestString());
big.revalidate();
big.repaint();
}
Since your child frame is not a modal window (for example, a JOptionPane is a modal dialog window), it does not halt program flow in the calling window. You call .getTestString() immediately on creation of the child frame but before the user has had any chance to enter in any data (again, because program flow in the calling window is not halted).
The solution is to make your child "frame" in fact a modal JDialog. This will pretty much solve the whole issue. So, don't have the child frame extend from JFrame, but rather extend JDialog, and use the JDialog constructor that makes it modal (see the JDialog API).
e.g.,
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
#SuppressWarnings("serial")
// note that class names should begin with an upper-case letter
public class ChildFrame extends JDialog {
String test;
JTextField name;
JButton ok, cancel;
public ChildFrame(JFrame parentFrame) {
// the true parameter makes this modal
super(parentFrame, "child frame", true);
Now this dialog window will freeze program flow from the calling code as soon as the dialog is set visible, and the calling code flow won't resume until this dialog is no longer visible.
Also, please have a look at The Use of Multiple JFrames, Good/Bad Practice?
An alternative to this is to continue to use multiple JFrames (not recommended!!), and add a WindowListener to the "child" window, listening for windows closing events, and then getting the information from your dialog in call-back method that is activated when the windows closing event occurs.
For a working example:
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ParentGuiPanel extends JPanel {
private DefaultListModel<String> listModel = new DefaultListModel<>();
private JList<String> jList = new JList<>(listModel);
private JButton addButton = new JButton("Add");
private JDialog childDialog;
private ChildGuiPanel childPanel = new ChildGuiPanel();
public ParentGuiPanel() {
listModel.addElement("Test 1");
listModel.addElement("Test 2");
jList.setPrototypeCellValue("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
jList.setVisibleRowCount(8);
JScrollPane scrollPane = new JScrollPane(jList);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
addButton.addActionListener(e -> addActionPerformed(e));
addButton.setMnemonic(KeyEvent.VK_A);
JPanel buttonPanel = new JPanel();
buttonPanel.add(addButton);
setLayout(new BorderLayout());
add(scrollPane);
add(buttonPanel, BorderLayout.PAGE_END);
}
private void addActionPerformed(ActionEvent e) {
Window window = null;
if (childDialog == null) {
window = SwingUtilities.getWindowAncestor(this);
if (window == null) {
return;
}
childDialog = new JDialog(window, "Child GUI", ModalityType.APPLICATION_MODAL);
childDialog.add(childPanel);
childDialog.pack();
childDialog.setLocationRelativeTo(window);
}
if (childDialog != null) {
childDialog.setVisible(true);
String text = childPanel.getText();
if (!text.trim().isEmpty()) {
listModel.addElement(text);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame mainGui = new JFrame("Main GUI");
mainGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ParentGuiPanel mainPanel = new ParentGuiPanel();
mainGui.add(mainPanel);
mainGui.pack();
mainGui.setLocationRelativeTo(null);
mainGui.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class ChildGuiPanel extends JPanel {
private JTextField textField = new JTextField(15);
private JButton okButton = new JButton("OK");
private JButton cancelButton = new JButton("Cancel");
public ChildGuiPanel() {
okButton.addActionListener(e -> okActionPerformed(e));
cancelButton.addActionListener(e -> cancelActionPerformed(e));
textField.addActionListener(e -> okActionPerformed(e));
okButton.setMnemonic(KeyEvent.VK_O);
cancelButton.setMnemonic(KeyEvent.VK_C);
add(new JLabel("Text: "));
add(textField);
add(okButton);
add(cancelButton);
}
public String getText() {
return textField.getText();
}
private void disposeWindow() {
textField.selectAll();
Window window = SwingUtilities.getWindowAncestor(this);
if (window != null) {
window.dispose();
}
}
private void okActionPerformed(ActionEvent e) {
disposeWindow();
}
private void cancelActionPerformed(ActionEvent e) {
textField.setText("");
disposeWindow();
}
}
My JPanel and JTextField are for some reason not appearing. The programs only task is to add a number to the counter every time the button is clicked. No compiling errors nor console issues. Simply not showing up??
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Swing
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
final JFrame mainFrame = new JFrame ("Counter (Program 1/2)");
mainFrame.setVisible(true);
mainFrame.setSize(400, 200);
mainFrame.setLayout(new BorderLayout());
mainFrame.setLocationRelativeTo(null);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton countButton = new JButton("Count up");
mainFrame.add(countButton, BorderLayout.SOUTH);
countButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JTextField clicks = new JTextField(BorderLayout.CENTER);
JPanel firstPanel = new JPanel();
mainFrame.add(firstPanel);
mainFrame.add(clicks, BorderLayout.NORTH);
int counter = 1;
counter++;
String textField = String.valueOf(counter);
clicks.setText(textField);
}
});
}
});
}
}
Don't add the JTextField and JPanel inside the ActionListener. This makes no sense since you'll be re-adding new components each time the button is pressed. Instead add them on GUI creation, before calling setVisible(true) on the GUI. Then update the text field's text in the ActionListener.
As a side recommendation: try to make your class more object oriented by giving it fields, a constructor, and getting most all of that code out of the static main method.
Your mistakes:
Add clicks and firstpanel to the frame in run method, not in the actionPerformed
BorderLayout.CENTER should be pass as a parameter to add method, not to the text field constructor.
Define count as static. This is not the best way but in your situation it is the easiest way.
Call mainFrame.setVisible(true); after you added all your components.
Here is the working code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Swing {
public static int counter = 1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame mainFrame = new JFrame("Counter (Program 1/2)");
mainFrame.setSize(400, 200);
mainFrame.setLayout(new BorderLayout());
mainFrame.setLocationRelativeTo(null);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton countButton = new JButton("Count up");
mainFrame.add(countButton, BorderLayout.SOUTH);
final JTextField clicks = new JTextField(String.valueOf(counter));
JPanel firstPanel = new JPanel();
mainFrame.add(firstPanel, BorderLayout.CENTER);
mainFrame.add(clicks, BorderLayout.NORTH);
countButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
String textField = String.valueOf(counter);
clicks.setText(textField);
}
});
mainFrame.setVisible(true);
}
});
}
}
I need help with this code, I'm trying to make a simple cookie clicker type game, I have most the code done, but for some reason, when I try to add the JLabel to the frame, it creates an error, I was hoping one of you guys could help me out, I'm fairly new to Java, thanks for the help!
//Variables
static int clicked = 0;
private FlowLayout layout;
private Container container;
public static void main(String [] args) {
//Declaring the buttons, panels, etc...
JButton button = new JButton("Click");
JPanel panel = new JPanel();
panel.add(button);
final JFrame frame = new JFrame("Button Pressed");
frame.setSize(400, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.add(panel);
//Action Listener Code
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Execute when button is pressed
clicked++;
System.out.println("Button pressed " + clicked + " times!");
}
}
}
You can add an JLabel then update its text when button is clicked.
Note: call JFrame.setVisible(true) in the end when all the component is added.
sample code:
// Declaring the buttons, panels, etc...
JButton button = new JButton("Click");
final JLabel label = new JLabel();
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
clicked++;
label.setText("Button pressed " + clicked + " times!");
}
});
JPanel panel = new JPanel();
panel.add(button);
panel.add(label);
final JFrame frame = new JFrame("Button Pressed");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
Find more examples here and here
The basic principle is relatively easy. In order to add something to something else, you first need to have access (or a reference to) the thing you want to add to.
While there are a number of ways you might achieve this, the simplest might be to use an instance/class field. This field would then be accessible from anywhere within the class, for example
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ClickTest {
public static void main(String[] args) {
new ClickTest();
}
private JPanel panel;
public ClickTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
//Declaring the buttons, panels, etc...
JButton button = new JButton("Click");
panel = new JPanel();
panel.add(button);
final JFrame frame = new JFrame("Button Pressed");
frame.setSize(400, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.add(panel);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.add(new JLabel("You clicked me"));
panel.revalidate();
}
});
}
});
}
}
Take a look at Creating a GUI With JFC/Swing and Understanding Class Members for more details
Okay I can get text fields and normal text and even images to show but I can not get a button to show. I am not sure what I am doing wrong because I have done the same steps for the rest. Any help would be great thanks!
package EventHandling2;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import EventHandling.GUITest;
public class EventMain extends JFrame{
private JLabel label;
private JButton button;
public static void main(String[] args) {
EventMain gui = new EventMain ();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when click x close program
//gui.setSize(600, 300);
gui.setVisible(true);
gui.setTitle("Button Test");
}
public void EventMain(){
setLayout(new FlowLayout());
button = new JButton ("click for text");
add(button);
label = new JLabel ("");
add(label);
Events e = new Events();
button.addActionListener(e);
}
public class Events implements ActionListener {
public void actionPerformed(ActionEvent e) {
label.setText("Now you can see words");
}
}
}
The problem is with the method: void EventMain()
Constructor has NO return type. Just remove "void". The code will work just fine.
Your actionListener(e) contains a minor control structure error:
public void actionPerformed(ActionEvent e) {
label.setText("Now you can see words");
}
Change to:
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
label.setText("Now you can see words");
}
}
First off, you have to remove void keyword in EventMain's constructor. Then, creating JPanel and add components into it, then add the JPanel to the JFrame.contentPane.
The following code should work:
public class EventMain extends JFrame {
private final JLabel label;
private final JButton button;
public static void main(String[] args) {
EventMain gui = new EventMain();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when click x
// close program
gui.setSize(600, 300);
gui.setTitle("Button Test");
gui.setVisible(true);
}
public EventMain() {
// setLayout(new FlowLayout());
JPanel panel = new JPanel(new FlowLayout());
button = new JButton("click for text");
panel.add(button);
label = new JLabel("");
panel.add(label);
Events e = new Events();
button.addActionListener(e);
this.getContentPane().add(panel);
}
public class Events implements ActionListener {
public void actionPerformed(ActionEvent e) {
label.setText("Now you can see words");
}
}
}
I am having trouble to set the frame as a owner to the dialog. Normally when I extend JDialog class for creating a dialog then I use super(frame) to specify the owner of the dialog such that both of them are not disjoint when you press alt+tab. But when I create a dialog using new like JDialog dialog = new JDialog() then I am unable to specify the frame as owner to the dialog.
Following example demonstrates above two approaches. Top Click button opens a dialog which is without extending JDialog. Bottom Click button opens a dialog with extending JDialog.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class DialogEx {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
new DialogEx().createUI();
}
};
EventQueue.invokeLater(r);
}
private void createUI() {
final JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
JButton button1 = new JButton("Top Click");
JButton button2 = new JButton("Bottom Click");
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
new DialogExtend(frame).createUI();
}
});
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
new DialogWithoutExtend(frame).cretaUI();
}
});
frame.setTitle("Test Dialog Instances.");
frame.add(button1, BorderLayout.NORTH);
frame.add(button2, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(300, 200));
frame.setVisible(true);
}
class DialogExtend extends JDialog {
private JFrame frame;
public DialogExtend(JFrame frame) {
super(frame);
this.frame = frame;
}
public void createUI() {
setLocationRelativeTo(frame);
setTitle("Dialog created by extending JDialog class.");
setSize(new Dimension(400, 100));
setModal(true);
setVisible(true);
}
}
class DialogWithoutExtend {
private JFrame frame;
public DialogWithoutExtend(JFrame frame) {
this.frame = frame;
}
public void cretaUI() {
JDialog dialog = new JDialog();
dialog.setTitle("Dialog created without extending JDialog class.");
dialog.setSize(new Dimension(400, 100));
dialog.setLocationRelativeTo(frame);
dialog.setModal(true);
dialog.setVisible(true);
}
}
}
A dialog's (or window's) owner can be set only in the constructor, so the only way to set it is by using a constructor which takes the owner as parameter, like:
class DialogWithoutExtend {
private JFrame frame;
public DialogWithoutExtend(JFrame frame) {
this.frame = frame;
}
public void cretaUI() {
JDialog dialog = new JDialog(frame);
dialog.setTitle("Dialog created without extending JDialog class.");
dialog.setSize(new Dimension(400, 100));
dialog.setLocationRelativeTo(frame);
dialog.setModal(true);
dialog.setVisible(true);
}
}