JTreeのTreeNodeが編集を開始可能かを調査する
Total: 345
, Today: 2
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
JTree
のノードエディタが編集を開始できるかどうかをTreePath
やMouseEvent
から状態を取得して判断します。
Screenshot
Advertisement
サンプルコード
JTree tree = new JTree() {
@Override public void updateUI() {
super.updateUI();
setEditable(true);
setCellEditor(makeTreeCellEditor(this));
}
@Override public boolean isPathEditable(TreePath path) {
appendLog("JTree#isPathEditable(TreePath)");
return Optional.ofNullable(path.getLastPathComponent())
.filter(TreeNode.class::isInstance)
.map(node -> {
boolean isLeaf = ((TreeNode) node).isLeaf();
appendLog(String.format(" isLeaf: %s", isLeaf));
if (node instanceof DefaultMutableTreeNode) {
int lv = ((DefaultMutableTreeNode) node).getLevel();
appendLog(String.format(" getLevel: %d", lv));
}
return isLeaf;
})
.orElse(false);
}
private TreeCellEditor makeTreeCellEditor(JTree tree) {
return new DefaultTreeCellEditor(
tree, (DefaultTreeCellRenderer) tree.getCellRenderer()) {
@Override public boolean isCellEditable(EventObject e) {
appendLog("TreeCellEditor#isCellEditable(EventObject)");
boolean ret;
if (e instanceof MouseEvent) {
MouseEvent me = (MouseEvent) e;
appendLog(" MouseEvent");
appendLog(String.format(" getPoint(): %s", me.getPoint()));
appendLog(String.format(" getClickCount: %d", me.getClickCount()));
appendLog(String.format(" isShiftDown: %s", me.isShiftDown()));
appendLog(String.format(" isControlDown: %s", me.isControlDown()));
ret = me.getClickCount() >= 2 || me.isShiftDown() || me.isControlDown();
} else if (e instanceof KeyEvent) {
appendLog(" KeyEvent");
ret = super.isCellEditable(e);
} else { // e == null
appendLog(" startEditing Action(F2)");
ret = super.isCellEditable(e);
}
return ret;
}
};
}
};
View in GitHub: Java, Kotlin解説
JTree#isPathEditable(TreePath)
- JTree#isPathEditable(TreePath) (Java Platform SE 8)
- デフォルトの
JTree
では引数のTreePath
は参照せずに常にJTree#isEditable()
を返すだけの関数のため、この関数は通常オーバーライドして使用する - このサンプルではこの関数をオーバーライドして葉ノードの場合のみ編集可能と設定
- 後述の
TreeCellEditor#isCellEditable(EventObject)
より先に実行される - 引数の
TreePath
からパス内の要素数(TreePath#getPathCount()
)や親TreePath
などを取得して編集可・不可を判断できる - 引数の
TreePath
からTreePath#getLastPathComponent()
でこのパスの最後の要素(TreeNode
、DefaultMutableTreeNode
)を取得できるので、葉ノードかどうか(TreeNode#isLeaf()
)やユーザーオブジェクト(DefaultMutableTreeNode#getUserObject()
)の状態を調査して編集可・不可を判断できる
TreeCellEditor#isCellEditable(EventObject)
- CellEditor#isCellEditable(EventObject) (Java Platform SE 8)
- 引数の
EventObject
を使用して編集を開始できるかどうかをエディタに問い合せる - このサンプルではこの関数をオーバーライドしてダブルクリック、またはShiftキーもしくはCtrlキーがクリック時に押下されている場合編集可と設定
TableCellEditor#isCellEditable(EventObject)
の場合引数のEventObject
がKeyEvent
になる場合があるがDefaultTreeCellEditor#isCellEditable(EventObject)
の場合はMouseEvent
かnull
のみになる?startEditing
アクション(F2)の場合引数のEventObject
はnull
- 引数の
EventObject
がMouseEvent
の場合JTree#isPathEditable(TreePath)
のTreePath
では取得できない以下のような情報で編集可・不可を判断できるMouseEvent#getPoint()
でJTree
座標系のクリックされた位置MouseEvent#getClickCount()
でクリック数MouseEvent#isShiftDown()
、MouseEvent#isControlDown()
などでクリックと同時にShiftキーなどが押されているか
MouseEvent#getComponent()
で親JTree
を参照しJTree#getPathForLocation(x, y)
でTreePath
、JTree#getLastSelectedPathComponent()
でTreeNode
を取得する方法もあるが、それだけの場合はJTree#isPathEditable(TreePath)
を使用すべき?- たとえばJCheckBoxをグループでまとめて有効化するのように編集対象ノードのユーザーオブジェクトの状態で編集可・不可を判断する場合、
JTree#isPathEditable(TreePath)
よりあとに実行されるTreeCellEditor#isCellEditable(EventObject)
で調査するとユーザーオブジェクトが編集不可なのに一瞬デフォルトの?(または直前に使用された?)編集可TreeCellEditor
が表示されてしまう
- たとえばJCheckBoxをグループでまとめて有効化するのように編集対象ノードのユーザーオブジェクトの状態で編集可・不可を判断する場合、
参考リンク
- JTree#isPathEditable(TreePath) (Java Platform SE 8)
- CellEditor#isCellEditable(EventObject) (Java Platform SE 8)
- JCheckBoxをグループでまとめて有効化する
JTree#isPathEditable(TreePath)
をオーバーライドしてTreePath
からDefaultMutableTreeNode
、ユーザーオブジェクトを順に取得し、これが編集可状態の場合のみノードエディタを起動
- JTreeのノード編集をJPopupMenuからのみに制限する
TreeCellEditor#isCellEditable(EventObject)
をオーバーライドしてEventObject
がMouseEvent
ではない場合のみノードエディタを起動
- JTreeのノードにクリック可能なJButtonを複数配置する
TreeCellEditor#isCellEditable(EventObject)
をオーバーライドしてEventObject
がMouseEvent
、かつクリック位置がセルレンダラー内に配置されたボタン上の場合のみノードエディタを起動