从内部类中获取事件,扩展SwingWorker

我试图从内部类中触发事件,但它不起作用。 这是我的代码:

摘要型号:

public abstract class AbstractModel { public PropertyChangeSupport propertyChangeSupport; public AbstractModel() { propertyChangeSupport = new PropertyChangeSupport(this); } public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } } 

模型:

 public class GUImodel extends AbstractModel { // Variables private final ArrayList tempResultsTable = new ArrayList(); private static boolean done; // // RUN PROGRAM // public ArrayList run(ArrayList iF) { try { final BackgroundThread myThread = new BackgroundThread(); myThread.init(iF); myThread.execute(); } catch (Exception e) { e.printStackTrace(); } return tempResultsTable; } public void done() { System.out.println("done() called"); boolean oldValue = done; done = true; firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done); } class BackgroundThread extends SwingWorker { private ArrayList inputsFilesDataList; public void init(ArrayList iF) { inputsFilesDataList = iF; done = false; } @Override public Void doInBackground() throws Exception { for (int i = 0; i < inputsFilesDataList.size(); i++) { System.out.println(i); } return null; } @Override protected void done() { try { boolean oldValue = done; done = true; firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done); } catch (Exception e) { e.printStackTrace(); } } } } 

视图:

 public class GUIview{ ... public void propertyChange(final PropertyChangeEvent event) { if (event.getPropertyName().equals(GUIcontroller.DONE_PROPERTY)) { String newTab = (String)event.getNewValue(); updateTab(newTab); } } ... } 

摘要控制器:

 public abstract class AbstractController implements PropertyChangeListener { public final ArrayList registeredViews; public final ArrayList registeredModels; public AbstractController() { registeredViews = new ArrayList(); registeredModels = new ArrayList(); } public void addModel(AbstractModel model) { registeredModels.add(model); model.addPropertyChangeListener(this); } public void removeModel(AbstractModel model) { registeredModels.remove(model); model.removePropertyChangeListener(this); } public void addView(GUIview view) { registeredViews.add(view); } public void removeView(AbstractFrame view) { registeredViews.remove(view); } @Override public void propertyChange(PropertyChangeEvent event) { for (AbstractFrame view : registeredViews) { view.propertyChange(event); } } } 

CONTROLLER

 public class GUIcontroller extends AbstractController { public static final String DONE_PROPERTY = "done"; ArrayList inputsFilesList = m_model.loadFromExcel(); @Override public void propertyChange(PropertyChangeEvent event) { if (event.getPropertyName().equals(GUIcontroller.DONE_PROPERTY)) { m_view.getResultsModel().updateResultsTableDataList( m_model.getTempResultsTable()); } else { for (AbstractFrame view : registeredViews) { view.propertyChange(event); } } } public runProgram(){ m_model.run(inputsFilesList); } } 

主要。

 public class GUImain { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { createGUI(); } catch (Exception e) { e.printStackTrace(); } } }); } public static void createGUI() { InputsModel inputsModel = new InputsModel(); ResultsModel resultsModel = new ResultsModel(); GUImodel model = new GUImodel(); GUIcontroller controller = new GUIcontroller(); controller.addModel(model); GUIview view = new GUIview(controller, model, inputsModel, resultsModel); controller.addControllerListerners(); view.setVisible(true); } } 

对这个问题有什么看法吗?

我需要在后台线程中运行一些方法,因此我使用的是扩展SwingWorker的内部类。 该线程完成后,我需要触发一个事件来向控制器报告一些更改。

不执行done()方法中的“firePropertyChange(…)”行。

相关问题:如果某个类ClassA扩展了ClassAA,而它的内部类ClassB扩展了ClassBB,那么内部类ClassB是否也扩展了ClassAA?

一个愚蠢的疯狂的猜测:

您是否将侦听器添加到正确的SwingPropertyChangeSupport对象 ? 这必须是AbstractModel持有的对象,而不是BackgroundThread。 换句话说,为了使您的侦听器能够接收属性已更改的通知,他们必须将其PropertyChangeListener添加到AbstractModel,并且您的BackgroundThread类必须具有执行此操作的方法。

编辑
要么从您的AbstractModel类中删除PropertyChangeSupport,要么只使用由mKorbel建议的SwingWorker持有的PropertyChangeSupport。 他的回答是1+。

否则又一次,你的问题在代码/信息方面存在严重缺陷,无法在当前状态下获得真正知识渊博的答案,我们所能做的就是猜测可能出现的问题及其答案。 在这里提问时,请考虑我们的观点,问自己哪些人需要能够完全理解问题并回答问题。


编辑2

您的代码certificate我的假设实际上是正确的,您正在将PropertyChangeListener添加到错误的PropertyChangeSupport对象,以便SwingWorker中的通知 – 从未将PropertyChangeListener分配给其支持 – 将对侦听器没有影响已添加到AbstractModel的suport对象中。

这个:

 firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done); 

在SwingWorker的SwingPropertyChangeSupport对象上调用,而不是在AbstractModel的SwingPropertyChangeSupport对象上调用。

一种可能的解决方案是将您的火灾方法更改为:

 GUImodel.this.firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done); 

这样正确的支持对象就会通知正确的侦听器。


编辑3
我的SSCCE (比真正的SSCCE稍长一点)certificate了我的论点:

 import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.event.SwingPropertyChangeSupport; public class MvcSscce { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { createGUI(); } catch (Exception e) { e.printStackTrace(); } } }); } public static void createGUI() { GUImodel model = new GUImodel(); GUIcontroller controller = new GUIcontroller(); controller.addModel(model); GUIview view = new GUIview(controller); view.setVisible(true); } } class GUIview { private JPanel mainPanel = new JPanel(); private JFrame frame = new JFrame("Fubar"); public GUIview(AbstractController controller) { mainPanel.add(new JButton(controller.getButtonAction())); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(mainPanel); frame.pack(); frame.setLocationRelativeTo(null); } public void setVisible(boolean visible) { frame.setVisible(visible); } } abstract class AbstractModel { // note this should be a SwingPropertyChangeSupport public SwingPropertyChangeSupport propertyChangeSupport; public abstract void run(); public AbstractModel() { propertyChangeSupport = new SwingPropertyChangeSupport(this); } public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } } class GUImodel extends AbstractModel { private boolean done = false; public void run() { done = false; final BackgroundThread myThread = new BackgroundThread(); myThread.execute(); } private class BackgroundThread extends SwingWorker { private static final long SLEEP_TIME = 2000; @Override protected Void doInBackground() throws Exception { Thread.sleep(SLEEP_TIME); return null; } @Override protected void done() { System.out.println("done() called"); boolean oldValue = done; done = true; // fire both property change listeners and see what gets notified firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done); GUImodel.this.firePropertyChange(GUIcontroller.DONE_PROPERTY_2, oldValue, done); } } } class AbstractController implements PropertyChangeListener { private AbstractModel model; public void addModel(AbstractModel model) { this.model = model; model.addPropertyChangeListener(this); } public Action getButtonAction() { @SuppressWarnings("serial") Action buttonAction = new AbstractAction("Press Me") { @Override public void actionPerformed(ActionEvent arg0) { model.run(); } }; return buttonAction; } @Override public void propertyChange(PropertyChangeEvent evt) { String output = String.format("Evt: %s, newValue: %s", evt.getPropertyName(), evt.getNewValue()); System.out.println(output); } } class GUIcontroller extends AbstractController { public static final String DONE_PROPERTY_2 = "done property 2"; public static final String DONE_PROPERTY = "done property"; } 

请注意,延迟2秒后,将通知侦听器,但仅通知DONE_PROPERTY_2属性,而不是DONE_PROPERTY。

  • 将PropertyChangeListener添加到SwingWorker的实例 ,并且没有为SwingWorker实现的另一个Swing侦听器

  • SwingWorkerPropertyChangeListener返回事件DONEPENDINGSTARTED

  • from public void propertyChange(PropertyChangeEvent event) {你可以将正确的通知程序分发给Model ,也可以View因为done()process()publish()保证输出是在Event Dispatch Thread