Java 关于操作实施和具有多个视图的单个模型使用的不确定性
我对GUI编程完全是个新手,也许我的问题已经解决了 一个非常简单的解决方案。 我正在尝试实现一个JavaSwingGUI,作为 用于树状数据结构的编辑器。GUI分为三个部分 部分:Java 关于操作实施和具有多个视图的单个模型使用的不确定性,java,swing,model-view-controller,Java,Swing,Model View Controller,我对GUI编程完全是个新手,也许我的问题已经解决了 一个非常简单的解决方案。 我正在尝试实现一个JavaSwingGUI,作为 用于树状数据结构的编辑器。GUI分为三个部分 部分: 窗口左四分之一处的树查看器显示 树结构数据 右上角的大区域显示包含文本字段的编辑器, 桌子之类的。树中每种不同类型的对象 结构有自己的编辑器,当在 树查看器 右下角区域显示控制台查看器。它用于显示 有关特定操作的消息 我正努力遵守严格的模型与模型的分离 在我的程序的树查看器/编辑器中进行可视化。所以我 创建Defau
private JTextField textField = new JTextField(10);
...
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath path = e.getNewLeadSelectionPath();
if (path != null) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
Resource user = (Resource) node.getUserObject();
textField.setText(user.toString());
} else {
textField.setText("");
}
}
}
});
textField.addActionListener(new AbstractAction("edit") {
@Override
public void actionPerformed(ActionEvent e) {
TreePath path = tree.getSelectionPath();
if (path != null) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
String s = textField.getText();
Resource user = (Resource) node.getUserObject();
user.setName(s);
treeModel.reload(node);
}
}
}
});
我知道我可以将动作对象附加到JMenu、jpopmpmenu和
甚至可以使用setAction方法创建JTextField对象。我
这样做了,现在我在程序的“编辑”中有一个“重命名”菜单项
菜单,在与表示
树查看器和显示节点名称的JTextField也有
附带的行动
为了更改树节点的“Name”属性,我创建了这个类
重命名为AbstractAction的子类。如前所述
名称显示在树查看器和操作的每个节点上
只是使此文本可编辑。执行此操作的代码如下所示
(在重命名节点类中):
需要这些if语句才能使操作从以下方面正常工作:
--弹出菜单(第一个if语句;此处为
打开弹出菜单时的鼠标可编辑)
--应用程序的菜单(第二个if语句;这里是树节点
当前选中的(如果有)将被设置为可编辑)
好吧,这在原则上很好,但实际上
节点不是通过RenameAction类的
actionPerformed(ActionEvent ev)方法。节点属性的真实变化
name在方法中树的MyTreeModel类中执行
valueForPathChanged(),其覆盖方式如下:
public class MyTreeModel extends DefaultTreeModel {
[...]
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
final MyTreeNode aNode = (MyTreeNode)path.getLastPathComponent();
if (newValue instanceof String) {
((MyNode) aNode.getUserObject()).setName((String) newValue);
} else {
aNode.setUserObject(newValue);
}
nodeChanged(aNode);
}
[...]
}
我完全不知道行动的概念是如何恰当地表达出来的
在这里申请。
更糟糕的是,重命名操作在运行时的情况
已执行更改JTextField对象中的文本的操作。此刻我
我不知道如何以干净的方式实现这一点。JTextField应该
从树模型结构中将单个节点关联为其
模型和附加的操作应修改该模型,以及何时修改该模型
模型已更改,树查看器需要得到更新通知
树查看器中相应节点的名称
我假设MyNode类(它始终是
DefaultMutableTreeNode)必须实现接口文档
RenameAction类必须修改它,然后修改一个事件
必须发出通知以通知显示
已更改节点
一句话:我必须承认,我还没有完全明白怎么做
正确地执行将在多个位置使用的操作
在GUI中,我不完全理解如何实现模型
可以由多个GUI对象使用(在我的例子中是JTree和
JTextField)。可能所有这些都很简单
提前感谢您的帮助
给出的答案对解释行动是如何进行的很有帮助
可与JTrees一起使用。但还有一点我想讨论。
在我的GUI中,我有一个业务数据的树表示
使用数据编辑器(位于窗口左四分之一处的树,旁边是特定于节点类型的编辑器)。所有节点都有可以更改的名称。并且,编辑器包含一个文本字段(使用JTextField实现),其中显示节点的名称,也可以对其进行编辑。我的不确定性如下:
JTextField允许分配操作对象和
模仿它。实际上,模型将是已经在JTree中查看的节点对象。我认为应该有一种方法可以使用JTree中使用的相同模型对象,也可以作为编辑器中JTextField的模型,并且还可以重用那里的Action类。关于模型的重用,我认为我的模型类MyTreeNode也必须实现文档接口,对吗?当打开特定于节点的编辑器时,我必须使用其setDocument()方法将当前在JTree中选择的节点与JTextField对象相关联。
最后,我的RenameNodeAction必须执行
JTextField的节点名称。
因此,我的中心观点是:在多个视图中显示一个模型,并在要重命名节点的任何位置重用一个重命名操作。这有意义吗?我的想法是如何做到这一点是可行的吗?哇,太详细了!谢谢 好的,我对
JTable
做了类似的操作(插入/删除行)
基本上你需要一个动作
public class RenameNodeAction extends AbstractAction {
private JTree tree;
public RenameNodeAction(JTree tree) {
this.tree = tree;
// Initialise action as you require...
}
// Access to the tree, provide mostly so you can extend the action
public JTree getTree() {
return tree;
}
public void actionPerformed(ActionEvent evt) {
JTree tree = getTree();
TreePath path = tree.getSelectionPath();
if (path != null && tree.isPathEditable(path)) {
tree.startEditingAtPath(path);
}
}
}
private JTextField textField = new JTextField(10);
...
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath path = e.getNewLeadSelectionPath();
if (path != null) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
Resource user = (Resource) node.getUserObject();
textField.setText(user.toString());
} else {
textField.setText("");
}
}
}
});
textField.addActionListener(new AbstractAction("edit") {
@Override
public void actionPerformed(ActionEvent e) {
TreePath path = tree.getSelectionPath();
if (path != null) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
String s = textField.getText();
Resource user = (Resource) node.getUserObject();
user.setName(s);
treeModel.reload(node);
}
}
}
});
public class RenameNode extends AbstractAction
implements TreeSelectionListener, CellEditorListener {
// Replace with whatever you're storing your text fields with
private FieldStorage fields;
private JTree tree;
public RenameNode(FieldStorage fields, JTree tree) {
this.fields = fields;
this.tree = tree;
}
public void actionPerformed(ActionEvent ev) {
// "mouseOverPath" is the Treepath were the mouse was placed on
// when the popup menu was opened
if (tree.existsMouseOverPath()) {
tree.startEditingAtPath(tree.mouseOverPath);
} else if (tree.getSelectionCount() != 0) {
tree.startEditingAtPath(tree.getSelectionPath());
}
}
public void valueChanged(TreeSelectionEvent e) {
tree.startEditingAtPath(tree.getSelectionPath());
setFieldText();
}
public void editingCanceled(ChangeEvent e) {
// empty
}
public void editingStopped(ChangeEvent e) {
setFieldText();
}
private void setFieldText() {
MyTreeNode node = (MyTreeNode) tree.getSelectionPath()
.getLastPathComponent();
String text = node.getUserObject().toString();
fields.getFieldFor(node).setText(text);
}
}
RenameNode renameNodeAction = new RenameNode(fields, tree);
tree.addTreeSelectionListener(renameNodeAction);
// editor is your TreeCellEditor. Can be the DefaultTreeCellEditor
// if you haven't already made your own
editor.addCellEditorListener(renameNodeAction);
tree.setCellEditor(editor);
tree.setEditable(true);