PyQt:【重磅干货】实现一个自定义样式的窗口(比如去掉边框、改变标题位置、窗口按钮样式)

如果想突破PyQt自带窗口的样式限制,比如同时去掉窗口的边框、改变边框、改变标题位置、窗口控制按钮等等,那就需要实现一个自定义样式的窗口,本文教你如何实现

先来看看PyQt创建窗口的默认样式:

在这里插入图片描述

再看看一个自定义样式的窗口:

在这里插入图片描述

可以看到,这里示例的自定义窗口去掉了窗口的边框、改变了标题位置、标题栏颜色、窗口控制按钮的样式、去掉了最大化按钮

上完整代码:


#-*- coding:utf-8 -*-

from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayout
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QFont, QCursor

class QTitleLabel(QLabel):
  """
  新建标题栏标签类
  """
  def __init__(self, *args):
    super(QTitleLabel, self).__init__(*args)
    self.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
    self.setFixedHeight(30)

class QTitleButton(QPushButton):
  """
  新建标题栏按钮类
  """
  def __init__(self, *args):
    super(QTitleButton, self).__init__(*args)
    self.setFont(QFont("Webdings")) # 特殊字体以不借助图片实现最小化最大化和关闭按钮
    self.setFixedWidth(40)

class QUnFrameWindow(QWidget):
  """
  无边框窗口类
  """
  def __init__(self):
    super(QUnFrameWindow, self).__init__(None, Qt.FramelessWindowHint) # 设置为顶级窗口,无边框
    self._padding = 5 # 设置边界宽度为5
    self.setGeometry(100, 100, 400, 300)
    self.initTitleLabel() # 安放标题栏标签
    self.setWindowTitle = self._setTitleText(self.setWindowTitle) # 用装饰器将设置WindowTitle名字函数共享到标题栏标签上
    self.setWindowTitle("自定义窗口")
    self.initLayout() # 设置框架布局
    self.setMinimumWidth(250)
    self.setMouseTracking(True) # 设置widget鼠标跟踪
    self.initDrag() # 设置鼠标跟踪判断默认值

  def initDrag(self):
    # 设置鼠标跟踪判断扳机默认值
    self._move_drag = False

  def initTitleLabel(self):
    # 安放标题栏标签
    self._TitleLabel = QTitleLabel(self)
    self._TitleLabel.setMouseTracking(True) # 设置标题栏标签鼠标跟踪(如不设,则标题栏内在widget上层,无法实现跟踪)
    self._TitleLabel.setIndent(150) # 设置标题栏文本缩进
    self._TitleLabel.move(0, 0) # 标题栏安放到左上角

  def initLayout(self):
    # 设置框架布局
    self._MainLayout = QVBoxLayout()
    self._MainLayout.setSpacing(0)
    self._MainLayout.addWidget(QLabel(), Qt.AlignLeft) # 顶一个QLabel在竖放框架第一行,以免正常内容挤占到标题范围里
    self._MainLayout.addStretch()
    self.setLayout(self._MainLayout)

  def addLayout(self, QLayout):
    # 给widget定义一个addLayout函数,以实现往竖放框架的正确内容区内嵌套Layout框架
    self._MainLayout.addLayout(QLayout)

  def _setTitleText(self, func):
    # 设置标题栏标签的装饰器函数
    def wrapper(*args):
      self._TitleLabel.setText(*args)
      return func(*args)
    return wrapper

  def setTitleAlignment(self, alignment):
    # 给widget定义一个setTitleAlignment函数,以实现标题栏标签的对齐方式设定
    self._TitleLabel.setAlignment(alignment | Qt.AlignVCenter)

  def setCloseButton(self, bool):
    # 给widget定义一个setCloseButton函数,为True时设置一个关闭按钮
    if bool == True:
      self._CloseButton = QTitleButton(b'\xef\x81\xb2'.decode("utf-8"), self)
      self._CloseButton.setObjectName("CloseButton") # 设置按钮的ObjectName以在qss样式表内定义不同的按钮样式
      self._CloseButton.setToolTip("关闭窗口")
      self._CloseButton.setMouseTracking(True) # 设置按钮鼠标跟踪(如不设,则按钮在widget上层,无法实现跟踪)
      self._CloseButton.setFixedHeight(self._TitleLabel.height()) # 设置按钮高度为标题栏高度
      self._CloseButton.clicked.connect(self.close) # 按钮信号连接到关闭窗口的槽函数

  def setMinMaxButtons(self, bool):
      # 给widget定义一个setMinMaxButtons函数,为True时设置最小化按钮
      if bool == True:
          self._MinimumButton = QTitleButton(b'\xef\x80\xb0'.decode("utf-8"), self)
          self._MinimumButton.setObjectName("MinMaxButton") # 设置按钮的ObjectName以在qss样式表内定义不同的按钮样式
          self._MinimumButton.setToolTip("最小化")
          self._MinimumButton.setMouseTracking(True) # 设置按钮鼠标跟踪(如不设,则按钮在widget上层,无法实现跟踪)
          self._MinimumButton.setFixedHeight(self._TitleLabel.height()) # 设置按钮高度为标题栏高度
          self._MinimumButton.clicked.connect(self.showMinimized) # 按钮信号连接到最小化窗口的槽函数

  def resizeEvent(self, QResizeEvent):
      # 自定义窗口调整大小事件
      self._TitleLabel.setFixedWidth(self.width()) # 将标题标签始终设为窗口宽度
      # 分别移动按钮到正确的位置
      try:
          self._CloseButton.move(self.width() - self._CloseButton.width(), 0)
      except:
          pass
      try:
          self._MinimumButton.move(self.width() - (self._CloseButton.width() + 1) * 2 + 1, 0)
      except:
          pass
  
  def mousePressEvent(self, event):
      # 重写鼠标点击的事件
      # 鼠标左键点击标题栏区域
      self._move_drag = True
      self.move_DragPosition = event.globalPos() - self.pos()
      event.accept()

  def mouseMoveEvent(self, QMouseEvent):
    # 鼠标手势
    self.setCursor(Qt.ArrowCursor)

    if Qt.LeftButton and self._move_drag:
      # 标题栏拖放窗口位置
      self.move(QMouseEvent.globalPos() - self.move_DragPosition)
      QMouseEvent.accept()

  def mouseReleaseEvent(self, QMouseEvent):
    # 鼠标释放后,各扳机复位
    self._move_drag = False

if __name__ == "__main__":
  from PyQt5.QtWidgets import QApplication
  import sys
  app = QApplication(sys.argv)
  app.setStyleSheet(open("./UnFrameStyle.qss").read())
  window = QUnFrameWindow()
  window.setCloseButton(True)
  window.setMinMaxButtons(True)
  window.show()
  sys.exit(app.exec_())

UnFrameStyle.qss文件中的代码:

/**********Title**********/
QTitleLabel{
    background-color: Gainsboro;
    font: 100 10pt;
}


/**********Button**********/
QTitleButton{
    background-color: rgba(255, 255, 255, 0);
    color: black;
    border: 0px;
    font: 100 10pt;
}
QTitleButton#MinMaxButton:hover{
    background-color: #D0D0D1;
    border: 0px;
    font: 100 10pt;
}
QTitleButton#CloseButton:hover{
    background-color: #D32424;
    color: white;
    border: 0px;
    font: 100 10pt;
}

有用点赞收藏加关注~

您可以使用PyQt5中的QMainWindow和QWidget实现自定义标题栏。下面是一个简单的示例代码,可以实现自定义标题栏: ```python from PyQt5.QtCore import Qt from PyQt5.QtGui import QMouseEvent from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QLabel, QPushButton class CustomTitleBar(QWidget): def __init__(self, parent=None): super().__init__(parent) self.setStyleSheet("background-color:rgb(38, 38, 38);") self.setFixedHeight(30) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.title = QLabel(self) self.title.setStyleSheet("color:white;") layout.addWidget(self.title, alignment=Qt.AlignCenter) self.minimize_button = QPushButton("-") self.minimize_button.clicked.connect(parent.showMinimized) layout.addWidget(self.minimize_button) self.close_button = QPushButton("x") self.close_button.clicked.connect(parent.close) layout.addWidget(self.close_button) def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.LeftButton: self.__mousePressPos = event.pos() super().mousePressEvent(event) def mouseMoveEvent(self, event: QMouseEvent) -> None: if event.buttons() == Qt.LeftButton: self.parent().move(event.globalPos() - self.__mousePressPos) super().mouseMoveEvent(event) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Custom Title Bar") self.setGeometry(100, 100, 500, 500) self.title_bar = CustomTitleBar(self) self.setCentralWidget(QWidget(self)) self.centralWidget().setStyleSheet("background-color:rgb(44, 44, 44);") self.setWindowFlags(Qt.FramelessWindowHint) layout = QHBoxLayout(self.centralWidget()) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(QLabel("Content", self.centralWidget()), alignment=Qt.AlignCenter) self.show() def setTitle(self, title): self.title_bar.title.setText(title) if __name__ == "__main__": import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) window = MainWindow() window.setTitle("Custom Title Bar") sys.exit(app.exec_()) ``` 这段代码中,我们首先定义了一个CustomTitleBar类,用于创建自定义标题栏。该类继承自QWidget,包含一个QHBoxLayout布局,用于添加标题和最小化、关闭按钮。我们还重载了mousePressEvent和mouseMoveEvent方法,用于实现拖动窗口的功能。 然后,我们创建了一个MainWindow类,继承自QMainWindow。在该类的构造函数中,我们创建了一个CustomTitleBar对象,并将其设置为窗口标题栏。我们还使用setCentralWidget方法设置了一个QWidget对象作为窗口的中心部件,用于显示窗口的内容。最后,我们使用setWindowFlags方法将窗口边框设置为无边框。 在主程序中,我们创建了一个QApplication对象和一个MainWindow对象,并设置了窗口标题。最后,我们调用app.exec_()方法启动应用程序。运行程序后,应该可以看到一个自定义标题栏和一个灰色的窗口内容区域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值