如何让 JButton 每次单击时显示 2 种不同的模式?
How do I make a JButton display 2 different modes every time I click it?
我正在尝试实现一个 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;
}
}
}}
);
为什么我点击按钮时它只显示连接?
现在,您的代码的基本轮廓是
if (button.getText().equals("Connect"){
button.setText("Disconnect")
}
if (button.getText().equals("Disconnect"){
button.setText("Connect")
}
看起来您正在将按钮文本值更改为 "Disconnect",这是您应该做的。但紧接着,您再次检查按钮文本值是否等于 "Disconnect" 并再次更改它。将您的两个 if 语句改为 else-if 语句
if (button.getText().equals("Connect"){
button.setText("Disconnect")
} else if (button.getText().equals("Disconnect"){
button.setText("Connect")
}
这个"basic"的问题是,连接的时候,你把按钮文字设置成Disconnect
,然后及时检查文字是不是Disconnect
,然后设置回Connect
.
更大的问题是你正在耦合你的代码,这将使管理和保持 UI 与实际发生的事情同步变得困难 - 如果套接字意外断开连接会发生什么。
另一个问题是,您可能会阻塞 UI,这会导致它 "freeze" 并变得无响应,因为建立套接字可能需要几秒钟。
更好的解决方案是尝试将 UI 与套接字分离并依赖某种观察者模式,这样当套接字状态发生变化时您可以得到通知,而不管 UI 停止套接字或由于其他原因停止。
就个人而言,我会为此使用 SwingWorker
,因为它允许您将长 running/blocking 操作重载到另一个线程,但提供了许多有用的机制来将更新传递回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();
}
}
}
在这个例子中,我只是使用 Thread.sleep
来放置一个 "mocked" 操作。我会考虑通过 worker 对套接字执行所有 reading/writing 并使其保持活动状态,直到它关闭套接字(无论出于何种原因)。但是,这将演示如何不基于点击状态而是基于 worker 本身的状态更新按钮
查看 Worker Threads and SwingWorker and Concurrency in Swing 了解更多详情
我正在尝试实现一个 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;
}
}
}}
);
为什么我点击按钮时它只显示连接?
现在,您的代码的基本轮廓是
if (button.getText().equals("Connect"){
button.setText("Disconnect")
}
if (button.getText().equals("Disconnect"){
button.setText("Connect")
}
看起来您正在将按钮文本值更改为 "Disconnect",这是您应该做的。但紧接着,您再次检查按钮文本值是否等于 "Disconnect" 并再次更改它。将您的两个 if 语句改为 else-if 语句
if (button.getText().equals("Connect"){
button.setText("Disconnect")
} else if (button.getText().equals("Disconnect"){
button.setText("Connect")
}
这个"basic"的问题是,连接的时候,你把按钮文字设置成Disconnect
,然后及时检查文字是不是Disconnect
,然后设置回Connect
.
更大的问题是你正在耦合你的代码,这将使管理和保持 UI 与实际发生的事情同步变得困难 - 如果套接字意外断开连接会发生什么。
另一个问题是,您可能会阻塞 UI,这会导致它 "freeze" 并变得无响应,因为建立套接字可能需要几秒钟。
更好的解决方案是尝试将 UI 与套接字分离并依赖某种观察者模式,这样当套接字状态发生变化时您可以得到通知,而不管 UI 停止套接字或由于其他原因停止。
就个人而言,我会为此使用 SwingWorker
,因为它允许您将长 running/blocking 操作重载到另一个线程,但提供了许多有用的机制来将更新传递回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();
}
}
}
在这个例子中,我只是使用 Thread.sleep
来放置一个 "mocked" 操作。我会考虑通过 worker 对套接字执行所有 reading/writing 并使其保持活动状态,直到它关闭套接字(无论出于何种原因)。但是,这将演示如何不基于点击状态而是基于 worker 本身的状态更新按钮
查看 Worker Threads and SwingWorker and Concurrency in Swing 了解更多详情