Java创建画笔描边动作

时间:2015-06-02 20:54:56

标签: java swing arraylist graphics shape

当您使用任何画笔绘制任意绘画应用的手绘线时,它最终将该画笔的多个点堆叠在一起以形成画笔笔触。

例如,拖动鼠标时,基本笔划会叠加1个像素。 在更高级的应用程序中,你有一个刷子,它只是一个花哨的形状,例如:一个星星,用“星刷”抚摸画布只会导致绘画应用程序在画布上拖动鼠标时绘制多个星星。 如果我错了,请纠正我。

我已经实现了“画笔”(即基本圆圈),每当用户将鼠标悬停在画布上,同时按住鼠标左键,应用程序会为每个新鼠标位置绘制一个圆圈。

我的问题是“撤消功能”,如果您可以这样称呼它。

当我撤消动作时,我的应用程序只删除最后绘制的形状(圆形),而我希望它从用户首次按下鼠标左键删除整个手绘图形(形状/圆形的集合) - 按钮发布。

如何将Shape对象“打包”成一个? 一个问题也是所有这些圈子的重新绘制,我希望重新绘制可能30000个圆圈的速度,就像BufferedImage一样。

我已经使用BufferedImage作为我的图像的背景。

“年龄超过50”的每个形状都会永久存储在BufferedImage背景中。

目前,我将最后50个Shape对象存储在ArrayList中,而第51个(最旧的)对象永久存储在BufferedImage中。 因此,用户无法撤消50个操作,而是撤消50个形状。

谢谢!

剥离代码示例:

public class GraphicPanel extends JComponent{

private int x = 0;
private int y = 0;
private int compXLen = 100;
private int compYLen = 100;
private boolean isCompFilled = false;
private boolean isAreaToBePainted = false;
private boolean isFocused = false;
private Shape ghost;
private ArrayList<Shape> shapeBuffer = new ArrayList<Shape>();
private BufferedImage img = new BufferedImage( PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB );
private static final int PREF_W = 800;
private static final int PREF_H = 500;

@Override
public void paintComponent( Graphics gPlain ){
    super.repaint();
    Graphics2D g = (Graphics2D)gPlain;

    //paint background
    if (img != null){
      g.drawImage(img, 0, 0, null);
    }       

    ghost = new Ellipse2D.Double( x-( compXLen/2 ), y-( compYLen/2 ), compXLen, compYLen );

    if( isAreaToBePainted ){
      //add ghost Shape to ArrayList
      add( g, ghost )
    }
    //paint arrayList
    for( Shape s : shapeBuffer ){
        g.fill( s );    
    }

    if( isFocused ){
    // draw ghost shape
       g.draw( ghost );
    }

}

/**
 * adds circles to arrayList
 */
private void add( Graphics2D g, Shape s ){
//fetch last arrayList element in Shape shp
//add ghost shape at the top of arrayList

    Graphics2D g2 = img.createGraphics();
    shapeBuffer.add( shp );
    g2.fill( shp );
    g2.dispose();
}

public void clearArea(){
    shapeBuffer = new ArrayList<Shape>();
    img = new BufferedImage( PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB );
    repaint();
}

private class GraphicPanelMouseListen implements MouseListener, MouseMotionListener{

    /**
     * @param e Mouse Event
     * @since 0.1
     */
    @Override
    public void mouseClicked( MouseEvent e ){}
    public void mousePressed( MouseEvent e ){
        x = e.getX();
        y = e.getY();
        isAreaToBePainted = true;
        repaint();
    }
    public void mouseReleased( MouseEvent e ){}
    public void mouseEntered( MouseEvent e ){
        isFocused = true;
    }
    public void mouseExited( MouseEvent e ){
        isFocused = false;
         repaint();
    }
    public void mouseDragged( MouseEvent e ){
        isAreaToBePainted = true;
        x = e.getX();
        y = e.getY();
        repaint();
    }
    public void mouseMoved( MouseEvent e ){
      x = e.getX();
      y = e.getY();
      repaint();
            }

}//public class GraphicPanelMouseListen implements MouseListener

}//public class GraphicPanel

1 个答案:

答案 0 :(得分:0)

您可以通过将每个完成的画笔描边或任何操作存储在自己的图像中来完全避免使用这些列表。然后,您可以按顺序对它们进行分层。它们将会更少,您可以轻松定义过去想要拥有的动作数量,而最底层的动作包含历史记录中不适合的所有动作。

Pixel blit操作相对较快,与使用形状的操作不同,您可以使用VolatileImage代替缓冲图像来收集历史记录中的所有操作,从而轻松加快速度。

在我看来,这种方法更快,对未来增加的行动的限制更少。您可以轻松地将某些图层标记为不可见,并像在Photoshop中一样在历史记录中来回移动,但不依赖于所述图层的实际内容。