如何在不关闭另一个 JFrame 窗口的情况下关闭一个 JFrame 窗口?

问题描述 投票:0回答:3

我是 Java Swing 的新手,我正在尝试学习如何关闭一帧而不使用按钮关闭另一帧。例如,我有一个frame1/窗口,其中只有一个名为“登录”的按钮。单击登录按钮后,会出现另一个窗口frame2。在第 2 帧上,我只有一个示例 JLabel“Hello And Welcome”,按钮名为“注销”。我希望能够单击框架 2 上的“注销”按钮,框架 2 窗口应该关闭,但框架 1 窗口显示仍然打开。我尝试过 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE),但只有当我单击 Frame2 窗口右上角的 x 图标时它才有效。有谁知道单击按钮时关闭框架的方法吗?

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();

    }
}
java swing jframe
3个回答
1
投票

因此,您需要尝试和学习一大堆概念。

  1. 通常建议不要从顶层容器扩展(如
    JFrame
    )。您不会向它们添加任何新功能;它们是复杂的复合组件;您将自己锁定在单个用例中(如果您想将 UI 包含在另一个 UI 中或使用对话框而不是框架,会发生什么?!)
  2. 多个框架并不总是一个好主意,并且可能会让用户感到困惑。一般来说,对于登录工作流程,我可能认为登录对话框通常是更好的解决方案,但您需要了解用例才能做出这些决定。
  3. Swing 是一个庞大、丰富且多样化的 API,它有很多内置功能,您可以使用它们,让您的生活更轻松(尽管看起来并不总是这样)

布局管理器是一个绝对必需的功能,您确实需要花时间来学习它们,请参阅在容器内布局组件了解更多详细信息。

所以,这是一个使用

CardLayout
和基本“观察者模式”的快速示例,它可以解耦和分离责任。

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
基于登录工作流程

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"));
        }

    }
}

0
投票

您复制了 JFrame,并在 JFrame 内创建了一个 JFrame 字段

f
。 不要使用按钮等静态组件。

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();
       }
    }
}

使用 swing/awt 事件队列 (

invokeLater
),因为在此线程上窗口事件将被进一步处理和分派。

和框架2:

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
做到了这一切。特别是
setVisible(true)
甚至应该在调用构造函数之后完成,所以它总是最后一个。

另一句话,快速深入布局管理器。绝对布局(空)是 PITA。


0
投票

我通过使用解决了这个问题 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) 您希望在不影响其他帧的情况下关闭哪个帧

© www.soinside.com 2019 - 2024. All rights reserved.