Konsolenausgabe in Fenster anzeigen

Fragen zu Tkinter.
Antworten
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Hallo an alle,

ich hab nochmal ne Frage. Und zwar möchte ich in meiner GUI ein Feld haben, in welchem die Print-Anweisungen aus einem anderen Programm angezeigt werden. Das Text-Feld soll quasie wie die normale Konsole fungieren. Nur das, dass was normalerweise auf der Konsole angezeigt wird, jetzt in dem GUI-Fenster in dem Text-Widget reingeschrieben werden.

Ich hatte schon irgendwo gelesen, dass der Standard-Output umgelegt/umgeleitet werden muss, nur wie funktioniert das/funktioniert das überhaupt, wenn die print-Anweisungen aus einem anderen Programm/Python-Skript kommen.

Danke schonmal für eure Hilfe

Daniela
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Daniela hat geschrieben:Hallo an alle,

ich hab nochmal ne Frage. Und zwar möchte ich in meiner GUI ein Feld haben, in welchem die Print-Anweisungen aus einem anderen Programm angezeigt werden. Das Text-Feld soll quasie wie die normale Konsole fungieren. Nur das, dass was normalerweise auf der Konsole angezeigt wird, jetzt in dem GUI-Fenster in dem Text-Widget reingeschrieben werden.

Ich hatte schon irgendwo gelesen, dass der Standard-Output umgelegt/umgeleitet werden muss, nur wie funktioniert das/funktioniert das überhaupt, wenn die print-Anweisungen aus einem anderen Programm/Python-Skript kommen.
Wenn das "andere Programm" ein Programm ist, das du zur Laufzeit deines Python-Programms quasi als Subprozess von diesem aus starten willst/kannst, dann geht das mit Hilfe des subprocess-Moduls. Die Konsolenausgabe dieses Programms kannst du dann abfangen und selbst weiter verarbeiten.

Wenn das "andere Programm" ein Programm ist, das schon vor Beginn deines Python-Programms läuft und auf die Konsole weiterhin Ausgaben produziert, dann sehe ich nicht, wie es gehen soll, falls du das "andere Programm" nicht dazu bewegen kannst, seinen Output an dein Python-Programm weiterzureichen.
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

numerix hat geschrieben: Wenn das "andere Programm" ein Programm ist, das du zur Laufzeit deines Python-Programms quasi als Subprozess von diesem aus starten willst/kannst, dann geht das mit Hilfe des subprocess-Moduls. Die Konsolenausgabe dieses Programms kannst du dann abfangen und selbst weiter verarbeiten.
Es ist genau dieser Fall. Also es wird auf ein Button gedrückt und der ruft ein anderes Skript auf, in welchem verschiedene Statusmeldungen gesendet werden. Und diese sollen dann statt in der Konsole in das entsprechende Textfeld angezeigt werden.

Ich werd mir mal das modul von dem du gesprochen hast anschauen.
danke für den Hinweis.

Daniela
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Hallo Daniela,
schau Dir mal an, was gerold zu diesem Thema
geschrieben hat:
http://www.python-forum.de/post-76403.html#76403

Da ich auch noch nie mit subprocess gearbeitet habe,
ist das folgende mit etwas Vorsicht zu geniessen
(bei mir funktionierts jedenfalls).

Datei p1.py (Rechte auf ausführbar):

Code: Alles auswählen

#!/usr/bin/env python

####

import time as ti
import sys

####

def count():

  for i in xrange(1, 22):
    #ti.sleep(0.1)
    #sys.stdout.flush()
    print '-'.join(['%s' % i] * i)
      
####
    
if __name__ == '__main__':

  count()
 
Datei p2.py (im gleichen Verzeichnis):

Code: Alles auswählen

#!/usr/bin/env python

####

import Tkinter as tk
import subprocess as sp
import os

####

class ShowWin(object):

  def __init__(self, root, *args):

    self.args = args
    self.root = root
    self.text = tk.Text(self.root)
    self.text.pack()
    self.button = tk.Button(self.root, text='Call Program',
                            command=lambda : self.show(*self.args))
    self.button.pack()

    
  def show(self, *args):

    proc = sp.Popen(args, stdout=sp.PIPE, cwd = os.curdir)
    for line in iter(proc.stdout.readline, ''):
      self.text.insert(tk.END, line)
      
    
####
    
if __name__ == '__main__':

  root = tk.Tk()
  win = ShowWin(root, 'p1.py')
  root.mainloop()
Dann einfach p2.py aufrufen.

:wink:
yipyip
Zuletzt geändert von yipyip am Dienstag 28. April 2009, 22:20, insgesamt 1-mal geändert.
problembär

In "Python GePackt" ist folgendes merkwürdiges Beispiel:

Code: Alles auswählen

#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

import Tkinter as tk
import sys

class Ausgabefenster:

    def __init__(self):

        self.mw = tk.Tk()
        self.mw.title("Ausgabefenster")
        self.text = tk.Text(self.mw,
                            width = 80,
                            height = 10,
                            font = "Courier 14")
        self.text.pack()

    def write(self, s):
        self.text.insert(tk.END, s)

ausgabe = Ausgabefenster()
sys.stdout = ausgabe

print "Nanu ?"

ausgabe.mw.mainloop()
Gruß
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

War auch erst etwas verblüfft, bis ich dann gesehen hatte,
dass 'Ausgabefenster' ja eine 'write'-Methode hat.

'print' schreibt nach 'sys.stdout', einem File-Objekt, das
eine 'write'-Methode besitzt.
Mit

sys.stdout = ausgabe

wird dieses File-Objekt nun durch ein anderes Objekt ersetzt,
das ebenfalls eine 'write'-Methode besitzt.
Daher wird für die 'print'-Ausgabe nun die Methode von 'Ausgabefenster' benutzt.

:wink:
yipyip
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Sorry dass ich mich so lange nicht gemeldet hab. Ich hatte kein Internet in der letzten Zeit.

Aber ich werde mir auf jedenfall mal die vorgeschlagenen Code-Schnippsel bzw. die Links anschauen.

Danke dafür schonmal.

Daniela
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Ich hab jetzt die Lösung von problembär mal umgesetzt und es funktioniert eigentlich auch so, wie ich es haben will.
Nur werden die Meldungen die normalerweise auf der Konsole angezeigt werden, nicht in der gleichen Zeit in der GUI angezeigt.
Dass heißt, erst wenn das aufgerufene Programm beendet ist, werden alle Meldungen im GUI-Fenster angezeigt.
Normalerweise werden die Meldungen ja in "Echtzeit" sofort auf der Konsole ausgegeben, nur jetzt beim "umlenken" geschieht es erst wenn alles schon vorbei ist.
Meine Vermutung ist ja, dass jetzt noch mit Threads das gearbeitet werden muss, da das aufrufende Programm sehr rechenintensiv ist und man in der Zeit, wo das Programm läuft auf die GUI nicht mehr zugreifen kann.

Ach ja und dann wollte noch wissen, wenn jetzt das Textfeld als Ersatzkonsole funktioniert, wie kann man das machen, das wenn es beschrieben wird, dass dann immer das Ende bzw. die letzten Zeilen angezeigt werden. Jetzt ist es so, dass bei längeren Einträgen man den Anfang sieht, aber wennn der Text jetzt mehr ist, als in das Widget passt, muss man noch selber scrollen und dass ist nicht umbedingt der Sinn und Zweck dieser "Ersatzkonsole".

Daniela
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Mit
text_widget.see(tk.END)
hast Du immer die letzte Zeile im Blick.

Habe noch etwas mit 'after()' und 'update()' herumexperimentiert,
da aber die Gui blockiert wird, solange auf die nächste Zeile aus
der Pipe gewartet wird (auch wenn es nur wenige Millisekunden
sind), halte ich es für sinnvoller, einen zusätzlichen Thread
zu verwenden.
Zum Glück hat man sowas ja in seiner Snippet-Sammlung.

Testausgabefile p1.py:
http://paste.pocoo.org/show/115866/

Anzeigeprogramm (im folgenden threaded.py genannt):
http://paste.pocoo.org/show/115867/

threaded.py ohne Argumente zeigt die Ausgabe von p1.py an.

threaded.py Programm [Argumente für Programm]

zeigt das an, was nach stdout geschrieben wird,
wenn 'Programm' aufgerufen wird.
Vielleicht läufts ja auf Anhieb mit Deinem Rechenprogramm.

:wink:
yipyip
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Cool Dankeschön. Ich schau mal, wie ich das verwenden kann mit dem zusätzlichen Thread

daniela
Antworten