1

对于图形练习和一些自我改进之类的东西,我决定基本上只是搞砸并尝试在winform中重新创建一些绘画功能。我有很多标准的工作,例如油漆罐,在光标周围画点,自由手绘等等,但是我对油漆如何做中间绘图动画有点困惑。例如;

要画一条简单的线,我可以简单地在 MouseUp 和 MouseDown 事件上获取鼠标坐标,并使用图形类在两者之间画一条线。

但是,在 MSpaint 上绘制一条线时,单击第一个点后,您几乎可以看到该线的“预览”,并且在将其拖动到第二个点时,该线会跟随您的光标,但我有点不知道如何这会做吗?它是否涉及不断重绘线条和图形设备?如果有人能给我一些提示/内在知识,那就太好了,我在互联网上进行了搜索,但真的找不到任何有用的东西..

4

2 回答 2

2

并且通过ControlPaint.DrawReversibleLine方法非常现代:)

Point? startPoint;
Point? endPoint;

private void Form_MouseDown(object sender, MouseEventArgs e)
{
    startPoint = PointToScreen(e.Location);
}

private void Form_MouseMove(object sender, MouseEventArgs e)
{
    if (!startPoint.HasValue)
        return;

    if (endPoint.HasValue)
        ControlPaint.DrawReversibleLine(startPoint.Value, endPoint.Value, Color.White);

    endPoint = PointToScreen(e.Location);
    ControlPaint.DrawReversibleLine(startPoint.Value, endPoint.Value, Color.White);
}

private void Form_MouseUp(object sender, MouseEventArgs e)
{
    startPoint = null;
    endPoint = null;
}
于 2012-12-05T23:20:50.283 回答
1

位图/光栅软件使用两个内存缓冲区:一个是当前“持久”画布,其中包含用户已明确修改的像素,第二个是图形卡上的帧缓冲区,用于在屏幕上显示画布。

只需将内存中位图文档的原始字节复制到帧缓冲区即可使位图文档显示在屏幕上(如果帧缓冲区的字节格式或颜色深度与内存中位图不同,则您需要执行转换。如有必要,GDI 可以为您执行此操作,但我们假设一切都是 32 位 ARGB)。

在 WinForms 中,帧缓冲区由Graphics传递给您的Control.OnPaint覆盖的参数公开。

您可以使用以下两种方法之一来实现这些“预览”效果:

现代的

今天使用第一种方法,并且已经使用了 17 年左右(从 Windows 95 开始)。每当屏幕需要更新时,内存中的位图就会被复制到帧缓冲区,例如单个鼠标移动(甚至 1px)。然后在顶部绘制预览效果(例如用户释放鼠标按钮后将绘制的线条)。一旦用户的鼠标再次移动,该过程就会重复,以便更新预览。

你会有这样的事情:

public class PaintingCanvas : Control {

    private Bitmap _canvas = new Bitmap();

    private Boolean _inOp; // are we in a mouse operation?
    private Point _opStart; // where the current mouse operation started
    private Point _opEnd; // where it ends

    public override void OnPaint(PaintEventArgs e) {
        Graphics g = e.Graphics;
        g.DrawImage( _canvas ); // draw the current state

        if( _inOp ) {
            // assuming the only operation is to draw a line
            g.DrawLine( _opStart, _opEnd );
        }
    }

    protected override OnMouseDown(Point p) {
        _inOp = true;
        _opStart = _opEnd = p;
    }
    protected override OnMouseMove(Point p) {
        _opEnd = p;
        this.Invalidate(); // trigger repainting
    }
    protected override OnMouseUp(Point p) {
        using( Graphics g = Graphics.FromImage( _bitmap ) ) {
            g.DrawLine( _opStart, _opEnd ); // a permanent line
        }
        _inOp = false;
    }
}

1980 年代闪光黑

在过去(想想:1980 年代),将位图从内存复制到帧缓冲区很慢,所以一个非常好的 hack 是使用 XOR 绘画。该程序假定帧缓冲区的所有权(因此没有重叠的窗口会导致它需要从内存中复制)。预览线是通过对线将覆盖的所有像素执行异或来绘制的。这很快,因为对像素进行异或意味着可以恢复它们的原始颜色,而无需从内存中重新复制像素。直到最近,此技巧在计算机中用于多种选择、突出显示或预览效果。

highlightOrPreviewColor = originalPixelColor XOR (2^bpp - 1)
originalPixelColor      = highlightOrPreviewColor XOR (2^bpp - 1)
于 2012-12-05T22:54:51.913 回答