2012-12-28 54 views
2

這裏我有一個代碼,它使用paintComponent在mouseClicked位置繪製一個矩形。我可以得到輸出消息,但與圖形和.draw()相關的任何東西都不起作用。Java在PaintComponent中的MouseListener Action事件

代碼:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public final class testclass extends JFrame { 

    static JPanel p; 
    Timer t; 
    int x = 1; 
    int y = 1; 
    int xspeed = 1; 
    int yspeed = 1; 

    public testclass() { 
     initComponents(); 
     this.setBounds(100, 300, 500, 500); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     t.start(); 
     this.add(p); 
    } 

    public void initComponents() { 
     final ActionListener action = new ActionListener() { 

      public void actionPerformed(ActionEvent evt) { 
       System.out.println("Hello!"); 
       p.repaint(); 
      } 
     }; 

     t = new Timer(50, action); 
     p = new JPanel() { 

      public void paintComponent(Graphics g) { 
       super.paintComponent(g); 
       final Graphics2D gD = (Graphics2D) g; 
       moveBALL(); 
       gD.drawOval(x, y, 25, 25); 

       p.addMouseListener(new MouseListener() { 

        @Override 
        public void mouseReleased(MouseEvent e) { 
         System.out.println("a"); 
        } 

        @Override 
        public void mousePressed(MouseEvent e) { 
         System.out.println("b"); 
        } 

        @Override 
        public void mouseExited(MouseEvent e) { 
         System.out.println("c"); 
        } 

        @Override 
        public void mouseEntered(MouseEvent e) { 
         System.out.println("d"); 
        } 

        @Override 
        public void mouseClicked(MouseEvent e) { 
         gD.drawRect(e.getX(), e.getY(), 10, 60); 
         gD.setColor(Color.green); 
         System.out.println("clicked"); 
        } 
       }); 
      } 

      void moveBALL() { 
       x = x + xspeed; 
       y = y + yspeed; 
       if (x < 0) { 
        x = 0; 
        xspeed = -xspeed; 
       } else if (x > p.getWidth() - 20) { 
        x = p.getWidth() - 20; 
        xspeed = -xspeed; 
       } 
       if (y < 0) { 
        y = 0; 
        yspeed = -yspeed; 
       } else if (y > p.getHeight() - 20) { 
        y = p.getHeight() - 20; 
        yspeed = -yspeed; 
       } 
      } 
     }; 
    } 

    public static void main(String args[]) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new testclass().setVisible(true); 
       p.setBackground(Color.WHITE); 
      } 
     }); 
    } 
} 

什麼是這個程序來實現的MouseListener()的正確方法? 謝謝。

+1

要添加新的MouseListener爲'p 「畫的每一幀! – Xeon

+0

@Xeon是否還有其他解決方法?因爲我把它放在paintComponent()之外,它給了我「未知變量」錯誤,即gD不在MouseListener的範圍內。 – user1934283

回答

2

目前的代碼一些建議。

  • 觀看級別的命名方案,即testclass應該TestClass或甚至更好Test(但那挑選)。所有類名都以大寫字母開頭,然後每個新單詞都大寫。

  • 不必延長JFrame。在JFrame

  • 不要調用setBounds而使用適當的LayoutManager和/或覆蓋的JPanelgetPreferredSize()並返回其尺寸適合其內容。

  • 始終在JFrame上調用pack(),然後將其設置爲可見(考慮以上因素)。

  • 使用MouseAdapter VS MouseListener

  • 不要調用moveBall()paintComponent而是把它在你的Timer其中重繪屏幕,不僅稍微好一點的設計,但我們也不能在油漆方法做可能長時間運行的任務。

至於你的問題,我認爲你的邏輯有點歪斜。

一種方法會看到Rectangle(或Rectangle2D)被它自己的自定義類替換(這將允許我們存儲顏色等屬性)。您的也將有其自己的類,其方法moveBall()及其屬性如xy位置等在每repaint()你的JPanel將調用的方法來移動球,JPanel本身可以包裝moveBall()它自己的公開方法,我們可以從計時器調用重畫屏幕。

這裏是實現上述修復您的代碼示例(請您分析它,如果你有任何問題,讓我知道):

enter image description here

import java.awt.*; 
import java.awt.event.*; 
import java.awt.geom.Ellipse2D; 
import java.awt.geom.Rectangle2D; 
import java.util.ArrayList; 
import javax.swing.*; 

public class Test { 

    private MyPanel p; 
    private Timer t; 

    public Test() { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     initComponents(); 
     frame.add(p); 

     frame.pack(); 
     frame.setVisible(true); 

     t.start(); 
    } 

    private void initComponents() { 
     final ActionListener action = new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent evt) { 
       p.moveEntities();//moves ball etc 
       p.repaint(); 
      } 
     }; 

     t = new Timer(50, action); 
     p = new MyPanel(); 

     p.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN); 
       System.out.println("clicked"); 
      } 
     }); 

     p.setBackground(Color.WHITE); 
    } 

    public static void main(String args[]) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new Test(); 
      } 
     }); 
    } 
} 

class MyPanel extends JPanel { 

    int width = 300, height = 300; 
    ArrayList<MyRectangle> entities = new ArrayList<>(); 
    MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height); 

    void addEntity(int x, int y, int w, int h, Color c) { 
     entities.add(new MyRectangle(x, y, w, h, c)); 
    } 

    void moveEntities() { 
     ball.moveBALL(); 
    } 

    @Override 
    protected void paintComponent(Graphics grphcs) { 
     super.paintComponent(grphcs); 
     Graphics2D g2d = (Graphics2D) grphcs; 

     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 

     g2d.setColor(ball.getColor()); 
     g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height); 

     for (MyRectangle entity : entities) { 
      g2d.setColor(entity.getColor()); 
      g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height); 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(width, height); 
    } 
} 

class MyRectangle extends Rectangle2D.Double { 

    Color color; 

    public MyRectangle(double x, double y, double w, double h, Color c) { 
     super(x, y, w, h); 
     color = c; 
    } 

    public void setColor(Color color) { 
     this.color = color; 
    } 

    public Color getColor() { 
     return color; 
    } 
} 

class MyBall extends Ellipse2D.Double { 

    int xspeed = 1; 
    int yspeed = 1; 
    Color color; 
    private final int maxWidth; 
    private final int maxHeight; 

    public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) { 
     super(x, y, w, h); 
     color = c; 
     this.width = w;//set width and height of Rectangle2D 
     this.height = h; 
     //set max width and height ball can move 
     this.maxWidth = maxWidth; 
     this.maxHeight = maxHeight; 
    } 

    public void setColor(Color color) { 
     this.color = color; 
    } 

    public Color getColor() { 
     return color; 
    } 

    void moveBALL() { 
     x = x + xspeed; 
     y = y + yspeed; 
     if (x < 0) { 
      x = 0; 
      xspeed = -xspeed; 
     } else if (x > maxWidth - ((int) getWidth()/2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed 
      x = maxWidth - ((int) getWidth()/2); 
      xspeed = -xspeed; 
     } 
     if (y < 0) { 
      y = 0; 
      yspeed = -yspeed; 
     } else if (y > maxHeight - ((int) getHeight()/2)) { 
      y = maxHeight - ((int) getHeight()/2); 
      yspeed = -yspeed; 
     } 
    } 
} 
+0

感謝您的快速回復和正確的代碼。在您的初始答覆後,我對使用ArrayList的矩形繪畫部分感到困惑,但後來在徹底閱讀代碼後,我明白了這一點。我仍然在學習類/方法,所以我最初的代碼可能一團糟。 – user1934283

+0

@ user1934283它很高興,並且很高興您能夠正常工作並理解代碼。而不是一個問題,我喜歡提供遵循最佳實踐的代碼,而不是僅僅用另一種黑客或不好的方式解決問題。現在,您已經獲得了一些基礎,可以在代碼中使用類來簡化事情並使其更加可重用。 –

0

首先在每次揮杆需要重繪組件時調用paint組件。
並且您每次調用paint時都會在面板中添加一個新的鼠標偵聽器實例。

只是招行
p.addMouseListener(新的MouseListener(){...}
出來的塗料組分,優選後面板的初始化。

默認模板是

JPanel p = new JPanel(){ 
    @Override 
    public void paintComponent(Graphics g) { 
    } 
}; 
p.addMouseListener(new MouseListener() or new MouseAdapter() 
//Your overridden methods 

}); 

希望這有助於

+0

嗯我嘗試了你的建議,但我得到了「找不到符號 符號:變量gD」錯誤。 – user1934283

+0

永遠不要忘記調用'super.XXX',即'super.paintComponent(g)'重載方法的實現,除非你故意忽略它或者代碼無法正常工作。 –