[英]Implementing news ticker in Compact Framework - Unable to get smooth scroll (C#)
我们需要一个新闻行情自动收录器,以在Win CE上运行的自定义设备上滚动文本。 我们借助字符串操作并在Label上显示文本来开发控件。 它正在工作,但是滚动不流畅。
在完成滚动之前,它有时会跳几个字符,有时会中断。 它们是我们可以购买的任何控件还是我们可以采用的任何开放源代码?
用代码更新
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;
}
我们确实需要查看您的滚动和绘画代码,但是我的猜测是,您的绘画效率很低,并且每次绘制操作都可能创建新的字符串,这可能导致GC收集的频率比必要的高。
UPDATE1
是的,用于生成滚动文本的代码正在构建大量不必要的字符串。 这不仅会使GC非常繁忙,而且还有很多不必要的字符串操作。 至少有两种方法可以改善此状况。
首先,您可以保留一个要绘制的文本字符串,然后保留偏移量和数字并使用SubString进行绘制-这样可以减少大量创建的字符串对象的数量 。
其次,您可以将整个字符串绘制到位图上,然后在滚动操作期间滑动位图。
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);
}
}
}
例如:
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);
您应该自己在所有者绘制的控件上打印文本。 然后,您可以只在X位置打印文本,该位置在每个计时器刻度上都会递减,而不必依靠字符串操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.