Notes

网上几乎翻不到多少 关于 PyQt5 无边框窗口后 在指定控件范围内拖动生效的解释。这里我讲一个方式,可以一次性解决Combobox冲突宕机、输入拉条冲突死机 以及 核心问题:想要自定义一个如原有的win有边窗外窗口那样指定窗体区域内的拖动。


1. 原理

直接说结论,这里用到一个窗体控件方法:self.控件名.underMouse()。
那么这有什么含义?就字面理解即可,返回一个bool值,表示你鼠标是否点击了该控件。既然有了这个,那么我们直接将这个判断条件加入到 全局鼠标事件监听方法mousePressEvent里 就能完美实现 自定义置顶可拖动窗体了。



2. 代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


class main(QMainWindow, Ui_MainWindow):
def __init__(self):
# 初始化
super().__init__()
self.setupUi(self)

# 无边窗化
self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)

# 窗口可拖动变量初始化
self.move_Flag = False
self.mouse_x = self.mouse_y = self.origin_x = self.origin_y = None


def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
"""鼠标点击状态"""
# 当点击时候,先重新初始化拖动标识位为否
self.move_Flag = False
# 核心部分: 当鼠标点击是左键 并且 在top控件内点击时候触发 (这里的top控件即为 我自定义的顶部窗体)
if a0.button() == Qt.LeftButton and self.top.underMouse():
self.setCursor(Qt.OpenHandCursor)
# 但判断条件满足时候, 把拖动标识位设定为真
self.move_Flag = True
self.mouse_x = a0.globalX()
self.mouse_y = a0.globalY()

# 获取窗体当前坐标
self.origin_x = self.x()
self.origin_y = self.y()

def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
"""鼠标移动状态"""
# 拖动标识位设定为真时, 进入移动事件
if self.move_Flag:
# 计算鼠标移动的x,y位移
move_x = a0.globalX() - self.mouse_x
move_y = a0.globalY() - self.mouse_y

# 计算窗体更新后的坐标:更新后的坐标 = 原本的坐标 + 鼠标的位移
dest_x = self.origin_x + move_x
dest_y = self.origin_y + move_y

# 移动窗体
self.move(dest_x, dest_y)

def mouseReleaseEvent(self, a0: QtGui.QMouseEvent) -> None:
"""鼠标释放状态"""
# 设定鼠标为普通状态: 箭头
self.setCursor(Qt.ArrowCursor)