PyQt5 简介和开发环境搭建
简介
PyQt是一个GUI小部件工具包。 它是Qt的Python接口, Qt是最强大,最受欢迎的跨平台GUI库之一。 PyQt由RiverBank Computing Ltd.开发。最新版本的PyQt可从其官方网站下载 - riverbankcomputing.com
PyQt API是一组包含大量类和函数的模块。 虽然QtCore模块包含用于处理文件和目录等的非GUI功能,但QtGui模块包含所有图形控件。 此外,还有用于处理XML (QtXml) ,SVG (QtSvg)和SQL (QtSql)等的模块。
PyCharm 搭建PyQt 开发环境
PyQt5 及 pyqt5-tools 安装
执行如下安装指令:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt5
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt5-tools
PyCharm配置环境
配置Qt Designer、pyuic工具,相关配置方法如下:
Qt Designer
Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。
最终生成.ui文件(实质上是XML格式的文件),可以通过pyuic5工具转换成.py文件。
在Pycharm中,依次打开 File - Settings - Tools - External Tools,点击 + Create Tool,配置如下:
Name: QtDesigner
Program :D:\python\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 当前designer目录,请根据实际修改
Working directory: $FileDir$
PyUIC配置
PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。
在Pycharm中,依次打开 File - Settings - Tools - External Tools,点击 + Create Tool,配置如下:
Name: PyUIC
Program : D:\python\python.exe # 当前Python目录,请根据实际修改
Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
Working directory: $FileDir$
PyQT 5 快速入门
使用PyQt 5创建一个简单的GUI应用程序涉及以下步骤
-
导入QtGui模块。
-
创建应用程序对象。
-
QWidget对象创建顶级窗口。 在其中添加QLabel对象。
-
将标签的标题设置为“hello world”。
-
通过setGeometry()方法定义窗口的大小和位置。
-
通过app.exec_ app.exec_()方法输入应用程序的主循环。
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
b = QLabel(w)
b.setText("PythonQt 5 快速入门")
w.setGeometry(100, 100, 200, 50)
b.move(50, 20)
w.setWindowTitle("PythonQt 5")
w.show()
sys.exit(app.exec_())
PyQT 5常见窗口类
QMainWindow
用于创建具有菜单栏、工具栏、状态栏和中心窗口部件(如文本编辑器、画布或其他自定义布局)的应用程序的主窗口。
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle("QMainWindow 窗口")
window.show()
sys.exit(app.exec_())
QWidget
所有用户界面对象的基类。当作为顶层窗口使用时,QWidget
提供了一个简单的带有标题栏和边框的窗口。
import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = QWidget()
widget.setWindowTitle("QWidget 窗口")
widget.show()
sys.exit(app.exec_())
QDialog
用于创建对话框窗口的类。
import sys
from PyQt5.QtWidgets import QApplication, QDialog
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = QDialog()
dialog.setWindowTitle("QDialog 窗口")
dialog.show()
sys.exit(app.exec_())
自定义窗口
在PyQt5中,可以通过继承现有的窗口类(如QMainWindow
、QWidget
或QDialog
)来创建自定义窗口,并重写特定方法或添加新的属性和功能,以满足特定的应用需求。
温馨提示:
QMainWindow
适用于大多数标准的桌面应用程序
QDialog
适合于模态对话框
QWidget适合于组件定制化和特殊化
PyQT 5 常见布局
QHBoxLayout/水平布局
QHBoxLayout
排列控件在水平方向上。控件按添加的顺序从左到右排列。
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_widget(object):
def setupUi(self, widget):
widget.setObjectName("widget")
widget.resize(651, 525)
self.horizontalLayout = QtWidgets.QHBoxLayout(widget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.pushButton = QtWidgets.QPushButton(widget)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.pushButton_3 = QtWidgets.QPushButton(widget)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout.addWidget(self.pushButton_3)
self.pushButton_4 = QtWidgets.QPushButton(widget)
self.pushButton_4.setObjectName("pushButton_4")
self.horizontalLayout.addWidget(self.pushButton_4)
self.pushButton_2 = QtWidgets.QPushButton(widget)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout.addWidget(self.pushButton_2)
self.retranslateUi(widget)
QtCore.QMetaObject.connectSlotsByName(widget)
def retranslateUi(self, widget):
_translate = QtCore.QCoreApplication.translate
widget.setWindowTitle(_translate("widget", "自定义组件"))
self.pushButton.setText(_translate("widget", "新增"))
self.pushButton_3.setText(_translate("widget", "修改"))
self.pushButton_4.setText(_translate("widget", "删除"))
self.pushButton_2.setText(_translate("widget", "查询"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_widget()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
QVBoxLayout/垂直布局
QVBoxLayout
在垂直方向上排列控件。控件按添加的顺序从上到下排列。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '7.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout.addWidget(self.pushButton_2)
self.pushButton_3 = QtWidgets.QPushButton(Form)
self.pushButton_3.setObjectName("pushButton_3")
self.verticalLayout.addWidget(self.pushButton_3)
self.pushButton_4 = QtWidgets.QPushButton(Form)
self.pushButton_4.setObjectName("pushButton_4")
self.verticalLayout.addWidget(self.pushButton_4)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "新增"))
self.pushButton_2.setText(_translate("Form", "查询"))
self.pushButton_3.setText(_translate("Form", "修改"))
self.pushButton_4.setText(_translate("Form", "删除"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_Form()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
QGridLayout/网格布局
QGridLayout
允许你以网格方式排列控件。你可以指定控件的行和列。
实战:基于QGridLayout
实现计算器
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QPushButton, QLineEdit
class Calculator(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
self.display = QLineEdit()
grid.addWidget(self.display, 0, 0, 1, 4)
buttons = [
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'C', '0', '=', '+'
]
row = 1
col = 0
for button in buttons:
if button == '=':
btn = QPushButton(button)
btn.clicked.connect(self.calculate_result)
elif button == 'C':
btn = QPushButton(button)
btn.clicked.connect(self.clear_display)
else:
btn = QPushButton(button)
btn.clicked.connect(self.on_click)
grid.addWidget(btn, row, col)
col += 1
if col > 3:
col = 0
row += 1
self.setWindowTitle('网格布局之计算器')
self.show()
def on_click(self):
button = self.sender()
self.display.setText(self.display.text() + button.text())
def calculate_result(self):
try:
result = eval(self.display.text())
self.display.setText(str(result))
except Exception as e:
self.display.setText("Error")
def clear_display(self):
self.display.clear()
if __name__ == '__main__':
app = QApplication(sys.argv)
calc = Calculator()
sys.exit(app.exec_())
QFormLayout/表单布局
QFormLayout
是为表单设计的,它以两列方式排列控件:左列是标签,右列是对应的字段(如文本框)。
实战:基于QFormLayout
实现个人信息登记表
# _*_ coding : UTF-8_*_
# 开发者 : zhuozhiwengang
# 开发时间 : 2024/4/9 16:49
# 文件名称 : 表单布局之个人信息登记表
# 开发工具 : PyCharm
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QFormLayout
class ReportForm(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('个人提交报告单')
self.setGeometry(300, 300, 400, 300)
form_layout = QFormLayout()
label_name = QLabel('姓名:')
self.input_name = QLineEdit()
form_layout.addRow(label_name, self.input_name)
label_id = QLabel('学号:')
self.input_id = QLineEdit()
form_layout.addRow(label_id, self.input_id)
label_department = QLabel('院系:')
self.input_department = QLineEdit()
form_layout.addRow(label_department, self.input_department)
self.submit_button = QPushButton('提交')
self.submit_button.clicked.connect(self.submitReport)
main_layout = QVBoxLayout()
main_layout.addLayout(form_layout)
main_layout.addWidget(self.submit_button)
self.setLayout(main_layout)
def submitReport(self):
name = self.input_name.text()
student_id = self.input_id.text()
department = self.input_department.text()
print(f'姓名: {name}\n学号: {student_id}\n院系: {department}')
if __name__ == '__main__':
app = QApplication(sys.argv)
report_form = ReportForm()
report_form.show()
sys.exit(app.exec_())
自定义布局
通过继承 QLayout
类来创建自定义布局管理器,为特定的布局需求提供解决方案。
PyQT 5 常见按钮
QPushButton
最常用的按钮类型
QRadioButton
多个选项并从中选择一个
QCheckBox
开启或关闭选项。与单选按钮不同,复选框允许多选。
QToolButton
工具栏的按钮
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '8.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.radioButton = QtWidgets.QRadioButton(Form)
self.radioButton.setObjectName("radioButton")
self.horizontalLayout.addWidget(self.radioButton)
self.radioButton_2 = QtWidgets.QRadioButton(Form)
self.radioButton_2.setObjectName("radioButton_2")
self.horizontalLayout.addWidget(self.radioButton_2)
self.verticalLayout.addLayout(self.horizontalLayout)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.checkBox = QtWidgets.QCheckBox(Form)
self.checkBox.setObjectName("checkBox")
self.horizontalLayout_2.addWidget(self.checkBox)
self.checkBox_2 = QtWidgets.QCheckBox(Form)
self.checkBox_2.setObjectName("checkBox_2")
self.horizontalLayout_2.addWidget(self.checkBox_2)
self.checkBox_3 = QtWidgets.QCheckBox(Form)
self.checkBox_3.setObjectName("checkBox_3")
self.horizontalLayout_2.addWidget(self.checkBox_3)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.toolButton = QtWidgets.QToolButton(Form)
self.toolButton.setObjectName("toolButton")
self.verticalLayout.addWidget(self.toolButton)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "普通按钮"))
self.radioButton.setText(_translate("Form", "选择一"))
self.radioButton_2.setText(_translate("Form", "选择二"))
self.checkBox.setText(_translate("Form", "读书"))
self.checkBox_2.setText(_translate("Form", "登山"))
self.checkBox_3.setText(_translate("Form", "篮球"))
self.toolButton.setText(_translate("Form", "..."))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_Form()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
温馨提示:
- 按钮通常与信号和槽机制一起使用,以便在按钮被点击时执行特定的函数或方法。
- 通过样式表,实现自定义按钮的外观
实战:QPushButton 自定义样式
import sys
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
class RoundButton(QPushButton):
def __init__(self, text, parent=None):
super(RoundButton, self).__init__(text, parent)
self.setFixedSize(100, 50)
self.setStyleSheet("background-color: #3498db; color: white; border-radius: 25px;")
self.clicked.connect(self.changeColor)
def changeColor(self):
color = self.palette().button().color()
if color == QColor(Qt.blue):
self.setStyleSheet("background-color: #e74c3c; color: white; border-radius: 25px;")
else:
self.setStyleSheet("background-color: #3498db; color: white; border-radius: 25px;")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
button = RoundButton("样式按钮")
layout = QVBoxLayout(window)
layout.addWidget(button)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
PyQT 5 常见容器
QGroupBox
分组相关的控件
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.groupBox = QtWidgets.QGroupBox(Form)
self.groupBox.setGeometry(QtCore.QRect(20, 80, 231, 41))
self.groupBox.setObjectName("groupBox")
self.widget = QtWidgets.QWidget(self.groupBox)
self.widget.setGeometry(QtCore.QRect(10, 10, 78, 18))
self.widget.setObjectName("widget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.radioButton = QtWidgets.QRadioButton(self.widget)
self.radioButton.setObjectName("radioButton")
self.horizontalLayout.addWidget(self.radioButton)
self.radioButton_2 = QtWidgets.QRadioButton(self.widget)
self.radioButton_2.setObjectName("radioButton_2")
self.horizontalLayout.addWidget(self.radioButton_2)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.groupBox.setTitle(_translate("Form", "性别选择:"))
self.radioButton.setText(_translate("Form", "男"))
self.radioButton_2.setText(_translate("Form", "女"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_Form()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
QScrollArea
用于显示包含超出可视区域的内容的部件。它提供了滚动条,以便用户可以滚动内容并查看超出可视区域的部分。。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.scrollArea = QtWidgets.QScrollArea(Form)
self.scrollArea.setGeometry(QtCore.QRect(20, 60, 351, 171))
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.label = QtWidgets.QLabel("Label 111111111111" *100)
self.label.setGeometry(QtCore.QRect(40, 60, 221, 31))
self.label.setObjectName("label")
self.scrollArea.setWidget(self.label)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_Form()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
QToolBox
创建带有折叠面板的容器。
import sys
from PyQt5.QtWidgets import QMainWindow, QToolBox, QWidget, QListWidget, QListWidgetItem, QVBoxLayout, QApplication
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
class MyToolBox(QMainWindow):
def __init__(self):
super().__init__()
self.init()
def init(self):
self.setWindowTitle("自定义 ToolBox")
self.setGeometry(100, 100, 800, 600)
toolbox = QToolBox()
page1 = QWidget()
list1 = QListWidget()
list1.addItem(QListWidgetItem("Item 1"))
list1.addItem(QListWidgetItem("Item 2"))
list1.addItem(QListWidgetItem("Item 3"))
layout1 = QVBoxLayout(page1)
layout1.addWidget(list1)
page2 = QWidget()
list2 = QListWidget()
list2.addItem(QListWidgetItem("Item A"))
list2.addItem(QListWidgetItem("Item B"))
list2.addItem(QListWidgetItem("Item C"))
layout2 = QVBoxLayout(page2)
layout2.addWidget(list2)
toolbox.addItem(page1, "Page 1")
toolbox.addItem(page2, "Page 2")
self.setCentralWidget(toolbox)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyToolBox()
ex.show()
sys.exit(app.exec_())
QTabWidget
包含多个标签页。
import sys
from PyQt5.QtWidgets import QMainWindow, QToolBox, QWidget, QListWidget, QListWidgetItem, QVBoxLayout, QApplication, \
QTabWidget, QLabel
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
class MyTabWidget(QMainWindow):
def __init__(self):
super().__init__()
self.init()
def init(self):
self.setWindowTitle("自定义 TabWidget")
self.setGeometry(100, 100, 800, 600)
tabWidget = QTabWidget()
tabWidget.addTab(QLabel("标签一"), "Tab 1")
tabWidget.addTab(QLabel("标签二"), "Tab 2")
self.setCentralWidget(tabWidget)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyTabWidget()
ex.show()
sys.exit(app.exec_())
QStackedWidget
创建一个堆叠的控件容器
from PyQt5.QtWidgets import QApplication, QWidget, QStackedWidget, QPushButton, QVBoxLayout, QLabel
def show_next_widget():
index = (stackedWidget.currentIndex() + 1) % stackedWidget.count()
stackedWidget.setCurrentIndex(index)
app = QApplication([])
window = QWidget()
stackedWidget = QStackedWidget()
stackedWidget.addWidget(QLabel("内容标签一"))
stackedWidget.addWidget(QLabel("内容标签二"))
button = QPushButton("Next")
button.clicked.connect(show_next_widget)
windowLayout = QVBoxLayout(window)
windowLayout.addWidget(stackedWidget)
windowLayout.addWidget(button)
window.show()
app.exec_()
QFrame
一个简单的容器,常用于绘制边框和分隔内容
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '15.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(600, 800)
self.frame = QtWidgets.QFrame(Form)
self.frame.setGeometry(QtCore.QRect(20, 10, 361, 241))
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.widget = QtWidgets.QWidget(self.frame)
self.widget.setGeometry(QtCore.QRect(70, 60, 116, 14))
self.widget.setObjectName("widget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QtWidgets.QLabel(self.widget)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.label_2 = QtWidgets.QLabel(self.widget)
self.label_2.setObjectName("label_2")
self.horizontalLayout.addWidget(self.label_2)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", " 标签一"))
self.label_2.setText(_translate("Form", "标签二"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_Form()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
QWidget
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '15.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.widget = QtWidgets.QWidget(Form)
self.widget.setGeometry(QtCore.QRect(70, 100, 56, 32))
self.widget.setObjectName("widget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(self.widget)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.label_2 = QtWidgets.QLabel(self.widget)
self.label_2.setObjectName("label_2")
self.verticalLayout.addWidget(self.label_2)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "TextLabel"))
self.label_2.setText(_translate("Form", "TextLabel"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
widget = QWidget()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_Form()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(widget)
# 创建窗口
widget.show()
sys.exit(app.exec_())
QMdiArea
一个多文档接口(MDI),允许管理多个子窗口。
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMdiArea, QAction, QMdiSubWindow
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
self.create_menu()
def create_menu(self):
new_action = QAction('新建', self)
new_action.triggered.connect(self.create_subwindow)
self.menuBar().addMenu('文件').addAction(new_action)
def create_subwindow(self):
sub_window = QMdiSubWindow()
sub_window.setWindowTitle('子 Window')
self.mdi.addSubWindow(sub_window)
sub_window.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
QDockWidget
QDockWidget
提供可停靠的控件,这些控件可以被移动和重新停靠在主窗口的不同位置。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '17.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.dockWidget = QtWidgets.QDockWidget(MainWindow)
self.dockWidget.setObjectName("dockWidget")
self.dockWidgetContents = QtWidgets.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.pushButton = QtWidgets.QPushButton(self.dockWidgetContents)
self.pushButton.setGeometry(QtCore.QRect(0, 0, 75, 23))
self.pushButton.setObjectName("pushButton")
self.dockWidget.setWidget(self.dockWidgetContents)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
PyQT 5 基本输入控件
QLineEdit
单行文本输入框,用户可以输入和编辑单行文本。
QTextEdit
多行文本编辑器,支持富文本和纯文本。
QSpinBox
带有增减按钮的数字输入框,允许用户选择一个整数值。
QDoubleSpinBox
类似于 QSpinBox
,但用于输入浮点数。
QComboBox
下拉列表,允许用户从预定义的选项列表中选择。
QSlider
滑动条,用于选择一个范围内的值。
QRadioButton
允许用户选择一个选项,通常用于一组单选按钮中。
QCheckBox
一个复选框,允许用户开启或关闭一个选项。
QDateTimeEdit
用于输入日期和时间。
QDateEdit
控件用于输入日期。它提供了一个方便的日历弹出窗口来帮助用户选择日期。
QTimeEdit
控件用于输入时间。用户可以通过它输入和编辑时间值。
QDial
旋钮控件,提供了一个圆形旋转界面,用于选择一个范围内的值。
QProgressBar
显示一个进度条。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '19.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(20, 43, 260, 564))
self.widget.setObjectName("widget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(self.widget)
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
self.textEdit = QtWidgets.QTextEdit(self.widget)
self.textEdit.setObjectName("textEdit")
self.verticalLayout.addWidget(self.textEdit)
self.spinBox = QtWidgets.QSpinBox(self.widget)
self.spinBox.setObjectName("spinBox")
self.verticalLayout.addWidget(self.spinBox)
self.doubleSpinBox = QtWidgets.QDoubleSpinBox(self.widget)
self.doubleSpinBox.setObjectName("doubleSpinBox")
self.verticalLayout.addWidget(self.doubleSpinBox)
self.comboBox = QtWidgets.QComboBox(self.widget)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("java")
self.comboBox.addItem("Python")
self.comboBox.addItem("C++")
self.comboBox.addItem("C")
self.verticalLayout.addWidget(self.comboBox)
self.horizontalSlider = QtWidgets.QSlider(self.widget)
self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
self.horizontalSlider.setObjectName("horizontalSlider")
self.verticalLayout.addWidget(self.horizontalSlider)
self.radioButton = QtWidgets.QRadioButton(self.widget)
self.radioButton.setObjectName("radioButton")
self.verticalLayout.addWidget(self.radioButton)
self.checkBox = QtWidgets.QCheckBox(self.widget)
self.checkBox.setObjectName("checkBox")
self.verticalLayout.addWidget(self.checkBox)
self.dateTimeEdit = QtWidgets.QDateTimeEdit(self.widget)
self.dateTimeEdit.setObjectName("dateTimeEdit")
self.verticalLayout.addWidget(self.dateTimeEdit)
self.dateEdit = QtWidgets.QDateEdit(self.widget)
self.dateEdit.setObjectName("dateEdit")
self.verticalLayout.addWidget(self.dateEdit)
self.timeEdit = QtWidgets.QTimeEdit(self.widget)
self.timeEdit.setObjectName("timeEdit")
self.verticalLayout.addWidget(self.timeEdit)
self.verticalLayout_2.addLayout(self.verticalLayout)
self.dial = QtWidgets.QDial(self.widget)
self.dial.setObjectName("dial")
self.verticalLayout_2.addWidget(self.dial)
self.progressBar = QtWidgets.QProgressBar(self.widget)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.verticalLayout_2.addWidget(self.progressBar)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.lineEdit.setText(_translate("MainWindow", "单行输入文本框"))
self.textEdit.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">多行输入文本框</p></body></html>"))
self.comboBox.setItemText(0, _translate("MainWindow", "Java"))
self.comboBox.setItemText(1, _translate("MainWindow", "Python"))
self.comboBox.setItemText(2, _translate("MainWindow", "C++"))
self.comboBox.setItemText(3, _translate("MainWindow", "C"))
self.radioButton.setText(_translate("MainWindow", "RadioButton"))
self.checkBox.setText(_translate("MainWindow", "CheckBox"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
PyQT 5 基本输入控件高级用法
QLineEdit 掩码录入
设置输入掩码,限制用户输入格式,例如电话号码、日期等。
QLineEdit 校验
验证器(Validator)来约束用户输入的类型。
QLineEdit 占位符
支持占位符文本
QRadioButton 单选组
通常一组中使用,以便用户从多个选项中选择一个
QSlider 自定义范围
自定义这个范围
QRadioButton 自定义图标
自定义图标
QComboBox 自定义下拉列表选项
可以让用户从下拉列表中选择,还可以允许用户输入文本。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 900)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_2.setObjectName("lineEdit_2")
self.verticalLayout.addWidget(self.lineEdit_2)
self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_3.setObjectName("lineEdit_3")
self.verticalLayout.addWidget(self.lineEdit_3)
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox.setObjectName("groupBox")
self.radioButton = QtWidgets.QRadioButton(self.groupBox)
self.radioButton.setGeometry(QtCore.QRect(20, 20, 89, 16))
self.radioButton.setObjectName("radioButton")
self.radioButton_2 = QtWidgets.QRadioButton(self.groupBox)
self.radioButton_2.setGeometry(QtCore.QRect(170, 20, 89, 16))
self.radioButton_2.setObjectName("radioButton_2")
self.verticalLayout.addWidget(self.groupBox)
self.horizontalSlider = QtWidgets.QSlider(self.centralwidget)
self.horizontalSlider.setMinimum(10)
self.horizontalSlider.setMaximum(30)
self.horizontalSlider.setSingleStep(2)
self.horizontalSlider.setPageStep(8)
self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
self.horizontalSlider.setObjectName("horizontalSlider")
self.verticalLayout.addWidget(self.horizontalSlider)
self.radioButton_3 = QtWidgets.QRadioButton(self.centralwidget)
self.radioButton_3.setObjectName("radioButton_3")
self.radioButton_3.setIcon(QIcon("icon/logo.png"))
self.verticalLayout.addWidget(self.radioButton_3)
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setEditable(True)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("语文")
self.comboBox.addItem("数学")
self.comboBox.addItem("英文")
self.verticalLayout.addWidget(self.comboBox)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.lineEdit.setInputMask(_translate("MainWindow", "******"))
self.lineEdit_3.setPlaceholderText(_translate("MainWindow", "Enter your 姓名..."))
self.groupBox.setTitle(_translate("MainWindow", "GroupBox"))
self.radioButton.setText(_translate("MainWindow", "高"))
self.radioButton_2.setText(_translate("MainWindow", "低"))
self.radioButton_3.setText(_translate("MainWindow", "RadioButton"))
self.comboBox.setItemText(0, _translate("MainWindow", "语文"))
self.comboBox.setItemText(1, _translate("MainWindow", "数学"))
self.comboBox.setItemText(2, _translate("MainWindow", "英语"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
PyQT 5 常见显示控件
QLabel
用于显示文本或图片的基础控件
基本功能
- 展示文本:QLabel 可以显示普通文本、富文本或者 HTML。它支持文本的多种格式化,比如字体大小、颜色和对齐方式。
- 展示图像:QLabel 也可以用来展示图像。它可以显示各种格式的图像,包括 PNG、JPEG 和 GIF。
自定义外观和行为
- 文本和图像对齐:可以设置 QLabel 的对齐方式,如左对齐、居中或右对齐。
- 字体样式:可以自定义字体大小、粗细、颜色等。
- 交互反馈:虽然 QLabel 通常用于显示信息,但它也可以配置为响应用户交互,例如当鼠标悬停或点击时改变样式。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setObjectName("label_2")
pixmap = QPixmap("icon/logo.png") # 加载图像
self.label_2.setPixmap(pixmap)
self.label_2.setAlignment(Qt.AlignCenter) # 设置图像居中对齐
self.verticalLayout.addWidget(self.label_2)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "Hello PyQt5之Label"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QTextBrowser
用于显示富文本内容,包括 HTML。它不仅可以展示格式化的文本和图像,还支持超链接、列表和其他 HTML 元素,使其成为展示复杂文本内容的理想选择。
功能概述
- 显示 HTML 和富文本:QTextBrowser 可以解析并显示 HTML 内容,包括文本格式化、图像、表格和超链接。
- 交互性:它支持超链接的交互,可以响应用户点击,使其适合于创建带有导航功能的文档浏览器。
- 文本导航:QTextBrowser 还支持内部滚动和文本搜索,便于用户浏览长文本内容。
加载和展示富文本内容
- 可以直接设置 HTML 内容,或者加载外部 HTML 文件。
- 支持通过设置富文本格式(如使用 QTextEdit 提供的格式化功能)来展示文本。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
self.textBrowser.setObjectName("textBrowser")
html_content = '''
<ol>
<li>咖啡</li>
<li>茶</li>
<li>牛奶</li>
</ol>
<ol start="50">
<li>咖啡</li>
<li>茶</li>
<li>牛奶</li>
</ol>
'''
self.textBrowser.setHtml(html_content)
self.verticalLayout.addWidget(self.textBrowser)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QGraphicsView
PyQt5 中用于展示和管理复杂2D图形的强大控件。它是基于 QGraphicsScene 和 QGraphicsItem 架构的,提供了一个丰富的框架,用于绘制、排列和操作图形项。
用途概述
- 绘制复杂的2D图形:QGraphicsView 可以用来展示复杂的图形和自定义绘制的项,包括形状、图像、文本等。
- 交互式内容:它支持交互,比如拖动、缩放和选择图形项。
- 高级图形管理:QGraphicsView 提供了高级的功能,如视图变换(缩放、旋转)和图形项的分层管理。
使用 QGraphicsScene 和 QGraphicsItem
- QGraphicsScene:这是一个容器,用于管理和维护图形视图中的所有图形项。
- QGraphicsItem:表示图形场景中的单个图形对象。有多种类型的图形项,如 QGraphicsEllipseItem、QGraphicsRectItem、QGraphicsTextItem 等。
# _*_ coding : UTF-8_*_
# 开发者 : zhuozhiwengang
# 开发时间 : 2024/4/12 10:06
# 文件名称 : 23
# 开发工具 : PyCharm
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '22.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsScene, QGraphicsEllipseItem, QGraphicsView
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
# 创建 QGraphicsScene 实例
self.scene = QGraphicsScene()
# 创建一个 QGraphicsEllipseItem 实例(圆形图形项)
self.ellipse = QGraphicsEllipseItem(0, 0, 100, 100) # x, y, width, height
self.scene.addItem(self.ellipse) # 将图形项添加到场景
# 创建 QGraphicsView 实例并设置场景
self.view = QGraphicsView(self.scene)
self.verticalLayout.addWidget(self.view)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QCalendarWidget
图形化的日历控件,允许用户选择日期。
基本功能
- 展示日期:QCalendarWidget 以日历的形式展示日期,允许用户浏览不同的月份和年份。
- 选择日期:用户可以通过点击日历上的特定日期来进行选择。
- 多种视图模式:支持不同的视图模式,如月视图和年视图,以适应不同的使用场景。
展示和选择日期
- 导航:用户可以通过导航栏快速切换月份和年份。
- 获取选中的日期:可以很容易地获取用户选中的日期,用于其他操作或处理。
自定义日历外观和捕获日期变化
- 自定义外观:QCalendarWidget 支持丰富的自定义选项,包括设置不同的颜色和字体。
- 捕获日期变化事件:可以通过信号和槽机制来响应日期的选择或变化,进行相应的操作。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.calendarWidget = QtWidgets.QCalendarWidget(self.centralwidget)
self.calendarWidget.setGeometry(QtCore.QRect(60, 60, 421, 221))
self.calendarWidget.setObjectName("calendarWidget")
self.calendarWidget.clicked.connect(self.on_date_selected) # 连接信号到槽函数
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def on_date_selected(self, date):
print("选中的日期是:", date.toString())
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QLCDNumber
显示一个数字的LCD(液晶显示器)控件
用途和特性
- 数字显示:主要用于显示固定数量的数字,适用于各种需要数字显示的场合,如计时器、仪表板等。
- 自定义样式:可以自定义其显示样式,如数字的颜色、背景和段式(如何显示数字)。
- 简单易用:提供简洁的接口来设置和更新显示的数字。
在界面中显示数字
- 设置显示的数字:可以通过程序动态地改变显示的数字。
- 格式化数字显示:支持不同的格式化选项,比如设置小数点的位数、填充零等。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.lcdNumber = QtWidgets.QLCDNumber(self.centralwidget)
self.lcdNumber.setObjectName("lcdNumber")
self.lcdNumber.display(12345) # 显示数字 12345
self.verticalLayout.addWidget(self.lcdNumber)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QProgressBar
显示任务的进度
功能和自定义选项
- 显示任务进度:用于图形化地展示任务的完成进度,特别是在长时间运行的操作中。
- 自定义样式:支持多种自定义选项,如进度条的颜色、形状和尺寸。
- 方向性:可以设置为水平或垂直显示,根据应用界面的需求进行调整。
实现和更新进度条
- 设置进度范围:可以设置进度条的最小和最大值,以适应不同的进度度量需求。
- 更新进度:可以根据任务的实际进度动态地更新进度条的值。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.verticalLayout.addWidget(self.progressBar)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QFrame
内容分隔符
创建水平线和垂直线
- 用途:在界面设计中,QFrame 可以用作水平或垂直的分隔线,帮助区分界面中的不同部分。
- 方向设置:通过设置其 frameShape 属性,可以定义 QFrame 为水平或垂直线。
自定义线条样式
- 样式设置:可以通过 setFrameStyle 方法来定义线条的风格,例如设置线条的宽度、阴影效果等。
- 颜色和宽度:还可以通过样式表(CSS)来自定义 QFrame 的颜色和宽度,以更好地融入整体界面设计。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setGeometry(QtCore.QRect(40, 100, 481, 16))
self.frame.setFrameShape(QtWidgets.QFrame.HLine)
self.frame.setFrameShadow(QtWidgets.QFrame.Sunken)
self.frame.setObjectName("frame")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
PyQt 5 常见Item View/ 视图组件
本章节重点
- QListView:用于展示一个简单列表,适合于显示一系列项,如文本列表或图标集。
- QTableView:提供了表格视图,适合于展示和编辑结构化数据,如电子表格。
- QTreeView:用于显示树形结构数据,非常适用于展示具有层级关系的信息,如文件系统。
- QColumnView:提供了一种独特的方式来浏览树形结构数据,通过连续的列来显示每个层级,适合于深层次的层级数据。
- QComboBox:这是一个组合框控件,允许用户从一个下拉列表中选择一个选项,适用于需要从有限选项中选择一个的场景。
QListView
基本概念
QListView 是 PyQt5 中用于展示列表项(例如文本列表或图标集)的控件。它显示一个可垂直滚动的列表,非常适合用于简单的数据展示,如显示字符串列表、图像集合或其他一维数据。QListView 可以与数据模型(如 QStringListModel 或 QStandardItemModel)结合使用,这使得它可以动态地展示和更新数据。
使用 QListView
QListView
与数据模型的结合使用为数据的展示和管理提供了极大的灵活性。以下是使用 QListView
显示简单列表数据的基本步骤:
- 创建
QListView
实例。 - 创建一个数据模型,并填充数据。
- 将数据模型设置为
QListView
的模型。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QStringListModel
from PyQt5.QtWidgets import QVBoxLayout, QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.listView = QtWidgets.QListView(self.centralwidget)
self.listView.setGeometry(QtCore.QRect(70, 80, 256, 192))
self.listView.setObjectName("listView")
# 创建一个数据模型并添加数据
self.model = QStringListModel()
self.model.setStringList(["Java 从入门到精通", "Python 从入门到精通", "MySQL 从入门到精通", "Hadoop3 从入门到精通"])
# 设置模型到视图
self.listView.setModel(self.model)
# 创建布局并添加视图
self.layout = QVBoxLayout(self.centralwidget)
self.layout.addWidget(self.listView)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QTableView
基本概念
QTableView 在 PyQt5 中用于展示和编辑结构化的表格数据,这使其成为数据库和电子表格等应用的理想选择。它支持显示多行和多列,并且可以与模型类(如 QStandardItemModel 或自定义模型)结合使用,来管理和展示复杂的数据集。QTableView 不仅提供了数据的视觉展示,还允许用户通过编辑功能直接操作这些数据。
使用 QTableView 实现自定义列、行和单元格:
- 自定义列和行: 可以设置列宽和行高,使其适应内容或满足特定的显示需求。还可以隐藏特定的列或行。
- 单元格定制: 每个单元格可以定制,包括字体、背景色、文本对齐方式等。也可以为单元格添加自定义的渲染器或编辑器,从而展示更复杂的内容,如图标、按钮或自定义绘制的元素。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setGeometry(0, 0, 800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(MainWindow)
self.verticalLayout.setObjectName("verticalLayout")
self.tableView = QtWidgets.QTableView(self.centralwidget)
self.tableView.setObjectName("tableView")
# 创建一个标准项模型
self.model = QStandardItemModel(4, 2) # 4行2列
self.model.setHorizontalHeaderLabels(['字段一', '字段二'])
# 填充数据到模型
for row in range(4):
for column in range(2):
item = QStandardItem(f'行号 {row}, 字段 {column}')
self.model.setItem(row, column, item)
# 设置模型到视图
self.tableView.setModel(self.model)
# 自定义列宽和行高
self.tableView.setColumnWidth(0, 120)
self.tableView.setRowHeight(0, 30)
self.verticalLayout.addWidget(self.tableView)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QTreeView
基本概念
QTreeView
是 PyQt5 中用于展示层次数据或树状结构的控件。它允许以树形方式展示信息,每个节点可以展开或折叠来显示或隐藏其子项。
使用QTreeView
使用 QTreeView
时,可以执行以下操作:
- 创建节点: 在树中添加新的节点,每个节点代表数据层次中的一个元素。
- 删除节点: 从树中移除不再需要的节点。
- 修改节点: 更新节点的内容,例如改变文本或添加图标。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.treeView = QtWidgets.QTreeView(self.centralwidget)
self.treeView.setObjectName("treeView")
# 创建一个标准项模型
model = QStandardItemModel()
model.setHorizontalHeaderLabels(['标题', '描述'])
# 创建根节点
root_node = QStandardItem('根节点')
model.appendRow(root_node)
# 添加子节点
child_node = QStandardItem('子节点')
root_node.appendRow(child_node)
# 添加子节点的子节点
subchild_node = QStandardItem('子节点的子节点')
child_node.appendRow(subchild_node)
# 设置模型到视图
self.treeView.setModel(model)
self.treeView.expandAll() # 展开所有节点
self.verticalLayout.addWidget(self.treeView)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QColumnView
QColumnView的特点和适用场景:
QColumnView 是 PyQt5 中一个独特的控件,用于以多列的方式展示树状或层次数据。它提供了一种动态和直观的方式来浏览复杂数据结构,每次选择一个节点都会在新的列中展示该节点的子节点。这种视图特别适用于需要展示深层次数据结构的应用,如文件浏览器或分类浏览器。
与 QTreeView 不同,QColumnView 通过连续的列来显示每个层级,为用户提供了一种更为直观的方式来浏览和导航复杂的层次结构。
使用QColumnView展示多列视图:
QColumnView 通常与模型(如 QStandardItemModel)结合使用,以动态展示数据。当用户选择某个节点时,其子节点会在新的列中显示,从而允许用户逐层深入地浏览数据。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.columnView = QtWidgets.QColumnView(self.centralwidget)
self.columnView.setObjectName("columnView")
# 创建一个标准项模型
model = QStandardItemModel()
# 创建根节点和子节点
root_node = QStandardItem('根节点')
child_node1 = QStandardItem('子节点 1')
child_node2 = QStandardItem('子节点 2')
root_node.appendRow([child_node1, child_node2])
# 创建子节点的子节点
subchild_node1 = QStandardItem('子节点1 的子节点')
subchild_node2 = QStandardItem('子节点2 的子节点')
child_node1.appendRow(subchild_node1)
child_node2.appendRow(subchild_node2)
# 设置模型到视图
model.appendRow(root_node)
self.columnView.setModel(model)
self.verticalLayout.addWidget(self.columnView)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
QComboBox
QComboBox的多功能性:
QComboBox 是 PyQt5 中一个非常灵活的控件,通常用作下拉列表,允许用户从一系列预定义选项中选择一个。
填充和检索组合框的数据:
添加项: 可以使用 addItem 或 addItems 方法向组合框中添加一个或多个项。
检索选项: 可以通过 currentText 或 currentIndex 方法获取用户选择的文本或选项索引。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setGeometry(QtCore.QRect(130, 130, 291, 31))
self.comboBox.setObjectName("comboBox")
# 向组合框中添加选项
self.comboBox.addItems(["小学", "初中", "高中", "大专", "本科", "研究生"])
# 当选项改变时执行的函数
def on_combobox_changed():
print(f"Selected: {self.comboBox.currentText()}")
# 连接信号
self.comboBox.currentIndexChanged.connect(on_combobox_changed)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
PyQt 5 常见图表
折线图
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个 PlotWidget 对象
self.graphWidget = pg.PlotWidget(MainWindow)
# 设置图表标题和颜色
self.graphWidget.setBackground('w')
self.graphWidget.setTitle("Title", color="b", size="30pt")
# 添加网格
styles = {"color": "#f00", "font-size": "20px"}
self.graphWidget.setLabel("left", "Y Axis", **styles)
self.graphWidget.setLabel("bottom", "X Axis", **styles)
self.graphWidget.showGrid(x=True, y=True)
# 设置数据
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = np.array([30, 32, 34, 32, 33, 31, 29, 32, 35, 45])
# 在 PlotWidget 上绘制数据
pen = pg.mkPen(color="#dcbeff")
self.graphWidget.plot(x, y, pen=pen)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(self.graphWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:创建了一个 PlotWidget
对象,这是 PyQtGraph 提供的用于绘图的控件。接下来,使用 plot
方法在绘图控件上绘制了一条折线图,其中 x
和 y
是数据点的列表。最后,显示主窗口并启动应用程序的事件循环。
二维填充图
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1800, 1600)
# 创建一个 PlotWidget 对象
self.graphWidget = pg.PlotWidget()
# 设置图表的标题和颜色
self.graphWidget.setBackground('w')
self.graphWidget.setTitle("2D Surface Plot", color="b", size="15pt")
# 添加网格
self.graphWidget.showGrid(x=True, y=True)
# 设置数据
x = np.arange(100) # X轴数据
y = np.random.normal(size=100).cumsum() # Y轴数据,这里使用累积和来模拟一个变化的数据集
# 绘制面图
plotItem = self.graphWidget.plot(x, y, pen=pg.mkPen(color="#dcbeff", width=2))
plotItem.setFillBrush(pg.mkBrush(color="#dcbeff", alpha=90))
plotItem.setFillLevel(0)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(self.graphWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:
创建了一个 PlotWidget,然后使用 plot 方法绘制了一条蓝色的线,并使用 setFillBrush 方法设置了填充颜色和 setFillLevel 方法指定了填充的底部水平线。alpha 参数设置了填充颜色的透明度。
柱状图
PyQtGraph 中绘制柱状图,需要使用 BarGraphItem
类。
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground("w")
# 准备数据
x = [1, 2, 3, 4, 5] # X轴数据
height = [10, 15, 7, 10, 5] # 柱状图的高度
width = 0.6 # 柱子的宽度
# 创建柱状图项目
barGraphItem = pg.BarGraphItem(x=x, height=height, width=width, brush='#dcbeff')
plotWidget.addItem(barGraphItem)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
饼图
在 PyQtGraph 中绘制饼图需要使用不同的方法,因为 PyQtGraph 主要是为了绘制二维和三维图形而设计的,它并不直接支持饼图。但是,可以通过使用 PyQt 的标准组件,如 QGraphicsScene 和 QGraphicsView,结合 QPainterPath 来绘制饼图。
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtCore import QRectF
from PyQt5.QtGui import QPainterPath, QBrush, QColor, QFont
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsTextItem
class PieChartView(QGraphicsView):
def __init__(self, data):
super().__init__()
# 创建一个 QGraphicsScene 来容纳饼图
self.scene = QGraphicsScene()
self.setScene(self.scene)
# 绘制饼图
self.draw_pie_chart(data)
def draw_pie_chart(self, data):
# 饼图的起始角度
start_angle = 0
total_value = sum(value for value, _ in data)
for value, color in data:
# 计算每个扇形的角度
span_angle = value * 360
# 创建一个 QPainterPath 对象来绘制这个扇形
path = QPainterPath()
path.moveTo(0, 0)
rect = QRectF(-200, -200, 400, 400) # 设置饼图尺寸
path.arcTo(rect, start_angle, span_angle)
path.closeSubpath()
# 创建一个画刷并设置颜色
brush = QBrush(QColor(color))
# 将扇形添加到场景中
slice_item = self.scene.addPath(path, brush=brush)
# 添加标签
label = QGraphicsTextItem(f"{value / total_value:.1%}", parent=slice_item)
label1 = QGraphicsTextItem(f"{value / total_value:.1%}", parent=slice_item)
label.setFont(QFont("Arial", 10))
label.setPos(-label.boundingRect().width() / 2, -label.boundingRect().height() / 2) # Center the label
label1.setFont(QFont("Arial", 10))
# 更新起始角度
start_angle += span_angle
# 计算标签的位置
angle = np.radians(start_angle - span_angle / 2) # 中间的角度
radius = 100 # 标签放置的半径
label_x = radius * np.cos(angle)
label_y = radius * np.sin(angle)
# 考虑标签的尺寸,对其位置进行微调
label.setPos(label_x - label.boundingRect().width() / 2,
label_y - label.boundingRect().height() / 2)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 饼图数据:(值, 颜色)
data = [
(0.3, '#dcbeff'),
(0.4, '#fffac8'),
(0.3, '#aaffc3')
]
# 创建饼图视图并设置为主窗口的中心控件
pieChartView = PieChartView(data)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(pieChartView)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:继承自 QGraphicsView
的 PieChartView
类来显示饼图。数据以 (值, 颜色)
对的形式传递给 PieChartView
,每个数据对表示饼图中一个扇区的大小和颜色。
散点图
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsTextItem
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground("w")
# 准备数据
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)
# 使用散点图绘制数据
scatterPlotItem = pg.ScatterPlotItem(pen=pg.mkPen(None), brush=pg.mkBrush(255, 100, 100, 200), size=5)
scatterPlotItem.setData(x, y)
plotWidget.addItem(scatterPlotItem)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:创建了一个包含散点图的窗口。x
和 y
是数据点的坐标数组,这里我们使用 numpy
生成了一些随机数据。我们使用 ScatterPlotItem
类来创建散点图,并添加到 PlotWidget
控件中。
箱线图
PyQtGraph 并不直接支持箱线图(Box Plot),但可以通过使用基本的图形和线条来手动创建一个。这样做比较复杂,因为您需要自己计算箱线图的各个组成部分(如四分位数、中位数、异常值等)并绘制它们。
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsTextItem
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground("w")
# 准备数据
data = np.random.normal(size=100)
# 计算箱线图数据
median, q1, q3, lower_whisker, upper_whisker = self.calculate_box_plot_data(data)
# 绘制箱线图
plotItem = plotWidget.getPlotItem()
plotItem.addLine(y=median, pen='#469990')
plotItem.addLine(y=q1, pen='#ffd8b1')
plotItem.addLine(y=q3, pen='#ffd8b1')
plotItem.plot([0, 1], [lower_whisker, lower_whisker], pen='#dcbeff')
plotItem.plot([0, 1], [upper_whisker, upper_whisker], pen='#dcbeff')
plotItem.plot([0.5, 0.5], [lower_whisker, q1], pen='#dcbeff')
plotItem.plot([0.5, 0.5], [q3, upper_whisker], pen='#dcbeff')
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def calculate_box_plot_data(self, data):
median = np.median(data)
q1 = np.percentile(data, 25)
q3 = np.percentile(data, 75)
iqr = q3 - q1
lower_whisker = q1 - 1.5 * iqr
upper_whisker = q3 + 1.5 * iqr
return median, q1, q3, lower_whisker, upper_whisker
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:calculate_box_plot_data
函数用于计算箱线图的关键数值,包括中位数、上下四分位数和两个须的位置。然后,使用 PyQtGraph 的 PlotItem
对象绘制这些线条来展示箱线图。
热力图
在 PyQtGraph 中绘制热力图可以通过使用 ImageItem
来完成。热力图通常用于表示二维数据集的强度或频率。
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsTextItem
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground("w")
# 创建一个
ImageItemimgItem = pg.ImageItem()
# 添加 ImageItem 到绘图控件
plotWidget.addItem(ImageItemimgItem)
# 准备数据:生成一个二维数组
data = np.random.normal(size=(100, 100))
# 设置 ImageItem 的图像数据
ImageItemimgItem.setImage(data)
# 使用颜色映射来表示不同的强度
colorMap = pg.colormap.get('CET-L17')
ImageItemimgItem.setLookupTable(colorMap.getLookupTable())
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:使用 ImageItem
来创建热力图。data
是一个二维数组,用于表示热力图中的数值。setLookupTable
方法用于设置颜色映射,根据数据的不同值显示不同的颜色。
雷达图
PyQtGraph 并不直接支持雷达图(也称为蜘蛛网图或极坐标图),但您可以使用 PyQt 的绘图能力手动创建一个。要在 PyQt 中绘制雷达图,您需要使用 QPainter
类来在 QWidget
或类似对象上进行自定义绘图。
import math
import sys
from PyQt5.QtCore import QPoint, Qt
from PyQt5.QtGui import QPainter, QPolygon, QPen
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsTextItem, QWidget
class RadarWidget(QWidget):
def __init__(self, data):
super().__init__()
self.data = data
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# 雷达图的中心点
center = QPoint(int(self.width() / 2), int(self.height() / 2))
radius = min(int(self.width() / 2), int(self.height() / 2)) - 10
# 绘制雷达图的轴
num_axes = len(self.data)
for i in range(num_axes):
angle = 2 * math.pi * i / num_axes
x = int(center.x() + radius * math.cos(angle))
y = int(center.y() + radius * math.sin(angle))
painter.drawLine(center, QPoint(x, y))
# 绘制雷达图的数据多边形
polygon = QPolygon()
for i in range(num_axes):
angle = 2 * math.pi * i / num_axes
value = self.data[i]
x = int(center.x() + value * radius * math.cos(angle))
y = int(center.y() + value * radius * math.sin(angle))
polygon << QPoint(x, y)
painter.setPen(QPen(Qt.blue, 2))
painter.drawPolygon(polygon)
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建雷达图窗口
radar_data = [0.7, 0.8, 0.5, 0.6, 0.9] # 示例数据
radarWidget = RadarWidget(radar_data)
radarWidget.resize(400, 400)
radarWidget.show()
sys.exit(app.exec_())
实现思路:继承自 QWidget
的 RadarWidget
类来显示雷达图。数据以列表形式传递给 RadarWidget
,每个元素表示雷达图上一个轴的值。
流程图
在 PyQtGraph 中绘制流程图需要使用图形和线条来手动创建图形元素。PyQtGraph 主要专注于数据可视化,并不直接支持流程图的绘制。但是,您可以使用 PyQt5 的图形视图框架(QGraphicsScene
和 QGraphicsView
)来创建流程图。
import sys
import math
from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QGraphicsRectItem, QGraphicsTextItem, \
QGraphicsLineItem, QGraphicsPolygonItem
from PyQt5.QtCore import Qt, QRectF, QPointF, QLineF
from PyQt5.QtGui import QPen, QBrush, QColor, QPolygonF
class Arrow(QGraphicsLineItem):
def __init__(self, start_item, end_item, parent=None):
super().__init__(parent)
# 计算起始点和结束点
start_point = start_item.mapToScene(start_item.rect().bottomLeft() + QPointF(start_item.rect().width() / 2, 0))
end_point = end_item.mapToScene(end_item.rect().topLeft() + QPointF(end_item.rect().width() / 2, 0))
# 设置线条
line = QLineF(start_point, end_point)
self.setLine(line)
self.setPen(QPen(Qt.black, 2))
# 箭头头部尺寸
arrow_size = 9.0
# 计算箭头角度
angle = math.atan2(-line.dy(), line.dx())
# 创建箭头头部
arrow_head = QPolygonF()
arrow_head.append(line.p2())
arrow_head.append(line.p2() - QPointF(math.sin(angle + math.pi / 3) * arrow_size,
math.cos(angle + math.pi / 3) * arrow_size))
arrow_head.append(line.p2() - QPointF(math.sin(angle + math.pi - math.pi / 3) * arrow_size,
math.cos(angle + math.pi - math.pi / 3) * arrow_size))
# 添加箭头头部到场景
arrow_head_item = QGraphicsPolygonItem(arrow_head, self)
arrow_head_item.setBrush(Qt.black)
arrow_head_item.setPen(QPen(Qt.black, 2))
class FlowChartNode(QGraphicsRectItem):
def __init__(self, text, x, y, width, height, parent=None):
super().__init__(x, y, width, height, parent)
self.setBrush(QBrush(QColor(200, 200, 255)))
self.setPen(QPen(Qt.black, 2))
# 添加文本标签
text_item = QGraphicsTextItem(text, self)
text_item.setPos(x + 10, y + 10)
text_item.setTextWidth(width - 20)
if __name__ == '__main__':
app = QApplication(sys.argv)
scene = QGraphicsScene()
node1 = FlowChartNode("开始", 50, 50, 100, 50)
node2 = FlowChartNode("步骤", 50, 150, 100, 50)
node3 = FlowChartNode("结束", 50, 250, 100, 50)
scene.addItem(node1)
scene.addItem(node2)
scene.addItem(node3)
arrow1 = Arrow(node1, node2)
arrow2 = Arrow(node2, node3)
scene.addItem(arrow1)
scene.addItem(arrow2)
view = QGraphicsView(scene)
view.show()
sys.exit(app.exec_())
实现思路:定义了一个 FlowChartNode
类来表示流程图中的节点,该类继承自 QGraphicsRectItem
。然后,我们创建了一个 QGraphicsScene
来容纳这些节点,并使用 QGraphicsView
显示它们。
网络图
在 PyQtGraph 中直接绘制网络图(Graph Visualization)并不直接支持,因为 PyQtGraph 主要用于绘制二维和三维的数据可视化图形,如折线图、散点图等。但是,您可以结合使用 PyQt 和其他 Python 图形库,如 NetworkX,来创建和显示网络图。
import sys
import networkx as nx
import matplotlib.pyplot as plt
from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QWidget, QVBoxLayout
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class NetworkGraph(QWidget):
def __init__(self, parent=None):
super(NetworkGraph, self).__init__(parent)
self.figure, self.ax = plt.subplots()
self.canvas = FigureCanvas(self.figure)
self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.canvas.updateGeometry()
layout = QVBoxLayout()
layout.addWidget(self.canvas)
self.setLayout(layout)
self.draw_graph()
def draw_graph(self):
# 创建一个网络图
G = nx.karate_club_graph()
# 绘制网络图
pos = nx.spring_layout(G)
nx.draw(G, pos, ax=self.ax, with_labels=True, node_color='skyblue', edge_color='gray')
# 更新画布
self.canvas.draw()
app = QApplication(sys.argv)
mainWindow = QMainWindow()
mainWindow.setCentralWidget(NetworkGraph())
mainWindow.show()
sys.exit(app.exec_())
实现思路:创建了一个名为 NetworkGraph
的自定义 QWidget,用于显示由 NetworkX 生成的网络图。使用 NetworkX 创建并配置图形,然后使用 Matplotlib 进行绘图。最后,将 Matplotlib 图形嵌入到 PyQt5 应用程序窗口中。
气泡图
在 PyQtGraph 中绘制气泡图可以通过使用 ScatterPlotItem
类并调整点的大小来实现。气泡图是散点图的一种变体,其中每个点的大小可以代表数据的一个额外维度。
import sys
import numpy as np
from PyQt5 import QtCore
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground("w")
# 准备数据
x = np.random.rand(100) * 10
y = np.random.rand(100) * 10
sizes = np.random.rand(100) * 50 # 气泡的大小
# 创建散点图项目
scatterPlotItem = pg.ScatterPlotItem(pen=pg.mkPen(None), brush="#dcbeff")
# 现在使用 setData 设置点的坐标和大小
scatterPlotItem.setData(x, y, size=sizes)
# 将散点图添加到绘图控件
plotWidget.addItem(scatterPlotItem)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:使用 ScatterPlotItem
创建了一个散点图,并通过改变每个点的大小(size
参数)来创建一个气泡图效果。x
和 y
是数据点的坐标,sizes
数组决定了每个点的大小。
地图图表
在 PyQt 中绘制地图图表通常需要结合使用地理信息系统(GIS)相关的库,例如 GeoPandas、Folium 或 PyQGIS。这些库可以处理地理数据并生成地图,但是它们不是 PyQtGraph 的一部分。另一种选择是使用 QGIS,这是一个完整的地理信息系统平台,它可以与 PyQt 结合使用。
实例:使用 Python、PyQt5 和 Folium 创建交互式地图图表的基本示例:
import sys
import os
import folium
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
class MapWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.view = QWebEngineView(self)
self.init_ui()
def init_ui(self):
# 创建一个 Folium 地图,您可以调整 zoom_start 来设置初始缩放级别
m = folium.Map(location=[45.5236, -122.6750], zoom_start=13)
# 获取当前文件夹的绝对路径
dirname = os.path.abspath(os.path.dirname(__file__))
# 保存地图为 HTML 文件
map_path = os.path.join(dirname, 'map.html')
m.save(map_path)
# 在 QWebEngineView 中加载 HTML self.view.load(QUrl.fromLocalFile(map_path))
# 设置 QWebEngineView 控件的最小尺寸
self.view.setMinimumSize(800, 600) # 例如,设置为宽800像素,高600像素
self.view.show()
app = QApplication(sys.argv)
mainWindow = QMainWindow()
mapWidget = MapWidget()
# 设置主窗口的初始大小
mainWindow.resize(800, 600) # 可以根据需要调整这个尺寸
mainWindow.setCentralWidget(mapWidget)
mainWindow.show()
sys.exit(app.exec_())
实现思路:使用 Folium 创建了一个简单的地图,并将其保存为一个 HTML 文件。然后我们使用 PyQt5 的 QWebEngineView
小部件加载并显示这个 HTML 文件,从而在 PyQt 应用程序中嵌入了地图。
桑基图
桑基图是一种特殊的流程图,它用于表示数据流和传输。在 PyQtGraph 中直接绘制桑基图并不支持,因为它主要用于绘制二维和三维的数据可视化图形,如折线图、散点图等。然而,您可以使用其他的Python库,如 matplotlib
,来创建桑基图,并将其嵌入到 PyQt 应用程序中。
实例:使用 Python、PyQt5 和 Matplotlib 创建桑基图的基本示例
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
from matplotlib.sankey import Sankey
class SankeyWidget(QWidget):
def __init__(self, parent=None):
super(SankeyWidget, self).__init__(parent)
self.figure, self.ax = plt.subplots()
self.canvas = FigureCanvas(self.figure)
layout = QVBoxLayout()
layout.addWidget(self.canvas)
self.setLayout(layout)
self.draw_sankey()
def draw_sankey(self):
# 创建桑基图
sankey = Sankey(ax=self.ax)
sankey.add(flows=[1, -1, 0.5, -0.5], labels=['', '', '', ''], orientations=[0, 0, 1, -1])
sankey.finish()
# 更新画布
self.canvas.draw()
app = QApplication(sys.argv)
mainWindow = QMainWindow()
mainWindow.setCentralWidget(SankeyWidget())
mainWindow.show()
sys.exit(app.exec_())
组合图
在 PyQtGraph 中创建组合图(例如,将折线图和柱状图组合在一起)可以通过在同一个绘图控件(PlotWidget
)中添加多个图表元素来实现。这样,您可以在同一个坐标轴上或在相互关联的坐标轴上展示不同类型的数据。
import sys
import numpy as np
from PyQt5 import QtCore
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground('w')
# 准备数据
x = np.arange(10)
y1 = np.random.randint(1, 20, size=10) # 柱状图的数据
y2 = np.random.randint(1, 20, size=10) # 折线图的数据
# 创建柱状图项目
barGraphItem = pg.BarGraphItem(x=x, height=y1, width=0.6, brush='#fffac8')
plotWidget.addItem(barGraphItem)
# 创建折线图项目
plotWidget.plot(x, y2, pen=pg.mkPen(color='#dcbeff', width=2))
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:创建了一个包含柱状图和折线图的 PlotWidget
。BarGraphItem
用于柱状图,而 plot
方法用于折线图。通过将它们添加到同一个 PlotWidget
中,我们可以将两种图表组合在一起显示。
股票图
在 PyQtGraph 中绘制股票图(通常指蜡烛图或OHLC图)需要一些额外的步骤,因为这需要特殊的图表来表示股票的开盘价、最高价、最低价和收盘价。PyQtGraph 提供了 CandlestickItem
类来创建这种类型的图表。
import sys
import numpy as np
from PyQt5 import QtCore
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow
class CandlestickItem(pg.GraphicsObject):
def __init__(self, data):
pg.GraphicsObject.__init__(self)
self.data = data # data应该是一个包含(open, high, low, close)的列表
self.generatePicture()
def generatePicture(self):
self.picture = pg.QtGui.QPicture()
p = pg.QtGui.QPainter(self.picture)
p.setPen(pg.mkPen('b')) # 设置蜡烛图的颜色
w = 0.3
for (t, open, high, low, close) in self.data:
p.drawLine(pg.QtCore.QPointF(t, low), pg.QtCore.QPointF(t, high))
if open > close:
p.setBrush(pg.mkBrush('g'))
else:
p.setBrush(pg.mkBrush('r'))
p.drawRect(pg.QtCore.QRectF(t - w, open, w * 2, close - open))
p.end()
def paint(self, p, *args):
p.drawPicture(0, 0, self.picture)
def boundingRect(self):
return pg.QtCore.QRectF(self.picture.boundingRect())
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建一个绘图控件
plotWidget = pg.PlotWidget()
plotWidget.setBackground("w")
mainWindow.setCentralWidget(plotWidget)
# 准备数据
data = [ # 示例数据:(时间, 开盘价, 最高价, 最低价, 收盘价)
(1, 10, 15, 5, 13),
(2, 13, 20, 10, 15),
(3, 15, 17, 13, 16),
(4, 16, 19, 14, 10),
# ...
]
# 创建蜡烛图项目
item = CandlestickItem(data)
plotWidget.addItem(item)
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(plotWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:定义了一个 CandlestickItem
类来创建股票图。该类继承自 GraphicsObject
,并且重写了绘图方法来绘制蜡烛图。数据格式是一个元组列表,每个元组代表一个时间点上的开盘价、最高价、最低价和收盘价。
甘特图
在 PyQtGraph 中创建甘特图需要一些额外的工作,因为它主要用于绘制二维和三维的数据可视化图形,如折线图、散点图等,而不直接支持甘特图。但是,您可以使用 PyQt 的基本图形功能来手动绘制甘特图。
import sys
import numpy as np
from PyQt5 import QtCore
import pyqtgraph as pg
from PyQt5.QtCore import QRectF
from PyQt5.QtGui import QColor, QPen, QFont
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsRectItem, QGraphicsTextItem, QGraphicsView, \
QGraphicsScene
class GanttChartItem(QGraphicsRectItem):
def __init__(self, text, start, duration, row, color, parent=None):
super(GanttChartItem, self).__init__(parent)
# 设置矩形的尺寸和位置
self.setRect(QRectF(start, row * 50, duration, 30))
self.setBrush(QColor(color))
self.setPen(QPen(QColor('black'), 2)) # 添加边框
# 添加文本标签
text_item = QGraphicsTextItem(text, self)
text_item.setFont(QFont('Arial', 10))
text_item.setDefaultTextColor(QColor('black'))
text_item.setPos(start + 2, row * 50 + 5)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
# 创建场景
scene = QGraphicsScene()
# 创建甘特图条目
ganttItem1 = GanttChartItem("项目1", 0, 100, 0, '#78C0A8')
ganttItem2 = GanttChartItem("项目2", 50, 150, 1, '#F4D35E')
ganttItem3 = GanttChartItem("项目3", 120, 100, 2, '#EE964B')
# 将条目添加到场景
scene.addItem(ganttItem1)
scene.addItem(ganttItem2)
scene.addItem(ganttItem3)
# 创建视图
view = QGraphicsView(scene)
# 设置合适的视图尺寸
view.setSceneRect(0, 0, 400, 200)
view.setMinimumSize(600, 400)
# 设置窗口标题
view.setWindowTitle("python")
# 设置主窗口的中心小部件为图表
MainWindow.setCentralWidget(view)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建对象
mainWindow = QMainWindow()
# 创建ui,引用demo1文件中的Ui_MainWindow类
ui = Ui_MainWindow()
# 调用Ui_MainWindow类的setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
sys.exit(app.exec_())
实现思路:定义了一个 GanttChartItem
类来表示甘特图中的单个任务。每个任务在水平方向上表示其持续时间,在垂直方向上表示不同的任务行。QGraphicsScene
用于容纳这些任务,而 QGraphicsView
用于显示它们。
平行坐标图
在 PyQtGraph 中直接绘制平行坐标图(Parallel Coordinates)并不直接支持,因为 PyQtGraph 主要用于绘制二维和三维的数据可视化图形,如折线图、散点图等。然而,您可以使用其他的Python库,如 matplotlib 或 pandas,来创建平行坐标图,并将其嵌入到 PyQt 应用程序中。
实例:使用 Python、PyQt5 和 Matplotlib 创建平行坐标图的基本示例:
import sys
import pandas as pd
import matplotlib.pyplot as plt
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from pandas.plotting import parallel_coordinates
class ParallelCoordinatesWidget(QWidget):
def __init__(self, parent=None):
super(ParallelCoordinatesWidget, self).__init__(parent)
self.figure, self.ax = plt.subplots()
self.canvas = FigureCanvas(self.figure)
layout = QVBoxLayout()
layout.addWidget(self.canvas)
self.setLayout(layout)
self.draw_parallel_coordinates()
def draw_parallel_coordinates(self):
# 创建数据
data = pd.DataFrame({
'A': [1, 2, 3, 4],
'B': [4, 3, 2, 1],
'C': [2, 3, 4, 1],
'D': [4, 1, 3, 2]
})
# 绘制平行坐标图
parallel_coordinates(data, 'A', ax=self.ax)
# 更新画布
self.canvas.draw()
app = QApplication(sys.argv)
mainWindow = QMainWindow()
mainWindow.setCentralWidget(ParallelCoordinatesWidget())
mainWindow.show()
sys.exit(app.exec_())
实现思路:定义了一个 ParallelCoordinatesWidget
类来展示平行坐标图。使用 Pandas 和 Matplotlib 创建平行坐标图,并将其嵌入到 PyQt5 应用程序中。
PyQt 5 动画
本章节将讨论以下主题:
- 基本动画效果:如何创建简单的动画,比如淡入淡出效果和移动动画。
- 复杂动画:介绍如何结合多个动画效果,创造更复杂的视觉效果。
- 图形效果处理:探讨如何使用PyQt5的图形框架来增强视觉呈现,比如阴影、模糊和颜色调整。
动画概念
动画是通过连续播放一系列静态图像来创造运动或变化的错觉。要理解和实现动画,我们需要掌握几个基本概念:
- 帧(Frame):动画由多个帧组成,每帧是一个静态的图像。在连续快速播放时,这些静态图像产生运动的错觉。
- 时间轴(Timeline):这是动画发生的时间框架。它定义了动画的开始、持续时间以及结束。在时间轴上,我们可以设定关键帧(特定的时间点),用来标记动画状态的改变。
- 缓动(Easing):缓动是动画的速度变化。不是所有动画都以恒定速度播放。缓动可以让动画开始慢、然后加速,或者开始快后减速,这样可以创造更自然、更吸引人的动画效果。
PyQt5 快速创建简单动画
PyQt5提供了一套完整的动画框架,可以轻松地创建和控制动画。以下是在PyQt5中实现基本动画的步骤:
定义动画对象:使用QPropertyAnimation类,您可以创建一个动画对象。这个类允许您选择要动画化的属性(例如,控件的位置、大小或颜色)。
设置动画属性:
目标对象:设置动画将作用的QWidget或其它对象。
属性名:设置您想要动画化的属性名,如"geometry"。
持续时间:定义动画从开始到结束所需的时间(以毫秒为单位)。
起始值和结束值:设置属性的起始值和结束值。这些值取决于动画的类型和您想要创建的效果。
应用缓动效果:可以通过设置easing curve来控制动画的速度变化。PyQt5提供了多种预定义的缓动效果。
启动动画:通过调用动画对象的start()方法来开始动画。
实例:点击按钮后,会触发QPropertyAnimation对按钮颜色进行动画变化效果,从红色渐变到蓝色并在1秒内完成。同时添加了QEasingCurve.InOutQuart缓动效果
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QColor
from PyQt5.QtCore import QPoint, QVariantAnimation, QEasingCurve
import sys
class AnimationWidget(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 300, 200)
self.button = QPushButton("Click me", self)
self.button.setGeometry(50, 50, 100, 30)
self.animation = QVariantAnimation()
self.animation.setDuration(1000) # 设置动画持续时间为1秒
self.animation.setStartValue(QColor(255, 0, 0)) # 起始颜色为红色
self.animation.setEndValue(QColor(0, 0, 255)) # 结束颜色为蓝色
self.animation.valueChanged.connect(self.changeColor)
self.animation.finished.connect(self.animationFinished)
self.button.clicked.connect(self.startAnimation)
def changeColor(self, color):
self.button.setStyleSheet(f"background-color: {color.name()}")
def animationFinished(self):
print("Animation finished!")
def startAnimation(self):
self.animation.setEasingCurve(QEasingCurve.InOutQuart) # 设置缓动效果
self.animation.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = AnimationWidget()
widget.show()
sys.exit(app.exec_())
QGraphicsView和QGraphicsItem
在PyQt5中,QGraphicsView和QGraphicsItem是创建复杂图形界面和动画的核心组件。它们是Qt的图形视图框架的一部分,提供了一个强大的场景-视图架构来管理和显示自定义的2D图形项。
QGraphicsView
作用:QGraphicsView是一个显示控件,用于展示QGraphicsScene中的内容。它相当于一个查看窗口,通过它可以观察场景中的图形项(QGraphicsItem)。
特点:支持缩放和旋转视图、可以处理大量的自定义图形项、支持图形项的交互操作(如拖动和选择)。
QGraphicsItem
作用:QGraphicsItem代表场景中的每一个图形元素。它可以是任何形状(如矩形、圆形、文本甚至自定义的复杂形状)。
特点:可以单独对每个项设置动画和变换(如移动、缩放、旋转),支持事件处理(如鼠标点击),可以组合多个项来创建复杂的图形结构。
实战:创建自定义图形
import sys
from PyQt5.QtCore import QRectF
from PyQt5.QtWidgets import QGraphicsItem, QApplication, QGraphicsView, QGraphicsScene, QMainWindow, QVBoxLayout, QWidget, QLabel
from PyQt5.QtGui import QPainter, QColor
class CustomItem(QGraphicsItem):
def __init__(self):
super().__init__()
def boundingRect(self):
return QRectF(0, 0, 100, 100)
def paint(self, painter, option, widget):
painter.setBrush(QColor(255, 0, 0))
painter.drawRect(0, 0, 100, 100)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
view = QGraphicsView()
scene = QGraphicsScene()
item = CustomItem()
scene.addItem(item)
view.setScene(scene)
layout = QVBoxLayout()
layout.addWidget(view)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.setGeometry(100, 100, 500, 500)
self.setWindowTitle("Custom QGraphicsItem Example")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
属性动画
属性动画是指在一定时间内逐渐改变对象的属性(如位置、大小、颜色等)的动画。这种类型的动画通过平滑地过渡对象属性的值,创造出流畅且吸引人的视觉效果。在PyQt5中,属性动画可以通过QPropertyAnimation类来实现。
属性动画的关键概念:
属性(Property):可以动画化的对象属性,例如,窗口控件的geometry、opacity或自定义属性。
持续时间(Duration):动画从开始到结束所需的时间。
起始值和结束值:动画属性的初始值和最终值。
缓动曲线(Easing Curve):控制动画速度变化的曲线,可以使动画更自然。
实战:为按钮添加移动动画
from PyQt5.QtWidgets import QApplication, QPushButton
from PyQt5.QtCore import QRect, QPropertyAnimation
import sys
app = QApplication(sys.argv)
# 创建一个按钮
button = QPushButton("Click Me", None)
button.show()
# 创建一个属性动画对象
anim = QPropertyAnimation(button, b"geometry")
anim.setDuration(1000) # 持续时间为1000毫秒
# 设置动画的起始值和结束值
anim.setStartValue(QRect(0, 0, 100, 30)) # 起始位置和大小
anim.setEndValue(QRect(250, 250, 100, 30)) # 结束位置和大小
# 启动动画
anim.start()
sys.exit(app.exec_())
QAnimation类的使用
在PyQt5中,QAnimation
类是一个虚拟基类,提供了创建和管理动画的框架。实际上,通常使用的是它的子类,如QPropertyAnimation
和QSequentialAnimationGroup
,来实现具体的动画效果。这些类使得动画的创建和管理变得更为简单和直观。
QAnimation的基本用法
以下是QPropertyAnimation的基本用法,作为QAnimation类的一个常用实现示例:
- 创建动画对象:选择要动画化的属性和目标对象。
- 设置动画的持续时间:定义动画从开始到结束所需的时间。
- 定义起始值和结束值:设置属性的初始值和最终值。
- 启动动画:调用动画对象的start()方法来开始动画。
from PyQt5.QtWidgets import QApplication, QPushButton
from PyQt5.QtCore import QRect, QPropertyAnimation
import sys
app = QApplication(sys.argv)
# 创建一个按钮
button = QPushButton("Click Me", None)
button.show()
# 创建动画对象,指定动画的属性和目标对象
anim = QPropertyAnimation(button, b"opacity")
# 设置动画持续时间为1000毫秒
anim.setDuration(1000)
# 设置动画的起始值和结束值
anim.setStartValue(0) # 开始时不透明度为0
anim.setEndValue(1) # 结束时不透明度为1
# 启动动画
anim.start()
sys.exit(app.exec_())
不同类型的动画
- 平移动画:通过改变控件的位置(通常是geometry或pos属性)来实现。
- 旋转动画:如果是自定义的图形项,可以通过改变其旋转属性来实现。
- 缩放动画:类似于旋转动画,可以通过改变控件或图形项的缩放属性来实现。
在PyQt5中,您可以通过结合这些不同类型的动画,创造出丰富且动态的用户界面效果。例如,您可以同时改变一个控件的位置、大小和颜色,以创造一个复杂的动画效果。通过使用QSequentialAnimationGroup和QParallelAnimationGroup,您甚至可以组合多个动画,以顺序或并行的方式播放。
动画控制和交互
在PyQt5中,动画的控制和用户交互是通过动画类的方法和信号来实现的。这些功能允许动画根据用户的输入或程序的需求进行灵活的控制。
动画播放控制
- 播放:通过调用start()方法开始动画。
- 暂停:使用pause()方法可以暂停动画。这对于长时间运行的动画特别有用,用户可以在需要时暂停动画。
- 恢复:暂停后,可以通过resume()方法恢复动画。
- 停止:stop()方法会停止动画。停止动画后,可以重新调整参数后再次启动。
- 循环播放:设置loopCount属性可以使动画循环播放指定次数,或者无限循环。
from PyQt5.QtCore import QPropertyAnimation, QObject
# 创建一个QPropertyAnimation对象
anim = QPropertyAnimation(widget, b"geometry")
# 设置动画参数
anim.setDuration(2000)
anim.setStartValue(widget.geometry())
anim.setEndValue(target_geometry)
# 启动动画
anim.start()
# 在需要时,可以调用以下方法来控制动画
anim.pause() # 暂停动画
anim.resume() # 恢复动画
anim.stop() # 停止动画
实战:用户交互的动画是指根据用户的操作来控制动画进程的动画。
from PyQt5.QtWidgets import QSlider, QApplication, QWidget, QVBoxLayout
from PyQt5.QtCore import QPropertyAnimation, QRect
import sys
class AnimationWidget(QWidget):
def __init__(self):
super().__init__()
self.slider = QSlider(self)
self.slider.setOrientation(Qt.Horizontal)
self.slider.valueChanged.connect(self.update_animation)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(0, 0, 100, 30))
self.anim.setEndValue(QRect(250, 250, 100, 30))
layout = QVBoxLayout(self)
layout.addWidget(self.slider)
def update_animation(self, value):
# 根据滑块位置更新动画进度
progress = value / self.slider.maximum()
self.anim.setCurrentTime(self.anim.duration() * progress)
app = QApplication(sys.argv)
widget = AnimationWidget()
widget.show()
sys.exit(app.exec_())
实现思路:创建了一个包含滑块和动画的小部件。滑块的值改变时会调用update_animation
函数,该函数根据滑块的位置来更新动画的当前时间,从而控制动画的进度。这样的交互方式使用户能够直观地控制动画,增强了应用程序的交互性。
缓动函数和自定义过渡效果
缓动函数在动画中扮演着至关重要的角色,它们定义了动画属性值随时间变化的方式,从而影响动画的感觉和流畅度。PyQt5提供了多种预定义的缓动函数,同时也支持自定义缓动函数。
缓动函数的作用
- 控制动画节奏:缓动函数确定动画的加速和减速方式,使动画看起来更自然。
- 增强视觉效果:不同的缓动函数可以创造出不同的动画效果,例如平滑的过渡、弹跳效果等。
使用预定义缓动函数
PyQt5内置了多种缓动函数,如QEasingCurve.Linear、QEasingCurve.InBounce、QEasingCurve.OutElastic等,可以直接应用于动画对象。
import sys
from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout
class EasingCurveDemo(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('缓动函数 Demo')
self.setGeometry(100, 100, 400, 200)
layout = QVBoxLayout()
button = QPushButton('动画启动', self)
button.clicked.connect(self.startAnimation)
layout.addWidget(button)
self.setLayout(layout)
def startAnimation(self):
animation = QPropertyAnimation(self, b'geometry')
animation.setDuration(1000)
animation.setStartValue(self.geometry())
animation.setEndValue(self.geometry().translated(200, 0))
easing_curve = QEasingCurve(QEasingCurve.InOutBack)
animation.setEasingCurve(easing_curve)
animation.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = EasingCurveDemo()
window.show()
sys.exit(app.exec_())
功能实现:创建了一个继承自QWidget的EasingCurveDemo类,其中包含了一个按钮,在按钮点击时触发动画效果。动画效果的缓动函数使用了QEasingCurve中的InOutBack类型。在startAnimation方法中,我们创建了一个QPropertyAnimation对象,设置了动画的持续时间、起始值和结束值,以及缓动函数,并通过调用start()方法开始动画。
图形效果和滤镜
PyQt5不仅提供了强大的动画功能,还支持各种图形效果和滤镜,这些可以用来改变图像或控件的外观。通过这些功能,可以为用户界面添加视觉上的吸引力和更复杂的效果。
使用图形效果和滤镜
PyQt5中的图形效果通常是通过QGraphicsEffect类及其子类来实现的。这些效果可以直接应用于任何继承自QWidget的对象。
主要的图形效果包括:
- 模糊效果 (QGraphicsBlurEffect):为图像或控件添加模糊效果。
- 阴影效果 (QGraphicsDropShadowEffect):为控件添加阴影。
- 颜色调整 (QGraphicsColorizeEffect):改变控件的颜色。
实战:模糊效果
import sys
from PyQt5.QtWidgets import QApplication, QGraphicsBlurEffect, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtGui import QPixmap
if __name__ == '__main__':
app = QApplication(sys.argv)
scene = QGraphicsScene()
view = QGraphicsView(scene)
view.setWindowTitle('模糊效果 Demo')
view.resize(800, 600)
pixmap = QPixmap('icon/logo.png')
item = QGraphicsPixmapItem(pixmap)
scene.addItem(item)
blur_effect = QGraphicsBlurEffect()
blur_effect.setBlurRadius(10)
item.setGraphicsEffect(blur_effect)
view.show()
sys.exit(app.exec_())
实现思路:首先创建了一个QApplication实例,然后创建了一个QGraphicsScene和QGraphicsView,并加载了一张图片。接着创建了一个QGraphicsBlurEffect实例,并设置了模糊半径为10,将模糊效果应用于图片上。最后显示了视图,并启动了应用程序的事件循环。
逐帧动画
逐帧动画是一种通过连续显示一系列静态图像(每个图像是动画的一个“帧”)来创造运动效果的动画形式。这种类型的动画非常适合创建复杂和详细的动画序列,例如人物运动、复杂的变形效果等。
创建逐帧动画
在PyQt5中,创建逐帧动画通常涉及以下步骤:
- 准备帧序列:这可以是一系列图像文件,或者是在程序中动态生成的图像序列。
- 定时更换帧:使用定时器(例如
QTimer
)按一定的间隔更换显示的帧。 - 显示帧:在每个定时器事件中,更新显示的图像。
实战:逐帧动画
import sys
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow
from PyQt5.QtCore import Qt, QTimer
class FrameAnimation(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Frame 动画")
self.setGeometry(100, 100, 400, 400)
self.label = QLabel(self)
self.label.setAlignment(Qt.AlignCenter)
self.setCentralWidget(self.label)
self.frames = ['icon/logo.png', "icon/logo.png", "icon/logo.png"]
self.current_frame = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_frame)
self.timer.start(100) # Change the time interval to control the speed of the animation
def update_frame(self):
pixmap = QPixmap(self.frames[self.current_frame])
self.label.setPixmap(pixmap.scaled(self.label.size(), Qt.KeepAspectRatio))
self.current_frame += 1
if self.current_frame >= len(self.frames):
self.current_frame = 0
if __name__ == '__main__':
app = QApplication(sys.argv)
window = FrameAnimation()
window.show()
sys.exit(app.exec_())
功能实现:设置了一个QLabel用于显示动画帧。frames变量保存了动画的每一帧的路径,current_frame表示当前显示的帧。通过使用QTimer,每次定时更新显示的帧,实现了逐帧动画效果。
PyQT 5 多线程
多线程基础
在Python中,多线程是一种同时执行多个线程的机制,每个线程都是独立的执行流。多线程可以提高程序的并发性,使得多个任务可以并行执行,从而提高整体运行效率。
多线程的优势包括:
- 提高响应性: 允许在应用程序执行其他任务的同时执行耗时的操作,使应用更加响应用户输入。
- 提高性能: 能够充分利用多核处理器,加速程序的运行速度。
- 处理并发任务: 适用于需要同时处理多个任务的场景,如同时下载多个文件或处理多个客户端请求。
快速入门:
import threading
import time
def print_numbers():
for i in range(5):
time.sleep(1)
print(f"数字为: {i}")
def print_letters():
for letter in 'ABCDE':
time.sleep(1)
print(f"字母为: {letter}")
# 创建两个线程
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)
# 启动线程
thread1.start()
thread2.start()
# 等待两个线程执行完毕
thread1.join()
thread2.join()
PyQt5 中的QThread
在PyQt5中,QThread
是用于支持多线程的类。通过使用 QThread
,可以在应用程序中实现并发执行的任务。以下是使用 QThread
的基本步骤:
- 创建自定义线程类: 继承自 QThread,并重写 run 方法,该方法包含线程的主要逻辑。
- 实例化线程对象: 创建自定义线程类的实例。
- 连接信号和槽: 使用信号和槽机制将线程的信号连接到主线程中的槽函数,以便在线程完成时更新主界面。
- 启动线程: 调用线程对象的 start 方法启动线程的执行。
快速入门:
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
import sys
import time
class WorkerThread(QThread):
# 信号声明
finished = pyqtSignal()
def run(self):
for i in range(5):
time.sleep(1)
print(f"线程: {i}")
# 信号发射
self.finished.emit()
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.label = QLabel("等待线程执行完成...", self)
layout = QVBoxLayout(self)
layout.addWidget(self.label)
self.thread = WorkerThread()
# 通过信号槽绑定线程执行完成,执行函数:on_thread_finished
self.thread.finished.connect(self.on_thread_finished)
# Start the thread when the widget is created
self.thread.start()
def on_thread_finished(self):
# 更新label 文本内容
self.label.setText("线程执行完成!")
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())
功能实现:WorkerThread 继承自 QThread,并在 run 方法中定义了线程的执行逻辑。在 MyWidget 中,创建了 WorkerThread 的实例,并连接了 finished 信号到 on_thread_finished 槽函数。在 on_thread_finished 中,更新了主界面的标签文字。
线程间通信
在线程应用中,线程间通信是至关重要的。PyQt5 提供了信号与槽机制,是一种强大的线程间通信方式。以下是线程间通信的基本步骤:
-
定义信号: 在线程类中定义一个信号。
-
发射信号: 在适当的时机,通过调用
emit
方法发射信号。 -
连接信号和槽: 在主线程中连接信号到槽函数,以便在信号发射时执行槽函数。
实战:
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QLabel, QProgressBar, QPushButton, QVBoxLayout, QWidget, QApplication
class WorkerThread(QThread):
# 定义信号,用于线程间通信
update_signal = pyqtSignal(str)
def __init__(self):
super(WorkerThread, self).__init__()
def run(self):
# 模拟耗时操作
for i in range(10):
time.sleep(1)
# 发送信号
self.update_signal.emit(f"Processing {i + 1}/10")
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.worker_thread = WorkerThread()
self.worker_thread.update_signal.connect(self.update_progress) # 连接信号与槽
self.progress_label = QLabel("进程:")
self.progress_bar = QProgressBar()
self.start_button = QPushButton("启动")
self.start_button.clicked.connect(self.start_thread)
layout = QVBoxLayout()
layout.addWidget(self.progress_label)
layout.addWidget(self.progress_bar)
layout.addWidget(self.start_button)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def start_thread(self):
self.worker_thread.start()
def update_progress(self, message):
self.progress_label.setText(message)
self.progress_bar.setValue(self.progress_bar.value() + 10)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
数据共享和保护
在多线程应用中,数据共享可能导致竞态条件和不确定性。为了确保数据的安全性,可以使用互斥锁等保护机制。
实战:
from PyQt5.QtCore import QThread, pyqtSignal, QMutex
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
import sys
class SharedData:
def __init__(self):
# 定义共享变量
self.counter = 0
# 定时互斥锁
self.mutex = QMutex()
def increment(self):
# 获取锁
self.mutex.lock()
# 共享变量执行累加操作
self.counter += 1
value = self.counter
# 释放锁
self.mutex.unlock()
return value
class WorkerThread(QThread):
# 定义信号,用于线程间通信
update_signal = pyqtSignal(int)
def __init__(self, shared_data):
super().__init__()
self.shared_data = shared_data
def run(self):
for i in range(5):
# 实现共享方法
value = self.shared_data.increment()
# 发送信号
self.update_signal.emit(value)
# 模拟耗时
self.msleep(1000)
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.label = QLabel("等待线程更新...", self)
layout = QVBoxLayout(self)
layout.addWidget(self.label)
self.shared_data = SharedData()
self.thread = WorkerThread(self.shared_data)
self.thread.update_signal.connect(self.on_thread_update)
# Start the thread when the widget is created
self.thread.start()
def on_thread_update(self, value):
self.label.setText(f"总数: {value}")
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())
实现思路:SharedData
类包含一个计数器和一个互斥锁。increment
方法用于安全地递增计数器的值。在 WorkerThread
中,通过构造函数传递了共享的 SharedData
实例,确保线程安全地访问计数器。
并发编程
并发编程是指同时执行多个独立任务的能力。在PyQt5中,尽管Python存在全局解释器锁(GIL),我们仍然可以通过并发编程实现一些并发性。
实战:如何使用concurrent.futures
模块实现并发编程
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
from concurrent.futures import ThreadPoolExecutor
import sys
import time
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.label1 = QLabel("Task 1: ", self)
self.label2 = QLabel("Task 2: ", self)
layout = QVBoxLayout(self)
layout.addWidget(self.label1)
layout.addWidget(self.label2)
# 创建 ThreadPoolExecutor 包含 2 threads
self.executor = ThreadPoolExecutor(max_workers=2)
# 提交 tasks 到 ThreadPoolExecutor 线程池
task1 = self.executor.submit(self.task_function, 1)
task2 = self.executor.submit(self.task_function, 2)
# 当线程执行完毕,使用add_done_callback函数去更新GUI
task1.add_done_callback(lambda future: self.label1.setText(f"任务 1: {future.result()}"))
task2.add_done_callback(lambda future: self.label2.setText(f"任务 2: {future.result()}"))
def task_function(self, task_number):
time.sleep(3) # 模拟耗时
return f"任务结果 {task_number}"
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())
实现思路:使用concurrent.futures.ThreadPoolExecutor
创建了一个包含两个线程的线程池。通过submit
方法,我们提交了两个任务,每个任务都是一个耗时的模拟任务。使用add_done_callback
,我们能够在任务完成时更新GUI。
使用 QThreadPool 进行任务管理
在 PyQt5 中,QThreadPool 是用于管理线程的类。它提供了一种方便的方式来处理并发任务。
实战:
import sys
import time
from PyQt5.QtCore import QObject, QRunnable, QThreadPool, pyqtSignal
from PyQt5.QtWidgets import QApplication
class WorkerSignals(QObject):
finished = pyqtSignal()
result = pyqtSignal(object)
class Worker(QRunnable):
def __init__(self, func, *args, **kwargs):
super(Worker, self).__init__()
self.func = func
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
def run(self):
result = self.func(*self.args, **self.kwargs)
self.signals.result.emit(result)
self.signals.finished.emit()
class TaskManager():
def __init__(self):
self.threadpool = QThreadPool.globalInstance()
def add_task(self, func, *args, **kwargs):
worker = Worker(func, *args, **kwargs)
worker.signals.result.connect(self.handle_result)
self.threadpool.start(worker)
def handle_result(self, result):
print(f"Task completed with result: {result}")
# Example usage
def task_func(param1, param2):
time.sleep(1)
return param1 + param2
if __name__ == '__main__':
app = QApplication(sys.argv)
task_manager = TaskManager()
task_manager.add_task(task_func, 5, 10)
sys.exit(app.exec_())
实现思路:通过TaskManager类可以添加任务,任务在后台线程中执行并返回结果。在示例中,我们定义了一个任务函数task_func,将其添加到任务管理器中,并在完成时打印结果。
异步编程与协程
在 PyQt5 应用中,异步编程和协程可以提高程序的效率,尤其是在处理涉及网络请求或其他 I/O 操作的任务时。
快速入门:
import sys
import asyncio
from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget, QLabel
async def long_running_task():
await asyncio.sleep(3)
return "Task completed"
async def on_button_click():
button.setEnabled(False)
result = await long_running_task()
label.setText(result)
button.setEnabled(True)
app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout()
label = QLabel("Click the button to start the task")
button = QPushButton("Start Task")
button.clicked.connect(lambda: asyncio.create_task(on_button_click()))
layout.addWidget(label)
layout.addWidget(button)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
关键总结如下:
多线程基础: 理解 Python 中的多线程概念,以及多线程的优势和适用场景。
QThread 类的使用: 学会在 PyQt5 中使用 QThread 类来创建和管理多线程,确保线程之间的协同工作。
线程间通信: 理解在多线程应用中如何进行线程间的通信,特别是通过 PyQt5 的信号与槽机制的应用。
数据共享和保护: 学习在多线程应用中处理数据共享问题的方法,包括互斥锁和其他保护机制。
并发编程: 了解并发编程的概念,以及 Python GIL 对并发的影响,同时掌握并发编程的实例和优化技巧。
QThreadPool 的使用: 学会使用 QThreadPool 类进行任务管理,提高多线程应用的效率。
异步编程与协程: 引入异步编程的概念,了解 Python 中协程的基本用法,以及它们在 PyQt5 中的实际应用场景。