带自定义绘制控件的Panel滚动时绘制异常问题求助
解决Panel滚动时自定义控件绘制异常的问题
嘿,我帮你找到这个滚动绘制问题的症结啦!你遇到的向左滚动时控件显示异常的情况,核心问题出在自定义控件的OnPaint方法里对绘制区域的处理上。
问题根源
你在OnPaint里用了pe.ClipRectangle.X和pe.ClipRectangle.Y来创建椭圆的绘制矩形,但ClipRectangle是相对于当前控件自身的客户端坐标,不是Panel滚动后的全局偏移坐标。当向左滚动时,Panel的AutoScrollPosition会改变控件的显示偏移,但你的绘制代码错误地把ClipRectangle的起始坐标当成了绘制起点,导致椭圆的位置跑偏,自然就显示异常了。
解决方案
修改自定义控件的OnPaint方法,直接基于控件自身的内部坐标来绘制(比如从(0,0)开始),Panel的滚动偏移会由WinForms自动处理,完全不需要你手动调整绘制位置。另外还可以优化一下滚动逻辑,去掉不必要的手动重绘调用。
修改后的自定义控件代码
public partial class CustomControl1 : Control { public bool isOdd { get; set; } public CustomControl1() { InitializeComponent(); // 开启双缓冲,减少滚动时的控件闪烁 this.DoubleBuffered = true; } protected override void OnPaint(PaintEventArgs pe) { Graphics gr = pe.Graphics; // 直接使用控件自身的客户端区域作为绘制范围 Rectangle rc = new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height); // 简化Brush的赋值逻辑 Brush br = isOdd ? new SolidBrush(Color.Yellow) : new SolidBrush(Color.Red); gr.FillEllipse(br, rc); base.OnPaint(pe); // 记得释放Brush资源,避免内存泄漏 br.Dispose(); } protected override void OnPaintBackground(PaintEventArgs pe) { base.OnPaintBackground(pe); } }
优化后的Form滚动逻辑
原来的滚动代码有两处小问题:左滚动的边界判断不准确,右滚动时错误引用了垂直滚动的最大值,而且手动调用Invalidate完全没必要——WinForms会自动处理滚动后的控件重绘。修改后的代码如下:
private void keyPress(object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.A: if (location - 20 >= 0) { location -= 20; pn.HorizontalScroll.Value = location; } else { location = 0; pn.AutoScrollPosition = new Point(location, 0); } break; case Keys.D: if (location + 20 <= pn.HorizontalScroll.Maximum) { location += 20; pn.HorizontalScroll.Value = location; } else { location = pn.HorizontalScroll.Maximum; pn.AutoScrollPosition = new Point(location, 0); } break; } // 移除不必要的手动重绘调用 // foreach(Control c in pn.Controls) { c.Invalidate(); } }
效果验证
这样修改之后,不管你向左还是向右滚动Panel,自定义控件都会基于自身的内部坐标正确绘制椭圆,WinForms会自动处理滚动带来的偏移,再也不会出现绘制异常的情况了。开启双缓冲还能让滚动过程更流畅,减少闪烁。
内容的提问来源于stack exchange,提问作者JW12689
相关产品推荐
相关产品推荐

