C#Draw Line OnPaint()vs CreateGraphics()

时间:2013-02-24 22:25:30

标签: c# drawing line

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

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

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

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

3 个答案:

答案 0 :(得分:2)

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

你应该使用“backbuffer bitmap”,如:

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);
}

试试吧。应该这样做:))

答案 1 :(得分:2)

你正在做很多“观察”,但没有“模特”。

如果要创建形状,当鼠标按钮向下/向上移动时,请创建一些表示形状的数据。

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

你需要做的所有绘画功能都是查看DATA结构并绘制它。因此,这将在尺寸/隐藏/显示之间持续存在。

答案 2 :(得分:1)

您正在做的是“异步”绘制表单(来自OnPaint方法)。你看,OnPaint方法是Windows Forms依赖于绘制整个表单的方法。当您的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);
        }
    }
}