Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 correct nodeSelectionChanged 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)


  • Lifetime Qt Champion

    Hi,

    Based on the 5.15.1 documented signature you should pass the name of the signal as string and not the signal itself.


Log in to reply