这是一个简单的gui。我正在从条目中的用户那里获取url。按下按钮时,url将保存在一个文件中,并调用另一个函数以通过调用(在子流程内(启动另一个流程。当进程运行时,我想显示不确定的进度条(直到按下按钮,该条需要隐藏(,当进程完成时,会显示一条showinfo消息来销毁gui。
问题:直到流程结束,酒吧才会出现。显示showinfo对话框后,它才开始进行。也就是说,酒吧在真正应该被摧毁的那一刻就开始了
我的代码出了什么问题?
import scrapy
import tkinter as tk
from tkinter import messagebox as tkms
from tkinter import ttk
import shlex
from subprocess import call
def get_url():
# get value from entry and write to a file
def scrape():
progress_bar = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=300, mode='indeterminate')
progress_bar.grid(row=3, column=2)
progress_bar.start(10)
command_line = shlex.split('scrapy runspider /media/mayank/Local/Coding/Lab/Scraping/Practices/img.py')
call(command_line)
mes = tkms.showinfo(title='progress', message='Scraping Done')
if mes == 'ok':
root.destroy()
root = tk.Tk()
root.title("Title")
entry1 = tk.Entry(root, width=90, textvariable=url)
entry1.grid(row=0, column=0, columnspan=3)
my_button = tk.Button(root, text="Process", command=lambda: [get_url(), scrape()])
my_button.grid(row=2, column=2)
root.mainloop()
----更新代码---
import scrapy
import tkinter as tk
from tkinter import messagebox as tkms
from tkinter import ttk
import shlex
from subprocess import call
def get_url():
# get value from entry and write to a file
scrapy = None
def watch():
global scrapy
if scrapy:
if scrapy.poll() != None:
# Update your progressbar to finished.
progress_bar.stop()
progress_bar.destroy()
# Maybe report scrapy.returncode?
print(f'scrapy return code =--######==== {scrapy.returncode}')
scrapy = None
else:
# indicate that process is running.
progress_bar.start(10)
print(f'scrapy return code =--######==== {scrapy.returncode}')
# Re-schedule `watch` to be called again after 0.1 s.
root.after(100, watch)
def scrape():
global scrapy
command_line = shlex.split('scrapy runspider ./img.py')
scrapy = Popen(command_line)
watch()
mes = tkms.showinfo(title='progress', message='Scraping Done')
if mes == 'ok':
root.destroy()
root = tk.Tk()
root.title("Title")
url = tk.StringVar(root)
entry1 = tk.Entry(root, width=90, textvariable=url)
entry1.grid(row=0, column=0, columnspan=3)
my_button = tk.Button(root, text="Process", command=lambda: [get_url(), scrape()])
my_button.grid(row=2, column=2)
progress_bar = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=300, mode='indeterminate')
progress_bar.grid(row=3, column=2)
root.mainloop()
使用subprocess.call
中断当前进程,直到调用的进程完成。因此,GUI在调用完成之前不会更新。
重要提示:
切勿从tkinter
程序的主线程调用subprocess.run
、subprocess.call
或其他方便函数之一。这样做将冻结GUI。您应该只从主线程创建subprocess.Popen
对象
相反,您应该创建一个Popen
对象,同时禁用启动按钮。
要跟踪进度,请定义一个用root.after()
周期性调用的函数,比如每0.1秒调用一次。在这个函数中,您可以调用poll()
方法来检查子流程是否已经完成。或者,您可以设置stdout=subprocess.PIPE
,并从Popen
对象的stdout
属性读取子流程中的数据。
下面的代码是基于您更新的问题的工作(对我来说(示例。请注意,我已经在UNIX机器上用一个相对长时间运行的命令替换了scrapy
(我没有(。由于您正在将scrapy作为子流程运行,因此不需要import scrapy
。
import tkinter as tk
from tkinter import messagebox as tkms
from tkinter import ttk
from subprocess import Popen
proc = None
def watch():
global proc
if proc:
if proc.poll() is not None:
# Update your progressbar to finished.
progress_bar.stop()
progress_bar.destroy()
# Maybe report proc.returncode?
print(f'proc return code =--######==== {proc.returncode}')
proc = None
mes = tkms.showinfo(title='progress', message='Scraping Done')
if mes == 'ok':
root.destroy()
else:
# indicate that process is running.
progress_bar.start(10)
# print(f'proc return code =--######==== {proc.returncode}')
# Re-schedule `watch` to be called again after 0.1 s.
root.after(100, watch)
def scrape():
global proc
command_line = ['netstat']
proc = Popen(command_line)
watch()
root = tk.Tk()
root.title("Title")
url = tk.StringVar(root)
entry1 = tk.Entry(root, width=90, textvariable=url)
entry1.grid(row=0, column=0, columnspan=3)
my_button = tk.Button(root, text="Process", command=lambda: [get_url(), scrape()])
my_button.grid(row=2, column=2)
progress_bar = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=300, mode='indeterminate')
progress_bar.grid(row=3, column=2)
root.mainloop()