如何在Tkinter父脚本中实现"input"方法,并将显示的提示和返回值发送回子脚本



我有两个脚本:

Processor_child.py:其目的是执行大量数据分析和清理操作。当单独运行(没有Tkinter_parent.py)时,它必须执行与使用Tkinter_parent.py打包到GUI中时相同的操作。

Tkinter_parent.py:它的目的是为那些不能直接使用Processor_child的用户提供一个GUI。

我正在努力从Processor_child.py中复制pythoninput函数,在这两个函数一起用作GUI的实例中。我需要向用户显示一个提示(在下面的代码中完成),将该响应传输到GUI(可用于此操作的各种选项,如Pipe),只有在该响应传递之后,Processor_child才能恢复其操作/检索条目值(如何?)。

问题的示例代码,###注释###指示代码需要插入到哪里才能执行所需功能:

### Processor_child.py ###
import pandas as pd
def smart_print(message, a_pipe = None):
if __name__ == "__main__":
print(message)
else:
a_pipe.send(message)
def review_with_user(var_names, dataset, a_pipe = None):
affirmed = []
review_message = 'Yes or no?'
if __name__ == "__main__":
review_response = input(review_message)
else:
smart_print(review_message, a_pipe)
review_response = 'Yes' ### INSTEAD SOMEHOW GET RESPONSE FROM Tkinter_parent.py ###
if review_response in ['Yes', 'yes']:
for v in set(var_names):
smart_print(dataset[v].dropna()[:8], a_pipe)
if __name__ == "__main__":
local_response = input(review_message)
else:
local_response = None ### INSTEAD SOMEHOW GET RESPONSE FROM Tkinter_parent.py ###
if local_response in ['Yes', 'yes']:
affirmed.append(v)
if __name__ == "__main__":
var_names = ['var1', 'var2']
df = pd.read_csv('dummy.csv')
review_with_user(var_names, df)

和Tkinter_parent.py:

### Tkinter_parent.py ###
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter import ttk
from multiprocessing import Process, Pipe
import pandas as pd
import Processor_child
class GUI:
def __init__(self, master):
self.master = master
def gui_input(message):
def input_done(event=None):
### INSTEAD SOMEHOW send entry.get() back to Processor_child.py ###
pass
entry = Entry(frame)
input_label = ttk.Label(frame, text=message)
entry.bind("<Return>", input_done)
submit_button = ttk.Button(frame, text="Submit", command=input_done)
input_label.pack()
entry.pack()
submit_button.pack()
def file_select():
dataset_path = askopenfilename()
if __name__ == '__main__':
pipe1, pipe2 = Pipe()
some_vars = ['a var', 'another var']
a_df = pd.read_csv(dataset_path)
p_review = Process(target=Processor_child.review_with_user, args=(some_vars, a_df, pipe2))
p_review.start()
gui_input(pipe1.recv())
if __name__ == '__main__':
root = Tk()
my_gui = GUI(root)
root.style = ttk.Style()
root.style.configure('my.TButton')
root.style.configure('my.TLabel')
canvas = Canvas(root)
frame = Frame(canvas)
frame.place()
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((45,50), window=frame, anchor="nw")
ttk.Button(frame, text="Select", command=file_select).pack()
root.mainloop()

我已经复习了许多关于SO的相关问题,例如是否将TKinter输入存储到下一个函数中的字符串变量中?:但它们不适用于在执行其他操作之前等待输入的情况(就像我在这里介绍的两种情况一样)。

其他SO问题,如如何使用Python GUI中的Entry框让程序等待输入?在这些情况下,输入嵌入到另一个脚本中执行函数的循环中,则不起作用;它们依赖于GUI脚本本身中正在进行的"等待"。

注意:这只在极少数情况下有效。这不是一个真正的"解决方案"。。。我仍然面临这个问题。修复以下方法有其自身的SO问题:Tkinter应用程序在不断轮询Pipe以获取内容(多处理)时"冻结">


我已经能够找到一个伪解决方案,其中我添加while循环pollPipe,当发现Pipe确实包含内容时,请求Pipe中的数据。这些while循环很容易使应用程序过载,而且似乎只能在简化的情况下工作。绝对不是最好的方式。

参见修改后的代码:

### processor_child.py ###
import pandas as pd
from multiprocessing import *
import time
def smart_print(message, a_pipe = None):
if __name__ == "__main__":
print(message)
else:
a_pipe.send(message)
def review_with_user(var_names, dataset, a_pipe = None):
affirmed = []
review_message = 'Yes or no?'
if __name__ == "__main__":
review_response = input(review_message)
else:
smart_print(review_message, a_pipe)
while a_pipe.poll() != True:
time.sleep(0.1)
review_response = a_pipe.recv()
if review_response in ['Yes', 'yes']:
for v in dataset.columns:
smart_print(dataset[v].dropna(), a_pipe)
if __name__ == "__main__":
local_response = input(review_message)
else:
while a_pipe.poll() != True:
time.sleep(0.1)
local_response = a_pipe.recv()
if local_response in ['Yes', 'yes']:
affirmed.append(v)
smart_print(affirmed, a_pipe)
if __name__ == "__main__":
var_names = ['var1', 'var2']
df = pd.read_csv('dummy.csv')
review_with_user(var_names, df)

和Tkinter_parent.py:

### Tkinter_parent.py ###
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter import ttk
from multiprocessing import Process, Pipe
import pandas as pd
import Processor_child
import time
class GUI:
def __init__(self, master):
self.master = master
def gui_input(message, a_pipe = None):
def input_done(event=None):
entry.pack_forget()
input_label.pack_forget()
submit_button.pack_forget()
a_pipe.send(entry.get())
next_one(a_pipe)
entry = Entry(frame)
input_label = ttk.Label(frame, text=message)
entry.bind("<Return>", input_done)
submit_button = ttk.Button(frame, text="Submit", command=input_done)
input_label.pack()
entry.pack()
submit_button.pack()
def file_select():
dataset_path = askopenfilename()
if __name__ == '__main__':
pipe1, pipe2 = Pipe()
some_vars = ['a var', 'another var']
a_df = pd.read_csv(dataset_path)
p_review = Process(target=Processor_child.review_with_user, args=(some_vars, a_df, pipe2))
p_review.start()
gui_input(pipe1.recv(), pipe1)
#time.sleep(1)
def next_one(pipe1):
while pipe1.poll() != True:
time.sleep(0.1)
gui_input(pipe1.recv(), pipe1)
if __name__ == '__main__':
root = Tk()
my_gui = GUI(root)
root.style = ttk.Style()
root.style.configure('my.TButton')
root.style.configure('my.TLabel')
canvas = Canvas(root)
frame = Frame(canvas)
frame.place()
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((45,50), window=frame, anchor="nw")
ttk.Button(frame, text="Select", command=file_select).pack()
root.mainloop()

最新更新