this->move(mapFromGlobal(QCursor::pos()) - d->dragPos);
dragPos 是你鼠标按下时,光标在窗口内的位置。
this->move(mapFromGlobal(QCursor::pos()) - d->dragPos);
dragPos 是你鼠标按下时,光标在窗口内的位置。
把当前光标的全局位置转换为你的窗口坐标中的位置,然后就是拖拽点和光标点的差值,做平移就好了。很简单。
把当前光标的全局位置转换为你的窗口坐标中的位置,然后就是拖拽点和光标点的差值,做平移就好了。很简单。
def mouseMoveEvent(self, event):
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
movePos = event.globalPos() - self.startPos
self.startPos = event.globalPos()
self.win.move(self.win.pos() + movePos)
我上面这段代码就是跟你一样的思路(但是是用全局鼠标位置减去鼠标初始按压的点击位置),但是就是快速挪动会造成偏移。
而且从最大化拖动变成还原窗口时,鼠标位置也是不对的。
def mouseMoveEvent(self, event):
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
movePos = event.globalPos() - self.startPos
self.startPos = event.globalPos()
self.win.move(self.win.pos() + movePos)
我上面这段代码就是跟你一样的思路(但是是用全局鼠标位置减去鼠标初始按压的点击位置),但是就是快速挪动会造成偏移。
而且从最大化拖动变成还原窗口时,鼠标位置也是不对的。
你的代码始终有个成员变量一直要给赋值。我以前也是像你这样写,慢速拖动还OK,快速拖动就会飞。
后来改了之后就非常丝滑了。
把光标全局位置转换为窗口内位置,始终是窗口内固定一点做平移。
this->move(mapFromGlobal(QCursor::pos()) - d->dragPos);
dragPos 是你鼠标按下时,光标在窗口内的位置。
这里没有写错吧?move里面不是要全局坐标吗?
貌似我改成了这样之后真的变丝滑了!
def mousePressEvent(self, event):
self.isPressed = True
self.startPos = event.pos()
return QWidget().mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.isPressed = False
return QWidget().mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
movePos =self.win.pos() + ( event.pos() - self.startPos)
self.win.move(movePos)
# self.startPos = event.globalPos()
哦莫进来学习学习
标题栏的移动不建议用窗口的mouse move事件实现,这样做很很多弊端,比如无法把窗口的任何区域移动到屏幕外面,无法拖拽窗口到屏幕边缘后自动最大化等。
推荐的方式是调用 x11 的接口,把窗口移动交给窗口管理器来做,可以参考:https://github.com/linuxdeepin/qt5platform-plugins/blob/master/xcb/utility_x11.cpp#L307
标题栏的移动不建议用窗口的mouse move事件实现,这样做很很多弊端,比如无法把窗口的任何区域移动到屏幕外面,无法拖拽窗口到屏幕边缘后自动最大化等。
推荐的方式是调用 x11 的接口,把窗口移动交给窗口管理器来做,可以参考:https://github.com/linuxdeepin/qt5platform-plugins/blob/master/xcb/utility_x11.cpp#L307
附上一个图:
标题栏的移动不建议用窗口的mouse move事件实现,这样做很很多弊端,比如无法把窗口的任何区域移动到屏幕外面,无法拖拽窗口到屏幕边缘后自动最大化等。
推荐的方式是调用 x11 的接口,把窗口移动交给窗口管理器来做,可以参考:https://github.com/linuxdeepin/qt5platform-plugins/blob/master/xcb/utility_x11.cpp#L307
是的,昨晚我也发现了这些问题,没法移动到屏幕外等等
这是不是意味着未来切换到treeland,这个功能就没法用了?😂
假如用QT起码我不用担心,
但是我自己调用xcb貌似就会可能未来版本要重新适配了
不过我可以在后续的版本中试一下修改为调用x11的接口看看
话说使用这个接口需要获取当前标题栏所在窗口ID,好像比较麻烦😥
是的,昨晚我也发现了这些问题,没法移动到屏幕外等等
这是不是意味着未来切换到treeland,这个功能就没法用了?😂
假如用QT起码我不用担心,
但是我自己调用xcb貌似就会可能未来版本要重新适配了
不过我可以在后续的版本中试一下修改为调用x11的接口看看
话说使用这个接口需要获取当前标题栏所在窗口ID,好像比较麻烦😥
是的,wayland下的话需要调用另外的接口,不过你也可以用Qt的封装,调用Qt的私有接口:这样就不用担心x11和wayland需要分别实现了
QPlatfromWindow::startSystemMove
可喜可贺,从Qt5.15开始,已经添加了 QWindow::startSystemMove,你可以直接用了。
是的,wayland下的话需要调用另外的接口,不过你也可以用Qt的封装,调用Qt的私有接口:这样就不用担心x11和wayland需要分别实现了
QPlatfromWindow::startSystemMove
def mouseDoubleClickEvent(self, event):
self.ShowRestoreWindow()
return QWidget().mouseDoubleClickEvent(event)
def mousePressEvent(self, event):
self.isPressed = True
# self.startPos = event.pos()
return QWidget().mousePressEvent(event)
# self.win.windowHandle().startSystemMove()
def mouseReleaseEvent(self, event):
self.isPressed = False
return QWidget().mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
self.win.windowHandle().startSystemMove()
# movePos =self.win.pos() + ( event.pos() - self.startPos)
# self.win.move(movePos)
# self.startPos = event.globalPos()
return QWidget().mouseMoveEvent(event)
原来就加一行代码这么省事就可以搞定了😧
self.win.windowHandle().startSystemMove()
当初我还去算什么鼠标坐标差值......
貌似是鼠标释放事件没有被触发
https://github.com/wangwenx190/framelesshelper/issues/75
https://stackoverflow.com/questions/76665812/qwindow-startsystemmove-stops-hover-events-on-child-widgets
https://github.com/wangwenx190/framelesshelper/issues/75
https://stackoverflow.com/questions/76665812/qwindow-startsystemmove-stops-hover-events-on-child-widgets
这个问题参见:https://github.com/linuxdeepin/qt5platform-plugins/blob/master/xcb/utility_x11.cpp#L330
原因是mouse press后鼠标实际上是被当前窗口grab了,这个grab是x11中自动的,会持续到mouse release,是用来确保在哪个窗口上按下,鼠标释放时无论鼠标是否还在窗口内,这个窗口都可以收到mouse release事件。
但是,触发 system move 操作之后,鼠标的grab会释放,接着由窗口管理器进行grab,后续的鼠标事件都给了窗口管理器,也就导致最终的mouse release 不会被收到,这样Qt程序可能会一直以为鼠标还在按下状态,这时候就不能正确的计算hover了,因为QWidget也是会把事件传递给mouse press时的那个QWidget。
这个问题参见:https://github.com/linuxdeepin/qt5platform-plugins/blob/master/xcb/utility_x11.cpp#L330
原因是mouse press后鼠标实际上是被当前窗口grab了,这个grab是x11中自动的,会持续到mouse release,是用来确保在哪个窗口上按下,鼠标释放时无论鼠标是否还在窗口内,这个窗口都可以收到mouse release事件。
但是,触发 system move 操作之后,鼠标的grab会释放,接着由窗口管理器进行grab,后续的鼠标事件都给了窗口管理器,也就导致最终的mouse release 不会被收到,这样Qt程序可能会一直以为鼠标还在按下状态,这时候就不能正确的计算hover了,因为QWidget也是会把事件传递给mouse press时的那个QWidget。
https://github.com/linuxdeepin/qt5platform-plugins/commit/fb00e2668f2d50d0276a480b8b2f0effc62196e4 这是 DTK 里的解决方案,是在收到 ungrab 的事件后,从x11那里重新查询下mouse button的按下状态,如果和Qt记录的状态不一致,就补发一个mouse release事件给Qt。
你这里简单实现的话,可以在调用 startSystemMove 后自己主动补发一个 mouseRelease 事件。
https://github.com/linuxdeepin/qt5platform-plugins/commit/fb00e2668f2d50d0276a480b8b2f0effc62196e4 这是 DTK 里的解决方案,是在收到 ungrab 的事件后,从x11那里重新查询下mouse button的按下状态,如果和Qt记录的状态不一致,就补发一个mouse release事件给Qt。
你这里简单实现的话,可以在调用 startSystemMove 后自己主动补发一个 mouseRelease 事件。
貌似手动补发事件也不行😥
def mouseDoubleClickEvent(self, event):
self.ShowRestoreWindow()
return QWidget().mouseDoubleClickEvent(event)
def mousePressEvent(self, event):
self.isPressed = True
# self.startPos = event.pos()
# self.win.windowHandle().startSystemMove()
return QWidget().mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
print("鼠标左键释放")
elif event.button() == Qt.RightButton:
print("鼠标右键释放")
# 其他按钮处理
self.isPressed=False
super().mouseReleaseEvent(event) # 调用基类的事件处理
def triggerMouseReleaseEvent(self, button=Qt.LeftButton):
# 创建一个QMouseEvent
event = QMouseEvent(QEvent.MouseButtonRelease, QPoint(), Qt.NoButton, button, Qt.NoModifier)
# 发送事件到你的窗口
QApplication.sendEvent(self, event)
def mouseMoveEvent(self, event):
print("鼠标按键移动")
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
self.win.windowHandle().startSystemMove()
# self.triggerMouseReleaseEvent( Qt.LeftButton)#
# 假设我们需要在移动结束后触发鼠标释放事件
self.triggerMouseReleaseEvent()
# self.win.setStyleSheet(self.win.styleSheet())
# self.win.activateWindow()
# movePos =self.win.pos() + ( event.pos() - self.startPos)
# self.win.move(movePos)
# self.startPos = event.globalPos()
# event.accept()
# self.win.update()
return QWidget().mouseMoveEvent(event)
貌似手动补发事件也不行😥
def mouseDoubleClickEvent(self, event):
self.ShowRestoreWindow()
return QWidget().mouseDoubleClickEvent(event)
def mousePressEvent(self, event):
self.isPressed = True
# self.startPos = event.pos()
# self.win.windowHandle().startSystemMove()
return QWidget().mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
print("鼠标左键释放")
elif event.button() == Qt.RightButton:
print("鼠标右键释放")
# 其他按钮处理
self.isPressed=False
super().mouseReleaseEvent(event) # 调用基类的事件处理
def triggerMouseReleaseEvent(self, button=Qt.LeftButton):
# 创建一个QMouseEvent
event = QMouseEvent(QEvent.MouseButtonRelease, QPoint(), Qt.NoButton, button, Qt.NoModifier)
# 发送事件到你的窗口
QApplication.sendEvent(self, event)
def mouseMoveEvent(self, event):
print("鼠标按键移动")
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
self.win.windowHandle().startSystemMove()
# self.triggerMouseReleaseEvent( Qt.LeftButton)#
# 假设我们需要在移动结束后触发鼠标释放事件
self.triggerMouseReleaseEvent()
# self.win.setStyleSheet(self.win.styleSheet())
# self.win.activateWindow()
# movePos =self.win.pos() + ( event.pos() - self.startPos)
# self.win.move(movePos)
# self.startPos = event.globalPos()
# event.accept()
# self.win.update()
return QWidget().mouseMoveEvent(event)
这里发没用,要用 QWindowSystemInterface::handleMouseEvent 发才行
这里发没用,要用 QWindowSystemInterface::handleMouseEvent 发才行
在C++里面貌似可以用,但是在Pyqt5里面貌似没法手动补发😢
膜拜大佬
如题,当我按压鼠标拖动标题栏并且快速来回挪动时,鼠标的位置会变动(此时我并没有松开鼠标)
部分代码如下:
完整代码文件:
deepin发帖.zip
有什么修改的好办法吗?