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

相关问题