2013-04-08 169 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