1

私が作成した「キャンバス」クラス (拡張された ) を使用して Java で問題が発生しJPanel、アニメーションのリング チャートを描画しました。このグラフは を使用しMouseListenerてクリック イベントを取得しています。

問題は、マウスの位置が正確ではないように見えることです。つまり、「キャンバス」に対して相対的ではなく、ウィンドウに対して相対的であるように見えます (左上隅で、y 座標に約 30px を取得しました)。

これは私のコードです:

JPanel を拡張し、メンバーとして BufferedImage を持つクラスを作成しました。

public class Canvas extends JPanel {

    public BufferedImage buf;
    private RingChart _parent;

    public Canvas(int width, int height, RingChart parent){
        buf = new BufferedImage(width, height, 1);
    ...

ペイント コンポーネント メソッドでは、バッファリングされたイメージを描画するだけなので、公開されているバッファリングされたイメージにペイントすることで、「外側」からキャンバスにペイントできます。

public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g; 
        g2.drawImage(buf, null, 0, 0); 

    }

「キャンバス」を含む RingChart クラスがあります。

public class RingChart extends JFrame{

    public Canvas c;
    ...

そして、キャンバス クラスで bufferedImage から Graphics2D を作成します。この g2d はペイントに使用されます:

public RingChart(){
    c = new Canvas(1500,980,this);
    add(c);
    setSize(1500, 1000);
    setTitle("Hans");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    g2d = (Graphics2D)c.buf.createGraphics();
    ...

私が今達成しようとしていたのは、キャンバス上で発生するマウス イベントをリッスンするマウス リスナーでした。したがって、ユーザーがキャンバスをクリックすると、イベント変数を介して、キャンバス上でクリックした位置を取得できます。

そこで、マウス リスナーを作成しました。

class MouseHandler implements MouseListener {

    @Override
    public void mouseClicked(MouseEvent e){
        RingChart r = ((Canvas)e.getSource()).getParent();
        r.mouseClick(e);
    }
    ...

...そして、このマウス リスナーを RingChart クラスのキャンバスに追加しました (myChart は RingChart のインスタンスで、c は含まれるキャンバスです)。

        ...
        MouseHandler mouse = new MouseHandler();
        myChart.c.addMouseListener(mouse);
        ...

しかし、上で述べたように、クリック イベントが呼び出されたときに返されるマウスの位置は正確ではないようです。間違いは、私がその mouseListener を作成した方法、または間違った要素に割り当てた方法などにあるに違いないと思います。しかし、私はかなりのことを試しましたが、それは変わりませんでした。私が間違ったことを誰かが教えてくれますか?

アップデート:

RingChart のメンバーであり、マウス リスナーで呼び出される関数「mouseClick」のコード:

public void mouseClick(MouseEvent evt){
    //evt = SwingUtilities.convertMouseEvent(this, evt, c);
    if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
        for(Element e : elements){
            if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
                //do some stuff
            }
        }
    }
}

繰り返しますが、私のクラスの階層: RingChart --contains a--> Canvas --got a--> MouseListener. この関数の形状は、キャンバス c に描かれた形状です。ユーザーがそれらのいずれかをクリックしたかどうかを確認したいと思います。私が思ったように、形状はキャンバス座標にある必要があり、イベントの位置はキャンバス座標にある必要があり、すべてが一致する必要があります。しかし、そうではありません。ここで、ユーザー MadProgrammer から、ConvertMouseEvent 関数を使用するように言われました。しかし、現在、これを賢明に使用する正確な方法はわかりません。

アップデート:

私は解決策を見つけました:私がしなければならなかったのは、キャンバスをに直接追加するJFrameのではなくContentPaneJFrame代わりにのに追加することだけです:

代わりに:

public RingChart(){
    c = new Canvas(1500,980,this);
    add(c);
    ...

そうです:

public RingChart(){
    c = new Canvas(1500,980,this);
    getContentPane().add(c);
    ...

次に、 を に渡しMouseListenerますContentPane

getContentPane().addMouseListener(new MouseHandler());
getContentPane().addMouseMotionListener(new MouseMoveHandler());

これがエレガントなソリューションかどうかはわかりませんが、機能します。

4

1 に答える 1

5

マウス イベントは、それが発生したコンポーネントに関連するように自動的に変換されます。つまり、ポイント 0x0 は常にコンポーネントの左上隅になります。

を使用RingChart r = ((Canvas)e.getSource()).getParent()することで、参照を効果的に変更したことになります。これは、場所が無効になったことを意味します。

座標が親コンポーネントのコンテキストになるように場所を変換する必要があります。SwingUtilities.convertMouseEvent(Component, MouseEvent, Component)を見てください。

写真で更新

この例を見てみましょう...

サンプル

青いボックスの相対位置は、赤いボックスに対して 50px x 50px です。青いボックスをクリックすると、たとえば 25x25 で、マウス座標は青いボックスに相対的になります (0x0 は青いボックスの左上になります)。

次に、このイベントを赤いボックスに渡し、そこから座標を使用しようとすると、座標がコンテキスト依存であるため、座標が赤いボックスの左上と青いボックスの中間になることがわかります。

動作させるには、マウス イベントの場所を青いボックスから赤いボックスに変換する必要があります。これにより、75x75 になります。

さて、マウスイベントをに渡すときに何をしているのかわからないRingChartので、これがあなたが直面している問題だと推測しているだけです。

クリックコードで更新

さて、Canvas100x100 の があるとしましょう。Canvas50x50でそれをクリックします。次に、その値をチェーンに戻します。

public void mouseClick(MouseEvent evt){
    //evt = SwingUtilities.convertMouseEvent(this, evt, c);
    if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
        for(Element e : elements){
            // Here, we are asking the shape if it contains the point 50x50...
            // Not 150x150 which would be the relative position of the click
            // in the context to the RingChart, which is where all your objects
            // are laid out.
            // So even the original Canvas you clicked on will return 
            // false because it's position + size (100x100x width x height) 
            // does not contain the specified point of 50x50...
            if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
                //do some stuff
            }
        }
    }
}

更新しました

私はあなたが間違った方法であなたの参照を持っていると思います...

public static MouseEvent convertMouseEvent(Component source,
                       MouseEvent sourceEvent,
                       Component destination)

私はそれが次のように読むべきだと思います

evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);

コード例による更新

さて、私はこの小さな例をまとめました...

public class TestMouseClickPoint extends JFrame {

    private ContentPane content;

    public TestMouseClickPoint() throws HeadlessException {

        setSize(600, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        setLayout(new BorderLayout());

        content = new ContentPane();
        add(content);

    }

    protected void updateClickPoint(MouseEvent evt) {
        content.updateClickPoint(evt);
    }

    protected class ContentPane extends JPanel {

        private Point relativePoint;
        private Point absolutePoint;

        public ContentPane() {
            setPreferredSize(new Dimension(600, 600));
            setLayout(null); // For testing purpose only...

            MousePane mousePane = new MousePane();
            mousePane.setBounds(100, 100, 400, 400);

            add(mousePane);
        }

        protected void updateClickPoint(MouseEvent evt) {
            absolutePoint = new Point(evt.getPoint());
            evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);
            relativePoint = new Point(evt.getPoint());

            System.out.println(absolutePoint);
            System.out.println(relativePoint);

            repaint();
        }

        protected void paintCross(Graphics2D g2d, Point p) {
            g2d.drawLine(p.x - 5, p.y - 5, p.x + 5, p.y + 5);
            g2d.drawLine(p.x - 5, p.y + 5, p.x + 5, p.y - 5);
        }

        /*
         * This is not recommended, but I want to paint ontop of everything...
         */
        @Override
        public void paint(Graphics g) {
            super.paint(g);

            Graphics2D g2d = (Graphics2D) g;

            if (relativePoint != null) {
                g2d.setColor(Color.BLACK);
                paintCross(g2d, relativePoint);
            }

            if (absolutePoint != null) {
                g2d.setColor(Color.RED);
                paintCross(g2d, absolutePoint);
            }

        }
    }

    protected class MousePane extends JPanel {

        private Point clickPoint;

        public MousePane() {

            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    clickPoint = e.getPoint();
                    TestMouseClickPoint.this.updateClickPoint(e);
                    repaint();
                }
            });

            setBorder(new LineBorder(Color.RED));

        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.BLUE);

            if (clickPoint != null) {
                g2d.drawLine(clickPoint.x, clickPoint.y - 5, clickPoint.x, clickPoint.y + 5);
                g2d.drawLine(clickPoint.x - 5, clickPoint.y, clickPoint.x + 5, clickPoint.y);
            }

        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
        } catch (InstantiationException ex) {
        } catch (IllegalAccessException ex) {
        } catch (UnsupportedLookAndFeelException ex) {
        }

        new TestMouseClickPoint().setVisible(true);
    }
}

基本的には3点塗ります。マウスがクリックされたポイント (イベントのソースに相対的)、親コンテナー内の変換されていないポイント、および親コンテナー内の変換されたポイント。

ここに画像の説明を入力

次に行う必要があるのは、マウスの位置が実際に変換されているかどうかを判断することです。実際に何をしているのかを判断するには、コードの実際の例を見る必要があるでしょう。

于 2012-09-17T20:21:51.483 に答える