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方法中调用。这种分离使得代码保持整洁,因为它本质上告诉每个红色方块自己进行绘制。