2

在 Liang 的Java 编程简介(第 7 版)的第 15 章中,他介绍了一个在 JPanel 上制作(2-D)球并在单击放大/缩小按钮时将其放大的程序。我已经修改了程序,以便它还 1) 如果用户单击/选项+单击,则放大/缩小球,2) 允许您通过按下按钮来选择球的颜色,以及 3) 允许您移动用鼠标拖动它来画圈。

最后的修改给我带来了一段时间的麻烦,因为我想在开始时将球居中,但随后允许用户用鼠标移动球。我想出的解决方案是让 paintComponent 方法在第一次绘制时只设置球相对于 getWidth() 和 getHeight() 的 x 和 y 坐标。为此,我在 BallCanvas 类中添加了一个 paintCount 变量并创建了一个 if 语句,以便它只会在第一次执行。当我最初试图弄清楚如何做到这一点时,我看到了其他解决方案,比如这里给出的那些:为什么我不能访问我的面板的 getWidth() 和 getHeight() 函数?,但我发现我的解决方案要简单得多。

所以问题是:我所做的是否被认为是糟糕的编码风格?专业程序员会嘲笑这个解决方案吗?或者可以吗?

更重要的是,有没有更好(但也相对简单)的方法来做到这一点,而不涉及设置计数器?

以下是相关的代码:

BallCanvas 的开头:

public static class BallCanvas extends JPanel {

    private int radius = 20;
    private Color color = Color.BLACK;
    private int ballX;
    private int ballY;
    private int paintCount = 0;

    ...

move 方法(响应 MouseDragged 事件):

public void move(MouseEvent e){

        ballX = e.getX() - radius;
        ballY = e.getY() - radius;
        repaint();

}

油漆组件方法:

protected void paintComponent(Graphics g){

        super.paintComponent(g);
        g.setColor(color);
        if(paintCount < 1){
            ballX = getWidth()/2 - radius;
            ballY = getHeight()/2 - radius;
        }
        g.fillOval(ballX, ballY, 2*radius, 2*radius);
        paintCount++;

}

完整程序:

// Reference: Liang's Intro to Java Programming

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

public class ControlBall extends JFrame{

    private JButton jbtRed = new JButton("Red");
    private JButton jbtGreen = new JButton("Green");
    private JButton jbtBlue = new JButton("Blue");
    private JButton jbtBlack = new JButton("Black");
    private BallCanvas canvas = new BallCanvas();
    private JMenuBar menuBar = new JMenuBar();
    private JMenu menu = new JMenu("Edit");
    private JMenuItem miEnlarge = new JMenuItem("Enlarge");
    private JMenuItem miShrink = new JMenuItem("Shrink");

    public ControlBall(){

        menuBar.add(menu);
        menu.add(miEnlarge);
        menu.add(miShrink);

        JPanel panel = new JPanel();
        panel.add(jbtRed);
        panel.add(jbtGreen);
        panel.add(jbtBlue);
        panel.add(jbtBlack);

        this.add(canvas, BorderLayout.CENTER);
        this.add(panel, BorderLayout.SOUTH);
        this.add(menuBar, BorderLayout.NORTH);

        jbtRed.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){
                canvas.setColor(Color.RED);
            }
        });

        jbtGreen.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){
                canvas.setColor(Color.GREEN);
            }
        });

        jbtBlue.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){
                canvas.setColor(Color.BLUE);
            }
        });

        jbtBlack.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){
                canvas.setColor(Color.BLACK);
            }
        });

        miEnlarge.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){ 
                canvas.enlarge();
            }
        });

        miShrink.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){ 
                canvas.shrink();
            }
        });

        canvas.addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent e){
                canvas.changeSize(e);
            }
            public void mousePressed(MouseEvent e){}
            public void mouseReleased(MouseEvent e){}
            public void mouseEntered(MouseEvent e){}
            public void mouseExited(MouseEvent e){}
        });

        canvas.addMouseMotionListener(new MouseMotionAdapter() {

            public void mouseDragged(MouseEvent e) {

                canvas.move(e);

            }
        });

    }

    public static void main(String[] args){

        JFrame frame = new ControlBall();
        frame.setTitle("ControlBall");
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 200);
        frame.setVisible(true);

    }

    public static class BallCanvas extends JPanel {

        private int radius = 20;
        private Color color = Color.BLACK;
        private int ballX;
        private int ballY;
        private int paintCount = 0;

        public BallCanvas(){

            System.out.println(getWidth() + " " + getHeight());

        }

        public BallCanvas(int initialRadius){

            radius = initialRadius;

        }

        public void setColor(Color color){

            this.color = color;
            repaint();

        }

        public void changeSize(MouseEvent e){

            int numClicks = e.getClickCount();

            if(e.isAltDown()){
                if(radius >= 6){
                    this.radius -= 5*numClicks;
                } else{
                    // do nothing
                }
            } else{

                this.radius += 5*numClicks;
            }

            repaint();

        }

        public void enlarge(){

            this.radius += 5;
            repaint();

        }

        public void shrink(){

            if(radius >= 10){
                this.radius -= 5;
            }
            repaint();
        } 

        public void move(MouseEvent e){

            ballX = e.getX() - radius;
            ballY = e.getY() - radius;
            repaint();

        }

        protected void paintComponent(Graphics g){

            super.paintComponent(g);
            g.setColor(color);
            if(paintCount < 1){
                ballX = getWidth()/2 - radius;
                ballY = getHeight()/2 - radius;
            }
            g.fillOval(ballX, ballY, 2*radius, 2*radius);
            paintCount++;

        }

    }

}
4

1 回答 1

4

有几点值得关注:

  • 覆盖getPreferredSize()以建立面板的初始几何图形。

  • 使用该几何形状来确定球的初始位置。

  • 调用pack()然后设置位置和可见性。

  • 用于Action封装菜单和控件共享的代码。

  • 始终使用适配器。

  • 正确使用初始线程

  • 请参阅此Q&A,它从多个角度检查了一个相关示例。

图片

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

public class ControlBall extends JFrame {

    private JButton jbtRed = new JButton("Red");
    private JButton jbtGreen = new JButton("Green");
    private JButton jbtBlue = new JButton("Blue");
    private JButton jbtBlack = new JButton("Black");
    private BallCanvas canvas = new BallCanvas();
    private JMenuBar menuBar = new JMenuBar();
    private JMenu menu = new JMenu("Edit");
    private JMenuItem miEnlarge = new JMenuItem("Enlarge");
    private JMenuItem miShrink = new JMenuItem("Shrink");

    public ControlBall() {

        menuBar.add(menu);
        menu.add(miEnlarge);
        menu.add(miShrink);

        JPanel panel = new JPanel();
        panel.add(jbtRed);
        panel.add(jbtGreen);
        panel.add(jbtBlue);
        panel.add(jbtBlack);

        this.add(canvas, BorderLayout.CENTER);
        this.add(panel, BorderLayout.SOUTH);
        this.add(menuBar, BorderLayout.NORTH);

        jbtRed.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                canvas.setColor(Color.RED);
            }
        });

        jbtGreen.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                canvas.setColor(Color.GREEN);
            }
        });

        jbtBlue.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                canvas.setColor(Color.BLUE);
            }
        });

        jbtBlack.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                canvas.setColor(Color.BLACK);
            }
        });

        miEnlarge.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                canvas.enlarge();
            }
        });

        miShrink.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                canvas.shrink();
            }
        });

        canvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                canvas.changeSize(e);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                canvas.move(e);
            }
        });
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new ControlBall();
                frame.setTitle("ControlBall");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });

    }

    public static class BallCanvas extends JPanel {

        private static final int SIZE = 400;
        private int radius = 20;
        private Color color = Color.BLACK;
        private int ballX = SIZE / 2 - radius;
        private int ballY = SIZE / 2 - radius;

        public BallCanvas() {
            System.out.println(getWidth() + " " + getHeight());
        }

        public BallCanvas(int initialRadius) {
            radius = initialRadius;
        }

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

        public void changeSize(MouseEvent e) {

            int numClicks = e.getClickCount();

            if (e.isAltDown()) {
                if (radius >= 6) {
                    this.radius -= 5 * numClicks;
                } else {
                    // do nothing
                }
            } else {

                this.radius += 5 * numClicks;
            }

            repaint();

        }

        public void enlarge() {

            this.radius += 5;
            repaint();

        }

        public void shrink() {

            if (radius >= 10) {
                this.radius -= 5;
            }
            repaint();
        }

        public void move(MouseEvent e) {

            ballX = e.getX() - radius;
            ballY = e.getY() - radius;
            repaint();

        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);
            g.setColor(color);
            g.fillOval(ballX, ballY, 2 * radius, 2 * radius);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(SIZE, SIZE);
        }
    }
}
于 2013-08-02T20:32:55.590 回答