Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
有关Java SE 9及后续版本中更新的语言功能的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息,请参阅JDK发布说明。
为了演示目的,将绘制逻辑完全封装在MyPanel
类中是有意义的。但是,如果您的应用程序需要跟踪多个实例,则可以将该代码提取到单独的类中,以便将每个方块视为单独的对象进行处理。这种技术在2D游戏编程中很常见,有时被称为“精灵动画”。
点击“启动”按钮使用Java™ Web Start来运行SwingPaintDemo4(下载JDK 7或更高版本)。或者,如果您想自己编译和运行示例,请参考示例索引。
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
方法中调用。这种分离使得代码保持整洁,因为它本质上告诉每个红色方块自己进行绘制。