有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我对如何正确、安全地将数据从事件调度线程(EDT)上的GUI元素传递给需要与该数据交互的SwingWorker感到困惑。我跟随了stackoverflow和web上的许多例子;无论我尝试以何种方式编写,似乎我违背了从未从不同线程接触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相反


共 (1) 个答案

  1. # 1 楼答案

    我想你实际上可能想要的是一个模型来表达你的观点。也就是说:顾名思义,视图就是您的GUI及其元素——JTextFields。您的模型将是81个值的支持图。现在,如果您想在其上计算一些东西,您应该将支持映射传递给该方法(SwingWorker)。如果某个事件更改了备份模型,则会触发GUI刷新(从模型加载值)。如果用户更改GUI中的值,则应通过控制器进行更改。它会依次更改模型并启动更改事件

    这样也可以避免反馈循环

    您可以在寻找“MVC”或“模型-视图-控制器”时了解这个概念