图形和特效
使用PyQt
实现的窗口样式,默认使用的是当前操作系统的原生窗口样式,我们需要定制窗口样式,实现统一美化的窗口界面。
窗口风格
获得当前平台支持的原有的QStyle
样式:QStyleFactory.keys()
对QApplication
设置QStyle
样式:QApplication.setStyle(QStyleFactory.create("WindowsXP"))
可以为每个Widget
设置风格:setStyle(QStyle style)
若其他的Widget
没有设置风格,默认使用QApplication
设置的QStyle
案例--查看支持的窗口风格,选择一类进行设置
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import QtCore
from PyQt5.QtGui import *
class AppWidget( QWidget):
def __init__(self, parent=None):
super(AppWidget, self).__init__(parent)
self.setWindowTitle("界面风格例子")
horizontalLayout = QHBoxLayout()
self.styleLabel = QLabel("Set Style:") # 设置提示信息
self.styleComboBox = QComboBox() # 创建一个列表框
self.styleComboBox.addItems( QStyleFactory.keys()) # 从QStyleFactory增加 styles到列表框中
# 选择当前界面风格
index = self.styleComboBox.findText(
QApplication.style().objectName(),
QtCore.Qt.MatchFixedString)
# 设置当前列表框的界面风格
self.styleComboBox.setCurrentIndex(index)
# 通过comboBox选择界面分割
self.styleComboBox.activated[str].connect(self.handleStyleChanged)
horizontalLayout.addWidget(self.styleLabel)
horizontalLayout.addWidget(self.styleComboBox)
self.setLayout(horizontalLayout)
# 改变界面风格
def handleStyleChanged(self, style):
QApplication.setStyle(style)
if __name__ == "__main__":
app = QApplication(sys.argv)
widgetApp = AppWidget()
widgetApp.show()
sys.exit(app.exec_())
窗口样式
PyQt
使用setWindowFlags(Qt.WindowFlags)
函数设置窗口样式
PyQt
下的基本窗口类型:
窗口类型 | 描述 |
---|---|
Qt.Widget | 默认窗口,有最小化、最大化、关闭按钮 |
Qt.Window | 普通窗口,有最小化、最大化、关闭按钮 |
Qt.Dialog | 对话框窗口,有问号和关闭按钮 |
Qt.Popup | 弹出窗口,窗口无边框 |
Qt.ToolTip | 提示窗口,窗口无边框,无任务栏 |
Qt.SplashScreen | 闪屏,窗口无边框,无任务栏 |
Qt.SubWindow | 子窗口,窗口无按钮,有标题 |
自定义顶层窗口外观标志:
标志 | 描述 |
---|---|
Qt.MSWindowsFixedSizeDialogHint | 窗口无法调整大小 |
Qt.FramelessWindowHint | 窗口无边框 |
Qt.CustomizeWindowHint | 有边框但无标题栏和按钮,不能移动和拖动 |
Qt.WindowTitleHint | 添加标题栏和一个关闭按钮 |
Qt.WindowSystemMenuHint | 添加系统目录和一个关闭按钮 |
Qt.WindowMaximizeButtonHint | 激活最大化和关闭按钮,禁止最小化按钮 |
Qt.WindowMinimizeButtonHint | 激活最小化和关闭按钮,禁止最大化按钮 |
Qt.WindowMinMaxButtonHint | 激活最小化、最大化和关闭按钮 |
Qt.WindowCloseButtonHint | 添加一个关闭按钮 |
Qt.WindowContextHelpButtonHint | 添加问号和关闭按钮,像对话框一样 |
Qt.WindowStaysOnTopHint | 窗口始终处于顶层位置 |
Qt.WindowStaysOnBottomHint | 窗口始终处于底层位置 |
设置窗口样式:如设置窗口无边框:self.setWindowFlags(Qt.FramelessWindowHint)
案例--使用自定义的无边框窗口
我们可以自定义一个无边框窗口,其可以100%占用用户的屏幕
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QMainWindow , QApplication
from PyQt5.QtCore import Qt
# 自定义窗口类
class MyWindow( QMainWindow):
def __init__(self,parent=None):
super(MyWindow,self).__init__(parent)
self.setWindowFlags(Qt.FramelessWindowHint) # 设置窗口标记(无边框)
self.setStyleSheet('''background-color:blue; ''') # 便于显示,设置窗口背景颜色(采用QSS)
# 覆盖函数
def showMaximized(self):
desktop = QApplication.desktop() # 得到桌面控件
rect = desktop.availableGeometry() # 得到屏幕可显示尺寸
self.setGeometry(rect) # 设置窗口尺寸
self.show() # 设置窗口显示
### 主函数
if __name__ == "__main__":
app = QApplication(sys.argv) # 声明变量
window = MyWindow() # 创建窗口
window.showMaximized() # 调用最大化显示
sys.exit(app.exec_()) # 应用程序事件循环
绘图
图像类
PyQt
中常用的图像类有四个:QPixmap
、QImage
、QPicture
、QBitmap
QPixmap
:专门为绘图设计,在绘制图片时要使用。QImage
:提供一个与硬件无关的图像表示函数,可以用于图片的像素级访问。QPicture
:绘图设备类,继承自QPainter
,使用QPainter
的begin()
函数在QPicture
上绘图,使用end()
函数结束绘图,使用QPicture的save()
函数将QPainter
所使用过的绘图指令保存到文件中。QBitmap
:是一个继承自QPixmap
的简单类,提供了1bit深度的二值图像的类。
案例--实现基本的画线功能
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication ,QWidget
from PyQt5.QtGui import QPainter ,QPixmap
from PyQt5.QtCore import Qt , QPoint
class Winform(QWidget):
def __init__(self,parent=None):
super(Winform,self).__init__(parent)
self.setWindowTitle("绘图例子")
self.pix = QPixmap()
self.lastPoint = QPoint()
self.endPoint = QPoint()
self.initUi()
def initUi(self):
self.resize(600, 500) # 窗口大小设置为600*500
# 画布大小为400*400,背景为白色
self.pix = QPixmap(400, 400)
self.pix.fill(Qt.white)
def paintEvent(self,event): # 重构paintEvent函数
pp = QPainter( self.pix)
pp.drawLine( self.lastPoint, self.endPoint) # 根据鼠标指针前后两个位置绘制直线
self.lastPoint = self.endPoint # 让前一个坐标值等于后一个坐标值,这样就能实现画出连续的线
painter = QPainter(self)
painter.drawPixmap(0, 0, self.pix)
def mousePressEvent(self, event) : # 重构mousePressEvent函数,使用两个点来绘制线条,点从鼠标事件中获取
# 鼠标左键按下
if event.button() == Qt.LeftButton :
self.lastPoint = event.pos()
self.endPoint = self.lastPoint
def mouseMoveEvent(self, event): # 重构mouseMoveEvent函数
# 鼠标左键按下的同时移动鼠标
if event.buttons() and Qt.LeftButton :
self.endPoint = event.pos()
# 进行重新绘制
self.update()
def mouseReleaseEvent( self, event):
# 鼠标左键释放
if event.button() == Qt.LeftButton :
self.endPoint = event.pos()
# 进行重新绘制
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Winform()
form.show()
sys.exit(app.exec_())
程序运行结果:按住鼠标左键在画板上进行绘画,释放鼠标左键结束绘画。
QSS
的UI
美化
QSS
即Qt
样式表,用来自定义控件外观的一种机制,QSS
使界面美化跟代码层分开,利于维护。
QSS
的语法规则
QSS
样式由两部分组成,其中一部分是选择器,指定受影响的控件;另一部分是声明,指定哪些属性应该在控件上进行设置,声明部分是一系列的“属性:值”对,使用(;)分隔各个不同的属性值对,使用({})将所有的声明包括在内。
如设置QPushButton
类及其子类的所有实例的前景色是红色:QPushButton {color:red}
QPushButton
表示选择器,指定所有的QPushButton
类及其子类都会受到影响;{color:red}
是规则的定义,表示前景色为红色。
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
import sys
class WindowDemo(QWidget):
def __init__(self ):
super().__init__()
# 创建相关控件
btn1 = QPushButton(self )
btn1.setText('按钮1')
btn2 = QPushButton(self )
btn2.setText('按钮2')
# 布局
vbox=QVBoxLayout()
vbox.addWidget(btn1)
vbox.addWidget(btn2)
self.setLayout(vbox)
self.setWindowTitle("QSS样式")
if __name__ == "__main__":
app = QApplication(sys.argv)
win = WindowDemo()
# 加载了自定义的QSS样式,窗口按钮的背景颜色为红色,字体颜色为蓝色
qssStyle = '''
QPushButton {background-color: red}
QPushButton {color: blue}
'''
win.setStyleSheet( qssStyle )
win.show()
sys.exit(app.exec_())
还可以使用多个选择器指定相关声明:QPushButton, QLineEdit, QComboBox {color:bule}
QSS
选择器类型
通配选择器:* 匹配所以控件
类型选择器:
QPushButton
匹配所有的QPushButton
类及其子类的实例属性选择器:
QPushButton[name = "myBtn"]
匹配所有的name
属性是myBtn
的QPushButton
实例
# 给按钮btn2设置属性名
btn2 = QPushButton(self )
btn2.setProperty( 'name' , 'myBtn' )
btn2.setText('按钮2')
# 修改属性名为myBtn的QPushButton,改变其背景颜色
qssStyle = '''
QPushButton[name = "myBtn"] {background-color: red}
'''
- 类选择器:
.QPushButton
匹配所有的QPushButton
实例,但是不匹配其子类。 - ID选择器:
#myButton
匹配所有ID
为myButton
的控件,ID
是objectName
指定的值。 - 后代选择器:
QDialog QPushButton
匹配所有的QDialog
容器中包含的QPushButton
,不管是直接还是间接的。 - 子选择器:
QDialog > QPushButton
匹配所有的QDialog
容器中包含的QPushButton
,其中要求QPushButton
的直接父容器是QDialog
QSS
子控件
QSS
子控件实际上也是一种选择器,应用在一些复合控件上,典型的如:QComboBox
子控件列表:
子控件 | 描述 |
---|---|
::add-line | 用于添加 QScrollBar 行的按钮 |
::add-page | 手柄(滑块)和 QScrollBar 的添加行之间的区域 |
::branch | QTreeView 的分支指示器 |
::chunk | QProgressBar 的进度块 |
::close-button | QDockWidget 的关闭按钮或 QTabBar 的选项卡 |
::corner | QAbstractScrollArea 中两个滚动条之间的角 |
::down-arrow | QComboBox,QHeaderView(排序指示器),QScrollBar或QSpinBox的向下箭头 |
::down-button | QScrollBar 或 QSpinBox 的向下按钮 |
::drop-down | QComboBox 的下拉按钮 |
::float-button | QDockWidget 的浮点按钮 |
::groove | QSlider的凹槽 |
::indicator | QAbstractItemView、QCheckBox、QRadioButton、可检查QMenu项目或可检查QGroupBox的指标 |
::handle | QScrollBar、QSplitter 或 QSlider 的手柄(滑块) |
::icon | QAbstractItemView 或 QMenu 的图标 |
::item | QAbstractItemView、QMenuBar、QMenu 或 QStatusBar 的项 |
::left-arrow | QScrollBar 的左箭头 |
::left-corner | QTabWidget 的左上角。例如,此控件可用于控制 QTabWidget 中左上角小部件的位置 |
::menu-arrow | 带有菜单的 QToolButton 的箭头 |
::menu-button | QToolButton 的菜单按钮 |
::menu-indicator | QPush按钮的菜单指示器 |
::right-arrow | QMenu 或 QScrollBar 的右箭头 |
::pane | QTabWidget 的窗格(框架) |
::right-corner | QTabWidget 的右上角。例如,此控件可用于控制 QTabWidget 中右上角小部件的位置 |
::scroller | QMenu 或 QTabBar 的滚动条 |
::section | QHeaderView 的部分 |
::separator | QMenu 或 QMainWindow 中的分隔符 |
::sub-line | 用于减去 QScrollBar 的一行的按钮 |
::sub-page | 控点(滑块)和 QScrollBar 的子行之间的区域 |
::tab | QTabBar 或 QToolBox 的选项卡 |
::tab-bar | QTabWidget 的标签栏。此子控件仅用于控制 QTabWidget 中 QTabBar 的位置。使用 ::tab 子控件设置选项卡样式 |
::tear | QTabBar 的撕裂指示器 |
::tearoff | QMenu 的撕下指示器 |
::text | QAbstractItemView 的文本 |
::title | QGroupBox 或 QDockWidget 的标题 |
::up-arrow | QHeaderView(排序指示器)、QScrollBar 或 QSpinBox 的向上箭头 |
::up-button | QSpinBox 的向上按钮 |
为其下来箭头自定义图片:
# 创建下拉文本框控件
combo = QComboBox(self)
combo.setObjectName('myQComboBox')
combo.addItem('Window')
combo.addItem('Ubuntu')
combo.addItem('Red Hat')
# 子控件选择器是选择复合控件的一部分,对复合控件的一部分应用样式,指定的是下拉箭头,而不是下拉框本身
qssStyle = '''
QComboBox#myQComboBox::drop-down {image: url( ./images/dropdown.png)}
'''
QSS
伪状态
QSS
伪状态选择器是以冒号开头的一个表达式,如:hover
,表示当鼠标指针经过时的状态,伪状态选择器限制了当控件处于某种状态时才可以使用QSS规则。
伪状态只能描述一个控件或者一个复合控件的子控件的状态,所以它只能放在选择器的最后面。
如:QPushButton:hover{background-color: red}
当鼠标经过时,该控件的背景颜色变成红色。
伪状态还可以描述子控件选择的复合控件的子控件的状态,但必须放在最后:
QComboBox::drop-down:hover{background-color: red}
当鼠标经过下拉箭头时,该下拉箭头背景变成红色。
QSS
的伪状态:多种伪状态可以同时组合使用,如:hover:checked
:!hover
表示其逆状态 一些特定的伪状态只能用在特定的控件上
伪状态 | 描述 |
---|---|
:active | 当小组件驻留在活动窗口中时,将设置此状态 |
:adjoins-item | 当 QTreeView 的 ::branch与一个item相邻时,将设置此状态。 |
:alternate | 当 QAbstractItemView::alternatingRowColors() 设置为 true 时,将为绘制 QAbstractItemView 行的每个交替行设置此状态 |
:bottom | 该项目位于底部。例如,其选项卡位于底部的 QTabBar |
:checked | 该项目已选中。例如,QAbstractButton 的已检查状态 |
:closable | 可以关闭这些项目。例如,QDockWidget 打开了 QDockWidget:😄 ockWidgetClosable 功能 |
:closed | 项目处于关闭状态。例如,QTreeView 中的非展开项 |
:default | 该项为默认值。例如,默认 QPushButton 或 QMenu 中的默认操作 |
:disabled | 该项目已禁用 |
:editable | QComboBox 是可编辑的 |
:edit-focus | 该项目具有编辑焦点(请参阅 QStyle::State_HasEditFocus)。此状态仅适用于 Qt 扩展应用程序 |
:enabled | 该项目已启用 |
:exclusive | 该物料是独占物料组的一部分。例如,独占 QActionGroup 中的菜单项 |
:first | 该项是第一个(在列表中)。例如,QTabBar 中的第一个选项卡 |
:flat | 该项目是平坦的。例如,一个平面的QPushButton |
:floatable | 这些项目可以浮动。例如,QDockWidget 打开了 QDockWidget:😄 ockWidgetFloatable 功能 |
:focus | 该项目具有输入焦点 |
:has-children | 项目具有子项。例如,QTreeView 中具有子项的项 |
:has-siblings | 该项目有同级。例如,QTreeView 中的同级项目 |
:horizontal | 项目具有水平方向 |
:hover | 鼠标悬停在项目上 |
:indeterminate | 项目具有不确定状态。例如,QCheckBox 或 QRadioButton 被部分选中 |
:last | 该项是最后一个(在列表中)。例如,QTabBar 中的最后一个选项卡 |
:left | 该项目位于左侧。例如,选项卡位于左侧的 QTabBar |
:maximized | 项目最大化。例如,最大化的 QMdiSubWindow |
:middle | 该项位于中间(在列表中)。例如,不在 QTabBar 的开头或结尾的选项卡 |
:minimized | 该项目已最小化。例如,最小化的 QMdiSubWindow |
:movable | 该项目可以四处移动。例如,QDockWidget 打开了 QDockWidget:😄 ockWidgetMovable 功能 |
:no-frame | 项目没有框架。例如,无框QSpinBox或QLineEdit |
:non-exclusive | 物料是非独占物料组的一部分。例如,非独占 QActionGroup 中的菜单项 |
:off | 对于可以切换的项目,这适用于处于“关闭”状态的项目 |
:on | 对于可以切换的项目,这适用于处于“打开”状态的小部件 |
:only-one | 该项是唯一的项(在列表中)。例如,QTabBar 中的单个选项卡 |
:open | 项目处于打开状态。例如,QTreeView 中的展开项,或者带有打开菜单的 QComboBox 或 QPushButton |
:next-selected | 下一个项目(在列表中)被选中。例如,QTabBar 的选定选项卡位于此项旁边 |
:pressed | 正在使用鼠标按下该项目 |
:previous-selected | 上一项(在列表中)处于选中状态。例如,QTabBar 中所选选项卡旁边的选项卡 |
:read-only | 项目标记为只读或不可编辑。例如,只读 QLineEdit 或不可编辑的 QComboBox |
:right | 该项目位于右侧。例如,选项卡位于右侧的 QTabBar |
:selected | 项目处于选中状态。例如,QTabBar 中的选定选项卡或 QMenu 中的选定项 |
:top | 该项目位于顶部。例如,其选项卡位于顶部的 QTabBar |
:unchecked | 该项目处于未选中状态 |
:vertical | 该项目具有垂直方向 |
:window | 小部件是一个窗口(即顶级小部件) |
设置窗口背景
窗口背景包括背景色和背景图片
使用QSS
设置窗口背景
在QSS
中,可以通过background
或者background-color
的方式来设置背景色,设置窗口的背景色后,子控件会默认继承父窗口的背景颜色,要想为控件设置背景图片或图标,可以使用setPixmap
或者setIcon
来完成。
使用setStyleSheet()
设置窗口背景图片
使用setStyleSheet()
来添加背景图片
win = QMainWindow()
# 设置窗口名
win.setObjectName("MainWindow")
# 设置图片的相对路径添加,当前文件夹下有images文件夹,images文件夹中有python.jpg图片
win.setStyleSheet("#MainWindow{border-image:url(images/python.jpg);}")
# 设置图片的绝对路径,从c盘/d盘或其他盘开始,可以点击图片的详情查看
win.setStyleSheet("#MainWindow{border-image:url(c:/images/python.jpg);}")
使用setStyleSheet()
设置窗口背景颜色
win = QMainWindow()
# 设置窗口名
win.setObjectName("MainWindow")
# 设置窗口的背景颜色
win.setStyleSheet("#MainWindow{background-color: yellow}")
使用QPalette
设置窗口背景
使用QPalette
(调色板)设置窗口背景图片
使用QPalette
设置背景图片时,要考虑背景图片的尺寸,当背景图片的宽度和高度大于窗口的宽度和高度时,背景图片会平铺整个背景;当背景图片的宽度和高度小于窗口的宽度和高度时,会加载多个背景图片。给窗口设置背景时,要看图片的分辨率和设置的窗口大小win.resize(460,255)
进行比较。
win = QMainWindow()
palette = QPalette()
palette.setBrush(QPalette.Background,QBrush(QPixmap("./images/python.jpg")))
win.setPalette(palette)
win.resize(460, 255 )
使用QPalette
(调色板)设置窗口背景颜色
win = QMainWindow()
palette = QPalette()
palette.setColor(QPalette.Background , Qt.red)
win.setPalette(palette)
使用paintEvent
设置窗口背景
使用paintEvent
设置窗口背景
def paintEvent(self,event): # 重载paintEvent,不需要调用,作为方法直接放入
painter = QPainter(self)
pixmap = QPixmap("./images/screen1.jpg")
# 绘制窗口背景,平铺到整个窗口,随着窗口改变而改变
painter.drawPixmap(self.rect(),pixmap)
使用paintEvent
设置窗口背景颜色
def paintEvent(self,event): # 重载paintEvent,不需要调用,作为方法直接放入
painter = QPainter(self)
painter.setBrush(Qt.yellow );
painter.drawRect(self.rect());
不规则窗口的显示
QWidget
类中重要的绘图函数:
函数 | 描述 |
---|---|
setMask(self, QBitmap) setMask(self, QRegion) | setMask()的作用是为调用它的控件增加一个遮罩,遮住所选区域外的部分,使看起来透明,它的参数可以为QBitmap或QRegion对象,调用QPixmap的mask()函数获得图片自身的遮罩,是一个QBitmap对象 |
paintEvent(self, QPaintEvent) | 通过重载paintEvent()函数绘制窗口背景 |
案例--实现不规则窗口的最简单方式是图片素材既当遮罩层又当背景图片
通过重载paintEvent()
函数绘制窗口背景
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication ,QWidget
from PyQt5.QtGui import QPixmap, QPainter , QBitmap
class Winform(QWidget):
def __init__(self,parent=None):
super(Winform,self).__init__(parent)
self.setWindowTitle("不规则窗体的实现例子")
self.resize(600, 400)
def paintEvent(self,event):
painter = QPainter(self)
painter.drawPixmap(0,0,280,390,QPixmap(r"./images/dog.jpg")) # 获取图片
painter.drawPixmap(300,0,280,390,QBitmap(r"./images/dog.jpg")) # 获取图片遮罩
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Winform()
form.show()
sys.exit(app.exec_())
案例--使用一张遮罩图片来控制窗口大小,再用paintEvent()
函数重绘窗口背景图
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication ,QWidget
from PyQt5.QtGui import QPixmap, QPainter , QBitmap
class Winform(QWidget):
def __init__(self,parent=None):
super(Winform,self).__init__(parent)
self.setWindowTitle("不规则窗体的实现例子")
self.pix = QBitmap("./images/mask.png")
self.resize(self.pix.size())
self.setMask(self.pix)
def paintEvent(self,event):
painter = QPainter(self)
# 在指定区域直接绘制窗口背景
painter.drawPixmap(0,0,self.pix.width(),self.pix.height(),QPixmap("./images/screen1.jpg"))
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Winform()
form.show()
sys.exit(app.exec_())
程序运行结果:窗口背景图片是不能移动的
案例--实现可以拖动的不规则窗口
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication ,QWidget
from PyQt5.QtGui import QPixmap, QPainter , QCursor , QBitmap
from PyQt5.QtCore import Qt
class ShapeWidget(QWidget):
def __init__(self,parent=None):
super(ShapeWidget,self).__init__(parent)
self.setWindowTitle("不规则的,可以拖动的窗体实现例子")
self.mypix()
# 显示不规则 pic
def mypix(self):
self.pix = QBitmap( "./images/mask.png" )
self.resize(self.pix.size())
self.setMask(self.pix)
print( self.pix.size())
self.dragPosition = None
# 重定义鼠标按下响应函数mousePressEvent(QMouseEvent)和鼠标移动响应函数mouseMoveEvent(QMouseEvent),使不规则窗体能响应鼠标事件,随意拖动。
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.m_drag=True
self.m_DragPosition=event.globalPos()-self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
if event.button()==Qt.RightButton:
self.close()
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
# 当左键移动窗体修改偏移值
self.move(QMouseEvent.globalPos()- self.m_DragPosition )
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag=False
self.setCursor(QCursor(Qt.ArrowCursor))
# 一般 paintEvent 在窗体首次绘制加载, 要重新加载paintEvent 需要重新加载窗口使用 self.update() or self.repaint()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(0,0,self.width(),self.height(),QPixmap("./images/boy.png"))
if __name__ == '__main__':
app=QApplication(sys.argv)
form=ShapeWidget()
form.show()
app.exec_()
程序运行结果:生成背景图片,图片可以鼠标左键按住移动位置。
不规则窗口实现动画效果
通过PyQt
设计不规则窗口的动画效果,显示不规则图片需注意:
pixmap.setMask()
函数的作用是为调用它的控件添加一个遮罩,遮住所选的区域外的部分,使控件看起来是透明的。paintEvent()
函数每次初始化窗口只调用一次,所以每加载一次图片就要重新调用一次paintEvent()
函数
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication ,QWidget
from PyQt5.QtGui import QPixmap, QPainter , QCursor
from PyQt5.QtCore import Qt, QTimer
class ShapeWidget(QWidget):
def __init__(self,parent=None):
super(ShapeWidget,self).__init__(parent)
self.i = 1
self.mypix()
self.timer = QTimer()
self.timer.setInterval(500) # 500毫秒
self.timer.timeout.connect(self.timeChange)
self.timer.start()
# 显示不规则 pic
def mypix(self):
self.update()
if self.i == 5:
self.i = 1
self.mypic = {1: './images/left.png', 2: "./images/up.png", 3: './images/right.png', 4: './images/down.png'}
self.pix = QPixmap(self.mypic[self.i], "0", Qt.AvoidDither | Qt.ThresholdDither | Qt.ThresholdAlphaDither)
self.resize(self.pix.size())
self.setMask(self.pix.mask())
self.dragPosition = None
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.m_drag=True
self.m_DragPosition=event.globalPos()-self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos()- self.m_DragPosition )
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag=False
self.setCursor(QCursor(Qt.ArrowCursor))
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(0, 0, self.pix.width(),self.pix.height(),self.pix)
# 鼠标双击事件
def mouseDoubleClickEvent(self, event):
if event.button() == 1:
self.i += 1
self.mypix()
# 每500毫秒修改paint
def timeChange(self):
self.i += 1
self.mypix()
if __name__ == '__main__':
app = QApplication(sys.argv)
form = ShapeWidget()
form.show()
sys.exit(app.exec_())
运行上述例子,会弹出一个窗口,显示不同方向的箭头,每500毫秒改变一次,按照上,右,下,左方向转动
案例--加载GIF
动画效果
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QLabel ,QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QMovie
class LoadingGifWin( QWidget):
def __init__(self,parent=None):
super(LoadingGifWin, self).__init__(parent)
self.label = QLabel('', self)
self.setFixedSize(128,128)
self.setWindowFlags( Qt.Dialog| Qt.CustomizeWindowHint)
self.movie = QMovie("./images/loading.gif")
self.label.setMovie(self.movie)
self.movie.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
loadingGitWin = LoadingGifWin()
loadingGitWin.show()
sys.exit(app.exec_())
设置样式
为标签添加背景图片
label1 = QLabel(self)
label1.setToolTip('这是一个文本标签')
label1.setStyleSheet("QLabel{border-image: url(./images/python.jpg);}")
# 设置标签的宽度和高度,设置的大小会影响窗口的大小,但是图片是全部填充的
label1.setFixedWidth(476)
label1.setFixedHeight(259)
为按钮添加背景图片
对所有的按钮同时生效:
btn1 = QPushButton(self )
btn1.setMaximumSize(64, 64)
btn1.setMinimumSize(64, 64)
style = '''
QPushButton{
border-radius: 30px;
background-image: url('./images/left.png');
}
'''
btn1.setStyleSheet(style)
对指定的按钮设置背景图片,要调用QPushButton
对象的setObjectName()
函数,为对象设置名字,指定的按钮时btn1
:
btn1 = QPushButton(self )
btn1.setObjectName('btn1')
btn1.setMaximumSize(64, 64)
btn1.setMinimumSize(64, 64)
style = '''
#btn1{
border-radius: 30px;
background-image: url('./images/left.png');
}
#btn1:hover{
border-radius: 30px;
background-image: url('./images/leftHover.png');
}
#btn1:Pressed{
border-radius: 30px;
background-image: url('./images/leftPressed.png');
}
'''
btn1.setStyleSheet(style)
缩放图片
使图片大小固定,不管窗口大小怎么变化,图片都保持原始大小:
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import QApplication, QLabel ,QWidget, QVBoxLayout
from PyQt5.QtGui import QImage , QPixmap
from PyQt5.QtCore import Qt
import sys
class WindowDemo(QWidget):
def __init__(self ):
super().__init__()
filename = r".\images\Cloudy_72px.png"
img = QImage( filename ) # 原始图片的大小高度,宽度是72像素,需要进行缩放处理
label1 = QLabel(self)
# 设置宽度,高度为120像素,所加载的图片按照标签的高度和宽度等比例缩放
label1.setFixedWidth(120)
label1.setFixedHeight(120)
# 缩放图片,以固定大小显示
result = img.scaled(label1.width(), label1.height(),Qt.IgnoreAspectRatio, Qt.SmoothTransformation);
# 在标签控件上显示图片
label1.setPixmap(QPixmap.fromImage(result))
vbox=QVBoxLayout()
vbox.addWidget(label1)
self.setLayout(vbox)
self.setWindowTitle("图片大小缩放例子")
if __name__ == "__main__":
app = QApplication(sys.argv)
win = WindowDemo()
win.show()
sys.exit(app.exec_())
设置窗口透明
窗口透明,就可以通过窗口看到桌面的背景,要想窗口透明,需要修改窗口的透明度:
win.QMainWindow()
win.setWindowOpacity(0.5); #透明度:0.0(全透明)-1.0(不透明),默认为1.0
加载QSS
在Qt
中使用样式,为了降低耦合性(与逻辑代码分离),我们需要定义一个QSS
文件,用来编写各种控件(如QLable
、QLineEdit
、QPushButton
)的样式,最后使用QApplication
或QMainWindow
来加载样式,从而使整个应用程序共享一种样式。
在编写QSS
时要新建一个拓展名为.qss
的文件,如style.qss
,再将其加入资源文件(.qrc)
中,
编写QSS
style.qss
的样式代码如下:
QMainWindow{
border-image:url(./images/python.jpg);
}
QToolTip{
border: 1px solid rgb(45, 45, 45);
background: white;
color: red;
}
加载QSS
为了方便调用,编写一个加载样式的公共类CommonHelper
放在CommonHelper.py
文件中。
# -*- coding: utf-8 -*-
class CommonHelper :
def __init__(self ) :
pass
@staticmethod
def readQss( style):
with open( style , 'r') as f:
return f.read()
最后在主函数中进行加载:
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QMainWindow , QApplication, QVBoxLayout , QPushButton
from CommonHelper import CommonHelper
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
self.resize(477, 258)
self.setWindowTitle("加载QSS文件")
btn1 = QPushButton( self)
btn1.setText('添加')
btn1.setToolTip('测试提示')
vbox = QVBoxLayout()
vbox.addWidget( btn1 )
self.setLayout(vbox)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MainWindow()
styleFile = './style.qss' # 换肤时进行全局修改,只需修改不同的QSS文件
qssStyle = CommonHelper.readQss( styleFile )
win.setStyleSheet( qssStyle )
win.show()
sys.exit(app.exec_())
程序运行结果:背景图片和测试提示界面都是通过QSS加载得到的