1

问题:您如何正确地从 OnPaint() 方法以外的方法绘制 winform?

附加信息:我现在的代码在 OnPaint() 方法中为井字游戏绘制了一些背景线。然后我使用 Mouse_Click 事件并运行这个显然不正确的代码:

private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
   Graphics g = this.CreateGraphics();
   g.DrawEllipse(this.penRed, this.Rectangle);

由于我不明白的原因,它确实绘制了圆圈,但是当最小化或将表单移出屏幕时,它会擦除​​圆圈而不是 OnPaint() 方法中的线条。

4

3 回答 3

2

问题是 Windows 窗口(包括 WinForms)没有自己的图形内存,除非它们的创建者提供这样的内存,并且特定窗口被覆盖或隐藏并最终需要重新绘制只是时间问题。您正在向屏幕绘画(您可能会说),其他人也可以这样做。您可以依赖的唯一约定是 OnPaint 将在需要时被调用。基本上可以在需要时使用你的哲学和绘画(而不是在一些神秘和不可预测的时间表上)。为此,请查看我的解决方案。

您应该使用“后缓冲位图”,例如:

private Bitmap bb;

protected override void OnResize(EventArgs e) {
  this.bb = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
  this.InitBackBuffer();
}
private void InitBackBuffer() {
  using (var g = Graphics.FromImage(this.bb)) {
    // do any of the "non dissapearing line" drawing here
  }
}

private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
  using (Graphics g = Graphics.FromImage(this.bb))
    g.DrawEllipse(this.penRed, this.Rectangle);
  this.Invalidate();
}

protected override void OnPaint(PaintEventArgs e) {
  base.OnPaint(e);
  e.Graphics.DrawImageUnscaled(this.bb);
}

试试看。应该这样做:)

于 2013-02-24T22:35:32.643 回答
2

您正在做很多“视图”但没有“模型”。

当您想创建一个形状时,当鼠标按钮向下/向上时,创建一些代表该形状的 DATA。

您的数据结构表示持久信息(它是允许您在会话之间保存和加载此信息的数据)。

您需要做的所有绘制函数就是查看 DATA 结构并绘制它。因此,这将在调整大小/隐藏/显示之间持续存在。

于 2013-02-24T22:45:14.643 回答
1

您正在做的是“异步”绘制表单(来自 OnPaint 方法)。你看,OnPaint 方法是 Windows 窗体绘制整个窗体所依赖的方法。当您的 From 发生某些事情时,它会失效并再次调用 OnPaint。如果在该方法中没有绘制某些内容,那么在此之后它将不存在。

如果您希望按钮触发某些内容永久显示,那么您需要做的是将该对象添加到某处的集合中,或设置与其相关的变量。然后调用 Refresh() 调用 Invalidate() 和 Update() 然后,在 OnPaint 期间,绘制该对象(省略号)。

如果您希望它在您的表单发生某些事情后仍然存在,例如最小化,您必须在 OnPaint 期间绘制它。

这是我的建议:

public partial class Form1 : Form
{
    Rectangle r = Rectangle.Empty;
    Pen redPen = new Pen(Color.Red);

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        r = new Rectangle(50, 50, 100, 100);
        Refresh();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (r != Rectangle.Empty)
        {
            e.Graphics.DrawRectangle(redPen, r);
        }
    }
}
于 2013-02-24T22:30:54.217 回答