900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 【PyQt】重写系统事件之拖动改变窗口大小

【PyQt】重写系统事件之拖动改变窗口大小

时间:2022-01-27 14:36:47

相关推荐

【PyQt】重写系统事件之拖动改变窗口大小

:系列文章,前后关联,请结合完整代码参考本系列文章;现已开源在 GitHub PyOc

文章目录

参考链接关于鼠标追踪 (重点) ***核心代码设置光标图标事件

参考链接

QT 创建一个 可移动、可拉伸的无边框窗体QT 鼠标跟踪

关于鼠标追踪 (重点) ***

属性mouseTracking : bool默认值 为False只在鼠标任一按键按键按下时触发鼠标移动事件

方法void setMouseTracking(bool enable)设置鼠标追踪属性

方法bool hasMouseTracking()获取当前鼠标追踪状态

注意:若想在 QMainWindow 中若要开启鼠标追踪,必须:

主窗口centralWidget同时开启鼠标追踪

并且开启所有覆盖在你想开启鼠标追踪区域的所有子控件的鼠标追踪

以上两个条件必须同同时满足,否则鼠标追踪会被子控件遮挡,没有效果

核心代码

窗口移动需要使用到鼠标事件,用新旧坐标之差计算偏移量

def _resize(self, event):"""实现拖动调整窗口大小的函数以新旧坐标差计算偏移量,使用 QRect 实例附带位置坐标;核心算法做了三重校验,以确保任意情况下窗口都能以正确的方式调整大小:一: 横纵坐标与最值校验,确保在最值范围内调整大小;二: 横纵坐标与左右区块校验,确保鼠标在窗口边缘时才调整大小;三: 横纵坐标与极值偏移量校验,确保在改变坐标的情况下,窗口不会发生漂移"""# 鼠标在窗口中的区域area = self._area# 鼠标偏移量offsetPos = event.globalPos() - self._posLast# 鼠标在窗口中的坐标winPos = event.pos()# 矩形实例,被赋予窗口的几何属性(x, y, width, height)# 利用其改变左上角坐标,但右下角坐标不变的特性,实现窗口移动效果rect = QRect(self.geometry())x = rect.x()y = rect.y()width = rect.width()height = rect.height()minWidth = self.minimumWidth()minHeight = self.minimumHeight()maxWidth = self.maximumWidth()maxHeight = self.maximumHeight()# 根据不同区域选择不同操作if area == 11:# 左上pos = rect.topLeft()if offsetPos.x() < 0 and width < maxWidth or offsetPos.x() > 0 and width > minWidth:if offsetPos.x() < 0 and winPos.x() <= 0 or offsetPos.x() > 0 and winPos.x() >= 0:if (maxWidth - width) >= -offsetPos.x() and (width - minWidth) >= offsetPos.x():pos.setX(pos.x() + offsetPos.x())if offsetPos.y() < 0 and height < maxHeight or offsetPos.y() > 0 and height > minHeight:if offsetPos.y() < 0 and winPos.y() <= 0 or offsetPos.y() > 0 and winPos.y() >= 0:if (maxHeight - height) >= -offsetPos.y() and (height - minHeight) >= offsetPos.y():pos.setY(pos.y() + offsetPos.y())rect.setTopLeft(pos)elif area == 13:# 右上pos = rect.topRight()if offsetPos.x() < 0 and width > minWidth or offsetPos.x() > 0 and width < maxWidth:if offsetPos.x() < 0 and winPos.x() <= width or offsetPos.x() > 0 and winPos.x() >= width:pos.setX(pos.x() + offsetPos.x())if offsetPos.y() < 0 and height < maxHeight or offsetPos.y() > 0 and height > minHeight:if offsetPos.y() < 0 and winPos.y() <= 0 or offsetPos.y() > 0 and winPos.y() >= 0:if (maxHeight - height) >= -offsetPos.y() and (height - minHeight) >= offsetPos.y():pos.setY(pos.y() + offsetPos.y())rect.setTopRight(pos)elif area == 31:# 左下pos = rect.bottomLeft()if offsetPos.x() < 0 and width < maxWidth or offsetPos.x() > 0 and width > minWidth:if offsetPos.x() < 0 and winPos.x() <= 0 or offsetPos.x() > 0 and winPos.x() >= 0:if (maxWidth - width) >= -offsetPos.x() and (width - minWidth) >= offsetPos.x():pos.setX(pos.x() + offsetPos.x())if offsetPos.y() < 0 and height > minHeight or offsetPos.y() > 0 and height < maxHeight:if offsetPos.y() < 0 and winPos.y() <= height or offsetPos.y() > 0 and winPos.y() >= height:pos.setY(pos.y() + offsetPos.y())rect.setBottomLeft(pos)elif area == 33:# 右下pos = rect.bottomRight()if offsetPos.x() < 0 and width > minWidth or offsetPos.x() > 0 and width < maxWidth:if offsetPos.x() < 0 and winPos.x() <= width or offsetPos.x() > 0 and winPos.x() >= width:pos.setX(pos.x() + offsetPos.x())if offsetPos.y() < 0 and height > minHeight or offsetPos.y() > 0 and height < maxHeight:if offsetPos.y() < 0 and winPos.y() <= height or offsetPos.y() > 0 and winPos.y() >= height:pos.setY(pos.y() + offsetPos.y())rect.setBottomRight(pos)elif area == 12:# 中上if offsetPos.y() < 0 and height < maxHeight or offsetPos.y() > 0 and height > minHeight:if offsetPos.y() < 0 and winPos.y() <= 0 or offsetPos.y() > 0 and winPos.y() >= 0:if (maxHeight - height) >= -offsetPos.y() and (height - minHeight) >= offsetPos.y():rect.setTop(rect.top() + offsetPos.y())elif area == 21:# 中左if offsetPos.x() < 0 and width < maxWidth or offsetPos.x() > 0 and width > minWidth:if offsetPos.x() < 0 and winPos.x() <= 0 or offsetPos.x() > 0 and winPos.x() >= 0:if (maxWidth - width) >= -offsetPos.x() and (width - minWidth) >= offsetPos.x():rect.setLeft(rect.left() + offsetPos.x())elif area == 23:# 中右if offsetPos.x() < 0 and width > minWidth or offsetPos.x() > 0 and width < maxWidth:if offsetPos.x() < 0 and winPos.x() <= width or offsetPos.x() > 0 and winPos.x() >= width:rect.setRight(rect.right() + offsetPos.x())elif area == 32:# 中下if offsetPos.y() < 0 and height > minHeight or offsetPos.y() > 0 and height < maxHeight:if offsetPos.y() < 0 and winPos.y() <= height or offsetPos.y() > 0 and winPos.y() >= height:rect.setBottom(rect.bottom() + offsetPos.y())# 设置窗口几何属性(坐标,宽高)self.setGeometry(rect)

设置光标图标

def _change_cursor_icon(self, area):"""改变光标在窗口边缘时的图片"""# 宽度固定时不应改变宽度if self.maximumWidth() == self.minimumWidth() and (area == 21 or area == 23):return None# 高度固定时不应改变高度if self.maximumHeight() == self.minimumHeight() and (area == 12 or area == 32):return Noneif area == 11 or area == 33:self.setCursor(Qt.SizeFDiagCursor)# 倾斜光标elif area == 12 or area == 32:self.setCursor(Qt.SizeVerCursor)# 垂直大小光标elif area == 13 or area == 31:self.setCursor(Qt.SizeBDiagCursor)# 反倾斜光标elif area == 21 or area == 23:self.setCursor(Qt.SizeHorCursor)# 水平大小光标else:self.setCursor(Qt.ArrowCursor)# 默认光标

事件

def mousePressEvent(self, event):"""重写继承的鼠标按住事件"""self._isPressed = True# 判断是否按下self._press_button = event.button() # 按下的鼠标按键self._area = self._compute_area(event.pos()) # 计算鼠标所在区域self._move_count = 0 # 鼠标移动计数,用于降低灵敏度self._posLast = event.globalPos() # 当前坐标return QMainWindow.mousePressEvent(self, event)# 交由原事件函数处理def mouseReleaseEvent(self, event):"""重写继承的鼠标释放事件"""self._isPressed = False # 重置按下状态self._press_button = None # 清空按下的鼠标按键self._area = None# 清空鼠标区域self._move_count = 0 # 清空移动计数self.setCursor(Qt.ArrowCursor) # 还原光标图标return QMainWindow.mouseReleaseEvent(self, event)def mouseMoveEvent(self, event):"""重写继承的鼠标移动事件,实现窗口移动及拖动改变窗口大小"""area = self._compute_area(event.pos()) # 计算鼠标区域# 调整窗口大小及移动if self._isPressed and self._press_button == Qt.LeftButton:if self._area == 22:self._move(event) # 调用移动窗口的函数elif not self.isMaximized():self._resize(event)# 调用调整窗口大小的函数# 更新鼠标全局坐标self._posLast = event.globalPos()return Noneif not self._isPressed and not self.isMaximized():# 调整鼠标图标,按下鼠标后锁定状态self._change_cursor_icon(area)return QMainWindow.mouseMoveEvent(self, event)

本文为 one-ccs 原创文章,引用必须注明出处!

/qq_43155814/article/details/104679678

上一篇:【PyQt】实战 Super Spider 之窗口移动

下一篇:【PyQt】实战 Super Spider 之自适应背景图片

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。