首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Swing 實現無邊框窗口拖動與自定義標題欄

     編輯:Java 相關知識

需求背景

默認 JFrame 帶有系統原生邊框、標題欄、最小/最大/關閉按鈕。許多現代應用(如 QQ 面板、音樂播放器)需要完全自定義外觀:無邊框、圖片背景、自定義控制按鈕、窗口拖動。本文提供完整實現方案。

核心技術點

  1. setUndecorated(true):移除原生裝飾(必須在 setVisible(true) 前調用)
  2. 層疊面板 JLayeredPane:分離背景層與控件層
  3. 鼠標事件監聽:記錄按下座標,拖動時計算偏移量移動窗口
  4. 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);

        // 可在此添加最小化、設置等按鈕
    }
}

關鍵問題解決

1. 圖片路徑問題

錯誤:new ImageIcon("img/bg.png") 依賴工作目錄,打包後失效。
正確:new ImageIcon(getClass().getResource("/img/bg.png")),圖片放在 src/main/resources/img/,打包進 JAR 內。

2. 拖動閃爍/卡頓

  • 開啟雙緩衝:setDoubleBuffered(true) (默認開啟)
  • 避免在 mouseDragged 中做複雜計算
  • 考慮使用 setLocation 而非 setBounds

3. 任務欄圖標設置

setIconImage(new ImageIcon(getClass().getResource("/img/appIcon.png")).getImage());

4. 多螢幕座標問題

e.getXOnScreen() 返回螢幕絕對座標,多螢幕環境下正常工作。

進階擴展建議

  • 邊框陰影:JFrame 無邊框無陰影,可用 JWindow + Graphics2D 繪製圓角陰影,或引入 FlatLaf 等現代 LookAndFeel
  • 縮放支持:監聽 ComponentListener 實現邊緣拖動縮放
  • 動畫效果:配合 Timer 實現淡入淡出、滑動展開
  • 高 DPI 適配:JDK 9+ setAutoRequestFocus(false)、圖片多倍圖支持

總結

無邊框窗口核心在於 setUndecorated(true) + 手動實現拖動邏輯 + 層疊面板分離背景與控件。本示例提供可直接運行的完整代碼,解決了圖片路徑、拖動座標、層級管理等實戰痛點,可作為自定義 UI 窗口的基礎模板。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved