在Windows上,我需要在Python中使用一些用C++编写的自定义Qt5小部件,pyside2因为它的许可证我必须使用它.
我已经能够pyside2从源代码编译库(连同shiboken2示例),但我无法找到如何包装自定义Qt5小部件的简单示例.
我知道pyside2仍然没有正式发布,但它似乎已经被使用(例如,在Maya中):在PySide2应用程序中,我如何获得QWindow的ID?
任何人都可以给出提示或指示吗?一个最小的例子会更好.
编辑
根据@placinta评论,我创建了一个包含一个最小示例的repo,它试图包装一个自定义QMainWindow.
在我的测试中,我使用了包装5.6 的pyside2 Conda包Qt.
当我执行shiboken2可执行文件时,我收到了大量的警告.
我认为这些警告触发编译错误与shiboken2生成的代码.
我使用PySide2作为我的GUI框架和PyInstaller构建了一个小的gui应用程序,以制作一个文件exe文件。
该应用程序可以在某些PC(Windows 7和10)上完美运行,但是在其他PC上则无法启动-向我显示错误消息:
“致命错误!:无法执行脚本pyi_rth_qt5plugins”
我相信它可能不会捆绑Qt5Gui.dll,Qt5Core.dll和Qt5Widgets.dll,但是我不知道如何使用PyInstaller做到这一点。
有谁知道如何解决这个问题?
这是我的.spec文件:
# -*- mode: python -*-
block_cipher = None
a = Analysis(['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='Application',
debug=True,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True , icon='Images\\Application_icon.ico')
Run Code Online (Sandbox Code Playgroud)
编辑
这是从cmd运行且debug = True时的完整输出。我发现奇怪的是,它是指我在(例如File "c:\users\jake\Projects\Application\venv\lib\site-packages\PyInsta
ller\loader\pyimod03_importers.py", line 714, in load_module)上开发应用程序的PC,而不是我正在测试并从中获得此错误消息的PC。
[4588] PyInstaller Bootloader 3.x
[4588] LOADER: executable is C:\Users\User\Desktop\Application.exe
[4588] LOADER: homepath is C:\Users\User\Desktop
[4588] LOADER: _MEIPASS2 is NULL
[4588] …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
if __name__ == '__main__':
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load('./QML/main.qml')
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,如果“engine.load”失败,我只会看到“-1”退出代码,而不会详细说明失败的原因以及发生的错误。如何在 python 控制台中打印 QML 错误?
QQuickView当使用而不是 QQmlApplicationEngine时,有一个解决方法,并在这篇文章中进行了描述,但是,我想知道 QQmlApplicationEngine 是否可以实现类似的功能?
我想发送字典,其中包含动态创建 qml 对象所需的数据,从 PySide2 类发送到 QML 接口,并且由于我需要响应某些事件来执行此操作,因此我需要使用信号和槽。
由于我刚刚开始使用 QML 和 python,我尝试创建一个简单的项目只是为了玩玩(正如您从代码中看到的)
质量管理语言:
import QtQuick 2.10
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import QtQuick.Controls.Material 2.3
import QtQuick.Layouts 1.0
ApplicationWindow {
id: mainWindow
width:640
height: 480
title: qsTr("Simple ui")
visible: true
locale:locale
Rectangle {
id: appWindow
objectName: "splasso"
anchors.fill: parent
color: "yellow"
Material.accent: Material.DeepPurple
Material.primary: Material.Cyan
Component.onCompleted: function(){
TestVar.theSignal.connect(catchAnswer);
testList.append(stuff1);
testList.append(stuff2);
testList.append(stuff3);
testCombo.currentIndex = 0;
//Just a pointless test print
console.log(JSON.stringify(stuff1));
}
function catchAnswer(answer){
console.log(JSON.stringify(answer));
}
ComboBox{
id: testCombo
anchors.centerIn: parent
width: …Run Code Online (Sandbox Code Playgroud) 我有一个在 python3.6 下运行的 python 应用程序,并使用 PyQt5 加载 Ui 窗口。这些窗口是使用 Qt Designer 5.9.4 创建的。下面的代码显示了 PyQt5 的工作示例。
现在我想拥有完全相同的功能,但使用 PySide2。目前,我无法弄清楚如何加载 Ui 文件并在单独的类中使用其对象(按钮、表格等)。例如:通过单击第一个窗口/类中的按钮,会出现第二个窗口,其中的函数是在单独的类中定义的,请参阅示例。我找到的所有示例都只是加载一个 Ui 窗口,但没有展示如何使用它。有人可以帮忙吗?
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from PyQt5.uic import loadUiType
from PyQt5 import QtGui, QtCore
Ui_FirstWindow, QFirstWindow = loadUiType('first_window.ui')
Ui_SecondWindow, QSecondWindow = loadUiType('second_window.ui')
class First(Ui_FirstWindow, QFirstWindow):
def __init__(self):
super(First, self).__init__()
self.setupUi(self)
self.button.clicked.connect(self.show_second_window)
def show_second_window(self):
self.Second = Second()
self.Second.show()
class Second(Ui_SecondWindow, QSecondWindow):
def __init__(self):
super(Second, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud) 由于以下代码,我从 PyQt5 切换到 PySide2 时遇到一些问题:
class EnumModel(QtCore.QAbstractListModel):
def __init__(self, list_of_enums):
"""
Enumeration model
:param list_of_enums: list of enumeration values to show
"""
QtCore.QAbstractListModel.__init__(self)
self.items = list_of_enums
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def data(self, index, role=QtCore.Qt.DisplayRole):
if index.isValid() is True:
if role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.items[index.row()].value[0])
elif role == QtCore.Qt.ItemDataRole:
return QtCore.QVariant(self.items[index.row()].value[0])
return QtCore.QVariant()
Run Code Online (Sandbox Code Playgroud)
代码在 PyQt5 下运行良好。
在我的迁移过程中我发现官方网站说:
PySide 仅支持 PyQt 的 API 2(请参阅 PSEP 101)了解详细信息。因此 Qt 类(例如 QStrings、QStringLists 和 QVariants)在 PySide 上不可用。相反,您应该简单地使用本机 Python 数据类型。
所以解决方案是(我猜)简单地更改QVariant为str …
我对 matplotlib 中的示例进行了轻微修改:https://matplotlib.org/gallery/user_interfaces/embedding_in_qt_sgskip.html
唯一改变的是导入,因为我使用的是 PySide2,所以导入看起来像这样:
from PySide2 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import (FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
Run Code Online (Sandbox Code Playgroud)
在 pycharm 中运行代码或单独运行脚本时,这工作正常,但是在使用 PyInstaller 创建 .exe 后,我收到以下错误:
TypeError: 'PySide2.QtWidgets.QBoxLayout.addWidget' called with wrong argument types:
PySide2.QtWidgets.QBoxLayout.addWidget(FigureCanvasQTAgg)
Supported signatures:
PySide2.QtWidgets.QBoxLayout.addWidget(PySide2.QtWidgets.QWidget, int=0,
PySide2.QtCore.Qt.Alignment=Default(Qt.Alignment))
PySide2.QtWidgets.QBoxLayout.addWidget(PySide2.QtWidgets.QWidget)
Run Code Online (Sandbox Code Playgroud)
看来FigureCanvasQtAgg不再被识别为QWidget,因此无法将其添加到布局中。
我尝试添加这些行来建议 pyside,如下所示:
os.environ["QT_API"] = "PySide2"
matplotlib.use('Qt5Agg')
matplotlib.rcParams['backend.qt5']='PySide2'
Run Code Online (Sandbox Code Playgroud)
但是,这不会更改 exe 的错误消息。在pycharm中仍然运行良好。
编辑:替换此行后,这似乎是 PySide2+PyInstaller 的一些问题:
from PySide2 import QtCore, QtWidgets
Run Code Online (Sandbox Code Playgroud)
用这一行:
from PyQt5 import QtCore, QtWidgets
Run Code Online (Sandbox Code Playgroud)
即使在使用 PyInstaller 之后它仍然可以工作。
但我想使用 PySide2 而不是 PyQt5,有人知道解决这个问题的方法吗?
因此,PySide2 删除了 QVariant* 类型。
然而,QtQuick 公开了大量的 QVariant API。
更具体地说,我想使用非常方便的功能将 QVariantList 作为 ListView 的模型传递,而不必实现完全成熟的 QAIM。
然而,通过 setContextProperty 将这样的对象提供给 QML
class Test(QObject):
def __init__(self):
super(Test, self).__init__()
self.propertyList = ["FOO", "BAR", 1]
def model(self):
return self.propertyList
modelChanged = Signal()
model = Property(list, model, notify=modelChanged)
Run Code Online (Sandbox Code Playgroud)
然后打印 .model 产生:
qml: QVariant(PySide::PyObjectWrapper)
Run Code Online (Sandbox Code Playgroud)
那么如何以 qml 实际能够理解的形式将 python 列表传递给 qml 呢?
TL;DR:我想要一个直接替换 PyQt5 的loadUiType()功能的uic模块,它可以与 PySide2 和 Python 3.6+ 一起使用。
我想将 PyQt5 应用程序迁移到 PySide2。我使用的一个常见模式是,我在 Qt Designer 中创建用户界面设计,并动态加载生成的.ui文件作为扩展 Python 代码中 Qt 小部件的混合类,例如主窗口本身:
from PyQt5 import QtWidgets, uic
class Window(QtWidgets.QMainWindow, uic.loadUiType('design.ui')[0]):
def __init__(self):
super().__init__()
self.setupUi(self)
print(self.label.text())
app = QtWidgets.QApplication([])
window = Window()
window.show()
app.exec_()
Run Code Online (Sandbox Code Playgroud)
这意味着我可以放弃在命令行上将.ui设计编译为.pyPython 模块。更重要的是,混合模式让我可以通过self.name导入窗口小部件的范围内访问设计中定义的所有 Qt 窗口小部件,name在 Qt 设计器中指定的位置。
为了提供可重现的示例,这里有一个与上述 Python 代码一起使用的最小 Qt 设计文件,其中引用为design.ui:
from PyQt5 import QtWidgets, uic
class Window(QtWidgets.QMainWindow, uic.loadUiType('design.ui')[0]):
def __init__(self):
super().__init__()
self.setupUi(self) …Run Code Online (Sandbox Code Playgroud) 我正在学习 python 和 PySide2 并跟进 learnpytq 的一些教程,特别是https://www.learnpyqt.com/courses/custom-widgets/bitmap-graphics/,我陷入了困境。
接下来,创建像素图画布后,我们在小部件上移动 mouseMoveEvent 以确保鼠标的坐标始终相对于画布。我已经复制了提供的源,但仍在运行的应用程序中,鼠标位置相对于窗口(或父窗口小部件,我不确定),导致绘制的线条偏移到鼠标位置。
这是代码:
import sys
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import Qt
class Canvas(QtWidgets.QLabel):
def __init__(self):
super().__init__()
pixmap = QtGui.QPixmap(600, 300)
self.setPixmap(pixmap)
self.last_x, self.last_y = None, None
self.pen_color = QtGui.QColor('#000000')
def set_pen_color(self, c):
self.pen_color = QtGui.QColor(c)
def mouseMoveEvent(self, e):
if self.last_x is None: # First event.
self.last_x = e.x()
self.last_y = e.y()
return # Ignore the first time.
painter = QtGui.QPainter(self.pixmap())
p = painter.pen()
p.setWidth(4)
p.setColor(self.pen_color)
painter.setPen(p) …Run Code Online (Sandbox Code Playgroud) pyside2 ×10
python ×8
pyqt5 ×3
python-3.x ×3
qml ×3
qt-designer ×2
c++ ×1
matplotlib ×1
pyinstaller ×1
pyside ×1
qt ×1
qt-signals ×1
qt-slot ×1
qt5 ×1
windows ×1