使用 PyInstaller 在 --onefile 中使用 QML 构建 PyQt5
Use PyInstaller to build PyQt5 with QML in --onefile
我想通过 PyInstaller 在 Windows 10 和Ubuntu。但是,在成功构建可执行文件后,它会崩溃并显示一些错误消息。
material.py
:
import os
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtQml import QQmlApplicationEngine
if __name__ == "__main__":
app = QApplication(sys.argv)
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
engine = QQmlApplicationEngine()
engine.load(QUrl('basic.qml'))
sys.exit(app.exec_())
basic.qml
:(从here复制而来)
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
ApplicationWindow {
visible: true
Material.theme: Material.Dark
Material.accent: Material.Purple
Column {
anchors.centerIn: parent
RadioButton { text: qsTr("Small") }
RadioButton { text: qsTr("Medium"); checked: true }
RadioButton { text: qsTr("Large") }
}
}
我使用以下命令构建可执行文件:
pyinstaller ./material.py --onefile
构建后,可执行文件会显示错误消息。在 Windows 10:
QQmlApplicationEngine failed to load component
file:///D:/test/dist/basic.qml:1 plugin cannot be loaded for module "QtQuick": Cannot load library D:\test\dist\QtQuick.2\qtquick2plugin.dll: ???????w?????C
在Linux中:
QQmlApplicationEngine failed to load component
file:///media/username/EA9E5E009E5DC5AB/test/dist/basic.qml:1 plugin cannot be loaded for module "QtQuick": Cannot load library /media/username/EA9E5E009E5DC5AB/test/dist/QtQuick.2/libqtquick2plugin.so: (/usr/lib/x86_64-linux-gnu/libQt5Quick.so.5: symbol _ZN3QV46Object11markObjectsEPNS_4Heap4BaseEPNS_15ExecutionEngineE, version Qt_5_PRIVATE_API not defined in file libQt5Qml.so.5 with link time reference)
项目的文件树为:
. (test)
+-- build
| +-- (some files generate by PyInstaller)
+-- dist
| +-- QtQuick (the folder copied from Python site-packages)
| | +-- (some files copied form Python site-packages)
| +-- QtQuick.2 (the folder copied from Python site-packages)
| | +-- plugins.qmltypes
| | +-- qmldir
| | +-- qtquick2plugin.dll (or 'libqtquick2plugin.so' in Linux)
| +-- basic.qml
| +-- material.exe (or 'material' in Linux)
+-- basic.qml
+-- material.py
+-- material.spec
我复制了两个文件夹,QtQuick
和 QtQuick.2
,因为我在这个 question and I do the same thing as the answer 上遇到了同样的问题。我一直在寻找解决方案一个星期,不知道为什么它无法加载库。
我找到了 Pyinstaller 3.3.1
和 PyQt5 >= 5.11
的解决方法来解决这个问题。
使用pyrcc5
编译QML文件并将其导入Python脚本。因此,Pyinstaller 会自动打包它们,而无需将 QML 文件放在可执行文件旁边。
在这种情况下,用pyrcc5
、
编译basic.qml
pyrcc5 -o src.py src.qrc
然后,修改material.py
,
import os
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtQml import QQmlApplicationEngine
import src # import the resource file compiled by pyrcc5
if __name__ == "__main__":
app = QApplication(sys.argv)
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
engine = QQmlApplicationEngine()
engine.load(QUrl('qrc:/basic.qml')) # modify the url for qrc format
sys.exit(app.exec_())
最后使用如下命令打包源码
pyinstaller material.py --windowed --onefile --hidden-import PyQt5.sip --hidden-import PyQt5.QtQuick
需要隐藏导入,因为新版本的 PyQt5 修改了一些模块名称,因此使它们与当前的 Pyinstaller 挂钩不兼容。
但是,在代码打包后,结果发布二进制文件可能存在一些关于 QtQuick2 样式显示的问题(尤其是 Material 和 Imagine 主题)。您可以使用最新开发的 Pyinstaller 版本 (3.4 dev
) 解决此问题。
我想通过 PyInstaller 在 Windows 10 和Ubuntu。但是,在成功构建可执行文件后,它会崩溃并显示一些错误消息。
material.py
:
import os
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtQml import QQmlApplicationEngine
if __name__ == "__main__":
app = QApplication(sys.argv)
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
engine = QQmlApplicationEngine()
engine.load(QUrl('basic.qml'))
sys.exit(app.exec_())
basic.qml
:(从here复制而来)
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
ApplicationWindow {
visible: true
Material.theme: Material.Dark
Material.accent: Material.Purple
Column {
anchors.centerIn: parent
RadioButton { text: qsTr("Small") }
RadioButton { text: qsTr("Medium"); checked: true }
RadioButton { text: qsTr("Large") }
}
}
我使用以下命令构建可执行文件:
pyinstaller ./material.py --onefile
构建后,可执行文件会显示错误消息。在 Windows 10:
QQmlApplicationEngine failed to load component
file:///D:/test/dist/basic.qml:1 plugin cannot be loaded for module "QtQuick": Cannot load library D:\test\dist\QtQuick.2\qtquick2plugin.dll: ???????w?????C
在Linux中:
QQmlApplicationEngine failed to load component
file:///media/username/EA9E5E009E5DC5AB/test/dist/basic.qml:1 plugin cannot be loaded for module "QtQuick": Cannot load library /media/username/EA9E5E009E5DC5AB/test/dist/QtQuick.2/libqtquick2plugin.so: (/usr/lib/x86_64-linux-gnu/libQt5Quick.so.5: symbol _ZN3QV46Object11markObjectsEPNS_4Heap4BaseEPNS_15ExecutionEngineE, version Qt_5_PRIVATE_API not defined in file libQt5Qml.so.5 with link time reference)
项目的文件树为:
. (test)
+-- build
| +-- (some files generate by PyInstaller)
+-- dist
| +-- QtQuick (the folder copied from Python site-packages)
| | +-- (some files copied form Python site-packages)
| +-- QtQuick.2 (the folder copied from Python site-packages)
| | +-- plugins.qmltypes
| | +-- qmldir
| | +-- qtquick2plugin.dll (or 'libqtquick2plugin.so' in Linux)
| +-- basic.qml
| +-- material.exe (or 'material' in Linux)
+-- basic.qml
+-- material.py
+-- material.spec
我复制了两个文件夹,QtQuick
和 QtQuick.2
,因为我在这个 question and I do the same thing as the answer 上遇到了同样的问题。我一直在寻找解决方案一个星期,不知道为什么它无法加载库。
我找到了 Pyinstaller 3.3.1
和 PyQt5 >= 5.11
的解决方法来解决这个问题。
使用pyrcc5
编译QML文件并将其导入Python脚本。因此,Pyinstaller 会自动打包它们,而无需将 QML 文件放在可执行文件旁边。
在这种情况下,用pyrcc5
、
basic.qml
pyrcc5 -o src.py src.qrc
然后,修改material.py
,
import os
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtQml import QQmlApplicationEngine
import src # import the resource file compiled by pyrcc5
if __name__ == "__main__":
app = QApplication(sys.argv)
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
engine = QQmlApplicationEngine()
engine.load(QUrl('qrc:/basic.qml')) # modify the url for qrc format
sys.exit(app.exec_())
最后使用如下命令打包源码
pyinstaller material.py --windowed --onefile --hidden-import PyQt5.sip --hidden-import PyQt5.QtQuick
需要隐藏导入,因为新版本的 PyQt5 修改了一些模块名称,因此使它们与当前的 Pyinstaller 挂钩不兼容。
但是,在代码打包后,结果发布二进制文件可能存在一些关于 QtQuick2 样式显示的问题(尤其是 Material 和 Imagine 主题)。您可以使用最新开发的 Pyinstaller 版本 (3.4 dev
) 解决此问题。