完善设计
出于演示 Object,将绘画逻辑完全包含在MyPanel
类中是有意义的。但是,如果您的应用程序需要跟踪多个实例,则可以使用的一种 Pattern 是将代码分解为一个单独的类,以便将每个正方形都视为一个单独的对象。此技术在 2D 游戏编程中很常见,有时也称为“画面动画”。
单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 SwingPaintDemo4.另外,要自己编译和运行示例,请查阅example index。
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("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
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){
// Current square state, stored as final variables
// to avoid repeat invocations of the same methods.
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)) {
// The square is moving, repaint background
// over the old square location.
repaint(CURR_X,CURR_Y,CURR_W+OFFSET,CURR_H+OFFSET);
// Update coordinates.
redSquare.setX(x);
redSquare.setY(y);
// Repaint the square at the new location.
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("This is my custom Panel!",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
的功能。无论如何实现RedSquare
,重要的一点是我们为类提供了一个接受Graphics
对象的方法,并且该方法是从面板的paintComponent
方法中调用的。这种分隔使您的代码保持干净,因为它实际上告诉每个红色正方形自己绘制。