2013-04-08 139 views
0

我有以下兩類:多次調用

public class Pencil extends JComponent implements MouseListener, MouseMotionListener{ 
Plansa plansa; 
Graphics g; 
public Pencil(Plansa newCanvas){ 
    this.plansa = newCanvas; 
    this.plansa.setFlagShape(false); 
} 
@Override 
public void mouseDragged(MouseEvent arg0) { 
    plansa.setMouseDragged(arg0); 
    this.plansa.setFlagShape(false); 
    plansa.paintComponent(plansa.getGraphics()); 
} 

@Override 
public void mouseClicked(MouseEvent e) { 
} 

@Override 
public void mousePressed(MouseEvent arg0) { 
    plansa.setMousePressed(arg0); 
} 

@Override 
public void mouseReleased(MouseEvent arg0) { 
    // TODO Auto-generated method stub 
    plansa.setMouseReleased(arg0); 
    this.plansa.setFlagShape(true); 
    plansa.paintComponent(plansa.getGraphics()); 

} 

@Override 
public void mouseEntered(MouseEvent e) { 
} 

@Override 
public void mouseExited(MouseEvent e) { 
} 

@Override 
public void mouseMoved(MouseEvent e) { 
} 

} 

這一個:

public class Plansa extends JPanel{ 
Image image; 
Pencil pencil; 
//... 
void init(){ 
    this.setShape("freeLine"); 
    this.setColor(Color.BLACK); 
    this.size=1; 
    this.type="round"; 
    this.fill=false; 
    this.setBackground(Color.WHITE); 
    pencil = new Pencil(this); 
    addMouseListener(pencil); 
    addMouseMotionListener(pencil); 
    flagPaint = true; 
    flagShape = false; 
} 
public Plansa(){ 
    this.setSize(800, 600); 
    init(); 
} 

//... 

     @Override 
    public void paintComponent(Graphics g) { 
    g.setColor(currentColor); 
    Graphics2D g2d = (Graphics2D) g; 
    g2d.setStroke(setBrush(size,type)); 
    super.paintComponent(g); 
    switch(shape){ 
     default: break; 
     case "freeLine":{ 
      g.drawLine(xDragged, yDragged, xCurrent, yCurrent); 
      break; 
     } 
      case "rectangle":{ 
       if(flagShape == true){ 
      g.drawRect(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); 
      if(fill == true) g.fillRect(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); 
       } 
      break; 
     } 
     case "circle":{ 
      if(flagShape == true){ 
      int radius = (int)Math.sqrt(Math.max(xCurrent-xPressed,xPressed-xCurrent)*Math.max(xCurrent-xPressed,xPressed-xCurrent)+Math.max(yCurrent-yPressed,yPressed-yCurrent)*Math.max(yCurrent-yPressed,yPressed-yCurrent)); 
      g.drawOval(xPressed, yPressed, radius, radius); 
      if(fill == true) g.fillOval(xPressed, yPressed, radius, radius); 
      } 
      break; 
     } 
     case "oval":{ 
      if(flagShape == true){ 
      g.drawOval(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); 
      if(fill == true) g.fillOval(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); 
      } 
      break; 
     } 
     case "line":{ 
      if(flagShape == true){ 
      g.drawLine(xPressed, yPressed, xCurrent, yCurrent); 
      } 
      break; 
     } 
    } 

} 

//... 
} 

我的問題是,每次我打電話的paintComponent()方法,JPanel的清除和剩下的唯一項目就是我剛畫的那個。有什麼辦法可以避免這種情況?

+3

你不應該自己調用'paintComponent'。這是繪畫鏈的一部分,由RepaintManager(通過事件調度線程)代表您的名字。相反,您應該使用'repaint',它向RepaintManager發出一個請求,以便在將來的某個時間安排更新。你也不應該使用'getGraphics'。這種方法可能返回null,並且僅僅是最後一次繪製週期的快照。它將在下一個週期的油漆被擦除 – MadProgrammer 2013-04-08 23:21:02

+0

。這使我想到的問題是,爲什麼你arn't只需添加'Plansa'直接到母部件和使用'null' /絕對佈局管理器來佈置出的組件。其餘的會照顧你。另外,請記住,繪畫是無國籍的。也就是說,你想在每個油漆週期中塗上什麼,必須在其中一種適當的塗漆方法中重新塗漆 – MadProgrammer 2013-04-08 23:24:10

+0

我會考慮這個,謝謝。 – 2013-04-08 23:29:36

回答

0

不要使用/註釋:

super.paintComponent(g); 

這條線是做清算之一。

+1

我認爲應該進一步強調,這個建議只是爲了觀察代碼之間的差異,並且**所有**真實世界的實現***應該***調用'super.paintComponent(g);' – 2013-04-08 23:23:00

+0

我想到這也是,但不知道如何去做,對象使用什麼數據類型。我應該創建一個新的課程,還是使用默認的東西? – 2013-04-08 23:23:03

3

存儲所有在ArrayList對象,並遍歷它,當你繪製。

您可以讓它們全部實現自定義界面,例如Drawable,然後存儲在ArrayList<Drawable>中。

+0

好吧,我會這樣做,謝謝你的答案。 – 2013-04-08 23:34:28

3

代碼的仔細檢查後,它將顯示你正在嘗試使用Component S作爲「畫家」,這是一個有點像用跑車的卡丁車,而收效甚微了很多羣衆演員。

相反,你應該確定自己的一些母牛,它提供的要繪製/油漆,然後定義具體的類實現,實現的功能有什麼基本要求的接口。

你會再維持某種可以畫的圖紙中的List

雖然簡單,下面的例子提供了一個起跳點可以得到加強,使圖紙的選擇,重新排序和刪除(你應該希望它)。

此,實質上是對於逐行附圖提出的門把手(1)

enter image description here

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.event.MouseMotionListener; 
import java.awt.geom.Line2D; 
import java.util.ArrayList; 
import java.util.List; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestDraw { 

    public static void main(String[] args) { 
     new TestDraw(); 
    } 

    public TestDraw() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new Pencil()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class Pencil extends JPanel implements MouseListener, MouseMotionListener { 

     private List<Drawable> drawables; 
     private Drawable activeDrawable; 

     private Point clickPoint; 

     public Pencil() { 
      drawables = new ArrayList<>(5); 
      addMouseListener(this); 
      addMouseMotionListener(this); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      for (Drawable drawable : drawables) { 
       drawable.paint(g2d); 
      } 
      g2d.dispose(); 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      if (activeDrawable != null) { 
       Point p = e.getPoint(); 
       Rectangle bounds = activeDrawable.getBounds(); 

       int x = bounds.x; 
       int y = bounds.y; 
       int width = p.x - clickPoint.x; 
       int height = p.y - clickPoint.y; 
       if (width < 0) { 
        width *= -1; 
        x = p.x; 
       } 
       if (height < 0) { 
        height *= -1; 
        y = p.y; 
       } 
       bounds = new Rectangle(x, y, width, height); 
       System.out.println(bounds); 
       activeDrawable.setBounds(bounds); 
       repaint(); 
      } 
     } 

     @Override 
     public void mouseClicked(MouseEvent e) { 
     } 

     protected Drawable createActiveShape(MouseEvent e) { 

      System.out.println("Anchor = " + e.getPoint()); 
      Drawable drawable = new FreeLine(e.getPoint()); 
      drawable.setLocation(e.getPoint()); 
      return drawable; 

     } 

     @Override 
     public void mousePressed(MouseEvent e) { 
      // You could also check to see if the clicked on a drawable... 
      clickPoint = e.getPoint(); 
      activeDrawable = createActiveShape(e); 
      drawables.add(activeDrawable); 
      repaint(); 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (activeDrawable != null) { 
       Rectangle bounds = activeDrawable.getBounds(); 
       if (bounds.width == 0 || bounds.height == 0) { 
        drawables.remove(activeDrawable); 
       } 
      } 
      clickPoint = null; 
      activeDrawable = null; 
     } 

     @Override 
     public void mouseEntered(MouseEvent e) { 
     } 

     @Override 
     public void mouseExited(MouseEvent e) { 
     } 

     @Override 
     public void mouseMoved(MouseEvent e) { 
     } 
    } 

    public interface Drawable { 

     public void setLocation(Point p); 

     public void setSize(Dimension dim); 

     public void setBounds(Rectangle bounds); 

     public Rectangle getBounds(); 

     public void paint(Graphics2D g2d); 
    } 

    public abstract class AbstractDrawable implements Drawable { 

     private Rectangle bounds; 

     public AbstractDrawable() { 
      bounds = new Rectangle(); 
     } 

     @Override 
     public void setLocation(Point p) { 
      bounds.setLocation(p); 
     } 

     @Override 
     public void setBounds(Rectangle bounds) { 
      this.bounds = bounds; 
     } 

     @Override 
     public void setSize(Dimension dim) { 
      bounds.setSize(dim); 
     } 

     @Override 
     public Rectangle getBounds() { 
      return bounds; 
     } 
    } 

    public class FreeLine extends AbstractDrawable { 

     private Point anchor; 

     public FreeLine(Point anchor) { 
      this.anchor = anchor; 
     } 

     @Override 
     public void paint(Graphics2D g2d) { 
      Rectangle bounds = getBounds(); 
      Point p1 = new Point(anchor); 
      Point p2 = new Point(bounds.getLocation()); 
      if (p1.x > p2.x) { 
       p2.x = p1.x - bounds.width; 
      } else { 
       p2.x = p1.x + bounds.width; 
      } 
      if (p1.y > p2.y) { 
       p2.y = p1.y - bounds.height; 
      } else { 
       p2.y = p1.y + bounds.height; 
      } 
      g2d.draw(new Line2D.Float(p1, p2)); 
     } 
    } 
+0

好吧,現在我明白了。這個例子非常有用。非常感謝您的幫助! – 2013-04-09 01:02:48

+0

+1,比我的答案好得多:P – Doorknob 2013-04-09 01:09:48

+0

@門把手你還是給了我這個主意 – MadProgrammer 2013-04-09 01:10:56

3

一個更好的想法大致相同的概念是使用一個BufferedImage作爲畫布,如圖here