Winform 下无闪烁走马灯效果实现
作者:肖波
最近需要在Winform项目中实现一个走马灯的效果,一开始用了一些办法比如移动Label控件,效果总是不太好,移动文本时总有闪烁的现象。后来找了一个国外的开源控件,应用了一下,效果还不错。仔细阅读了一下代码,发现还有一些地方值得改进,现把代码以及改动说明贴出来,和大家分享。
控件出处: http://www.codeproject.com/KB/miscctrl/ScrollingTextControlArtic.aspx
我的改动:
1、DoubleBuffer 的设置
原代码中用的是 this.SetStyle(ControlStyles.DoubleBuffer, true); 但一些网友反映这个标志在.net 2.0 以上版本无效。说句老实话,我也不是特别确信,MSDN上也没有说明这一点。在我的.net 2.0 系统中,两种设置的效果似乎没有太多区别。在一个国外网站上找到他们的区别,下面是原文:
I'm following up on the need for deprecating CS.DB and Control.DoubleBuffered's getter and will post here.
总之保险起见,还是判一下版本号,下面是判断代码
2、刷新区域
原代码中刷新区域是这样设置的
lastKnownRect是文字的整个区域,如果文字较长,这个刷新区域就会比较大,但实际上我们只需要刷新控件显示范围内的区域就可以了。
所以这里改动如下:
2、修改Enabled属性
当Enabled设置为false时,原控件依然会滚动,觉得还是不让它滚动更好一些。
修改代码如下:
下面给出修改后完整的控件代码,代码原作者为 jconwell,原始代码见前面提到的控件出处
最近需要在Winform项目中实现一个走马灯的效果,一开始用了一些办法比如移动Label控件,效果总是不太好,移动文本时总有闪烁的现象。后来找了一个国外的开源控件,应用了一下,效果还不错。仔细阅读了一下代码,发现还有一些地方值得改进,现把代码以及改动说明贴出来,和大家分享。
控件出处: http://www.codeproject.com/KB/miscctrl/ScrollingTextControlArtic.aspx
我的改动:
1、DoubleBuffer 的设置
原代码中用的是 this.SetStyle(ControlStyles.DoubleBuffer, true); 但一些网友反映这个标志在.net 2.0 以上版本无效。说句老实话,我也不是特别确信,MSDN上也没有说明这一点。在我的.net 2.0 系统中,两种设置的效果似乎没有太多区别。在一个国外网站上找到他们的区别,下面是原文:
ControlStyles == CS
AllPaintingInWMPaint == APWMP
OptimizedDoubleBuffer = ODB
DoubleBuffer = DB
An earlier permutation of the design called for ODB to simply be a combination of DB, APWMP and UserPaint. Through several design changes, the two control styles are nearly synonymous, but they still have differences. Now that we've broken that, we may consider un-deprecating CS.DB to retain . Here is a more complete summary of the current design:
Mechanism | Side effects | Other flags required to work | Require APWMP? | Notes |
ControlStyle .DB |
none |
APWMP, UserPaint |
Yes |
We are considering NOT deprecating this flag because ODB isn't an exact replacement for DB. |
ControlStyle .ODB |
none |
none |
No |
Works, but without APWMP set you'll buffer foreground and background separately and will still see flicker. |
Control .DoubleBuffered |
sets CS.ODB, CS.APWMP |
none |
No |
Works for most mainstream buffering needs. Getter is peculiar in that it only checks CS.ODB. |
I'm following up on the need for deprecating CS.DB and Control.DoubleBuffered's getter and will post here.
总之保险起见,还是判一下版本号,下面是判断代码
Version v
=
System.Environment.Version;
if (v.Major < 2 )
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
else
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
if (v.Major < 2 )
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
else
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
2、刷新区域
原代码中刷新区域是这样设置的
private
void
Tick(
object
sender, EventArgs e)
{
//update rectangle to include where to paint for new position
//lastKnownRect.X -= 10;
//lastKnownRect.Width += 20;
lastKnownRect.Inflate(10, 5);
//create region based on updated rectangle
Region updateRegion = new Region(lastKnownRect);
//repaint the control
Invalidate(updateRegion);
Update();
}
{
//update rectangle to include where to paint for new position
//lastKnownRect.X -= 10;
//lastKnownRect.Width += 20;
lastKnownRect.Inflate(10, 5);
//create region based on updated rectangle
Region updateRegion = new Region(lastKnownRect);
//repaint the control
Invalidate(updateRegion);
Update();
}
lastKnownRect是文字的整个区域,如果文字较长,这个刷新区域就会比较大,但实际上我们只需要刷新控件显示范围内的区域就可以了。
所以这里改动如下:
//
Controls the animation of the text.
private void Tick( object sender, EventArgs e)
{
//update rectangle to include where to paint for new position
//lastKnownRect.X -= 10;
//lastKnownRect.Width += 20;
lastKnownRect.Inflate(10, 5);
//get the display rectangle
RectangleF refreshRect = lastKnownRect;
refreshRect.X = Math.Max(0, lastKnownRect.X);
refreshRect.Width = Math.Min(lastKnownRect.Width + lastKnownRect.X, this.Width);
refreshRect.Width = Math.Min(this.Width - lastKnownRect.X, refreshRect.Width);
//create region based on updated rectangle
//Region updateRegion = new Region(lastKnownRect);
Region updateRegion = new Region(refreshRect);
//repaint the control
Invalidate(updateRegion);
Update();
}
private void Tick( object sender, EventArgs e)
{
//update rectangle to include where to paint for new position
//lastKnownRect.X -= 10;
//lastKnownRect.Width += 20;
lastKnownRect.Inflate(10, 5);
//get the display rectangle
RectangleF refreshRect = lastKnownRect;
refreshRect.X = Math.Max(0, lastKnownRect.X);
refreshRect.Width = Math.Min(lastKnownRect.Width + lastKnownRect.X, this.Width);
refreshRect.Width = Math.Min(this.Width - lastKnownRect.X, refreshRect.Width);
//create region based on updated rectangle
//Region updateRegion = new Region(lastKnownRect);
Region updateRegion = new Region(refreshRect);
//repaint the control
Invalidate(updateRegion);
Update();
}
2、修改Enabled属性
当Enabled设置为false时,原控件依然会滚动,觉得还是不让它滚动更好一些。
修改代码如下:
[
Browsable( true ),
CategoryAttribute( " Behavior " ),
Description( " Indicates whether the control is enabled " )
]
new public bool Enabled
{
set
{
timer.Enabled = value;
base.Enabled = value;
}
get
{
return base.Enabled;
}
}
Browsable( true ),
CategoryAttribute( " Behavior " ),
Description( " Indicates whether the control is enabled " )
]
new public bool Enabled
{
set
{
timer.Enabled = value;
base.Enabled = value;
}
get
{
return base.Enabled;
}
}
下面给出修改后完整的控件代码,代码原作者为 jconwell,原始代码见前面提到的控件出处
using
System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
namespace ScrollingTextControl
{
/**//// <summary>
/// Summary description for ScrollingTextControl.
/// </summary>
[
ToolboxBitmapAttribute(typeof(ScrollingTextControl.ScrollingText), "ScrollingText.bmp"),
DefaultEvent("TextClicked")
]
public class ScrollingText : System.Windows.Forms.Control
{
private Timer timer; // Timer for text animation.
private string text = "Text"; // Scrolling text
private float staticTextPos = 0; // The running x pos of the text
private float yPos = 0; // The running y pos of the text
private ScrollDirection scrollDirection = ScrollDirection.RightToLeft; // The direction the text will scroll
private ScrollDirection currentDirection = ScrollDirection.LeftToRight; // Used for text bouncing
private VerticleTextPosition verticleTextPosition = VerticleTextPosition.Center; // Where will the text be vertically placed
private int scrollPixelDistance = 2; // How far the text scrolls per timer event
private bool showBorder = true;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
namespace ScrollingTextControl
{
/**//// <summary>
/// Summary description for ScrollingTextControl.
/// </summary>
[
ToolboxBitmapAttribute(typeof(ScrollingTextControl.ScrollingText), "ScrollingText.bmp"),
DefaultEvent("TextClicked")
]
public class ScrollingText : System.Windows.Forms.Control
{
private Timer timer; // Timer for text animation.
private string text = "Text"; // Scrolling text
private float staticTextPos = 0; // The running x pos of the text
private float yPos = 0; // The running y pos of the text
private ScrollDirection scrollDirection = ScrollDirection.RightToLeft; // The direction the text will scroll
private ScrollDirection currentDirection = ScrollDirection.LeftToRight; // Used for text bouncing
private VerticleTextPosition verticleTextPosition = VerticleTextPosition.Center; // Where will the text be vertically placed
private int scrollPixelDistance = 2; // How far the text scrolls per timer event
private bool showBorder = true;