Hallo mal wieder!
Angenommen ist habe eine Reihe von Eingabeelementen gleichen Typs (in meinem Falle SpinBoxen). Bei diesen möchte ich ein bestimmtes Signal mit einem Slot verbinden, dass bei einer Änderung auftritt und den aktuellen Wert beinhaltet.
Im einfachsten Falle würde ich eben x-Widgets erstellten und dazu x-Slots, die ich dann mit x-connects verbinden. Das ist natürlich unschön - auch wenn es bei 8 Spinboxes bei mir theoretisch noch machbar wäre.
Also muss das doch auch anders gehen! Das Erzeugen der Widgets ist mittels Schleife ja kein Problem. Aber ich möchte natürlich auch nur einen Slot erstellen, der entsprechend mit den Änderungs-Signalen verbunden ist und dann das Model enstprechend anpasst.
Aber wie kann ich nun das Signal so verändern, dass ich diesem einen neuen Parameter mitgeben kann, der einen Index oder einen anderen Parameter enthält, so daß ich in dem Slot weiß, welches Element verändert wurde? Es gibt ja die QButtonGroup, bei der das letztlich exakt so ist, wie ich mir das denke. Dort wird einfach der Index des gedrückten Buttons mit übergeben. Bei mir wäre es eben "neuer Wert" und "Index" o.ä.
Als dirty Workaround fiele mir noch ein, den / die Datenparameter des Signals des Widgets im Slot einfach zu ignorieren und per Hand alle Werte aus den in Frage kommenden Widgets auszulesen. Bei einer kleinen Anzahl wäre das ja durchaus ok, aber sauberer ist es ja schon, den Wert zu erhalten und eben dazu die Info, welches Element diesen Wert nun hat.
Ich bilde mir ein, dass es mal in der Qt-Doku dazu ein Beispiel gab, aber ich finde es einfach nicht wieder.
Ich hoffe auch hier kann mir jemand nen Denkanstoß oder Tipp geben.
Liste von Widgets, wie zu einem Slot connecten?
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Danke für den Hinweis. Allerdings habe ich da noch ein Problem. Eine SpinBox emitted ja das Signal "valueChanged(int i)". Der Mapper hat aber nur die beiden Slots map() und map(QObject). Wie kann ich denn das verbinden?
Ich habe mir mal ein Minimalbeispiel geschrieben:
http://paste.pocoo.org/show/144362/
Das funzt so halt nicht.
Vielleicht hilft das weiter, mein Problem zu verstehen.
Ich habe mir mal ein Minimalbeispiel geschrieben:
http://paste.pocoo.org/show/144362/
Das funzt so halt nicht.
Vielleicht hilft das weiter, mein Problem zu verstehen.
Das mit den connects ist manchmal schön verfuchst. Dazu kommen dann gleichnamige SIGNALS (oder SLOTS) mit unterschiedlichen Typen in C++.
Um dein Beispiel zum Arbeiten zu bringen, mussten beide geändert werden.
Zusätzlich dazu hab ich nicht auf den QString gemapped, sondern direkt auf das spin, dann hast du im SLOT gleich direkten Zugriff auf das value. Außerdem hab ich dem Objekt seinen objectName gesetzt, damit auch daran erkannt werden kann, welches Objekt das jetzt ist.
So schauts bei mir jetzt aus:
Um dein Beispiel zum Arbeiten zu bringen, mussten beide geändert werden.
Zusätzlich dazu hab ich nicht auf den QString gemapped, sondern direkt auf das spin, dann hast du im SLOT gleich direkten Zugriff auf das value. Außerdem hab ich dem Objekt seinen objectName gesetzt, damit auch daran erkannt werden kann, welches Objekt das jetzt ist.
So schauts bei mir jetzt aus:
Code: Alles auswählen
import sys
from PyQt4 import QtGui, uic, QtCore
EIGS = ["MU", "KL", "IN"]
class Demo(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.signal_map = QtCore.QSignalMapper(self)
form = QtGui.QFormLayout(self)
for tag in EIGS:
spin = QtGui.QSpinBox(self)
spin.setObjectName(tag)
form.addRow(tag, spin)
self.signal_map.setMapping(spin, spin)
self.connect(spin, QtCore.SIGNAL('valueChanged(int)'), self.signal_map, QtCore.SLOT('map()'))
self.connect(self.signal_map, QtCore.SIGNAL('mapped(QWidget*)'), self.slot_show)
def slot_show(self, w):
print w.objectName(), w.value()
def main():
app = QtGui.QApplication(sys.argv)
widget = Demo()
widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Die Lösung, die Python dafür bereit hält, ist "functools.partial()":franzf hat geschrieben:Die Lösung die Qt hier für dich bereit hält, ist der QSignalMapper. Schau dir in der Doku dazu einfach das Beispiel an.
Code: Alles auswählen
class Demo(QWidget):
def __init__(self):
QWidget.__init__(self)
form = QFormLayout(self)
for tag in EIGS:
spin = SpinBox(self)
form.addRow(tag, spin)
spin.valueChanged[int].connect(partial(self.slot_show, spin, tag)))
def slot_show(self, spin, tag, value):
print('Spinbox {0!r} with {1} changed to {2}'.format(spin, tag, value))
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
@franzf: Argh... ich hatte das "map" tatsächlich so übersehen... dabei hat's mein Editor sogar per Syntax Highlughting sichtbar gemacht. An manchen tagen weiß man es einfach nicht ....
@Lunar: Jo, das ist hübsch und kompakt! Vielen Dank dafür
@Lunar: Jo, das ist hübsch und kompakt! Vielen Dank dafür
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Jetzt habe ich doch noch mal eine Verständnisfrage zu folgender Zeile:
was ist "valueChanegd[int]" für ein Ausdruck? mit [] greife ich doch normalerweise auf einen Index oder einen Key in einem Dict zu. Aber int ist doch eine built-in-Funktion? Ich kapiere dieses Konstrukt einfach nicht. Oder ist der Slot von spin in Wirklichkeit ein dict und nutzt als Key die Signatur der int() Funktion?lunar hat geschrieben:Code: Alles auswählen
class Demo(QWidget): spin.valueChanged[int].connect(partial(self.slot_show, spin, tag))
(Ich habe von Qt keine Ahnung, aber) [Nn]ormalerweise, und insbesondere, sollte das ein Dictlike sein, ist das ein Zugriff auf __setitem__ mit dem Typ / der Klasse "int" (ist eine Klasse, keine Funktion) - was auch kein Problem darstellt:
Code: Alles auswählen
>>> a = {}
>>> a[int] = 42
>>> print a
{<type 'int'>: 42}
>>> print list(a.keys())[0]()
0
>>> print list(a.keys())[0]() + 30
30
>>> class A(object):
... pass
...
>>> a[A] = A()
>>> print a
{<type 'int'>: 42, <class '__main__.A'>: <__main__.A object at 0xb7dc342c>}
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ja und?Hyperion hat geschrieben:was ist "valueChanegd[int]" für ein Ausdruck? mit [] greife ich doch normalerweise auf einen Index oder einen Key in einem Dict zu. Aber int ist doch eine built-in-Funktion? Ich kapiere dieses Konstrukt einfach nicht.
Code: Alles auswählen
d = {
str : "foo"
int : 3
unicode : u'bar'
float : 42.0
}
print d[int]
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Code: Alles auswählen
>>> hash(list())
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(dict())
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> hash(set())
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash(int()), hash(float()), hash(str()), hash(unicode()), hash(frozenset())
(0, 0, 0, 0, -32682612)
@Hyperion: Dokumentation lesen!
Dahinter steckt auch keine tiefe Magie. Der Index-Operator [] lässt sich mit __setitem__ und __getitem__ überladen. Bei Wörterbüchern ist der Operator eben so implementiert, dass er einen Wert zu einem Schlüssel liefert. Bei "bound signals" in PyQt4 dagegen ist er so implementiert, dass er das passende Signal für die übergebene Signatur auswählt.
@derdon und Rest: Mit Hashing hat das nun gar nichts zu tun. __setitem__ kann man beliebig implementieren, auch ohne sich überhaupt um den Hash zu kümmern.
Dahinter steckt auch keine tiefe Magie. Der Index-Operator [] lässt sich mit __setitem__ und __getitem__ überladen. Bei Wörterbüchern ist der Operator eben so implementiert, dass er einen Wert zu einem Schlüssel liefert. Bei "bound signals" in PyQt4 dagegen ist er so implementiert, dass er das passende Signal für die übergebene Signatur auswählt.
@derdon und Rest: Mit Hashing hat das nun gar nichts zu tun. __setitem__ kann man beliebig implementieren, auch ohne sich überhaupt um den Hash zu kümmern.
Ui, sehr doll! Python hat ja richtig charmelunar hat geschrieben:Das ist doch viel hübscher. Man kann nicht nur beliebig viele Argumente an den Slot weiterreichen, sondern auch die Argumente des Signals noch nutzen.
Thx!