Pergunta

Eu criei um programa que imprime resultados na linha de comando. (É servidor e imprime log na linha de comando.)

Agora, eu quero ver o mesmo resultado para GUI.

Como posso redirecionar resultados de linha de comando para GUI?

Por favor, sugerem um truque para facilmente transformar aplicativo de console para simples GUI.

Note que ele deve funcionar em Linux e Windows.

Foi útil?

Solução

Você pode criar um wrapper script que executa o seu programa de linha de comando como um processo sub, em seguida, adicione a saída para algo como um 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()

onde script é o seu programa. Você pode, obviamente, imprimir os erros em uma cor diferente, ou algo parecido.

Outras dicas

Para subprocess display saída em uma GUI enquanto ele ainda está em execução , uma solução apenas de stdlib portátil que funciona tanto em Python 2 e 3 tem de usar uma discussão de fundo:

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

A essência da solução é:

  • colocar a saída subprocess na fila em uma discussão de fundo
  • obter a saída da fila no segmento de GUI.

ou seja, process.readline() chamada na discussão de fundo -. Rótulo GUI> atualização no segmento principal -> fila. Relacionado kill-process.py (sem votação - uma solução menos portátil que usa event_generate em uma discussão de fundo).

Redirecionando stdout a um método write () que atualiza seu gui é um caminho a percorrer, e provavelmente o mais rápido - embora a execução de um subprocesso é provavelmente uma solução mais elegante.

Apenas stderr redirecionamento uma vez que você está realmente confiante de que está instalado e funcionando, embora!

Exemplo implimentation (arquivo de gui e script de teste):

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

Desculpe pelo meu mau Inglês. Eu na verdade, usou uma forma diferente para imprimir Command Prompt de saída para a minha nova ferramenta de automação. Por favor, encontrar os passos abaixo.

1> Criar um arquivo de Bat & redirecionar sua saída para um arquivo de log. Command Prompt de comando: tasklist /svc

2> Faça ler esse arquivo com Python 3.x. `= ProcessedFile aberto ( 'D: \ LOG \ taskLog.txt', 'r')

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

** Assim Informamos que, eu não incluem a barra de rolagem para este código ainda.

Publicação de Captura de tela:

enter descrição da imagem aqui

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top