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

Java Swing 無標題欄視窗實現滑鼠拖曳移動

     編輯:Java 相關知識

場景痛點

JFrame 預設標題欄支援拖曳移動,但自訂 UI 時常隱藏標題欄(setUndecorated(true))或直接用 JWindow,導致失去原生移動功能。若直接在 mouseDragged 中 setLocation(e.getX(), e.getY()),視窗會因座標系差異閃爍、跳動。

核心解法:相對位移計算

新位置 = 視窗原位置 + (滑鼠當前螢幕座標 - 滑鼠按下時螢幕座標)
關鍵:必須用 螢幕絕對座標(e.getXOnScreen() / e.getYOnScreen() 或 元件轉換),而非元件相對座標。

完整可執行範例 (MyFrame.java)

package com.jebysun.test.globalhotkey;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.MouseInputListener;

public class MyFrame extends JWindow {
    private static final long serialVersionUID = 1L;
    private JLabel titleBar;
    private Point dragOrigin = new Point(); // 滑鼠按下時的螢幕座標

    public MyFrame() {
        // 1. 基本視窗設定
        getContentPane().setBackground(new Color(0x99FF66));
        setBounds(100, 100, 600, 400);
        setLayout(null);

        // 2. 自訂標題欄(作為拖曳手柄)
        titleBar = new JLabel(" 自訂視窗標題欄");
        titleBar.setOpaque(true);
        titleBar.setBackground(new Color(0x66CC00));
        titleBar.setBounds(0, 0, 600, 30);
        add(titleBar);

        // 3. 滑鼠事件監聽
        MouseHandler handler = new MouseHandler();
        titleBar.addMouseListener(handler);
        titleBar.addMouseMotionListener(handler);

        setVisible(true);
    }

    private class MouseHandler implements MouseInputListener {
        @Override public void mousePressed(MouseEvent e) {
            // 記錄按下時的螢幕絕對座標
            dragOrigin.setLocation(e.getXOnScreen(), e.getYOnScreen());
        }

        @Override public void mouseDragged(MouseEvent e) {
            // 計算位移並套用
            int dx = e.getXOnScreen() - dragOrigin.x;
            int dy = e.getYOnScreen() - dragOrigin.y;
            Point loc = getLocation();
            setLocation(loc.x + dx, loc.y + dy);

            // 更新基準點,避免累積誤差
            dragOrigin.setLocation(e.getXOnScreen(), e.getYOnScreen());
        }

        @Override public void mouseEntered(MouseEvent e) {
            setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
        }
        @Override public void mouseExited(MouseEvent e) {
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }
        // 未使用事件保留空實作
        @Override public void mouseClicked(MouseEvent e) {}
        @Override public void mouseReleased(MouseEvent e) {}
        @Override public void mouseMoved(MouseEvent e) {}
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(MyFrame::new);
    }
}

關鍵細節對照

錯誤寫法正確寫法原因
setLocation(e.getX(), e.getY())setLocation(loc.x + dx, loc.y + dy)元件座標隨視窗移動變化,導致抖動
未更新 dragOrigindragOrigin 更新為最新螢幕座標避免長距離拖曳時誤差累積
直接 extends JFrameextends JWindow + setUndecorated(true)JWindow 無原生邊框,完全自訂

進階擴充建議

  • 邊框縮放:在視窗四邊/角佈置 5px 透明 JPanel,監聽 mouseDragged 調整 setSize()。
  • 螢幕邊界吸附:移動時檢測與螢幕邊緣距離 < 10px 自動對齊。
  • 多螢幕支援:使用 GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() 取得各螢幕邊界。

掌握「螢幕座標系 + 相對位移」核心邏輯,即可為任何無邊框視窗、自訂元件賦予原生般順滑的拖曳體驗。

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