java - 如何安全地将用户 GUI 输入数据传递给 SwingWorker 并使用该数据?

标签 java thread-safety parameter-passing swingworker event-dispatch-thread

我对如何正确、安全地将数据从事件分派(dispatch)线程 (EDT) 上的 GUI 元素传递到需要与该数据交互的 SwingWorker 感到困惑。我遵循了 stackoverflow 和网络上的许多示例;无论我尝试以哪种方式编写,似乎都违反了绝不接触不同线程中的 GUI 元素的誓言。

我将尝试用伪代码来说明我的困惑。

我有一个带有一些 Swing 元素的 JFrame 来获取用户的输入。用户单击 JButton,JButton 被禁用,因此用户不能单击它两次,并且他们的输入将传递到后台线程中的 SwingWorker:

import javax.swing.*;
import java.awt.event.*;

class GUI implements Runnable{
    JFrame jFrame;
    JTextField userInputTextField;
    JButton beginLongTaskButton;

    GUI(){
        //initialize the GUI elements, add them to JFrame, JPanel, etc.

        this.beginLongTaskButton = new JButton("Begin Task");
        this.beginLongTaskButton.addActionListener(a -> beginLongTask());//lambda sure is nice
    }

    void beginLongTask(){
        this.beginLongTaskButton.setEnabled(false);
        this.beginLongTaskButton.setText("Doing your long task...");
        LongTaskWorker longTaskWorker = new LongTaskWorker(this.userInputTextField);//isn't this bad?
        longTask.execute();
    }

    @Override
    public void run(){
        this.jFrame.setVisible(true);//blah blah
    }
}

此时,EDT 应该一切正常,除了一个问题:SwingWorker 通过其构造函数获得了一些 GUI 元素:

import javax.swing.*;

class LongTaskWorker extends SwingWorker<Void, Void>{
    JTextField userInputTextField;

    public LongTaskWorker(final JTextField userInputTextField){
        this.userInputTextField = userInputTextField;//the text field on EDT I'm not supposed to touch
    }

    @Override
    protected Void doInBackground() throws Exception{
        //read lots of stuff from JTextField in this Thread (the wrong thread)?
        //write? lots of stuff to JTextField in this Thread (the wrong thread)?
        //do lots of other stuff to JTextField?

        return null;
    }
}

我见过很多人做类似的事情。我认为即使是 JavaDoc SwingWorker 示例也是这样做的。但这是否意味着我在不应该的情况下弄乱了不同线程上的对象?读取(不更改)GUI 组件的值是否仍然违反跨线程规则?如果我的 SwingWorker 必须频繁地从 GUI 元素读取数据,这不会减慢 EDT 的速度吗?

也许正确的做法是从 EDT 内的 GUI 元素中提取我需要的数据,然后将提取的数据传递给 SwingWorker?与直接将 GUI 元素传递给 SwingWorker 不同。

最佳答案

我认为您实际上可能想要的是您的 View 的模型。也就是说: View 顾名思义就是您的 GUI 及其元素 - JTextFields。您的模型将是 81 个值(value)观的支持 map 。现在,如果您想对其进行计算,您可以将支持 Map 传递给该方法 (SwingWorker)。如果支持模型发生更改,则事件应触发 GUI 刷新(从模型加载值)。如果用户更改 GUI 中的值,则应通过 Controller 进行更改。它依次更改模型并启动更改事件。

这样您还可以避免反馈循环。

您可以通过查找“MVC”或“ Model View Controller ”来了解此概念。

关于java - 如何安全地将用户 GUI 输入数据传递给 SwingWorker 并使用该数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32557334/

相关文章:

java - java List适合addAll和clear上的线程安全的什么方法

C++ 将数组传递给函数

c++ - 在 C++ 标准中通过指向函数的指针传递数组的严格规则背后的原因

javascript - 如何正确传递参数?

java - 适用于 Android 的 RTP 库

java - 在 Android/Java 中格式化 MAC 地址而不会产生不必要的垃圾

java - JAX-RS @POST 语法

java - 在 Java 中将大 Wav 文件提取为较小的 block

c# - List<T> 的线程安全,只有一个 Writer,没有 Enumerators

c# - 多重锁定任务(线程)