有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

swing Java创建笔刷笔划动作

当你用任何画笔用任何画笔画一条手绘线时,它最终会将该画笔的多个点叠加在一起,形成一个画笔笔划

例如,当你拖动鼠标时,一个基本的笔划会叠加1个像素。 在更高级的应用程序中,你有一个画笔,它只是一个奇特的形状,比如说:一个星星,用“星星画笔”在画布上划动,只会使绘画应用程序在你将鼠标拖动到画布上时绘制多个星星。 如果我错了,请纠正我

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

我的问题是“撤销功能”,如果你这么说的话

当我撤销一个动作时,我的应用程序只删除最后绘制的形状(圆),而我希望它删除从用户第一次按下鼠标左键到释放的整个徒手绘制(形状/圆的集合)

如何将一组形状对象“打包”为一个? 还有一个问题是重新绘制所有这些圆圈,我希望重新绘制30000个圆圈的速度要快,就像一个BuffereImage

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

每一个超过50岁的形状都会永久存储在BuffereImage背景中

目前,我将最后50个形状对象存储在ArrayList中,第51个(最老的)永久存储在BuffereImage中。 所以用户不能撤销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) 个答案

  1. # 1 楼答案

    通过将每个完成的画笔笔划或相关的任何动作存储在自己的图像中,可以避免完全使用这些列表。然后你可以按制作顺序将它们分层。这将是更少的,你可以很容易地定义多少行动在过去你想有,而最底部的一个包含一切不符合历史

    Pixel blit是一种相对快速的操作,与处理形状的操作不同,通过使用VolatileImage而不是缓冲图像来收集历史中的所有动作,可以轻松地提高速度

    在我看来,这种方法更快,并且对未来添加的操作限制更少。你可以很容易地将某些层标记为不可见,并在历史中来回移动,比如在Photoshop中,但不依赖于所述层的实际内容