文档

Java™ 教程
隐藏目录
优化设计
路径: 使用Swing创建GUI
教程: 执行自定义绘图

完善设计

为了演示目的,将绘制逻辑完全封装在MyPanel类中是有意义的。但是,如果您的应用程序需要跟踪多个实例,则可以将该代码提取到单独的类中,以便将每个方块视为单独的对象进行处理。这种技术在2D游戏编程中很常见,有时被称为“精灵动画”。

点击“启动”按钮使用Java™ Web Start来运行SwingPaintDemo4(下载JDK 7或更高版本)。或者,如果您想自己编译和运行示例,请参考示例索引

启动SwingPaintDemo4示例
package painting;

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics; 
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseMotionAdapter;

public class SwingPaintDemo4 {
    
    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI(); 
            }
        });
    }

    private static void createAndShowGUI() {
        System.out.println("在EDT上创建GUI? "+
        SwingUtilities.isEventDispatchThread());
        JFrame f = new JFrame("Swing绘图演示");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        f.add(new MyPanel());
        f.setSize(250,250);
        f.setVisible(true);
    } 

}

class MyPanel extends JPanel {

    RedSquare redSquare = new RedSquare();

    public MyPanel() {

        setBorder(BorderFactory.createLineBorder(Color.black));

        addMouseListener(new MouseAdapter(){
            public void mousePressed(MouseEvent e){
                moveSquare(e.getX(),e.getY());
            }
        });

        addMouseMotionListener(new MouseAdapter(){
            public void mouseDragged(MouseEvent e){
                moveSquare(e.getX(),e.getY());
            }
        });

    }

    private void moveSquare(int x, int y){

        // 当前方块的状态,保存为final变量,避免重复调用相同的方法。
        final int CURR_X = redSquare.getX();
        final int CURR_Y = redSquare.getY();
        final int CURR_W = redSquare.getWidth();
        final int CURR_H = redSquare.getHeight();
        final int OFFSET = 1;

        if ((CURR_X!=x) || (CURR_Y!=y)) {

            // 方块正在移动,重绘背景,覆盖旧方块的位置。
            repaint(CURR_X,CURR_Y,CURR_W+OFFSET,CURR_H+OFFSET);

            // 更新坐标。
            redSquare.setX(x);
            redSquare.setY(y);

            // 在新位置重绘方块。
            repaint(redSquare.getX(), redSquare.getY(), 
                    redSquare.getWidth()+OFFSET, 
                    redSquare.getHeight()+OFFSET);
        }
    }

    public Dimension getPreferredSize() {
        return new Dimension(250,200);
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);       
        g.drawString("这是我的自定义面板!",10,20);

        redSquare.paintSquare(g);
    }  
}

class RedSquare{

    private int xPos = 50;
    private int yPos = 50;
    private int width = 20;
    private int height = 20;

    public void setX(int xPos){ 
        this.xPos = xPos;
    }

    public int getX(){
        return xPos;
    }

    public void setY(int yPos){
        this.yPos = yPos;
    }

    public int getY(){
        return yPos;
    }

    public int getWidth(){
        return width;
    } 

    public int getHeight(){
        return height;
    }

    public void paintSquare(Graphics g){
        g.setColor(Color.RED);
        g.fillRect(xPos,yPos,width,height);
        g.setColor(Color.BLACK);
        g.drawRect(xPos,yPos,width,height);  
    }
}

在这个特定的实现中,我们完全从头开始创建了一个RedSquare类。另一种方法是通过使RedSquare成为java.awt.Rectangle的子类来重用java.awt.Rectangle的功能。无论RedSquare如何实现,重要的是我们给这个类一个接受Graphics对象的方法,并且该方法从面板的paintComponent方法中调用。这种分离使得代码保持整洁,因为它本质上告诉每个红色方块自己进行绘制。


上一页: 创建演示应用程序(第3步)
下一页: 更详细地了解绘制机制