实战PyQt5: 113-QSS+定制窗口的标题栏

定制标题栏

在前面的学习中可以看到,我们可以使用QSS为窗口的部件定义各种炫酷的效果,但是一个窗口的标题栏始终是和所使用的操作系统相关,在Win7下,是win7样式的标题栏,在Win10下是win10样式的标题栏,在Ubuntu下是Ubuntu样式的标题栏,Qt这样设计,保持了应用在不同的平台下与相应的系统的外观上的统一。但是也带来了一些问题,比如我们在窗口中使用深色主题,但是标题栏一直保持浅色主题,看起来有些不协调。如果想在标题栏和窗口统一使用一个主题样式,则需要对标题栏进行定制处理。

在Qt下,可以将窗口设置成无标题样式,我们可以在无标题样式下,布局一个自己需要的标题栏。定义对应标题栏按钮功能,同时需要添加对窗口的移动,缩放等操作。为了达到上述目的和方便移植,定义类WindowDragger来作为标题栏的父部件,它主要是处理一些鼠标事件和绘图事件。定义类FramelessWindow作为窗口的外框控件,使用其定义的setContent函数将要显示的窗口放入其中,就可以轻松完成标题栏的替换。

测试

演示工程代码文件包括:

  • resource.qrc, 定义资源文件;
  • windowdragger.py, 实现类WindowDragger,控制标题栏的鼠标操作和绘图控制;
  • framelesswindow.py, 实现类FramelessWindow,实现一个带定制标题栏的框架;
  • mainwindow.py, 定义主窗口;
  • fw_demo.py 主程序,运行它,演示最终效果。
  • images/icon_window_close.png, 标题栏的关闭图标;
  • images/icon_window_maximize.png, 标题栏的最大化图标;
  • images/icon_window_minimize.png, 标题栏的最小化图标;
  • images/icon_window_restore.png, 标题栏的恢复图标。

代码文件内容分别如下:

resource.qrc:

<RCC>
    <qresource prefix="/">
        <file>images/icon_window_close.png</file>
        <file>images/icon_window_maximize.png</file>
        <file>images/icon_window_minimize.png</file>
        <file>images/icon_window_restore.png</file>
    </qresource>
</RCC>

windowdragger.py:

from PyQt5.QtCore import pyqtSignal, QPoint
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget, QStyleOption, QStyle
 
class WindowDragger(QWidget):
    doubleClicked = pyqtSignal()
    
    def __init__(self, parent = None):
        super(WindowDragger, self).__init__(parent)
        
        self.mousePressed = False
        
    def mousePressEvent(self, event):
        self.mousePressed = True
        self.mousePos = event.globalPos()
        
        parent = self.parentWidget()
        if parent:
            parent = parent.parentWidget()
            
        if parent:
            self.wndPos = parent.pos()
            
    def mouseMoveEvent(self, event):
        parent = self.parentWidget()
        if parent:
            parent = parent.parentWidget()
            
        if parent and self.mousePressed:
            parent.move(self.wndPos + (event.globalPos() - self.mousePos))
    
    def mouseReleaseEvent(self, event):
        self.mousePressed = False
        
    def mouseDoubleClickEvent(self, event):
        self.doubleClicked.emit()
        
    def paintEvent(self, event):
        styleOption = QStyleOption()
        styleOption.initFrom(self)
        painter = QPainter(self)
        self.style().drawPrimitive(QStyle.PE_Widget, styleOption, painter, self)

framelesswindow.py:

import platform
 
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QEvent, QRect, QPoint
from PyQt5.QtGui import QIcon, QScreen, QColor, QPalette,QGuiApplication
from PyQt5.QtWidgets import (QWidget, QApplication, QDesktopWidget, QGraphicsDropShadowEffect,
                             QHBoxLayout, QVBoxLayout, QLabel, QToolButton, QSizePolicy, qApp)
 
from windowdragger import WindowDragger
import resource_rc
 
CONST_DRAG_BORDER_SIZE = 15
 
class FramelessWindow(QWidget):
    
    def __init__(self, parent = None):
        super(FramelessWindow,self).__init__(parent)
        
        self.mousePressed = False
        self.dragTop = False
        self.dragLeft = False
        self.dragRight = False
        self.dragBottom = False
        self.startGeometry = QRect()
        
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowSystemMenuHint)
        #为了在Windows系统下正确处理最小化函数,需要加上最小化标志按钮
        if platform.system() == 'Windows':
            self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)
            
        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAttribute(Qt.WA_TranslucentBackground)
        
        self.initUi()
        
        #窗口阴影
        windowShadow = QGraphicsDropShadowEffect()
        windowShadow.setBlurRadius(9.0)
        windowShadow.setColor(self.palette().color(QPalette.Highlight))
        windowShadow.setOffset(0.0)
        self.windowFrame.setGraphicsEffect(windowShadow)
               
        self.setMouseTracking(True)
        
        #监测所有子窗口的鼠标移动事件
        QApplication.instance().installEventFilter(self)
        
    def initUi(self):      
        self.setObjectName('FramelessWindow')
        
        #关闭按钮
        self.btnClose = QToolButton()
        self.btnClose.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.btnClose.setIcon(QIcon(':/images/icon_window_close.png'))
        self.btnClose.clicked.connect(self.close)
        #最大化按钮
        self.btnMaximize = QToolButton()
  
  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值