PySide6 : Qt for Python 教程

Qt for Python 教程:https://doc.qt.io/qtforpython/tutorials/index.html

官方文档示例:https://doc.qt.io/qtforpython/examples/index.html

Qt for Python 提供了一系列带有演练指南的教程,以帮助新用户入门。

其中一些文档是从 C++ 移植到 Python 的,涵盖了一系列主题,从 "小部件 ( 也叫 控件" 的基本使用,到展示如何 设计应用程序的分步教程。

1、Qt Widgets:基础教程

widget:中文翻译为 "控件、组件、部件 "。

如果想查看可用的 部件,可以查看 ( PySide6.QtWidgets:https://doc.qt.io/qtforpython/PySide6/QtWidgets/index.html#module-PySide6.QtWidgets ) 

第一个 QtWidgets 应用程序

:https://doc.qt.io/qtforpython/tutorials/basictutorial/widgets.html

与任何其他编程框架一样,从传统的 “Hello World” 程序开始。以下是 PySide6 中 Hello World 应用程序的简单示例:

import sys
from PySide6.QtWidgets import QApplication, QLabelapp = QApplication(sys.argv)  # app = QApplication([])label = QLabel("Hello World!")
# This HTML approach will be valid too!
label = QLabel("<font color=red size=40>Hello World!</font>")label.resize(300, 150)
label.show()
app.exec()

解释:

  • 使用 PySide6 的 控件 应用程序,必须始终从 PySide6.QtWidgets 模块导入适当的类开始。
  • 导入后,首先创建一个 QApplication 实例。由于 Qt 可以从命令行接收参数,所以可以将所有参数传递给 QApplication 对象。如果不需要传递任何参数则可以传递 []
  • 创建应用程序对象后,我们创建了一个 QLabel 对象。QLabel是一个可以呈现文本(简单或丰富,如 html)和 图像的 控件
  • 创建完标签后,调用标签的 show() 方法 进行显示。
  • 最后,调用 app.exec()进入 Qt 主循环,开始执行Qt代码

所有的控件 都是 PySide6.QtWidgets子类

按钮

:https://doc.qt.io/qtforpython/tutorials/basictutorial/clickablebutton.html

展示如何使用 Qt for Python 处理 信号和插槽。Signals and slots 是 Qt 的一项功能,它可以让您的 图形控件 与其他 图形控件  或您的 python 代码进行通信。

应用程序创建了一个按钮来记录单击的 按钮,你好!每次单击时都会向 python 控制台发送消息。

# -*- coding: utf-8 -*-import sys
from PySide6.QtWidgets import QApplication, QPushButton
from PySide6.QtCore import Slot@Slot()
def say_hello():print("Button clicked, Hello!")if __name__ == '__main__':# 创建 Qt Applicationapp = QApplication(sys.argv)# 创建 一个按钮控件button = QPushButton("Click me")# 按钮的 "信号clicked" 连接到 "槽函数say_hello"button.clicked.connect(say_hello)button.show()# Run the main Qt loopapp.exec()pass

@Slot () 是一个将 函数 标识为 槽 的装饰器。

示例:

# -*- coding: utf-8 -*-import sys
from PySide6 import QtCore, QtWidgets, QtGuidef main():app = QtWidgets.QApplication([])widget = QtWidgets.QWidget()def show_msg():QtWidgets.QMessageBox.information(widget, '信息提示框', 'Ok 弹出测试信息')btn = QtWidgets.QPushButton('测试点击按钮', widget)btn.clicked.connect(show_msg)widget.resize(500, 500)widget.show()sys.exit(app.exec())passif __name__ == "__main__":main()pass

示例:

# -*- coding: utf-8 -*-import sys
import random
from PySide6 import QtCore, QtWidgets, QtGuidef main():my_app = QtWidgets.QApplication()  # 实例化一个应用main_window = QtWidgets.QMainWindow()  # 实例化一个主窗口main_window.resize(500, 400)  # 设置窗口大小main_window.move(300, 310)  # 移动窗口距离屏幕左上角的位置。main_window.setWindowTitle('这是标题')  # 设置窗口标题。# 在主窗口中添加一个文本框,并指定父窗口 是 main_windowtext_edit = QtWidgets.QPlainTextEdit(main_window)text_edit.setPlaceholderText('默认输入内容……')  # 设置文本框内的默认内容。text_edit.move(10, 25)text_edit.resize(300, 350)btn_1 = QtWidgets.QPushButton('btn_1', main_window)  # 在主窗口中添加一个按钮btn_1.move(350, 50)btn_1.clicked.connect(lambda x: text_edit.appendPlainText("点击按钮次"))  # 给按钮绑定调用函数。btn_2 = QtWidgets.QPushButton('btn_2', main_window)  # 在主窗口中添加一个按钮def say_hello():text_edit.appendPlainText("Button clicked, Hello!")btn_2.clicked.connect(say_hello)btn_2.move(100, 100)main_window.show()  # 显示窗口my_app.exec()  # 使窗口保持显示状态。if __name__ == "__main__":main()pass

示例:

# -*- coding: utf-8 -*-import sys
import random
from PySide6 import QtCore, QtWidgets, QtGuiclass MyWidget(QtWidgets.QWidget):def __init__(self):super().__init__()self.hello = ["Hello 111", "Hello 222", "Hello 333"]self.button = QtWidgets.QPushButton("Click me!")self.text = QtWidgets.QLabel("Hello World")self.text.setAlignment(QtCore.Qt.AlignCenter)self.layout = QtWidgets.QVBoxLayout(self)self.layout.addWidget(self.text)self.layout.addWidget(self.button)self.button.clicked.connect(self.magic)@QtCore.Slot()def magic(self):self.text.setText(random.choice(self.hello))def main():app = QtWidgets.QApplication([])widget = MyWidget()widget.resize(800, 600)widget.show()sys.exit(app.exec())if __name__ == "__main__":main()pass

信号、插槽

:https://doc.qt.io/qtforpython/tutorials/basictutorial/signals_and_slots.html

信号事件槽函数事件处理函数。槽 用于建立 "事件" 和 "槽函数" 的关联关系。

由于 Qt 的性质,QObjects 需要一种通信方式,这就是这种机制成为Qt 核心特性的原因。

信号与插槽简单比喻:可以想象和家里的灯互动,来类比和理解 Signal 和 Slots 。当你移动电灯开关(信号)时,您会得到一个结果,可能是您的灯泡打开/关闭(插槽)。

在开发界面时,您可以通过单击按钮的效果来获得一个真实的示例:“单击”将是信号,而插槽将是单击该按钮时发生的情况,例如关闭窗口,保存文档等.

所有继承自 QObject 的子类,以及其子类之一的 QWidget类 都可以包含信号和插槽。当一个对象以可能对其他对象感兴趣的方式改变其状态时,信号由对象发出。这就是对象进行通信的全部内容

可以将任意数量的信号连接到单个插槽,并且可以将信号连接到任意数量的插槽。甚至可以将一个信号直接连接到另一个信号。(这将在第一个信号发出时立即发出第二个信号。)

Qt 的 控件 有许多预定义的信号和槽。例如, QAbstractButton(Qt 中按钮的基类)有一个clicked() 信号,QLineEdit(单行输入字段)有一个名为 clear() 的槽。因此,可以通过在QLineEdit 的右侧 放置一个 QToolButton 并将其 clicked() 信号连接到插槽 "clear()" 来实现带有清除文本的按钮的文本输入字段。这是使用信号的connect()方法完成的:

button = QToolButton()
line_edit = QLineEdit()
button.clicked.connect(line_edit.clear)

connect() 返回一个 QMetaObject.Connection 对象,可以与 disconnect() 方法一起使用来断开连接。信号也可以连接到自由函数:

import sys
from PySide6.QtWidgets import QApplication, QPushButtondef func():print("The 'function' has been called!")app = QApplication()
button = QPushButton("Call function")
button.clicked.connect(func)
button.show()
sys.exit(app.exec())

信号 类

在 Python 中编写类时,信号被声明为 class 的类级变量QtCore.Signal()。基于 QWidget 的按钮控件发送 clicked() 信号 伪代码:

from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QWidgetclass Button(QWidget):clicked = Signal(Qt.MouseButton)...def mousePressEvent(self, event):self.clicked.emit(event.button())

Signal 的 构造函数 接受一个元组或 Python 类型和 C 类型的列表:

signal1 = Signal(int)  # Python types
signal2 = Signal(QUrl)  # Qt Types
signal3 = Signal(int, str, int)  # more than one type
signal4 = Signal((float,), (QDate,))  # optional types

Signal 的 构造函数 还可以接收 name 定义信号名称的命名参数。如果没有传递任何内容,则新信号将与分配给它的变量具有相同的名称。

# TODO
signal5 = Signal(int, name='rangeChanged')
# ...
rangeChanged.emit(...)

另一个有用的选项 Signal 是参数名称,对于 QML 应用程序按名称引用发出的值很有用:

sumResult = Signal(int, arguments=['sum'])
Connections {target: ...function onSumResult(sum) {// do something with 'sum'}

插槽 类

QObject 派生类中的插槽应由装饰器 @QtCore.Slot() 指示 。同样,要定义签名,只需传递与类相似的 QtCore.Signal() 类型。

@Slot(str)
def slot_function(self, s):...

Slot() 也接受一个 name 和一个 result 关键字。result关键字定义将返回的类型,可以是 C 或 Python 类型。关键字的 name 行为方式为 Signal()。如果没有作为名称传递,则新插槽将与正在装饰的函数具有相同的名称。

重载不同类型的 信号 和 槽

实际上可以使用具有不同参数类型列表的相同名称的信号和槽。这是 Qt 5 的遗留问题,不推荐用于新代码。在 Qt 6 中,不同类型的信号具有不同的名称。

import sys
from PySide6.QtWidgets import QApplication, QPushButton
from PySide6.QtCore import QObject, Signal, Slotclass Communicate(QObject):# create two new signals on the fly: one will handle# int type, the other will handle stringsspeak = Signal((int,), (str,))def __init__(self, parent=None):super(Communicate, self).__init__(parent)self.speak[int].connect(self.say_something)self.speak[str].connect(self.say_something)# define a new slot that receives a C 'int' or a 'str'# and has 'say_something' as its name@Slot(int)@Slot(str)def say_something(self, arg):if isinstance(arg, int):print("This is a number:", arg)elif isinstance(arg, str):print("This is a string:", arg)if __name__ == "__main__":app = QApplication(sys.argv)someone = Communicate()# emit 'speak' signal with different arguments.# we have to specify the str as int is the defaultsomeone.speak.emit(10)someone.speak[str].emit("Hello everybody!")

示例:获取网页 html

:https://www.52pojie.cn/thread-1570807-1-1.html

import sys
import httpx
from PySide6.QtCore import *
from PySide6.QtWidgets import *class HtmlWorker(QThread):completed = Signal(httpx.Response)failed = Signal(object)def set_url(self, url):self.url = urldef run(self):try:resp = httpx.get(self.url, follow_redirects=True)except BaseException as be:self.failed.emit(be)else:self.completed.emit(resp)class MainWindow(QMainWindow):def __init__(self):super(MainWindow, self).__init__()self.output = Noneself.btn = Noneself.edit = Noneself.setWindowTitle('PySide6 Demo')rect = self.screen().geometry()size = self.size()self.setGeometry(QStyle.alignedRect(Qt.LayoutDirection.LeftToRight, Qt.AlignCenter, size, rect))self.htmlWorker = HtmlWorker()self.htmlWorker.completed.connect(self.show_message)self.htmlWorker.failed.connect(self.show_error)# uiwidget = QWidget()self.setCentralWidget(widget)layout = QVBoxLayout()layout.addLayout(self.set_input_layout())layout.addWidget(self.set_output_widget())widget.setLayout(layout)def set_input_layout(self):self.edit = QLineEdit()self.btn = QPushButton('&Show Html')layout = QHBoxLayout()layout.addWidget(self.edit)layout.addWidget(self.btn)self.edit.returnPressed.connect(self.btn.click)self.btn.clicked.connect(self.fetch_html)return layoutdef set_output_widget(self):self.output = QTextEdit()return self.output@Slot()def fetch_html(self):if self.htmlWorker.isRunning():returnurl = self.edit.text()if not url:returnself.output.clear()if not url.startswith('http'):url = 'https://' + urlself.htmlWorker.set_url(url)self.htmlWorker.start()@Slot(httpx.Response)def show_message(self, resp):self.output.setPlainText(resp.text)@Slot(object)def show_error(self, err):QMessageBox.warning(self, 'error', str(err))if __name__ == '__main__':app = QApplication(sys.argv)win = MainWindow()win.show()sys.exit(app.exec())

菜单栏

示例:

# -*- coding: utf-8 -*-"""PySide6 Active Qt Viewer example"""import sys
from PySide6.QtAxContainer import QAxSelect, QAxWidget
from PySide6.QtGui import QAction
from PySide6.QtWidgets import (QApplication, QDialog,QMainWindow, QMessageBox, QToolBar
)class MainWindow(QMainWindow):def __init__(self):super().__init__()toolBar = QToolBar()self.addToolBar(toolBar)fileMenu = self.menuBar().addMenu("&File")loadAction = QAction("Load...", self, shortcut="Ctrl+L", triggered=self.load)fileMenu.addAction(loadAction)toolBar.addAction(loadAction)exitAction = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close)fileMenu.addAction(exitAction)aboutMenu = self.menuBar().addMenu("&About")aboutQtAct = QAction("About &Qt", self, triggered=qApp.aboutQt)aboutMenu.addAction(aboutQtAct)self.axWidget = QAxWidget()self.setCentralWidget(self.axWidget)def load(self):axSelect = QAxSelect(self)if axSelect.exec() == QDialog.Accepted:clsid = axSelect.clsid()if not self.axWidget.setControl(clsid):QMessageBox.warning(self, "AxViewer", f"Unable to load {clsid}.")if __name__ == '__main__':app = QApplication(sys.argv)mainWin = MainWindow()availableGeometry = mainWin.screen().availableGeometry()mainWin.resize(availableGeometry.width() / 3, availableGeometry.height() / 2)mainWin.show()sys.exit(app.exec())

创建 对话框 应用程序

:https://doc.qt.io/qtforpython/tutorials/basictutorial/dialog.html

创建一个自定义类 Form ,并继承 QDialog 。添加 __init()__方法,然后调用 QDialog 的 init 方法。 setWindowTitle() 方法只是设置对话框窗口的标题。在 main()中,创建一个Form 对象,然后调用 show() 方法 进行显示

# -*- coding: utf-8 -*-import sys
from PySide6 import QtCore, QtWidgets, QtGuiclass Form(QtWidgets.QDialog):def __init__(self, parent=None):super(Form, self).__init__(parent)self.setWindowTitle("My Form")# 创建组件self.edit = QtWidgets.QLineEdit("Write my name here..")self.button = QtWidgets.QPushButton("Show Greetings")# 连接 greetings 槽函数 和 按钮单击信号self.button.clicked.connect(self.btn_clicked)# 创建布局并添加组件self.layout = QtWidgets.QVBoxLayout(self)  # 指定布局的 父窗口是当前窗口# 也可以这样设置布局,因为 Form 继承自 QtWidgets.QDialog# QtWidgets 有个 setLayout 方法设置布局# layout111 = QtWidgets.QVBoxLayout()# self.setLayout(layout111)self.layout.addWidget(self.edit)self.layout.addWidget(self.button)def btn_clicked(self):print(f"Hello {self.edit.text()}")if __name__ == '__main__':app = QtWidgets.QApplication([])my_form = Form()my_form.resize(800, 600)my_form.show()sys.exit(app.exec())pass

使用 表格控件 显示数据

:https://doc.qt.io/qtforpython/tutorials/basictutorial/tablewidget.html

如果要显示排列在表格中的数据,可以使用 aQTableWidget来执行此操作,而无需处理太多配置。

注意:使用 aQTableWidget并不是在表格中显示信息的唯一路径。还可以创建数据模型,然后使用QTableView显示。

# -*- coding: utf-8 -*-import sys
from PySide6 import QtWidgets
from PySide6.QtGui import QColorcolors = [("Red", "#FF0000"),("Green", "#00FF00"),("Blue", "#0000FF"),("Black", "#000000"),("White", "#FFFFFF"),("Electric Green", "#41CD52"),("Dark Blue", "#222840"),("Yellow", "#F9E56d")
]def get_rgb_from_hex(code):code_hex = code.replace("#", "")rgb = tuple(int(code_hex[i:i + 2], 16) for i in (0, 2, 4))return QColor.fromRgb(rgb[0], rgb[1], rgb[2])def main():app = QtWidgets.QApplication()table = QtWidgets.QTableWidget()table.setRowCount(len(colors))table.setColumnCount(len(colors[0]) + 1)table.setHorizontalHeaderLabels(["Name", "Hex Code", "Color"])for i, (name, code) in enumerate(colors):item_name = QtWidgets.QTableWidgetItem(name)item_code = QtWidgets.QTableWidgetItem(code)item_color = QtWidgets.QTableWidgetItem()item_color.setBackground(get_rgb_from_hex(code))table.setItem(i, 0, item_name)table.setItem(i, 1, item_code)table.setItem(i, 2, item_color)table.resize(500, 500)table.show()sys.exit(app.exec())if __name__ == '__main__':main()pass

使用 树 控件 显示数据

:https://doc.qt.io/qtforpython/tutorials/basictutorial/treewidget.html

注意:使用 aQTreeWidget并不是在树中显示信息的唯一路径。还可以创建数据模型,然后使用 QTreeView 显示。

# -*- coding: utf-8 -*-import sys
from PySide6 import QtWidgetsdef main():data = {"Project A": ["file_a.py", "file_a.txt", "something.xls"],"Project B": ["file_b.csv", "photo.jpg"],"Project C": []}app = QtWidgets.QApplication()tree = QtWidgets.QTreeWidget()tree.setColumnCount(2)tree.setHeaderLabels(["Name", "Type"])items = []for key, values in data.items():item = QtWidgets.QTreeWidgetItem([key])for value in values:ext = value.split(".")[-1].upper()child = QtWidgets.QTreeWidgetItem([value, ext])item.addChild(child)items.append(item)tree.insertTopLevelItems(0, items)tree.show()sys.exit(app.exec())if __name__ == '__main__':main()pass

使用 Designer 或 QtCreator 的.ui文件与QUiLoader和pyside6-uic 

:https://doc.qt.io/qtforpython/tutorials/basictutorial/uifiles.html

使用 Qt Designer 可以为 Qt for Python 项目创建基于 Qt Widgets 的图形界面。 Qt Designer是一个图形 UI 设计工具,它可以作为独立的二进制文件 ( pyside6-designer) 使用,也可以嵌入到 Qt Creator IDE中。使用 Qt Designer 描述了 它在Qt Creator中的使用。

设计好的图形界面存储在.ui文件中,这是一种基于 XML 的格式。pyside6-uic 工具将在项目构建时将其转换为填充小部件实例的 Python 或 C++ 代码。

文件 mainwindow.ui如下所示

下面说明如何在 Python 中使用这个 ui 文件。

方法 1: ui代码 转成 Python代码

与UI 文件 交互的标准方法是 " 生成 Python 类 "。这要归功于pyside6-uic工具。

在控制台上运行以下命令:pyside6-uic mainwindow.ui > ui_mainwindow.py

命令的所有输出重定向到一个名为 ui_mainwindow.py 的文件,该文件将直接导入:from ui_mainwindow import Ui_MainWindow

完整代码:

import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import QFile
from ui_mainwindow import Ui_MainWindowclass MainWindow(QMainWindow):def __init__(self):super(MainWindow, self).__init__()self.ui = Ui_MainWindow()self.ui.setupUi(self)if __name__ == "__main__":app = QApplication(sys.argv)window = MainWindow()window.show()sys.exit(app.exec())

self.ui = Ui_MainWindow()
self.ui.setupUi(self)

这两行代码 负责从 UI 文件加载生成的 python 类

每次对UI 文件进行更改时,都必须再次运行pyside6-uic。

示例:

# -*- coding: utf-8 -*-from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,QMetaObject, QObject, QPoint, QRect,QSize, QTime, QUrl, Qt
)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,QFont, QFontDatabase, QGradient, QIcon,QImage, QKeySequence, QLinearGradient, QPainter,QPalette, QPixmap, QRadialGradient, QTransform
)
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWidgets import (QApplication, QMainWindow, QMenuBar, QPushButton,QSizePolicy, QStatusBar, QWidget, QPlainTextEdit
)class Ui_MainWindow(object):def setupUi(self, MainWindow):if not MainWindow.objectName():MainWindow.setObjectName(u"MainWindow")MainWindow.resize(700, 567)self.centralwidget = QWidget(MainWindow)self.centralwidget.setObjectName(u"centralwidget")self.plainTextEdit = QPlainTextEdit(self.centralwidget)  # 添加的文本框self.plainTextEdit.setObjectName(u"plainTextEdit")self.plainTextEdit.setGeometry(QRect(90, 40, 521, 311))self.pushButton = QPushButton(self.centralwidget)  # 添加的按钮self.pushButton.setObjectName(u"pushButton")self.pushButton.setGeometry(QRect(330, 410, 75, 24))MainWindow.setCentralWidget(self.centralwidget)self.menubar = QMenuBar(MainWindow)self.menubar.setObjectName(u"menubar")self.menubar.setGeometry(QRect(0, 0, 700, 22))MainWindow.setMenuBar(self.menubar)self.statusbar = QStatusBar(MainWindow)self.statusbar.setObjectName(u"statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)  # 调用下面的retranslateUi(self, MainWindow)函数。QMetaObject.connectSlotsByName(MainWindow)# setupUidef retranslateUi(self, MainWindow):MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"\u81ea\u5b9a\u4e49\u7684\u6807\u9898\u680f", None))self.plainTextEdit.setPlaceholderText(QCoreApplication.translate("MainWindow", u"\u8bf7\u8f93\u5165", None))self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u70b9\u51fb", None))# retranslateUi# ================== 上面为 自动生成 的代码 ============================
# ================== 下面代码 使其显示出来  ============================
app = QApplication()
main_window = QMainWindow()auto_ui_window = Ui_MainWindow()  # 实例化部件
auto_ui_window.setupUi(main_window)  # 调用setupUi()方法,并传入 主窗口 参数。# 给按钮绑定调用函数。
# auto_ui_window.pushButton.clicked.connect(lambda x: print('点击了按钮'))
auto_ui_window.pushButton.clicked.connect(lambda x: auto_ui_window.plainTextEdit.appendPlainText("点击按钮"))main_window.show()
app.exec()
pass

方法 2:直接加载 ui 代码

要直接加载 UI 文件,需要 QtUiTools 模块中的一个类:from PySide6.QtUiTools import QUiLoader

QUiLoader 可以动态加载 ui文件并立即使用它:

# -*- coding: utf-8 -*-from PySide6.QtCore import QFile, QIODevice
from PySide6.QtUiTools import QUiLoaderui_file = QFile("mainwindow.ui")
ui_file.open(QFile.ReadOnly)loader = QUiLoader()
window = loader.load(ui_file)
window.show()

完整代码:

# -*- coding: utf-8 -*-import sys
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication
from PySide6.QtCore import QFile, QIODeviceif __name__ == "__main__":app = QApplication(sys.argv)ui_file_name = "mainwindow.ui"ui_file = QFile(ui_file_name)if not ui_file.open(QIODevice.ReadOnly):print(f"Cannot open {ui_file_name}: {ui_file.errorString()}")sys.exit(-1)loader = QUiLoader()window = loader.load(ui_file)ui_file.close()if not window:print(loader.errorString())sys.exit(-1)window.show()sys.exit(app.exec())

使用.qrc文件

:https://doc.qt.io/qtforpython/tutorials/basictutorial/qrcfiles.html

Qt 资源系统是一种在应用程序中存储二进制文件的机制。这些文件将被嵌入到应用程序中,并且可以 QFile通过QIcon使用QPixmap 以:/。最常见的用途是自定义图像、图标、字体等。

在本教程中,将自定义图像加载为按钮图标。以 Qt 中的多媒体播放器示例。

将有关资源的信息添加到.qrc 文件中:

把 图标 添加到 

</ui>
<!DOCTYPE RCC><RCC version="1.0">
<qresource><file>icons/play.png</file><file>icons/pause.png</file><file>icons/stop.png</file><file>icons/previous.png</file><file>icons/forward.png</file>
</qresource>
</RCC>

生成 Python 文件

现在 icons.qrc 文件准备好了,使用 pyside6-rcc 工具生成一个 Python 类。

运行命令:pyside6-rcc icons.rc -o rc_icons.py

-o 选项允许您指定输出文件名,在本例中为rc_icons.py。

修改代码:

from PySide6.QtGui import QIcon, QKeySequence
playIcon = self.style().standardIcon(QStyle.SP_MediaPlay)
previousIcon = self.style().standardIcon(QStyle.SP_MediaSkipBackward)
pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause)
nextIcon = self.style().standardIcon(QStyle.SP_MediaSkipForward)
stopIcon = self.style().standardIcon(QStyle.SP_MediaStop)

改为

from PySide6.QtGui import QIcon, QKeySequence, QPixmap
playIcon = QIcon(QPixmap(":/icons/play.png"))
previousIcon = QIcon(QPixmap(":/icons/previous.png"))
pauseIcon = QIcon(QPixmap(":/icons/pause.png"))
nextIcon = QIcon(QPixmap(":/icons/forward.png"))
stopIcon = QIcon(QPixmap(":/icons/stop.png"))

这可确保使用新图标而不是应用程序主题提供的默认图标。请注意,这些行不是连续的,而是位于文件的不同部分。在所有导入之后,在主 Python 文件的顶部添加以下导入:import rc_icons

类 的构造函数:

def __init__(self):super(MainWindow, self).__init__()self.playlist = QMediaPlaylist()self.player = QMediaPlayer()toolBar = QToolBar()self.addToolBar(toolBar)fileMenu = self.menuBar().addMenu("&File")openAction = QAction(QIcon.fromTheme("document-open"),"&Open...", self, shortcut=QKeySequence.Open,triggered=self.open)fileMenu.addAction(openAction)exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit",self, shortcut="Ctrl+Q", triggered=self.close)fileMenu.addAction(exitAction)playMenu = self.menuBar().addMenu("&Play")playIcon = QIcon(QPixmap(":/icons/play.png"))self.playAction = toolBar.addAction(playIcon, "Play")self.playAction.triggered.connect(self.player.play)playMenu.addAction(self.playAction)previousIcon = QIcon(QPixmap(":/icons/previous.png"))self.previousAction = toolBar.addAction(previousIcon, "Previous")self.previousAction.triggered.connect(self.previousClicked)playMenu.addAction(self.previousAction)pauseIcon = QIcon(QPixmap(":/icons/pause.png"))self.pauseAction = toolBar.addAction(pauseIcon, "Pause")self.pauseAction.triggered.connect(self.player.pause)playMenu.addAction(self.pauseAction)nextIcon = QIcon(QPixmap(":/icons/forward.png"))self.nextAction = toolBar.addAction(nextIcon, "Next")self.nextAction.triggered.connect(self.playlist.next)playMenu.addAction(self.nextAction)stopIcon = QIcon(QPixmap(":/icons/stop.png"))self.stopAction = toolBar.addAction(stopIcon, "Stop")self.stopAction.triggered.connect(self.player.stop)playMenu.addAction(self.stopAction)# many lines were omitted

执行 python main.py 来运行应用程序,检查新的图标集

为 控件 应用程序 设置 样式

:https://doc.qt.io/qtforpython/tutorials/basictutorial/widgetstyling.html

Qt Widgets 应用程序根据平台使用默认主题。在某些情况下需要修改 Qt 主题的配置让应用程序以不同的方式显示。可以位控件提供自定义样式。

# -*- coding: utf-8 -*-import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QLabelif __name__ == "__main__":app = QApplication()w = QLabel("This is a placeholder text")w.setAlignment(Qt.AlignCenter)w.resize(300, 150)w.show()sys.exit(app.exec())

可以使用类似 CSS 的语法为 应用程序设置样式。有关详细信息,请参阅 Qt 样式表参考:https://doc.qt.io/qt-5/stylesheet-reference.html

QLabel 可以通过设置它的一些 CSS 属性来设置不同的样式,例如:background-color 和 font-family,示例:

# -*- coding: utf-8 -*-import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QLabelif __name__ == "__main__":app = QApplication()w = QLabel("This is a placeholder text")w.setAlignment(Qt.AlignCenter)w.setStyleSheet("""background-color: #262626;color: #FFFFFF;font-family: Titillium;font-size: 18px;""")w.resize(300, 150)w.show()sys.exit(app.exec())

上面代码中单独设置每个 UI 元素的样式需要做很多工作。更简单的替代方法是使用 Qt 样式表,它是一个或多个 .qss 文件,用于定义应用程序中 UI 元素的样式。

更多示例可以在 (  Qt 样式表示例: https://doc.qt.io/qt-5/stylesheet-examples.html ) 文档页面中找到。

Qt 样式表

qss文件与 CSS 文件非常相似,但您需要指定 Widget 组件以及可选的对象名称:

QLabel {background-color: red;
}QLabel#title {font-size: 20px;
}

第一个样式为应用程序中的所有 QLabel 对象定义背景颜色,而后一个样式仅设置标题对象的样式。程序中可以通过 setObjectName(str) 函数,为任何 Qt 对象设置对象名称,例如:对于 label = QLabel("Test") ,设置 label.setObjectName("title")。

一旦你的应用程序有了一个qss文件,你可以通过读取文件并使用 QApplication.setStyleSheet(str)函数来应用它:

if __name__ == "__main__":app = QApplication()w = Widget()w.show()with open("style.qss", "r") as f:_style = f.read()app.setStyleSheet(_style)sys.exit(app.exec())

通过 qss,可以让 程序代码 和 样式 分开设计,这样的设计不会导致 代码和样式混淆到一块,也可以很方便的 启用或禁用 样式。

示例:

# -*- coding: utf-8 -*-import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import *_style = """
QListWidget {color: #FFFFFF;background-color: #33373B;
}QListWidget::item {height: 50px;
}QListWidget::item:selected {background-color: #2ABf9E;
}QLabel {background-color: #FFFFFF;qproperty-alignment: AlignCenter;
}QPushButton {background-color: #2ABf9E;padding: 20px;font-size: 18px;
}
"""class Widget(QWidget):def __init__(self, parent=None):super(Widget, self).__init__(parent)menu_widget = QListWidget()for i in range(10):item = QListWidgetItem(f"Item {i}")item.setTextAlignment(Qt.AlignCenter)menu_widget.addItem(item)text_widget = QLabel("标签")button = QPushButton("按钮")content_layout = QVBoxLayout()content_layout.addWidget(text_widget)content_layout.addWidget(button)main_widget = QWidget()main_widget.setLayout(content_layout)layout = QHBoxLayout()layout.addWidget(menu_widget, 1)layout.addWidget(main_widget, 4)self.setLayout(layout)if __name__ == "__main__":app = QApplication()w = Widget()w.show()# with open("style.qss", "r") as f:#     _style = f.read()#     app.setStyleSheet(_style)app.setStyleSheet(_style)sys.exit(app.exec())

2、Quick/QML:基础教程

第一个 QtQuick/QML 应用程序

QML 是一种声明性语言,可让您比使用传统语言更快地开发应用程序。由于其声明性,它非常适合设计应用程序的 UI。在 QML 中,用户界面被指定为具有属性的对象树。在本教程中,我们将展示如何使用 PySide6 和 QML 制作一个简单的“Hello World”应用程序。

PySide6/QML 应用程序至少包含两个不同的文件——一个包含用户界面 QML 描述的文件,以及一个加载 QML 文件的 python 文件。为了方便起见,让我们将这两个文件保存在同一个目录中。

这是一个简单的 QML 文件,名为view.qml

import QtQuickRectangle {id: mainwidth: 200height: 200color: "green"Text {text: "Hello World"anchors.centerIn: main}
}

我们首先导入QtQuick,这是一个 QML 模块。

对于以前使用过 HTML 或 XML 文件的人来说,其余的 QML 代码非常简单。基本上,我们正在创建一个大小为200*200的绿色矩形,并添加一个文本元素,内容为“Hello World”。该代码使文本在对象中居中显示,在本例中为 Rectangle。anchors.centerIn: mainid: main

现在,让我们看看代码在 PySide6 上的样子。让我们称之为main.py

import sys
from PySide6.QtWidgets import QApplication
from PySide6.QtQuick import QQuickViewif __name__ == "__main__":app = QApplication()view = QQuickView()view.setSource("view.qml")view.show()sys.exit(app.exec())

Python-QML 集成

:https://doc.qt.io/qtforpython/tutorials/qmlintegration/qmlintegration.html

QML 应用教程

:https://doc.qt.io/qtforpython/tutorials/qmlapp/qmlapplication.html

QML、SQL 和 PySide 集成教程

:https://doc.qt.io/qtforpython/tutorials/qmlsqlintegration/qmlsqlintegration.html

3、一般应用

数据可视化工具教程

:https://doc.qt.io/qtforpython/tutorials/datavisualize/index.html

学习如何在折线图中可视化来自 CSV 的数据。

  • 第 1 章 - 从 CSV 读取数据
  • 第 2 章 - 过滤数据
  • 第 3 章 - 创建一个空的 QMainWindow
  • 第 4 章 - 添加 QTableView
  • 第 5 章 - 添加图表视图
  • 第 6 章 - 在 ChartView 中绘制数据

您可以从 下载源代码 https://doc.qt.io/qtforpython/_downloads/06ada84b04e72c9468651471cc91b026/datavisualize.tar.bz2 。

综合教程

:https://doc.qt.io/qtforpython/tutorials/expenses/expenses.html

学习以下概念:

  • 以编程方式创建用户界面

  • 布局、控件

  • 重载 Qt 类

  • 连接信号和插槽

  • 与 QWidgets 交互

要求:

  • 应用程序的简单窗口(QMainWindow)。

  • 用于跟踪费用的表(QTableWidget)。

  • 添加费用信息的两个输入字段(QLineEdit)。

  • 用于向表格添加信息、绘制数据、清除表格和退出应用程序的按钮 ( QPushButton )。

  • 避免无效数据输入的验证步骤。

  • 用于可视化将嵌入图表视图 ( QChartView )的费用数据 ( QChart ) 的图表。

# -*- coding: utf-8 -*-import sys
from PySide6.QtCore import Qt, Slot
from PySide6.QtGui import QAction, QPainter
from PySide6.QtWidgets import (QApplication, QHeaderView, QHBoxLayout, QLabel, QLineEdit,QMainWindow, QPushButton, QTableWidget, QTableWidgetItem,QVBoxLayout, QWidget
)
from PySide6.QtCharts import QChartView, QPieSeries, QChartclass Widget(QWidget):def __init__(self):QWidget.__init__(self)self.items = 0# Example dataself._data = {"Water": 24.5, "Electricity": 55.1, "Rent": 850.0,"Supermarket": 230.4, "Internet": 29.99, "Bars": 21.85,"Public transportation": 60.0, "Coffee": 22.45, "Restaurants": 120}# Leftself.table = QTableWidget()self.table.setColumnCount(2)self.table.setHorizontalHeaderLabels(["Description", "Price"])self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)# Chartself.chart_view = QChartView()self.chart_view.setRenderHint(QPainter.Antialiasing)# Rightself.description = QLineEdit()self.price = QLineEdit()self.add = QPushButton("Add")self.clear = QPushButton("Clear")self.quit = QPushButton("Quit")self.plot = QPushButton("Plot")# Disabling 'Add' buttonself.add.setEnabled(False)self.right = QVBoxLayout()self.right.addWidget(QLabel("Description"))self.right.addWidget(self.description)self.right.addWidget(QLabel("Price"))self.right.addWidget(self.price)self.right.addWidget(self.add)self.right.addWidget(self.plot)self.right.addWidget(self.chart_view)self.right.addWidget(self.clear)self.right.addWidget(self.quit)# QWidget Layoutself.layout = QHBoxLayout()# self.table_view.setSizePolicy(size)self.layout.addWidget(self.table)self.layout.addLayout(self.right)# Set the layout to the QWidgetself.setLayout(self.layout)# Signals and Slotsself.add.clicked.connect(self.add_element)self.quit.clicked.connect(self.quit_application)self.plot.clicked.connect(self.plot_data)self.clear.clicked.connect(self.clear_table)self.description.textChanged[str].connect(self.check_disable)self.price.textChanged[str].connect(self.check_disable)# Fill example dataself.fill_table()@Slot()def add_element(self):des = self.description.text()price = self.price.text()try:price_item = QTableWidgetItem(f"{float(price):.2f}")price_item.setTextAlignment(Qt.AlignRight)self.table.insertRow(self.items)description_item = QTableWidgetItem(des)self.table.setItem(self.items, 0, description_item)self.table.setItem(self.items, 1, price_item)self.description.setText("")self.price.setText("")self.items += 1except ValueError:print("Wrong price", price)@Slot()def check_disable(self, s):if not self.description.text() or not self.price.text():self.add.setEnabled(False)else:self.add.setEnabled(True)@Slot()def plot_data(self):# Get table informationseries = QPieSeries()for i in range(self.table.rowCount()):text = self.table.item(i, 0).text()number = float(self.table.item(i, 1).text())series.append(text, number)chart = QChart()chart.addSeries(series)chart.legend().setAlignment(Qt.AlignLeft)self.chart_view.setChart(chart)@Slot()def quit_application(self):QApplication.quit()def fill_table(self, data=None):data = self._data if not data else datafor desc, price in data.items():description_item = QTableWidgetItem(desc)price_item = QTableWidgetItem(f"{price:.2f}")price_item.setTextAlignment(Qt.AlignRight)self.table.insertRow(self.items)self.table.setItem(self.items, 0, description_item)self.table.setItem(self.items, 1, price_item)self.items += 1@Slot()def clear_table(self):self.table.setRowCount(0)self.items = 0class MainWindow(QMainWindow):def __init__(self, widget):QMainWindow.__init__(self)self.setWindowTitle("Tutorial")# Menuself.menu = self.menuBar()self.file_menu = self.menu.addMenu("File")# Exit QActionexit_action = QAction("Exit", self)exit_action.setShortcut("Ctrl+Q")exit_action.triggered.connect(self.exit_app)self.file_menu.addAction(exit_action)self.setCentralWidget(widget)@Slot()def exit_app(self, checked):QApplication.quit()if __name__ == "__main__":# Qt Applicationapp = QApplication(sys.argv)# 创建 my_widgetmy_widget = Widget()# QMainWindow using QWidget as central widgetwindow = MainWindow(my_widget)window.resize(800, 600)window.show()# Execute applicationsys.exit(app.exec())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/495092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PySide6 信号、槽

信号与槽的入门应用&#xff08;一&#xff09;&#xff1a;https://blog.csdn.net/jia666666/article/details/81774175 信号与槽的再细分&#xff08;二&#xff09;&#xff1a;https://blog.csdn.net/jia666666/article/details/81774858 信号与槽的高级玩法&#xff08;三…

芯片业又起波澜!博通189亿美元收购遭质疑,股价一度跌近19%

来源&#xff1a;华尔街见闻摘要&#xff1a;如果说博通上次收购高通面临的最大“对手”是特朗普政府&#xff0c;这次收购CA的“对手”可能是华尔街。如果说博通上次收购高通面临的最大“对手”是特朗普政府&#xff0c;这次收购CA的“对手”可能是华尔街。美东时间周三&#…

JavaScript常用技巧专题五

文章目录 一、使用适当的命名和注释来提高代码可读性二、优雅的写条件判断代码2.1、普通的if else2.2、三元运算符2.3、多个if else2.4、switch case2.5、对象写法2.6、Map写法 三、封装条件语句四、函数应该只做一件事五、Object.assign给默认对象赋默认值六、函数参数两个以下…

HTML 页面的生命周期、HTML 事件

From&#xff1a;https://blog.csdn.net/WuLex/article/details/101016936 1、页面生命周期 HTML页面的生命周期有以下三个重要事件&#xff0c;每个事件都有特定的用途 DOMContentLoaded &#xff1a; 浏览器已经完全加载 HTML&#xff0c;DOM 树已经构建完毕&#xff0c;js …

腾讯再次海选AI项目,1500进40,医疗零售机器人成新风向

雷刚 发自 凹非寺 量子位 报道 | 公众号 QbitAI一年一度风向标&#xff0c;腾讯又一次海选AI项目。去年第一期腾讯AI加速器结业后&#xff0c;鹅厂就马不停蹄开启了第二期报名&#xff0c;而且这一次报名企业更多、竞争更激烈、最终录取概率甚至不到3%。第二期AI加速器通过初试…

The Human Touch 将人工智能和机器人用于病人工作的实际和伦理意义

来源&#xff1a;IEEE电气电子工程师学会摘要&#xff1a;我们生活在一个科幻小说可以很快成为科学事实的时代。在一代人的时间里&#xff0c;互联网已经从技术奇迹变成了实用工具&#xff0c;移动电话重新定义了我们的交流方式。我们生活在一个科幻小说可以很快成为科学事实的…

渗透测试 ( 0 ) --- XSS、CSRF、文件上传、文件包含、反序列化漏洞

漏洞数据库&#xff1a;https://www.exploit-db.com/google-hacking-database 1、渗透测试 实用 浏览器插件 chrome、edge 插件&#xff1a;搜索 cookie&#xff0c;安装 cookie editor&#xff0c;打开插件&#xff0c;可以 导出 cookie HackBar &#xff1a;Hackbar是网络安…

专访盛大创始人陈天桥:未来的杀手级应用必将诞生于脑科学

翻译丨于波 校对丨其奇来源丨Medium 神经科技初见陈天桥&#xff0c;他穿着带有花纹的短袖衬衫&#xff0c;休闲款式的蓝色牛仔裤&#xff0c;迷彩色的运动鞋&#xff0c;仿佛是个享受退休生活的人。过去的他可不是这样。1999年&#xff0c;陈天桥创建盛大游戏公司&#xff0c…

动手解决jar转txt软件的一个缺陷

代码&#xff1a; import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReade…

渗透测试 ( 2 ) --- 渗透测试系统、靶机、GoogleHacking、kali工具

操作系统&#xff1a;https://zhuanlan.zhihu.com/p/162865015 1、基于 Windows、Linux、Android 的渗透测试系统 1.1 基于 Linux 的系统 Kali&#xff1a;https://www.kali.org/get-kali/Parrot Security OS&#xff1a;Parrot Securitybackbox&#xff1a;https://www.backbo…

清华发布《中国AI发展报告2018》:中科院系统AI论文产出全球第一

来源&#xff1a;大数据文摘人工智能正成为全球性话题&#xff0c;各国的AI人才争夺战也正愈演愈烈。那么目前&#xff0c;人工智能在中国的发展条件如何&#xff0c;中国距离成为真正的人工智能强国到底还有多远&#xff1f;基于此&#xff0c;7月13日&#xff0c;《中国人工智…

单例模式小记【原创】

中国的历史上很少出现两个皇帝并存的时期&#xff0c;是有&#xff0c;但不多&#xff0c;那我们就认为皇帝是个单例模式&#xff0c;在这个场景中&#xff0c;有皇帝&#xff0c;有大臣&#xff0c;大臣是天天要上朝参见皇帝的&#xff0c;今天参拜的皇帝应该和昨天、前天的一…

渗透测试 ( 3 ) --- Metasploit Framework ( MSF )

白嫖 &#xff1a;https://zhuanlan.zhihu.com/p/449836479&#xff1a;http://t.zoukankan.com/hxlinux-p-15787814.html&#xff1a;https://www.52pojie.cn/thread-1586222-1-1.html Metasploit Pro 英文文档&#xff1a;https://docs.rapid7.com/metasploit/ Metasploit P…

工业4.0进行时:工业机器人为何能够快速爆发?

来源&#xff1a;资本实验室摘要&#xff1a;聚焦前沿科技创新与传统产业升级自George Devol于1961发明第一台可编程工业机器人“Unimate”以来&#xff0c;工业机器人产业已经走过了几十年的历史。到了2000年&#xff0c;全球约有74.25万台工业机器人。其中&#xff0c;超过一…

CRITICAL_SECTION 学习

// Critsetion.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <Windows.h> #include <iostream> #include <process.h> using namespace std;CRITICAL_SECTION g_cs; char name[]"zhangdongsheng";unsigned __std…

渗透测试 ( 4 ) --- Meterpreter 命令详解

From&#xff1a;https://blog.csdn.net/weixin_45605352/article/details/115824811 <<Web 安全攻防(渗透测试实战指南)>> 1、初识 Meterpreter 1.1.什么是 Meterpreter Meterpreter 是 Metasploit 框架中的一个扩展模块&#xff0c;作为溢出成功以后的攻击载荷使…

深度:中国车企遭遇最大危机!末尾淘汰赛开始【附下载】| 智东西内参

来源&#xff1a;智东西摘要&#xff1a;靠“合资”起步的中国自主品牌汽车走到了成熟期的转折点&#xff0c;面临的形势极为严峻。中国汽车自主品牌30多年的发展过程&#xff0c;从闭门造车到合资建厂&#xff0c;再到民营崛起&#xff0c;正在逐渐走向开放。经国务院批准&…

渗透测试 ( 5 ) --- 扫描之王 nmap、渗透测试工具实战技巧合集

Nmap 官方文档 ( 中文文档是 Nmap 版本4.50&#xff0c;英文文档是最新的 )&#xff1a; 英文文档&#xff1a;https://nmap.org/book/man.html中文文档&#xff1a;https://nmap.org/man/zh/index.html#man-description官方 Nmap 项目指南 &#xff1a;https://nmap.org/book…

OSI、TCP/IP or Five-layer(Protocols Use) Model

转载于:https://www.cnblogs.com/michael-shan/archive/2012/03/31/6649681.html

央视深入报道,国内主流芯片真实水平如何?

来源&#xff1a;芯师爷摘要&#xff1a; 站在风口上&#xff0c;猪都会飞&#xff01;——用这来概括当下国内芯片领域再恰当不过了。自中兴事件之后&#xff0c;很多创业者纷纷将商业计划的关键字调整为“芯片”。与此同时&#xff0c;投资者也将目光转移至AI芯片、自动驾驶芯…