Swing : Exit application actionListener - java

I am trying to figure out how can we exit the application with button click.
The problem i faced which makes me unable to exit the application is because i am using "extend JFRame" from the main class.
For an example,
app.class
public class app{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame frame = new MainFrame("Exercise one");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
.. .. ..
frame.setVisible(true);
})
}
}
MainFrame.java
public class MainFrame extends JFrame(){
public MainFrame(String title){
super(title)
//set layout manager
setLayout(new BorderLayout());
//swing components
JButton exit = new JButton("Exit");
//add container
Container container = getContentPane();
container.add(exit);
//create actionlist logic
exit.addActionListener(new ActionListener()){
#Override
public void actionPerformed(ActionEvent arg0){
// on click , this logic will end the application
}
}
}
}
I fully understand how i can cancel the application from app class.But in scenarios where i want to cancel the application from MainFrame.Can it be done ?
Thank you in advance.

The defaultCloseOperation is only processed by the frame when it encounters a WINDOW_CLOSING event, neither setVisible or dispose trigger this event, which means the the defaultCloseOperation won't be processed
The only way to ensure that this operation is triggered is to manually dispatch a WINDOW_CLOSING event
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
One of the main reasons for wanting to follow this path is that it ensures the application is following the configured defaultCloseOperation and making up it's own mind (like calling System.exit manually)
The following demonstrates hiding, disposing and dispatching approaches. Only the dispatch approach will close the window and terminate the JVM
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.NAME;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
frame.add(new JButton(new HideAction(frame)), gbc);
frame.add(new JButton(new DisposeAction(frame)), gbc);
frame.add(new JButton(new DispatchAction(frame)), gbc);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.out.println("Closing");
}
#Override
public void windowClosed(WindowEvent e) {
System.out.println("Closed");
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HideAction extends AbstractAction {
private JFrame frame;
public HideAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Hide");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
}
}
public class DisposeAction extends AbstractAction {
private JFrame frame;
public DisposeAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Dispose");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
}
}
public class DispatchAction extends AbstractAction {
private JFrame frame;
public DispatchAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Dispatch");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
}
}
}
If I run this in my IDE, unless I use the dispatch option, the JVM is left running and I have to terminate the session to close it fully.
I also noted that calling dispose only triggers the WINDOW_CLOSED event, while the dispatch method will trigger the WINDOW_CLOSING event

Problem solved.
Credits to #XtremeBaumer.
Basically, when using "classname" extend JFRame.
We can input dispose() which will kill the application completely. This will causes the JFrame window to be destroyed and cleaned up by the operating system. :)

Indeed, dispose() is the right solution. I also suggest to add a pack() call so the UI shows up properly:
public class MainFrame extends JFrame {
public MainFrame(String title) {
super(title);
...
// create actionlist logic
exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("--> closing app programmatically");
MainFrame.this.dispose();
}
});
this.pack();
}
}
You can test the events with a WindowListener on the MainFrame. They are invoked as if the user pressed the close button:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new MainFrame("Exercise one");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
// .. .. ..
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.out.println("--> closing...");
}
public void windowClosed(WindowEvent e) {
System.out.println("--> closed...");
}
});
}
});
}

Related

How to retain assigned cursor to JDialog even on lost focus?

Is there a way to retain the set mouse cursor even the JDialog is not in focus?
I have the following SSCCE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JDialog {
public Test() {
super((Frame) null, true);
setLayout(new BorderLayout());
setModalityType(Dialog.ModalityType.MODELESS);
setType(Window.Type.UTILITY);
setUndecorated(true);
setAlwaysOnTop(true);
setBackground(Color.BLACK);
setSize(300, 300);
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
getContentPane().setBackground(Color.BLACK);
getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
setLocationRelativeTo(null);
var label = new JLabel("Focused");
label.setForeground(Color.WHITE);
addWindowFocusListener(new WindowAdapter() {
#Override
public void windowGainedFocus(WindowEvent e) {
label.setText("Focused");
}
#Override
public void windowLostFocus(WindowEvent e) {
label.setText("Not Focused");
}
});
add(label, BorderLayout.CENTER);
}
public static void main(String[] args) {
// Create the GUI on the event-dispatching thread
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test sw = new Test();
// Display the window.
sw.setVisible(true);
}
});
}
}
Here is what is happening:
My goal is for the resize cursor to be retained on mouse hover even if the JDialog is not focused.
Tried on AdoptOpenJDK 11 & 15 and Liberica JDK 11 on MacOS Catalina 10.15.4
Add a mouse listener for your dialog. By using the MouseAdapter implementation, you can override only the methods that you want.
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
setCursor(Cursor.getDefaultCursor());
}
});

Java Nested MouseListener [duplicate]

I have a main window:
public class MainPanel extends JFrame implements MouseListener {
public MainPanel() {
setLayout(new FlowLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(this);
ChildPanel child = new ChildPanel();
add(child);
JPanel spacer = new JPanel();
spacer.setPreferredSize(new Dimension(50, 50));
add(spacer);
pack();
setLocationRelativeTo(null);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse click event on MainPanel");
}
}
And a child JPanel:
public class ChildPanel extends JPanel implements MouseListener {
public ChildPanel() {
setBackground(Color.RED);
setPreferredSize(new Dimension(200, 200));
//addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse click event on ChildPanel");
}
}
With the call to addMouseListener commented out in the child panel, the parent receives click events when I click anywhere in the window, including on the child. If I uncomment that call and click on the child panel, only the child receives the click event and it doesn't propagate to the parent.
How do I stop the event from being consumed by the child?
In Swing, you generally want the clicked component to respond; but you can forward the mouse event to the parent, as shown below. Here's a related example.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/questions/3605086 */
public class ParentPanel extends JPanel {
public ParentPanel() {
this.setPreferredSize(new Dimension(640, 480));
this.setBackground(Color.cyan);
this.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked in parent panel.");
}
});
JPanel child = new JPanel();
child.setPreferredSize(new Dimension(320, 240));
child.setBackground(Color.blue);
child.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked in child panel.");
ParentPanel.this.processMouseEvent(e);
}
});
this.add(child);
}
private void display() {
JFrame f = new JFrame("MouseEventTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ParentPanel().display();
}
});
}
}
I don't think you can. I believe it's a Swing design principle that only one component receives an event.
You can get the behavior you want, however, but pass the JFrame to the ChildPanel and calling its mouseClicked(MouseEvent) or whatever method you want. Or just get the parent component.
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse click event on ChildPanel");
this.frame.mouseClicked(e);
getParent().mouseClicked(e);
}

Making JButton in one class open seperate JDialog class

I am creating a quiz and have created a class with a JFrame which sort of acts like the main menu. On this menu, I have created a JButton which I want to open the seperate JDialog (which will contain the questions etc).
The JDialog is a seperate class called questionDialog.java
I believe you have to implement an action listener calling setVisible(true) however when I do that, I get a cannot make static reference to non-static method setvisible error.
Any help would be greatly appreciated, I am using eclipse and Jigloo for the GUI
here is my code in my main menu JFrame class, specifically the code for the button I want to open the new JDialog
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
NewJFrame inst = new NewJFrame();
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
startButton = new JButton();
getContentPane().add(startButton);
startButton.setText("Start Quiz");
startButton.setBounds(454, 239, 65, 23);
And here is the code which gives me the error
startButton = new JButton();
getContentPane().add(startButton);
startButton.setText("Start Quiz");
startButton.setBounds(454, 239, 65, 23);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionevent)
{
questionDialog.setVisible(true);
}
});
Here is the code from the seperate JDialog class
package ZillionaireGUI;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class questionDialog extends javax.swing.JDialog {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
questionDialog inst = new questionDialog(frame);
inst.setVisible(true);
}
});
}
public questionDialog(JFrame frame) {
super(frame);
initGUI();
}
private void initGUI() {
try {
setSize(400, 300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here's what you should do.
Get rid of the main method in the JDialog class. Your application should only have one main method, and that should be in your JFrame class.
Don't create a new JFrame to pass it to your dialog.
To open it on a button click just create a new questionDialog() passing the current frame to it. Something like this
public class MyFrame extends JFrame {
public MyFrame() {
JButton but = new JButton("but");
but.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
QuestionDialog dialog = new QuestionDialog(MyFrame.this);
dialog.setVisible(true);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new MyFrame();
}
});
}
}
public class QuestionDialog extends JDialog {
public QuestionDialog(Frame parent) {
super(parent);
}
}
Bonus
You are getting the error doing questionDialog.setVisible(true) because setVisible is an instance method and you are trying to call it in a static way. You need to create a new instance of your dialog class to call it.
Use Java naming convention. Class names begin with capital letters.questionDialog → QuestionDialog
In your main menu write the following
startButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
questionDialog inst = new questionDialog(frame);
inst.setVisible(true);
}
});
}
});
I think it is likely that you are trying to do something to a non-static member while you are in main (which is a static method). You should just use main to create an instance and then call some method of that instance. I've put some working code below:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Zillionaire extends JFrame implements ActionListener {
JButton startButton;
public static void main(String[] args) {
Zillionaire zillionaire = new Zillionaire();
zillionaire.init();
}
private void init() {
startButton = new JButton();
// Removed: we just use add now, and bets to do this last.
// getContentPane().add(startButton);
startButton.setText("Start Quiz");
startButton.setBounds(454, 239, 65, 23);
startButton.addActionListener(this);
// Add after the button is configured, not before
add(startButton);
// This just makes our JFrame pretty and visible
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
// Anything that implements the ActionListener interface can listen
// for the button being pressed and activate the JDialog
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Button pressed, but Dialog doesn't do much");
QuestionDialog questionDialog = new QuestionDialog(this);
}
}
class QuestionDialog extends javax.swing.JDialog {
public QuestionDialog(JFrame frame) {
super(frame);
initGUI();
}
// Set it visible when we make our GUI
private void initGUI() {
try {
setSize(400, 300);
// Added so we can see something
add(new JLabel("I should add something!"));
setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}

JButton changes size

I have a JFrame, and whenever I switch from one JFrame using a JButton it starts out normally, but whenever I create a new instance of the first JFrame, the JButton is in an incorrect location and is the wrong size.
Example on startup
and when another one is created
Code:
public class Menu extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
public static int Number_of_Participants = 0;
protected JPanel window = new JPanel();
double p;
private JButton Participants;
private Rectangle rParticipants;
protected int Button_width = 240;
protected int Button_height = 48;
boolean running = false;
Thread thread;
JFrame frame = new JFrame();
public Menu() {
window.setBackground(Color.BLUE);
frame.setSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().add(window);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Image image = null;
try {
image = ImageIO.read(new File("res/BG.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
generateFiles();
drawButtons();
startMenu();
frame.repaint();
}
public void drawButtons() {
rParticipants = new Rectangle(520, 12, Button_width, Button_height);
Participants = new JButton("A");
Participants.setBounds(rParticipants);
window.add(Participants);
Participants.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.dispose();
new Participant(Number_of_Participants);
}
});
}
}
Participant.java extends Menu.java
int Participant_ID;
public Participant(int Participant_ID) {
super();
this.Participant_ID = Participant_ID;
}
makes a JButton that goes back to Menu.java
As mentioned in the comment, your problem is most likely related to the call to setVisible(true). This should always be the LAST call in the constructor. Particularly, it should only be called AFTER all components have been added to the frame.
Apart from that, from the code that you posted, it seems like you want to switch through a seqence of frames, starting with a "main" menu, and then going through one frame for each "Participant". This intention could already be considered as questionable, because closing and disposing a JFrame just in order to create a new one does not seem to be very elegant. Most likely, a more elegant solution would be possible with a CardLayout : http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html
However, some general hints:
Create the GUI on the Event Dispatch Thread
Don't extend JFrame. Instead, create a JFrame and fill it as needed
Don't implement Runnable with your top level class
Obey the standardJavaNamingConventions!
Don't try to do manual layouts with setBounds
This code is still not "beautiful", but at least shows how the goal of switching through several frames might be achieved, taking into account these points
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MenuExample
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JPanel mainMenuPanel = new MainMenuPanel();
createAndShowFrame(mainMenuPanel);
}
});
}
static void createAndShowFrame(JPanel panel)
{
JFrame frame = new JFrame();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(800, 600));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static JButton createNextParticipantButton(
final JComponent container, final int nextID)
{
JButton nextParticipantButton = new JButton("New Participant");
nextParticipantButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
Window window =
SwingUtilities.getWindowAncestor(container);
window.dispose();
ParticipantPanel participantPanel =
new ParticipantPanel(nextID);
createAndShowFrame(participantPanel);
}
});
return nextParticipantButton;
}
}
class MainMenuPanel extends JPanel
{
public MainMenuPanel()
{
setBackground(Color.BLUE);
add(MenuExample.createNextParticipantButton(this, 0));
}
}
class ParticipantPanel extends JPanel
{
private final int participantID;
public ParticipantPanel(int participantID)
{
this.participantID = participantID;
add(new JLabel("Add the contents for participant "+participantID));
add(MenuExample.createNextParticipantButton(this, participantID+1));
}
}

JDialog WindowOpened event is fired just once

I'm trying to get the WindowOpened event from JDialog, but it is fired just once.
Why windowClosing works correctly and WindowOpened just once? Is there any way to fire the open event for JDialog every time?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
public class NewClass extends JDialog {
public void init() {
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
setModal(true);
setSize(100,100);
setLocationRelativeTo(null);
}
public void addListener() {
addWindowListener(
new java.awt.event.WindowAdapter() {
public void windowOpened(WindowEvent e) {
System.out.println("Invoking WindowOpened from JDialog");
}
public void windowClosing(WindowEvent e) {
System.out.println("Invoking WindowClosing from JDialog");
dispose();
}
});
}
public static void main( String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200,70);
final NewClass d = new NewClass();
d.init();
d.addListener();
JButton b = new JButton("Show Dialog");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d.setVisible(true);
}
});
f.getContentPane().add(b);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
ComponentListener#componentShown(ComponentEvent e) is fired whenever your Window is made visible.
I don't believe WindowActivated is a good choice (like others said) because it can be fired in some others circumstances. For instance, if your Dialog is not modal, WindowActivated will be fired whenever the window regains focus.
addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
super.windowActivated(e);
}
});

Categories

Resources