C#Draw Line OnPaint()vs CreateGraphics()

问题:如何从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()方法中的线条。

你正在做的是在“异步”(来自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); } } } 

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

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

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

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

问题是Windows窗口(包括WinForms)没有自己的图形内存,除非它们的创建者提供这样的内存,并且在特定窗口被覆盖或隐藏并且最终需要重新绘制之前只是时间问题。 你正在画画(你可能会说),而其他人也可以这样做。 您可以依赖的唯一约定是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); } 

试试吧。 应该这样做:)