我对如何正确安全地将事件调度线程(EDT)上的GUI元素的数据传递给需要与该数据交互的SwingWorker的数据感到困惑。我遵循了stackoverflow和网络上的许多示例;无论我尝试写什么样的方式,它似乎都打破了从不接触不同线程的GUI元素的誓言。如何安全地将用户GUI输入数据传递给SwingWorker并使用该数据?
我会试着用伪码来说明我的困惑。
我有一个带有一些摆动元素的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
}
}
在这一刻,在美国东部时间应该只是坐在漂亮,但有一个问题: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相反。
而不是传递TextField,只是传递它的值,你就完成了。 – Fildor
感谢您的回复。通过传递“它的值”,你的意思是传递jTextField.getText()?我认为这就是我在我的帖子中提出的最后一个问题的意思。在我的实际程序中,我有81个JTextField,我已经添加到HashMap中,这就是我需要传递和使用的。确切地说, – Yankee
。只需从'getText()'传递字符串即可。你需要传递Hashmap?你能解释一下更详细一点吗? – Fildor