2016-06-13 86 views
0

好吧,所以我正在尝试制作一个油漆项目,至今我都很成功。我有一个“画布”来绘制,我有一个带有颜色选择的工具栏菜单。我用drawLine()制作了一个按钮和方法,它通过鼠标移动侦听器和我的结束坐标获取我当前的坐标,基本上在画布上随时随地绘制线条。现在我想添加一个按钮,单击它时,将在我的画布上绘制一个椭圆形/圆形。这里出现问题。第一个问题 - 我可以让它在我的鼠标坐标上绘制椭圆,但在释放鼠标按钮并实际绘制它之前,我无法拖动它以改变其大小(就像在Microsoft绘制中那样)。如何正确使用drawOval()方法?

第二个问题 - 当我选择了我的“线条”按钮来调用我的画线方法时,我可以画线条,但是当我点击“椭圆形”按钮时,它将绘制椭圆形,当我点击鼠标时(我假设当我选择椭圆时我需要禁用鼠标移动侦听器)。相反也是如此,如果我之前选择了“椭圆”按钮并绘制了椭圆,则点击“线”按钮,它会绘制一条线,而且每次点击开始绘制线条时都会放一个椭圆。

这是我简单的程序看起来像: Image

下面是有关的drawLine,drawOval和我协调收集方法的代码,因为其他一切都如预期运行的一部分:

// Image in which we're drawing. 
    private Image image; 
    // Graphics2D object which we used to draw on. 
    private Graphics2D g2; 
    // Mouse coordinates 
    private int currentX, currentY, oldX, oldY; 

    public DrawArea(){ 
     setDoubleBuffered(false); 
     addMouseListener(new MouseAdapter(){ 

      public void mousePressed(MouseEvent e){ 
       //save coordinates x,y when mouse is pressed. 
       oldX=e.getX(); 
       oldY=e.getY(); 
      }}); 

    } 

protected void paintComponent(Graphics g){ 
    if (image==null){ 
     //image to draw null ==> we create 
     image = createImage(getSize().width, getSize().height); 
     g2 = (Graphics2D) image.getGraphics(); 
     //enable antialiasing. 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
       RenderingHints.VALUE_ANTIALIAS_ON); 
     //clear draw area 
     clear(); 
    } 

    g.drawImage(image, 0, 0, null); 
} 

public void clear(){ 
    g2.setPaint(Color.white); 
    //draw white on entire draw are to clear it. 
    g2.fillRect(0, 0, getSize().width, getSize().height); 
    g2.setPaint(Color.black); 
    repaint(); 
} 

public void Line(){ 
    addMouseMotionListener(new MouseMotionAdapter(){ 
     public void mouseDragged(MouseEvent e){ 
      //coordinates x,y when dragging mouse. 
      currentX=e.getX(); 
      currentY=e.getY(); 
      if (g2 != null){ 
       g2.drawLine(oldX, oldY, currentX, currentY); 
       repaint(); 
       oldX = currentX; 
       oldY = currentY; 
      } 
     } 
    }); 
} 

public void Oval(){ 
    addMouseListener(new MouseAdapter(){ 
     public void mousePressed(MouseEvent e){ 
      currentX=e.getX(); 
      currentY=e.getY(); 
      if (g2 != null){ 
       g2.drawOval(oldX, oldY, currentX, currentY); 
       repaint(); 
      } 
     } 
    }); 
} 

回答

0

第一个问题 - 我可以让它在我的鼠标坐标上绘制椭圆,但在释放鼠标按钮并实际绘制它之前,我不能拖动它来改变其大小(就像在Microsoft绘画中一样)。

每当您移动鼠标时您都可以重新绘制整个画布,但您可能不想这样做。相反,您可能需要使用第二个画布来绘制临时椭圆(或线条,方框等),并在您拖动鼠标时重新绘制。这并不昂贵,因为您只需要一个或几个绘制调用。

释放鼠标时,您可以将当前选中的形状绘制到更持久的画布上。实现此目的的一种方法是使用BufferedImage作为您的永久性画布和面板(或您使用的任何画布)作为临时画布。然后拖动鼠标时,首先将图像绘制到面板上,然后添加形状。释放鼠标时,将图形绘制到图像上,然后将图像绘制到面板上并完成。

这样你就可以有一个图像对象,如果需要的话你可以写入一个文件。

编辑:看着你的代码,你似乎已经有了图像。因此,只需将图形对象的绘图临时形状更改为:只要拖动鼠标,就可以直接使用正在绘制的组件。

其次的问题 - 当我选择我的“线”按钮,它会调用我的画线方法,我可以画线,并以其优良的,但是当我点击“椭圆”按钮,它绘制椭圆形,但也当我点击鼠标时放置一条线(我假设我需要在选择椭圆时禁用线上的鼠标移动侦听器。)

是的,你应该可能只有一个用于绘制的监听器(虽然监听器绘图本身似乎是有问题的设计,但我现在就跳过)。该监听器在您按下按钮时记录鼠标位置,并在拖动鼠标或再次释放按钮后记录鼠标位置。

当释放按钮时,你会检查位置是否在画布内,如果不是就忘记其余的。因此,单击按钮时不会得到任何形状。

此外,单击按钮应该可能只是改变您要绘制的形状(通过设置某个变量或替换处理实际绘图的对象)。然后,鼠标监听器将使用该信息绘制当前选定的形状(如果有的话) - 理想情况下,通知“抽屉”关于任何相关事件。

编辑:仅使用一个侦听器(简化,即没有任何检查,颜色等)的示例。

interface Renderer { 
    void draw(Graphics2D g, Point start, Point end); 
} 

class OvalRenderer implements Renderer { 
    public void draw(Graphics2D g, Point start, Point end) { 
    g.drawOval(start.getX(), start.getY(), end.getY(), end.getY()); 
    } 
} 

class CanvasListener extends MouseAdapter { 
    Point start; 
    public void mousePressed(MouseEvent e){ 
    start = e.getPoint(); 
    } 

    public void mouseDragged(MouseEvent e){ 
    //currentRenderer is defined elsewhere and just made accessible to the listener 
    currentRenderer.draw(component.getGraphics(), start, e.getPoint()); 
    } 

    public void mouseReleased(MouseEvent e){ 
    currentRenderer.draw(image.getGraphics(), start, e.getPoint()); 
    } 
} 
+0

谢谢您的输入。问题更加突出,例如当我选择Oval并选择Line时,每当我按下画线时,它也会弹出一个椭圆,反之亦然。当我按下按钮时它没有画任何东西,因为我已经在检查它了,所以这至少不是问题。我只需要弄清楚如何让mouselistener一次只能使用一个“形状”。 – Sick

+0

@Sick你也可以删除以前添加的侦听器,如果有的话,但我会建议尝试只使用一个。毕竟,听众的任务是收集某些事件的位置并通知其他组件,但不会执行实际绘制(请参阅单一职责原则)。因此,尝试使用另一个类(或更好的层次结构)进行渲染 - 我将添加一个示例。 – Thomas