我正在寻找一个相当简单的(简单来说,我的意思是没有什么需要太多的代码行)来解决以下问题:
我有一个绘画应用程序。该应用的代码位于:https://github.com/Tigatok/JavaProjects/tree/master/Paint2.0
这是我的问题:
如何使方线与pencilLine一样平滑?
答案 0 :(得分:4)
对于细线,您当前正在调用
g2D.drawLine(oldX, oldY, currentX, currentY);
对于粗线,您只需要调用
g2D.fillRect(currentX, currentY, getXSize(), getYSize());
这意味着当您快速移动鼠标时,前一个鼠标位置和新鼠标位置之间将没有任何关联。
一个简单的解决方案已经允许实现接近你可能想要的效果,可以将第二个调用更改为
g2D.setStroke(new BasicStroke(getXSize()));
g2D.drawLine(oldX, oldY, currentX, currentY);
但是,您当前的绘画代码有几种可能的改进。您应该考虑不根据一组布尔标志做出关于如何绘制的决定。相反,您可以考虑类似Pen
接口,允许您通过使用此接口的不同实现在不同的笔之间切换。
已经提到过,您可以将点组装成Path2D
并绘制此路径。这是一个很好的建议,你也应该考虑一下:它提供了一些很好的可能性。例如,您可以定义Stroke
并使用任意笔形状创建“描边形状”。
然而,所有这些变化可能需要相当多的重构,因此,直到现在,它们只是相当模糊的建议。
编辑:添加了基于评论的示例
我可以想象你想要达到的效果。但这可能相当困难。一个简单的解决方案,至少可以关闭到你想要的东西可能是这个(使用来自http://www.jhlabs.com/java/java2d/strokes/的类的简化版本)
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SharpiePaintTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new SharpiePaintTestPanel());
f.setSize(1100,600);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class SharpiePaintTestPanel extends JPanel
{
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setColor(Color.BLACK);
Path2D path = new Path2D.Double();
path.moveTo(300,300);
path.curveTo(400, 400, 400, 300, 300, 200);
g.setStroke(new ShapeStroke(new Rectangle2D.Double(0,0,3,15), 3.0f));
g.draw(path);
}
}
// Based on http://www.jhlabs.com/java/java2d/strokes/ShapeStroke.java,
// only slightly simplified
class ShapeStroke implements Stroke {
private Shape shape;
private float advance;
private static final float FLATNESS = 1;
public ShapeStroke(Shape shape, float advance ) {
this.advance = advance;
Rectangle2D bounds = shape.getBounds2D();
this.shape = AffineTransform.getTranslateInstance(
-bounds.getCenterX(), -bounds.getCenterY()).createTransformedShape(shape);
}
@Override
public Shape createStrokedShape( Shape shape ) {
GeneralPath result = new GeneralPath();
PathIterator it = new FlatteningPathIterator( shape.getPathIterator( null ), FLATNESS );
float points[] = new float[6];
float moveX = 0, moveY = 0;
float lastX = 0, lastY = 0;
float thisX = 0, thisY = 0;
int type = 0;
float next = 0;
while (!it.isDone() ) {
type = it.currentSegment( points );
switch( type ){
case PathIterator.SEG_MOVETO:
moveX = lastX = points[0];
moveY = lastY = points[1];
result.moveTo( moveX, moveY );
next = 0;
break;
case PathIterator.SEG_CLOSE:
points[0] = moveX;
points[1] = moveY;
// Fall into....
case PathIterator.SEG_LINETO:
thisX = points[0];
thisY = points[1];
float dx = thisX-lastX;
float dy = thisY-lastY;
float distance = (float)Math.sqrt( dx*dx + dy*dy );
if ( distance >= next ) {
float r = 1.0f/distance;
while (distance >= next ) {
float x = lastX + next*dx*r;
float y = lastY + next*dy*r;
AffineTransform t = new AffineTransform();
t.setToTranslation( x, y );
result.append( t.createTransformedShape(this.shape), false );
next += advance;
}
}
next -= distance;
lastX = thisX;
lastY = thisY;
break;
}
it.next();
}
return result;
}
}
答案 1 :(得分:1)
与Java2D相比,Java2D的绘制速度还不够快,尽管与渲染库的速度相比,Java2D是一个缓慢的库。
无论如何,在您的计划和Path2D.Double
中声明Path2D.Float
或mouseDrag
,将mouseEvent
的坐标添加到此Path2D
对象。
如果是您要添加的第一个坐标,请使用moveTo()
方法,或使用lineTo()
方法。
完成后,请致电repaint()
。
在重新绘制中,绘制Path2D
,如下所示:
public void paintComponent(Graphics graphics)
{
Graphics2D g = (Graphics2D) graphics;
// set appropriate color and line thickness here.
g.draw(path);
// draw other stuff.
g.dispose();
}