完整程式碼
package swt_jface.demo1;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
public class RingShell {
// 產生圓周頂點座標陣列
private int[] createCircle(int radius, int centerX, int centerY) {
int[] points = new int[360 * 2];
for (int i = 0; i < 360; i++) {
double rad = Math.toRadians(i);
points[i * 2] = centerX + (int) (radius * Math.cos(rad));
points[i * 2 + 1] = centerY + (int) (radius * Math.sin(rad));
}
return points;
}
private Point originalPosition = null;
public RingShell() {
Display display = new Display();
// 無邊框、置頂
Shell shell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP);
shell.setBackground(display.getSystemColor(SWT.COLOR_DARK_MAGENTA));
// 建立 Region:外圓減去內圓 = 圓環
Region region = new Region();
region.add(createCircle(100, 100, 100)); // 外半徑 100
region.subtract(createCircle(50, 100, 100)); // 內半徑 50
shell.setRegion(region); // 套用非矩形視窗
// 滑鼠拖曳移動視窗
shell.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
originalPosition = new Point(e.x, e.y);
}
@Override
public void mouseUp(MouseEvent e) {
originalPosition = null;
}
@Override
public void mouseDoubleClick(MouseEvent e) {
display.dispose(); // 雙擊關閉
}
});
shell.addMouseMoveListener(new MouseMoveListener() {
@Override
public void mouseMove(MouseEvent e) {
if (originalPosition == null) return;
Point pt = display.map(shell, null, e.x, e.y); // 轉換為螢幕座標
shell.setLocation(pt.x - originalPosition.x, pt.y - originalPosition.y);
}
});
// 依 Region 邊界設定 Shell 大小
Rectangle bounds = region.getBounds();
shell.setSize(bounds.width, bounds.height);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
region.dispose(); // 釋放 Region 資源
}
public static void main(String[] args) {
new RingShell();
}
}
核心技術解析
| 技術點 | 實現方式 |
| 非矩形視窗 | Shell(SWT.NO_TRIM | SWT.ON_TOP) 移除標題列/邊框、置頂顯示 |
| 形狀裁剪 | Region.add()/subtract() 布爾運算組合幾何形狀,shell.setRegion(region) 套用 |
| 圓周點陣生成 | 參數方程 x = cx + r·cos(θ), y = cy + r·sin(θ),360 點近似圓 |
| 拖曳移動 | mouseDown 記錄相對座標 → mouseMove display.map() 轉螢幕座標 → shell.setLocation() |
| 資源釋放 | Region.dispose()、Display.dispose() 必須成對調用 |
進階擴充想法
- 漸層/圖片填充:
shell.setBackgroundImage() 或在 PaintListener 中繪製漸層。
- 點擊穿透:Windows 需 JNA 呼叫
SetWindowLong(WS_EX_TRANSPARENT);跨平台較複雜。
- 動畫效果:計時器漸變
shell.setAlpha()(需 SWT.ALPHA 支援)或縮放 Region。
- 系統托盤整合:
Tray + TrayItem 實現最小化到托盤、右鍵選單。
適用場景
- 桌面小工具(時鐘、CPU 監控、便利貼)
- 螢幕取色器、放大鏡等浮動工具
- 遊戲外掛/輔助覆蓋層(需注意反作弊)
- 非標準形狀啟動畫面