Button-Klicks zählen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Joa
User
Beiträge: 14
Registriert: Samstag 21. Mai 2011, 12:49

Hallo,
ich habe eine Frage:
Wie kann ich zählen wie oft ein Button gedrückt wurde?

Insgesamt soll beim ersten klicken meines Buttons eine Animation gestartet werden und beim zweiten klicken diese Animation wieder beendet werden.Und wenn man dann nochmal klickt, dann soll die Animation wieder starten usw.

Vielen Dank schonmal.
LG Joa
BlackJack

@Joa: Wo genau liegt denn das Problem? Objektorientierte Programmierung kannst Du schon? Falls nein, solltest Du Dich damit vielleicht erst einmal unabhängig von GUI-Programmierung auseinander setzen. Dann kannst Du die Klicks einfach in einem Attribut mit zählen.

Für GUI-Fragen gibt es übrigens auch Unterforen. Das beantwortet dann in der Regel auch die Frage welches GUI-Toolkit Du verwendest.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Joa:
Wobei ich das Wechseln zwischen On/Off nicht über einen Zähler lösen würde. Ich würde eine Weiche einbauen, die die Animation startet, wenn diese noch nicht gestartet ist oder eben beendet, wenn sie bereits läuft.

Code: Alles auswählen

startet = False

def switch():
    if started:
        stop_ani()
    else:
        start_ani()

def start_ani():
    started = True
    ...

def stop_ani():
    started = False
    ...
Und das 'Buttonwurdegeklickt'-Event bindest Du an 'switch()'.
Natürlich kannst Du Dir 'switch()' auch sparen und das 'started'-Flag direkt in der Animationsroutine abfragen. Hängt halt davon ab, wie Dein Programm strukturiert ist. Mein Beispiel sollte nur grundsätzlich zeigen, wie man sowas lösen kann.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
pillmuncher
User
Beiträge: 1532
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Oder als kleine State Machine mit zwei Zuständen:

Code: Alles auswählen

class Switch(object):
    def __init__(self, when_on, when_off):
        self._state = 0
        self._transition = ((1, when_on), (0, when_off))
    def __call__(self):
        self._state, action = self._transition[self._state]
        action()

def start_ani():
    print 'an'

def stop_ani():
    print 'aus'

switch = Switch(when_on=start_ani, when_off=stop_ani)
switch()
switch()
switch()
switch()
switch()
In specifications, Murphy's Law supersedes Ohm's.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Cool, das gefällt mir....!! Kann ich gerade in meiner 'PatternFactory' gut gebrauchen um in ein searchpattern Suchwerte rein- oder rauszunehmen, je nachdem eben...
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Joa
User
Beiträge: 14
Registriert: Samstag 21. Mai 2011, 12:49

Vielen Dank, hat super funktioniert :-)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Joa hat geschrieben:Vielen Dank, hat super funktioniert :-)
Du solltest dazu sagen, dass du den Code von pillmuncher meinst, denn der von mutetella funktioniert eben ja gerade nicht (auch dann nicht, wenn man startet in started umbenennt).
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Stimmt... :oops:
Mein Beispiel ist echt für den Müll, selbst wenn man sich verrenkt und 'started' durchreicht...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Joa
User
Beiträge: 14
Registriert: Samstag 21. Mai 2011, 12:49

Hey,
ich habe aber den Code von mutetella genommen und angepasst und es funktioniert bei mir einwandfrei.
BlackJack

@Joa: Falls ”angepasst” bedeutet, dass Du ``global`` verwendet hast, dann solltest Du eine andere Lösung suchen/nehmen. Kommunikation über globale Variablen ist unsauber.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Joa:
Dass mein Beispiel bei Dir funktioniert muss an Deiner Anpassung liegen :wink: !

Auf numerix' Beitrag hin konnte ich natürlich nicht mehr ruhig sitzen und musste mein Beispiel nochmal durchkauen.
Auch wenn es vorerst so aussieht, als würde es funktionieren, tauchen ganz ganz fiese Gemeinheiten auf:

- Nach dem ersten Aufruf von 'switch()' funktioniert alles, nachdem 'started' auf False zeigt wird 'start_ani()' aufgerufen.
- Innerhalb von 'start_ani()' wird 'started' auf True gesetzt, ein erneuter Aufruf von 'switch()' sollte demnach 'stop_ani()' starten. Passiert aber nicht!
- Ich ziehe also meine Wunderwaffe 'print' aus dem Ärmel :wink: und füge gleich als erste Zeile ein 'print started' sowohl in 'switch()' als auch in 'start_ani()' ein.

Code: Alles auswählen

started = False

def switch():
    print started
    if started:
        stop_ani()
    else:
        start_ani()

def start_ani():
    print started
    started = True
    print 'gestartet'

def stop_ani():
    started = False
    print 'gestoppt'
- Genau jetzt beginnt mein Leidensweg: Ich rufe 'switch()' auf und erhalte

Code: Alles auswählen

In [62]: switch()
False
-------------------------------------------------------
     10 def start_ani():
---> 11     print started
     12     started = True
     13     print 'gestartet'

UnboundLocalError: local variable 'started' referenced before assignment
Wie kann das sein :? ? Weshalb funktioniert 'print started' in 'switch()', wirft aber in 'start_ani()' einen 'UnboundLocalError'?

'switch()' sucht zuerst im lokalen Namensraum nach 'started' und findet dort den Namen nicht. Deshalb schaut es im globalen Namensraum (auf Modulebene) nach, findet dort den (globalen) Namen 'started', gibt 'False' aus und verzweigt zu 'start_ani()'.
Warum meckert 'start_ani()', dass es den lokalen Namen 'started' nicht findet? 'switch()' hat doch nach dem lokalen auch im globalen Namensraum gesucht?
Es muss wohl daran liegen, dass der Interpreter durch die Anweisung 'started = True' innerhalb von 'start_ani()' einen lokalen Namen 'started' anlegt. Wenn dann während der Ausführung von 'start_ani()' die print-Anweisung 'started' ausgeben möchte, wird wohl der (lokale) Name gefunden, allerdings ist dieser Name noch 'zeigerlos', da ein Verweis erst eine Zeile danach stattfindet.

Fazit: Das Problem an meinem Beispiel ist also, dass 'switch()' auf den globalen Namen 'started' (False) zugreift, 'start_ani()' und 'stop_ani()' aber jeweils ihren eigenen lokalen Namen 'started' setzen und auch gleich danach wieder verlieren, da Funktionen nach ihrem Ende ihre lokalen Namen nicht behalten.
Letztlich verwendet mein Beispiel also 3 Namen 'started', die miteinander in keiner Verbindung stehen, obwohl sie den selben Namen tragen.

Sauber wäre also folgendes:

Code: Alles auswählen

def switch(started):
    if started:
        started = stop_ani()
    else:
        started = start_ani()
    return started

def start_ani():
    print 'gestartet'
    return True

def stop_ani():
    print 'gestoppt'
    return False

In [67]: started = False

In [68]: started = switch(started)
gestartet

In [69]: started = switch(started)
gestoppt

In [70]: started = switch(started)
gestartet


mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6908
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mutella: Deine Lösung halte ich nicht gerade für "sauber". Was hast du gegen die bereits vorgeschlagene Verwendung einer Klasse auszusetzen?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

snafu hat geschrieben:Was hast du gegen die bereits vorgeschlagene Verwendung einer Klasse auszusetzen?
Überhaupt nichts. Hatte ich doch bereits gesagt, dass ich pillmuncher's Lösung sehr viel besser finde!

Nachdem aber Joa schreibt, dass er meine Variante verwendet (wenn auch 'angepasst') wollte ich mein nicht funktionierendes Beispiel noch in einer 'sauberen', will heißen funktionierenden 'globalfreien' Version einstellen.

Mein ganzes Geschreibe drumherum sollte nicht für meine Variante 'werben' sondern nur aufzeigen, in welche Fallen man (ich!) mit globalen Variablen immer wieder tappen kann.

Ursprünglich war mein Beispiel auch nicht zur Weiterverwendung gedacht. Ich wollte damit nur zeigen, dass sich die Verwendung eines start-/stop-flag gegenüber einem Zähler IMHO besser eignet.

mutetella


EDIT: Letztlich würde mich jetzt a bisl interessieren, wie Joa's Lösung wohl aussieht... :wink:
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten