Frage

I want use the autoconnection feature. I am using this example:

http://www.eurion.net/python-snippets/snippet/Connecting%20signals%20and%20slots.html

it works, but I want to create my own signals and own slots, the example using built in signals.

for example, here are a custom signal with a custom slot, but don't works:

import sys
from PyQt4 import QtGui, QtCore

class SignalsAndSlots(QtGui.QWidget):

    testSignal = QtCore.pyqtSignal(str,name='testSignal')  



    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setObjectName('testObject')
        self.label = QtGui.QLabel(self)

        QtCore.QMetaObject.connectSlotsByName(self)
        self.emitSignal()


    def emitSignal(self):
        self.testSignal.emit('message')  

    @QtCore.pyqtSlot(str,name='on_testObject_testSignal')     
    def autoSlot(self,msg):
        self.label.setText(msg)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    gui = SignalsAndSlots()
    gui.show()
    app.exec_()

Thanks a lot

War es hilfreich?

Lösung

Ber is right. This what the pyqt documentation says:

QMetaObject.connectSlotsByName searches recursively for all child objects of the given object [...]

Here is a simple example with custom signals :

import sys
from PyQt4 import QtGui, QtCore

class CustomButton(QtGui.QPushButton):
    custom_clicked = QtCore.pyqtSignal(str, name='customClicked')
    def mousePressEvent(self, event):
        self.custom_clicked.emit("Clicked!")

class SignalsAndSlots(QtGui.QWidget):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        layout = QtGui.QHBoxLayout(self)
        self.custom_button = CustomButton("Press Me", self)
        self.custom_button.setObjectName('customButton')
        self.label = QtGui.QLabel("Nothing...", parent=self)
        layout.addWidget(self.custom_button)
        layout.addWidget(self.label)
        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot(str, name='on_customButton_customClicked')     
    def autoSlot(self, msg):
        self.label.setText(msg)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    gui = SignalsAndSlots()
    gui.show()
    app.exec_()

But I think you should consider not using the object names. New-style signal connection is way neater. Here is the same application :

import sys
from PyQt4 import QtGui, QtCore

class CustomButton(QtGui.QPushButton):
    custom_clicked = QtCore.pyqtSignal(str)
    def mousePressEvent(self, event):
        self.custom_clicked.emit("Clicked!")

class SignalsAndSlots(QtGui.QWidget):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        layout = QtGui.QHBoxLayout(self)
        self.custom_button = CustomButton("Press Me", self)
        self.custom_button.setObjectName('customButton')
        self.label = QtGui.QLabel("Nothing...", parent=self)
        layout.addWidget(self.custom_button)
        layout.addWidget(self.label)
        self.custom_button.custom_clicked.connect(self.on_clicked)

    def on_clicked(self, msg):
        self.label.setText(msg)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    gui = SignalsAndSlots()
    gui.show()
    app.exec_()

Andere Tipps

I investigated a bit into the doc. of QtCore.QMetaObject.connectSlotsByName().

For this, I made an MCVE to collect things not working vs. things working:

#!/usr/bin/python3

import sys
from PyQt5.QtCore import QT_VERSION_STR
from PyQt5.QtCore import QMetaObject, pyqtSlot
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QWidget

class MainWindow(QMainWindow):
  def __init__(self):
    QMainWindow.__init__(self)
    # build GUI
    qMain = QWidget()
    qVBox = QVBoxLayout()
    qBtnPreview1 = QPushButton("Preview 1")
    qBtnPreview1.setObjectName("preview1")
    qVBox.addWidget(qBtnPreview1)
    qBtnPreview2 = QPushButton("Preview 2")
    qBtnPreview2.setObjectName("preview2")
    qVBox.addWidget(qBtnPreview2)
    qBtnPreview3 = QPushButton("Preview 3")
    qBtnPreview3.setObjectName("preview3")
    qVBox.addWidget(qBtnPreview3)
    qBtnPreview4 = QPushButton("Preview 4")
    qBtnPreview4.setObjectName("preview4")
    qVBox.addWidget(qBtnPreview4)
    qBtnPreview5 = QPushButton("Preview 5")
    qBtnPreview5.setObjectName("preview5")
    qVBox.addWidget(qBtnPreview5)
    qBtnPreview6 = QPushButton("Preview 6")
    qBtnPreview6.setObjectName("preview6")
    qVBox.addWidget(qBtnPreview6)
    qMain.setLayout(qVBox)
    self.setCentralWidget(qMain)
    # install signal handlers
    qBtnPreview1.clicked.connect(lambda: print("preview1 clicked."))
    qBtnPreview2.clicked.connect(lambda: print("preview2 clicked."))
    qBtnPreview3.clicked.connect(lambda: print("preview3 clicked."))
    qBtnPreview4.clicked.connect(lambda: print("preview4 clicked."))
    qBtnPreview5.clicked.connect(lambda: print("preview5 clicked."))
    qBtnPreview6.clicked.connect(lambda: print("preview6 clicked."))
    QMetaObject.connectSlotsByName(self)

  @pyqtSlot()
  def preview1(self):
    print("MainWindow.preview1() called.")
  
  @pyqtSlot()
  def preview2_clicked(self):
    print("MainWindow.preview2_clicked() called.")
  
  @pyqtSlot()
  def on_preview3(self):
    print("MainWindow.on_preview3() called.")

  @pyqtSlot()
  def on_preview4_clicked(self):
    print("MainWindow.on_preview4_clicked() called.")
  
  @pyqtSlot(name='on_preview5_clicked')
  def preview5_clicked(self):
    print("MainWindow.preview5_clicked() called.")

  def on_preview6_clicked(self):
    print("MainWindow.on_preview6_clicked() called.")
    
if __name__ == '__main__':
  print("Qt Version: {}".format(QT_VERSION_STR))
  app = QApplication(sys.argv)
  # build GUI
  qWinMain = MainWindow()
  qWinMain.show()
  # runtime loop
  sys.exit(app.exec_())

Output:

$ ./testQMetaObjectConnectSlotsByName.py 
Qt Version: 5.9.3

snapshot of testQMetaObjectConnectSlotsByName.py

After clicking each of the six buttons once, I got:

preview1 clicked.
preview2 clicked.
preview3 clicked.
preview4 clicked.
MainWindow.on_preview4_clicked() called.
preview5 clicked.
MainWindow.preview5_clicked() called.
preview6 clicked.
MainWindow.on_preview6_clicked() called.
MainWindow.on_preview6_clicked() called.

Observations:

  1. MainWindow.preview1(), MainWindow.preview2_clicked(), MainWindow.on_preview3() were not connected. They don't follow the required convention of QtCore.QMetaObject.connectSlotsByName().

  2. MainWindow.on_preview4_clicked() is connected by name – properly following the required name convention.

  3. MainWindow.preview5_clicked() is connected as well – by giving the required name by @pyqtSlot(name='on_preview5_clicked').

  4. MainWindow.on_preview6_clicked() is connected as well – even without marking it as slot explicitly. (However, it is called twice for any reason which might be undesirable.)

  5. Explicit connections work in any case and appear more robust to me.

Further readings:


Actually, this was my answer to another question (SO: How to display two images in each Qlabel PyQt5) until I realized that QtCore.QMetaObject.connectSlotsByName() unlikely plays a role in that question. So, I moved it here where it may be more appropriate even although the question is a bit aged.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top