Winform 下无闪烁走马灯效果实现
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; // Show a border or not
private bool stopScrollOnMouseOver = false; // Flag to stop the scroll if the user mouses over the text
private bool scrollOn = true; // Internal flag to stop / start the scrolling of the text
private Brush foregroundBrush = null; // Allow the user to set a custom Brush to the text Font
private Brush backgroundBrush = null; // Allow the user to set a custom Brush to the background
private Color borderColor = Color.Black; // Allow the user to set the color of the control border
private RectangleF lastKnownRect; // The last known position of the text

public ScrollingText()
{
// Setup default properties for ScrollingText control
InitializeComponent();
//This turns off internal double buffering of all custom GDI+ drawing
Version v = System.Environment.Version;

if (v.Major < 2)
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
else
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);

//setup the timer object
timer = new Timer();
timer.Interval = 25; //default timer interval
timer.Enabled = true;
timer.Tick += new EventHandler(Tick);
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
//Make sure our brushes are cleaned up
if (foregroundBrush != null)
foregroundBrush.Dispose();

//Make sure our brushes are cleaned up
if (backgroundBrush != null)
backgroundBrush.Dispose();

//Make sure our timer is cleaned up
if (timer != null)
timer.Dispose();
}
base.Dispose( disposing );
}

Component Designer generated code
//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();
}

//Paint the ScrollingTextCtrl.
protected override void OnPaint(PaintEventArgs pe)
{
//Console.WriteLine(pe.ClipRectangle.X + ", " + pe.ClipRectangle.Y + ", " + pe.ClipRectangle.Width + ", " + pe.ClipRectangle.Height);

//Paint the text to its new position
DrawScrollingText(pe.Graphics);

//pass on the graphics obj to the base Control class
base.OnPaint(pe);
}

//Draw the scrolling text on the control
public void DrawScrollingText(Graphics canvas)
{
canvas.SmoothingMode = SmoothingMode.HighQuality;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;

//measure the size of the string for placement calculation
SizeF stringSize = canvas.MeasureString(this.text, this.Font);
//Calculate the begining x position of where to paint the text
if (scrollOn)
{
CalcTextPosition(stringSize);
}

//Clear the control with user set BackColor
if (backgroundBrush != null)
{
canvas.FillRectangle(backgroundBrush, 0, 0, this.ClientSize.Width, this.ClientSize.Height);
}
else
{
canvas.Clear(this.BackColor);
}

// Draw the border
if (showBorder)
{
using (Pen borderPen = new Pen(borderColor))
canvas.DrawRectangle(borderPen, 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
}

// Draw the text string in the bitmap in memory
if (foregroundBrush == null)
{
using (Brush tempForeBrush = new System.Drawing.SolidBrush(this.ForeColor))
canvas.DrawString(this.text, this.Font, tempForeBrush, staticTextPos, yPos);
}
else
{
canvas.DrawString(this.text, this.Font, foregroundBrush, staticTextPos, yPos);
}

lastKnownRect = new RectangleF(staticTextPos, yPos, stringSize.Width, stringSize.Height);
EnableTextLink(lastKnownRect);
}

private void CalcTextPosition(SizeF stringSize)
{
switch (scrollDirection)
{
case ScrollDirection.RightToLeft:
if (staticTextPos < (-1 * (stringSize.Width)))
staticTextPos = this.ClientSize.Width - 1;
else
staticTextPos -= scrollPixelDistance;
break;
case ScrollDirection.LeftToRight:
if (staticTextPos > this.ClientSize.Width)
staticTextPos = -1 * stringSize.Width;
else
staticTextPos += scrollPixelDistance;
break;
case ScrollDirection.Bouncing:
if (currentDirection == ScrollDirection.RightToLeft)
{
if (staticTextPos < 0)
currentDirection = ScrollDirection.LeftToRight;
else
staticTextPos -= scrollPixelDistance;
}
else if (currentDirection == ScrollDirection.LeftToRight)
{
if (staticTextPos > this.ClientSize.Width - stringSize.Width)
currentDirection = ScrollDirection.RightToLeft;
else
staticTextPos += scrollPixelDistance;
}
break;
}

//Calculate the vertical position for the scrolling text
switch (verticleTextPosition)
{
case VerticleTextPosition.Top:
yPos = 2;
break;
case VerticleTextPosition.Center:
yPos = (this.ClientSize.Height / 2) - (stringSize.Height / 2);
break;
case VerticleTextPosition.Botom:
yPos = this.ClientSize.Height - stringSize.Height;
break;
}
}

Mouse over, text link logic

Properties
}

public enum ScrollDirection
{
RightToLeft,
LeftToRight,
Bouncing
}

public enum VerticleTextPosition
{
Top,
Center,
Botom
}
}

注意事项
如果要调整滚动速度,可以通过设置以下两个属性的值来实现
TextScrollSpeed 和 TextScrollDistance
TextScrollSpeed 其实是设置刷新频率,单位是毫秒,这个值越小,滚动速度越快。但刷新频率越高,CPU占用率越高。
TextScrollDistance 是指每次刷新移动的像素点,这个值越大,速度越快,但如果太大,文字滚动看起来就不是特别连贯。
所以在实际应用中我们需要同时调整这两个值,以找到最佳的平衡点
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; // Show a border or not
private bool stopScrollOnMouseOver = false; // Flag to stop the scroll if the user mouses over the text
private bool scrollOn = true; // Internal flag to stop / start the scrolling of the text
private Brush foregroundBrush = null; // Allow the user to set a custom Brush to the text Font
private Brush backgroundBrush = null; // Allow the user to set a custom Brush to the background
private Color borderColor = Color.Black; // Allow the user to set the color of the control border
private RectangleF lastKnownRect; // The last known position of the text
public ScrollingText()
{
// Setup default properties for ScrollingText control
InitializeComponent();
//This turns off internal double buffering of all custom GDI+ drawing
Version v = System.Environment.Version;
if (v.Major < 2)
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
else
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
//setup the timer object
timer = new Timer();
timer.Interval = 25; //default timer interval
timer.Enabled = true;
timer.Tick += new EventHandler(Tick);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
//Make sure our brushes are cleaned up
if (foregroundBrush != null)
foregroundBrush.Dispose();
//Make sure our brushes are cleaned up
if (backgroundBrush != null)
backgroundBrush.Dispose();
//Make sure our timer is cleaned up
if (timer != null)
timer.Dispose();
}
base.Dispose( disposing );
}
Component Designer generated code
//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();
}
//Paint the ScrollingTextCtrl.
protected override void OnPaint(PaintEventArgs pe)
{
//Console.WriteLine(pe.ClipRectangle.X + ", " + pe.ClipRectangle.Y + ", " + pe.ClipRectangle.Width + ", " + pe.ClipRectangle.Height);
//Paint the text to its new position
DrawScrollingText(pe.Graphics);
//pass on the graphics obj to the base Control class
base.OnPaint(pe);
}
//Draw the scrolling text on the control
public void DrawScrollingText(Graphics canvas)
{
canvas.SmoothingMode = SmoothingMode.HighQuality;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
//measure the size of the string for placement calculation
SizeF stringSize = canvas.MeasureString(this.text, this.Font);
//Calculate the begining x position of where to paint the text
if (scrollOn)
{
CalcTextPosition(stringSize);
}
//Clear the control with user set BackColor
if (backgroundBrush != null)
{
canvas.FillRectangle(backgroundBrush, 0, 0, this.ClientSize.Width, this.ClientSize.Height);
}
else
{
canvas.Clear(this.BackColor);
}
// Draw the border
if (showBorder)
{
using (Pen borderPen = new Pen(borderColor))
canvas.DrawRectangle(borderPen, 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
}
// Draw the text string in the bitmap in memory
if (foregroundBrush == null)
{
using (Brush tempForeBrush = new System.Drawing.SolidBrush(this.ForeColor))
canvas.DrawString(this.text, this.Font, tempForeBrush, staticTextPos, yPos);
}
else
{
canvas.DrawString(this.text, this.Font, foregroundBrush, staticTextPos, yPos);
}
lastKnownRect = new RectangleF(staticTextPos, yPos, stringSize.Width, stringSize.Height);
EnableTextLink(lastKnownRect);
}
private void CalcTextPosition(SizeF stringSize)
{
switch (scrollDirection)
{
case ScrollDirection.RightToLeft:
if (staticTextPos < (-1 * (stringSize.Width)))
staticTextPos = this.ClientSize.Width - 1;
else
staticTextPos -= scrollPixelDistance;
break;
case ScrollDirection.LeftToRight:
if (staticTextPos > this.ClientSize.Width)
staticTextPos = -1 * stringSize.Width;
else
staticTextPos += scrollPixelDistance;
break;
case ScrollDirection.Bouncing:
if (currentDirection == ScrollDirection.RightToLeft)
{
if (staticTextPos < 0)
currentDirection = ScrollDirection.LeftToRight;
else
staticTextPos -= scrollPixelDistance;
}
else if (currentDirection == ScrollDirection.LeftToRight)
{
if (staticTextPos > this.ClientSize.Width - stringSize.Width)
currentDirection = ScrollDirection.RightToLeft;
else
staticTextPos += scrollPixelDistance;
}
break;
} 
//Calculate the vertical position for the scrolling text
switch (verticleTextPosition)
{
case VerticleTextPosition.Top:
yPos = 2;
break;
case VerticleTextPosition.Center:
yPos = (this.ClientSize.Height / 2) - (stringSize.Height / 2);
break;
case VerticleTextPosition.Botom:
yPos = this.ClientSize.Height - stringSize.Height;
break;
}
}
Mouse over, text link logic

Properties
}
public enum ScrollDirection
{
RightToLeft,
LeftToRight,
Bouncing
}
public enum VerticleTextPosition
{
Top,
Center,
Botom
}
}
注意事项
如果要调整滚动速度,可以通过设置以下两个属性的值来实现
TextScrollSpeed 和 TextScrollDistance
TextScrollSpeed 其实是设置刷新频率,单位是毫秒,这个值越小,滚动速度越快。但刷新频率越高,CPU占用率越高。
TextScrollDistance 是指每次刷新移动的像素点,这个值越大,速度越快,但如果太大,文字滚动看起来就不是特别连贯。
所以在实际应用中我们需要同时调整这两个值,以找到最佳的平衡点


浙公网安备 33010602011771号