QWizardPage, error when running registerField. Signal name cut off
-
Hello,
I have a problem when trying to use registerField for a QWizardPage in which i'm selecting one node name (a str) from a QWidgetList. This field is marked mandatory, along this a property for it is created aswell as a signal. But when calling self.registerField("nodeName*", self, "selectedNode", "nodeSelectionChanged()") in the class i get:
QObject::connect: No such signal Wizard_NodeSelection::odeSelectionChanged()
I'm not completely sure if I type the signal name correct. But I've tried it without the parenthesis aswell and it yields:
QObject::connect: Parentheses expected, signal Wizard_NodeSelection::odeSelectionChanged
Anyways, notice how the 'n' falls of from the signal name...
Test code is as follows:
from PySide2.QtCore import Property, Signal from PySide2.QtWidgets import QWizard, QWizardPage, QLineEdit, QListWidget, QGridLayout, QPushButton, QLabel def get_nodes(): return ["Test1", "Test2", "Test3", "Test4", "Test5"] class NodeWizard(QWizard): def __init__(self, parent): QWizard.__init__(self, parent) self.addPage(Wizard_NodeSelection(self)) self.setModal(True) self.setWindowTitle("Nodes") def accept(self): print("DONE! Chosen node {}".format(self.field("nodeName"))) QWizard.accept(self) class Wizard_NodeSelection(QWizardPage): # Create a signal for when the selected node changes nodeSelectionChanged = Signal() def __init__(self, parent): QWizardPage.__init__(self, parent) self.selectedNode_val = None self.setTitle("Select Node") layout = QGridLayout() # Create a simple list widget for testing and initialize it with some test data self.nodeList = QListWidget() self.nodeList.addItems(get_nodes()) # Whenever we change item trigger a selection change self.nodeList.currentItemChanged.connect(self.nodeListSelectionChanged) layout.addWidget(self.nodeList) # Getting error here self.registerField("nodeName*", self, "selectedNode", "nodeSelectionChanged()") self.setLayout(layout) def getSelectedNode(self): return self.selectedNode_val def setSelectedNode(self, node): self.selectedNode_val = node print("Updated selected node to {}".format(node)) self.nodeSelectionChanged.emit() print("Emitted signal") def nodeListSelectionChanged(self, current, previous): if current: self.setSelectedNode(current.text()) else: self.setSelectedNode(None) # Create a property for this page selectedNode = Property(str, getSelectedNode, setSelectedNode) # For testing if __name__ == "__main__": from PySide2.QtWidgets import QApplication, QMainWindow import sys app = QApplication(sys.argv) window = QMainWindow() wizard = NodeWizard(window) button = QPushButton("wizard", window) button.clicked.connect(lambda: wizard.show()) window.show() sys.exit(app.exec_())
Any thoughts?
-
Okay so I tried this weird thing. I changed my signal name to actually be odeSelectionChanged instead of nodeSelectionChanged and adjusted the code accordingly except for the registerField bit, the code then runs as intented.
SO changing the code to something like this:
from PySide2.QtCore import Property, Signal from PySide2.QtWidgets import QWizard, QWizardPage, QLineEdit, QListWidget, QGridLayout, QPushButton, QLabel def get_nodes(): return ["Test1", "Test2", "Test3", "Test4", "Test5"] class NodeWizard(QWizard): def __init__(self, parent): QWizard.__init__(self, parent) self.addPage(Wizard_NodeSelection(self)) self.setModal(True) self.setWindowTitle("Nodes") def accept(self): print("DONE! Chosen node {}".format(self.field("nodeName"))) QWizard.accept(self) class Wizard_NodeSelection(QWizardPage): # Create a signal for when the selected node changes odeSelectionChanged = Signal() def __init__(self, parent): QWizardPage.__init__(self, parent) self.selectedNode_val = None self.setTitle("Select Node") layout = QGridLayout() # Create a simple list widget for testing and initialize it with some test data self.nodeList = QListWidget() self.nodeList.addItems(get_nodes()) # Whenever we change item trigger a selection change self.nodeList.currentItemChanged.connect(self.nodeListSelectionChanged) layout.addWidget(self.nodeList) # Getting error here self.registerField("nodeName*", self, "selectedNode", "nodeSelectionChanged()") self.setLayout(layout) def getSelectedNode(self): return self.selectedNode_val def setSelectedNode(self, node): self.selectedNode_val = node print("Updated selected node to {}".format(node)) self.odeSelectionChanged.emit() print("Emitted signal") def nodeListSelectionChanged(self, current, previous): if current: # For testing purposes, only change to a valid value when selecting node Test3 if current.text() == "Test3": self.setSelectedNode(current.text()) return self.setSelectedNode(None) # Create a property for this page selectedNode = Property(str, getSelectedNode, setSelectedNode) # For testing if __name__ == "__main__": from PySide2.QtWidgets import QApplication, QMainWindow import sys app = QApplication(sys.argv) window = QMainWindow() wizard = NodeWizard(window) button = QPushButton("wizard", window) button.clicked.connect(lambda: wizard.show()) window.show() sys.exit(app.exec_())
actually works.
What gives? What am I doing wrong :) I'm only 3 days in to learning python and pyside2 so chances are that I'm doing something wrong :)
-
@agnon
If what you say is indeed the case, I suspect you have found a bug!Your call to
registerField()
looks right to me. Put your signal name back to the correctnodeSelectionChanged
and instead pass"ZnodeSelectionChanged()"
for the signal. Does that make it work? That would be your workaround for now. Also, if you remove the*
from the name, does that make any difference to the handling of the signal name?Assuming there is indeed an issue, it is not certain whether that is from Python/PySide2 or in the underlying Qt code. I don't suppose you're in a position to test it from PyQt5 instead of PySide2? In any case, you would need to report this, including the Qt & PySide2 versions, at https://bugreports.qt.io/, probably in the "PySide2" category.
-
@JonB
Thanks for the quick reply.I did change the name back and instead used a Z in front of the signal when registering the field. This works, it's basically the same thing right, only nicer :)
Also tried it without modifications when not marking it as mandatory. But then it doesn't care about what signal name i supply. So I guess the signal name is really only needed (and connected) for when you need to trigger an update to happen in regards to mandatory fields.
I'll try to implement this in PyQt5 to see if it's present there aswell...
-
Using PyQt5 it works. PyQt5 doesn't rely on the signal to be passed as a str though. So it's quite different.
This works:
from PyQt5.QtCore import pyqtProperty, pyqtSignal from PyQt5.QtWidgets import QWizard, QWizardPage, QLineEdit, QListWidget, QGridLayout, QPushButton, QLabel def get_nodes(): return ["Test1", "Test2", "Test3", "Test4", "Test5"] class NodeWizard(QWizard): def __init__(self, parent): QWizard.__init__(self, parent) self.addPage(Wizard_NodeSelection(self)) self.setModal(True) self.setWindowTitle("Nodes") def accept(self): print("DONE! Chosen node {}".format(self.field("nodeName"))) QWizard.accept(self) class Wizard_NodeSelection(QWizardPage): # Create a signal for when the selected node changes nodeSelectionChanged = pyqtSignal() def __init__(self, parent): QWizardPage.__init__(self, parent) self.selectedNode_val = None self.setTitle("Select Node") layout = QGridLayout() # Create a simple list widget for testing and initialize it with some test data self.nodeList = QListWidget() self.nodeList.addItems(get_nodes()) # Whenever we change item trigger a selection change self.nodeList.currentItemChanged.connect(self.nodeListSelectionChanged) layout.addWidget(self.nodeList) # Getting error here self.registerField("nodeName*", self, "selectedNode", self.nodeSelectionChanged) self.setLayout(layout) def getSelectedNode(self): return self.selectedNode_val def setSelectedNode(self, node): self.selectedNode_val = node print("Updated selected node to {}".format(node)) self.nodeSelectionChanged.emit() print("Emitted signal") def nodeListSelectionChanged(self, current, previous): if current: if current.text() == "Test3": self.setSelectedNode(current.text()) return self.setSelectedNode(None) # Create a property for this page selectedNode = pyqtProperty(str, getSelectedNode, setSelectedNode) # For testing if __name__ == "__main__": from PyQt5.QtWidgets import QApplication, QMainWindow import sys app = QApplication(sys.argv) window = QMainWindow() wizard = NodeWizard(window) button = QPushButton("wizard", window) button.clicked.connect(lambda: wizard.show()) window.show() sys.exit(app.exec_())
I guess I'll report this as a bug then.
-
@agnon said in QWizardPage, error when running registerField. Signal name cut off:
PyQt5 doesn't rely on the signal to be passed as a str though.
self.registerField("nodeName*", self, "selectedNode", self.nodeSelectionChanged)
Have you tried this under PySide2?
Anyway, I leave you to report. I think there is a "QtForPython" category somewhere in that bug reporting system. Tell them what versions you are using, and maybe show what does work under PyQt5 as well.
-
@JonB said in QWizardPage, error when running registerField. Signal name cut off:
Have you tried this under PySide2?
Yes, I have :)
TypeError: 'PySide2.QtWidgets.QWizardPage.registerField' called with wrong argument types:
PySide2.QtWidgets.QWizardPage.registerField(str, Wizard_NodeSelection, str, SignalInstance)
Supported signatures:
PySide2.QtWidgets.QWizardPage.registerField(str, PySide2.QtWidgets.QWidget, typing.Union[bytes, NoneType] = None, typing.Union[bytes, NoneType] = None) -
Hi,
Based on the 5.15.1 documented signature you should pass the name of the signal as string and not the signal itself.