我正在尝试从内部类中触发事件,但它无法正常工作。这是我的代码:
摘要模型:
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);
}
}
MODEL:
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<Void, Void> {
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<AbstractFrame> registeredViews;
public final ArrayList<AbstractModel> 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);
}
}
MAIN。
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?
答案 0 :(得分:2)
添加PropertyChangeListener to instance of SwingWorker,并且没有为Swing Listener实施其他SwingWorker
SwingWorker
从DONE
PENDING
,STARTED
,PropertyChangeListener
来自public void propertyChange(PropertyChangeEvent event) {
的您也可以将Model
和View
分配给done()
,process()
,publish()
{ {1}}保证输出在Event Dispatch Thread
答案 1 :(得分:2)
愚蠢的疯狂猜测:
您是否将侦听器添加到 正确的SwingPropertyChangeSupport对象 ?这必须是AbstractModel持有的对象,而不是BackgroundThread。换句话说,为了让您的侦听器能够接收属性已更改的通知,他们必须将其PropertyChangeListener添加到AbstractModel,并且您的BackgroundThread类必须具有执行此操作的方法。
(修改强>)
要么从您的AbstractModel类中删除PropertyChangeSupport,要么只使用由mKorbel建议的SwingWorker持有的PropertyChangeSupport。他的回答是1+。
另外,您的问题在代码/信息方面存在严重缺陷,无法在当前状态下获得真正知识渊博的答案,我们所能做的就是猜测可能存在的问题及其答案。在这里提问时,请考虑我们的观点,问自己哪些人需要能够完全理解问题并回答问题。
修改2
您的代码证明我的假设实际上是正确的,您正在将PropertyChangeListener添加到错误的PropertyChangeSupport对象中,以便SwingWorker中的通知 - 从未将PropertyChangeListener分配给其支持 - 将不起作用在已添加到AbstractModel的suport对象的侦听器上。
这:
firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done);
在SwingWorker的SwingPropertyChangeSupport对象上调用,而不是在AbstractModel的对象上调用。
一个可能的解决方案是将您的火灾方法更改为:
GUImodel.this.firePropertyChange(GUIcontroller.DONE_PROPERTY, oldValue, done);
以便正确的支持对象通知正确的侦听器。
编辑3
我的SSCCE(比真正的SSCCE稍长一点)证明了我的论点:
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<Void, Void> {
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。