moospit
Anmeldungsdatum: 10. Juni 2007
Beiträge: 171
Wohnort: /home/franken
|
Hallo,
bin im Moment dabei, mir ein kleines Python-Programm mit Tkinter-GUI zu schreiben mit welchem ich via SNMP dauerhaft Messwerte von angeschlossenen Geräten beziehen will. Die Ansteuerung über SNMP funktioniert wunderbar, nur habe ich das Problem, dass ich während der Messung nicht mehr auf die Funktion zugreifen kann, da die Funktion meine GUI einfriert. Der Code sieht wie folgt aus (nur die relevanten Teile): 1
2
3
4
5
6
7
8
9
10
11
12
13 | class SNMP(): #Klasse für SNMP
class MainWindow():
def __init__(self,..):
self.startb = Button(command=self.run)
self.stopb = Button(command=self.stop)
def run(self):
while(1):
# hole Werte vom entsprechenden Gerät
# verarbeite Werte
def stop(self):
# soll self.run anhalten/beenden
|
Das Programm funktioniert wunderbar, nur würde mich interessieren, ob ich die Funktion run auch ohne Threading über die GUI pausieren/beenden kann. mfg moospit
|
Lunar
Anmeldungsdatum: 17. März 2006
Beiträge: 5792
|
moospit schrieb: Das Programm funktioniert wunderbar, nur würde mich interessieren, ob ich die Funktion run auch ohne Threading über die GUI pausieren/beenden kann.
Nein.
|
dauerbaustelle
Anmeldungsdatum: 2. Juli 2007
Beiträge: 1936
|
moospit schrieb: Das Programm funktioniert wunderbar, nur würde mich interessieren, ob ich die Funktion run auch ohne Threading über die GUI pausieren/beenden kann.
Wie meinen?
|
moospit
(Themenstarter)
Anmeldungsdatum: 10. Juni 2007
Beiträge: 171
Wohnort: /home/franken
|
Ich meine damit, dass man, da die Anwendung nicht zeitkritisch ist, in die Schleife folgendes einbaut:
| b = true
while b == true:
#mach etwas
1 sekunde auf eingabe warten
if eingabe:
b = false
else:
#weitermachen
|
Ich will also während der Schleife mittels eines Timers für 1 Sek pro Durchlauf auf eine Eingabe (Return, etc.) warten, und falls diese gemacht wird, so soll die Bedingung für die Schleife geändert werden. mfg moospit
|
dauerbaustelle
Anmeldungsdatum: 2. Juli 2007
Beiträge: 1936
|
D.h. der User hat nur 1 Sekunde Zeit etwas einzugeben? Evtl. solltest du das Prinzip nochmals überdenken...
|
snafu1
Anmeldungsdatum: 5. September 2007
Beiträge: 2133
Wohnort: Gelsenkirchen
|
Warum überhaupt Tastatureingaben bei einer GUI? Threads sind doch perfekt für dein Problem. Du baust zwei Buttons für Stopp und Pause ein, und die beeinflussen den Thread dann entsprechend. Was hast du also gegen diese Lösung? Wenn es dir darum geht, die bisherigen Ergebnisse nach der Pause zu sehen, dann mach das z.B. so: | ergebnisse = []
while True:
ergebnisse.append(hole_ergebnis())
|
hole_ergebnis() holt dabei immer nur ein Ergebnis. Und die while-Schleife wäre dein Thread, den du nach Belieben anhalten und weiterlaufen lassen (oder ganz abbrechen) kannst. Alternativ könnte hole_ergebnis() ja auch yield'en (sollte dann korrekterweise hole_ergebnisse() heißen), statt zu return'en. Das wäre dann sogar schneller als eine Liste.
|
moospit
(Themenstarter)
Anmeldungsdatum: 10. Juni 2007
Beiträge: 171
Wohnort: /home/franken
|
Ich lasse in der Konsole einen Log mitlaufen. Nun habe ich mir gedacht, da die SNMP-Verbindung samt Verarbeitung der Daten keine 2 Sekunden braucht, ein optisches Signal zu setzten, sobald der Benutzer die Eingabe machen kann.
Muss ausserdem nicht anwenderfreundlich sein, da ich es nur selbst benutze und die Funktion nicht sehr oft brauchen werde,. mfg moospit
|
snafu1
Anmeldungsdatum: 5. September 2007
Beiträge: 2133
Wohnort: Gelsenkirchen
|
Dann würde der Warte-auf-Eingaben Thread nach jedem Messergebnis gestartet und nach time.sleep(2) wieder beendet werden. Das Abfangen der Eingaben könnte so aussehen: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #!/usr/bin/env python
import termios
import tty
import sys
def getkey():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
key = sys.stdin.read(1)
if key == '\x1b':
key = key + sys.stdin.read(2)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return key
if __name__ == '__main__':
print "Press a key..."
print repr(getkey())
|
|
moospit
(Themenstarter)
Anmeldungsdatum: 10. Juni 2007
Beiträge: 171
Wohnort: /home/franken
|
Bin jetzt doch auf Threads umgestiegen, scheint einfacher zu sein. Jedoch hängt sich mein Programm auf, wenn ich den Thread beenden will.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | ...
import thread, time
...
CANCEL_FLAG = None
RUNNING_FLAG = None
...
def funktion():
global RUNNING_FLAG, CANCEL_FLAG
if RUNNING_FLAG is None:
RUNNING_FLAG = 1
while CANCEL_FLAG is None:
#Hier wird die Funktion ausgeführt
def start_function():
if RUNNING_FLAG is None:
thread.start_new_thread(funktion, (), {})
start['state'] = 'disabled'
def cancel_funktion():
while RUNNING_FLAG:
CANCEL_FLAG = 1
time.sleep(.1)
start['state'] = 'normal'
...
# Hier die dazugehörigen GUI-Elemente
start = Button(root, text='Start', command=start_funktion)
cancel = Button(root, text='Abbrechen', command=cancel_funktion)
...
root.mainloop()
...
|
|
dauerbaustelle
Anmeldungsdatum: 2. Juli 2007
Beiträge: 1936
|
global ist hier nicht nötig, weil auf Variablen auf Modulebene von überall aus zugegriffen werden kann. global sollte IMMER vermieden werden!
Dass sich das Programm aufhängt liegt daran, dass sich deine cancel -Funktion dauernd wiederholt, weil das RUNNING_FLAG NIE auf False bzw. 0 gesetzt wird. GROSSSCHREIBWEISE sollte nur bei Konstanten verwendet werden (in Python also Variablen deren Wert sich im Programmfluss nie ändert), deine Variablen ändern sich aber.
|
moospit
(Themenstarter)
Anmeldungsdatum: 10. Juni 2007
Beiträge: 171
Wohnort: /home/franken
|
Tausend Dank. Auf das Setzten des Flags hätt ich selber kommen müssen, aber manchmal hat man ein Brett vor dem Kopf 😉 mfg moospit
|
snafu1
Anmeldungsdatum: 5. September 2007
Beiträge: 2133
Wohnort: Gelsenkirchen
|
Ein paar Anmerkungen zum Stil noch: Dass Funktionen Funktionen sind, sieht man auch ohne dass es dahinter steht. 😉 Bei den Flags genau so - und wie schon gesagt wurde: Klein schreiben. Außerdem würde ich statt None/1 besser False/True verwenden. Für solche Sachen sind sie nämlich eigentlich auch gedacht. Und in Zeile 12+18 reicht auch ein if not running, was sogar etwas "menschlicher" klingt. ☺
|