侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

PyQt5实现无边框窗口的标题拖动和窗口缩放

Python  /  管理员 发布于 5年前   335

网上找了半天都找不到好用的PyQt5无边框窗口的实现,借鉴部分前辈的窗口拖放代码,自己实现了一下无边框窗口,问题可能还有一点,慢慢改吧

先做个笔记

py文件

#!/usr/bin/env python#-*- coding:utf-8 -*-from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayoutfrom PyQt5.QtCore import Qt, QPointfrom PyQt5.QtGui import QFont, QCursorclass 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.initTitleLabel() # 安放标题栏标签    self.setWindowTitle = self._setTitleText(self.setWindowTitle) # 用装饰器将设置WindowTitle名字函数共享到标题栏标签上    self.setWindowTitle("UnFrameWindow")    self.initLayout() # 设置框架布局    self.setMinimumWidth(250)    self.setMouseTracking(True) # 设置widget鼠标跟踪    self.initDrag() # 设置鼠标跟踪判断默认值  def initDrag(self):    # 设置鼠标跟踪判断扳机默认值    self._move_drag = False    self._corner_drag = False    self._bottom_drag = False    self._right_drag = False  def initTitleLabel(self):    # 安放标题栏标签    self._TitleLabel = QTitleLabel(self)    self._TitleLabel.setMouseTracking(True) # 设置标题栏标签鼠标跟踪(如不设,则标题栏内在widget上层,无法实现跟踪)    self._TitleLabel.setIndent(10) # 设置标题栏文本缩进    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) # 按钮信号连接到最小化窗口的槽函数      self._MaximumButton = QTitleButton(b'\xef\x80\xb1'.decode("utf-8"), self)      self._MaximumButton.setObjectName("MinMaxButton") # 设置按钮的ObjectName以在qss样式表内定义不同的按钮样式      self._MaximumButton.setToolTip("最大化")      self._MaximumButton.setMouseTracking(True) # 设置按钮鼠标跟踪(如不设,则按钮在widget上层,无法实现跟踪)      self._MaximumButton.setFixedHeight(self._TitleLabel.height()) # 设置按钮高度为标题栏高度      self._MaximumButton.clicked.connect(self._changeNormalButton) # 按钮信号连接切换到恢复窗口大小按钮函数  def _changeNormalButton(self):    # 切换到恢复窗口大小按钮    try:      self.showMaximized() # 先实现窗口最大化      self._MaximumButton.setText(b'\xef\x80\xb2'.decode("utf-8")) # 更改按钮文本      self._MaximumButton.setToolTip("恢复") # 更改按钮提示      self._MaximumButton.disconnect() # 断开原本的信号槽连接      self._MaximumButton.clicked.connect(self._changeMaxButton) # 重新连接信号和槽    except:      pass  def _changeMaxButton(self):    # 切换到最大化按钮    try:      self.showNormal()      self._MaximumButton.setText(b'\xef\x80\xb1'.decode("utf-8"))      self._MaximumButton.setToolTip("最大化")      self._MaximumButton.disconnect()      self._MaximumButton.clicked.connect(self._changeNormalButton)    except:      pass  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) * 3 + 1, 0)    except:      pass    try:      self._MaximumButton.move(self.width() - (self._CloseButton.width() + 1) * 2 + 1, 0)    except:      pass    # 重新调整边界范围以备实现鼠标拖放缩放窗口大小,采用三个列表生成式生成三个列表    self._right_rect = [QPoint(x, y) for x in range(self.width() - self._padding, self.width() + 1)  for y in range(1, self.height() - self._padding)]    self._bottom_rect = [QPoint(x, y) for x in range(1, self.width() - self._padding) for y in range(self.height() - self._padding, self.height() + 1)]    self._corner_rect = [QPoint(x, y) for x in range(self.width() - self._padding, self.width() + 1)      for y in range(self.height() - self._padding, self.height() + 1)]  def mousePressEvent(self, event):    # 重写鼠标点击的事件    if (event.button() == Qt.LeftButton) and (event.pos() in self._corner_rect):      # 鼠标左键点击右下角边界区域      self._corner_drag = True      event.accept()    elif (event.button() == Qt.LeftButton) and (event.pos() in self._right_rect):      # 鼠标左键点击右侧边界区域      self._right_drag = True      event.accept()    elif (event.button() == Qt.LeftButton) and (event.pos() in self._bottom_rect):      # 鼠标左键点击下侧边界区域      self._bottom_drag = True      event.accept()    elif (event.button() == Qt.LeftButton) and (event.y() < self._TitleLabel.height()):      # 鼠标左键点击标题栏区域      self._move_drag = True      self.move_DragPosition = event.globalPos() - self.pos()      event.accept()  def mouseMoveEvent(self, QMouseEvent):    # 判断鼠标位置切换鼠标手势    if QMouseEvent.pos() in self._corner_rect:      self.setCursor(Qt.SizeFDiagCursor)    elif QMouseEvent.pos() in self._bottom_rect:      self.setCursor(Qt.SizeVerCursor)    elif QMouseEvent.pos() in self._right_rect:      self.setCursor(Qt.SizeHorCursor)    else:      self.setCursor(Qt.ArrowCursor)    # 当鼠标左键点击不放及满足点击区域的要求后,分别实现不同的窗口调整    # 没有定义左方和上方相关的5个方向,主要是因为实现起来不难,但是效果很差,拖放的时候窗口闪烁,再研究研究是否有更好的实现    if Qt.LeftButton and self._right_drag:      # 右侧调整窗口宽度      self.resize(QMouseEvent.pos().x(), self.height())      QMouseEvent.accept()    elif Qt.LeftButton and self._bottom_drag:      # 下侧调整窗口高度      self.resize(self.width(), QMouseEvent.pos().y())      QMouseEvent.accept()    elif Qt.LeftButton and self._corner_drag:      # 右下角同时调整高度和宽度      self.resize(QMouseEvent.pos().x(), QMouseEvent.pos().y())      QMouseEvent.accept()    elif Qt.LeftButton and self._move_drag:      # 标题栏拖放窗口位置      self.move(QMouseEvent.globalPos() - self.move_DragPosition)      QMouseEvent.accept()  def mouseReleaseEvent(self, QMouseEvent):    # 鼠标释放后,各扳机复位    self._move_drag = False    self._corner_drag = False    self._bottom_drag = False    self._right_drag = Falseif __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_())

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;}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    Pyqt实现无边框窗口拖动以及窗口大小改变
    下一条:
    利用numpy和pandas处理csv文件中的时间方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客