首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使主方法等待GUI上的输入而不使用侦听器作为直接触发器?

如何使主方法等待GUI上的输入而不使用侦听器作为直接触发器?
EN

Stack Overflow用户
提问于 2012-08-01 21:24:00
回答 1查看 2.4K关注 0票数 0

我正在开发一个the抓取工具,它应该对被刮掉的数据执行各种操作。

正因为如此,我需要各种不同的GUI来有序地工作,正因为如此,我需要主要的方法来等待,直到每个人都完成了它的目的。

在搜索了一段时间之后,我发现了以下StackOverflow问题,这些问题提供了一些关于如何解决问题的线索,但我无法实现,因为它们与我的情况有些不同:

如何等待文本字段中的输入 如何使主线程等待另一个线程完成

我知道我可以使用侦听器触发/GUI组件(例如按钮)的代码,但我很难让主线程等待该侦听器唤醒它,而GUI线程的代码(当有一个线程时)由主线程初始化.

这是一段简化的代码,用来演示程序应该如何工作:

代码语言:javascript
复制
public class Main {
    /*
     * Waiter is a simple GUI with just an "Start" button in it. Here in place of my actual GUIs.
     */
    private static Waiter auth; //Represents my NTLM-authentication form.
    private static Waiter status; //Represents a status-feedback GUI that will be displayed during processing.
    private static Waiter operation; //Represents a GUI in with the user choses what to do with the gathered data.

    public static void main(String[] args) throws InterruptedException {
        auth = new Waiter();
        auth.setVisible(true);
        System.out.println("NTLM Authentication form. Should wait here until user has filled up the GUI and clicked \"Start\".");
        System.out.println("Authenticates WebClient's NTLM using data inputed to the GUI...");
        auth.dispose();
        Thread srt = new Thread(status = new Waiter());
        srt.start();
        status.setVisible(true);
        //Performs webscraping operations...
        System.out.println("Prepares the webscraped data here...Things like downloading files and/or parsing text...");
        System.out.println("Keeps the user aware of the progress using the \"status\" GUI.");
        status.setVisible(false);
        //Clears the status GUI.
        operation = new Waiter();
        operation.setVisible(true);
        System.out.println("Operation selection form. Should wait here until user selects an option.");
        System.out.println("Starts performing the operation(s)...");
        operation.dispose();
        status.setVisible(true);
        System.out.println("Performs the operation(s), while giving status-feedback to the user.");
        status.setVisible(false);
        System.out.println("Displays a file-save dialog to save the results.");
        System.out.println("And finally, displays a \"End of operations\" dialog before ending.");
    }
}

更新1:我面临的主要困难是实现这样的东西(这就是我想要做的):

代码语言:javascript
复制
//Main method...code...
Thread srt = new Thread(status = new Waiter());
//Before "srt.start();"...
status.startButton.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
    main.continueExecution();
  }
});
//Thread's run() being something like "status.setVisible(true); main.waitGUI();"
srt.start();
//continues here after the Listener is triggered...more code...

而不是这个(如果我理解得对的话,大多数人的解决方案是什么?)(这就是我不想做的事情,如果可能的话):

代码语言:javascript
复制
//GUI before this one...
//code...
Thread srt = new Thread(status = new Waiter());
status.startButton.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
    /*
     * Code that should come after this GUI.
     */
  }
});
//Thread's run() being something like "status.setVisible(true);"
srt.start();
//"ends" here...(Initial code or GUI before this "status")

换句话说,我在实现GUI和监听器时遇到了困难,无法触发main线程的“睡眠”和“唤醒”操作,而不是触发实际的处理代码。

更新2:

按照@JB_Nizet关于SwingUtilities.invokeLater()的技巧,我很好地了解了SwingUtilities文档,在了解了SwingUtilities.invokeAndWait()方法是如何工作的之后,我想我已经找到了如何使用SemaphoreinvokeAndWait()的组合来实现它。

我需要一个更好地理解多线程和/或GUI的人来确认它是否是一个安全、有效的解决方案。(然后我会编辑这个问题并把它清理干净,如果确认的话,以正确的“回答格式”发布)

无论如何,修改后的代码似乎适用于我:

代码语言:javascript
复制
public class Main_Test {

    //Semaphore:
    public static Semaphore semaphore;
    //GUIs:
    private static Waiter auth; //Represents my NTLM-authentication form.

    public static void main(String[] args) {
        try {
            semaphore = new Semaphore(1);
//          semaphore.acquire();
            auth = new Waiter() {

                @Override
                public void run() {
                    try {
                        System.out.println(Main_Test.getThread() + this.getName() + " has been created and is now running.");
                        semaphore.acquire(); //Makes main pause.
                        this.setVisible(true);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Main_Test.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            };
            auth.jButton1.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    System.out.println(getThread() + "NTLM has been hypothetically authenticated.");
                    semaphore.release(); //Makes main continue after GUI is done.
                    auth.dispose();
                }
            });
//          semaphore.release();
            SwingUtilities.invokeAndWait(auth);
            semaphore.acquire(); //<- Where the main effectively gets paused until the permit is released.
            /*
             * GUI's run() will accquire the semaphore's permit.
             * The invokeAndWait() garantees (?) it will happen before main's acquire().
             * This causes the main to pause when trying to acquire the permit.
             * It stays paused until the actionListener release() that permit.
             */
            System.out.println(getThread() + "This message represents the processing, and should come only after the hypothetical NTLM authentication.");
        } catch (InterruptedException ex) {
            Logger.getLogger(Main_Test.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(Main_Test.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static String getThread() {
        return String.format("%-32s --- ", Thread.currentThread().toString());
    }
}
EN

回答 1

Stack Overflow用户

发布于 2012-08-02 13:19:34

我不确定我是否完全理解您想要做什么,但在我看来,您有一个使用者线程(主线程,等待事件分派线程中的事件)和一个生产者线程(事件分派线程)。

实现这一点的典型方法是使用阻塞队列作为通信机制:

  • 创建阻塞队列
  • 创建GUI并将阻塞队列传递给它
  • 启动一个循环,从队列中获取数据。由于队列是阻塞的,主线程将被阻塞,直到队列中有什么东西。
  • 让您的事件侦听器在EDT中运行,将数据发送到阻塞队列。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11767788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档