Home > Net >  How do you close a Jframe window without closing another one?
How do you close a Jframe window without closing another one?

Time:11-22

I am new to Java Swing and I am trying to learn how to close one frame without closing the other one using button. For example I have a frame1/window that just have a button called login. Once I click on login button, another window appear frame2. On frame2 I just have a sample JLabel "Hello And Welcome", button called Logout. I want to be able to click on the Logout button on frame2 and frame2 window should close, but frame1 window show still be open. I have try setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE), but it only work if I click on the x icon on the top right of the frame2 window. Does anyone know of a way to close a frame when you click on a button?

public class Frame1 extends JFrame implements ActionListener{
    
    private static JButton login = new JButton("Login"); 
    private static JFrame f = new JFrame("Login");  

    Frame1(){
     
        f.setSize(1000,750);
        f.setLocation(750, 250);

        login.setBounds(250, 350, 150, 30);

        f.add(login);
        f.setLayout(null);    
        f.setVisible(true); 
        login.addActionListener(this);

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    public void actionPerformed(ActionEvent e){

        if (e.getSource() == login){

            Frame2.frame2windown();
        }
    }

    public static void main(String [] args){

        Frame1 login1 = new Frame1();
    }
}

public class Frame2 extends JFrame implements ActionListener{

    private static JButton logout = new JButton("Logout"); 
    private static JLabel jb1 = new JLabel ("Hello And Welcome");
    private static JFrame f = new JFrame("Log Out");  

    Frame2(){
     

        f.setSize(1000,750);
        f.setLocation(750, 250);

        jb1.setBounds(250, 150, 350, 30);

        logout.setBounds(250, 350, 150, 30);

        f.add(logout);
        f.add(jb1);
        f.setLayout(null);    
        f.setVisible(true); 

        logout.addActionListener(this);

        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    }

    public void actionPerformed(ActionEvent a){

        if(a.getSource() == logout){

            dispose();
            WindowEvent closeWindow = new WindowEvent(this, JFrame.DISPOSE_ON_CLOSE);
            Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(closeWindow);

        }

    }


    public static void frame2windown(){
        
        Frame2 f2 = new Frame2();

    }
}

CodePudding user response:

So, there are a whole bunch of concepts your need to try and learn.

  1. It's generally recommended NOT to extend from top level containers (like JFrame). You're not adding any new functionality too them; they are complicated, compound components; you lock yourself into a single use case (what happens if you want to include the UI in another UI or use a dialog instead of frame?!)
  2. Multiple frames aren't always a good idea and can be confusing to the user. Generally, with login workflows though, I might argue a login dialog is generally a better solution, but you need to understand the use cases to make those determinations.
  3. Swing is a large, rich and diverse API, it has a LOT of inbuilt functionality, which you can use, to make your life easier (although it doesn't always seem this way)

Layout managers are an absolutely required feature and you really need to take the time to learn them, see Laying Out Components Within a Container for more details.

So, a really quick example of using a CardLayout and a basic "observer pattern", which decouples and separates responsibility.

import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Test {
    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new NavigationPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class NavigationPane extends JPanel {

        protected enum NavigationTarget {
            LOGIN, MAIN;
        }

        private LoginPane loginPane;
        private MainPane mainPane;

        private CardLayout cardLayout;

        public NavigationPane() {
            cardLayout = new CardLayout();
            setLayout(cardLayout);

            loginPane = new LoginPane();
            loginPane.addLoginListener(new LoginPane.LoginListener() {
                @Override
                public void loginDidFail(LoginPane source) {
                    JOptionPane.showMessageDialog(NavigationPane.this, "You are not unauthroised", "Error", JOptionPane.ERROR_MESSAGE);
                }

                @Override
                public void loginWasSuccessful(LoginPane source) {
                    navigateTo(NavigationTarget.MAIN);
                }
            });

            mainPane = new MainPane();

            add(loginPane, NavigationTarget.LOGIN.name());
            add(mainPane, NavigationTarget.MAIN.name());

            navigateTo(NavigationTarget.LOGIN);
        }

        protected void navigateTo(NavigationTarget target) {
            cardLayout.show(this, target.name());
        }
    }

    public static class LoginPane extends JPanel {

        public static interface LoginListener extends EventListener {
            public void loginDidFail(LoginPane source);
            public void loginWasSuccessful(LoginPane source);
        }

        public LoginPane() {
            setBorder(new EmptyBorder(10, 10, 10, 10));
            setLayout(new GridBagLayout());
            JButton btn = new JButton("Login");
            btn.addActionListener(new ActionListener() {
                private Random rnd = new Random();

                @Override
                public void actionPerformed(ActionEvent e) {
                    // Do some logic here
                    if (rnd.nextBoolean()) {
                        fireLoginWasSuccessful();
                    } else {
                        fireLoginDidFail();
                    }
                }
            });
            add(btn);
        }

        public void addLoginListener(LoginListener listener) {
            listenerList.add(LoginListener.class, listener);
        }

        public void removeLoginListener(LoginListener listener) {
            listenerList.remove(LoginListener.class, listener);
        }

        protected void fireLoginDidFail() {
            LoginListener[] listeners = listenerList.getListeners(LoginListener.class);
            for (LoginListener listener : listeners) {
                listener.loginDidFail(this);
            }
        }

        protected void fireLoginWasSuccessful() {
            LoginListener[] listeners = listenerList.getListeners(LoginListener.class);
            for (LoginListener listener : listeners) {
                listener.loginWasSuccessful(this);
            }
        }

    }

    public static class MainPane extends JPanel {

        public MainPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(10, 10, 10, 10));
            add(new JLabel("Welcome"));
        }

    }
}

JDialog based login workflow

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                NavigationPane navigationPane = new NavigationPane();
                JFrame frame = new JFrame();
                frame.add(navigationPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                if (LoginPane.showLoginDialog(navigationPane)) {
                    navigationPane.didLogin();
                } else {
                    frame.dispose();
                }
            }
        });
    }

    public static class NavigationPane extends JPanel {

        protected enum NavigationTarget {
            SPLASH, MAIN;
        }

        private SplashPane splashPane;
        private MainPane mainPane;

        private CardLayout cardLayout;

        public NavigationPane() {
            cardLayout = new CardLayout();
            setLayout(cardLayout);

            mainPane = new MainPane();
            splashPane = new SplashPane();

            add(splashPane, NavigationTarget.SPLASH.name());
            add(mainPane, NavigationTarget.MAIN.name());

            navigateTo(NavigationTarget.SPLASH);
        }

        protected void navigateTo(NavigationTarget target) {
            cardLayout.show(this, target.name());
        }

        public void didLogin() {
            navigateTo(NavigationTarget.MAIN);
        }
    }

    public static class LoginPane extends JPanel {

        private Random rnd = new Random();
        private boolean isAuthorised = false;

        public LoginPane() {
            setBorder(new EmptyBorder(10, 10, 10, 10));
            setLayout(new GridBagLayout());

            add(new JLabel("User name and password fields go here"));
        }

        protected void authenticate() {
            // Authenticate
            isAuthorised = rnd.nextBoolean();
            if (!isAuthorised) {
                JOptionPane.showMessageDialog(this, "You are not authorised", "Error", JOptionPane.ERROR_MESSAGE);
            }
        }

        // So this should return some kind of "session" or something so
        // can identify the user, but for now, we'll just use
        // a boolean
        public boolean isAuthorised() {
            return isAuthorised;
        }

        public static boolean showLoginDialog(Component parent) {
            LoginPane loginPane = new LoginPane();
            JPanel panel = new JPanel(new BorderLayout());
            JPanel buttonPane = new JPanel(new GridBagLayout());

            JButton okayButton = new JButton("Login");
            JButton cancelButton = new JButton("Cancel");

            buttonPane.add(okayButton);
            buttonPane.add(cancelButton);

            panel.add(loginPane);
            panel.add(buttonPane, BorderLayout.SOUTH);

            JDialog dialog = new JDialog(SwingUtilities.windowForComponent(parent));
            dialog.add(panel);

            okayButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    loginPane.authenticate();
                    if (loginPane.isAuthorised()) {
                        dialog.dispose();
                    }
                }
            });
            cancelButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    dialog.dispose();
                }
            });
            dialog.setModal(true);
            dialog.pack();
            dialog.setLocationRelativeTo(parent);
            dialog.setVisible(true);

            return loginPane.isAuthorised();
        }

    }

    public static class SplashPane extends JPanel {

        public SplashPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(10, 10, 10, 10));
            add(new JLabel("This is a splash panel, put some nice graphics here"));
        }

    }

    public static class MainPane extends JPanel {

        public MainPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(10, 10, 10, 10));
            add(new JLabel("Welcome"));
        }

    }
}

CodePudding user response:

You duplicated the JFrame, created a JFrame field f inside the JFrame. Do not use static components like the button.

public class Frame1 extends JFrame implements ActionListener {

    private final JButton login = new JButton("Login");

    Frame1() {
        setTitle("Login");
        setSize(1000, 750);
        setLocation(750, 250);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(null);

        login.setBounds(250, 350, 150, 30);

        add(login);
        login.addActionListener(this);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == login) {
            Frame2.frame2windown();
        }
    }

    public static void main(String[] args) {
       EventQueue.invokeLater(() -> {
          Frame1 login1 = new Frame1();
       }
    }
}

Use the swing/awt event queue (invokeLater) as on this thread window events are handled and dispatched further.

And Frame2:

public class Frame2 extends JFrame implements ActionListener {

    private JButton logout = new JButton("Logout");
    private JLabel jb1 = new JLabel("Hello And Welcome");

    Frame2() {
        setTitle("Logout");
        setSize(1000, 750);
        setLocation(750, 250);
        setLayout(null);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        jb1.setBounds(250, 150, 350, 30);
        logout.setBounds(250, 350, 150, 30);
        add(logout);
        add(jb1);
        logout.addActionListener(this);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent a) {
        if (a.getSource() == logout) {
            setVisible(false); // <--- ALL
        }
    }

    public static void frame2windown() {
        Frame2 f2 = new Frame2();
    }
}

JFrame.setVisible does it all. Especially setVisible(true) should maybe even done after the constructor is called, so it always is last.

Another remark, dive into layout managers fast. Absolute layouts (null) are a PITA.

  • Related