添加项目文件。

This commit is contained in:
Administrator
2026-08-06 09:23:30 +08:00
parent 771e23e00a
commit 4660ceee70
604 changed files with 138380 additions and 0 deletions
+291
View File
@@ -0,0 +1,291 @@
using JinYuan.ControlLib.UCHelper;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace JinYuan.ControlLib
{
public partial class UCRollText : UserControl
{
private Rectangle _rectText;
private int _moveDirection = 1;
private const int DEFAULT_MOVE_STEP = 2; // 减小步长,使滚动更平滑
private const int DEFAULT_SLEEP_TIME = 20; // 减小刷新间隔,提高流畅度
private readonly SemaphoreSlim _updateLock = new SemaphoreSlim(1, 1);
private CancellationTokenSource _cts;
private volatile bool _isStop = true;
#region Properties
public override Font Font
{
get => base.Font;
set
{
base.Font = value;
UpdateTextRectangle();
}
}
public override string Text
{
get => base.Text;
set
{
base.Text = value;
UpdateTextRectangle();
}
}
private RollStyle _rollStyle = RollStyle.LeftToRight;
public RollStyle RollStyle
{
get => _rollStyle;
set
{
_rollStyle = value;
_moveDirection = value == RollStyle.RightToLeft ? -1 : 1;
ResetTextPosition();
}
}
private bool _isChangeReset;
[Description("文本改变是否重新从边缘运动"), Category("自定义")]
public bool IsChangeReset
{
get => _isChangeReset;
set => _isChangeReset = value;
}
private bool _isExit;
[Description("是否退出"), Category("自定义")]
public bool IsExit
{
get => _isExit;
set
{
_isExit = value;
if (value) StopAnimation();
}
}
private int _moveSleepTime = DEFAULT_SLEEP_TIME;
[Description("每次滚动间隔时间,越小速度越快"), Category("自定义")]
public int MoveSleepTime
{
get => _moveSleepTime;
set => _moveSleepTime = value > 0 ? value : DEFAULT_SLEEP_TIME;
}
#endregion
public UCRollText()
{
InitializeControl();
InitializeEvents();
StartAnimation();
}
private void InitializeControl()
{
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.Selectable |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserPaint, true);
DoubleBuffered = true; // 启用双缓冲,减少闪烁
Size = new Size(450, 30);
Text = "滚动文字";
ForeColor = Color.FromArgb(255, 77, 59);
}
private void InitializeEvents()
{
Load += UCRollText_Load;
SizeChanged += UCRollText_SizeChanged;
VisibleChanged += (s, e) =>
{
_isStop = !Visible;
if (Visible) StartAnimation();
};
}
private void UCRollText_SizeChanged(object sender, EventArgs e)
{
if (_rectText != Rectangle.Empty)
{
_rectText.Y = (Height - _rectText.Height) / 2 + 1;
}
}
private void UCRollText_Load(object sender, EventArgs e)
{
ResetTextPosition();
}
private async void StartAnimation()
{
if (!_isStop) return;
_isStop = false;
_cts = new CancellationTokenSource();
try
{
await Task.Run(async () =>
{
var stopwatch = new Stopwatch();
stopwatch.Start();
while (!_isStop && !_isExit)
{
try
{
var elapsed = stopwatch.ElapsedMilliseconds;
stopwatch.Restart();
await Task.Delay(MoveSleepTime, _cts.Token);
if (!IsHandleCreated || IsDisposed) continue;
await UpdateTextPositionAsync(elapsed);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
Debug.WriteLine($"Animation error: {ex.Message}");
}
}
}, _cts.Token);
}
catch (OperationCanceledException) { }
}
private void StopAnimation()
{
_isStop = true;
_cts?.Cancel();
_cts?.Dispose();
_cts = null;
}
private async Task UpdateTextPositionAsync(long elapsedMilliseconds)
{
if (_rectText == Rectangle.Empty) return;
if (_rollStyle == RollStyle.BackAndForth && _rectText.Width >= Width) return;
await _updateLock.WaitAsync();
try
{
await Task.Run(() =>
{
if (InvokeRequired)
{
BeginInvoke((MethodInvoker)(() => UpdateTextPosition(elapsedMilliseconds)));
}
else
{
UpdateTextPosition(elapsedMilliseconds);
}
});
}
finally
{
_updateLock.Release();
}
}
private void UpdateTextPosition(long elapsedMilliseconds)
{
// 根据时间调整滚动步长,确保动画平滑
int step = (int)(DEFAULT_MOVE_STEP * (elapsedMilliseconds / (double)MoveSleepTime));
_rectText.X += step * _moveDirection;
switch (_rollStyle)
{
case RollStyle.BackAndForth:
if (_rectText.X <= 0)
_moveDirection = 1;
else if (_rectText.Right >= Width)
_moveDirection = -1;
break;
case RollStyle.LeftToRight:
if (_rectText.X > Width)
_rectText.X = -_rectText.Width - 1;
break;
case RollStyle.RightToLeft:
if (_rectText.Right < 0)
_rectText.X = Width + _rectText.Width + 1;
break;
}
Invalidate();
}
private void UpdateTextRectangle()
{
if (string.IsNullOrEmpty(Text)) return;
using (var g = CreateGraphics())
{
var size = g.MeasureString(Text, Font);
_rectText = new Rectangle(
_isChangeReset ? 0 : _rectText.X,
(Height - (int)size.Height) / 2 + 1,
(int)size.Width,
(int)size.Height
);
}
}
private void ResetTextPosition()
{
if (_rectText == Rectangle.Empty) return;
switch (_rollStyle)
{
case RollStyle.LeftToRight:
_rectText.X = -_rectText.Width - 1;
break;
case RollStyle.RightToLeft:
_rectText.X = Width + _rectText.Width + 1;
break;
default:
_rectText.X = 0;
break;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (_rectText != Rectangle.Empty)
{
e.Graphics.SetGDIHigh();
using (var brush = new SolidBrush(ForeColor))
{
e.Graphics.DrawString(Text, Font, brush, _rectText.Location);
}
}
}
}
public enum RollStyle
{
LeftToRight,
RightToLeft,
BackAndForth
}
}