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

时间:2017-01-25 11:12:29

标签: java multithreading swing user-interface

抱歉,但这是我第一次使用主题。

我希望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

}
}

2 个答案:

答案 0 :(得分:5)

如果在Swing事件线程上调用Thread.sleep,则会将整个应用程序置于睡眠状态,使其无效,但更重要的是,不需要执行此操作。您只需让ActionListener激活需要激活的对象,因为这是事件驱动编程的工作方式。

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

答案 1 :(得分:2)

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

首先查看Lock Objects了解更多详情。

以下是该概念的一个非常基本的示例,允许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"); } } } } 继续工作,直到再次阻止“等待”

SwingWorker

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

如果您需要从其他线程出于某种原因更新UI,那么我建议您查看ActionListener,这将使您的生活更加简单。有关详细信息,请参阅Worker Threads and SwingWorker

您有一个Timer,当按钮被激活时会通知您,为什么您需要一个监视器锁来执行相关操作?是否需要花费大量时间才能启动所需的操作?您可以在单击按钮时启动新线程。

如果你正在等待某种超时,那么,说实话,Swing {{1}}可能更适合这项任务