Java 如何使JButton每次单击时显示2种不同的模式?

Java 如何使JButton每次单击时显示2种不同的模式?,java,swing,jbutton,action,Java,Swing,Jbutton,Action,我正在尝试实现一个JButton,它根据是否连接到服务器来显示Connect或Disconnect。因此,当我点击按钮,当它说连接时,它将连接到服务器,然后它将显示断开连接。当我单击Disconnect时,它将与服务器断开连接,按钮将再次显示connect。但是,当我单击按钮时,什么也没有发生 btnConnect.addMouseListener(new MouseAdapter() { @Override public void

我正在尝试实现一个JButton,它根据是否连接到服务器来显示Connect或Disconnect。因此,当我点击按钮,当它说连接时,它将连接到服务器,然后它将显示断开连接。当我单击Disconnect时,它将与服务器断开连接,按钮将再次显示connect。但是,当我单击按钮时,什么也没有发生

        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;
                }

        }
            }}
        );

为什么当我单击按钮时,它只显示Connect?

现在,代码的基本轮廓是

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

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

if (button.getText().equals("Connect"){
   button.setText("Disconnect")
} else if (button.getText().equals("Disconnect"){
   button.setText("Connect")
}
这个“基本”问题是,当连接时,您将按钮文本设置为
Disconnect
,然后立即检查文本是否为
Disconnect
,并将其设置回
Connect

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

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

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

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

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();
        }

    }
}
导入java.awt.GridBagLayout;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.beans.PropertyChangeEvent;
导入java.beans.PropertyChangeListener;
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.PrintWriter;
导入java.net.Socket;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
导入javax.swing.SwingWorker;
公开课考试{
公共静态void main(字符串[]args){
新测试();
}
公开考试(){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
JFrame=新JFrame();
frame.add(newtestpane());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共类TestPane扩展了JPanel{
私人杜斯塔夫;
私人网络工人;
公共测试窗格(){
setLayout(新的GridBagLayout());
doStuff=新的JButton(“连接”);
addActionListener(新的ActionListener(){
@凌驾
已执行的公共无效操作(操作事件){
if(worker==null){
doStuff.setText(“…”);
worker=新的SocketWorker(“主机名”);
worker.addPropertyChangeListener(新的PropertyChangeListener(){
@凌驾
公共作废属性更改(属性更改事件evt){
if(“state”.equals(evt.getPropertyName())){
System.out.println(worker.getState());
开关(worker.getState()){
案件开始:
doStuff.setText(“断开”);
打破
案件完成:
worker=null;
doStuff.setText(“连接”);
打破
}
}
}
});
worker.execute();
}否则{
System.out.println(“…”);
试一试{
工人。停止();
}捕获(IOEX异常){
例如printStackTrace();
}
doStuff.setText(“连接”);
}
}
});
添加(doStuff);
}
}
公共类SocketWorker扩展SwingWorker{
专用插座;
私有字符串主机名;
私人印刷撰稿人writeSock;
专用缓冲读卡器读卡器;
公共SocketWorker(字符串主机名){
this.hostName=主机名;
}
@凌驾
受保护的Void doInBackground()引发异常{
//这只是为了证明这一点
睡眠(5000);
//int-portNum=5520;
//套接字=新套接字(主机名、端口号);
//writeSock=新的PrintWriter(socket.getOutputStream(),true);
//readSock=new BufferedReader(新的InputStreamReader(socket.getInputStream());
//在这里做你的插座处理。。。
返回null;
}
public void stop()引发IOException{
如果(socket==null){return;}
socket.close();
}
}
}
在本例中,我刚刚使用了
Thread.sleep
来放置一个“mock”操作。我会考虑做你所有的事情