paintComponentのJava - MouseListenerアクションイベント

ここでは、paintComponentを使用してmouseClicked位置に矩形を描くコードを持っています。出力メッセージを得ることはできますが、グラフィックスや.draw()に関係するものは動作しません。

コード:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public final class testclass extends JFrame {

    static JPanel p;
    Timer t;
    int x = 1;
    int y = 1;
    int xspeed = 1;
    int yspeed = 1;

    public testclass() {
        initComponents();
        this.setBounds(100, 300, 500, 500);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.start();
        this.add(p);
    }

    public void initComponents() {
        final ActionListener action = new ActionListener() {

            public void actionPerformed(ActionEvent evt) {
                System.out.println("Hello!");
                p.repaint();
            }
        };

        t = new Timer(50, action);
        p = new JPanel() {

            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                final Graphics2D gD = (Graphics2D) g;
                moveBALL();
                gD.drawOval(x, y, 25, 25);

                p.addMouseListener(new MouseListener() {

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        System.out.println("a");
                    }

                    @Override
                    public void mousePressed(MouseEvent e) {
                        System.out.println("b");
                    }

                    @Override
                    public void mouseExited(MouseEvent e) {
                        System.out.println("c");
                    }

                    @Override
                    public void mouseEntered(MouseEvent e) {
                        System.out.println("d");
                    }

                    @Override
                    public void mouseClicked(MouseEvent e) {
                        gD.drawRect(e.getX(), e.getY(), 10, 60);
                        gD.setColor(Color.green);
                        System.out.println("clicked");
                    }
                });
            }

            void moveBALL() {
                x = x + xspeed;
                y = y + yspeed;
                if (x < 0) {
                    x = 0;
                    xspeed = -xspeed;
                } else if (x > p.getWidth() - 20) {
                    x = p.getWidth() - 20;
                    xspeed = -xspeed;
                }
                if (y < 0) {
                    y = 0;
                    yspeed = -yspeed;
                } else if (y > p.getHeight() - 20) {
                    y = p.getHeight() - 20;
                    yspeed = -yspeed;
                }
            }
        };
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new testclass().setVisible(true);
                p.setBackground(Color.WHITE);
            }
        });
    }
}

このプログラムでmouseListener()を実装する適切な方法は何ですか? ありがとう。

2
nl ru de
ペイントされるすべてのフレームで新しいMouseListenerを p に追加しています。
追加された 著者 Xeon,
@Xeonはこれを回避する方法がありますか?paintComponent()の外側に置く場所はどこにでも "不明な変数"エラー、つまりMouseListenerのスコープにないgDがあります。
追加された 著者 user1934283,

2 答え

現在のコードに関するいくつかの提案:

    Testclass は、 TestClass またはさらに優れた Test (ただし、ニックピッキング)である必要があります。すべてのクラス名は大文字で始まり、それ以降の新しい単語は大文字になります。
  • JFrame を不必要に拡張しないでください。 LayoutManager を使用するか、または getPreferredSize()をオーバーライドする JFramesetBounds JPanel のコンテンツのサイズを返します。

  • JFramepack()

    MouseListener paintComponent 内の moveBall()を呼び出すのではなく、ちょっとしたデザインだけでなく、画面を再描画する Timer ペイントメソッドで長時間実行している作業を行うべきではありません。

あなたの問題については、あなたのロジックは少し歪んでいると思います。

1つのアプローチでは、 Rectangle (または Rectangle2D )が独自のカスタムクラス(色などの属性を格納できるようになります)に置き換えられます。あなたの ball には moveBall()というメソッドと xy JPanel のすべての repaint()で、ボールを移動するメソッドを呼び出すと、 JPanel 自体が moveBallスクリーンを再描画するタイマーから呼び出すことができる独自のパブリックメソッド内で()を呼び出します。

上記の修正が実装されたコードの例を示します(解析してください。ご不明な点がありましたら教えてください):

enter image description here

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.*;

public class Test {

    private MyPanel p;
    private Timer t;

    public Test() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initComponents();
        frame.add(p);

        frame.pack();
        frame.setVisible(true);

        t.start();
    }

    private void initComponents() {
        final ActionListener action = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                p.moveEntities();//moves ball etc
                p.repaint();
            }
        };

        t = new Timer(50, action);
        p = new MyPanel();

        p.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN);
                System.out.println("clicked");
            }
        });

        p.setBackground(Color.WHITE);
    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }
}

class MyPanel extends JPanel {

    int width = 300, height = 300;
    ArrayList entities = new ArrayList<>();
    MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height);

    void addEntity(int x, int y, int w, int h, Color c) {
        entities.add(new MyRectangle(x, y, w, h, c));
    }

    void moveEntities() {
        ball.moveBALL();
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        Graphics2D g2d = (Graphics2D) grphcs;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.setColor(ball.getColor());
        g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height);

        for (MyRectangle entity : entities) {
            g2d.setColor(entity.getColor());
            g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height);
        }
    }

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

class MyRectangle extends Rectangle2D.Double {

    Color color;

    public MyRectangle(double x, double y, double w, double h, Color c) {
        super(x, y, w, h);
        color = c;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return color;
    }
}

class MyBall extends Ellipse2D.Double {

    int xspeed = 1;
    int yspeed = 1;
    Color color;
    private final int maxWidth;
    private final int maxHeight;

    public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) {
        super(x, y, w, h);
        color = c;
        this.width = w;//set width and height of Rectangle2D
        this.height = h;
        //set max width and height ball can move
        this.maxWidth = maxWidth;
        this.maxHeight = maxHeight;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    void moveBALL() {
        x = x + xspeed;
        y = y + yspeed;
        if (x < 0) {
            x = 0;
            xspeed = -xspeed;
        } else if (x > maxWidth - ((int) getWidth()/2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed
            x = maxWidth - ((int) getWidth()/2);
            xspeed = -xspeed;
        }
        if (y < 0) {
            y = 0;
            yspeed = -yspeed;
        } else if (y > maxHeight - ((int) getHeight()/2)) {
            y = maxHeight - ((int) getHeight()/2);
            yspeed = -yspeed;
        }
    }
}
2
追加された
@ user1934283その喜び、そしてうまくいけば、コードを理解して理解できました。そして、問題ではなく、別のハッキーまたは良い方法で問題を解決するのではなく、ベストプラクティスに従うコードを提供するのが好きです。そして、あなたのコードでクラスをどのように使用して物を簡素化し、再利用可能にするかの基礎を学びました。
追加された 著者 David Kroukamp,
迅速な返信と正しいコードをありがとう。あなたの最初の返事の後、私は、ArrayListを使用して矩形塗装の部分について混乱していたが、後でコードを徹底的に読んだ後、私はその点を得た。私はまだクラス/メソッドを学んでいるので、私の初期コードは混乱しているかもしれません。
追加された 著者 user1934283,

First of all the paint component is called every time swing needs to redraw the component.
And you are adding a new instance of mouse listener to the panel every time the paint is called.

Just move the line
p.addMouseListener(new MouseListener() {...}
out of the paint component, preferably after the initialization of the panel.

デフォルトのテンプレートは

JPanel p = new JPanel(){
    @Override
    public void paintComponent(Graphics g) {
    }
};
p.addMouseListener(new MouseListener()  or new MouseAdapter()
//Your overridden methods

});

お役に立てれば。

0
追加された
意図的に無視するか、コードが正しく機能しない限り、オーバーライドされたメソッドの super.XXX つまり super.paintComponent(g)の呼び出しを忘れないでください。
追加された 著者 David Kroukamp,
うーん、私はあなたが示唆したものを試してみましたが、 "シンボルシンボルを見つけることができません:可変gD"エラーが発生しています。
追加された 著者 user1934283,