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

C# 圖形開發基礎入門:打造橢圓按鈕控件

     編輯:關於C#

前言:從零開始的圖形控件開發之旅

在掌握 Windows 圖形子系統基本原理後,本講將引導大家完成第一個實戰專案——橢圓形按鈕控件。這個看似簡單的專案其實涵蓋了自訂控件開發的完整流程:繪製邏輯、滑鼠互動狀態機、事件觸發、座標點擊測試等核心技術,是進入 C# 圖形開發大門的最佳敲門磚。

需求分析與設計規劃

功能規格

  • 呈現橢圓外觀,置中顯示單行文字
  • 滑鼠進入/離開時邊框與背景色動態變化
  • 點擊橢圓區域內觸發 Click 事件

架構決策

  • 繼承 UserControl,封裝為可重用元件
  • 覆寫 OnPaint 負責所有繪製
  • 覆寫 OnMouseMove、OnMouseEnter、OnMouseLeave 處理懸停狀態
  • 覆寫 OnClick 實作橢圓區域點擊測試

核心程式碼逐節解析

1. 繪製邏輯:OnPaint 深度剖析

protected override void OnPaint(PaintEventArgs e) {
    base.OnPaint(e);
    // 1. 建立橢圓路徑(GraphicsPath 可組合多條曲線/直線)
    using (GraphicsPath path = new GraphicsPath()) {
        // 外接矩形即控件客戶區
        path.AddEllipse(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
        // 2. 填充背景(先填再畫框,避免邊框被覆蓋)
        using (SolidBrush brush = new SolidBrush(
            bolMouseHoverFlag ? this.HoverBackColor : this.ButtonBackColor)) {
            e.Graphics.FillPath(brush, path);
        }
        // 3. 繪製邊框
        using (Pen pen = new Pen(
            bolMouseHoverFlag ? this.HoverBorderColor : this.BorderColor, 2)) {
            e.Graphics.DrawPath(pen, path);
        }
    }
    // 4. 繪製置中文字
    if (this.Caption != null) {
        using (StringFormat fmt = new StringFormat()) {
            fmt.Alignment = StringAlignment.Center;       // 水平置中
            fmt.LineAlignment = StringAlignment.Center;   // 垂直置中
            fmt.FormatFlags = StringFormatFlags.NoWrap;   // 單行不換行
            using (SolidBrush brush = new SolidBrush(this.ForeColor)) {
                e.Graphics.DrawString(this.Caption, this.Font, brush,
                    new RectangleF(0, 0, this.ClientSize.Width, this.ClientSize.Height), fmt);
            }
        }
    }
}

關鍵知識點:

  • GraphicsPath:矢量圖形路徑容器,支援 AddEllipse、AddRectangle、AddCurve 等,可重複使用於填充與描邊
  • ClientSize vs Size:前者為可繪製客戶區(扣除邊框),後者為控件整體大小;繪圖務必使用 ClientSize
  • 繪圖順序:先填充再描邊,否則邊框會被填充覆蓋
  • using 區塊:Pen、Brush、GraphicsPath 實作 IDisposable,包含非託管 GDI+ 資源,必須及時釋放
  • StringFormat 控制文字對齊、換行、截斷等排版行為

2. 懸停偵測:幾何點擊測試

private bool CheckMouseHover(int x, int y) {
    using (GraphicsPath path = new GraphicsPath()) {
        path.AddEllipse(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
        bool hit = path.IsVisible(x, y); // 核心:路徑幾何包含性測試
        if (hit != bolMouseHoverFlag) {
            bolMouseHoverFlag = hit;
            this.Invalidate(); // 標記需重繪(非同步,效能較好)
            // this.Refresh();  // 強制立即重繪(同步,特殊情況才用)
        }
        return hit;
    }
}

GraphicsPath.IsVisible 直接利用 GDI+ 幾何引擎判斷點是否在路徑內,避免手寫橢圓方程式。Invalidate() 與 Refresh() 差異在於前者發送 WM_PAINT 訊息由訊息迴圈稍後處理(非同步),後者直接呼叫 UpdateWindow 同步重繪;一般 UI 互動用 Invalidate 即可。

3. 滑鼠事件鏈

protected override void OnMouseMove(MouseEventArgs e) {
    base.OnMouseMove(e);
    CheckMouseHover(e.X, e.Y); // 即時檢測
}

protected override void OnMouseLeave(EventArgs e) {
    base.OnMouseLeave(e);
    if (bolMouseHoverFlag) { bolMouseHoverFlag = false; this.Invalidate(); }
}

4. 點擊事件:精準區域判斷

protected override void OnClick(EventArgs e) {
    // base.OnClick(e); // 暫不呼叫基類
    Point screenPt = Control.MousePosition;        // 螢幕絕對座標
    Point clientPt = this.PointToClient(screenPt); // 轉為控件客戶區座標
    if (CheckMouseHover(clientPt.X, clientPt.Y)) {
        base.OnClick(e); // 僅在橢圓內才觸發 Click 事件
    }
}

因 OnClick 事件參數不含座標,需自行透過 Control.MousePosition + PointToClient 取得點擊位置,再複用 CheckMouseHover 判斷。

測試與部署

  1. 編譯專案 → 工具箱「我的使用者控件」自動出現 EllipseButton
  2. 拖曳至表單,屬性視窗設定 Caption、顏色屬性
  3. 事件頁面雙擊 Click 加入測試碼(如 MessageBox.Show)
  4. 執行驗證:懸停變色、點擊彈窗、離開還原
  5. 專案屬性 → 輸出類型改為「類別庫」 → 重新建置 → 產出 DLL 交付

圖形開發的效能與體驗考量

文章特別提到:人眼對畫面變化極其敏感(可感知數十毫秒延遲),因此圖形程式碼執行速度要求極高。.NET 圖形類庫雖封裝了 GDI+,但底層仍大量呼叫 Win32 API(InvalidateRect、UpdateWindow 等),深入掌握圖形開發需對 Windows 訊息機制與 GDI+ 管線有基本認知。

本講總結與延伸挑戰

本講完成了首個具備動態視覺回饋的圖形控件,涵蓋:

  • GraphicsPath 建構複雜幾何形狀
  • FillPath/DrawPath 矢量繪製流程
  • 幾何點擊測試(IsVisible)
  • 滑鼠狀態機與 Invalidate/Refresh 差異
  • 座標系統轉換(螢幕→客戶區)

課後挑戰:嘗試在本專案基礎上實作「三角形按鈕」,提示:GraphicsPath.AddPolygon 配合三個頂點即可。下一講我們將挑戰資料網格控件,引入文檔-視圖架構、捲動虛擬化與多重選取邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved