#python #ide #console #tkinter
#python #ide #консоль #tkinter
Вопрос:
Я создаю простую IDE с текстовым полем и кнопкой запуска. При этом пользователю предлагается ввести имя файла, записывается код, записанный в файл, и выполняется этот файл. Я хочу показывать все, что выводится с консоли, например, печать, ввод и т.д., Как это делают IDE. Возможно ли это?
Вот мой код:
from Tkinter import *
import tkFileDialog
import ScrolledText
import subprocess
filepath=""
def run():
global filepath
print "<<<<<<=====-------------Restart-------------=====>>>>>>"
py=code.get(1.0,END)
if filepath=="":
filepath=tkFileDialog.asksaveasfilename()
if ".py" not in filepath:
filepath=filepath ".py"
script=open(filepath, "w")
script.write(py)
script.close()
p = subprocess.Popen(['python', filepath],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
for line in iter(p.stdout.readline, ''):
print line
print "<<<<<<=====-------------EXECUTION FINISHED-------------=====>>>>>>"
root = Tk()
code=ScrolledText.ScrolledText(root)
code.pack()
run=Button(root,text="Run", command=run)
run.pack()
root.mainloop()
Комментарии:
1. Конечно, это возможно. Если бы это было невозможно, другие IDE не смогли бы этого сделать, не могли бы они теперь? Попробуйте запустить пользовательскую программу как подпроцесс и записать ее вывод.
2. Ха, хорошая мысль, никогда не понимал, как работает IDE, пока не попробовал ее создать!
Ответ №1:
Да, просто используйте модуль subprocess.
Получение вывода за один раз
import subprocess
output = subprocess.check_output(['python', filepath])
Если вы хотите зафиксировать стандартную ошибку вызываемого процесса, а также стандартный вывод, используйте это вместо:
output = subprocess.check_output(['python', filepath], stderr=subprocess.STDOUT)
Или, если вы хотите записать их отдельно:
p = subprocess.Popen(['python', filepath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
out, err = p.communicate()
Получение вывода по мере его создания
Это дает вам комбинированный вывод stdout и strerr, построчно:
p = subprocess.Popen(['python', filepath],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
for line in iter(p.stdout.readline, ''):
# process the line
Сохранение адаптивного пользовательского интерфейса
Если вы запускаете приведенный выше код в том же потоке, что и ваш графический интерфейс, вы, по сути, блокируете выполнение цикла событий Tk во время ожидания каждой строки. Это означает, что, хотя вы получаете каждую строку в режиме реального времени и записываете ее в свой графический интерфейс, он не обновит отображение до тех пор, пока цикл событий не запустится снова и не обработает все ваши вызовы Tk.
Вам нужно запустить код подпроцесса в новом потоке, а в вашем потоке GUI периодически проверять наличие нового ввода.
Я сделал для вас пример на основе вашего, вы можете найти его здесь:
Комментарии:
1. Ошибка при печати и вывод работает, но как мне распечатать его в том виде, в каком он был выведен в том же порядке? Это запускает всю программу, собирает ошибки и выходные данные и печатает их после завершения работы main… Я хочу, чтобы он печатался так, как это делает консольный ввод-вывод.
2. Смотрите мою правку для этого. Если вы хотите stdout и stderr отдельно, то это сложнее, так как вам нужно использовать потоки. Дайте мне знать, требуется ли это.
3. Таким образом, редактирование выведет все выходные данные и ошибки в порядке их отправки? Что, если я хочу, чтобы он печатался по мере отправки? В этом случае он выводит их в таком порядке, но, допустим, я должен ввести код, который печатает «Hello World» и использует
time.sleep(1)
и печатает его снова. Я хочу, чтобы он печатал и выводил следующую инструкцию после задержки в 1 секунду. Это редактирование просто напечатало бы два отпечатка сразу после завершения работы программы в подпроцессе. Есть ли способ сделать это?4.Да, эта версия работает, но я ввел код
print "Hello"
time.sleep(5)
print "Hello"
, но когда я нажимаю выполнить, программа в подпроцессе ожидает завершения программы в течение 5 секунд, а затем печатает два приветственных мира, я хочу, чтобы он печатал первый по мере его вывода, а затем следующий по мере его вывода через 5 секунд.5. Я не понимаю этот последний комментарий …?