0

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

+2

而不是傳遞TextField,只是傳遞它的值,你就完成了。 – Fildor

+0

感謝您的回覆。通過傳遞「它的值」,你的意思是傳遞jTextField.getText()?我認爲這就是我在我的帖子中提出的最後一個問題的意思。在我的實際程序中,我有81個JTextField,我已經添加到HashMap中,這就是我需要傳遞和使用的。確切地說, – Yankee

+0

。只需從'getText()'傳遞字符串即可。你需要傳遞Hashmap?你能解釋一下更詳細一點嗎? – Fildor

回答

1

我想你實際上可能需要的是你的視圖模型。即:視圖顧名思義就是您的GUI及其元素 - JTextFields。您的模型將成爲81值的支持地圖。現在,如果你想計算一些東西,你可以將支持Map傳遞給該方法(SwingWorker)。如果某件事更改了支持模型,則事件應該觸發GUI刷新(從模型加載值)。如果用戶在GUI中更改某個值,則應通過控制器進行更改。它反過來改變模型並啓動變更事件。

這樣你也可以避免反饋循環。

您可以閱讀關於尋找「MVC」或「Model View Controller」的這個概念。

+0

我從來沒有聽說過這種MVC類型的設計策略,但是你打開了一個全新的可能性來實現我想要的東西。我對此有點學習,看起來很酷。非常感謝您的建議!如果有效,我最終會將您的答案標記爲正確。 – Yankee

相關問題