GUI不响应按钮点击

时间:2018-01-05 01:43:05

标签: java swing port-scanning

我试图用Java编写一个简单的端口扫描程序。它可以工作,但扫描开始后整个窗口停止响应点击。这不允许我使用停止按钮暂停操作或退出窗口。这是我的代码:

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。

2 个答案:

答案 0 :(得分:2)

欢迎来到蜂蜜的精彩世界,我阻止了事件调度线程&#34;。

首先,请查看Concurrency in Swing了解更多概述。

基本上,Swing是单线程的,而不是线程安全的。这意味着您不应该在EDT的上下文中执行长时间运行或阻塞操作,而且,您不应该从EDT上下文之外更新UI。

相反,您应该考虑使用类似@pollie = User.is_pollie?的内容,它允许您在后台运行阻止/长时间运行的操作,但提供EDT中SwingWorkerpublish更新的功能

答案 1 :(得分:2)

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