【问题标题】:How do I make a JButton display 2 different modes every time I click it?每次单击时,如何使 JButton 显示 2 种不同的模式?
【发布时间】:2019-09-17 22:04:33
【问题描述】:

我正在尝试实现一个显示连接或断开连接的 JButton,具体取决于它是否连接到服务器。因此,当我单击按钮时显示连接时,它将连接到服务器,然后显示断开连接。当我单击断开连接时,它将与服务器断开连接,并且按钮将再次显示连接。但是,当我单击按钮时,什么也没有发生。

        btnConnect.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent arg0) {

                if (btnConnect.getText().equals("Connect")){
                    btnConnect.setText("Disconnect");

                try {
                    int portNum = 5520;
                    String hostAddress = Actual_IP_Address.getText();
                    sock = new Socket(hostAddress, portNum);
                    writeSock = new PrintWriter ( sock.getOutputStream(), true);
                    readSock = new BufferedReader (new InputStreamReader(sock.getInputStream()));
                }
                catch(Exception ex) {
                    System.out.println("Error: " + ex);
                    sock = null;
                }
                }
                if (btnConnect.getText().equals("Disconnect")){
                    btnConnect.setText("Connect");

                try {
                    readSock.close();
                    writeSock.close();
                    sock.close();
                    sock = null;
                }
                catch(Exception ex) {
                    System.out.println("Error: " + ex);
                    sock = null;
                }

        }
            }}
        );

为什么当我点击按钮时它只显示连接?

【问题讨论】:

  • 附带说明,不要为此使用MouseListener,而是使用ActionListener,因为可以通过键盘和鼠标“操作”按钮;)
  • 你的套接字和 UI 逻辑也应该分开,你冒着阻塞 UI 的风险,直到套接字完成写入/读取(这实际上可能是你的首要问题的原因 - UI 赢了在退出 mouseClicked 方法之前不要更新)。我会改用观察者模式

标签: java swing jbutton action


【解决方案1】:

现在,您的代码的基本轮廓是

if (button.getText().equals("Connect"){
   button.setText("Disconnect")
}

if (button.getText().equals("Disconnect"){
   button.setText("Connect")
}

看起来正在发生的事情是您正在将按钮文本值更改为“断开连接”,就像您应该做的那样。但紧接着,您再次检查按钮文本值是否等于“断开连接”并再次更改。将您的两个 if 语句更改为 else-if 语句

if (button.getText().equals("Connect"){
   button.setText("Disconnect")
} else if (button.getText().equals("Disconnect"){
   button.setText("Connect")
}

【讨论】:

    【解决方案2】:

    这个“基本”问题是,连接后,将按钮文本设置为Disconnect,然后及时检查文本是否为Disconnect,并将其设置回Connect

    更大的问题是您正在耦合您的代码,这将难以管理并使 UI 与实际发生的事情保持同步 - 如果套接字意外断开连接会发生什么。

    另一个问题是,您可能会阻塞 UI,这会导致它“冻结”并变得无响应,因为建立套接字可能需要几秒钟。

    更好的解决方案是尝试将 UI 与套接字分离并依赖某种观察者模式,以便在套接字状态更改时通知您,无论 UI 是停止套接字还是由于某些原因而停止其他条件。

    就个人而言,我会为此使用SwingWorker,因为它允许您将长时间运行/阻塞的操作重载到另一个线程,但提供了许多有用的机制来将更新传递回 UI 线程(即事件Dispatching Thread) 安全,例如...

    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JButton doStuff;
            private SocketWorker worker;
    
            public TestPane() {
                setLayout(new GridBagLayout());
                doStuff = new JButton("Connect");
                doStuff.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent event) {
                        if (worker == null) {
                            doStuff.setText("...");
                            worker = new SocketWorker("hostname");
                            worker.addPropertyChangeListener(new PropertyChangeListener() {
                                @Override
                                public void propertyChange(PropertyChangeEvent evt) {
                                    if ("state".equals(evt.getPropertyName())) {
                                        System.out.println(worker.getState());
                                        switch (worker.getState()) {
                                            case STARTED: 
                                                doStuff.setText("Disconnect");
                                                break;
                                            case DONE: 
                                                worker = null;
                                                doStuff.setText("Connect");
                                                break;
                                        }
                                    }
                                }
                            });
                            worker.execute();
                        } else {
                            System.out.println("...");
                            try {
                                worker.stop();
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                            doStuff.setText("Connect");
                        }
                    }
                });
                add(doStuff);
            }
    
        }
    
        public class SocketWorker extends SwingWorker<Void, Void> {
    
            private Socket socket;
            private String hostName;
    
            private PrintWriter writeSock;
            private BufferedReader readSock;
    
            public SocketWorker(String hostName) {
                this.hostName = hostName;
            }
    
            @Override
            protected Void doInBackground() throws Exception {
                // This is just here to demonstrate the point
                Thread.sleep(5000);
                //int portNum = 5520;
                //socket = new Socket(hostName, portNum);
                //writeSock = new PrintWriter(socket.getOutputStream(), true);
                //readSock = new BufferedReader(new InputStreamReader(socket.getInputStream()));        
    
                // Do your socket handling here...
    
                return null;
            }
    
            public void stop() throws IOException {
                if (socket == null) { return; }
    
                socket.close();
            }
    
        }
    }
    

    在这个例子中,我刚刚使用了Thread.sleep 来放置一个“模拟”操作。我会考虑通过工作人员对套接字进行所有读/写,并使其保持活动状态,直到套接字关闭(无论出于何种原因)。但是,这将演示如何根据点击状态而不是根据工作人员本身的状态来更新按钮

    查看Worker Threads and SwingWorkerConcurrency in Swing 了解更多详情

    【讨论】:

      猜你喜欢
      • 2020-11-09
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 2013-01-20
      • 2018-12-30
      • 2016-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多