默認 JFrame 帶有系統原生邊框、標題欄、最小/最大/關閉按鈕。許多現代應用(如 QQ 面板、音樂播放器)需要完全自定義外觀:無邊框、圖片背景、自定義控制按鈕、窗口拖動。本文提供完整實現方案。
setUndecorated(true):移除原生裝飾(必須在 setVisible(true) 前調用)JLayeredPane:分離背景層與控件層ImageIcon 加載圖片:注意相對路徑問題(建議用 Class.getResource())package com.qiantu.jframe;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JFrameNoBorder extends JFrame {
private static final long serialVersionUID = 1L;
// 拖動記錄座標
private int xOld = 0, yOld = 0;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new JFrameNoBorder().setVisible(true));
}
public JFrameNoBorder() {
setLayout(null);
initDragSupport();
initUI();
setBounds(100, 100, 400, 300);
setUndecorated(true); // 關鍵:無邊框無標題
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/** 初始化拖動支持 */
private void initDragSupport() {
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
xOld = e.getX();
yOld = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
int xOnScreen = e.getXOnScreen();
int yOnScreen = e.getYOnScreen();
setLocation(xOnScreen - xOld, yOnScreen - yOld);
}
});
}
/** 初始化界面:層疊面板 + 背景 + 控件層 */
private void initUI() {
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setBounds(0, 0, 400, 300);
add(layeredPane);
// === 背景層 ===
JPanel bgPanel = new JPanel(null);
bgPanel.setBounds(0, 0, 400, 300);
layeredPane.add(bgPanel, JLayeredPane.DEFAULT_LAYER);
// 背景圖片 (建議放在 resources/img/ 下,用 getResource 讀取)
JLabel bgLabel = new JLabel(new ImageIcon(getClass().getResource("/img/bgImage.png")));
bgLabel.setBounds(0, 0, 400, 300);
bgPanel.add(bgLabel);
// === 控件層 (最上層) ===
JPanel mainPanel = new JPanel(null);
mainPanel.setBounds(0, 0, 400, 300);
layeredPane.add(mainPanel, JLayeredPane.PALETTE_LAYER);
// 關閉按鈕
JButton closeBtn = new JButton(new ImageIcon(getClass().getResource("/img/closeButton.png")));
closeBtn.setBounds(370, 0, 30, 30);
closeBtn.setBorderPainted(false);
closeBtn.setContentAreaFilled(false);
closeBtn.addActionListener(e -> System.exit(0));
mainPanel.add(closeBtn);
// 可在此添加最小化、設置等按鈕
}
}
錯誤:new ImageIcon("img/bg.png") 依賴工作目錄,打包後失效。
正確:new ImageIcon(getClass().getResource("/img/bg.png")),圖片放在 src/main/resources/img/,打包進 JAR 內。
setDoubleBuffered(true) (默認開啟)mouseDragged 中做複雜計算setLocation 而非 setBoundssetIconImage(new ImageIcon(getClass().getResource("/img/appIcon.png")).getImage());
e.getXOnScreen() 返回螢幕絕對座標,多螢幕環境下正常工作。
JFrame 無邊框無陰影,可用 JWindow + Graphics2D 繪製圓角陰影,或引入 FlatLaf 等現代 LookAndFeelComponentListener 實現邊緣拖動縮放Timer 實現淡入淡出、滑動展開setAutoRequestFocus(false)、圖片多倍圖支持無邊框窗口核心在於 setUndecorated(true) + 手動實現拖動邏輯 + 層疊面板分離背景與控件。本示例提供可直接運行的完整代碼,解決了圖片路徑、拖動座標、層級管理等實戰痛點,可作為自定義 UI 窗口的基礎模板。