我试图在同一个包下的另一个类中将逻辑与Jframe分开。但是当我为Jframe conponents添加函数时,例如它在Jframe文件中添加了一个按钮。而且我无法从那里访问逻辑文件中的对象。什么是分离逻辑和图形的正确方法?
答案 0 :(得分:0)
你可以更具体一点吗?让我们给它一个背景。假设我只有一个对象Data包含一个int,一个Jframe包含一个按钮,我希望它将1添加到Data。我该如何设置系统?
这基本上描述了一个模型,该模型负责控制逻辑并为其他感兴趣的各方提供所需的功能
所以你可以从简单的合同开始......
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);
}
}
但是,到目前为止,用户界面并未参与其中任何一项,它并不关心,它只需要一个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));
允许您指定要使用的模型的实际功能(因为谁知道您将来想要做什么)
但是我仍然有点混淆视图和控制器部分彼此分离。你可以根据上面的例子解释一下吗?另外,我看到MVC是3个对象所以主要的方法是3个都没有,我是否正确?
如How MVC work with java swing GUI,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
方法,该方法返回实现实际使用的实际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);
}
});
把它们放在一起