Java JTreeにポップアップメニューを実装しようとしています。DefaultTreeCellRenderer(ノードの外観を変更するため)とDefaultTreeCellEditor(イベントリスナーをアタッチするコンポーネントを作成するため)をサブクラス化しました。 DefaultTreeCellRenderer.getTreeCellRendererComponent()が返すコンポーネントはそれを実行できませんか?)ノードを「編集」したくありません。ノードが右クリックされたときにメニューをポップアップできるだけですが、これは私が今それを行うことを考えることができる唯一の方法...
以下は、私がこれまでに持っているコードです-私は、MouseEventsをキャプチャする方法を理解しようとしています。それは一種の仕事ですが、ひどいです。私がここでやろうとしていることを達成するためのより良い方法は何ですか?
private class My_TreeCellRenderer extends DefaultTreeCellRenderer {
My_TreeCellRenderer() {
super ();
}
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
// set label text and tool tips
setText(((My_Object)value).getTreeLabel());
setToolTipText(((My_Object)value).getTreeToolTip());
return this;
}
}
private class My_TreeCellEditor extends DefaultTreeCellEditor {
private MouseAdapter ma;
My_TreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
super (tree, renderer);
ma = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
System.out.println("My Popup");
}
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
System.out.println("My Popup");
}
}
};
}
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
String src_filename = null;
// return non-editing component
Component c = renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, true);
// add mouse listener if it's not listening already
MouseListener mouseListeners[] = c.getMouseListeners();
int i;
for (i=0; i < mouseListeners.length && mouseListeners[i] != ma; i++);
if (i >= mouseListeners.length)
c.addMouseListener(ma);
return c;
}
protected boolean canEditImmediately(EventObject event) {
if (event instanceof MouseEvent && ((MouseEvent)event).getClickCount() == 1)
return true;
else
return false;
}
}
このタスクは簡単に実行でき、必要なものは次のとおりです。
//create a class which implements the MouseListener interface and
//implement the following in your overridden mouseClicked method
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = tree.getClosestRowForLocation(e.getX(), e.getY());
tree.setSelectionRow(row);
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
次に、このカスタムリスナーを目的のツリーに追加できます。
JTree API から直接取得
// If you are interested in detecting either double-click events or when a user clicks on a node, regardless of whether or not it was selected, we recommend you do the following:
final JTree tree = ...;
MouseListener ml = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int selRow = tree.getRowForLocation(e.getX(), e.getY());
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
if(selRow != -1) {
if(e.getClickCount() == 1) {
mySingleClick(selRow, selPath);
}
else if(e.getClickCount() == 2) {
myDoubleClick(selRow, selPath);
}
}
}
};
tree.addMouseListener(ml);
もちろん、左クリックではなく右クリックのために少し変更する必要があります
みんな、ありがとう。シンプルなポップアップの実装に多くの労力を費やしていたときに、何かがおかしいと思いました。
探しているノードを見つけるためにx座標とy座標に頼るのは変だと感じたので、最初はこの考えを却下しましたが、これはその方法だと思います。
// add MouseListener to tree
MouseAdapter ma = new MouseAdapter() {
private void myPopupEvent(MouseEvent e) {
int x = e.getX();
int y = e.getY();
JTree tree = (JTree)e.getSource();
TreePath path = tree.getPathForLocation(x, y);
if (path == null)
return;
tree.setSelectionPath(path);
My_Obj obj = (My_Obj)path.getLastPathComponent();
String label = "popup: " + obj.getTreeLabel();
JPopupMenu popup = new JPopupMenu();
popup.add(new JMenuItem(label));
popup.show(tree, x, y);
}
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) myPopupEvent(e);
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) myPopupEvent(e);
}
};
(...)
JTree tree = new JTree();
tree.addMouseListener(ma);
あなたは物事を必要以上に難しくしていると思います。
JTreeにはいくつかの「add_foo_Listener」メソッドがあります。それらの1つを実装すると(TreeSelectionListenerはほぼ正常に見えます)、現在選択されているノードを取得します。
マウスリスナーを実装して、右クリックイベントを検出し(JTreeはコンポーネントであるため、JTreeに追加できます)、コンテキスト依存のメニューをポストするために必要なものがすべて揃うようにします。
詳細はこちら チュートリアル をご覧ください。
レンダラーは一時的な「ゴム印」にすぎないため、その上に入力リスナーを追加することは特に役立ちません。あなたが指摘するように、編集者は編集するためにジェスチャーを行った後にのみそこにいます。したがって、リスナーをJTreeに追加したいとします(複合コンポーネントとして実装されていない場合)。
addRightClickListener()
を呼び出して、右クリックコンテキストメニューリスナーをJTree
に追加します。どちらのオーバーライドも、適切なクロスプラットフォーム機能のためのものです(Windows
とLinux
はここでは異なります)。
private void addRightClickListener()
{
MouseListener mouseListener = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
handleContextMenu(mouseEvent);
}
@Override
public void mouseReleased(MouseEvent mouseEvent)
{
handleContextMenu(mouseEvent);
}
};
tree.addMouseListener(mouseListener);
}
private void handleContextMenu(MouseEvent mouseEvent)
{
if (mouseEvent.isPopupTrigger())
{
MyContextMenu contextMenu = new MyContextMenu();
contextMenu.show(mouseEvent.getComponent(),
mouseEvent.getX(),
mouseEvent.getY());
}
}