PyQt5与PyQt6:有哪些区别是时候升级了吗

2,790 阅读6分钟

如果你已经在用PyQt5开发Python GUI应用,你可能会问自己是否是时候升级到PyQt6并使用最新版本的Qt库了。在这篇文章中,我们将看看PyQt5和PyQt6的主要区别,升级的好处以及升级时可能遇到的问题。

背景介绍

Qt是一个用C++编程语言编写的图形用户界面框架,由Trolltech创建,现在由Qt公司开发。有两个Python绑定。PySidePyQt。前者是由Qt公司内部开发的,而PyQt是由Riverbank Computing Ltd.独立开发的。PyQt6的第一个版本于2021年1月4日发布,仅比Qt6本身的发布晚一个月。

关于两个绑定的最新版本之间的差异的更多信息,请看PyQt6 vs PySide6

从PyQt5升级到PyQt6

PyQt5PyQt6的升级路径相当简单,只有一个主要问题。对于一些应用程序来说,只需将导入文件从PyQt5 重命名为PyQt6 ,就足以将你的应用程序转换为与新库一起工作。然而,对于大多数应用程序来说,你将需要考虑PyQt和Qt本身的变化。

让我们熟悉一下这两个版本之间的一些差异,以了解如何编写能与这两个版本无缝工作的代码。阅读完这些之后,你应该能够在网上找到任何PyQt5的例子,并将其转换为与PyQt6一起工作。

枚举

最有可能影响你的项目的变化是取消了枚举成员的简写名称。在PyQt6中,所有枚举成员都必须使用它们的全称来命名。这适用于所有的枚举和标志,包括那些在QtCore.Qt 名称空间的枚举。例如,PyQt6中的Qt.Checked 标志变成了Qt.CheckState.Checked

  • PyQt5
  • PyQt6
widget = QCheckBox("This is a checkbox")
widget.setCheckState(Qt.Checked)
widget = QCheckBox("This is a checkbox")
widget.setCheckState(Qt.CheckState.Checked)

这里有太多的更新值,无法一一提及。但如果你要转换一个代码库,你通常可以直接在网上搜索短的形式,长的形式会出现在结果中。

好消息是,这种改变是向后兼容的:全限定的名字在PyQt5中也能使用。所以你可以在开始升级进程之前在你的PyQt5代码中进行修改。

.exec() 或 ?.exec_()

Qt中的.exec() 方法启动你的QApplication 或对话框的事件循环。在Python 2.7中,exec 是一个关键字,意味着它不能作为变量名、函数名或方法名使用。在PyQt的早期版本中,该方法被重命名为.exec_() --增加了一个尾部下划线--以避免冲突。

Python 3.0删除了exec 这个关键字,释放了这个名字的使用。由于PyQt6只针对Python 3.x版本,下划线的名字已经被删除。在PyQt5中,这些名字已经被废弃了,而.exec() 方法在那里也可以使用。

不再有QResources

PyQt6已经取消了对Qt资源框架的支持。对于将数据文件与你的应用程序打包,你可以使用PyInstaller的数据文件支持

Qt6的不同之处

除了上述变化外,还有许多其他的小变化,这些变化反映了Qt6与Qt5的基本差异,并不是PyQt本身独有的。

QAction 移动

在Qt6中,用于创建工具栏和菜单的QAction 类,已经从QtWidgets移到了QtGui模块:

  • PyQt5
  • PyQt6
from PyQt5.QtWidgets import QAction
from PyQt6.QtGui import QAction

这看起来很奇怪,但此举是有意义的,因为动作也可以在QML(非widgets)应用程序中使用。

高 DPI 缩放

高 DPI*(dots per inch*) 缩放属性Qt.AA_EnableHighDpiScaling,Qt.AA_DisableHighDpiScalingQt.AA_UseHighDpiPixmaps 已经被弃用,因为在 PyQt6 中高 DPI 是默认启用的,不能被禁用。

QMouseEvent

QMouseEvent.pos() 和 方法返回一个 对象,以及 和 方法返回一个 对象已被废弃 - 使用 和 方法返回一个 对象代替,所以像 和 。QMouseEvent.globalPos() QPoint QMouseEvent.x() QMouseEvent.y() int QMouseEvent.position() QMouseEvent.globalPosition() QPointF QMouseEvent.position().x() QMouseEvent.position().y()

Qt.MidButton 已被重新命名为Qt.MiddleButton

平台特定

最后,QtWinQtMac 模块中特定于平台的方法已被废弃,转而使用本地调用。在PyQt应用程序中,唯一可能的后果是setCurrentProcessExplicitAppUserModelID ,以设置一个应用程序ID,用于Windows上的任务栏图标分组:

  • QtWin
  • 本机
try:
    # Include in try/except block if you're also targeting Mac/Linux
    from PyQt5.QtWinExtras import QtWin
    myappid = 'com.learnpyqt.examples.helloworld'
    QtWin.setCurrentProcessExplicitAppUserModelID(myappid)
except ImportError:
    pass
try:
    # Include in try/except block if you're also targeting Mac/Linux
    from ctypes import windll  # Only exists on Windows.
    myappid = 'mycompany.myproduct.subproduct.version'
    windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
except ImportError:
    pass

杂项

  • QDesktopWidget 已被删除 - 使用 代替,可以使用 , , 或 进行检索。QScreen QWidget.screen() QGuiApplication.primaryScreen() QGuiApplication.screens()
  • .width() QFontMetrics 的内容已被重新命名为 。.horizontalAdvance()
  • .get() 当获取Open GL库的任何功能时,推荐使用 而不是 或 。QOpenGLVersionFunctionsFactory() .versionFunctions() QOpenGLContext()
  • QRegularExpression 已经取代了 。QRegExp
  • QWidget.mapToGlobal() 和 现在接受并返回一个 对象。QWidget.mapFromGlobal() QPointF

缺少的模块

这已经不是一个问题了,但是当Qt6还是新的时候,并不是所有的Qt模块都被移植了,所以在PyQt中是不可用的。如果你需要这些模块中的任何一个,升级到PyQt6以前是不可行的。快进到Qt 6.2和PyQt 6.2,好消息是所有这些缺失的模块现在都回来了,所以你可以顺利升级。

是时候升级了吗?

是否到了升级的时候取决于你的项目。如果你刚开始学习PyQt(或一般的GUI编程),你可能更愿意暂时坚持使用PyQt5,因为网上有更多的例子。虽然差异相对较小,但当你学习新东西时,任何不工作的东西都是令人困惑的。你在PyQt5中学到的任何东西都会延续到PyQt6,所以一旦你有了更多的信心,你可以切换。

然而,如果你正在开始一个新的项目,或者对PyQt相当熟悉,我建议现在就跳到PyQt6。

如果你想开始使用PyQt6,可以阅读PyQt6的书,书中的所有代码例子都是为这个最新版本的PyQt更新的。

PyQt 向后兼容

如果你正在开发同时针对PyQt5和PyQt6的软件,你可以使用条件导入来导入哪个模块的类。

python

try:
    from PyQt6 import QtWidgets, QtGui, QtCore # ...
except ImportError:
    from PyQt5 import QtWidgets, QtGui, QtCore # ...

如果你将这些导入添加到你的项目根部的一个文件中,名为qt.py 。然后,你可以在自己的代码文件中导入使用from qt import QtWidgets ,可用的库将被自动导入。

如果你使用枚举和exec() 的全限定名称,那么许多以前用PyQt5编写的应用程序就可以按原样工作。然而,以这种方式导入并不能解决上面提到的Qt5和Qt6之间的任何差异。为此,我们推荐使用QtPy库。

通用兼容性

如果你需要支持所有的Python Qt库(PyQt5、PyQt6、PySide2、PySide6),或者依赖于在Qt版本之间发生变化的特性,那么你应该考虑使用QtPy。这个包是围绕所有版本的Qt库的一个小型抽象层,它允许你在你的应用程序中交替使用它们(尽可能)。

如果你正在开发需要跨版本移植的Python库或应用程序,那么它绝对值得一看。

结论

正如我们所发现的,PyQt5和PyQt6之间没有大的区别。有的变化可以很容易地被解决。如果你是使用Qt进行Python GUI编程的新手,你可能会发现从PyQt5开始更容易,但对于任何新项目,我建议从PyQt6开始