221 lines
8.5 KiB
C#
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;
|
|
}
|
|
}
|