Как закрыть окно Jframe, не закрывая другое?
Я новичок в Java Swing, и я пытаюсь узнать, как закрыть один кадр, не закрывая другой с помощью кнопки. Например, у меня есть frame1 / window, в котором есть только кнопка с именем входа. Как только я нажимаю кнопку входа в систему, появляется другое окно frame2. На frame2 у меня просто образец JLabel «Hello And Welcome», кнопка под названием «Выход». Я хочу иметь возможность нажать кнопку «Выход» в окне frame2, и окно frame2 должно закрываться, но окно окна frame1 все еще будет открыто. Я попробовал setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE), но он работает, только если я щелкну значок x в правом верхнем углу окна frame2. Кто-нибудь знает, как закрыть фрейм при нажатии на кнопку?
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(); >>
Избавьтесь от extends JFrame для начала, это просто сбивает с толку. Вы создаете вторичные экземпляры JFrame внутри классов, и трудно понять, какие из них были представлены и когда. setLayout(null) вернется, чтобы преследовать вас, найдите время, чтобы узнать, как использовать менеджеры компоновки Swing Размещение компонентов в контейнере. Это может занять некоторое время, но в долгосрочной перспективе это избавит вас от множества проблем.
Кто-нибудь знает, как закрыть фрейм при нажатии кнопки? — проверьте: Закрытие приложения. Он содержит Action , который вы можете добавить к своей кнопке, чтобы закрыть фрейм.
Спасибо за совет. Как я уже упоминал, я новичок в Java Swing. SetLayout — это тема, в которую я еще не входил.
2 ответа
Вы продублировали JFrame, создали поле JFrame f внутри JFrame. Не используйте статические компоненты, такие как кнопка.
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 ), поскольку в этом окне потока события обрабатываются и отправляются дальше.
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); // > public static void frame2windown() < Frame2 f2 = new Frame2(); >>
JFrame.setVisible делает все это. Особенно setVisible(true) , возможно, следует сделать даже после вызова конструктора, так что он всегда будет последним.
Еще одно замечание, быстро погрузитесь в менеджеры по расположению. Абсолютные макеты (null) — это PITA.
Итак, есть целый ряд концепций, которые вам нужно попробовать и изучить.
- Обычно НЕ рекомендуется расширяться из контейнеров верхнего уровня (например, JFrame ). Вы также не добавляете им никаких новых функций; они сложные, составные компоненты; вы ограничиваете себя одним вариантом использования (что произойдет, если вы захотите включить пользовательский интерфейс в другой пользовательский интерфейс или использовать диалог вместо фрейма ?!)
- Использование нескольких кадров не всегда является хорошей идеей и может сбивать с толку пользователя. В целом, с рабочими процессами входа в систему, я могу утверждать, что диалог входа в систему, как правило, является лучшим решением, но вам нужно понимать варианты использования, чтобы делать эти определения.
- 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")); >> >
Закрытие текущего окна
Есть массив из n окон , созданных динамически . В каждом окне будет поле для ввода и кнопка «Ok», при нажатии на которую текущее окно закрывается и открывается следующее из массива. Опять вводятся данные и следует закрытие окна, открытие следующего.
Подскажите, пожалуйста, как закрыть только текущее окно, чтоб остальные (n-1) окна закрывались тоже по очереди.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
JFrame[] frm = new JFrame[n]; JLabel [] lble = new JLabel[n]; JTextField [] txtFldA = new JTextField[n]; JTextField [] txtFldB = new JTextField[n]; JButton [] btn3 = new JButton[n]; int numb=n; for(int i=0; in;i++ ){ frm[i] = new JFrame("Введите интервал"); frm[i].setSize(250, 120); frm[i].setVisible(true); frm[i].setLayout(new FlowLayout()); btn3[i] = new JButton("Ok"); btn3[i].setSize(80, 50); btn3[i].setVisible(true); frm[i].getContentPane().add(btn3[i]); numb--; btn3[i].addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for(int k = 0; k n; k++){ // frm[k].dispose(); } }); }} });
Java Swing приложение, закройте одно окно и откройте другое при нажатии кнопки
У меня есть приложение Java netbeans, которое должно отображать JFrame (класс StartUpWindow расширяет JFrame) с некоторыми параметрами при запуске приложения, затем пользователь нажимает кнопку и что JFrame должен быть закрыт, а новый (класс MainWindow) должен открывается. Итак, как мне это сделать правильно. Я, очевидно, устанавливаю обработчик щелчка на кнопке в StartupWindow, но что я помещаю в этот обработчик, чтобы я мог закрыть StartUpWindow и открыть MainWindow? Похоже, что в это тоже входит нить, так как каждое окно, похоже, имеет собственный поток. или проблемы с потоками, которые автоматически обрабатываются самими JFrames.
6 ответов
StartupWindow.java
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.SwingUtilities; public class StartupWindow extends JFrame implements ActionListener < private JButton btn; public StartupWindow() < super("Simple GUI"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); btn = new JButton("Open the other JFrame!"); btn.addActionListener(this); btn.setActionCommand("Open"); add(btn); pack(); >@Override public void actionPerformed(ActionEvent e) < String cmd = e.getActionCommand(); if(cmd.equals("Open")) < dispose(); new AnotherJFrame(); >> public static void main(String[] args) < SwingUtilities.invokeLater(new Runnable()< @Override public void run() < new StartupWindow().setVisible(true); >>); > >
AnotherJFrame.java
import javax.swing.JFrame; import javax.swing.JLabel; public class AnotherJFrame extends JFrame < public AnotherJFrame() < super("Another GUI"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); add(new JLabel("Empty JFrame")); pack(); setVisible(true); >>
@Eng.FouadEng.Fouad как открытая StartupWindow от AnotherJFrame , создавая объект StartupWindow в AnotherJFrame не будет работать
Вы можете вызвать dispose() в текущем окне и setVisible(true) на тот, который вы хотите отобразить.
Вы бы сохранили переменную JFrame в области видимости класса? или вы бы сделали его выбираемым для сборки мусора, как только появится второй JFrame?
Это, очевидно, сценарий, в котором вы должны использовать CardLayout. Здесь вместо того, чтобы открывать два JFrame, вы можете просто изменить JPanels, используя CardLayout.
И код, который отвечает за создание и отображение вашего графического интерфейса, должен находиться внутри SwingUtilities.invokeLater(. ); метод для обеспечения безопасности потоков. Для получения дополнительной информации вы должны прочитать о Concurrency в Swing.
Но если вы хотите придерживаться своего подхода, вот пример кода для вашей справки.
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class TwoFrames < private JFrame frame1, frame2; private ActionListener action; private JButton showButton, hideButton; public void createAndDisplayGUI() < frame1 = new JFrame("FRAME 1"); frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame1.setLocationByPlatform(true); JPanel contentPane1 = new JPanel(); contentPane1.setBackground(Color.BLUE); showButton = new JButton("OPEN FRAME 2"); hideButton = new JButton("HIDE FRAME 2"); action = new ActionListener() < public void actionPerformed(ActionEvent ae) < JButton button = (JButton) ae.getSource(); /* * If this button is clicked, we will create a new JFrame, * and hide the previous one. */ if (button == showButton) < frame2 = new JFrame("FRAME 2"); frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame2.setLocationByPlatform(true); JPanel contentPane2 = new JPanel(); contentPane2.setBackground(Color.DARK_GRAY); contentPane2.add(hideButton); frame2.getContentPane().add(contentPane2); frame2.setSize(300, 300); frame2.setVisible(true); frame1.setVisible(false); >/* * Here we will dispose the previous frame, * show the previous JFrame. */ else if (button == hideButton) < frame1.setVisible(true); frame2.setVisible(false); frame2.dispose(); >> >; showButton.addActionListener(action); hideButton.addActionListener(action); contentPane1.add(showButton); frame1.getContentPane().add(contentPane1); frame1.setSize(300, 300); frame1.setVisible(true); > public static void main(String. args) < /* * Here we are Scheduling a JOB for Event Dispatcher * Thread. The code which is responsible for creating * and displaying our GUI or call to the method which * is responsible for creating and displaying your GUI * goes into this SwingUtilities.invokeLater(. ) thingy. */ SwingUtilities.invokeLater(new Runnable() < public void run() < new TwoFrames().createAndDisplayGUI(); >>); > >
и
Закрыть только одно окно Jframe
У меня есть пасьянс, который содержит две разные игры. Для доступа к играм у меня есть строка меню с Игровым меню, содержащим Пасьянс Ковров и Пасьянс Часов.
По умолчанию программа запускается в пасьянсе Carpet, и я хотел бы выбрать Game -> Clock Solitaire, затем всплывающее окно с пасьянсом Clock и старое окно пасьянса Carpet, которое нужно закрыть.
В настоящее время моя программа откроет окно часов, но не закроет старое окно Carpet.
public void clockGame() < JButton[] buttons = < new JButton("Close"), new JButton("New Game") >; final JDialog dialog = new JDialog(GUI, "Click a button"); final JOptionPane optionPane = new JOptionPane("Would you like to start a new game of Clock Solitaire?", JOptionPane.INFORMATION_MESSAGE, JOptionPane.INFORMATION_MESSAGE, null, buttons, buttons[1]); buttons[0].addActionListener(new ActionListener() < public void actionPerformed(ActionEvent e) < dialog.setVisible(false); >>); buttons[1].addActionListener(new ActionListener() < public void actionPerformed(ActionEvent e) < // What can I put here to close the Carpet Window new ClockSolitaire(); dialog.setVisible(false); >>); dialog.setContentPane(optionPane); dialog.pack(); dialog.setLocationRelativeTo(GUI); dialog.setVisible(true); >
Что я могу добавить ко второму actionPerformed так старое окно закрывается?
2 ответа
Если вы хотите использовать один JFrame, вы можете создать частную JPanel, где вы будете перекрашивать ее в зависимости от того, какую игру он выберет.
иначе, если вы хотите только 2 JFrames, вам нужно создать ссылочную переменную для каждого JFrame. Это означает, что вам нужно удалять «новый JFrame» для каждого клика, чтобы получить контроль над ним
в моем случае я бы сделал;
private JFrame clockSolitaireFrame;
класс ClockSolitaire будет использовать переменную clockSolitaire для отображения пользовательского интерфейса и использовать эту переменную, чтобы иметь возможность закрыть кадр в будущем. код будет выглядеть примерно так;
buttons[1].addActionListener(new ActionListener() < public void actionPerformed(ActionEvent e) < clockSolitaireFrame.dispose(); new ClockSolitaire(); dialog.setVisible(false); >>);