[英]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.