是摆动线程安全的MVC

我试图在Swing中接触MVC体系结构的限制,但是当我尝试所有的东西(从SwingWorkerRunnable#Thread )都在EDT

我的问题:

  • 是有一些限制或严格依赖的实现顺序(包装到SwingWorkerRunnable#Thread )?

  • 有限的是如果是JComponent#方法线程安全与否?

  • Swing中MVC体系结构的基本特征?

  • INC。 容器重新布局?

注意:对于我的SSCCE我采取了SSCCE一个很好的例子,也许通过严格控制这个principes是不可能产生任何EDT缺乏或GUI冻结的

在这里输入图像描述在这里输入图像描述在这里输入图像描述在这里输入图像描述

 import java.awt.BorderLayout; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.LinkedList; import java.util.Queue; import javax.swing.*; public class MVC_ProgressBarThread { private MVC_ProgressBarThread() { MVC_View view = new MVC_View(); MVC_Model model = new MVC_Model(); MVC_Control control = new MVC_Control(view, model); view.setControl(control); JFrame frame = new JFrame("MVC_ProgressBarThread"); frame.getContentPane().add(view); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { MVC_ProgressBarThread mVC_ProgressBarThread = new MVC_ProgressBarThread(); } }); } } class MVC_View extends JPanel { private static final long serialVersionUID = 1L; private MVC_Control control; private JProgressBar progressBar = new JProgressBar(); private JButton startActionButton = new JButton("Press Me and Run this Madness"); private JLabel myLabel = new JLabel("Nothing Special"); public MVC_View() { startActionButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { buttonActionPerformed(); } }); JPanel buttonPanel = new JPanel(); startActionButton.setFocusPainted(false); buttonPanel.add(startActionButton); setLayout(new BorderLayout(10, 10)); add(buttonPanel, BorderLayout.NORTH); progressBar.setStringPainted(true); add(progressBar, BorderLayout.CENTER); myLabel.setIcon(UIManager.getIcon("OptionPane.questionIcon")); myLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); add(myLabel, BorderLayout.SOUTH); } public void setControl(MVC_Control control) { this.control = control; } private void buttonActionPerformed() { if (control != null) { control.doButtonAction(); } } public void setProgress(int progress) { progressBar.setValue(progress); } public void setProgressLabel(String label) { progressBar.setString(label); } public void setIconLabel(Icon icon) { myLabel.setIcon(icon); } public void start() { startActionButton.setEnabled(false); } public void done() { startActionButton.setEnabled(true); setProgress(100); setProgressLabel(" Done !!! "); setIconLabel(null); } } class MVC_Control { private MVC_View view; private MVC_Model model; public MVC_Control(final MVC_View view, final MVC_Model model) { this.view = view; this.model = model; model.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent pce) { if (MVC_Model.PROGRESS.equals(pce.getPropertyName())) { view.setProgress((Integer) pce.getNewValue()); } if (MVC_Model.PROGRESS1.equals(pce.getPropertyName())) { view.setProgressLabel((String) pce.getNewValue()); } if (MVC_Model.PROGRESS2.equals(pce.getPropertyName())) { view.setIconLabel((Icon) pce.getNewValue()); } } }); } public void doButtonAction() { view.start(); SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { model.reset(); model.startSearch(); return null; } @Override protected void done() { view.done(); } }; swingworker.execute(); } } class MVC_Model { public static final String PROGRESS = "progress"; public static final String PROGRESS1 = "progress1"; public static final String PROGRESS2 = "progress2"; private static final int MAX = 11; private static final long SLEEP_DELAY = 1000; private int progress = 0; private String label = "Start"; private PropertyChangeSupport pcs = new PropertyChangeSupport(this); private PropertyChangeSupport pcs1 = new PropertyChangeSupport(this); private PropertyChangeSupport pcs2 = new PropertyChangeSupport(this); private final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Pig", "Fish", "Horse", "Cow", "Bee", "Skunk"}; private int index = 1; private Queue<Icon> iconQueue = new LinkedList<Icon>(); private Icon icon = (UIManager.getIcon("OptionPane.questionIcon")); public void setProgress(int progress) { int oldProgress = this.progress; this.progress = progress; PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS, oldProgress, progress); pcs.firePropertyChange(evt); } public void setProgressLabel(String label) { String oldString = this.label; this.label = label; PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS1, oldString, label); pcs1.firePropertyChange(evt); } public void setIconLabel(Icon icon) { Icon oldIcon = this.icon; this.icon = icon; PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS2, oldIcon, icon); pcs2.firePropertyChange(evt); } public void reset() { setProgress(0); } public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); pcs1.addPropertyChangeListener(listener); pcs2.addPropertyChangeListener(listener); } public void startSearch() { iconQueue.add(UIManager.getIcon("OptionPane.errorIcon")); iconQueue.add(UIManager.getIcon("OptionPane.informationIcon")); iconQueue.add(UIManager.getIcon("OptionPane.warningIcon")); iconQueue.add(UIManager.getIcon("OptionPane.questionIcon")); for (int i = 0; i < MAX; i++) { int newValue = (100 * i) / MAX; setProgress(newValue); setProgressLabel(petStrings[index]); index = (index + 1) % petStrings.length; setIconLabel(nextIcon()); try { Thread.sleep(SLEEP_DELAY); } catch (InterruptedException e) { } } } private Icon nextIcon() { Icon icon1 = iconQueue.peek(); iconQueue.add(iconQueue.remove()); return icon1; } } 

这太长了评论…

首先,这与这个答案的其余部分无关:这里有许多不同的MVC,你在这里发布的那段代码中使用的那个与你链接到的文章中使用的一样: http:/ /www.oracle.com/technetwork/articles/javase/mvc-136693.html

这篇文章正确地指出,这只是“一个常见的MVC实现” (视图注册了一个侦听器,监听模型的变化)。 您的实现是一种不同types的MVC,其中控制器注册侦听器侦听模型更改,然后更新视图。

这并不是什么问题:有很多不同types的MVC(*)。

(另一个小警告…您的视图在您的示例中已经意识到了您的控制器,这有点奇怪:还有其他方法可以执行您正在执行的操作,而无需将控制器“馈送”到视图中你的MVCView中的setControl(…) 。)

但无论如何…基本上你几乎总是从EDT外部修改GUI(你不应该这样做):

 public void setIconLabel(final Icon icon) { myLabel.setIcon(icon); } 

你可以通过添加这个来检查它:

 System.out.println("Are we on the EDT? " + SwingUtilities.isEventDispatchThread()); 

这是因为你最终从SwingWorker线程中执行了这些更新(SwingWorker线程在EDT之外运行:这基本上是Swing worker的要点)。

我宁愿从EDT更新GUI,做这样的事情:

 public void setIconLabel(final Icon icon) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { myLabel.setIcon(icon); } }); }