0
public void mousePressed(MouseEvent e) {
    //Invoked when a mouse button has been pressed on a component.
    if (e.getButton() == MouseEvent.BUTTON1) {
        isDown = true;
        System.out.println("isDown is now true");
    }
    if (e.getButton() == MouseEvent.BUTTON3) {
        isDown2 = true;
        System.out.println("isDown2 is now true");
    }
    do {
        Point location = MouseInfo.getPointerInfo().getLocation(); 
        int x = location.x - (drawingPanel.getLocationOnScreen()).x;
        int y = location.y - (drawingPanel.getLocationOnScreen()).y;
        drawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19);
    } while (isDown);
    System.out.println("Mouse has been pressed down.");
}

public void mouseReleased(MouseEvent e) {
    //Invoked when a mouse button has been released on a component.
    if (e.getButton() == MouseEvent.BUTTON1) {
        isDown = false;
        System.out.println("isDown is now false");
    }
    if (e.getButton() == MouseEvent.BUTTON3) {
        isDown2 = false;
        System.out.println("isDown2 is now false");
    }
    System.out.println("Mouse has been released.");
}

これは私がこれまでに持っているものです。isDown私の当初の意図は、マウスが押されたときにブール値がtrueに設定され、trueのときにwhileループが実行されるようにコードを設計することでしisDownた。マウスボタンを離すと、ループisDownを終了するためにfalseに設定します。while

私はここで何を台無しにしていますか?2つのMouseEventメソッドを同時に実行することはできませんか?ブール変数の変更はisDown登録されておらず、手に無限のwhileループがあります。

4

2 に答える 2

7

これは、イベント ディスパッチ スレッドの典型的な違反です。

すべての UI コードは、単一のスレッド内から実行されます。すべてのイベントは、この同じスレッドから UI にディスパッチされます。つまり、このスレッドを (ループまたは他のブロック操作を使用して) ブロックすると、イベントはディスパッチされません。これにより、プログラムがハングしたように見えます。

詳細については、Swing での同時実行をご覧ください。

実際にすべきことは、MouseMoitionListener代わりにドラッグ イベントを追跡するために a を使用することです。詳細については、マウス リスナーの使用方法を参照してください。

これdrawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19);もとてつもなく気になります。

getGraphicsカスタム ペインティングの実行に は決して使用しないでください。getGraphicsnull を返すことができ、最後のペイント サイクルのスナップ ショットにすぎません。このメソッドを使用して行われたペイントは、別の再ペイントが発生したときに削除/クリーニングされます。

カスタム コンポーネント ( などJPanel) を作成し、そのメソッドをオーバーライドしてpaintComponent、必要な描画を実行する必要があります。詳細については、カスタム ペインティングの実行を参照してください。

ここに画像の説明を入力

public class MouseDraggedTest {

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

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

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Map<Point, List<Point>> mapPoints;
        private Point currentPoint;

        public TestPane() {
            mapPoints = new HashMap<>(25);
            MouseAdapter mouseListener = new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    currentPoint = e.getPoint();
                    mapPoints.put(currentPoint, new ArrayList<Point>(25));
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    List<Point> points = mapPoints.get(currentPoint);
                    if (points.isEmpty()) {
                        mapPoints.remove(currentPoint);
                    }
                    currentPoint = null;
                }

                @Override
                public void mouseDragged(MouseEvent me) {
                    List<Point> points = mapPoints.get(currentPoint);
                    points.add(me.getPoint());
                    repaint();
                }
            };
            addMouseListener(mouseListener);
            addMouseMotionListener(mouseListener);
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            for (Point startPoint : mapPoints.keySet()) {
                List<Point> points = mapPoints.get(startPoint);
                for (Point p : points) {
                    if (startPoint != null) {
                        g.drawLine(startPoint.x, startPoint.y, p.x, p.y);
                    }
                    startPoint = p;
                }
            }
        }
    }
}
于 2013-02-08T01:24:46.563 に答える
2

whileメソッド内でループを実行していますmousePressed()。これは、Swing イベントのディスパッチ スレッドをブロックしていることを意味します。このメソッドは true である限り返さないためisDown、実行はリスナー ハンドラーに戻らず、リスナーを呼び出すことはありませんmouseReleased()

原則として、リスナーで実行時間の長い操作を起動しないでください。これは、実行中は GUI がイベントに応答しなくなるためです。この場合、これは永遠を意味します。リスナーは、いくつかのフラグを設定してから戻るだけではいけません。アプリケーションの応答性を維持する必要があります。

典型的な解決策の 1 つは、長時間実行される作業を行うために新しいスレッドを起動することです。Event Dispatching Thread が解放され、mouseReleased() リスナーが呼び出されます。

このソリューションの問題点は、作業が Swing コンポーネントにペイントされていることです。すべてのグラフィックスは、オーバーライドされたpaintComponentメソッドで実行する必要があります。@MadProgrammer がすでに説明しているので、詳しくは説明しません。

于 2013-02-08T01:23:55.000 に答える