Seite 3 von 3
Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Sonntag 27. Januar 2013, 19:47
von Nobuddy
Hallo Sirius3
Wie soll das aussehen?
Code: Alles auswählen
def sampler(self):
if not self.queue.empty():
data = self.queue.get_nowait()
# Please do the job
self.text.insert('end', data)
self.text.see('end')
self.queue.task_done()
if not worker.is_active():
self.enable_close_button()
self.win.after(50, self.sampler)
Funktioniert nicht.
Grüße Nobuddy
Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Montag 28. Januar 2013, 19:20
von wuf
Hi Nobuddy
Es heisst nicht:
sondern:
Damit es auch wirklich funktioniert musst du die Skripte anpassen. Mein Versuch ist wie folgt:
Startskript:
Code: Alles auswählen
#!/usr/bin/env python
# coding: UTF-8
import threading
from vendors import MyVendors
from gui_terminal import App
app = App()
worker = threading.Thread(target=MyVendors)
worker.start()
app.worker = worker
app.run()
Terminalskript (gui_terminal.py):
Code: Alles auswählen
#!/usr/bin/env python
# coding: UTF-8
import sys
try:
#~~ For Python 2.x
import Queue as qu
import Tkinter as tk
except ImportError:
#~~ For Python 3.x
import queue as qu
import tkinter as tk
class TeeStd(object):
def __init__(self, queue, type):
self.queue = queue
if type == 'stderr':
self.std_obj = sys.stderr
sys.stderr = self
else:
self.std_obj = sys.stdout
sys.stdout = self
def write(self, data):
# Ausgabe auf Tk-Textbox
self.queue.put(data)
APP_WIN_XPOS = 50
APP_WIN_YPOS = 50
class App(object):
def __init__(self, worker=None): #, check):
self.worker = worker
self.win = tk.Tk()
self.win.geometry('+{0}+{1}'.format(APP_WIN_XPOS, APP_WIN_YPOS))
self.win.protocol("WM_DELETE_WINDOW", self.close)
self.queue = qu.Queue()
self.queue_modules = qu.Queue()
self.text = tk.Text(self.win, width=80, height=20, highlightthickness=0,
bd=0, bg='white', relief='sunken', padx=5, pady=5)
self.text.pack()
self.close_button = tk.Button(self.win, text='Fenster schließen',
command=self.close)
self.close_button.pack()
self.close_button['state']="disabled"
self.win.title("My Stdout/Stderr Terminal")
# Umleitung der Standard-Ausgabe auf meine Textbox
TeeStd(self.queue, 'stderr')
TeeStd(self.queue, 'stdout')
print('Hello')
self.sampler()
def sampler(self):
if not self.queue.empty():
data = self.queue.get()
self.text.insert('end', data)
#if not self.queue_modules.empty():
#data = self.queue_modules.get()
#if data == 'end':
#self.enable_close_button()
if self.worker:
if not self.worker.is_alive():
self.enable_close_button()
self.win.after(50, self.sampler)
def run(self):
#self.sampler()
self.win.mainloop()
def enable_close_button(self):
self.close_button['state']="normal"
def close(self):
"""Process before shutdown"""
self.win.destroy()
Modulskript (vendors.py):
Code: Alles auswählen
#!/usr/bin/env python
# coding: UTF-8
import time
class MyVendors(object):
#queue = None
def __init__(self):
self.vendors = list()
self.vendors.append("Vendor-1")
self.vendors.append("Vendor-2")
self.vendors.append("Vendor-3")
self.update_vendors()
def update_vendors(self, new_vendor=None):
if new_vendor != None:
self.vendors.append('Vendor-{0}: {1}'.format(len(self.vendors)+1,
new_vendor))
for vendor in self.vendors:
print(vendor)
print()
# Nur für Simulation (Verlängert die Lebensdauer des Threads um 5 Sek.
time.sleep(5)
#if MyVendors.queue is not None:
#MyVendors.queue.put('end')
Gruß wuf

Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Montag 28. Januar 2013, 19:55
von Nobuddy
Hallo wuf
Danke für Deine Unterstützung, funktioniert jetzt prima!
Bin beim Googeln zwar auf is_alive() gestoßen, bei der Umsetzung kam ich aber nicht weiter.
Wenn ich jetzt Deinen Code sehe, ist die Vorgehensweise eigentlich logisch ... muß da wohl mehr an meiner Logik arbeiten...
Grüße und einen schönen Abend
Nobuddy
Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Dienstag 29. Januar 2013, 17:16
von Nobuddy
Hallo zusammen
Poste hier den Code, mit dem ich arbeite, damit man nicht erst den ganzen Thread bis zum Ergebnis lesen muß.
terminal.py
Code: Alles auswählen
#!/usr/bin/env python
# coding: UTF-8
import sys
import tkinter.messagebox
try:
#~~ For Python 2.x
import Queue as qu
import Tkinter as tk
except ImportError:
#~~ For Python 3.x
import queue as qu
import tkinter as tk
class TeeStd(object):
def __init__(self, queue, type):
self.queue = queue
if type == 'stderr':
self.std_obj = sys.stderr
sys.stderr = self
else:
self.std_obj = sys.stdout
sys.stdout = self
def write(self, data):
# Ausgabe auf Tk-Textbox
self.queue.put(data)
APP_WIN_XPOS = 170
APP_WIN_YPOS = 70
class App(object):
def __init__(self, worker=None):
self.win = tk.Tk()
self.win.geometry('+{0}+{1}'.format(APP_WIN_XPOS, APP_WIN_YPOS))
self.win.protocol("WM_DELETE_WINDOW", self.close)
self.worker = worker
self.queue = qu.Queue()
self.queue_modules = qu.Queue()
self.text = tk.Text(self.win, width=120, height=20, highlightthickness=0,
bd=0, bg='white', relief='sunken', padx=5, pady=5)
self.text.pack()
self.close_button = tk.Button(self.win, text='Fenster schließen',
state='disabled', command=self.close)
self.close_button.pack()
self.win.title("My Stdout/Stderr Terminal")
# Umleitung der Standard-Ausgabe auf meine Textbox
TeeStd(self.queue, 'stderr')
TeeStd(self.queue, 'stdout')
self.sampler()
def sampler(self):
if not self.queue.empty():
data = self.queue.get_nowait()
# Please do the job
self.text.insert('end', data)
self.text.see('end')
self.queue.task_done()
if self.worker:
if not self.worker.is_alive():
self.enable_close_button()
self.win.after(50, self.sampler)
def run(self):
self.win.mainloop()
def enable_close_button(self):
self.close_button['state']="normal"
def close(self):
"""Process before shutdown"""
text = 'Möchten Sie das Terminal schließen?'
if tkinter.messagebox.askokcancel('Info', text) == True:
self.win.quit()
Auszug aus meinem Modul, in dem ich terminal.py benutze.
Code: Alles auswählen
import threading
from gui_terminal import App
from update_vendor import suppliers_data
def terminal(modul):
app = App() # redirect stdout auf Terminal-Fenster
worker = threading.Thread(target=modul)
worker.start() # macht die Arbeit in Hintergrund-Thread
app.worker = worker
app.run() # aktiviert das Terminal-Fenster
terminal(suppliers_data)
Nochmals Vielen Dank an Alle!
Grüße Nobuddy
Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Dienstag 29. Januar 2013, 17:25
von EyDu
Da sampler noch immer eine potenzielle Race Codition hat:
Code: Alles auswählen
def sampler(self):
try:
data = self.queue.get_nowait()
except queue.Empty:
pass
else:
self.text.insert("end", data)
self.text.see("end")
if self.worker:
...
Und dann ist mir beim Durchscrollen noch ein unsinniges ``== True`` aufgefallen

Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Dienstag 29. Januar 2013, 18:31
von Nobuddy
Hallo EyDu
Danke für Deine Unterstützung!
Dein Code funktioniert bei mir so nicht.
Aber so würde er funktionieren:
Code: Alles auswählen
def sampler(self):
if not self.queue.empty():
try:
data = self.queue.get_nowait()
except queue.Empty:
pass
else:
self.text.insert("end", data)
self.text.see("end")
if self.worker:
if not self.worker.is_alive():
self.enable_close_button()
self.win.after(50, self.sampler)
Wäre das so in Ordnung?
'self.queue.task_done()' wird das hier nicht mehr benötigt?
Das 'True' habe ich eliminiert.
Was sich verändert hat, ist daß ich 'destroy()' jetzt statt 'quit() verwenden muß, damit das Fenster sich wieder schließt.
Dabei erhalte ich immer folgende Meldung:
invalid command name "28829240callit"
while executing
"28829240callit"
("after" script)
Was kann man dagegen tun?
Grüße Nobuddy
Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Dienstag 29. Januar 2013, 19:20
von EyDu
Was heißt denn "funktioniert nicht"? Was passiert? Gibt es einen Fehler?
Wie weiter oben schon geschrieben: du darfst kein self.queue.empty()-Aufruf machen und dich dann darauf verlassen, dass das Ergebnis noch beim get(_nowait)-Aufruf gilt.
Re: Konsolenausgabe in tkinter ausgeben
Verfasst: Dienstag 29. Januar 2013, 19:37
von Nobuddy
Habe Dein Codeschnipsel 1:1 übernommen.
Das Terminal öffnet sich zwar, aber es kommt keine Ausgabe.
Fehlermeldung, gibt es keine.