当前位置: 首页 > 编程语言 > C#

尽管双重缓冲,但自动收报机仍在闪烁分享

时间:2023-04-10 16:43:16 C#

C#学习教程:尽管有双重缓冲,代码仍然闪烁我研究了SO、网络,并尝试了很多不同的东西,比如将TickerControl放入双缓冲面板中,而不是在双缓冲时在OnPaint()中绘制:为什么它不起作用?除了很多其他的东西。它仍然闪烁,不是每次都重复,而是每秒闪烁几次。此外,即使在OnPaint中删除“g.Clear(BackColor)”之后,背景仍然需要清除,因为文本继续滚动可读。这里是我的TickerControl类的相关部分:classTickerControl:Control{privatestaticreadonlyStringFormatstringFormat=newStringFormat(StringFormatFlags.NoWrap);私有constint填充=40;私人常量intscrollSleep=10;私有常量intscrollAdvancePixels=1;私有浮动文本宽度;私人浮动电流X;privatestaticreadonlyTimerscrollTimer=newTimer();publicTickerControl(){this.SetStyle(ControlStyles.UserPaint|ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer,true);scrollTimer.Tick+=AdvanceText;scrollTimer.Interval=scrollSleep;scrollTimer.Enabled=true;}privatevoidAdvanceText(objectsender,EventArgse){if(IsDisposed)return;currentX-=scrollAdvancePixels;如果(currentX<=-textWidth)currentX=0;无效();}protectedoverridevoidOnPaintBackground(PaintEventArgspevent){}protectedoverridevoidOnPaint(PaintEventArgse){Graphicsg=e.Graphics;g.Clear(BackColor);我们ing(SolidBrushbrush=newSolidBrush(ForeColor)){g.DrawString(Text,Font,brush,currentX,0,stringFormat);g.DrawString(Text,Font,brush,currentX+textWidth,0,stringFormat);}}有任何想法吗?更新:正如sallushan建议的手动双缓冲,让我补充一点,我之前尝试过,使用下面的代码但在屏幕上它看起来与上面完全一样,所以问题似乎不在我的OnPaint方法中。我想它必须在我的控件设置中的某个地方。私人位图后备缓冲区;protectedoverridevoidOnPaint(PaintEventArgse){if(backBuffer==null)backBuffer=newBitmap(this.ClientSize.Width,this.ClientSize.Height);图形g=Graphics.FromImage(backBuffer);G。清除(背景颜色);使用(SolidBrushbrush=newSolidBrush(ForeColor)){g.DrawString(Text,Font,brush,currentX,0,stringFormat);g.DrawString(Text,Font,brush,currentX+textWidth,0,stringFormat);}g.Dispose();e.Graphics.DrawImageUnscaled(backBuffer,0,0);}protectedoverridevoidOnPaintBackground(PaintEventArgspevent){//不要调用base!}protectedoverridevoidOnSizeChanged(EventArgse){if(backBuffer!=null){backBuffer.Dispose();后备缓冲区=空;}base.OnSizeChanged(e);}在表单中设置此代码。它将删除闪烁保护覆盖CreateParamsCreateParams{get{CreateParamscp=base.CreateParams;cp.ExStyle|=0x02000000;返回cp;希望能帮助您创建一个常量位图作为框架。然后对该位图进行更改,然后在控件上呈现该位图。这应该消除闪烁。类MyControl:System.Windows.Forms.Control{位图bmp;图形克;整数x=100;publicMyControl(){this.SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint|System.Windows.Forms.ControlStyles.UserPaint|System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,true);bmp=新位图(100,100);g=Graphics.FromImage(bmp);}protectedoverridevoidOnPaint(System.Windows.Forms.PaintEventArgse){this.g.FillRectangle(Brushes.White,newRectangle(0,0,100,100));this.g.DrawString("Hello",this.Font,Brushes.Black,(float)x,10);e.Graphics.DrawImage(bmp,newPoint(0,0));X-;}}尝试使用Invalidate(Rectangle)或Invalidate(Region)方法将重绘的数量限制在实际需要完成的范围内。您在每个OnPaint事件期间重新绘制完整控件。好吧,除了三重缓冲的想法——坦率地说,我从来没有在我的自定义控件中使用过它,而且我有相当复杂的——我想说每10毫秒使控件无效与它有关。那是每秒100次。就动作的流畅性而言,25fps的电影对人眼来说是舒适的,但您将重新获得4倍的控制。尝试一个更高的值:比如40。另外,当你重绘一个控件时,你可以只重绘它的一个区域,改变的部分:形成旧文本位置和新文本位置的两个区域的并集。您不需要重新绘制任何仍然存在的周围区域(无论是背景还是其他)。与TextRenderer的DrawText相比,DrawString()相当慢-大约6倍,您可能想要使用它。您将失去一些功能(使用GDI而不是GDI+),但它可能适用于您的方案。哦,我还会微优化并拉出您在每个OnPaint()之外重新创建的SolidBrush画笔作为类成员,仅在ForeColor更改时更新它。看起来您正在绘制2个并排的字符串:g.DrawString(Text,Font,brush,currentX,0,stringFormat);g.DrawString(Text,Font,brush,currentX+textWidth,0,stringFormat);它应该只是使Invalidate'部分控件已更改的情况。最简单的方法是缓存/计算字符串的高度并执行:Invalidate(newRectangle((int)currentX,0,(int)textWidth*2,(int)textHeight));在我的机器上,这比禁用整个控件要顺畅得多。将HansPassant的评论变成一个答案,这样我就可以接受了:这种效果不叫闪烁,叫撕裂。您将看到部分旧位图和部分新位图。在移动的物体上变得非常明显,它们看起来很紧张。无法在Winforms中修复,谷歌“垂直消隐间隔”。–HansPaster以上是C#学习教程:虽然是双缓冲,但ticker依然在闪烁所有分享的内容,如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——本文整理自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: