Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
196 views
in Technique[技术] by (71.8m points)

python - Signals and Missing Positional Arguments

I developed two windows in QtDesigner (SourceForm, DestinationForm) and used pyuic5 to convert their .ui pages. I am using a third class WController as a way to navigate between the two windows using a stacked widget. I have a button in SourceForm that populates treeWidget with some data and the method handle_treewidget_itemchange dictates what happens when a particular item in treeWidget gets checked or unchecked by using self.treeWidget.itemChanged.connect(self.handle_treewidget_itemchange). It was my understanding that itemChanged.connect would automatically send the row and column of what was changed to the slot but when handle_treewidget_itemchange(self,row,col) gets called for the first time, my script crashes with a TypeError:

TypeError: handle_treewidget_itemchange() missing 2 required positional arguments: 'row' and 'col'

If I take out the row and col args, the script runs fine. When I originally had both the method and the call in the SourceForm .py file itself, my code worked as intended...maybe this is just a scope issue? I am beginning to think attempting to use PyQt while still inexperienced with Python a bad idea :(

I've tried to strip the code down to the essentials:

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import pyqtSlot
from imp_sourceform import Ui_SourceForm
from imp_destform import Ui_DestinationForm


class WController(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(WController, self).__init__(parent)
        self.central_widget = QtWidgets.QStackedWidget()
        self.setCentralWidget(self.central_widget)

        self.sourcewindow = SourceForm()
        self.destinationwindow = DestinationForm()

        self.central_widget.addWidget(self.sourcewindow)
        self.central_widget.addWidget(self.destinationwindow)

        self.central_widget.setCurrentWidget(self.sourcewindow)

        self.sourcewindow.selectdestinationsbutton.clicked.connect(lambda: self.navigation_control(1))
        self.destinationwindow.backbutton.clicked.connect(lambda: self.navigation_control(0))

    def navigation_control(self, topage):
        if topage == 1:
            self.central_widget.setCurrentWidget(self.destinationwindow)
        elif topage == 0:
            self.central_widget.setCurrentWidget(self.sourcewindow)

class SourceForm(QtWidgets.QWidget, Ui_SourceForm):
    def __init__(self):
        super(SourceForm, self).__init__()
        self.setupUi(self)

        self.treeWidget.itemChanged.connect(self.handle_treewidget_itemchange) 

    @pyqtSlot()
    def handle_treewidget_itemchange(self,row,col): 
        if row.parent() is None and row.checkState(col) == QtCore.Qt.Unchecked: 
            for x in range(0,row.childCount()):
                row.child(x).setCheckState(0, QtCore.Qt.Unchecked)
        elif row.parent() is None and row.checkState(col) == QtCore.Qt.Checked:
            for x in range(0,row.childCount()):
                row.child(x).setCheckState(0, QtCore.Qt.Checked)
        else:
            pass

class DestinationForm(QtWidgets.QWidget, Ui_DestinationForm):
    def __init__(self):
        super(DestinationForm, self).__init__()
        self.setupUi(self)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = WController()
    window.show()
    sys.exit(app.exec_())
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to be careful when using pyqtSlot, as it is only too easy to clobber the signature of the slot it is decorating. In your case, it has re-defined the slot as having no arguments, which explains why you are getting that error message. The simple fix is to simply remove it, as your example will work perfectly well without it.

The main purpose of pyqtSlot is to allow several different overloads of a slot to be defined, each with a different signature. It may also be needed sometimes when making cross-thread connections. However, these use-cases are relatively rare, and in most PyQt/PySide applications it is not necessary to use pyqtSlot at all. Signals can be connected to any python callable object, whether it is decorated as a slot or not.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...