Java Swing GUI-如何让线程一直处于睡眠状态并通过单击唤醒


抱歉,这是我第一次使用Threads。

我希望Parlami类线程睡眠,并且只被actionListener唤醒。

我试过这种方法,但不起作用,他还在睡觉。这样使用线程正确吗?还是应该使用wait()?

package parlami;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author giacomofava
*/
public class Parlami
{
public boolean finito = false;
public String s="";
public void ascolta()
{
int i=0;
while (i<=1500)
{
// dormi 50 millisecondi 
try
{
Thread.sleep(50);
i+=40;
}
catch (InterruptedException e)
{
}
while (voce.SpeechInterface.getRecognizerQueueSize() > 0)
{
s = s+"n"+voce.SpeechInterface.popRecognizedString();
}
}
}
public String scrivi()
{
return "Hai detto: "+s;
}
public void leggi()
{
voce.SpeechInterface.synthesize(s);
}
public void dormi(int milli)
{
try
{
System.out.println("i'm sleeping");
Thread.sleep(milli);
}
catch (InterruptedException ex)
{
System.out.println("i'm awake ");
ascolta();
}
}
}

这是gui:

public class GUI extends JFrame
{
private Parlami p;
private JPanel nord, centro;
private JButton registra, leggi;
private JTextArea display;
public static void main(String[] args)
{
new GUI();
}
public GUI()
{
p=new Parlami();
initComponents();
}
private void initComponents()
{
voce.SpeechInterface.init("./lib", true, true,"./lib/gram", "vocabolario");
// N O R D
nord=new JPanel();
display=new JTextArea("");
display.setForeground(Color.GREEN);
display.setBackground(Color.BLACK);
nord.setBackground(Color.BLACK);
nord.add(display);
// C E N T R O
centro=new JPanel();
registra=new JButton("tieni premuto per registrare");
registra.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
Thread.currentThread().interrupt();// <-------- HERE I TRY TO AWAKE HIM
display.setText(p.scrivi());
}
});
centro.add(registra);
leggi=new JButton("leggi");
centro.add(leggi);
this.setLayout(new BorderLayout());
this.add(nord, BorderLayout.NORTH);
this.add(centro, BorderLayout.CENTER);
this.setSize(700,300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
p.dormi(50000);  // <-------- HERE I TELL HIM TO SLEEP
}
}

如果您在Swing事件线程上调用Thread.sleep,您将使整个应用程序进入睡眠状态,使其变得无用,但更重要的是,没有必要这样做。您只需让ActionListener激活任何需要激活的对象,因为这就是事件驱动编程的工作方式。

如果您在Swing应用程序中需要延迟,请使用Swing Timer,这是本网站上反复讨论的内容。

这是与线程锁主题相关联的线程等待/通知的基本概念。基本上,您有一些充当"锁"的公共对象,一个线程在这个线程上"等待",当另一个线程需要时,它会"通知"监视器已经发生了一些他们应该/可以响应的操作。

它将从锁定对象开始了解更多细节。

下面是这个概念的一个非常基本的例子,允许Thread连续运行,但它在公共锁上"等待"。按钮的ActionListener在按下时"通知"锁定,允许Thread继续工作,直到再次在"等待"处阻塞

import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Thread t = new Thread(new Runner());
t.start();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static final Object LOCK = new Object();
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Press me");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
synchronized (LOCK) {
LOCK.notifyAll();
}
}
});
add(btn);
}
}
public class Runner implements Runnable {
@Override
public void run() {
while (true && !Thread.currentThread().isInterrupted()) {
synchronized (LOCK) {
try {
System.out.println("Nothing to see here, just waiting");
LOCK.wait();
} catch (InterruptedException ex) {
}
}
System.out.println("Look at me, I'm busy");
}
}
}
}

记住,Swing是单线程的,从不在事件调度线程的上下文中执行任何阻塞的操作,同样,从不从EDT外部更新UI。

如果你出于某种原因需要从另一个线程更新UI,那么我建议你看看SwingWorker,它会让你的生活变得更简单。有关更多详细信息,请参阅Worker Threads和SwingWorker。

您有一个ActionListener,当按钮被激活时会收到通知,为什么您需要一个监视器锁来执行相关操作?启动所需的操作是否需要相当长的时间?单击按钮时,您可以启动一个新线程。

如果您正在等待某种超时,那么,老实说,SwingTimer可能更适合任务

最新更新