我们需要一个新闻自动收录器,用于在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;
}
答案 0 :(得分:1)
我们真的需要看看你的滚动和绘画代码,但我的猜测是你在绘图中既低效又可能在每次绘制操作时创建新的字符串,这可能导致GC更频繁地收集比必要的。
<强> UPDATE1 强>
是的,用于生成滚动文本的代码正在构建大量不必要的字符串。这不仅会使GC非常繁忙,而且还会进行大量不必要的字符串操作。至少有几种方法可以解决这个问题。
首先,您可以保留要绘制的文本的一个字符串,然后保留偏移量和数字并使用SubString绘制 - 这将减少您创建批次的字符串对象的数量。
其次,您可以将整个字符串绘制到位图,只需在滚动操作期间滑动位图。
答案 1 :(得分:1)
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);
}
}
}
e.x:
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);
答案 2 :(得分:0)
您应该在拥有者绘制的控件上自行打印文本。然后,您可以在X位置打印文本,该位置在每个计时器滴答时递减,而不是依赖于字符串操作。