简体   繁体   English

在Compact Framework中实现新闻行情-无法平滑滚动(C#)

[英]Implementing news ticker in Compact Framework - Unable to get smooth scroll (C#)

We need a news ticker that scrolls text on a custom device running on Win CE. 我们需要一个新闻行情自动收录器,以在Win CE上运行的自定义设备上滚动文本。 We developed a control with the help of string manipulations and displaying the text on Label. 我们借助字符串操作并在Label上显示文本来开发控件。 It's working, but the scrolling is not smooth. 它正在工作,但是滚动不流畅。

At times it jumps few chars and at times cuts off before completing the scroll. 在完成滚动之前,它有时会跳几个字符,有时会中断。 Are they are any controls we can buy or any open source code that we can adopt? 它们是我们可以购买的任何控件还是我们可以采用的任何开放源代码?

Updated with code 用代码更新

while (true)
        {
            //
            if (stringBuilder.Length == 0)
                stringBuilder.Append(OrignalFullMessage);
            //
            stringBuilder = stringBuilder.Remove(0, 1);
            if (stringBuilder.Length > MAX_DISPLAY_CHARS)
            {
                eventArgs.Message = stringBuilder.ToString(0, MAX_DISPLAY_CHARS);

            }
            else
            {
                eventArgs.Message = stringBuilder.ToString().PadRight(MAX_DISPLAY_CHARS,' ');
            }

            //

            this.scrollerLabel.Invoke(new ScrollMessageUpdateHandler(WorkerUpdateHandler), this, eventArgs);
            Thread.Sleep(MESSAGE_SCROLL_DELAY);
            if (KillThread == true)
                return;

        }

We'd really need to see your scrolling and painting code, but my guess is that you're being both inefficient in your drawing and probably creating new strings with every draw operation, which is probably causing the GC to collect more frequently than is necessary. 我们确实需要查看您的滚动和绘画代码,但是我的猜测是,您的绘画效率很低,并且每次绘制操作都可能创建新的字符串,这可能导致GC收集的频率比必要的高。

Update1 UPDATE1

Yes, your code for generating the scroll text is building a whole lot of unnecessary strings. 是的,用于生成滚动文本的代码正在构建大量不必要的字符串。 Not only is this going to make the GC very busy, it's a whole lot of unnecessary string manipulation. 这不仅会使GC非常繁忙,而且还有很多不必要的字符串操作。 There are at least a couple of ways you could approach this to improve things. 至少有两种方法可以改善此状况。

First you could keep one string of the text to be drawn and then keep offsets and numbers and draw using SubString - that would decrease the amount of string objects you're creating a lot . 首先,您可以保留一个要绘制的文本字符串,然后保留偏移量和数字并使用SubString进行绘制-这样可以减少大量创建的字符串对象的数量

Second, you could draw the whole string to a Bitmap and just slide the bitmap during the scroll operation. 其次,您可以将整个字符串绘制到位图上,然后在滚动操作期间滑动位图。

using System;
using System.Drawing;
using System.Windows.Forms;
namespace MissingLink.Windows.Forms
{
public partial class ScrollingLabel : System.Windows.Forms.Control
{
    private static readonly StringFormat _strFmt = new StringFormat(StringFormatFlags.NoWrap);
    private float _txtWidth;
    private bool _needsScrolling;
    private float _x;
    private float _maxX;
    private const int _whiteSpaceLength = 40;
    private const int _updateTime = 1000;
    private const int _updateX = 5;
    private static readonly System.Threading.Timer _updateTimer = new System.Threading.Timer(ScrollText, 0, 0, 0);

    private static readonly object _updateTimerLock = new object();
    private StringFormat _nonScrollStrFmt = new StringFormat(StringFormatFlags.NoWrap);

    private static event EventHandler _updateTimerTick;

    private static event EventHandler UpdateTimerTick
    {
        add
        {
            lock(_updateTimerLock)
            {
                bool wasNull = (_updateTimerTick == null);
                _updateTimerTick += value;
                if(wasNull && (_updateTimerTick != null))
                {
                    _updateTimer.Change(0, _updateTime);
                }
            }
        }
        remove
        {
            lock(_updateTimerLock)
            {
                bool wasNull = (_updateTimerTick == null);
                _updateTimerTick -= value;
                if(wasNull && (_updateTimerTick == null))
                {
                    _updateTimer.Change(0, 0);
                }
            }
        }
    }

    public ScrollingLabel()
    {
        InitializeComponent();
    }

    private bool NeedsScrolling
    {
        get
        {
            return _needsScrolling;
        }
        set
        {
            if(_needsScrolling == value)
            {
                return;
            }
            UpdateTimerTick -= UpdateText;
            _needsScrolling = value;
            if(_needsScrolling)
            {
                UpdateTimerTick += UpdateText;
            }
        }
    }

    public StringAlignment TextAlign
    {
        get
        {
            return _nonScrollStrFmt.Alignment;
        }
        set
        {
            if(_nonScrollStrFmt.Alignment == value)
            {
                return;
            }
            _nonScrollStrFmt.Alignment = value;
            Invalidate();
        }
    }

    private void UpdateText(object sender, EventArgs e)
    {
        if(!NeedsScrolling)
        {
            return;
        }
        try
        {
            BeginInvoke((Action)(delegate
            {
                if(IsDisposed)
                {
                    return;
                }
                Invalidate();
            }));
        }
        catch { }
    }

    private static void ScrollText(object state)
    {
        EventHandler listeners = _updateTimerTick;
        if(listeners != null)
        {
            listeners(null, EventArgs.Empty);
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.Clear(BackColor);
        using(SolidBrush brush = new SolidBrush(ForeColor))
        {
            if(NeedsScrolling)
            {
                e.Graphics.DrawString(Text, Font, brush, _x, 0, _strFmt);
                e.Graphics.DrawString(Text, Font, brush, _x + _txtWidth, 0, _strFmt);
                _x -= _updateX;
                if(_x <= _maxX)
                {
                    _x = 0;
                }
            }
            else
            {
                e.Graphics.DrawString(Text, Font, brush, ClientRectangle, _nonScrollStrFmt);
            }
        }
        base.OnPaint(e);
    }

    private void UpdateNeedsScrollingFlag()
    {
        using(Graphics graphics = CreateGraphics())
        {
            float txtWidth = graphics.MeasureString(Text, Font).Width;
            if(txtWidth > Width)
            {
                NeedsScrolling = true;
                _txtWidth = txtWidth + _whiteSpaceLength;
                _maxX = _txtWidth * -1;
            }
            else
            {
                NeedsScrolling = false;
            }
        }
        _x = 0;
    }

    protected override void OnResize(EventArgs e)
    {
        UpdateNeedsScrollingFlag();
        Invalidate();

        base.OnResize(e);
    }

    protected override void OnTextChanged(EventArgs e)
    {
        UpdateNeedsScrollingFlag();
        Invalidate();

        base.OnTextChanged(e);
    }
}

} }

ex: 例如:

Form1 f = new Form1();
  ScrollingLabel sl = new ScrollingLabel();
  sl.Text = @"qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_+-={}[]|\:;'<,>.sl?/";
  sl.Dock = DockStyle.Fill;
  f.Size = new Size(100, 100);
  f.Controls.Add(sl);
  Application.Run(f);

you should print the text yourself on an owner drawn control. 您应该自己在所有者绘制的控件上打印文本。 You can then just print the text at an X position which is decremented on every timer tick instead of relying on string manipulations. 然后,您可以只在X位置打印文本,该位置在每个计时器刻度上都会递减,而不必依靠字符串操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM