首頁
編程語言
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()) 會導致視窗閃爍、位置跳動,本文提供正確解法。

核心原理:相對位移計算

正確公式:

新視窗位置 = 原視窗位置 + (目前滑鼠位置 - 按下時滑鼠位置)

需記錄滑鼠按下瞬間的相對座標(相對於元件原點),拖曳時計算位移量累加到視窗原位置。

完整可執行範例

package com.jebysun.test.globalhotkey;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseEvent;
import javax.swing.JLabel;
import javax.swing.JWindow;
import javax.swing.event.MouseInputListener;

/** 
 * 自訂程式視窗,支援滑鼠拖曳移動
 * @author Jeby Sun
 */
public class MyFrame extends JWindow {
    private static final long serialVersionUID = 1L;
    JLabel titleLbl;

    public MyFrame() {
        // JWindow 背景色需設定給 ContentPane
        this.getContentPane().setBackground(new Color(0x99FF66));
        this.setBounds(100, 100, 600, 400);
        this.setLayout(null);
        
        // 自訂標題欄區域
        titleLbl = new JLabel(" 自訂視窗標題欄");
        titleLbl.setOpaque(true);
        titleLbl.setBackground(new Color(0x66CC00));
        titleLbl.setBounds(0, 0, 600, 30);
        this.add(titleLbl);
        
        // 滑鼠事件監聽
        MouseEventListener mouseListener = new MouseEventListener(this);
        titleLbl.addMouseListener(mouseListener);
        titleLbl.addMouseMotionListener(mouseListener);
        
        this.setVisible(true);
    }

    /** 滑鼠事件處理內部類別 */
    class MouseEventListener implements MouseInputListener {
        Point origin;           // 記錄按下時滑鼠相對座標
        MyFrame frame;          // 目標視窗
        
        public MouseEventListener(MyFrame frame) {
            this.frame = frame;
            origin = new Point();
        }
        
        @Override public void mouseClicked(MouseEvent e) {}
        
        /** 按下瞬間記錄相對座標 */
        @Override 
        public void mousePressed(MouseEvent e) {
            origin.x = e.getX();
            origin.y = e.getY();
        }
        
        @Override public void mouseReleased(MouseEvent e) {}
        
        /** 進入區域顯示移動游標 */
        @Override 
        public void mouseEntered(MouseEvent e) {
            frame.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
        }
        
        /** 離開區域恢復預設游標 */
        @Override 
        public void mouseExited(MouseEvent e) {
            frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }
        
        /** 拖曳時計算新位置 */
        @Override 
        public void mouseDragged(MouseEvent e) {
            Point p = frame.getLocation();
            frame.setLocation(
                p.x + (e.getX() - origin.x),
                p.y + (e.getY() - origin.y)
            );
        }
        
        @Override public void mouseMoved(MouseEvent e) {}
    }
    
    public static void main(String[] args) {
        new MyFrame();
    }
}

關鍵點解析

方法用途
mousePressed記錄滑鼠相對於標題欄左上角的座標 (origin)
mouseDragged視窗新位置 = 目前視窗位置 + (目前滑鼠座標 - origin)
mouseEntered/Exited切換游標樣式提升 UX
setUndecorated(true)JFrame 隱藏原生標題欄時同樣適用此邏輯

常見錯誤與避坑

  • 錯誤:setLocation(e.getXOnScreen(), e.getYOnScreen()) → 視窗左上角跳到滑鼠位置,造成劇烈跳動
  • 錯誤:使用螢幕絕對座標 e.getXOnScreen() 而非元件相對座標 e.getX()
  • 正確:累加相對位移量,而非直接設定絕對座標

延伸應用

  • 可擴充支援視窗縮放(邊緣拖曳調整大小)
  • 加入螢幕邊界檢測防止視窗移出可見區域
  • 搭配動畫效果實現平滑移動
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved