0

I use QT to build my GUI, and decorator to record the log. When I use the decorator on a slot, the GUI will crush.

The code is:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


def LogInfos(func):

    def wrapper(*s, **gs):
        print('log')
        ret = func(*s, **gs)
        return ret

    return wrapper
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        layout = QHBoxLayout(self)
        btn = QPushButton('test')
        layout.addWidget(btn)
        btn.clicked.connect(self.testSlot)

    @LogInfos
    def testSlot(self):
        print('test slot')


@LogInfos
def testLog():
    print('test log')

if __name__ == '__main__':

    testLog()

    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

I has tested that the decorator function is OK, and the GUI is ok after remove the decorator.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Qiang Zhang
  • 820
  • 8
  • 32

2 Answers2

1

See @ekhumoro's explanation of why, but using the decorated method in the slot is causing your problem due to an incorrect signature.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


def LogInfos(func):

    def wrapper(*s, **gs):
        print('log')
        ret = func(*s, **gs)
        return ret

    return wrapper
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        layout = QHBoxLayout(self)
        btn = QPushButton('test')
        layout.addWidget(btn)
        btn.clicked.connect(self.testSlot)

    @LogInfos
    def testSlot(self, checked=False):
        print('test slot')


@LogInfos
def testLog():
    print('test log')

if __name__ == '__main__':

    testLog()

    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
shao.lo
  • 4,387
  • 2
  • 33
  • 47
  • 1
    The [clicked signal](https://doc.qt.io/qt-5/qabstractbutton.html#clicked) sends its *checked* state by default, so the slot needs to defined like this: `def testSlot(self, checked=False):`. The function doesn't have a `self` argument, so it's not affected. – ekhumoro May 08 '18 at 18:47
  • There is no point in using a second slot - you might as well just use a `lambda` as in the other answer. Or, even better, define the original slot properly as I suggested, so that no work-around is required. – ekhumoro May 08 '18 at 23:35
  • 1
    @ekhumoro I agree. I added the second to show the difference...I will update the code to show the clear correct solution. – shao.lo May 09 '18 at 03:51
0

Try it: btn.clicked.connect(lambda: self.testSlot())

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


def LogInfos(func):

    def wrapper(*s, **gs):
        print('log')
        ret = func(*s, **gs)
        return ret

    return wrapper
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        layout = QHBoxLayout(self)
        btn = QPushButton('test')
        layout.addWidget(btn)
        #btn.clicked.connect(self.testSlot)
        btn.clicked.connect(lambda: self.testSlot())         

    @LogInfos
    def testSlot(self):
        print('test slot')


@LogInfos
def testLog():
    print('test log')

if __name__ == '__main__':

    testLog()

    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

enter image description here

S. Nick
  • 12,879
  • 8
  • 25
  • 33