注意事项#
API变更#
PySide6的一个目标是与PyQt API兼容,但有某些例外。
最新的注意事项和已知问题也将报告在开发者注意事项中。
__hash__()函数返回值#
对于类PySide6.QtCore.QDate
、PySide6.QtCore.QDateTime
、PySide6.QtCore.QTime
、PySide6.QtCore.QUrl
返回的hash值将基于它们的字符串表示形式,因此具有相同值的对象将产生相同的hash值。
QString#
改变了QString参数的内容的方法和函数已被修改为接收不可变的Python Unicode(或str)并返回另一个Python Unicode/str作为修改后的字符串。
以下方法已按此方式更改了返回类型
类: QAbstractSpinBox, QDateTimeEdit, QDoubleSpinBox, QSpinBox, QValidator
fixup(string): string
validate(string, int): [QValidator.State, string, int]
类: QDoubleValidator, QIntValidator, QRegExpValidator
validate(string, int): [QValidator.State, string, int]
类: QClipboard
text(string, QClipboard.Mode mode=QClipboard.Clipboard): [string, string]
类: QFileDialog
与PyQt不同,PySide已将原始方法修改为返回一个元组,而不是getOpenFileNameAndFilter()
、getOpenFileNamesAndFilter()
和getSaveFileNameAndFilter()
。
getOpenFileName(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0): [string, filter]
getOpenFileNames(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0): [list(string), filter]
getSaveFileName(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0): [string, filter]
类: QWebPage
javaScriptPrompt(QWebFrame, string, string): [bool, string]
类: QFontMetrics 和 QFontMetricsF
添加了两个新方法。这两个方法都接受一个字符字符串并将它转换为 QChar (以调用其 C++ 对应物)
widthChar(string)
boundingRectChar(string)
QTextStream#
在这个类中,一些函数名更改为避免与原生 Python 函数冲突。它们是:bin_()
、hex_()
和 oct_()
。唯一的修改是添加了‘_’字符。
QVariant#
由于移除了 QVariant
,任何期望它作为参数的函数都可以接受任何 Python 对象(None
是无效的 QVariant
)。当返回值时,返回的 QVariant
将被转换回其原始的 Python 对象类型。
当方法期望传入 QVariant::Type
时,程序员可以使用字符串(类型的名称)或该类型本身。
qApp “宏”#
QtWidgets 的 C++ API 提供了一个名为 qApp
的宏,它大致相当于 QtWidgets::QApplication</code>>->instance()
。
在 PySide 中,我们试图创建类似宏的体验。为此,qApp
变量被实现为一个正常的内置变量。导入 PySide6
后,你可以立即使用 qApp
。
作为一个用于“创建应用(如果尚未创建)”的有用快捷方式,我们建议使用以下方法:
qApp or QtWidgets.QApplication()
或者,如果你想要检查是否存在一个,只需简单地使用布尔值即可
if qApp:
# do something if an application was created
pass
使用 None
进行比较也是可能的,但这略微有些多余。
测试支持#
对于测试目的,您还可以通过调用以下方法来去除应用:
qApp.shutdown()
对于 5.14.2 版本,这目前是一个实验性功能,尚未完全测试。
嵌入状态#
在嵌入式模式下,C++ 中预先创建的应用对象没有 Python 包装器。与包装好的应用一起创建 qApp
变量。因此,在该嵌入式模式下不存在 qApp
。请注意,您始终可以使用 QtWidgets.QApplication.instance()
来代替。
废弃的替代方案#
我们还尝试了一个带有 qApp()
函数的替代实现,这个函数更加Pythonic且没有问题,但由于很多人更喜欢 qApp
宏的简洁性,所以这里就是它。
富比较#
在 PySide 类的 tp_richcompare
实现中存在一个长期存在的错误。
当一个类没有实现它时,将使用
object
的默认实现。这实现类似于==
和!=
的is
操作符。当一个类只实现了一个像
<
的函数时,默认实现被禁用,并且类似obj in sequence
的表达式会因NotImplemented
而失败。
这个疏忽在版本 5.15.1 中得到了修复。
特性#
在 Qt for Python 中,我们首次开始支持更符合 Python 习惯的用户界面。通过一个特殊的导入语句,你可以开启一些特性来替换 Python 解释器的某些方面。这是通过在 PySide6 导入之后立即使用一个导入语句来实现的。
snake_case#
使用如下语句
from __feature__ import snake_case
当前模块中的所有方法将从 camelCase
切换到 snake_case
。单个大写字母替换为大写字母下面的下划线和字母。
true_property#
使用如下语句
from __feature__ import true_property
所有在 Qt6 文档中标记为属性的获取器和设置器函数,都被 Python 属性对象所替换。属性也在类的相应 QMetaObject 中列出。
这两个特性的示例#
一些 Qt for Python 的代码段可能如下所示
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
在选择上述特性后,这将读作
self.table.horizontal_header().section_resize_mode = QHeaderView.Stretch
此外,您也可以在 Shiboken 中直接声明非 Qt 库的属性,请参阅 property-declare。
更多关于特性的信息#
有关特性的详细信息,请参阅此处: 为什么我们有 __feature__?
工具#
Qt for Python 随带了某些 Qt 工具
pyside6-rcc
:Qt 资源编译器。这是一个命令行工具,可以将包含二进制数据(例如图像)的.qrc
文件编译成可执行的 Python 代码(请参阅 使用 .qrc 文件(pyside6-rcc))。pyside6-uic
:Qt 用户界面编译器。这是一个命令行工具,可以将包含基于 Qt Widget 的表单设计的.ui
文件编译成可执行的 Python 代码(请参阅 使用 Designer 或 QtCreator 中的 .ui 文件以及 QUiLoader 和 pyside6-uic)。pyside6-assistant
:Qt 帮助查看器。这是一个图形工具,可以用来查看 Qt 压缩帮助文件(.qhc
)中的 Qt 文档。目前,为了减少轮的大小,只随带了没有文档集的二进制文件。有关构建文档,请参阅 构建文档。pyside6-designer
:Qt 用户界面设计器。这是一个图形工具,用于创建基于 Qt Widget 的表单设计和使用自定义小部件(请参阅 使用 Designer 或 QtCreator 中的 .ui 文件以及 QUiLoader 和 pyside6-uic,Qt Widgets Designer 中的自定义小部件)。
新Python枚举#
使用新枚举的动机#
长期以来,只有一个Shiboken枚举,它们尽可能地模拟能够在Qt中找到的现有枚举。这些枚举是既继承int的小类。
与此同时,Python枚举经过多年发展,已经成为现代Python的天然部分。其实现完美地适应了Python用户的需求。因此,停止在同一应用程序中保留两种不同的枚举实现,而无一例外地使用新的Python实现是顺理成章的。
现有工作#
从PySide 6.3开始的新枚举,用Python变体替换了Shiboken枚举,这使内建枚举与已经在QEnum部分中展示的QEnum
“宏”相适应。
PySide中的枚举行为#
在PySide 6.3
中,旧枚举和新枚举存在双重实现,其中默认为旧枚举。新的枚举方法是PySide 6.4
的默认方法,并在PySide 6.6
中变为强制性的。存在一个名为PYSIDE6_OPTION_PYTHON_ENUM
的环境变量,默认值为“1”。也可以通过指定不同标志来选择各种变体,但值为“0”(关闭)不再受支持。
在枚举功能集部分,可以找到仍然可用的用于关闭某些枚举功能的选项。
旧枚举和新枚举之间的差异#
Python枚举和Shiboken枚举相互之间几乎是兼容的。小小的不同出现在限制上
Python枚举不能相互继承,而Shiboken枚举可以
Python枚举不允许未定义的值,Shiboken枚举则可以
Python枚举总是需要精确的一个参数,而Shiboken枚举有一个默认的零值
Python枚举很少从int继承,而Shiboken枚举总是继承
以下内容显示标志之间的差异更为明显
Shiboken标志构造函数示例在PySide中先于6.3存在
flags = Qt.Alignment()
enum = Qt.AlignmentFlag
枚举快捷操作符如下
Qt.AlignLeft = Qt.AlignmentFlag.AlignLeft
Qt.AlignTop = Qt.AlignmentFlag.AlignTop
在PySide 6.3中,这些快捷操作符和标志不再存在(官方上)。取而代之的是,Python有一个枚举的Flags类,它是枚举类的子类。但请不要太过担忧,下面是好消息……
从旧枚举中进行平稳过渡#
突然更改所有枚举代码以使用新语法是繁琐且容易出错的,因为这些必要的更改不容易找到。因此,开发了一种宽容模式
宽容模式允许您继续使用旧的结构,但将它们静默地转换为新的结构。例如,如果您写下
flags = Qt.Alignment()
enum = Qt.AlignLeft
item.setForeground(QColor(Qt.green))
flags_type = QPainter.RenderHints
flags = QPainter.RenderHints()
chart_view.setRenderHint(QPainter.Antialiasing)
实际上得到以下结构的构造,这是推荐编写Flags和枚举的方式
flags = Qt.AlignmentFlag(0)
enum = Qt.AlignmentFlag.AlignLeft
item.setForeground(QColor(Qt.GlobalColor.green))
flags_type = QPainter.RenderHint
flags = QPainter.RenderHint(0)
chart_view.setRenderHint(QPainter.RenderHint.Antialiasing)
此功能允许您在初始阶段忽略旧枚举和新枚举之间的差异,只要新枚举是类的属性。这不能应用于没有类的全局枚举(请参阅下面的局限性
。)
容错模式和类型提示#
当你检查例如QtCore.pyi
时,你只会找到新枚举,尽管旧枚举仍然被允许。此外,行补全只能与新结构一起使用,永远不会建议旧的结构。
以这种方式实现容错模式
的原因是
尽可能使过渡平滑,但
鼓励人们在使用新代码时使用新枚举。
因此,您可以继续写入
self.text.setAlignment(Qt.AlignCenter)
但这个结构被推荐用于未来
self.text.setAlignment(Qt.AlignmentFlag.AlignCenter)
局限性#
当枚举类嵌入在正常的PySide类中时,容错模式工作得非常好。但是有一些全局枚举,特别是QtMsgType
存在问题
t = QtMsgType.QtDebugMsg
不能以快捷方式书写
t = QtDebugMsg
因为没有提供容错模式实现的周围PySide类。通常,所需更改很容易找到,因为它们通常出现在导入语句中。
权限API#
跨平台权限API是在Qt 6.5版本中引入的,目前与macOS、iOS、Android和WebAssembly平台相关。使用此API,您的Qt应用程序可以检查和请求某些功能(如摄像头、麦克风、位置、蓝牙、联系人、日历)的权限。更多关于权限API的信息,请参阅此博客文章。
当使用权限API的PySide6应用程序在解释模式(即python <main_file>.py
)下运行时,实现权限API的代码将不工作。使您的PySide6应用程序使用权限API工作的唯一方法是打包应用程序。对于Android,这意味着使用pyside6-android-deploy工具,对于macOS,这意味着使用pyside6-deploy工具。
在解释模式下运行时,您可以使用以下if条件跳过权限检查/请求
is_deployed = "__compiled__" in globals()
if not is_deployed and sys.platform == "darwin":
# code implementing permission check and request
这也可以在PySide6摄像头示例中看到。* __compiled __*是Nuitka属性,用于检查应用程序是作为独立应用程序运行还是在Python解释模式下运行。
Android#
对于Android,pyside6-android-deploy负责识别应用程序需要的权限,并使用<uses-permission>元素将这些权限添加到AndroidManifest.xml。
macOS#
由于Android平台没有自动捆绑Python解释器,因此很明显,为了使PySide6应用程序在Android上运行,必须对PySide6应用程序进行打包。这对于桌面平台(如macOS)并不适用,在macOS上,Python解释器和其包可以轻松安装和运行。
macOS的问题在于,为了使权限API正常工作,你需要一个包含Info.plist文件的macOS包,该文件列出了使用usage description字符串的所需权限。当你用Python的交互模式运行时,即当你运行Python时,默认情况下Qt权限API会从Python解释器中获取Info.plist文件,它不包含所需权限的usage description字符串。当然,你可以修改Python框架安装的Info.plist文件,以便在终端运行PySide6应用程序时Qt权限API能够正常工作。然而,这并不可取。因此,唯一可行的解决方案是使用pyside6-deploy将PySide6应用程序捆绑成macOS应用程序包。这个macOS应用程序包将有自己的Info.plist文件。