繼字形窗體後,本文演示如何用同樣技術製作「心形」等任意非矩形窗體。核心同樣是 FormBorderStyle.None + TransparencyKey + OnPaint 繪製帶透明通道的圖片,區別僅在於素材圖片形狀不同。提供完整代碼、設計器配置、素材準備與拖動補丁。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ArbitraryShapeForm
{
public partial class Form1 : Form
{
private Bitmap _shapeBmp;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// 1. 載入心形圖片(建議 PNG 透明背景)
_shapeBmp = new Bitmap("heart.png"); // 或 heart.bmp + MakeTransparent
// _shapeBmp.MakeTransparent(Color.Magenta); // 若用 BMP,指定洋紅為透明色
// 2. 窗體大小跟隨圖片
this.ClientSize = _shapeBmp.Size;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawImage(_shapeBmp, Point.Empty);
}
// 標籤作為關閉鍵(右上角小圓點)
private void label1_Click(object sender, EventArgs e)
{
this.Close();
}
// 拖動無邊框窗體
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 0x84;
const int HTCLIENT = 1;
const int HTCAPTION = 2;
if (m.Msg == WM_NCHITTEST)
{
base.WndProc(ref m);
if ((int)m.Result == HTCLIENT)
m.Result = (IntPtr)HTCAPTION;
return;
}
base.WndProc(ref m);
}
protected override void Dispose(bool disposing)
{
if (disposing && _shapeBmp != null)
_shapeBmp.Dispose();
base.Dispose(disposing);
}
}
}
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
// label1:關閉按鈕,置於心形右上曲線處
this.label1.BackColor = Color.Transparent;
this.label1.Location = new Point(280, 42);
this.label1.Size = new Size(17, 16);
this.label1.Click += label1_Click;
this.AutoScaleDimensions = new SizeF(6F, 12F);
this.AutoScaleMode = AutoScaleMode.Font;
this.BackColor = SystemColors.Control; // 必須與 TransparencyKey 一致
this.ClientSize = new Size(393, 317); // 會在 Load 中被圖片尺寸覆蓋
this.Controls.Add(this.label1);
this.FormBorderStyle = FormBorderStyle.None;
this.Name = "Form1";
this.StartPosition = FormStartPosition.CenterScreen;
this.Text = "任意形狀窗體";
this.TransparencyKey = SystemColors.Control; // 關鍵:將背景色設為透明
this.Load += Form1_Load;
this.ResumeLayout(false);
}
| 格式 | 透明方式 | 優點 | 缺點 |
|---|---|---|---|
| PNG (32-bit) | 原生 Alpha 通道 | 邊緣抗鋸齒完美、無需代碼處理 | 文件稍大 |
| BMP (24-bit) | MakeTransparent(Color) | 無壓縮、載入快 | 邊緣鋸齒、需純色背景 |
| GIF | 單一透明色 | 支持動畫 | 256 色、邊緣鋸齒 |
建議:PS/AI 導出 PNG,背景勾選透明,邊緣羽化 0.5-1px,尺寸即窗體 ClientSize。
預設透明區域點擊會穿透到下層窗體。若需「只有心形區域可點擊」,兩種方案:
using System.Drawing.Drawing2D;
// 在 Load 中
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, _shapeBmp.Width, _shapeBmp.Height); // 簡易橢圓
// 或用圖片非透明像素構建精確路徑(較複雜)
this.Region = new Region(path);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
const int GWL_EXSTYLE = -20;
const int WS_EX_LAYERED = 0x80000;
const int WS_EX_TRANSPARENT = 0x20;
// 啟用分層窗體
int exStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
SetWindowLong(this.Handle, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
// 設置透明度 200/255
SetLayeredWindowAttributes(this.Handle, 0, 200, 2); // LWA_ALPHA
HeartShapeForm/
├── Form1.cs
├── Form1.Designer.cs
├── Program.cs
├── Resources/
│ └── heart.png // 32-bit PNG,透明背景
└── HeartShapeForm.csproj
任意形狀窗體本質是「矩形窗體 + 透明色鍵 + 非矩形圖片繪製」。掌握 TransparencyKey、OnPaint、Region/Layered Window 三大技術點,即可實現從簡單心形到複雜遊戲啟動器皮膚的各種異形界面。記住:素材決定上限,代碼決定下限。