首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# WinForms Timer 元件實作視窗飄動特效完整教學

     編輯:關於C#

前言

System.Windows.Forms.Timer 是 WinForms 專用的**元件型定時器**,它在 **UI 執行緒** 的訊息迴圈中觸發 Tick 事件,因此可以直接安全地存取與修改 UI 控制項 (如視窗位置、標籤文字、按鈕狀態),無需呼叫 Invoke。本文將透過一個**「視窗水平飄動」**的完整範例,詳細解析 Timer 元件的屬性 (Interval, Enabled) 、事件 (Tick) 、啟動/停止方法、以及如何配合 Form.DesktopLocation 與 Point 結構實現平滑動畫效果。

Timer 元件核心特性

視窗飄動邏輯設計

  1. **初始位置**:Form_Load 設定 DesktopLocation = new Point(0, 240) (螢幕座標)。
  2. **Timer1 (向右)**:Interval=10ms,每 Tick DesktopLocation.X += 1,到達 X=550 時停止 Timer1、啟動 Timer2。
  3. **Timer2 (向左)**:Interval=10ms,每 Tick DesktopLocation.X -= 1,到達 X=-150 時停止 Timer2、啟動 Timer1。
  4. **無限循環**:兩 Timer 交替啟用,形成來回飄動。
  5. **停止按鈕**:同時 Stop() 兩個 Timer。

完整程式碼:FloatingForm 專案

using System;
using System.Drawing;
using System.Windows.Forms;

namespace FloatingFormDemo
{
    public partial class MainForm : Form
    {
        private readonly Timer _timerRight = new Timer(); // 向右飄動
        private readonly Timer _timerLeft = new Timer();  // 向左飄動
        private readonly Label _lblMessage = new Label();
        private readonly Button _btnStop = new Button();

        // 邊界常數
        private const int RIGHT_BOUND = 550;
        private const int LEFT_BOUND = -150;
        private const int TIMER_INTERVAL = 10; // 毫秒
        private const int STEP = 1;            // 每次移動像素

        public MainForm()
        {
            InitializeComponent();
            InitializeTimers();
            InitializeUI();
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.AutoScaleDimensions = new SizeF(6F, 13F);
            this.AutoScaleMode = AutoScaleMode.Font;
            this.ClientSize = new Size(352, 70);
            this.Name = "MainForm";
            this.Text = "C# Timer 飄動視窗示範";
            this.Load += MainForm_Load;
            this.ResumeLayout(false);
        }

        private void InitializeTimers()
        {
            // Timer1:向右
            _timerRight.Interval = TIMER_INTERVAL;
            _timerRight.Tick += TimerRight_Tick;

            // Timer2:向左
            _timerLeft.Interval = TIMER_INTERVAL;
            _timerLeft.Tick += TimerLeft_Tick;
        }

        private void InitializeUI()
        {
            // 標籤
            _lblMessage.Font = new Font("微軟正黑體", 14F, FontStyle.Bold, GraphicsUnit.Point);
            _lblMessage.Location = new Point(8, 38);
            _lblMessage.Size = new Size(344, 40);
            _lblMessage.Text = "C# Timer 實作視窗飄動特效!";
            _lblMessage.AutoSize = false;
            _lblMessage.TextAlign = ContentAlignment.MiddleCenter;

            // 停止按鈕
            _btnStop.Font = new Font("微軟正黑體", 10F);
            _btnStop.Location = new Point(1, 8);
            _btnStop.Size = new Size(80, 25);
            _btnStop.Text = "停止飄動";
            _btnStop.Click += BtnStop_Click;

            this.Controls.Add(_lblMessage);
            this.Controls.Add(_btnStop);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            // 設定初始位置 (螢幕座標)
            this.DesktopLocation = new Point(0, 240);

            // 啟動向右飄動
            _timerRight.Start();
        }

        /// 
        /// 向右飄動:X += 1,到達右邊界切換向左
        /// 
        private void TimerRight_Tick(object sender, EventArgs e)
        {
            Point newLoc = new Point(this.DesktopLocation.X + STEP, this.DesktopLocation.Y);
            this.DesktopLocation = newLoc;

            if (newLoc.X >= RIGHT_BOUND)
            {
                _timerRight.Stop();
                _timerLeft.Start();
            }
        }

        /// 
        /// 向左飄動:X -= 1,到達左邊界切換向右
        /// 
        private void TimerLeft_Tick(object sender, EventArgs e)
        {
            Point newLoc = new Point(this.DesktopLocation.X - STEP, this.DesktopLocation.Y);
            this.DesktopLocation = newLoc;

            if (newLoc.X <= LEFT_BOUND)
            {
                _timerLeft.Stop();
                _timerRight.Start();
            }
        }

        private void BtnStop_Click(object sender, EventArgs e)
        {
            _timerRight.Stop();
            _timerLeft.Stop();
            _btnStop.Text = "已停止";
            _btnStop.Enabled = false;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _timerRight?.Dispose();
                _timerLeft?.Dispose();
            }
            base.Dispose(disposing);
        }

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

關鍵技術細節解析

1. DesktopLocation vs Location

特性說明
命名空間System.Windows.Forms
執行緒模型**UI 執行緒** (訊息迴圈派送 WM_TIMER 訊息)
精確度約 15-55 毫秒 (受系統時鐘解析度限制),不適合高精度動畫
安全性Tick 事件在 UI 執行緒,**可直接操作 UI 控制項**
可見性設計時可見於元件托盤,**執行時不可見**
核心屬性Interval (毫秒)、Enabled (啟用/停止)
核心事件Tick (間隔到達觸發)
核心方法Start() / Stop() (等同設定 Enabled)

飄動視窗為獨立 Form,**必須使用 DesktopLocation**。

2. Point 結構運算

// 建立新位置 (不可直接修改 DesktopLocation.X,因為 Point 為實值型別)
Point newLoc = new Point(this.DesktopLocation.X + 1, this.DesktopLocation.Y);
this.DesktopLocation = newLoc; // 整體指派觸發視窗移動

3. Timer 精確度與平滑度

  • Interval=10 理論上 100 FPS,但實際受限於系統時鐘 (~15.6ms 解析度),實際約 60-65 FPS。
  • 若需更平滑動畫,建議改用:
屬性座標系用途
Location父容器客戶區 (MDI 子視窗相對父視窗)一般子控制項定位
DesktopLocation**螢幕絕對座標** (虛擬螢幕左上角為 0,0)**最上層視窗 (Form) 定位**、跨螢幕移動

4. 多螢幕與虛擬螢幕座標

  • DesktopLocation 使用**虛擬螢幕座標系**:主螢幕左上為 (0,0),次螢幕在左側則 X 為負、在上方則 Y 為負。
  • 範例中 LEFT_BOUND = -150 允許視窗部分移出主螢幕左側。
  • 取得螢幕範圍:Screen.PrimaryScreen.Bounds、Screen.AllScreens。

5. 視窗樣式優化 (可選)

若要隱藏標題列、邊框、最小化/最大化按鈕,使飄動效果更像「浮動標籤」:

this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
this.TopMost = true; // 可選:永遠置頂

擴充創意:更多飄動模式

// 1. 垂直飄動 (上下)
newLoc = new Point(loc.X, loc.Y + (goingDown ? STEP : -STEP));

// 2. 圓形軌跡
double angle = _tickCount * 0.05;
newLoc = new Point(
    centerX + (int)(radius * Math.Cos(angle)),
    centerY + (int)(radius * Math.Sin(angle))
);

// 3. 隨機漫步 (布朗運動)
newLoc = new Point(loc.X + _rd.Next(-STEP, STEP+1), loc.Y + _rd.Next(-STEP, STEP+1));
// 配合邊界檢查 Math.Clamp

// 4. 跟隨滑鼠 (延遲跟隨)
Point mouse = Cursor.Position;
newLoc = new Point(
    loc.X + (int)((mouse.X - loc.X) * 0.1),
    loc.Y + (int)((mouse.Y - loc.Y) * 0.1)
);

常見問題與除錯

方案優點缺點
System.Windows.Forms.TimerUI 安全、簡單精度低、佔用 UI 執行緒
WPF DispatcherTimer + 動畫硬體加速、插值平滑需 WPF 專案
WinForms + System.Threading.Timer + BeginInvoke背景執行緒計算、UI 執行緒只更新需手動同步、複雜
Direct2D / SharpDX / SkiaSharp最高效能、GPU 加速學習曲線陡峭

總結

System.Windows.Forms.Timer 是 WinForms 中最簡單、最安全的 UI 定時器。本文透過「視窗水平飄動」範例,完整展示了:Interval/Enabled/Tick 核心用法、DesktopLocation + Point 視窗定位技巧、兩 Timer 交替啟用實現來回動畫、Dispose 釋放資源。掌握這些基礎後,可輕鬆擴充至垂直飄動、圓形軌跡、隨機漫步、滑鼠跟隨等豐富動畫效果,為應用程式增添生動互動體驗。進階需求請考慮 WPF 動畫系統或 GPU 加速繪圖庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因解決
視窗不移動Timer 未 Start、Interval=0、Tick 未訂閱檢查 InitializeTimers、MainForm_Load 中 Start()
視窗閃爍/抖動Interval 太小、UI 執行緒忙碌、雙重繪製調大 Interval (50-100ms)、啟用 DoubleBuffered、減少控制項
視窗飛出螢幕找不回邊界常數設錯、多螢幕座標誤解加入螢幕邊界檢查、提供「重置位置」按鈕
關閉視窗後程式未結束Timer 未 Dispose、背景執行緒殘留Override Dispose 呼叫 timer.Dispose()