You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wayland下Qt QWidget.move(x,y)无法更新组件位置问题求助

问题诊断与修复

核心问题

你的QMovableResizableWidget拖拽失效有两个关键原因:

  1. 坐标转换错误:无父级的顶级窗口,self.pos()本身就是屏幕全局坐标,你用self.mapToGlobal(self.pos())会重复转换,得到错误的位置值。
  2. 拖拽基准未更新:每次移动后没有更新鼠标的初始基准点,导致后续偏移计算不断累加初始差值,最终窗口位置计算混乱,视觉上表现为不移动。

修复后的代码

import sys
from PySide6 import QtWidgets, QtCore, QtGui

Qt = QtCore.Qt
QMouseEvent = QtGui.QMouseEvent
QWidget = QtWidgets.QWidget
QEvent = QtCore.QEvent
CursorShape = Qt.CursorShape
QApplication = QtWidgets.QApplication
WindowTypes = Qt.WindowType
QPoint = QtCore.QPoint


class QCustomWidget(QWidget):
    def __init__(self, p, f):
        super().__init__(p, f)
        self.setMouseTracking(True)
        

class QResizableWidget(QCustomWidget):
    def __init__(self,p, f):
        super().__init__(p, f)
        pass
        

class QMovableResizableWidget(QCustomWidget):
    def __init__(self,p, f):
        super().__init__(p, f)

        self.__moveInitLoc = None
        self.__isDragging = False
        self.setAttribute(Qt.WidgetAttribute.WA_MouseTracking, True)
        
    def event(self, ev):
        if isinstance(ev, QMouseEvent):
            if (
                ev.type() == QEvent.Type.MouseButtonPress
                and ev.button() == Qt.MouseButton.LeftButton
            ):
                self.__isDragging = True
                # 同时记录点击时的窗口位置和鼠标全局位置
                self.__moveInitLoc = (self.pos(), ev.globalPos())

            elif (
                ev.type() == QEvent.Type.MouseMove
                and self.__isDragging
            ):
                if self.__moveInitLoc is not None:
                    self.setCursor(CursorShape.DragMoveCursor)
                    
                    window_init_pos, mouse_init_pos = self.__moveInitLoc
                    # 计算鼠标偏移,直接用初始窗口位置加偏移得到新位置
                    diff = ev.globalPos() - mouse_init_pos
                    new_pos = window_init_pos + diff
                    self.move(new_pos)
                    # 更新基准点,避免后续计算偏移累加
                    self.__moveInitLoc = (new_pos, ev.globalPos())
                    return True

            elif ev.type() == QEvent.Type.MouseButtonRelease:
                self.__isDragging = False
                self.__moveInitLoc = None
                self.unsetCursor()

        return super().event(ev)
    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle("Fusion")

    window = QMovableResizableWidget(None, WindowTypes.Window | WindowTypes.FramelessWindowHint)

    window.resize(300, 300)
    window.show()
    sys.exit(app.exec())

关键修改点

  • 调整基准数据存储:将__moveInitLoc改为存储元组(窗口初始全局位置, 鼠标初始全局位置),避免坐标转换错误。
  • 修正位置计算逻辑:直接通过初始窗口位置 + 鼠标偏移量得到新位置,无需多余的坐标转换。
  • 实时更新基准点:每次移动后更新__moveInitLoc为当前窗口位置和鼠标位置,确保后续拖拽的偏移计算准确。

另外,关于你提到的直接调用move(x,y)无效的情况:修正拖拽逻辑后,顶级窗口直接调用move也能正常生效,因为问题根源在拖拽逻辑的坐标计算错误,而非move方法本身。

内容的提问来源于stack exchange,提问作者razor_chk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:03:28