class FrameLessWindowUI(QWidget): """ 主窗口UI 无边框窗口的基本事件(放大缩小移动等)处理""" Left, Top, Right, Bottom, LeftTop, RightTop, LeftBottom, RightBottom = range( 8) # 枚举左上右下以及四个定点 MARGIN = 5 # 边缘宽度小用于调整窗口大小 def __init__(self, *args, **kwargs): super(FrameLessWindowUI, self).__init__(*args, **kwargs) main_layout = QVBoxLayout() main_layout.setContentsMargins( QMargins(self.MARGIN, self.MARGIN, self.MARGIN, self.MARGIN)) main_layout.setSpacing(0) self.setWindowIcon(QIcon("media/logo.png")) self.setWindowTitle("分析决策系统") # 基本事件属性设置 self.setMouseTracking(True) self._pressed = False self._direction = None self._mouse_pos = None self.title_bar = TitleBarUI(self) # 窗口标题栏 main_layout.addWidget(self.title_bar, alignment=Qt.AlignTop) self.navigation_bar = NavigationBar(self) # 菜单和用户状态栏 main_layout.addWidget(self.navigation_bar, alignment=Qt.AlignTop) self.center_widget = QMainWindow() # 模块窗体显示窗口 self.center_widget.setContentsMargins(QMargins(2, 0, 2, 2)) main_layout.addWidget(self.center_widget) self.setLayout(main_layout) # 样式,属性,大小设置 self.title_bar.installEventFilter(self) # 安装事件过滤进入标题栏还原鼠标样式 self.navigation_bar.installEventFilter(self) self.center_widget.installEventFilter(self) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint) available_size = QDesktopWidget().availableGeometry( ) # 用户的桌面信息,来改变自身窗体大小 available_width, available_height = available_size.width( ), available_size.height() self.resize(available_width * 0.75, available_height * 0.8) self.setMaximumSize(available_width, available_height) # 最大为用户桌面大小 self.setMinimumSize(available_width * 0.5, available_height * 0.5) # 最小为用户桌面大小的一半 self.setAttribute(Qt.WA_TranslucentBackground, True) # 窗口透明 self.center_widget.setAutoFillBackground(True) # 被窗口透明影响,自动填充 self.center_widget.setObjectName("centerWidget") self.setStyleSheet( "#centerWidget{background-color:rgb(255,255,255);border:2px solid rgb(34,102,175);border-top:none;" "border-bottom-right-radius:5px;border-bottom-left-radius:5px}") def eventFilter(self, obj, event): """ 事件过滤器, 用于解决鼠标进入其它控件后还原为标准鼠标样式 """ if isinstance(event, QEnterEvent): self.setCursor(Qt.ArrowCursor) self._direction = None # 去除方向 self._pressed = None # 去除按下标记 return super(FrameLessWindowUI, self).eventFilter(obj, event) def mousePressEvent(self, event): """ 鼠标按下 """ super(FrameLessWindowUI, self).mousePressEvent(event) if event.button() == Qt.LeftButton: self._mouse_pos = event.pos() self._pressed = True def mouseReleaseEvent(self, event): """ 鼠标弹起事件 """ super(FrameLessWindowUI, self).mouseReleaseEvent(event) self._pressed = False self._direction = None # 鼠标移动事件(只有边框MARGIN大小范围有效果,因为其他的是其子控件)(会捕获子控件的鼠标按住移动的事件) def mouseMoveEvent(self, event): super(FrameLessWindowUI, self).mouseMoveEvent(event) pos = event.pos() pos_x, pos_y = pos.x(), pos.y() wm, hm = self.width() - self.MARGIN, self.height() - self.MARGIN # print(wm, hm) # 窗口最大无需事件 if self.isMaximized() or self.isFullScreen(): self._direction = None self.setCursor(Qt.ArrowCursor) return if event.buttons() == Qt.LeftButton and self._pressed: self.resize_window(pos) if pos_x <= self.MARGIN and pos_y <= self.MARGIN: # 左上角 self._direction = self.LeftTop self.setCursor(Qt.SizeFDiagCursor) elif wm <= pos_x <= self.width() and hm <= pos_y <= self.height(): # 右下角 self._direction = self.RightBottom self.setCursor(Qt.SizeFDiagCursor) elif wm <= pos_x and pos_y <= self.MARGIN: # 右上角 self._direction = self.RightTop self.setCursor(Qt.SizeBDiagCursor) elif pos_x <= self.MARGIN and hm <= pos_y: # 左下角 self._direction = self.LeftBottom self.setCursor(Qt.SizeBDiagCursor) elif 0 <= pos_x <= self.MARGIN <= pos_y <= hm: # 左边 self._direction = self.Left self.setCursor(Qt.SizeHorCursor) elif wm <= pos_x <= self.width() and self.MARGIN <= pos_y <= hm: # 右边 self._direction = self.Right self.setCursor(Qt.SizeHorCursor) elif wm >= pos_x >= self.MARGIN >= pos_y >= 0: # 上面 self._direction = self.Top self.setCursor(Qt.SizeVerCursor) elif self.MARGIN <= pos_x <= wm and hm <= pos_y <= self.height(): # 下面 self._direction = self.Bottom self.setCursor(Qt.SizeVerCursor) def paintEvent(self, event): """ 由于是全透明背景窗口,重绘事件中绘制透明度为1的难以发现的边框,用于调整窗口大小 """ super(FrameLessWindowUI, self).paintEvent(event) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.setPen(QPen(QColor(255, 255, 255, 1), self.MARGIN * 2)) painter.drawRect(self.rect()) def resize_window(self, pos): """ 调整窗口大小 """ if self._direction is None: return mpos = pos - self._mouse_pos xPos, yPos = mpos.x(), mpos.y() geometry = self.geometry() x, y, w, h = geometry.x(), geometry.y(), geometry.width( ), geometry.height() if self._direction == self.LeftTop: # 左上角 if w - xPos > self.minimumWidth(): x += xPos w -= xPos if h - yPos > self.minimumHeight(): y += yPos h -= yPos elif self._direction == self.RightBottom: # 右下角 if w + xPos > self.minimumWidth(): w += xPos self._mouse_pos = pos if h + yPos > self.minimumHeight(): h += yPos self._mouse_pos = pos elif self._direction == self.RightTop: # 右上角 if h - yPos > self.minimumHeight(): y += yPos h -= yPos if w + xPos > self.minimumWidth(): w += xPos self._mouse_pos.setX(pos.x()) elif self._direction == self.LeftBottom: # 左下角 if w - xPos > self.minimumWidth(): x += xPos w -= xPos if h + yPos > self.minimumHeight(): h += yPos self._mouse_pos.setY(pos.y()) elif self._direction == self.Left: # 左边 if w - xPos > self.minimumWidth(): x += xPos w -= xPos else: return elif self._direction == self.Right: # 右边 if w + xPos > self.minimumWidth(): w += xPos self._mouse_pos = pos else: return elif self._direction == self.Top: # 上面 if h - yPos > self.minimumHeight(): y += yPos h -= yPos else: return elif self._direction == self.Bottom: # 下面 if h + yPos > self.minimumHeight(): h += yPos self._mouse_pos = pos else: return self.setGeometry(x, y, w, h) def showMaximized(self): """ 窗口最大化去除边界MARGIN """ super(FrameLessWindowUI, self).showMaximized() self.layout().setContentsMargins(0, 0, 0, 0) def showNormal(self): """ 还原保留调整大小的边界 """ super(FrameLessWindowUI, self).showNormal() self.layout().setContentsMargins(self.MARGIN, self.MARGIN, self.MARGIN, self.MARGIN)
def __init__(self, w_window: QMainWindow) -> None: super().__init__(w_window) self._w_window = w_window # Main Qt window. w_window.installEventFilter(self)