Nach 5min Inaktiv Bild anzeigen

Fragen zu Tkinter.
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Hallo zusammen,
Ich würde gerne, wenn 5 Minuten nichts geklickt wird auf dem Touchscreen, auf diesem ein Bild anzeigen lassen.
Ich kann dies nicht über den Screensaver machen da ich diesen nach weitern 5 Minuten aktivieren möchte :)

Kann mir jemand helfen?
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Spricht etwas gegen eine eigene Zeitzählschleife?
Du definierst eine Variable z.B. last_action_time, die jeweils bei Interaktion die aktuelle Zeit time.time speichert.
Außerdem eine Methode last_action_time_checker, die die Differenz zwischen time.time und last_action_time ermittelt, sofern letztere nicht gleich 0 ist.
Ist die Differenz größer als ein Grenzwert, 300s bei 5 Minuten, führ die Aktion aus und setz last_action_time auf 0. Am Ende registriert sich die Methode selbst für erneute Ausführung mit self.after(...) nach n Millisekunden, je nach Prüfintervall.

Ich merke gerade, ein paar Zeilen Code wären kürzer gewesen. :lol:
Diese Nachricht zersört sich in 5 Sekunden selbst ...
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Hallo, ich weis genau was du meinst.
Jedoch habe ich Probleme dies Umzusetzen.

Meinst du das ich bei jedem Button klick
last_action_time = 0 setzten muss?

Wie kann ich wie löse ich das mit dem Timer :) ...

Danke für dein Verständnis und deine Geduld :)
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi schnibli,
schnibli hat geschrieben:Meinst du das ich bei jedem Button klick
last_action_time = 0 setzten muss?

Wie kann ich wie löse ich das mit dem Timer :)
ich habe hier leider kein python installiert, darum kann ich den Code nicht testen. Aber ich meine das in etwa so (nur für das Problem wichtiger Code):

Code: Alles auswählen

import Tkinter as tk
import time

class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.last_action_time = 0
        self.last_action_time_poll_interval = 1000  # 1000 ms min. Zeit zwischen zwei Aufrufen
        self.last_action_delay = 300                      # 300 s, bevor die Methode self.handle_action aufgerufen wird
        self._last_action_time_checker()

    def _last_action_time_checker(self):
        if self.last_action_time:
            if (time.time - self.last_action_time) > self.last_action_delay:
                self.last_action_time = 0                # Sicherstellen, dass die Aktion nur einmal pro Ablauf ausgeführt wird
                self.handle_action()
        self.after(self.last_action_time_poll_interval, self._last_action_time_checker)

    def handle_action(self):
        "Handle action after n seconds"

    def any_callback(self, event=None):
        self.last_action_time = time.time           # setzt den Counter auf die aktuelle Zeit hoch -> Differenz = 0
Wie gesagt, ist gerade ungetestet!
Ich habe gleich noch ein paar Steuervariablen eingebaut, so dass Du jederzeit die Abfragehäufigkeit und Dauer der Verzögerung anpassen kannst (Achtun, erstes in ms, zweites in s).

Siehe auch hier zur after-Methode: http://effbot.org/tkinterbook/widget.htm

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Vielen Dank für deine Antwort

Ich habe beim handel:
Print("ich bin fertig") hineingeschrieben(zum testen)

Wenn ich das Programm starte erscheint leider nie eine meldung
BlackJack

@schnibli: So auf den ersten Blick fehlt bei den `time.time()` jeweils die Klammern zum Aufrufen der Funktion.
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Dies scheint leider nicht das Problem zu sein:

Code: Alles auswählen

self.last_action_time = time.time()           # setzt den Counter auf die aktuelle Zeit hoch -> Differenz = 0
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

@schnibli,
bitte auch in Zeile 14 ändern. Ich kann den Post leider nicht bearbeiten.

BlackJack hat natürlich recht, ich habe nicht aufgepasst und das mit web2py verwechselt, wo man als Referenz für die aktuelle Zeit die Ankunftzeit im Requestobjekt verwenden kann.
time.time ist eine Funktion.
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich denke mal sollte besser per event handler schauen wann sich zuletzt die Maus bewegt und wann zulest eine taste gedrückt wurde...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Jens,
jens hat geschrieben:Ich denke mal sollte besser per event handler schauen wann sich zuletzt die Maus bewegt und wann zulest eine taste gedrückt wurde...
welchen event Handler meinst Du? Wenn ich schnibli richtig verstanden habe, soll das Bild nach 5 Minuten angezeigt werden, wenn gerade nichts passiert ist (keine Bewegung und kein Tastendruck). Wie würdest Du das ohne Polling machen?
Man könnte auch einen after-Handler auf 5 Minuten stellen und dann prüfen, ob tatsächlich seit 5 Minuten keine Benutzerinteraktion stattfand. Dann würde sich aber eine Handler-Schlange aufbauen.

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab bei Test Skript gemacht: http://www.python-forum.de/viewtopic.php?f=11&t=35134

Demnach würde ich "Motion", "KeyPress" und "Configure" (Fenster verschieben) benutzten. Das sollte genug an Aktivität zeigen.
Ein event-Handler, der dann nur self.last_action_time = time.time() setzt.

Dann mit .after() regelmäßig prüfen, ob 5 Min schon vorbei sind.

Aber mal ehrlich, wozu das ganze? Dafür gibt es ja den "Bildschirmschoner" vom OS...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

jens hat geschrieben:Demnach würde ich "Motion", "KeyPress" und "Configure" (Fenster verschieben) benutzten. Das sollte genug an Aktivität zeigen.
Ein event-Handler, der dann nur self.last_action_time = time.time() setzt.

Dann mit .after() regelmäßig prüfen, ob 5 Min schon vorbei sind.
Ok, und in wie weit unterscheidet sich das von meinem Vorschlag? :-)
In Deinem verlinkten Beitrag verknüpfst Du alle Events mit derselben Methode "_update_status". Aber ich denke, es geht nicht NUR um das Zurücksetzen des Counters, sondern es sollen je nach Event auch unterschiedliche Aktionen ausgeführt werden. In meinem Vorschlag wird für jede Aktion eine callback-Funktion erstellt, die zusätzlich zum Handler-Code die eine Zeile zum aktualisieren der Zeit enthalten soll.

VG,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

@jens: In diesem Fall soll dem Benutzer vor dem Bildschirmschoner anscheinend was angezeigt werden. Manchmal hat man ja auch Software die wenn nichts passiert nach einer gewissen Zeit in einen Demomodus wechselt, der dem Benutzer verschiedene Möglichkeiten aufzeigt.
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

BlackJack hat geschrieben:Manchmal hat man ja auch Software die wenn nichts passiert nach einer gewissen Zeit in einen Demomodus wechselt, der dem Benutzer verschiedene Möglichkeiten aufzeigt.
... oder ein Bild seiner Freundin. :mrgreen:

Zu meinem Code: vielleicht liegt ein Missverständnis vor. Die Funktion "any_callback" soll so nicht wörtlich heißen und ein Callback für alle Userevents sein. Vielmehr sollte 'any' eine Art Platzhalter für alle möglichen Benutzerevents darstellen, also "buttonpress_callback", "keyup_callback", "motion_callback" usw., für die jeweils eine Methode geschrieben wird, welche die eine Zeitsetzzeile enthalten soll. Das hätte ich dazu schreiben sollen.
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also ich glaube es sollte alle Informationen ausgetauscht worden sein, um das zu realisieren. Halt die Teile zusammen Puzzeln :D

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Vielen Dank, ich wollte mal zum Testen das erste Beispiel zum laufen bringen:

Code: Alles auswählen

import tkinter as tk
import time
 
class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.last_action_time = 0
        self.last_action_time_poll_interval = 1000  # 1000 ms min. Zeit zwischen zwei Aufrufen
        self.last_action_delay = 10                      # 300 s, bevor die Methode self.handle_action aufgerufen wird
        self._last_action_time_checker()
 
    def _last_action_time_checker(self):
        if self.last_action_time:
            if (time.time() - self.last_action_time) > self.last_action_delay:
                self.last_action_time = 0                # Sicherstellen, dass die Aktion nur einmal pro Ablauf ausgeführt wird
                self.handle_action()
        self.after(self.last_action_time_poll_interval, self._last_action_time_checker)
 
    def handle_action(self):
        print("hallo ich bin fertig")         
    def any_callback(self, event=None):
        self.last_action_time = time.time()           # setzt den Counter auf die aktuelle Zeit hoch -> Differenz = 0
Dies Teste ich auf einem Windows Rechner mit Python3.4.1 und es kommt nie die Meldung "ich bin fertig" :s
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Pack mehr print rein und schau dir so Werte an bzw. zeig dir an, welche Methoden aufgerufen bzw. nicht aufgerufen werden. :wink:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Das Programm wird gleich geschlossen, es wird nicht offen gehalten :)....

Irgendwas fehlt aber steh gerade auf dem schlauch ^^

Code: Alles auswählen

try:
    import tkinter as tk
except:
    import Tkinter as tk
import time
        
class MainFrame():
    

    def __init__(self):
        tk.Tk.__init__(self)
        self.last_action_time = 0
        self.last_action_time_poll_interval = 1000  # 1000 ms min. Zeit zwischen zwei Aufrufen
        self.last_action_delay = 10                      # 300 s, bevor die Methode self.handle_action aufgerufen wird
        self._last_action_time_checker()
 
    def _last_action_time_checker(self):
        if self.last_action_time:
            if (time.time() - self.last_action_time) > self.last_action_delay:
                self.last_action_time = 0                # Sicherstellen, dass die Aktion nur einmal pro Ablauf ausgeführt wird
                self.handle_action()
        self.after(self.last_action_time_poll_interval, self._last_action_time_checker)
 
    def handle_action(self):
        print("hallo ich bin fertig")        
    def any_callback(self, event=None):
        self.last_action_time = time.time()           # setzt den Counter auf die aktuelle Zeit hoch -> Differenz = 0


print ("Programm beendet")
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Schnibli,

wie sieht denn dein ganzes Programm aus, d.h. wo wird das tk.Tk Hauptfenster instanziert und die Eventschleife initialisiert?
Und wo ist die tk.Tk Basisklasse aus den Klammern hinter "class MainFrame" geblieben?

Wenn man unter Windows ein python-Skript per Doppelklick startet, öffnet sich im Hintergrund ein Kommandofenster, das verschwindet, wenn der Programmablauf am Ende ankommt. Das kann passieren, wenn die Tkinter Eventschleife beendet wird, aber auch wenn ein Fehler auftritt. Du musst dafür sorgen, dass das Fenster erhalten bleibt, um die ausgegebene Fehlermeldung zu lesen. Dazu fängst Du entweder global eventuelle Fehler ab und verzögerst das Ende z.B. mit "raw_input()".
Oder einfacher, Du öffnest erst eine Windows Eingabeaufforderung (startmenü -> "cmd") und führst dort das Skript aus. Die schließt sich nicht, auch wenn das Skript mit einem Fehler abbricht.

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
schnibli
User
Beiträge: 27
Registriert: Mittwoch 19. November 2014, 18:52

Hallo, ich kriege folgenden fehler bei:

Code: Alles auswählen

        self.after(self.last_action_time_poll_interval, self._last_action_time_checker)

Code: Alles auswählen

AttributeErrot: 'MainFrame' object has no attribute 'after'
Antworten