2

これが私の問題です:

ここに画像の説明を入力してください

基本的に、JTreeの要素が右クリックされたときにドロップダウンメニューを作成しています。問題は、JTreeがJScrollPane内にあり、ペインがスクロールされるほど、ポップアップメニューが遠くに移動することです。

右クリックすると、次のコードでインターセプトされるMouseEventが起動し、その結果、新しいポップアップメニューが作成されます。

@Override
public void mouseClicked(MouseEvent e) {
    if (SwingUtilities.isRightMouseButton(e)) {

        int row = tree.getClosestRowForLocation(e.getX(), e.getY());
        tree.setSelectionRow(row);

        TreePath path = tree.getPathForRow(row);  

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();  

        // If this object is a Search...
        if(node.getUserObject().getClass() == Search.class) {
            jp = new ItemEditPopUpMenu(tree, row, true);
        } else {
            jp = new ItemEditPopUpMenu(tree, row, false);
        }

        jp.show(this, e.getX(), e.getY());
    }
}

ご覧のとおり、私が行っているのは、MouseEventから位置を取得し、それを次の行でポップアップメニューを作成する場所として使用することだけです。

jp.show(this, e.getX(), e.getY());

これがイベントを送信した要素に対する相対的な位置であることに気づきました。これが問題を説明しています。JScrollPanelはスクロールされるとJFrameからオフセットされます。問題は、どのくらいの距離を知ることができるかということです。

わからないのですが、それが私に助けが必要なことです。よろしくお願いします!

4

4 に答える 4

7

問題はないようです。

ポップアップへの参照としてビューポート「view」を使用すると、ポップアップにはマウスがクリックされた場所が正確に表示されます。

ツリーへの参照をポップアップに渡していないことを想像することしかできません...

ここに画像の説明を入力してください

ポイント変換の混乱になるだろうと思っていましたが、結局のところ、それは可能な限り単純でした...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestScrollPane {

    public static void main(String[] args) {
        new TestScrollPane();
    }

    public TestScrollPane() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(new TestPane()));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private List<Point> points;
        private JPopupMenu pm;

        public TestPane() {
            pm = new JPopupMenu();
            pm.add(new JLabel("Suprise"));
            points = new ArrayList<>(3);
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    Point p = e.getPoint();
                    points.clear();
                    points.add(p);
                    // View port
                    Container parent = getParent();
                    Point pp = SwingUtilities.convertPoint(TestPane.this, p, parent);
                    points.add(pp);
                    // ScrollPane...
                    parent = parent.getParent();
                    Point ppp = SwingUtilities.convertPoint(TestPane.this, p, parent);
                    points.add(ppp);

                    pm.show(TestPane.this, p.x, p.y);

                    repaint();
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(1000, 1000);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (points.size() == 3) {
                g2d.setColor(Color.RED);
                Point p = points.get(0);
                g2d.fillOval(p.x - 2, p.y - 2, 4, 4);

                g2d.setColor(Color.GREEN);
                p = points.get(1);
                g2d.fillOval(p.x - 2, p.y - 2, 4, 4);

                g2d.setColor(Color.BLUE);
                p = points.get(2);
                g2d.fillOval(p.x - 2, p.y - 2, 4, 4);
            }
            g2d.dispose();
        }
    }
}

私が何かを見逃していないことを確認するために、これはJTree

ここに画像の説明を入力してください

(テスト用にカスタムセルレンダリングを捨てることができます。これは私が置いていたスクラップコードでした)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;

public class TestCustomTreeNode {

    public static void main(String args[]) {
        new TestCustomTreeNode();
    }
    private JPopupMenu pm;

    public TestCustomTreeNode() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                pm = new JPopupMenu();
                pm.add(new JLabel("Suprise"));

                JFrame f = new JFrame("JTree Sample");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JPanel pnlMain = new JPanel(new BorderLayout());
                pnlMain.setBackground(Color.white);

                createTree(pnlMain);

                f.setContentPane(new JScrollPane(pnlMain));

                f.setSize(300, 200);
                f.setVisible(true);
            }
        });
    }

    private void createTree(JPanel pnlMain) {
        Employee bigBoss = new Employee(Employee.randomName(), true);
        Employee[] level1 = new Employee[5];
        bigBoss.employees = level1;

        for (int i = 0; i < level1.length; i++) {
            level1[i] = new Employee(Employee.randomName(), true);
        }


        for (int i = 0; i < level1.length; i++) {
            Employee employee = level1[i];
            if (employee.isBoss) {
                int count = 5;
                employee.employees = new Employee[count];

                for (int j = 0; j < employee.employees.length; j++) {
                    employee.employees[j] = new Employee(Employee.randomName(), false);
                }
            }
        }

        CustomTreeNode root = new CustomTreeNode(loadResource("/pirate.png"), bigBoss);
        root.setUserObject("Root");
        DefaultTreeModel model = new DefaultTreeModel(root);

        for (Employee employee : bigBoss.employees) {
            CustomTreeNode boss = new CustomTreeNode(loadResource("/angel.png"), employee);
            root.add(boss);
            if (employee.isBoss) {
                for (Employee employee1 : employee.employees) {
                    CustomTreeNode emp = new CustomTreeNode(loadResource("/devil.png"), employee1);
                    boss.add(emp);
                }
            }
        }

        JTree tree = new JTree(model);
        tree.setCellRenderer(new CustomeTreeCellRenderer());
        pnlMain.add(tree, BorderLayout.CENTER);

        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    pm.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });

    }

    protected ImageIcon loadResource(String name) {

        ImageIcon image = null;
        try {
            image = new ImageIcon(ImageIO.read(getClass().getResource(name)));
            System.out.println(name + " - " + image);
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        return image;

    }

    public static class Employee {

        public String name;
        public int id;
        public boolean isBoss;
        public Employee[] employees;

        public Employee(String name, boolean isBoss) {
            this.name = name;
            this.isBoss = isBoss;
            this.id = new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE);
        }

        @Override
        public String toString() {
            return this.name;
        }

        static String randomName() {
            String chars = "abcdefghijklmnopqrstuvwxyz";
            StringBuilder builder = new StringBuilder();
            Random r = new Random(System.currentTimeMillis());
            int length = r.nextInt(10) + 1;
            for (int i = 0; i < length; i++) {
                builder.append(chars.charAt(r.nextInt(chars.length())));
            }

            return builder.toString();
        }
    }

    public class CustomTreeNode extends DefaultMutableTreeNode {

        /**
         * The icon which is displayed on the JTree object. open, close, leaf icon.
         */
        private ImageIcon icon;

        public CustomTreeNode(ImageIcon icon) {
            this.icon = icon;
        }

        public CustomTreeNode(ImageIcon icon, Object userObject) {
            super(userObject);
            this.icon = icon;
        }

        public CustomTreeNode(ImageIcon icon, Object userObject, boolean allowsChildren) {
            super(userObject, allowsChildren);
            this.icon = icon;
        }

        public ImageIcon getIcon() {
            return icon;
        }

        public void setIcon(ImageIcon icon) {
            this.icon = icon;
        }
    }

    class CustomeTreeCellRenderer extends DefaultTreeCellRenderer {

        public CustomeTreeCellRenderer() {
        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {

//            if (!leaf) {
            CustomTreeNode node = (CustomTreeNode) value;

            if (node.getIcon() != null) {
                System.out.println(node + " - " + node.getIcon());
                setClosedIcon(node.getIcon());
                setOpenIcon(node.getIcon());
                setLeafIcon(node.getIcon());
            } else {
                System.out.println(node + " - default");
                setClosedIcon(getDefaultClosedIcon());
                setLeafIcon(getDefaultLeafIcon());
                setOpenIcon(getDefaultOpenIcon());
            }
//            }

            super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);

            return this;
        }
    }
}

nb:ポップアップトリガーはプラットフォームごとに異なる可能性があるため、マウスイベントを変更する必要がある場合があります。これは、Windowsでは問題なく機能します。

JPopupMenu#showこのことから、渡したコンポーネント参照はマウスイベントを生成したものではないと結論付けることができます。

于 2013-03-06T06:53:47.790 に答える
3

私が使用した:

PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
SwingUtilities.convertPointFromScreen(b, component);

コンポーネントは私のJTreeでした。これは、マウスの画面位置を取得し、Swingに埋め込まれた変換ユーティリティ関数を使用して機能させるように見えます。これが誰かを助けることを願っています!

于 2013-03-06T04:31:14.010 に答える
3

私はこの問題を逐語的に、JTreeそしてすべて持っていました。受け入れられた回答は有用であることがわかりましたが、何が問題で、修正がどのように見えるかを理解するには、まだ掘り下げが必要でした.

したがって、問題のコードは次のようになります。

final Component parent = ...
final JTree tree = ...
final JPopupMenu menu = ...

parent.add(tree);

tree.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        if (e.getButton() == MouseEvent.BUTTON3) // Right click
            menu.show(parent, e.getX(), e.getY());
    }
});

エラーは明らかなはずです。

はfromMouseEventによって生成されましたが、 toとして渡しています。これにより、スクリーンショットで望ましくない動作が発生します。treeMouseListenerparentinvokermenu.show(...)

tree修正は、次のようにinvokertomenu.show(...)として渡すことです。

final Component parent = ...
final JTree tree = ...
final JPopupMenu menu = ...

parent.add(tree);

tree.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        if (e.getButton() == MouseEvent.BUTTON3) // Right click
            menu.show(tree, e.getX(), e.getY());
    }
});
于 2016-06-03T00:40:13.337 に答える
1

これは良い解決策ではないかもしれませんが、それはあなたの問題を解決します。

ここでの問題は、e.getX()またはと言うときe.getY()、返される座標はJTreeを基準にしていることです。与えられたスクリーンショットからわかるように、JTreeを下にスクロールしたので、「Y」座標から垂直スクロールバーの値の差を差し引く必要があります。

int verticalScrollValue = scrollPane.getVerticalScrollBar().getValue();
jp.show(this, e.getX(), e.getY() - verticalScrollValue);
于 2013-03-06T04:42:14.310 に答える