精炼设计

原文: https://docs.oracle.com/javase/tutorial/uiswing/painting/refining.html

出于演示目的,将绘制逻辑完全包含在MyPanel类中是有意义的。但是,如果您的应用程序需要跟踪多个实例,那么您可以使用的一种模式是将该代码分解为一个单独的类,以便可以将每个方块视为单个对象。这种技术在 2D 游戏编程中很常见,有时也被称为“精灵动画”。

单击“启动”按钮以使用 Java™Web Start下载 JDK 7 或更高版本)运行 SwingPaintDemo4。或者,要自己编译并运行示例,请参考示例索引

Launches the SwingPaintDemo4 example

  1. package painting;
  2. import javax.swing.SwingUtilities;
  3. import javax.swing.JFrame;
  4. import javax.swing.JPanel;
  5. import javax.swing.BorderFactory;
  6. import java.awt.Color;
  7. import java.awt.Dimension;
  8. import java.awt.Graphics;
  9. import java.awt.event.MouseEvent;
  10. import java.awt.event.MouseListener;
  11. import java.awt.event.MouseAdapter;
  12. import java.awt.event.MouseMotionListener;
  13. import java.awt.event.MouseMotionAdapter;
  14. public class SwingPaintDemo4 {
  15. public static void main(String[] args) {
  16. SwingUtilities.invokeLater(new Runnable() {
  17. public void run() {
  18. createAndShowGUI();
  19. }
  20. });
  21. }
  22. private static void createAndShowGUI() {
  23. System.out.println("Created GUI on EDT? "+
  24. SwingUtilities.isEventDispatchThread());
  25. JFrame f = new JFrame("Swing Paint Demo");
  26. f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  27. f.add(new MyPanel());
  28. f.setSize(250,250);
  29. f.setVisible(true);
  30. }
  31. }
  32. class MyPanel extends JPanel {
  33. RedSquare redSquare = new RedSquare();
  34. public MyPanel() {
  35. setBorder(BorderFactory.createLineBorder(Color.black));
  36. addMouseListener(new MouseAdapter(){
  37. public void mousePressed(MouseEvent e){
  38. moveSquare(e.getX(),e.getY());
  39. }
  40. });
  41. addMouseMotionListener(new MouseAdapter(){
  42. public void mouseDragged(MouseEvent e){
  43. moveSquare(e.getX(),e.getY());
  44. }
  45. });
  46. }
  47. private void moveSquare(int x, int y){
  48. // Current square state, stored as final variables
  49. // to avoid repeat invocations of the same methods.
  50. final int CURR_X = redSquare.getX();
  51. final int CURR_Y = redSquare.getY();
  52. final int CURR_W = redSquare.getWidth();
  53. final int CURR_H = redSquare.getHeight();
  54. final int OFFSET = 1;
  55. if ((CURR_X!=x) || (CURR_Y!=y)) {
  56. // The square is moving, repaint background
  57. // over the old square location.
  58. repaint(CURR_X,CURR_Y,CURR_W+OFFSET,CURR_H+OFFSET);
  59. // Update coordinates.
  60. redSquare.setX(x);
  61. redSquare.setY(y);
  62. // Repaint the square at the new location.
  63. repaint(redSquare.getX(), redSquare.getY(),
  64. redSquare.getWidth()+OFFSET,
  65. redSquare.getHeight()+OFFSET);
  66. }
  67. }
  68. public Dimension getPreferredSize() {
  69. return new Dimension(250,200);
  70. }
  71. public void paintComponent(Graphics g) {
  72. super.paintComponent(g);
  73. g.drawString("This is my custom Panel!",10,20);
  74. redSquare.paintSquare(g);
  75. }
  76. }
  77. class RedSquare{
  78. private int xPos = 50;
  79. private int yPos = 50;
  80. private int width = 20;
  81. private int height = 20;
  82. public void setX(int xPos){
  83. this.xPos = xPos;
  84. }
  85. public int getX(){
  86. return xPos;
  87. }
  88. public void setY(int yPos){
  89. this.yPos = yPos;
  90. }
  91. public int getY(){
  92. return yPos;
  93. }
  94. public int getWidth(){
  95. return width;
  96. }
  97. public int getHeight(){
  98. return height;
  99. }
  100. public void paintSquare(Graphics g){
  101. g.setColor(Color.RED);
  102. g.fillRect(xPos,yPos,width,height);
  103. g.setColor(Color.BLACK);
  104. g.drawRect(xPos,yPos,width,height);
  105. }
  106. }

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