GUI 不响应按钮点击
GUI is not responding to button clicks
我正在尝试在 Java 中编写一个简单的端口扫描器。它可以工作,但是一旦扫描开始,整个 window 就会停止响应点击。这将不允许我使用停止按钮暂停操作或退出 window。这是我的代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.swing.*;
import java.awt.event.*;
public class GUIScanner {
JFrame frame = new JFrame("Port Scanner");
JTextField textField = new JTextField("",20);
JPanel panel = new JPanel();
JButton button = new JButton("Scan");
JButton button2 = new JButton("Stop");
JLabel label = new JLabel("");
boolean stopped = false;
public GUIScanner() {
initialize();
}
public static void main(String[] args) {
GUIScanner scanner = new GUIScanner();
}
public void initialize() {
panel.add(textField);
panel.add(button);
panel.add(button2);
frame.add(panel);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String address = textField.getText().toString();
scanHost(address, 200);
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stopped) {
stopped = true;
button2.setText("Resume");
} else {
stopped = false;
button2.setText("Stop");
}
}
});
}
public void scanHost(String ip, int timeout) {
while(!stopped) {
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stopped) {
stopped = true;
button2.setText("Resume");
} else {
stopped = false;
button2.setText("Stop");
}
}
});
for(int port = 0; port <= 65535; port++) {
frame.setTitle("Scanning port " + port + " of 65535");
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
System.out.println(port);
} catch (IOException e) {
}
}
}
}
}
我不确定问题是线程问题还是我的代码中的其他问题。我对 Java 相当缺乏经验。如果有帮助,我正在使用 Eclipse Oxygen。
欢迎来到 "Honey, I blocked the Event Dispatching Thread" 的精彩世界。
首先查看 Concurrency in Swing 以获得更多概述。
本质上,Swing 是单线程的并且不是线程安全的。这意味着您不应该在 EDT 上下文中执行长 运行ning 或阻塞操作,而且,您也不应该从 EDT 上下文之外更新 UI。
相反,您应该考虑使用 SwingWorker
之类的东西,它允许您 运行 blocking/long 运行 在后台执行操作,但提供 publish
和 process
在 EDT
中更新
在后台使用 SwingWorker 运行 另一个线程。这可以防止 Swing 在您暂停后台线程时被阻塞。这是端口扫描器代码的更正版本:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.swing.*;
import java.awt.event.*;
public class GUIScanner {
JFrame frame = new JFrame("Port Scanner");
JTextField textField = new JTextField("", 20);
JPanel panel = new JPanel();
JButton button = new JButton("Scan");
JButton button2 = new JButton("Stop");
JLabel label = new JLabel("");
boolean stopped = false;
PausableSwingWorker<Void, String> scanningWorker;
abstract class PausableSwingWorker<K, V> extends SwingWorker<K, V> {
private volatile boolean isPaused;
final Object lock = new Object();
public final void pause() {
if (!isPaused() && !isDone()) {
isPaused = true;
}
}
public final void resume() {
if (isPaused() && !isDone()) {
isPaused = false;
synchronized(lock) {
lock.notify();
}
}
}
public final boolean isPaused() {
return isPaused;
}
}
public GUIScanner() {
initialize();
}
public static void main(String[] args) {
GUIScanner scanner = new GUIScanner();
}
public void initialize() {
panel.add(textField);
panel.add(button);
panel.add(button2);
frame.add(panel);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String address = textField.getText().toString();
scanHost(address, 200);
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!stopped) {
stopped = true;
button2.setText("Resume");
scanningWorker.pause();
} else {
stopped = false;
button2.setText("Stop");
scanningWorker.resume();
}
}
});
}
public void scanHost(String ip, int timeout) {
scanningWorker = new PausableSwingWorker<Void, String>() {
@Override
public Void doInBackground() {
for (int port = 0; port <= 65535; port++) {
if (!isPaused()) {
frame.setTitle("Scanning port " + port + " of 65535");
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
System.out.println("Port " + port + " is open");
} catch (IOException e) {
}
}
else {
synchronized(lock) {
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return null;
}
@Override
public void done() {
}
};
scanningWorker.execute();
}
}
我正在尝试在 Java 中编写一个简单的端口扫描器。它可以工作,但是一旦扫描开始,整个 window 就会停止响应点击。这将不允许我使用停止按钮暂停操作或退出 window。这是我的代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.swing.*;
import java.awt.event.*;
public class GUIScanner {
JFrame frame = new JFrame("Port Scanner");
JTextField textField = new JTextField("",20);
JPanel panel = new JPanel();
JButton button = new JButton("Scan");
JButton button2 = new JButton("Stop");
JLabel label = new JLabel("");
boolean stopped = false;
public GUIScanner() {
initialize();
}
public static void main(String[] args) {
GUIScanner scanner = new GUIScanner();
}
public void initialize() {
panel.add(textField);
panel.add(button);
panel.add(button2);
frame.add(panel);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String address = textField.getText().toString();
scanHost(address, 200);
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stopped) {
stopped = true;
button2.setText("Resume");
} else {
stopped = false;
button2.setText("Stop");
}
}
});
}
public void scanHost(String ip, int timeout) {
while(!stopped) {
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stopped) {
stopped = true;
button2.setText("Resume");
} else {
stopped = false;
button2.setText("Stop");
}
}
});
for(int port = 0; port <= 65535; port++) {
frame.setTitle("Scanning port " + port + " of 65535");
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
System.out.println(port);
} catch (IOException e) {
}
}
}
}
}
我不确定问题是线程问题还是我的代码中的其他问题。我对 Java 相当缺乏经验。如果有帮助,我正在使用 Eclipse Oxygen。
欢迎来到 "Honey, I blocked the Event Dispatching Thread" 的精彩世界。
首先查看 Concurrency in Swing 以获得更多概述。
本质上,Swing 是单线程的并且不是线程安全的。这意味着您不应该在 EDT 上下文中执行长 运行ning 或阻塞操作,而且,您也不应该从 EDT 上下文之外更新 UI。
相反,您应该考虑使用 SwingWorker
之类的东西,它允许您 运行 blocking/long 运行 在后台执行操作,但提供 publish
和 process
在 EDT
在后台使用 SwingWorker 运行 另一个线程。这可以防止 Swing 在您暂停后台线程时被阻塞。这是端口扫描器代码的更正版本:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.swing.*;
import java.awt.event.*;
public class GUIScanner {
JFrame frame = new JFrame("Port Scanner");
JTextField textField = new JTextField("", 20);
JPanel panel = new JPanel();
JButton button = new JButton("Scan");
JButton button2 = new JButton("Stop");
JLabel label = new JLabel("");
boolean stopped = false;
PausableSwingWorker<Void, String> scanningWorker;
abstract class PausableSwingWorker<K, V> extends SwingWorker<K, V> {
private volatile boolean isPaused;
final Object lock = new Object();
public final void pause() {
if (!isPaused() && !isDone()) {
isPaused = true;
}
}
public final void resume() {
if (isPaused() && !isDone()) {
isPaused = false;
synchronized(lock) {
lock.notify();
}
}
}
public final boolean isPaused() {
return isPaused;
}
}
public GUIScanner() {
initialize();
}
public static void main(String[] args) {
GUIScanner scanner = new GUIScanner();
}
public void initialize() {
panel.add(textField);
panel.add(button);
panel.add(button2);
frame.add(panel);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String address = textField.getText().toString();
scanHost(address, 200);
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!stopped) {
stopped = true;
button2.setText("Resume");
scanningWorker.pause();
} else {
stopped = false;
button2.setText("Stop");
scanningWorker.resume();
}
}
});
}
public void scanHost(String ip, int timeout) {
scanningWorker = new PausableSwingWorker<Void, String>() {
@Override
public Void doInBackground() {
for (int port = 0; port <= 65535; port++) {
if (!isPaused()) {
frame.setTitle("Scanning port " + port + " of 65535");
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
System.out.println("Port " + port + " is open");
} catch (IOException e) {
}
}
else {
synchronized(lock) {
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return null;
}
@Override
public void done() {
}
};
scanningWorker.execute();
}
}