自定义圆对象的MouseListener绘制到JPanel Gameboard对象时不起作用

时间:2018-07-31 00:02:38

标签: java swing jpanel paintcomponent mouselistener

我正在用Java开发钉子游戏,当单击它以表明它已被选中时,我一直被困在要改变颜色的孔上。我目前有3个类,所有这些类都扩展了JPanel:

Display.java:创建JFrame并将游戏板渲染到JFrame。

GameBoard.java:包含渲染游戏板的逻辑。

Hole.java:渲染一个孔并保留MouseListener的逻辑。当一个人点击一个洞时,它会变成蓝色,表明它已被选中。

我能够在游戏板上渲染孔,但是MouseListener无法正常工作;当我单击一个孔时,它不会变成蓝色。

下面是三个类:

Display.java

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.logging.*;


public class Display extends JPanel {

    private static final long serialVersionUID = 1L;

    private static String staticClassName = Display.class.getName();
    private static Logger logger = Logger.getLogger(staticClassName);
    private final static Logger LOGGER = Logger.getLogger(staticClassName);
    private static String title;
    private static int width;
    private static int height;
    private static JFrame frame;
    private static JPanel mainPanel;
    private static GameBoard gameBoard;

    public Display(String title, int width, int height){

        logger.info(staticClassName +".Constructor: Constructing Display"); 
        Display.title = title;
        Display.width = width;
        Display.height = height;

        logger.info(staticClassName +".Constructor: Display constructed."); 

         initDisplay();
    }

    private static void initDisplay() {

        logger.info(staticClassName +".initDisplay(): Entering method");    
        try {       

            logger.info(staticClassName +".initDisplay(): About to create JFrame"); 

            frame = new JFrame(title);
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
            frame.setSize(width, height);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            mainPanel  = new JPanel();

            logger.info(staticClassName +".initDisplay(): About to create GameBoard object"); 
            gameBoard = new GameBoard();
            mainPanel.add(gameBoard);
            frame.getContentPane().add(mainPanel);
            frame.pack();

        } catch (Exception e) {

            logger.info(staticClassName +".initDisplay(): Failed to render display: " + e); 
        }

        logger.info(staticClassName +".initDisplay(): Exiting Method"); 
    }


    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    LOGGER.setLevel(Level.INFO);
                    Display d = new Display("Peg Game", 800, 800);
                } catch (Exception e) {

                }
            }
        });
    }


}

GameBoard.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import java.util.logging.Logger;
import javax.swing.JPanel;

public class GameBoard extends JPanel {

    private static final long serialVersionUID = 1L;
    private static String staticClassName = GameBoard.class.getName();
    private static Logger logger = Logger.getLogger(staticClassName);

    private static final int RGB1 = 223;
    private static final int RGB2 = 191;
    private static final int RGB3 = 159;
    private static final int WIDTH = 800;
    private static final int HEIGHT = WIDTH;
    private Path2D path = new Path2D.Double();
    private static Color boardColor = new Color(RGB1, RGB2, RGB3);

    private int [] adjacentHoles1;

    public GameBoard() {

        logger.info(staticClassName +".Constructor: Constructing GameBoard"); 

        double firstX = (WIDTH / 2.0) * (1 - 1 / Math.sqrt(3));
        double firstY = 3.0 * HEIGHT / 4.0;
        path.moveTo(firstX, firstY);
        path.lineTo(WIDTH - firstX, firstY);
        path.lineTo(WIDTH / 2.0, HEIGHT / 4.0);
        path.closePath();

        logger.info(staticClassName +".Constructor: GameBoard constructed"); 

    }

    @Override 
    protected void paintComponent(Graphics g) {

        logger.info(staticClassName +".paintComponent(): Entering method"); 

        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setPaint(boardColor);
        g2.fill(path);

        int xPos = 390;

        int yPos = 310;

        // I was rendering up to 15 holes, but took them out for purpose of 
        // shortening my example
        for (int i = 0; i < 15; i ++ ) {

            if (i == 0) {

               // Declare the hole here
                Hole hole = new Hole(i, xPos, yPos, adjacentHoles1);
               // Render it here
                hole.paintComponent(g2);
                yPos += 50;
            }

        }

        logger.info(staticClassName +".paintComponent(): Exiting method"); 

    }

    @Override
    public Dimension getPreferredSize() {

        logger.info(staticClassName +".getPreferredSize(): Entering method"); 
        if (isPreferredSizeSet()) {
            logger.info(staticClassName +".getPreferredSize(): isPreferredSizeSet() == true. Exiting method"); 
            return super.getPreferredSize();
        }
        logger.info(staticClassName +".getPreferredSize(): isPreferredSizeSet() == false.  Exiting method"); 
            return new Dimension(WIDTH, HEIGHT);
    }

}

Hole.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.logging.Logger;

import javax.swing.JPanel;

public class Hole extends JPanel {


    private static final long serialVersionUID = 1235245435988434L;

    private static String staticClassName = Hole.class.getName();
    private static Logger logger = Logger.getLogger(staticClassName);

    private int holeNumber;
    private int xPos, yPos;
    private final int HOLEWIDTH = 20;
    private final int HOLEHEIGHT = HOLEWIDTH;
    private static final int RGB1 = 0;
    private static final int RGB2 = 0;
    private static final int RGB3 = 0;
    private static Color defaultCircleColor = new Color(RGB1, RGB2, RGB3);
    private static Color selectedCircleColor =  Color.BLUE;
    private static Color circleColor = defaultCircleColor;
    private int [] adjacentHoles;

    public Hole (int holeNumber, int xPos, int yPos, int [] adjacentHoles) {

        logger.info(staticClassName +".Constructor: Constructing Hole"); 

        this.holeNumber = holeNumber;
        this.xPos = xPos;
        this.yPos = yPos;
        this.adjacentHoles = adjacentHoles;

        initComponents();

    }

    @Override 
    protected void paintComponent(Graphics g) {

        logger.info(staticClassName +".paintComponent(): Entering method"); 
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setPaint(circleColor);

        g2.fillOval(xPos,yPos,HOLEWIDTH,HOLEHEIGHT);

        logger.info(staticClassName +".paintComponent(): Exiting method"); 

    }

    private void initComponents() {

            addMouseListener(new java.awt.event.MouseAdapter() {
                public void mouseClicked(java.awt.event.MouseEvent event) {
                    selectHole(event);
                }});

    }

    public void selectHole(java.awt.event.MouseEvent event) {

        logger.info(staticClassName +"------------------------------------------------"); 
        logger.info(staticClassName +".selectHole(): Entering method"); 

        if (circleColor == defaultCircleColor) {
            circleColor = selectedCircleColor;
            repaint();
        }
        else {
            circleColor = defaultCircleColor;
            repaint();
        }

        logger.info(staticClassName +".selectHole(): Exiting method"); 
        logger.info(staticClassName +"------------------------------------------------"); 
    }

    @Override
    public Dimension getPreferredSize() {
        logger.info(staticClassName +".getPreferredSize(): Getting the preferred size of the circle."); 
         return new Dimension(800, 800);

    }


}

请注意,如果您注意到我可以在代码中的任何地方使用更好的编码实践,请告诉我。

1 个答案:

答案 0 :(得分:0)

所以,您的基本问题就在这里...

for (int i = 0; i < 15; i ++ ) {

    if (i == 0) {

       // Declare the hole here
        Hole hole = new Hole(i, xPos, yPos, adjacentHoles1);
       // Render it here
        hole.paintComponent(g2);
        yPos += 50;
    }

}

Hole是组件,您永远不要调用任何paint组件方法,但是,您的组件也不是“实时”的,这意味着它永远不会收到任何事件。

您应该做的是将MouseListener附加到GameBoard上并测试是否在有孔的地方单击鼠标。

最简单的解决方案是利用“形状” API并生成“孔”列表。然后可以简单地对其进行迭代以进行绘制,并检查是否在其中单击了鼠标。

我在确定孔的位置上并没有付出很大的努力,相反,我只是将它们按行/列布局,但是您应该了解预期解决方案的基本概念

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Display extends JPanel {

    private static final long serialVersionUID = 1L;

    private static String staticClassName = Display.class.getName();
    private static Logger logger = Logger.getLogger(staticClassName);
    private final static Logger LOGGER = Logger.getLogger(staticClassName);
    private static String title;
    private static int width;
    private static int height;
    private static JFrame frame;
    private static JPanel mainPanel;
    private static GameBoard gameBoard;

    public Display(String title, int width, int height) {

        logger.info(staticClassName + ".Constructor: Constructing Display");
        Display.title = title;
        Display.width = width;
        Display.height = height;

        logger.info(staticClassName + ".Constructor: Display constructed.");

        initDisplay();
    }

    private static void initDisplay() {

        frame = new JFrame(title);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        frame.setSize(width, height);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        mainPanel = new JPanel();

        gameBoard = new GameBoard();
        mainPanel.add(gameBoard);
        frame.getContentPane().add(mainPanel);
        frame.pack();
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    LOGGER.setLevel(Level.INFO);
                    Display d = new Display("Peg Game", 800, 800);
                } catch (Exception e) {

                }
            }
        });
    }

    public static class GameBoard extends JPanel {

        private static final long serialVersionUID = 1L;
        private static String staticClassName = GameBoard.class.getName();
        private static Logger logger = Logger.getLogger(staticClassName);

        private static final int RGB1 = 223;
        private static final int RGB2 = 191;
        private static final int RGB3 = 159;
        private static final int WIDTH = 800;
        private static final int HEIGHT = WIDTH;
        private Path2D path = new Path2D.Double();
        private static Color boardColor = new Color(RGB1, RGB2, RGB3);

        private int[] adjacentHoles1;

        private Shape[] holes;
        private Shape selectedHole;

        public GameBoard() {

            logger.info(staticClassName + ".Constructor: Constructing GameBoard");

            double firstX = (WIDTH / 2.0) * (1 - 1 / Math.sqrt(3));
            double firstY = 3.0 * HEIGHT / 4.0;
            path.moveTo(firstX, firstY);
            path.lineTo(WIDTH - firstX, firstY);
            path.lineTo(WIDTH / 2.0, HEIGHT / 4.0);
            path.closePath();

            logger.info(staticClassName + ".Constructor: GameBoard constructed");

            holes = new Shape[15];
            int yPos = 310;
            int index = 0;
            for (int row = 0; row < 3; row++) {
                int xPos = 390;
                for (int col = 0; col < 5; col++) {
                    holes[index] = new Ellipse2D.Double(xPos, yPos, 50, 50);
                    index++;
                    xPos += 50;
                }
                yPos += 50;
            }

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    selectedHole = null;
                    for (Shape hole : holes) {
                        if (hole.contains(e.getPoint())) {
                            selectedHole = hole;
                            break;
                        }
                    }
                    repaint();
                }
            });
        }

        @Override
        protected void paintComponent(Graphics g) {

            logger.info(staticClassName + ".paintComponent(): Entering method");

            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;

            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setPaint(boardColor);
            g2.fill(path);

            g2.setColor(Color.BLACK);
            for (Shape hole : holes) {
                g2.fill(hole);
            }

            if (selectedHole != null) {
                g2.setColor(Color.RED);
                g2.fill(selectedHole);
            }

            logger.info(staticClassName + ".paintComponent(): Exiting method");

        }

        @Override
        public Dimension getPreferredSize() {

            logger.info(staticClassName + ".getPreferredSize(): Entering method");
            if (isPreferredSizeSet()) {
                logger.info(staticClassName + ".getPreferredSize(): isPreferredSizeSet() == true. Exiting method");
                return super.getPreferredSize();
            }
            logger.info(staticClassName + ".getPreferredSize(): isPreferredSizeSet() == false.  Exiting method");
            return new Dimension(WIDTH, HEIGHT);
        }

    }

}