views:

1932

answers:

3
+1  Q: 

PyQt: No such slot

I am starting to learn Qt4 and Python, following along some tutorial i found on the interwebs. I have the following two files:

lcdrange.py:

from PyQt4 import QtGui, QtCore

class LCDRange(QtGui.QWidget):                        
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        lcd = QtGui.QLCDNumber(2)

        self.slider = QtGui.QSlider()
        self.slider.setRange(0,99)
        self.slider.setValue(0)

        self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'),
                     lcd, QtCore.SLOT('display(int)'))
        self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'),
                     self, QtCore.SIGNAL('valueChanged(int)'))

        layout = QtGui.QVBoxLayout()
        layout.addWidget(lcd)
        layout.addWidget(self.slider)
        self.setLayout(layout)

    def value(self):
        self.slider.value()

    def setValue(self,value):
        self.slider.setValue(value)

main.py:

import sys
from PyQt4 import QtGui, QtCore

from lcdrange import LCDRange

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        quit = QtGui.QPushButton('Quit')
        quit.setFont(QtGui.QFont('Times', 18, QtGui.QFont.Bold))
        self.connect(quit, QtCore.SIGNAL('clicked()'), QtGui.qApp, QtCore.SLOT('quit()'))

        grid = QtGui.QGridLayout()
        previousRange = None

        for row in range(0,3):
            for column in range(0,3):
                lcdRange = LCDRange()

                grid.addWidget(lcdRange, row, column)
                if not previousRange == None:
                    self.connect(lcdRange, QtCore.SIGNAL('valueChanged(int)'),
                                 previousRange, QtCore.SLOT('setValue(int)'))
                previousRange = lcdRange

        layout = QtGui.QVBoxLayout()
        layout.addWidget(quit)
        layout.addLayout(grid)
        self.setLayout(layout)




app = QtGui.QApplication(sys.argv)

widget = MyWidget()
widget.show()


sys.exit(app.exec_())

When i run this i get the following errors:

Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)
Object::connect: No such slot LCDRange::setValue(int)

I've read that PyQt slots are nothing more than methods, which i have defined, so what am i doing wrong?

I am also learning Qt4 with Ruby which is where this code originates from, i translated it from Ruby to Python. In the Ruby version the LCDRange class is defined as this:

class LCDRange < Qt::Widget
  signals 'valueChanged(int)'
  slots 'setValue(int)'

  def initialize(parent = nil)
  ...

So my guess was that i have to somehow declare the existence of the custom slot?

+6  A: 

Try this:

self.connect(lcdRange, QtCore.SIGNAL('valueChanged'), previousRange.setValue)

What's the difference?

The PyQt documentation has a section about SIGNALS/SLOTS in PyQt, they work a little differently.

SIGNAL

SIGNAL('valueChanged') is something called a short-circuit signal. They work only for Python-to-Python methods, but they are faster and easier to implement.

SLOT

If you have a python slot, you can specify it just by tipping the method: previousRange.setValue. This works for all methods accessible by Python.

If your slots should be accessible like C++ Qt slots, as you tried in your code, you have to use a special syntax. You can find information about pyqtSignature decorator on the PyQt website.

Georg
Works perfectly now, thanks! Now if i could only decide which i like better, Python or Ruby...
Jason Miesionczek
For me, Ruby is more fun to program. But, there are far more libraries for Python, it's faster and I didn't trust QtRuby to be as advanced as PyQt. Maybe it's even better. :)
Georg
A: 

NOTE

The "text" within the SIGNAL must match the c++ API documentation.

# This will work - its IDENTICAL to the documentation 
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)')

# this wont
QtCore.SIGNAL('customContextMenuRequested(QPoint&)')

# and this wont
QtCore.SIGNAL('customContextMenuRequested(const QPoint)')

# Spot the bug 
QtCore.SIGNAL('selectionChanged(const QItemSelection,const QItemSelection&)')
                                                    ^ < missing &
PedroMorgan
+1  A: 
Tiho