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

时间:2011-09-07 13:25:45

标签: java swing actionlistener

我在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);
        }
    });


}

}

4 个答案:

答案 0 :(得分:5)

运行你的代码片段(在自定义类周围删除/调整之后),抛出一个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 :-)

        }

答案 1 :(得分:4)

你的问题在于这一行:

  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<Boolean, Void> {
      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();
         }
      }
   }
}

答案 2 :(得分:1)

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

如果您粘贴了异常的堆栈跟踪,这也会有所帮助。

我怀疑问题来自于frame为null的事实。这是因为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());

答案 3 :(得分:1)