gpt4 book ai didi

java - Swing 多线程。我的 GUI 卡住了

转载 作者:行者123 更新时间:2023-12-01 07:54:17 25 4
gpt4 key购买 nike

免责声明:我不会将我的程序用于任何恶意行为,即使它的名称是 Spambot。我只是用它来练习。

编辑: 我的问题是,如果我按下一个按钮,GUI 就会卡住,因此在第一个按钮完成其工作之前我无法按下另一个按钮。我该如何解决这个问题?

我创建了一个类(SpambotGUI),它基本上是一个带有 3 个 JButton 的 JFrame。这是它的代码:

public class SpambotGUI extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
static JButton button1 = new JButton("Spam first file");
static JButton button2 = new JButton("Spam second file");
static JButton button3 = new JButton("Stop");

public SpambotGUI() throws AWTException {
button1.addActionListener(this);
button2.addActionListener(this);
button3.addActionListener(this);
button1.setActionCommand("spam1");
button2.setActionCommand("spam2");
button3.setActionCommand("stop");
button1.setMnemonic(KeyEvent.VK_F7);
button2.setMnemonic(KeyEvent.VK_F8);
button3.setMnemonic(KeyEvent.VK_F9);
button3.setToolTipText("Stop the program");
add(button1, BorderLayout.WEST);
add(button2, BorderLayout.CENTER);
add(button3, BorderLayout.SOUTH);

}

public void actionPerformed(ActionEvent e) {
System.out.println(java.awt.EventQueue.isDispatchThread());
if ((e.getActionCommand()).equals("spam1")) {
try {
Spambot.Start("data/spambotLines1.txt");
} catch (FileNotFoundException | AWTException | InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} else if ((e.getActionCommand()).equals("spam2")) {
try {
Spambot.Start("data/spambotLines2.txt");
} catch (FileNotFoundException | AWTException | InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} else if ((e.getActionCommand()).equals("stop")) {
Spambot.stopped = true;
Spambot.thread.interrupt();
}

}

public static void CreateGUI() throws AWTException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SpambotGUI buttons = new SpambotGUI();
buttons.setOpaque(true);
frame.setContentPane(buttons);

frame.pack();
frame.setVisible(true);
}

public static void main(String args[]) throws Exception {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
CreateGUI();
} catch (AWTException e) {
e.printStackTrace();
}

}
});
}

}

我还有一个 Spambot 类,它由以下内容组成:在 Start 方法中,我有一个循环,包含不相关的内容和 thread.Sleep-s (我创建了一个名为 thread 的新 Thread(),这就是为什么它在 SpambotGUI 中用小写 t 拼写),并且循环应该运行直到 stopped Spambot 中的 boolean 为 false。如果我按下 GUI 中的 Stop 按钮,后者将设置为 false。问题是,当 Start 中的循环运行时,我无法单击 GUI 中的任何按钮。我在互联网上读到此后,我得出的结论是我应该在这里使用多线程。

问题是,我只是不知道它应该如何工作。我尝试在我的 Spambot 类中实现 Runnable,然后从 SpambotGUI 调用 run() 方法,但没有任何改变。

有人知道我应该在这里做什么吗?

编辑:这是 Spambot 类的一部分:

public class Spambot{

private static Robot robot;
public static Thread thread = new Thread();
public static boolean stopped = false;

public static void main(String... args) throws Exception {

}

public static void Start(String path) throws AWTException, InterruptedException, FileNotFoundException {
Scanner input = new Scanner(new FileReader(path));
Spambot keyboard = new Spambot();
Random rand = new Random();
robot.keyPress(KeyEvent.VK_ALT);
thread.sleep(150);
robot.keyPress(KeyEvent.VK_TAB);
thread.sleep(150);
robot.keyRelease(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_ALT);
thread.sleep(500);
while (input.hasNextLine() && !stopped) {
keyboard.type(input.nextLine());
thread.sleep(rand.nextInt(1500)+1000);
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
}
input.close();
}


public Spambot() throws AWTException {
Spambot.robot = new Robot();
}

public Spambot(Robot robot) {
Spambot.robot = robot;
}
}

最佳答案

您实际上可能必须启动一个新的 Thread ,因此阻塞操作不会对您的应用程序 GUI 产生太大影响。但是,更新 GUI 中的操作应由原始事件调度线程执行。

pointed in other answers ,这里的主要罪犯似乎是使用 Thread.sleep() 。当在事件调度线程中执行时,将导致 GUI 变得无响应(在完成执行事件监听器代码之前不会接受您的输入或重绘)。但是,如果在其他线程中使用 Thread.sleep() 是可以接受的(这不会卡住您的 GUI)。

如何做

首先:在单独的线程中启动阻塞处理代码。

public void actionPerformed(ActionEvent e) {
if ((e.getActionCommand()).equals("spam1")) {
new Thread(){
@Override
public void run() {
try {
Spambot.Start("data/firstfile.txt");
} catch (FileNotFoundException | InvocationTargetException |
AWTException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
// ... rest of conditions

}

其次,延迟之间的每个单独的 GUI 更新都应该在事件调度线程中完成。

EventQueue.invokeAndWait(new Runnable(){
public void run() {
robot.keyPress(KeyEvent.VK_ALT);
};
});

因为所有更新都在 robot.keyPress() 中调用时,一个不错的选择可能是封装并在方法中重用。请注意,内部类中使用的局部变量和参数应定义为final(以便它们在方法的堆栈框架之外可用)

private static void invokeRobotInAWT(final Integer ... ke) throws InvocationTargetException, InterruptedException {
EventQueue.invokeAndWait(new Runnable(){
public void run() {
for (int currentEvent : ke) {
robot.keyPress(currentEvent);
}
};
});
}

public static void Start(String path) throws AWTException, InterruptedException, FileNotFoundException, InvocationTargetException {
try (Scanner input = new Scanner(new FileReader(path));) {
Spambot keyboard = new Spambot();
Random rand = new Random();
invokeRobotInAWT(KeyEvent.VK_ALT);
Thread.sleep(150);
invokeRobotInAWT(KeyEvent.VK_TAB);
Thread.sleep(150);
invokeRobotInAWT(KeyEvent.VK_TAB, KeyEvent.VK_ALT);
Thread.sleep(500);
while (input.hasNextLine() && !stopped) {
// @@@ Would need extra threading here?
keyboard.type(input.nextLine());
Thread.sleep(rand.nextInt(1500)+1000);
invokeRobotInAWT(KeyEvent.VK_ENTER, KeyEvent.VK_ENTER);
}
} finally {
// input closed by try-with-resources
}
}

已编辑:哎呀。我对 SwingWorker 的理解有误。实际上可能就足够了。

注意: Swing 中有一些辅助组件可以使我们免于复杂且容易出错的线程处理。您实际上可能使用 SwingWorker你在哪里被覆盖doInBackground()方法(在工作线程中)遍历文件,进行暂停,并发送击键(调用 publish(Integer) ),以由重写的 process(List<Integer>) 中的 EDT 进行处理。方法。

关于java - Swing 多线程。我的 GUI 卡住了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32246105/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com