私は GUI プログラミングに関してまったくの初心者であり、おそらく私の問題には非常に単純な解決策があります。データ構造のようなツリーのエディターとして機能する Java Swing GUI を実装しようとしています。GUI は次の 3 つの部分に分かれています。
ウィンドウの左 4 分の 1 にあるツリー ビューアには、ツリー構造のデータが表示されます。
右上の大きな領域には、テキスト フィールド、テーブルなどを含むエディタが表示されます。ツリー構造内のさまざまな種類のオブジェクトには、ツリー ビューアで選択したときに表示される独自のエディタがあります。
右下の領域には、コンソール ビューアーが表示されます。特定のアクションに関するメッセージを表示するために使用されます。
私は、プログラムのツリー ビューアー/エディターでモデルを視覚化から厳密に分離することに懸命に取り組んでいます。したがって、ビジネス データへの参照を格納する DefaultTreeModel (MyTreeModel) のサブクラスのインスタンスと、ツリー構造の視覚的表現を提供する JTree のサブクラスのインスタンスを作成しました。
Action クラスを使用してデータを変更する機能を実装しようとしています。すべてのアクション (CreateNode、RenameNode、DeleteNode など) は、独自のアクション クラス (AbstractAction のサブクラス) に実装されます。アクションは、ツリー ビューアのコンテキスト メニューとアプリケーションの [編集] メニューで使用されます。しかし、RenameNode アクションなど、GUI のエディター部分で再利用したいものもあります。そして、ここで私は現在立ち往生しています。
ツリー ビューアには、ツリー内のすべてのノードの名前とともにアイコンが表示されます。また、それぞれのエディタには、関連するノードの名前を示す JTextField も含まれています。
setAction メソッドを使用して、アクション オブジェクトを JMenu、JPopupMenu、さらには JTextField オブジェクトにアタッチできることを知っています。私はそうしましたが、プログラムの「編集」メニューに「名前の変更」メニューエントリがあり、ツリービューアを表すJTreeに関連付けられたポップアップメニューにあり、ノード名を示すJTextFieldにもこのアクションが添付されています。
ツリー ノードの「名前」属性を変更するために、クラス RenameNode を AbstractAction のサブクラスとして作成しました。すでに述べたように、名前はツリー ビューアの各ノードに表示され、アクションは単にこのテキストを編集可能にします。これを行うコードは次のようになります (クラス RenameNode 内):
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());
}
}
これらの if ステートメントは、アクションを適切に機能させるために必要です。
-- ポップアップ メニュー (最初の if ステートメント。ここでは、ポップアップ メニューを開いたときにマウスの下にあったオブジェクトを編集可能にします)
-- アプリケーションのメニュー (2 番目の if ステートメント。ここでは、現在選択されているツリー ノード (存在する場合) が編集可能になります)。
これは原理的には問題なく動作しますが、実際にはノードの名前変更は RenameAction クラスの actionPerformed(ActionEvent ev) メソッドのコードでは行われません。ノードの名前の実際の変更は、次のようにオーバーライドされるメソッド valueForPathChanged() のツリーの MyTreeModel クラスで実行されます。
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 のサブクラスである) は Document インターフェイスを実装する必要があり、RenameAction クラスはそれを変更する必要があり、次にイベントを発行してツリー ビューアーに通知する必要があると想定しています。ノードを変更しました。
結論: GUI の複数の場所で使用されるアクションを適切に実装する方法をまだ完全には理解していないこと、および複数の GUI オブジェクトで使用できるモデルを実装する方法を完全に理解していないことを認めなければなりません。 (私の場合は JTree と JTextField)。おそらくすべてが非常に単純です...
助けてくれてありがとう!
与えられた回答は、アクションを JTree と一緒に使用する方法を説明するのに非常に役立ちました。しかし、もう 1 つ議論したい点があります。私の GUI には、ビジネス データのツリー表示と、データ用のエディター (ウィンドウの左側の 4 分の 1 にあるツリーと、その横にあるノード タイプ固有のエディター) が組み合わされています。すべてのノードには変更可能な名前があります。また、エディタには、ノードの名前が表示され、編集可能なテキスト フィールド (JTextField で実装) が含まれています。ここでの私の不確実性は次のとおりです。JTextField を使用すると、アクション オブジェクトとモデルをそれに割り当てることができます。実際には、モデルは JTree ですでに表示されているノード オブジェクトになります。JTree で使用されているのと同じモデル オブジェクトをエディターの JTextField のモデルとして使用し、そこで Action クラスを再利用する方法が必要だと思います。モデルの再利用に関しては、私のモデル クラス MyTreeNode も Document インターフェイスを実装する必要があると思いますよね?また、ノード固有のエディタを起動するときは、setDocument() メソッドを使用して、JTree で現在選択されているノードを JTextField オブジェクトに関連付ける必要があります。最後に、RenameNodeAction で JTextField のノードの名前を変更する必要があります。したがって、私の中心的なポイントは、1 つのモデルを複数のビューに表示し、ノードの名前を変更するあらゆる場所で 1 つの RenameAction を再利用することです。これは理にかなっており、これを実現する方法は私の考えですか? モデルの再利用に関しては、私のモデル クラス MyTreeNode も Document インターフェイスを実装する必要があると思いますよね?また、ノード固有のエディタを起動するときは、setDocument() メソッドを使用して、JTree で現在選択されているノードを JTextField オブジェクトに関連付ける必要があります。最後に、RenameNodeAction で JTextField のノードの名前を変更する必要があります。したがって、私の中心的なポイントは、1 つのモデルを複数のビューに表示し、ノードの名前を変更するあらゆる場所で 1 つの RenameAction を再利用することです。これは理にかなっており、これを実現する方法は私の考えですか? モデルの再利用に関しては、私のモデル クラス MyTreeNode も Document インターフェイスを実装する必要があると思いますよね?また、ノード固有のエディタを起動するときは、setDocument() メソッドを使用して、JTree で現在選択されているノードを JTextField オブジェクトに関連付ける必要があります。最後に、RenameNodeAction で JTextField のノードの名前を変更する必要があります。したがって、私の中心的なポイントは、1 つのモデルを複数のビューに表示し、ノードの名前を変更するあらゆる場所で 1 つの RenameAction を再利用することです。これは理にかなっており、これを実現する方法は私の考えですか? setDocument() メソッドを使用して、JTree で現在選択されているノードを JTextField オブジェクトに関連付ける必要があります。最後に、RenameNodeAction で JTextField のノードの名前を変更する必要があります。したがって、私の中心的なポイントは、1 つのモデルを複数のビューに表示し、ノードの名前を変更するあらゆる場所で 1 つの RenameAction を再利用することです。これは理にかなっており、これを実現する方法は私の考えですか? setDocument() メソッドを使用して、JTree で現在選択されているノードを JTextField オブジェクトに関連付ける必要があります。最後に、RenameNodeAction で JTextField のノードの名前を変更する必要があります。したがって、私の中心的なポイントは、1 つのモデルを複数のビューに表示し、ノードの名前を変更するあらゆる場所で 1 つの RenameAction を再利用することです。これは理にかなっており、これを実現する方法は私の考えですか?