我對如何正確安全地將事件調度線程(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