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

C# 製作不規則形狀按鈕:依圖片透明區域裁剪 Button 可點擊範圍

     編輯:關於C語言

核心原理

Windows Forms 控制項的 Region 屬性決定其可見與可點擊區域。透過掃描圖片像素,建立由不透明像素組成的 GraphicsPath,指派給 Button.Region,即可實現任意不規則形狀按鈕。

完整實作碼

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

public class IrregularButton : Button
{
    protected override void OnPaint(PaintEventArgs pevent)
    {
        base.OnPaint(pevent);
        this.Cursor = Cursors.Hand;

        if (this.Image == null) return;

        using (Bitmap bmp = new Bitmap(this.Image))
        using (GraphicsPath path = CalculateControlGraphicsPath(bmp))
        {
            this.Region = new Region(path);
        }
    }

    private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)
    {
        var path = new GraphicsPath();
        Color transparentColor = bitmap.GetPixel(0, 0); // 假設左上角為透明色

        for (int y = 0; y < bitmap.Height; y++)
        {
            int xStart = -1;

            for (int x = 0; x < bitmap.Width; x++)
            {
                bool isOpaque = bitmap.GetPixel(x, y) != transparentColor;

                if (isOpaque && xStart == -1)
                {
                    xStart = x; // 找到不透明區段起點
                }
                else if (!isOpaque && xStart != -1)
                {
                    // 區段結束,加入矩形
                    path.AddRectangle(new Rectangle(xStart, y, x - xStart, 1));
                    xStart = -1;
                }
            }

            // 行尾仍在不透明區段
            if (xStart != -1)
            {
                path.AddRectangle(new Rectangle(xStart, y, bitmap.Width - xStart, 1));
            }
        }

        return path;
    }
}

使用方式

  1. 準備 PNG 圖片,背景為透明,前景為按鈕形狀。
  2. 表單上放置一般 Button,設定 Image 屬性指向該圖片,Text 留空,FlatStyle = Flat、FlatAppearance.BorderSize = 0。
  3. 將按鈕類別改為 IrregularButton(或在 Paint 事件掛上述邏輯)。

效能優化建議

  • 快取 GraphicsPath: 圖片不變時,Region 只需建立一次。可在 Image 屬性變更時重算,OnPaint 僅指派快取結果。
  • LockBits 取代 GetPixel: 大圖片時 GetPixel 極慢,應用 Bitmap.LockBits 直接存取記憶體像素資料,速度提升百倍。
  • 預先計算: 設計階段即產生 .region 檔或序列化路徑資料,執行期直接反序列化。

LockBits 高速版核心邏輯


private static GraphicsPath CalculatePathFast(Bitmap bmp)
{
    var path = new GraphicsPath();
    var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    var data = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
    try
    {
        unsafe
        {
            byte* ptr = (byte*)data.Scan0;
            int bytesPerPixel = Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
            int stride = data.Stride;
            byte alphaThreshold = 0; // 完全透明

            for (int y = 0; y < bmp.Height; y++)
            {
                byte* row = ptr + y * stride;
                int xStart = -1;

                for (int x = 0; x < bmp.Width; x++)
                {
                    byte alpha = row[x * bytesPerPixel + 3]; // ARGB 第 4 位元組
                    bool opaque = alpha > alphaThreshold;

                    if (opaque && xStart == -1) xStart = x;
                    else if (!opaque && xStart != -1)
                    {
                        path.AddRectangle(new Rectangle(xStart, y, x - xStart, 1));
                        xStart = -1;
                    }
                }
                if (xStart != -1) path.AddRectangle(new Rectangle(xStart, y, bmp.Width - xStart, 1));
            }
        }
    }
    finally { bmp.UnlockBits(data); }
    return path;
}

需在專案屬性 → Build → Allow unsafe code 勾選。

延伸應用

  • 不規則視窗:Form.Region 同理可做異形視窗。
  • 圖片熱點區域:結合 MouseMove 即時判斷滑鼠是否在有效區域,切換游標樣式。
  • WPF/UWP:使用 Path、Clip 或 PointerEvents 更原生簡單。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved