在 Netbeans 中将逻辑与 Jframe 文件分离
Separating logic from Jframe file in Netbeans
我试图在同一包下的不同 class 中将逻辑与 Jframe 分开。但是当我为 Jframe 组件添加功能时,例如按钮,它会添加到 Jframe 文件中。而且我无法从那里访问逻辑文件中的对象。逻辑和图形分离的正确方法是什么?
Could you be more specific? Let's give it a context. Say I have only one object Data containing an int, a Jframe contains a button which I want it to add 1 to Data. How should I set up the system?
这基本上描述了一个模型,该模型负责控制逻辑并为其他感兴趣的各方提供所需的功能
所以你可以从一个简单的合同开始...
public interface DataModel {
public void add();
public int getData();
}
然后我会创建一个 abstract
版本的模型,它完成大部分样板工作...
public abstract class AbstractDataModel implements DataModel {
private int data;
public AbstractDataModel(int value) {
this.data = value;
}
public void add(int delta) {
data += delta;
}
@Override
public int getData() {
return data;
}
}
然后允许我创建简单的具体实现...
public class AddByOneDataModel extends AbstractDataModel {
public AddByOneDataModel(int value) {
super(value);
}
@Override
public void add() {
add(1);
}
}
或者如果你真的想变得懒惰,你可以做...
public class DeltaDataModel extends AbstractDataModel {
private int delta;
public DeltaDataModel(int delta, int value) {
super(value);
this.delta = delta;
}
@Override
public void add() {
add(delta);
}
}
但是,到目前为止,UI 没有参与其中的任何一个,它不关心,它只需要 DataModel
的一个实例
那么你的 UI 可能看起来像...
public class TestPane extends JPanel {
private DataModel model;
private JButton add;
public TestPane() {
//...
add = new JButton("Add");
add.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getModel().add();
int data = getModel().getData();
// Update the UI in some meaningful way...
}
});
//...
}
public void setModel(DataModel model) {
this.model = model;
}
public DataModel getModel() {
return model;
}
}
这样您就可以执行诸如...
TestPane pane = new TestPane();
pane.setModel(new DeltaDataModel(0, 100));
它允许您指定要使用的模型的实际功能(因为谁知道您将来想要做什么)
But I'm still a bit confused how the View and Controller part seperate from each other. Can you explain a bit still based on the example above? Also, I saw MVC are 3 objects so the main method is in none of the 3, am I correct?
正如在 , Java and GUI - Where do ActionListeners belong according to MVC pattern?, Listener Placement Adhering to the Traditional (non-mediator) MVC Pattern 和其他有关该主题的答案中所解释的那样,Swing 是 MVC 的一个实现,尽管更像是 M-VC,其中组件是独立的视图和控制器以及模型是动态的
这使得尝试包装更传统的 MVC 变得困难。相反,我们使用视图的概念是包含在容器中的一系列组件,然后符合某些指定的合同。
在更传统的 MVC 中,模型和视图不会相互交互,它们彼此之间一无所知,而是由控制器维护这种关系。
型号...
让我们返回并更新我们的模型。为了方便MVC,我们需要给它提供一个Observer Pattern,这样它就可以在模型更新时触发通知(因为模型可以独立于控制器或视图进行更新)
public abstract class AbstractDataModel implements DataModel {
private List<ChangeListener> changeListeners;
private int data;
public AbstractDataModel(int value) {
this.data = value;
changeListeners = new ArrayList<>(25);
}
@Override
public void addChangeListener(ChangeListener listener) {
changeListeners.add(listener);
}
@Override
public void removeChangeListener(ChangeListener listener) {
changeListeners.remove(listener);
}
protected void fireStateChanged() {
if (!changeListeners.isEmpty()) {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : changeListeners) {
listener.stateChanged(evt);
}
}
}
public void add(int delta) {
data += delta;
fireStateChanged();
}
@Override
public int getData() {
return data;
}
}
public class DeltaDataModel extends AbstractDataModel {
private int delta;
public DeltaDataModel(int value, int delta) {
super(value);
this.delta = delta;
}
@Override
public void add() {
add(delta);
}
}
public class AddByOneDataModel extends DeltaDataModel {
public AddByOneDataModel(int value) {
super(value, 1);
}
}
查看...
接下来,让我们来看看风景吧。首先我们为视图定义契约,这确保控制器只能做契约规定的事情。
public interface AddView {
public static final String ADD_ACTION_COMMAND = "Action.add";
public void setData(int data);
public void addActionListener(ActionListener listener);
public void removeActionListener(ActionListener listener);
}
nb:我可能还想添加一个 getComponent
方法,该方法 returns 实现实际使用的实际 JComponent
,但那会下降您想要做什么,并在其他一些链接中进行了演示
以及物理实现...
public class AddViewPane extends JPanel implements AddView {
private JButton btn;
private JLabel label;
public AddViewPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
btn = new JButton("Add");
label = new JLabel("...");
add(btn, gbc);
add(label, gbc);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireAddAction();
}
});
}
@Override
public void setData(int data) {
label.setText(NumberFormat.getNumberInstance().format(data));
}
@Override
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
@Override
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
protected void fireAddAction() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ADD_ACTION_COMMAND);
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
}
控制器...
同样,从最低层开始,向上构建功能
public interface AddController {
public DataModel getModel();
public AddView getView();
}
public class AbstractAddController implements AddController {
private AddView view;
private DataModel model;
public AbstractAddController(AddView view, DataModel model) {
this.view = view;
this.model = model;
view.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getModel().add();
}
});
model.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
getView().setData(getModel().getData());
}
});
}
@Override
public DataModel getModel() {
return model;
}
@Override
public AddView getView() {
return view;
}
}
public class DefaultAddController extends AbstractAddController {
public DefaultAddController(AddView view, DataModel model) {
super(view, model);
}
}
放在一起...
最后,您也许可以使用类似...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DataModel model = new AddByOneDataModel(0);
AddViewPane view = new AddViewPane();
DefaultAddController controller = new DefaultAddController(view, model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// This is where having a getComponent method in
// view interface would be helpful
frame.add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
把它们放在一起
我试图在同一包下的不同 class 中将逻辑与 Jframe 分开。但是当我为 Jframe 组件添加功能时,例如按钮,它会添加到 Jframe 文件中。而且我无法从那里访问逻辑文件中的对象。逻辑和图形分离的正确方法是什么?
Could you be more specific? Let's give it a context. Say I have only one object Data containing an int, a Jframe contains a button which I want it to add 1 to Data. How should I set up the system?
这基本上描述了一个模型,该模型负责控制逻辑并为其他感兴趣的各方提供所需的功能
所以你可以从一个简单的合同开始...
public interface DataModel {
public void add();
public int getData();
}
然后我会创建一个 abstract
版本的模型,它完成大部分样板工作...
public abstract class AbstractDataModel implements DataModel {
private int data;
public AbstractDataModel(int value) {
this.data = value;
}
public void add(int delta) {
data += delta;
}
@Override
public int getData() {
return data;
}
}
然后允许我创建简单的具体实现...
public class AddByOneDataModel extends AbstractDataModel {
public AddByOneDataModel(int value) {
super(value);
}
@Override
public void add() {
add(1);
}
}
或者如果你真的想变得懒惰,你可以做...
public class DeltaDataModel extends AbstractDataModel {
private int delta;
public DeltaDataModel(int delta, int value) {
super(value);
this.delta = delta;
}
@Override
public void add() {
add(delta);
}
}
但是,到目前为止,UI 没有参与其中的任何一个,它不关心,它只需要 DataModel
那么你的 UI 可能看起来像...
public class TestPane extends JPanel {
private DataModel model;
private JButton add;
public TestPane() {
//...
add = new JButton("Add");
add.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getModel().add();
int data = getModel().getData();
// Update the UI in some meaningful way...
}
});
//...
}
public void setModel(DataModel model) {
this.model = model;
}
public DataModel getModel() {
return model;
}
}
这样您就可以执行诸如...
TestPane pane = new TestPane();
pane.setModel(new DeltaDataModel(0, 100));
它允许您指定要使用的模型的实际功能(因为谁知道您将来想要做什么)
But I'm still a bit confused how the View and Controller part seperate from each other. Can you explain a bit still based on the example above? Also, I saw MVC are 3 objects so the main method is in none of the 3, am I correct?
正如在
这使得尝试包装更传统的 MVC 变得困难。相反,我们使用视图的概念是包含在容器中的一系列组件,然后符合某些指定的合同。
在更传统的 MVC 中,模型和视图不会相互交互,它们彼此之间一无所知,而是由控制器维护这种关系。
型号...
让我们返回并更新我们的模型。为了方便MVC,我们需要给它提供一个Observer Pattern,这样它就可以在模型更新时触发通知(因为模型可以独立于控制器或视图进行更新)
public abstract class AbstractDataModel implements DataModel {
private List<ChangeListener> changeListeners;
private int data;
public AbstractDataModel(int value) {
this.data = value;
changeListeners = new ArrayList<>(25);
}
@Override
public void addChangeListener(ChangeListener listener) {
changeListeners.add(listener);
}
@Override
public void removeChangeListener(ChangeListener listener) {
changeListeners.remove(listener);
}
protected void fireStateChanged() {
if (!changeListeners.isEmpty()) {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : changeListeners) {
listener.stateChanged(evt);
}
}
}
public void add(int delta) {
data += delta;
fireStateChanged();
}
@Override
public int getData() {
return data;
}
}
public class DeltaDataModel extends AbstractDataModel {
private int delta;
public DeltaDataModel(int value, int delta) {
super(value);
this.delta = delta;
}
@Override
public void add() {
add(delta);
}
}
public class AddByOneDataModel extends DeltaDataModel {
public AddByOneDataModel(int value) {
super(value, 1);
}
}
查看...
接下来,让我们来看看风景吧。首先我们为视图定义契约,这确保控制器只能做契约规定的事情。
public interface AddView {
public static final String ADD_ACTION_COMMAND = "Action.add";
public void setData(int data);
public void addActionListener(ActionListener listener);
public void removeActionListener(ActionListener listener);
}
nb:我可能还想添加一个 getComponent
方法,该方法 returns 实现实际使用的实际 JComponent
,但那会下降您想要做什么,并在其他一些链接中进行了演示
以及物理实现...
public class AddViewPane extends JPanel implements AddView {
private JButton btn;
private JLabel label;
public AddViewPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
btn = new JButton("Add");
label = new JLabel("...");
add(btn, gbc);
add(label, gbc);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireAddAction();
}
});
}
@Override
public void setData(int data) {
label.setText(NumberFormat.getNumberInstance().format(data));
}
@Override
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
@Override
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
protected void fireAddAction() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ADD_ACTION_COMMAND);
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
}
控制器...
同样,从最低层开始,向上构建功能
public interface AddController {
public DataModel getModel();
public AddView getView();
}
public class AbstractAddController implements AddController {
private AddView view;
private DataModel model;
public AbstractAddController(AddView view, DataModel model) {
this.view = view;
this.model = model;
view.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getModel().add();
}
});
model.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
getView().setData(getModel().getData());
}
});
}
@Override
public DataModel getModel() {
return model;
}
@Override
public AddView getView() {
return view;
}
}
public class DefaultAddController extends AbstractAddController {
public DefaultAddController(AddView view, DataModel model) {
super(view, model);
}
}
放在一起...
最后,您也许可以使用类似...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DataModel model = new AddByOneDataModel(0);
AddViewPane view = new AddViewPane();
DefaultAddController controller = new DefaultAddController(view, model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// This is where having a getComponent method in
// view interface would be helpful
frame.add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
把它们放在一起