Pregunta

He creado un programa que imprima resultados en línea de comandos. (Es servidor y se imprime el registro en línea de comandos.)

Ahora, quiero ver el mismo resultado de interfaz gráfica de usuario.

¿Cómo puedo redirigir los resultados de línea de comandos de interfaz gráfica de usuario?

Por favor, sugerir un truco para transformar fácilmente aplicación de consola de interfaz gráfica de usuario sencilla.

Tenga en cuenta que debería funcionar en Linux y Windows.

¿Fue útil?

Solución

Se puede crear un derivador de scripts que se ejecuta el programa de línea de comandos como un proceso secundario, a continuación, añadir la salida a algo así como un widget de texto.

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()

donde la escritura es su programa. Es obvio que puede imprimir los errores en un color diferente, o algo por el estilo.

Otros consejos

Para mostrar subproceso de salida en una interfaz gráfica de usuario mientras aún se está ejecutando , una solución portátil de sólo stdlib que funciona tanto en Python 2 y 3 tiene que utilizar un subproceso de fondo:

#!/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()

La esencia de la solución es:

  • poner la salida subproceso en la cola en un subproceso de fondo
  • obtener la salida de la cola en el hilo GUI.
.

es decir, llamar process.readline() en el hilo de fondo -> cola -> etiqueta de actualización interfaz gráfica de usuario en el hilo principal. kill-process.py (sin interrogación - una solución menos portátil que utiliza event_generate en una hilo de fondo).

Redirección de la salida estándar a un método de escritura () que actualiza su interfaz gráfica de usuario es una manera de ir, y probablemente el más rápido - a pesar de la ejecución de un subproceso es probablemente una solución más elegante.

Sólo redirigir stderr una vez que esté seguro de que es realmente y de trabajo, sin embargo!

Ejemplo implimentation (archivo GUI y escritura de la prueba):

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!"

Lo siento por mi mala Inglés. En realidad, utilizado de una manera diferente para imprimir la salida del comando Prompt en mi nueva herramienta de automatización. Por favor, encontrar los pasos a continuación.

1> Crea un archivo BAT y redirigir su salida a un archivo de registro. Símbolo del sistema de comando: tasklist /svc

2> Hacer leer ese archivo con Python 3.x `ProcessedFile = abierto ( 'D: \ LOG \ taskLog.txt', 'r')

3> El paso final. ttk.Label(Tab4, text=[ProcessFile.read()]).place(x=0, y=27)

** De ahí que se le informa de que, no he incluir barra de desplazamiento en el código todavía.

Publicación de pantalla:

introducir descripción de la imagen aquí

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top