-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWindow.py
157 lines (138 loc) · 5.89 KB
/
Window.py
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import typing
from PyQt5.QtCore import QEvent, QObject, Qt
from PyQt5.QtGui import QCloseEvent, QCursor, QFont, QPainter, QPaintEvent, QColor
from PyQt5.QtWidgets import QAction, QDesktopWidget, QSizePolicy, QSpacerItem, QWidget
from qfluentwidgets import RoundMenu, qconfig, Theme
from qframelesswindow import FramelessWindow
from Events import *
class Window(FramelessWindow):
"""
替换系统原生窗口
保留原生窗口特性外还支持往标题栏上添加控件
"""
def __init__(self, client: QWidget):
super().__init__()
self.titlemenu_actions: list[QAction] = []
# 用来分离标题栏左右控件
self.si_separate = QSpacerItem(
0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
)
self.titleBar.hBoxLayout.insertSpacerItem(0, self.si_separate)
self.titleBar.hBoxLayout.setStretch(1, 0)
self.titleBar.hBoxLayout.setStretch(0, 1)
# 客户区
self.client = client
self.client.setParent(self)
self.client.move(0, self.titleBar.height())
self.client.windowIconChanged.connect(
lambda icon: (self.setWindowIcon(icon), self.repaint())
)
self.client.windowTitleChanged.connect(
lambda title: (self.setWindowTitle(title), self.repaint())
)
self.client.installEventFilter(self)
self.client.show()
self.setWindowTitle(self.client.windowTitle())
self.setWindowIcon(self.client.windowIcon())
self.resize(self.client.width(), self.client.height() + self.titleBar.height())
self.move(
int((QDesktopWidget().width() - self.width()) / 2),
int((QDesktopWidget().height() - self.height()) / 2),
)
self.titleBar.setObjectName("titleBar")
self.titleBar.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.titleBar.customContextMenuRequested.connect(self.showTitleMenu)
qconfig.themeChanged.connect(self.on_themeChanged)
self.on_themeChanged()
self.origin_size = self.size()
def on_themeChanged(self):
theme = qconfig.theme
color = QColor(0, 0, 0) if theme == Theme.LIGHT else QColor(255, 255, 255)
hoverbgcolor = (
QColor(0, 0, 0, 26) if theme == Theme.LIGHT else QColor(255, 255, 255, 21)
)
pressedbgcolor = (
QColor(0, 0, 0, 51) if theme == Theme.LIGHT else QColor(255, 255, 255, 51)
)
for button in (
self.titleBar.minBtn,
self.titleBar.maxBtn,
self.titleBar.closeBtn,
):
button.setNormalColor(color)
button.setHoverColor(color)
button.setPressedColor(color)
if button != self.titleBar.closeBtn:
button.setHoverBackgroundColor(hoverbgcolor)
button.setPressedBackgroundColor(pressedbgcolor)
def paintEvent(self, a0: QPaintEvent) -> None:
painter = QPainter(self)
# 绘制标题
painter.setFont(QFont("Microsoft YaHei", 10))
title = self.windowTitle()
painter.drawText(
self.si_separate.geometry(), Qt.AlignmentFlag.AlignCenter, title
)
return super().paintEvent(a0)
def resizeEvent(self, e):
self.client.resize(self.width(), self.height() - self.titleBar.height())
return super().resizeEvent(e)
def addTitleWidget(
self,
widget: QWidget,
place: typing.Literal["right", "left"] = "left",
index: int = 0,
):
"""往标题栏上添加控件"""
self.removeTitleWidget(widget) # 防止重复添加
if place == "right":
index = self.titleBar.hBoxLayout.indexOf(self.si_separate) + index + 1
self.titleBar.hBoxLayout.insertWidget(index, widget, 0)
def removeTitleWidget(self, widget: QWidget):
"""移除标题栏上的控件"""
self.titleBar.hBoxLayout.removeWidget(widget)
def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
if a0 == self.client:
if a1.type() in (QEvent.Type.Close, QEvent.Type.DeferredDelete):
self.close()
elif a1.type() == QEvent.Type.ParentChange:
if a0.parent() != self:
self.close()
return super().eventFilter(a0, a1)
def closeEvent(self, a0: QCloseEvent) -> None:
self.client.removeEventFilter(self)
self.client.close()
# 防止self.client被删除
if self.client.parent() == self:
self.client.setParent(None)
# 用户添加的按钮也不删除
for child in self.titleBar.findChildren(QWidget):
if child not in (
self.titleBar.minBtn,
self.titleBar.maxBtn,
self.titleBar.closeBtn,
):
child.setParent(None)
self.deleteLater()
return super().closeEvent(a0)
def showTitleMenu(self):
"""显示标题栏的右键菜单"""
menu = RoundMenu(self)
menu.addActions(self.titlemenu_actions)
menu.exec(QCursor.pos())
def event(self, a0: QEvent) -> bool:
# 这些事件必须发送给顶层窗口
if a0.type() == AddToTitleEvent.EventType:
self.addTitleWidget(a0.widget, a0.place, a0.index)
elif a0.type() == RemoveFromTitleEvent.EventType:
self.removeTitleWidget(a0.widget)
elif a0.type() == AddToTitleMenuEvent.EventType:
if a0.action not in self.titlemenu_actions:
self.titlemenu_actions.append(a0.action)
elif a0.type() == RemoveFromTitleMenuEvent.EventType:
if a0.action in self.titlemenu_actions:
self.titlemenu_actions.remove(a0.action)
elif a0.type() == QEvent.Type.Resize:
if self.windowState() != Qt.WindowState.WindowMaximized:
self.origin_size = self.size()
return super().event(a0)