Java:Swing:按下按钮后隐藏框架

我在java框架中有一个按钮,按下它时会从文本字段中读取一个值,并使用该字符串作为尝试连接到串行设备的端口名称。

如果此连接成功,则该方法返回true,否则返回false。 如果它返回true,我希望框架消失。 然后将出现在其他类中指定的一系列其他帧以及控制串行设备的选项。

我的问题是:按钮连接到动作侦听器,按下此方法被调用。 如果我尝试使用frame.setVisible(true); 方法java抛出一个抽象按钮错误,因为我实际上告诉它在按钮按下方法退出之前消失包含按钮的框架。 删除frame.setVisible(true); 允许程序正确运行但是我留下了一个不再有用的延迟连接框架。

按下按钮后,如何让框架消失?

package newimplementation1; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * * @author Zac */ public class ConnectionFrame extends JPanel implements ActionListener { private JTextField textField; private JFrame frame; private JButton connectButton; private final static String newline = "\n"; public ConnectionFrame(){ super(new GridBagLayout()); textField = new JTextField(14); textField.addActionListener(this); textField.setText("/dev/ttyUSB0"); connectButton = new JButton("Connect"); //Add Components to this panel. GridBagConstraints c = new GridBagConstraints(); c.gridwidth = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.HORIZONTAL; add(textField, c); c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; add(connectButton, c); connectButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean success = Main.mySerialTest.initialize(textField.getText()); if (success == false) {System.out.println("Could not connect"); return;} frame.setVisible(false); // THIS DOES NOT WORK!! JTextInputArea myInputArea = new JTextInputArea(); myInputArea.createAndShowGUI(); System.out.println("Connected"); } }); } public void actionPerformed(ActionEvent evt) { // Unimplemented required for JPanel } public void createAndShowGUI() { //Create and set up the window. frame = new JFrame("Serial Port Query"); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); //Add contents to the window. frame.add(new ConnectionFrame()); frame.setLocation(300, 0); //Display the window. frame.pack(); frame.setVisible(true); frame.addComponentListener(new ComponentAdapter() { @Override public void componentHidden(ComponentEvent e) { System.out.println("Exiting Gracefully"); Main.mySerialTest.close(); ((JFrame)(e.getComponent())).dispose(); System.exit(0); } }); } } 

你的问题在于这一行:

  frame.add(new ConnectionFrame()); 

您正在创建一个新的ConnectionFrame对象,因此您的按钮尝试关闭的框架与显示的框架不同,这是您的问题的根源。

如果你改成它,

  //!! frame.add(new ConnectionFrame()); frame.add(this); 

这样两个JFrame是同一个,事情可能会更顺利。

但话说回来,你的整个设计闻起来很糟糕,我会以更多的OOP和更少静态的方式重新思考它。 此外,使用需要对话框的对话框,而不是框架,而不是对话框考虑通过CardLayout交换视图(JPanels)作为更好的选择。

我自己,我为此创建一个“哑”的GUI,创建一个JPanel(在我的例子中,为了简单起见,它扩展了JPanel,但是如果没有必要我会避免扩展),我会让任何人调用此代码通过某种控制决定如何处理信息。 例如,

 import java.awt.*; import java.awt.event.*; import javax.swing.*; @SuppressWarnings("serial") public class ConnectionPanel extends JPanel { private JTextField textField; private JButton connectButton; private ConnectionPanelControl control; public ConnectionPanel(final ConnectionPanelControl control) { super(new GridBagLayout()); this.control = control; ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { if (control != null) { control.connectButtonAction(); } } }; textField = new JTextField(14); textField.addActionListener(listener); textField.setText("/dev/ttyUSB0"); connectButton = new JButton("Connect"); GridBagConstraints c = new GridBagConstraints(); c.gridwidth = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.HORIZONTAL; add(textField, c); c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; add(connectButton, c); connectButton.addActionListener(listener); } public String getFieldText() { return textField.getText(); } } 

同样,简单GUI之外的内容将决定如何处理文本字段包含的文本以及如何处理显示此JPanel的GUI:

 public interface ConnectionPanelControl { void connectButtonAction(); } 

此外,您可能会在后台线程中进行任何连接,以便不冻结您的GUI,可能是SwingWorker。 也许是这样的:

 import java.awt.event.ActionEvent; import java.util.concurrent.ExecutionException; import javax.swing.*; @SuppressWarnings("serial") public class MyMain extends JPanel { public MyMain() { add(new JButton(new ConnectionAction("Connect", this))); } private static void createAndShowGui() { JFrame frame = new JFrame("My Main"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new MyMain()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } @SuppressWarnings("serial") class ConnectionAction extends AbstractAction { private MyMain myMain; private ConnectionPanel cPanel = null; private JDialog dialog = null; public ConnectionAction(String title, MyMain myMain) { super(title); this.myMain = myMain; } @Override public void actionPerformed(ActionEvent e) { if (dialog == null) { dialog = new JDialog(SwingUtilities.getWindowAncestor(myMain)); dialog.setTitle("Connect"); dialog.setModal(true); cPanel = new ConnectionPanel(new ConnectionPanelControl() { @Override public void connectButtonAction() { final String connectStr = cPanel.getFieldText(); new MySwingWorker(connectStr).execute(); } }); dialog.getContentPane().add(cPanel); dialog.pack(); dialog.setLocationRelativeTo(null); } dialog.setVisible(true); } private class MySwingWorker extends SwingWorker { private String connectStr = ""; public MySwingWorker(String connectStr) { this.connectStr = connectStr; } @Override protected Boolean doInBackground() throws Exception { // TODO: make connection and then return a result // right now making true if any text in the field if (!connectStr.isEmpty()) { return true; } return false; } @Override protected void done() { try { boolean result = get(); if (result) { System.out.println("connection successful"); dialog.dispose(); } else { System.out.println("connection not successful"); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } } 

运行你的代码片段(在删除/调整自定义类之后),抛出一个NPE。 原因是您访问的帧为空。 那是因为它从未设定过。 最好不要依赖任何领域,让按钮找到它的顶级祖先并隐藏它,就像在

  public void actionPerformed(final ActionEvent e) { boolean success = true; if (success == false) { System.out.println("Could not connect"); return; } Window frame = SwingUtilities.windowForComponent((Component) e .getSource()); frame.setVisible(false); //no problem :-) } 

如果您将JFrame实例命名为xxxFrame,并将JPanel实例命名为xxxPanel,那么您的代码将更具可读性。 命名JPanel实例xxxFrame会让事情变得非常混乱。

如果您粘贴了exception的堆栈跟踪,它也会有所帮助。

我怀疑问题来自于框架为空的事实。 这是因为frame字段仅在createAndShowGUI方法中初始化,但此方法不显示当前连接面板,而是显示新的连接面板,因此具有空框架字段:

 ConnectionFrame firstPanel = new ConnectionFrame(); // The firstPanel's frame field is null firstPanel.createAndShowGUI(); // the firstPanel's frame field is now not null, but // the above call opens a JFrame containing another, new ConnectionFrame, // which has a null frame field 

createAndShowGUI的代码应该包含

 frame.add(this); 

而不是

 frame.add(new ConnectionFrame()); 

对于Swing GUI最好只创建一次JFrame和另一个顶级容器将是JDialogJWindow (默认情况下未装饰),

这个简单的例子

 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SuperConstructor extends JFrame { private static final long serialVersionUID = 1L; public SuperConstructor() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setPreferredSize(new Dimension(300, 300)); setTitle("Super constructor"); Container cp = getContentPane(); JButton b = new JButton("Show dialog"); b.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { FirstDialog firstDialog = new FirstDialog(SuperConstructor.this); } }); cp.add(b, BorderLayout.SOUTH); JButton bClose = new JButton("Close"); bClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { System.exit(0); } }); add(bClose, BorderLayout.NORTH); pack(); setVisible(true); } public static void main(String args[]) { EventQueue.invokeLater(new Runnable() { @Override public void run() { SuperConstructor superConstructor = new SuperConstructor(); } }); } private class FirstDialog extends JDialog { private static final long serialVersionUID = 1L; FirstDialog(final Frame parent) { super(parent, "FirstDialog"); setPreferredSize(new Dimension(200, 200)); setLocationRelativeTo(parent); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); JButton bNext = new JButton("Show next dialog"); bNext.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { SecondDialog secondDialog = new SecondDialog(parent, false); } }); add(bNext, BorderLayout.NORTH); JButton bClose = new JButton("Close"); bClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { setVisible(false); } }); add(bClose, BorderLayout.SOUTH); pack(); setVisible(true); } } private int i; private class SecondDialog extends JDialog { private static final long serialVersionUID = 1L; SecondDialog(final Frame parent, boolean modal) { //super(parent); // Makes this dialog unfocusable as long as FirstDialog is visible setPreferredSize(new Dimension(200, 200)); setLocation(300, 50); setModal(modal); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); setTitle("SecondDialog " + (i++)); JButton bClose = new JButton("Close"); bClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { setVisible(false); } }); add(bClose, BorderLayout.SOUTH); pack(); setVisible(true); } } } 

更好的是重新使用顶级容器,因为在运行时创建了许多顶级容器(可能缺少内存)