简体   繁体   English

GUI中python程序的实时输出

[英]realtime output from program in python in GUI

i am writing a graphical shell for a command-line program in python using GTK.我正在使用 GTK 在 python 中为命令行程序编写图形 shell。 The main program has output like this:主程序有这样的输出:

Starting Tractor:

Dec 04 22:10:34.000 [notice] Bootstrapped 0%: Starting
Dec 04 22:10:34.000 [notice] Bootstrapped 80%: Connecting to the Tor network
Dec 04 22:10:35.000 [notice] Bootstrapped 85%: Finishing handshake with first hop
Dec 04 22:10:36.000 [notice] Bootstrapped 90%: Establishing a Tor circuit
Dec 04 22:10:37.000 [notice] Bootstrapped 100%: Done
Tractor is conneted.

I have a start button which starts the program via subprocess.我有一个通过子进程启动程序的开始按钮。 since I want the main window to be operative during the start process, I used thrading for that.因为我希望主窗口在启动过程中可以运行,所以我使用了遍历。 Here is my code:这是我的代码:

def on_start_clicked(self, button):
    spinner = Gtk.Spinner()
    self.props.icon_widget = spinner
    spinner.start()
    self.show_all()
    header_bar = self.get_parent()
    if self.is_running():
        def task_thread():
            task = Popen(command + "stop", stdout=PIPE, shell=True)
            task.wait()
            spinner.stop()
            header_bar.show_progress_button(False)
            self.update_label()
    else:
        def task_thread():
            header_bar.show_progress_button(True)
            task = Popen(command + "start", stdout=PIPE, shell=True)
            while True:
                output = task.stdout.readline().decode("utf-8")
                if output == '' and task.poll() is not None:
                    break
                if output and '%' in output:
                    print(output.split()[5][:-2])
            task.wait()
            spinner.stop()
            self.update_label()

    thread = Thread(target=task_thread)
    thread.daemon = True
    thread.start()

The problem is that the log output is not realtime, but it waits until the whole process to be complete and then prints the whole output altogether!问题是日志输出不是实时的,而是等到整个过程完成,然后一共打印整个输出!

I want the actual percentage at the time, in order to pass it to a progress bar, showing how much of the task is done.我想要当时的实际百分比,以便将其传递给进度条,显示完成了多少任务。 How can I accomplish that?我怎样才能做到这一点?

EDIT编辑

I changed the code as following thanks to theGtknerd , but the feed function still works after the process is done and just prints the first line of the whole output.由于theGtknerd ,我将代码更改为如下所示,但是在该过程完成后提要功能仍然有效,并且只打印整个输出的第一行。 I think here is a malfunction in when IO_IN is triggered.我认为这是触发 IO_IN 时的故障。

def thread_finished (self, stdout, condition):
    GLib.source_remove(self.io_id)
    stdout.close()
    self.spinner.stop()
    self.update_label()
    print("heeey")
    return False

def feed (self, stdout, condition):
    line = stdout.readline()
    line = line.decode("utf-8")
    print(line)
    return True

def on_start_clicked(self, button):
    self.spinner = Gtk.Spinner()
    self.props.icon_widget = self.spinner
    self.spinner.start()
    self.show_all()
    header_bar = self.get_parent()
    if self.is_running():
        header_bar.show_progress_button(False)
        task = Popen(command + "stop", stdout=PIPE, shell=True)
    else:
        header_bar.show_progress_button(True)
        task = Popen(command + "start", stdout=PIPE, shell=True)
    self.io_id = GLib.io_add_watch(task.stdout, GLib.IO_IN, self.feed)
    GLib.io_add_watch(task.stdout, GLib.IO_HUP, self.thread_finished)

Here is a small example for you to learn from.这里有一个小例子供您学习。 So in my Python file I have:所以在我的 Python 文件中,我有:

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, GObject
from subprocess import Popen, PIPE, STDOUT
import os, sys


class GUI:
    def __init__(self):

        window = Gtk.Window()
        self.label = Gtk.Label()
        window.add(self.label)
        window.show_all()
        window.connect("destroy", self.on_window_destroy)

        p = Popen(['./long_run.sh'], stdout = PIPE,stderr = STDOUT,stdin = PIPE)
        self.io_id = GObject.io_add_watch(p.stdout, GObject.IO_IN, self.feed)
        GObject.io_add_watch(p.stdout, GObject.IO_HUP, self.thread_finished)

    def feed (self, stdout, condition):
        line = stdout.readline()
        line = line.decode(encoding="utf-8", errors="strict")
        self.label.set_label(line)
        return True

    def thread_finished (self, stdout, condition):
        GObject.source_remove(self.io_id)
        stdout.close()
        self.label.set_label("Hurray, all done!")

    def on_window_destroy(self, window):
        Gtk.main_quit()
        print ("shutdown")

def main():
    app = GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

And in the file long_run.sh I have:在文件 long_run.sh 中,我有:

#!/bin/bash

echo "Loading, please wait..."
sleep 5
echo "10%"
sleep 5
echo "20%"
sleep 5
echo "30%"
sleep 5
echo "40%"
sleep 5
echo "50%"
sleep 5
echo "60%"
sleep 5
echo "70%"
sleep 5
echo "80%"
sleep 5
echo "90%"
sleep 5
echo "100%"
sleep 5

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM