Java:Swing:按下按钮后隐藏帧
我在java框架中有一个按钮,按下该按钮时,它会从文本字段中读取一个值,并将该字符串用作尝试连接到串行设备的端口名 如果此连接成功,则该方法返回true,否则返回false。如果它返回true,我希望帧消失。然后,在其他类中指定的一系列其他帧将显示,其中包含控制串行设备的选项 我的问题是:按钮连接到一个动作监听器,当按下此按钮时,将调用此方法。如果我尝试使用frame.setVisible(true);方法java抛出了一个抽象按钮错误,因为我实际上是在告诉它在按钮按下方法退出之前消失包含按钮的帧。移除frame.setVisible(true);允许程序正确运行,但我留下了一个挥之不去的连接框架,不再有任何用处 如何在按下按钮时使画面消失Java:Swing:按下按钮后隐藏帧,java,swing,actionlistener,Java,Swing,Actionlistener,我在java框架中有一个按钮,按下该按钮时,它会从文本字段中读取一个值,并将该字符串用作尝试连接到串行设备的端口名 如果此连接成功,则该方法返回true,否则返回false。如果它返回true,我希望帧消失。然后,在其他类中指定的一系列其他帧将显示,其中包含控制串行设备的选项 我的问题是:按钮连接到一个动作监听器,当按下此按钮时,将调用此方法。如果我尝试使用frame.setVisible(true);方法java抛出了一个抽象按钮错误,因为我实际上是在告诉它在按钮按下方法退出之前消失包含按钮的
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是一个相同的框架,事情可能会更顺利地进行
但话说回来,你的整个设计闻起来很糟糕,我会用一种更面向对象、更少静态的方式重新思考。此外,使用对话框,其中需要对话框,而不是框架,而不是对话框考虑交换视图(JBAND)通过卡纸布局作为一个更好的选择仍然。
我自己会为此创建一个“哑”GUI,一个创建JPanel的GUI(在我的示例中,为了简单起见,它扩展了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之外的东西将决定如何处理textfield包含的文本以及如何处理显示此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();
}
}
}
}
导入java.awt.event.ActionEvent;
导入java.util.concurrent.ExecutionException;
导入javax.swing.*;
@抑制警告(“串行”)
公共类MyMain扩展了JPanel{
公共MyMain(){
添加(newjbutton(newconnectionAction(“Connect”,this)));
}
私有静态void createAndShowGui(){
JFrame=新的JFrame(“我的主框架”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(newmymain());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
createAndShowGui();
}
});
}
}
@抑制警告(“串行”)
类连接扩展了AbstractAction{
私人密曼密曼;
私有连接面板cPanel=null;
私有JDialog对话框=null;
公共连接(字符串标题,MyMain MyMain){
超级(标题);
this.myMain=myMain;
}
@凌驾
已执行的公共无效操作(操作事件e){
如果(对话框==null){
dialog=newjdialog(SwingUtilities.getWindowSenator(myMain));
对话框。设置标题(“连接”);
dialog.setModal(true);
cPanel=新连接面板(新连接面板控件(){
@凌驾
public void connectButtonAction(){
最后一个字符串connectStr=cPanel.getFieldText();
新建MySwingWorker(connectStr.execute();
}
});
dialog.getContentPane().add(cPanel);
dialog.pack();
对话框.setLocationRelativeTo(空);
}
对话框.setVisible(true);
}
私有类MyWingWorker扩展SwingWorker{
私有字符串connectStr=“”;
公共MySwingWorker(字符串连接str){
this.connectStr=connectStr;
}
@凌驾
受保护的布尔值doInBackground()引发异常{
//TODO:建立连接,然后返回结果
//现在,如果字段中有任何文本,则为真
如果(!connectStr.isEmpty()){
返回true;
}
返回false;
}
@凌驾
受保护的void done(){
试一试{
布尔结果=get();
如果(结果){
System.out.println(“连接成功”);
dialog.dispose();
}否则{
System.out.println(“连接不成功”);
}
}捕捉(中断异常e){
e、 printStackTrace();
}捕获(执行例外){
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会让事情变得非常混乱 如果粘贴异常的堆栈跟踪,也会有所帮助 我怀疑问题来自帧为空的事实。这是因为帧字段仅在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
,另一个是JDialog
或JWindow
(默认情况下未修饰)
这里有一个简单的例子
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);
}
}
}
打赌