SWT 結合原生界面庫,效能與外觀兼顧,但預設僅支援矩形窗體。通過 org.eclipse.swt.graphics.Region 定義任意多邊形、結合圖片透明通道提取輪廓,可實現圓形按鈕、異形窗口、媒體播放器等酷炫界面——且 RCP 應用同樣適用。
// 逆時針頂點:x1,y1, x2,y2, ...
int[] rect = {0,0, 0,320, 520,320, 520,0}; // 矩形
int[] rect2 = {50,320, 50,370, 470,370, 470,320}; // 另一矩形
Region region = new Region();
region.add(rect);
region.add(rect2); // 疊加形成 L 形

int[] circle(int r, int offsetX, int offsetY) {
int[] ring = new int[8 * r + 4];
for (int i = 0; i < 2 * r + 1; i++) {
int x = i - r;
int y = (int) Math.sqrt(r * r - x * x);
ring[2 * i] = offsetX + x;
ring[2 * i + 1] = offsetY + y;
ring[8 * r - 2 * i - 2] = offsetX + x;
ring[8 * r - 2 * i - 1] = offsetY - y;
}
return ring;
}

region.subtract(circle(20, 400, 345)); // 在右下角挖圓洞
Display display = new Display();
Shell shell = new Shell(display, SWT.NO_TRIM); // 無標題欄邊框
Region region = new Region();
region.add(getBackRect1());
region.add(getBackRect2());
region.subtract(circle(20, 400, 345));
shell.setRegion(region);
Rectangle bounds = region.getBounds();
shell.setSize(bounds.width, bounds.height);
shell.open();
// 事件循環...
region.dispose(); display.dispose();

關鍵點:
SWT.NO_TRIM 移除系統裝飾,Region 完全接管外形setRegion 後必須 setSize 為 Region boundsdispose()Eclipse 3.4+ 才原生支援 Control.setRegion,早期版本採用「透明圖片 + Region 裁剪」變通:
Button btn = new Button(shell, SWT.PUSH);
Image img = new Image(display, "play.png");
Region btnRegion = new Region();
btnRegion.add(circle(35, 40, 40)); // 圓形點擊區
btn.setRegion(btnRegion);
btn.setSize(img.getBounds().width + 10, img.getBounds().height + 10);
btn.setImage(img);


原理:Region 定義響應區域,圖片提供視覺邊界,超出 Region 點擊無響應。
手工寫坐標極其繁瑣,利用 ImageData.getTransparencyMask() 掃描非零像素:
Region getRegionFromImage(Display display, String path) {
ImageLoader loader = new ImageLoader();
ImageData[] data = loader.load(path);
ImageData img = data[0];
ImageData mask = img.getTransparencyMask();
Region region = new Region(display);
Rectangle pixel = new Rectangle(0,0,1,1);
for (int y=0; y
同時設置背景圖:
Image bgImage = new Image(display, data[0]);
shell.setBackgroundImage(bgImage);

完整代碼見 清單 6,單張 PNG/GIF 同時定義形狀與皮膚。

Application → WorkbenchAdvisor → WorkbenchWindowAdvisorpreWindowOpen():設置 SWT.NO_TRIM | SWT.NO_BACKGROUNDcreateWindowContents():創建 Page、按鈕等控件,設置 RegionpostWindowCreate():獲取 Shell,應用 Region、背景圖、拖拽移動監聽
核心代碼片段:
// postWindowCreate - 窗體形狀與背景
Shell shell = configurer.getWindow().getShell();
backRegion = getRegionFromImage(shell.getDisplay(), backImage);
shell.setRegion(backRegion);
shell.setSize(imgWidth, imgHeight);
// 拖拽移動 + 重繪背景
shell.addListener(SWT.MouseDown, e -> { startX=e.x; startY=e.y; });
shell.addListener(SWT.MouseMove, e -> {
if ((e.stateMask & SWT.BUTTON1) != 0) {
Point p = shell.toDisplay(e.x, e.y);
shell.setLocation(p.x - startX, p.y - startY);
}
});
shell.addListener(SWT.Paint, e -> e.gc.drawImage(backImage, 0, 0));
// createWindowContents - Page 與按鈕
Composite page = configurer.createPageComposite(shell);
page.setRegion(getRegionFromImage(display, pageImage));
page.setBounds(45, 21, pageW, pageH);
Button playBtn = new Button(shell, SWT.PUSH);
playBtn.setRegion(circleRegion(35));
playBtn.setImage(playImg);
playBtn.addSelectionListener(e -> openMediaEditor());
Button exitBtn = new Button(shell, SWT.PUSH);
exitBtn.setRegion(getRegionFromImage(display, exitImg));
exitBtn.setImage(exitImg);
exitBtn.addSelectionListener(e -> PlatformUI.getWorkbench().close());
注意:
Composite) 同樣支援 setRegion| 技術點 | 建議 |
|---|---|
| 複雜形狀 | 優先用圖片透明通道提取,避免手算坐標 |
| 圖片格式 | PNG (無損透明) > GIF (單色透明) > JPEG (不支援透明) |
| 效能 | Region 越複雜,重繪/命中測試越慢,適度簡化 |
| RCP 整合 | 在 WorkbenchWindowAdvisor 統一管理,避免分散在各 View/Editor |
| 無裝飾窗口 | 必須自行實現:移動、最小化/最大化/關閉、重繪 |
SWT/RCP 的 Region 機制將「像素級界面控制權」交還開發者,配合圖片皮膚,構建差異化桌面應用不再是夢。