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 楼答案
我想你实际上可能想要的是一个模型来表达你的观点。也就是说:顾名思义,视图就是您的GUI及其元素——JTextFields。您的模型将是81个值的支持图。现在,如果您想在其上计算一些东西,您应该将支持映射传递给该方法(SwingWorker)。如果某个事件更改了备份模型,则会触发GUI刷新(从模型加载值)。如果用户更改GUI中的值,则应通过控制器进行更改。它会依次更改模型并启动更改事件
这样也可以避免反馈循环
您可以在寻找“MVC”或“模型-视图-控制器”时了解这个概念