Files
aiData/WordAddIn/WordAddIn/LoadingForm.cs
HuangHai 8aa397cea7 'commit'
2026-01-28 21:46:06 +08:00

221 lines
8.5 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace WordAddIn
{
/// <summary>
/// 加载动画窗体。
/// 功能描述:
/// 1. 在执行耗时操作(如 AI 生成)时显示,阻断用户界面。
/// 2. 使用 GDI+ 自定义绘制旋转动画 (Spinner)。
/// 3. 支持跨线程安全关闭。
/// </summary>
public class LoadingForm : Form
{
private System.Windows.Forms.Label lblMessage;
private System.Windows.Forms.RichTextBox txtProgress;
private System.Windows.Forms.Timer animationTimer;
private System.ComponentModel.IContainer components;
private int _spinnerAngle = 0;
private const int SPINNER_SIZE = 60;
// 现代化配色
private readonly Color _primaryColor = Color.FromArgb(43, 87, 154); // Word Blue
private readonly Color _backgroundColor = Color.White;
private readonly Color _borderColor = Color.FromArgb(100, 100, 100);
/// <summary>
/// 构造函数。
/// </summary>
/// <param name="message">加载时显示的提示文字</param>
public LoadingForm(string message = "AI 正在思考中...")
{
InitializeComponent();
lblMessage.Text = message;
// 开启双缓冲以减少闪烁
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
this.UpdateStyles();
}
/// <summary>
/// 初始化窗体组件。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.lblMessage = new System.Windows.Forms.Label();
this.txtProgress = new System.Windows.Forms.RichTextBox();
this.animationTimer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// lblMessage
//
this.lblMessage.BackColor = System.Drawing.Color.Transparent;
this.lblMessage.Dock = System.Windows.Forms.DockStyle.None;
this.lblMessage.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.lblMessage.Location = new System.Drawing.Point(0, 150);
this.lblMessage.Name = "lblMessage";
this.lblMessage.Size = new System.Drawing.Size(500, 30);
this.lblMessage.TabIndex = 0;
this.lblMessage.Text = "AI 正在思考中...";
this.lblMessage.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// txtProgress
//
this.txtProgress.BackColor = System.Drawing.Color.White;
this.txtProgress.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.txtProgress.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtProgress.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.txtProgress.Location = new System.Drawing.Point(40, 190);
this.txtProgress.Name = "txtProgress";
this.txtProgress.ReadOnly = true;
this.txtProgress.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
this.txtProgress.Size = new System.Drawing.Size(420, 190);
this.txtProgress.TabIndex = 1;
this.txtProgress.Text = "";
//
// animationTimer
//
this.animationTimer.Enabled = true;
this.animationTimer.Interval = 30;
this.animationTimer.Tick += new System.EventHandler(this.AnimationTimer_Tick);
//
// LoadingForm
//
// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(500, 400);
this.Controls.Add(this.txtProgress);
this.Controls.Add(this.lblMessage);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "LoadingForm";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "AI助手";
this.TopMost = true;
this.ResumeLayout(false);
}
/// <summary>
/// 动画定时器触发事件。更新旋转角度并重绘。
/// </summary>
private void AnimationTimer_Tick(object sender, EventArgs e)
{
_spinnerAngle = (_spinnerAngle + 10) % 360;
this.Invalidate(); // 触发重绘
}
/// <summary>
/// 重写绘制事件,自定义绘制加载动画。
/// </summary>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
// 1. 绘制边框
using (Pen borderPen = new Pen(_borderColor, 2))
{
g.DrawRectangle(borderPen, 0, 0, this.Width - 1, this.Height - 1);
}
// 2. 绘制 Spinner (中心位置)
int centerX = this.Width / 2;
int centerY = 100; // 居中
g.TranslateTransform(centerX, centerY);
g.RotateTransform(_spinnerAngle);
// 绘制一个渐变的圆环或一串圆点
// 这里我们画 8 个圆点,透明度渐变
int dotCount = 10;
int radius = SPINNER_SIZE / 2;
int dotSize = 6;
for (int i = 0; i < dotCount; i++)
{
// 计算每个点的透明度 (0-255)
// 使得看起来像是有拖尾
int alpha = 255 * (i + 1) / dotCount;
using (Brush brush = new SolidBrush(Color.FromArgb(alpha, _primaryColor)))
{
// 保存当前状态
var state = g.Save();
// 旋转到对应角度
float angle = 360f / dotCount * i;
g.RotateTransform(angle);
// 在半径处画圆点
g.FillEllipse(brush, radius - dotSize, -dotSize / 2, dotSize, dotSize);
// 恢复状态
g.Restore(state);
}
}
g.ResetTransform();
}
/// <summary>
/// 线程安全的关闭方法。
/// 允许从非 UI 线程调用。
/// </summary>
public void UpdateProgress(string content)
{
if (this.IsDisposed) return;
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(UpdateProgress), content);
}
else
{
this.txtProgress.AppendText(content);
this.txtProgress.ScrollToCaret();
}
}
public void CloseSafe()
{
if (this.IsDisposed) return;
if (this.InvokeRequired)
{
this.Invoke(new Action(CloseSafe));
}
else
{
animationTimer.Stop();
this.Close();
}
}
/// <summary>
/// 支持鼠标拖动无边框窗体。
/// </summary>
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
}
}