利用 SetWindowRgn 配合位圖像素掃描,可建立任意形狀的視窗。本範例示範載入圖片、以左上角像素色作為透明色、掃描建立多邊形區域、移除內凹白色區塊,最後套用至視窗並支援滑鼠拖曳移動。
BmpToRgnvoid __fastcall TForm1::BmpToRgn()
{
Image1->AutoSize = true;
Form1->AutoSize = true;
Form1->BorderStyle = bsNone; // 移除標題列與邊框
TColor ColorKey = Image1->Canvas->Pixels[0][0]; // 透明基準色
int x, y, l, r;
POINT *a;
bool lb, rb;
HRGN wndrgn, temprgn;
// 分配座標陣列
if ((a = (POINT *)malloc(Width * 2 * sizeof(POINT))) == NULL) {
ShowMessage("記憶體配置失敗!"); exit(0);
}
l = 0; r = Image1->Height * 2 - 1;
wndrgn = CreateRectRgn(0, 0, Image1->Width, Image1->Height);
// 雙向掃描每一列,找出左右邊界非透明色像素
for (y = 0; y < Image1->Height; y++) {
lb = true;
for (x = 0; x < Image1->Width + 1; x++)
if (Image1->Canvas->Pixels[x][y] != ColorKey) {
a[l].x = x; a[l].y = y; lb = false; break;
}
if (lb) a[l] = a[l-1]; l++;
rb = true;
for (x = Image1->Width; x >= 0; x--)
if (Image1->Canvas->Pixels[x][y] != ColorKey) {
a[r].x = x; a[r].y = y; rb = false; break;
}
if (rb) a[r] = a[r+1]; r--;
}
// 移除內凹透明區塊 (逐像素 XOR)
r = Image1->Height * 2 - 1;
for (y = 0; y < Image1->Height - 1; y++) {
for (x = a[y].x; x <= a[r].x; x++)
if (Image1->Canvas->Pixels[x][y] == ColorKey) {
temprgn = CreateRectRgn(x, y, x+1, y+1);
CombineRgn(wndrgn, wndrgn, temprgn, RGN_XOR);
DeleteObject(temprgn);
}
r--;
}
// 建立外框多邊形區域並取交集
temprgn = CreatePolygonRgn(a, Image1->Height * 2, WINDING);
CombineRgn(wndrgn, wndrgn, temprgn, RGN_AND);
DeleteObject(temprgn);
free(a);
SetWindowRgn(Handle, wndrgn, true); // 套用視窗區域
}
void __fastcall TForm1::Image1MouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
if (Button == mbLeft) {
ReleaseCapture();
Perform(WM_NCLBUTTONDOWN, HTCAPTION, 0); // 模擬點擊標題列拖曳
}
}
void __fastcall TForm1::Open1Click(TObject *Sender)
{
if (OpenPictureDialog1->Execute()) {
Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
BmpToRgn();
}
}
bsNone 才無標題列、邊框,配合區域呈現不規則外觀。