效果與核心技術
- 無邊框異形視窗:
FormBorderStyle = None + 位圖透明色建立 Region。
- 不搶焦點顯示:P/Invoke
ShowWindow(hWnd, SW_SHOWNOACTIVATE=4)。
- 平滑動畫:雙緩衝繪圖(
OnPaintBackground 繪製到記憶體位圖再一次貼上)+ Timer 控制升起/停留/降落。
- 拖曳移動:攔截標題列區域滑鼠按下,發送
WM_NCLBUTTONDOWN + HT_CAPTION 模擬標題列拖曳。
- 換膚機制:外部傳入
Image 與透明色,動態重建 Region。
關鍵程式碼架構
public class TaskbarForm : Form
{
// P/Invoke 宣告
[DllImport("user32.dll")] static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")] static extern bool ReleaseCapture();
[DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int WM_NCLBUTTONDOWN = 0xA1;
const int HT_CAPTION = 0x2;
const int SW_SHOWNOACTIVATE = 4;
// 狀態與動畫參數
int currentTop = 1, intervalValue = 5;
Rectangle TitlebarRectangle, CloseBtnRectangle, ContentRectangle;
Image BackgroundBitmap;
// 公開介面:顯示通知
public void ShowForm(string title, string content, Rectangle titleRect, Rectangle titlebarRect, Rectangle contentRect, Rectangle closeRect)
{
TitlebarRectangle = titlebarRect; CloseBtnRectangle = closeRect; ContentRectangle = contentRect;
WorkAreaRectangle = Screen.GetWorkingArea(WorkAreaRectangle);
this.Top = WorkAreaRectangle.Height + this.Height; // 起始位置:螢幕下方外
FormBorderStyle = FormBorderStyle.None;
ShowWindow(this.Handle, SW_SHOWNOACTIVATE);
timer1.Enabled = true; // 開始升起動畫
}
// 雙緩衝繪圖
protected override void OnPaintBackground(PaintEventArgs e)
{
var offscreen = new Bitmap(BackgroundBitmap.Width, BackgroundBitmap.Height);
using (var g = Graphics.FromImage(offscreen))
{
g.DrawImage(BackgroundBitmap, 0, 0);
DrawText(g); // 繪製標題與內容
}
e.Graphics.DrawImage(offscreen, 0, 0);
}
// 滑鼠處理:拖曳、關閉、連結點擊
private void TaskbarForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (TitlebarRectangle.Contains(e.Location)) { ReleaseCapture(); SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); }
if (CloseBtnRectangle.Contains(e.Location)) { Hide(); currentTop = 1; }
if (ContentRectangle.Contains(e.Location)) Process.Start("https://www.example.com");
}
}
// 計時器驅動動畫:升起 → 停留 → 降落 → 隱藏
private void timer1_Tick(object sender, EventArgs e) { /* 更新 this.Top, 切換狀態 */ }
}
建立不規則視窗 Region
public void SetBackgroundBitmap(Image image, Color transparencyColor)
{
BackgroundBitmap = new Bitmap(image);
Width = BackgroundBitmap.Width; Height = BackgroundBitmap.Height;
Region = BitmapToRegion(BackgroundBitmap, transparencyColor);
}
public Region BitmapToRegion(Bitmap bmp, Color transparent)
{
var path = new GraphicsPath();
for (int y = 0; y < bmp.Height; y++)
for (int x = 0; x < bmp.Width; x++)
{
if (bmp.GetPixel(x, y) == transparent) continue;
int x0 = x;
while (x < bmp.Width && bmp.GetPixel(x, y) != transparent) x++;
path.AddRectangle(new Rectangle(x0, y, x - x0, 1));
}
return new Region(path);
}
部署注意事項
- 圖片背景色需統一(如
#FF00FF),且不可出現在前景圖案中。
- 動畫速度可透過
intervalValue 與 Timer.Interval 調整。
- 若需多顯示器支援,請使用
Screen.FromControl(this) 取得正確工作區。