Python / Tkinter: итерации цикла не завершаются - PullRequest
0 голосов
/ 28 ноября 2011

В следующем случае я пытаюсь распечатать весь вывод сценария temp2 (который выполняется через подпроцесс) в виджет текстового поля в режиме реального времени.

Проблема, с которой я сталкиваюсь, заключается в следующем: в temp2 для i <= 468 скрипт работает нормально, и мне кажется, что он работает в режиме реального времени.

Однако, если я поставлю i = 469 или выше, выполнение останавливается после многих итераций без завершения.

Так, например, для i = 469 в файле журнала есть записи от i = 469 до i = 3. Там после всего процесса останавливается.

Обратите внимание: значение i = 469 может не совпадать для вашей машины. Если i = 469 работает для вас нормально, попробуйте более высокое значение.

Temp1.py является основным скриптом.

#temp1.py
from Tkinter import *
import Tkinter as tk
import os
import ttk 
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
import sys

#Creating new Window to display output 
t = Tk()
t.title('output Run Display')
t.geometry('800x1000-5+40')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=115, height=150, wrap='none')
log.grid(row = 1, column = 0)

test=subprocess.Popen('temp2',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)


#stdout
while True:
    line_out = test.stdout.readline()
    line_er  = test.stderr.readline()
    if line_out == "" and line_er == "":
        break
    else:
        log['state'] = 'normal'
        log.insert('end', line_out)
        log.insert('end', line_er)
        log['state'] = 'disabled'
        print line_out
        print line_er
        t.update()
t.mainloop()

И ниже скрипт, который я запускаю через подпроцесс.

#temp2 #csh script

set i = 469
while ($i > 0)
  echo i is $i | tee -a log
  set i = `expr "$i" - 1`
end 

Ответы [ 3 ]

1 голос
/ 28 ноября 2011

Ваша проблема в том, что вызов test.stdout.readline блокируется - это означает, что обработка на этом останавливается и возобновляется только при наличии новой доступной строки данных, которая возвращается.

То же самое верно для test.stderr.readline конечно.

Я думаю, что самый простой способ справиться с тем, что вам нужно - это записать подпроцесс в файл в файловой системе, открыть этот файл в главном процессе и попытаться прочитать его внутри функции обратного вызова tkinter, регулярно вызываемой с помощью .after метод tkinter.

(с файлом в файловой системе вы можете использовать методы seek и tell, чтобы проверить, находитесь ли вы в конце файла)

Обратите внимание, что в коде, который вы поместили в качестве примера, ваш вызов Tkinter.mainloop достигается только после того, как подпроцесс уже завершен.

Лучшим, но все же решением, будет чтение журналов, которые вы хотите полностью на Python, без использования сценария оболочки.

Tkinter.after похож на settimeout javascript - это метод в виджете (скажем, ваш объект "t"), и вы передаете ему количество ожидающих миллисекунд и имя вызываемой функции -

как в

def verify_output():
    # read subprocess output file and update the window if needed
    ...
    # call self after 1 second
    t.after(1000, verify_output)

# callreader callback for the first time:

t.after(10, verify_output)
Tkinter.mainloop()
0 голосов
/ 08 декабря 2011

При ответе jsbueno ваша проблема связана с блокировкой вызова на readline. Вместо этого вы можете использовать источник событий файла, чтобы получать уведомления о доступности данных (с помощью метода createfilehandler tkinter). Подробнее см. этот предыдущий ответ .

0 голосов
/ 29 ноября 2011
import os
import ConfigParser
from Tkinter import *
import Tkinter as tk
import os
import ttk 
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
from subprocess import call
import sys

os.system('rm stdout')

#Creating new Window to display output 
t = Tk()
t.title('output Run Display')
t.geometry('100x100')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=50, height=50, wrap='none')
log.grid(row = 1, column = 0,sticky=(N,W,E,S))
s = ttk.Scrollbar(t,orient=VERTICAL,command=log.yview)
s.grid(column=1,row=1,sticky=(N,S))
log.configure(yscrollcommand=s.set)
ttk.Sizegrip().grid(column=1, row=1, sticky=(S,E))

with open("stdout","wb") as out:
    with open("stderr","wb") as err:
        test=subprocess.Popen('tem',shell=True,stdout=out,stderr=err)
fout = open('stdout','r')
ferr = open('stderr','r') 
def verify():

    data_out = fout.readlines()
    data_out = ''.join(data_out)

    log['state'] = 'normal'
    log.insert('end',data_out)
    log['state'] = 'disabled'
    #print data_out

    t.after(1000,verify)
    fout.close()

verify()

t.mainloop()
...