Winform 下无闪烁走马灯效果实现

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 系统中,两种设置的效果似乎没有太多区别。在一个国外网站上找到他们的区别,下面是原文:

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);
            }
    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();
        }
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();
        }
    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;
            }
        }
下面给出ä¿æ”¹åŽåŒæ•´çš„控件代码,代码原作者为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;                    // 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#region Component Designer generated code
        /**//// <summary>
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            //ScrollingText            
            this.Name = "ScrollingText";
            this.Size = new System.Drawing.Size(216, 40);
            this.Click += new System.EventHandler(this.ScrollingText_Click);                    
        }
        #endregion
    
        //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#region Mouse over, text link logic
        private void EnableTextLink(RectangleF textRect)
        {
            Point curPt = this.PointToClient(Cursor.Position);

            //if (curPt.X > textRect.Left && curPt.X < textRect.Right
            //    && curPt.Y > textRect.Top && curPt.Y < textRect.Bottom)            
            if (textRect.Contains(curPt))
            {
                //Stop the text of the user mouse''s over the text
                if (stopScrollOnMouseOver)
                    scrollOn = false;                

                this.Cursor = Cursors.Hand;                                    
            }
            else
            {
                //Make sure the text is scrolling if user''s mouse is not over the text
                scrollOn = true;
                
                this.Cursor = Cursors.Default;
            }
        }        

        private void ScrollingText_Click(object sender, System.EventArgs e)
        {
            //Trigger the text clicked event if the user clicks while the mouse 
            //is over the text.  This allows the text to act like a hyperlink
            if (this.Cursor == Cursors.Hand)
                OnTextClicked(this, new EventArgs());
        }

        public delegate void TextClickEventHandler(object sender, EventArgs args);    
        public event TextClickEventHandler TextClicked;

        private void OnTextClicked(object sender, EventArgs args)
        {
            //Call the delegate
            if (TextClicked != null)
                TextClicked(sender, args);
        }
        #endregion
        

        Properties#region Properties
        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("The timer interval that determines how often the control is repainted")
        ]
        public int TextScrollSpeed
        {
            set
            {
                timer.Interval = value;
            }
            get
            {
                return timer.Interval;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("How many pixels will the text be moved per Paint")
        ]
        public int TextScrollDistance
        {
            set
            {
                scrollPixelDistance = value;
            }
            get
            {
                return scrollPixelDistance;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("The text that will scroll accros the control")
        ]
        public string ScrollText
        {
            set
            {
                text = value;
                this.Invalidate();
                this.Update();
            }
            get
            {
                return text;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("What direction the text will scroll: Left to Right, Right to Left, or Bouncing")
        ]
        public ScrollDirection ScrollDirection
        {
            set
            {
                scrollDirection = value;
            }
            get
            {
                return scrollDirection;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("The verticle alignment of the text")
        ]
        public VerticleTextPosition VerticleTextPosition
        {
            set
            {
                verticleTextPosition = value;
            }
            get
            {
                return verticleTextPosition;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("Turns the border on or off")
        ]
        public bool ShowBorder
        {
            set
            {
                showBorder = value;
            }
            get
            {
                return showBorder;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("The color of the border")
        ]
        public Color BorderColor
        {
            set
            {
                borderColor = value;
            }
            get
            {
                return borderColor;
            }
        }

        [
        Browsable(true),
        CategoryAttribute("Scrolling Text"),
        Description("Determines if the text will stop scrolling if the user''s mouse moves over the text")
        ]
        public bool StopScrollOnMouseOver
        {
            set
            {
                stopScrollOnMouseOver = value;
            }
            get
            {
                return stopScrollOnMouseOver;
            }
        }

        [
        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(false)
        ]
        public Brush ForegroundBrush
        {
            set
            {
                foregroundBrush = value;
            }
            get
            {
                return foregroundBrush;
            }
        }
        
        [
        ReadOnly(true)
        ]
        public Brush BackgroundBrush
        {
            set
            {
                backgroundBrush = value;
            }
            get
            {
                return backgroundBrush;
            }
        }
        #endregion        
    }

    public enum ScrollDirection
    {
        RightToLeft,
        LeftToRight,
        Bouncing
    }

    public enum VerticleTextPosition
    {
        Top,
        Center,
        Botom
    }
}

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

 

时间: 2024-08-04 11:12:28

Winform 下无闪烁走马灯效果实现的相关文章

Winform下无闪烁走马灯效果实现

最近需要在Winform项目中实现一个走马灯的效果,一开始用了一些办法比如移动Label控件,效果总是不太好,移动文本时总有闪烁的现象.后来找了一个国外的开源控件,应用了一下,效果还不错.仔细阅读了一下代码,发现还有一些地方值得改进,现把代码以及改动说明贴出来,和大家分享. 控件出处:http://www.codeproject.com/KB/miscctrl/ScrollingTextControlArtic.aspx 我的改动: 1.DoubleBuffer 的设置 原代码中用的是 this

javascript-jquery为动态插入的checkbox绑定事件在IE8下无效果

问题描述 jquery为动态插入的checkbox绑定事件在IE8下无效果 //obj是checkbox对象,这些checkbox都是通过js方法动态插入html的 obj.click(function(){ var valueStr=""; var nameStr=""; // initObjs是所有的checkbox对象集合 initObjs.filter(":checkbox[name='"+name+"']:checked&qu

《HTML5 开发实例大全》——1.7 实现下拉弹出效果

1.7 实现下拉弹出效果 实例说明 在本实例中,首先在页面中显示一行提问文本"需要在线咨询吗?".当单击左侧的小三角符号后,将在下方无刷新弹出一个下拉区域,在里面显示文本"非常"需要.上述描述效果在很多动态网站中比较常见,原来一般都是用JavaScript技术或Ajax技术实现的.但现在只需使用HTML 5中的< details >标记元素即可实现完全同样的功能. 具体实现 使用Dreamweaver创建一个名为"007.html"的

Ajax实现无闪烁定时刷新页面实例代码_AJAX相关

在Web开发中我们经常需要实现定时刷新某个页面: 1.来保持session的值或者检查session的值是否为空(比如说防止同一用户重复登录): 2.实现实时站内短信: 3.定时更新页面数据等等.但是我们在网上搜搜会发现有很多定时刷新页面的方法,最简单的就是在<head></head>标记之间加上如下代码: 在<head></head>标记之间加上代码,实现定时刷新,此代码我已经测试过,可以实现效果 <meta http-equiv="ref

jQuery实现图片走马灯效果的原理分析_jquery

本文实例分析了jQuery实现图片走马灯效果的原理.分享给大家供大家参考,具体如下: 这里只讲解水平走马灯效果,垂直向上走马灯效果不讲解,原理一样,但是水平走马灯效果有一个小坑.待会讲解 先上代码: HTML: <div class="box"> <div style="width: 1000px;" id="boxdiv"> <ul> <li style="display: block;&qu

winform 下HttpWebRequest 和xmlhttp去下载网页.哪个好?

问题描述 希望从各方面说说. 解决方案 解决方案二:httpwebrequest是.netframework中的方法,支持Cookies,Session等,这个我用过Microsoft.XMLHTTP是一个独立的组件,可以在js等各种语言里调用,这个没太用过就不评论了.如果你想用httpwebrequest的话,我这有封装好的类库和源代码,简化了很多操作http://blog.zhaoyu.me/archives/142.shtmlHTTPRequestrequest=newHTTPReques

初次使用C#做项目,请问WinForm下将项目分解成多个DLL,这样是不是能节约内存啊!

问题描述 是这样的,小弟在做一个C#项目项目,WinForm的,原来打算在进入系统的时候使用ListView组件,本来打算每点击一个ListView项目,弹出一个操作窗口,进行相应的操作,一共有50多个项目,小弟我设计了50个窗体文件,进行静态编译成一个项目后,发现占用了很多内存,现在我想问:1)如果我做成50个DLL(DLL也是C#开发的托管的那种)来封装相应的窗体操作,这样在启动项目之后,当我点击ListView条目的时候从DLL文件中寻找,我想问的是,这样会不会节约我的内存占用?2)这样做

简单实现Ajax无刷新分页效果

Ajax无刷新分页效果,如下代码实现 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax无刷新分页效果</title> <script type="text/javascript"> function showpage(url) { var xhr = new XML

Ajax实现无闪烁定时刷新页面实例代码

在Web开发中我们经常需要实现定时刷新某个页面: 1.来保持session的值或者检查session的值是否为空(比如说防止同一用户重复登录): 2.实现实时站内短信: 3.定时更新页面数据等等.但是我们在网上搜搜会发现有很多定时刷新页面的方法,最简单的就是在<head></head>标记之间加上如下代码: 在<head></head>标记之间加上代码,实现定时刷新,此代码我已经测试过,可以实现效果 <meta http-equiv="ref