[英]Implementing threading in Swing's EDT?
我的项目是基于Java的Swing库构建的。 它产生了显示我的GUI(正常工作)的EDT。
该计划的入口,初始化EDT:
public final class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Start());
}
class Start implements Runnable {
private Model model = new Model();
private Controller controller = new Controller(model);
private View view = new View(controller);
@Override
public void run() {
// Initialize the view and display its JFrame...
}
}
}
}
但是,当在我的GUI中单击按钮/单选框/等时,Controller类必须对模型执行操作。
我的问题如下:
例如:
public class Controller {
public void updateModel() {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
model.somethingSomethingSomething();
}
}.execute();
}
}
public class Model {
public void somethingSomethingSomething() {
notifyListeners(); // This is going to notify whichever GUI
// is listening to the model.
// Does it have to be wrapped with Swing.invokeLater?
}
}
public class View {
// This function is called when the model notifies its listeners.
public void modelChangedNotifier() {
button.setText("THE MODEL HAS CHANGED"); // Does this occur on the EDT?
}
}
您可以在此处阅读: 使用Java SE 6中的SwingWorker提高应用程序性能 。 简而言之: 所有耗时的操作,不受影响的UI必须在另一个线程中完成 。 要显示操作结果,您必须返回EDT。 例如,如果进行数据库搜索,则应显示进度条(通常为无限)并使用SwingWorker开始搜索。 要在表格中显示搜索结果,您必须在EDT中。 或者你可以使用foxtrot lib (它允许你的代码更方便Swing而不需要重新设计它)。 如果您的控制器代码永久更新swing小部件,您应该在EDT中执行它,或者至少在EDT中执行UI的这些更新(使用SwingUtilities.invokeLater,SwingWorker中的块处理或swing.Timer)。 所以你的样本是错的:模型更新应该在EDT中是最新的。
而不是从doInBackground()
更新模型, publish()
中间结果并从在EDT上执行的process()
更新模型。 在此示例中 , JTable
对应于您的View
而TableModel
对应于您的Model
。 请注意, JTable
侦听自己的TableModel
。
来自实践9.4.2中的Java Concurrency的一种替代方法使用“拆分”或“共享数据模型”。 您可以在任何您想要的线程上更新您的业务模型,可能是长期运行的非EDT线程。 但是,不是直接调用notifyListeners()并担心你所在的线程,而只需调用myComponent.repaint(),它将在EDT上排队重绘请求。
然后,在paintComponent()
方法的某处,显式地从Model中获取所有新数据,通常在名为modelToView()
的方法中
commentTextArea.setText(myModel.getCommentText());
fooLabel.setText(myModel.getFooText());
...
好处是线程不是一个问题,并且,至少对某些人来说,这“有道理”,并且模型与视图很好地分离。 缺点是您每次都要重置所有值。 所以,如果你有100个JComponents,那就是设置的100件事。 此外,视图与模型紧密耦合。
工作代码示例
@MadProgrammer和@kleopatra是正确的,如果视图直接包含正在更新的组件,则会出现“无限循环的厄运”。 有关证明,请参阅
但是,如果视图与组件隔离 ,则可以避免无限循环。 通常情况下,更高级别的视图将包含JSplitPanes,持有JScrollPanes,持有Box或更多JPanels等内容,保留实际的低级别组件。 所以这个要求,IMO,并非不合理。
为Downvoters添加了一些评论 :
有些人想打败Swing 。 他们正在编写仪器控制代码或算法,只想在不担心EDT,无休止的SwingWorkers和invokeLaters的情况下完成工作。 这项技术让他们完成了自己的工作。 有一个重要的警告,它有效。 (就个人而言,我理解并且通常喜欢Swing,但很多人不喜欢)。
虽然Swing组件很适合MVC,但它们通常都处于微观层面。 “真实”模型不是单个String,而是几十个值。 “真正的”视图不是单个JLabel,它是许多JPanel,每个都有许多组件,结合了滚动条,分离器等。这种技术通常更适合现实世界,允许程序员自然地在更高层次上思考。
至于“糟糕的做法”,请与Brian Goetz,Josh Bloch等人讨论,好吧,这是“对权威的吸引力”,但它对我有用。 :-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.