Frage

Ich habe ein Programm, das druckt die Ergebnisse auf Befehlszeile erstellt. (Es ist Server und druckt es Protokoll auf der Kommandozeile.)

Nun möchte ich das gleiche Ergebnis zu GUI sehen.

Wie kann ich umleiten Ergebnisse Kommandozeile GUI?

Bitte, schlägt einen Trick leicht Konsolenanwendung auf einfache GUI-Transformation.

Beachten Sie, dass es sollte unter Linux und Windows.

War es hilfreich?

Lösung

Sie können ein Skript-Wrapper erstellen, die Kommandozeilen-Programm als Unterprozess läuft, dann fügen Sie die Ausgabe so etwas wie ein Text-Widget.

from tkinter import *
import subprocess as sub
p = sub.Popen('./script',stdout=sub.PIPE,stderr=sub.PIPE)
output, errors = p.communicate()

root = Tk()
text = Text(root)
text.pack()
text.insert(END, output)
root.mainloop()

wo Skript ist Ihr Programm. Sie können natürlich die Fehler in einer anderen Farbe gedruckt werden, oder so ähnlich.

Andere Tipps

Um subprocess' Ausgabe in einem GUI angezeigt werden, während es noch läuft , eine tragbare stdlib-einzige Lösung, die 2 sowohl Python arbeitet und 3 hat einen Hintergrund-Thread zu verwenden:

#!/usr/bin/python
"""
- read output from a subprocess in a background thread
- show the output in the GUI
"""
import sys
from itertools import islice
from subprocess import Popen, PIPE
from textwrap import dedent
from threading import Thread

try:
    import Tkinter as tk
    from Queue import Queue, Empty
except ImportError:
    import tkinter as tk # Python 3
    from queue import Queue, Empty # Python 3

def iter_except(function, exception):
    """Works like builtin 2-argument `iter()`, but stops on `exception`."""
    try:
        while True:
            yield function()
    except exception:
        return

class DisplaySubprocessOutputDemo:
    def __init__(self, root):
        self.root = root

        # start dummy subprocess to generate some output
        self.process = Popen([sys.executable, "-u", "-c", dedent("""
            import itertools, time

            for i in itertools.count():
                print("%d.%d" % divmod(i, 10))
                time.sleep(0.1)
            """)], stdout=PIPE)

        # launch thread to read the subprocess output
        #   (put the subprocess output into the queue in a background thread,
        #    get output from the queue in the GUI thread.
        #    Output chain: process.readline -> queue -> label)
        q = Queue(maxsize=1024)  # limit output buffering (may stall subprocess)
        t = Thread(target=self.reader_thread, args=[q])
        t.daemon = True # close pipe if GUI process exits
        t.start()

        # show subprocess' stdout in GUI
        self.label = tk.Label(root, text="  ", font=(None, 200))
        self.label.pack(ipadx=4, padx=4, ipady=4, pady=4, fill='both')
        self.update(q) # start update loop

    def reader_thread(self, q):
        """Read subprocess output and put it into the queue."""
        try:
            with self.process.stdout as pipe:
                for line in iter(pipe.readline, b''):
                    q.put(line)
        finally:
            q.put(None)

    def update(self, q):
        """Update GUI with items from the queue."""
        for line in iter_except(q.get_nowait, Empty): # display all content
            if line is None:
                self.quit()
                return
            else:
                self.label['text'] = line # update GUI
                break # display no more than one line per 40 milliseconds
        self.root.after(40, self.update, q) # schedule next update

    def quit(self):
        self.process.kill() # exit subprocess if GUI is closed (zombie!)
        self.root.destroy()


root = tk.Tk()
app = DisplaySubprocessOutputDemo(root)
root.protocol("WM_DELETE_WINDOW", app.quit)
# center window
root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
root.mainloop()

Das Wesen der Lösung ist:

  • legt den Subprozess Ausgang in die Warteschlange in einem Hintergrund-Thread
  • erhält die Ausgabe aus der Warteschlange in dem GUI-Thread.

das heißt, Aufruf process.readline() im Hintergrund-Thread. -> Warteschlange -> update GUI-Label im Hauptthread. Verwandte kill-process.py (kein Polling - eine weniger tragbare Lösung, die event_generate in einem Hintergrund-Thread verwendet).

Umleiten von stdout zu einem write () -Methode, die Ihre gui aktualisiert ist ein Weg zu gehen, und wahrscheinlich die schnellste - obwohl einen Teilprozess läuft, ist wahrscheinlich eine elegantere Lösung.

Nur stderr umleiten, wenn Sie wirklich sicher sind, es ist und arbeitet, aber!

Beispiel implimentation (gui Datei und Testskript):

test_gui.py:

from Tkinter import *
import sys
sys.path.append("/path/to/script/file/directory/")

class App(Frame):
    def run_script(self):
        sys.stdout = self
        ## sys.stderr = self
        try:
            del(sys.modules["test_script"])
        except:
            ## Yeah, it's a real ugly solution...
            pass
        import test_script
        test_script.HelloWorld()
        sys.stdout = sys.__stdout__
        ## sys.stderr = __stderr__

    def build_widgets(self):
        self.text1 = Text(self)
        self.text1.pack(side=TOP)
        self.button = Button(self)
        self.button["text"] = "Trigger script"
        self.button["command"] = self.run_script
        self.button.pack(side=TOP)

    def write(self, txt):
        self.text1.insert(INSERT, txt)

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.build_widgets()

root = Tk()
app = App(master = root)
app.mainloop()

test_script.py:

print "Hello world!"

def HelloWorld():
    print "HelloWorldFromDef!"

Sorry für mein schlechtes Englisch. Früher habe ich eigentlich eine andere Art und Weise der Eingabeaufforderung Ausgabe in mein neues Automatisierungstool zu drucken. Sie finden alle Schritte aus.

1> Erstellen Sie eine BAT-Datei und umleiten seine Ausgabe in eine Protokolldatei. Eingabeaufforderung Befehl: tasklist /svc

2> Erstellen Sie diese Datei mit Python 3.x lesen `ProcessedFile = open ( 'D: \ LOG \ taskLog.txt', 'r')

3> Das Finale Schritt. ttk.Label(Tab4, text=[ProcessFile.read()]).place(x=0, y=27)

** Daher bitte informiert werden, dass, ich habe nicht Scrollbar in diesen Code enthalten noch.

Posting Screenshot:

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top