LoadingScreen.cs 12.6 KB
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;

namespace SmartScan.SetControl.WPF.Model
{
    public class LoadingScreen
    {
        #region 单例实现
        private static LoadingScreen _instance;
        private static readonly object _lock = new object();
        /// <summary>
        /// 获取LoadingScreen实例
        /// </summary>
        public static LoadingScreen Instance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                        _instance = new LoadingScreen();
                    return _instance;
                }
            }
        }
        #endregion
        #region 私有成员
        private LoadingForm _loadingForm;
        private Thread _loadingThread;
        private bool _isShowing;
        #endregion
        #region 构造函数
        private LoadingScreen()
        {
            _isShowing = false;
        }
        #endregion
        #region 公共方法
        /// <summary>
        /// 显示加载界面
        /// </summary>
        /// <param name="message">主提示信息</param>
        /// <param name="subMessage">副提示信息</param>
        /// <param name="ownerForm">父窗体(可选)</param>
        public void Show(string message = "请稍后...", string subMessage = "加载中...", System.Windows.Forms.Form ownerForm = null)
        {
            if (_isShowing)
            {
                // 如果已经在显示,则只更新消息
                UpdateStatus(message, subMessage);
                return;
            }
            _isShowing = true;
            // 在新线程中创建并显示加载界面
            _loadingThread = new Thread(() =>
            {
                _loadingForm = new LoadingForm();
                if (ownerForm != null && !ownerForm.IsDisposed)
                {
                    // 如果提供了父窗体,则使加载界面相对于父窗体居中
                    _loadingForm.StartPosition = FormStartPosition.Manual;
                    int x = ownerForm.Location.X + (ownerForm.Width - _loadingForm.Width) / 2;
                    int y = ownerForm.Location.Y + (ownerForm.Height - _loadingForm.Height) / 2;
                    _loadingForm.Location = new Point(x, y);
                    _loadingForm.Size = ownerForm.Size;
                    _loadingForm.TopMost = true;
                }
                // 初始化消息
                _loadingForm.UpdateStatus(message, subMessage);

                // 显示窗体,开始消息循环
                Application.Run(_loadingForm);
            });
            _loadingThread.IsBackground = true;
            _loadingThread.SetApartmentState(ApartmentState.STA);
            _loadingThread.Start();
        }
        /// <summary>
        /// 关闭加载界面
        /// </summary>
        public void Hide()
        {
            if (!_isShowing)
                return;
            if (_loadingForm != null)
            {
                _loadingForm.CloseLoading();
                _loadingForm = null;
            }
            _isShowing = false;
        }
        /// <summary>
        /// 更新加载界面的状态信息
        /// </summary>
        /// <param name="message">主提示信息</param>
        /// <param name="subMessage">副提示信息(可选)</param>
        public void UpdateStatus(string message, string subMessage = null)
        {
            if (_loadingForm != null && _isShowing)
            {
                _loadingForm.UpdateStatus(message, subMessage);
            }
        }
        /// <summary>
        /// 检查加载界面是否正在显示
        /// </summary>
        public bool IsShowing
        {
            get { return _isShowing; }
        }
        #endregion
        #region 内部加载窗体类
        /// <summary>
        /// 内部加载窗体实现
        /// </summary>
        private class LoadingForm :System.Windows.Forms. Form
        {
            #region 私有成员
            private Timer _animationTimer;
            private int _currentFrame = 0;
            private const int TOTAL_DOTS = 8;
            private int _dotSize = 10;
            private int _dotRadius = 30;
            private Color[] _dotColors;
            private Label _statusLabel;
            private Label _subStatusLabel;
            private Panel _contentPanel;
            #endregion
            #region 构造函数
            public LoadingForm()
            {
                InitializeForm();
                SetupAnimationTimer();
                SetupDotColors();
            }
            #endregion
            #region 初始化方法
            private void InitializeForm()
            {
                // 设置窗体属性
                this.BackColor = Color.FromArgb(15, 15, 15);
                this.FormBorderStyle = FormBorderStyle.None;
                this.Size = new Size(500, 300);
                this.StartPosition = FormStartPosition.CenterScreen;
                this.Text = "NEO SCAN";
                this.ShowInTaskbar = false;
                this.TopMost = true;
                // 创建内容面板
                _contentPanel = new Panel
                {
                    Dock = DockStyle.Fill,
                    BackColor = Color.Transparent
                };
                this.Controls.Add(_contentPanel);
                // 创建标题标签
                Label titleLabel = new Label
                {
                    Text = "NEO SCAN",
                    ForeColor = Color.FromArgb(0, 174, 239), // 亮蓝色 #00AEEF
                    Font = new Font("Segoe UI", 20, FontStyle.Bold),
                    AutoSize = true,
                    Location = new Point(50, 20),
                    BackColor = Color.Transparent
                };
                _contentPanel.Controls.Add(titleLabel);
                // 添加左上角图标
                PictureBox iconBox = new PictureBox
                {
                    Size = new Size(24, 24),
                    Location = new Point(20, 25),
                    BackColor = Color.Transparent
                };
                iconBox.Paint += (s, e) => DrawNeoIcon(e.Graphics);
                _contentPanel.Controls.Add(iconBox);
                // 添加状态标签
                _statusLabel = new Label
                {
                    Text = "请稍后...",
                    ForeColor = Color.White,
                    Font = new Font("Microsoft YaHei UI", 14, FontStyle.Regular),
                    AutoSize = false,
                    Size = new Size(300, 30),
                    TextAlign = ContentAlignment.MiddleCenter,
                    BackColor = Color.Transparent
                };
                // 添加子状态标签
                _subStatusLabel = new Label
                {
                    Text = "加载中...",
                    ForeColor = Color.White,
                    Font = new Font("Microsoft YaHei UI", 12, FontStyle.Regular),
                    AutoSize = false,
                    Size = new Size(300, 25),
                    TextAlign = ContentAlignment.MiddleCenter,
                    BackColor = Color.Transparent
                };
                // 窗体尺寸变化时重新定位控件
                this.Resize += (s, e) => RepositionControls();
                RepositionControls();
                // 双击关闭窗体 (调试用)
                this.DoubleClick += (s, e) => this.CloseLoading();
            }
            private void DrawNeoIcon(Graphics g)
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                using (GraphicsPath path = new GraphicsPath())
                {
                    path.AddEllipse(2, 2, 20, 20);
                    using (Pen pen = new Pen(Color.FromArgb(0, 174, 239), 2))
                    {
                        g.DrawPath(pen, path);
                    }
                }
                g.FillEllipse(Brushes.White, 7, 7, 4, 4);
                g.FillEllipse(Brushes.White, 14, 7, 4, 4);
            }
            private void SetupAnimationTimer()
            {
                // 创建并启动动画计时器
                _animationTimer = new Timer
                {
                    Interval = 100  // 100毫秒/帧
                };
                _animationTimer.Tick += AnimationTimer_Tick;
                _animationTimer.Start();
            }
            private void SetupDotColors()
            {
                // 设置点的颜色
                _dotColors = new Color[TOTAL_DOTS];
                for (int i = 0; i < TOTAL_DOTS; i++)
                {
                    if (i == 0)
                        _dotColors[i] = Color.FromArgb(0, 174, 239); // 高亮点 - 蓝色 #00AEEF
                    else
                        _dotColors[i] = Color.FromArgb(150, 150, 150); // 其他点 - 灰色
                }
            }
            #endregion
            #region 事件处理
            private void AnimationTimer_Tick(object sender, EventArgs e)
            {
                // 更新帧并重绘
                _currentFrame = (_currentFrame + 1) % TOTAL_DOTS;

                // 更新点的颜色
                for (int i = 0; i < TOTAL_DOTS; i++)
                {
                    if (i == _currentFrame)
                        _dotColors[i] = Color.FromArgb(0, 174, 239); // 高亮点 - 蓝色
                    else if (i == (_currentFrame + 1) % TOTAL_DOTS || i == (_currentFrame - 1 + TOTAL_DOTS) % TOTAL_DOTS)
                        _dotColors[i] = Color.White; // 相邻点 - 白色
                    else
                        _dotColors[i] = Color.FromArgb(100, 100, 100); // 其他点 - 深灰色
                }

                this.Invalidate(); // 触发重绘
            }
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);

                // 绘制加载动画
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

                // 计算加载环的位置
                int centerX = this.ClientSize.Width / 2;
                int centerY = this.ClientSize.Height / 2;

                for (int i = 0; i < TOTAL_DOTS; i++)
                {
                    // 计算每个点的位置
                    double angle = 2 * Math.PI * i / TOTAL_DOTS;
                    int x = centerX + (int)(Math.Cos(angle) * _dotRadius);
                    int y = centerY + (int)(Math.Sin(angle) * _dotRadius);

                    // 绘制点
                    using (SolidBrush brush = new SolidBrush(_dotColors[i]))
                    {
                        e.Graphics.FillEllipse(brush, x - _dotSize / 2, y - _dotSize / 2, _dotSize, _dotSize);
                    }
                }
            }
            private void RepositionControls()
            {
                // 重新计算和定位控件
                int centerX = this.ClientSize.Width / 2;
                int centerY = this.ClientSize.Height / 2;

                _statusLabel.Location = new Point(centerX - _statusLabel.Width / 2, centerY + _dotRadius + 30);
                _subStatusLabel.Location = new Point(centerX - _subStatusLabel.Width / 2, centerY + _dotRadius + 60);

                if (!_contentPanel.Controls.Contains(_statusLabel))
                    _contentPanel.Controls.Add(_statusLabel);

                if (!_contentPanel.Controls.Contains(_subStatusLabel))
                    _contentPanel.Controls.Add(_subStatusLabel);
            }
            #endregion
            #region 公共方法
            /// <summary>
            /// 更新状态文本
            /// </summary>
            public void UpdateStatus(string mainStatus, string subStatus = null)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke(new Action(() => UpdateStatus(mainStatus, subStatus)));
                    return;
                }
                _statusLabel.Text = mainStatus;

                if (subStatus != null)
                    _subStatusLabel.Text = subStatus;
            }
            /// <summary>
            /// 关闭加载窗体
            /// </summary>
            public void CloseLoading()
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke(new Action(CloseLoading));
                    return;
                }
                _animationTimer.Stop();
                this.Close();
            }
            #endregion
        }
        #endregion
    }
}