如何在 Tkinter 父脚本中实现 `input` 方法,并将显示的提示和返回值发送回子脚本? [英] How can I implement an `input` method in a Tkinter parent script, with the displayed prompt and return value being sent back to a child script?

查看:30
本文介绍了如何在 Tkinter 父脚本中实现 `input` 方法,并将显示的提示和返回值发送回子脚本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个脚本:

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

Processor_child.py: Its purpose is to perform a number of data analysis and cleaning operations. This must perform the same operations when run alone (without Tkinter_parent.py) as it does when packaged into a GUI with Tkinter_parent.py.

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

Tkinter_parent.py: Its purpose is to provide a GUI for those who can't use Processor_child directly.

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

Where I'm struggling is to reproduce the python input function from Processor_child.py in the instance where these two are used together as a GUI. I need to present a prompt to the user (done in code below), transfer that response to the GUI (various options available for this, such as Pipe), and only after that response has been passed have Processor_child resume its operation / retrieve the entry value (how?).

问题的示例代码,### 注释 ### 指示需要插入代码以执行所需功能的位置:

Example code of the issue, with ### comments ### indicating where code needs to be inserted to perform desired functionality:

### 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:

And 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 输入存储到下一个函数中的字符串变量?:但它们不适用于在执行其他操作之前等待输入的情况(如我在此处介绍的两种情况).

I've reviewed a number of related questions on SO, such as Getting a TKinter input stored into a string variable in the next function?: But they do not apply to cases where the input is being waited on before other actions are being performed (as in both cases I've presented here).

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

Other SO questions like How do I make the program wait for an input using an Entry box in Python GUI? don't work in these instances where the input in embedded within a loop within an executing function in another script; they rely on the 'waiting' being done within the GUI script itself.

推荐答案

注意:这仅在极少数情况下有效.这不是一个真正的解决方案"......我仍然面临这个问题.修复下面的方法有它自己的 SO 问题:Tkinter application冻结"同时不断轮询管道以获取内容(多处理)

Note: This only works in rare cases. It is not a true 'solution'... I still face this issue. Fixing the approach below has its own SO question: Tkinter application 'freezes' while continually polling Pipe for contents (multiprocessing)

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

I've been able to find a pseudo-solution in which I add while loops that poll the Pipe, and upon finding that the Pipe does contain content, request the data in the Pipe. These while loops easily overload the application, and only seem to work in a simplified case. Definitely not the best way.

查看修改后的代码:

### 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:

And 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()

这篇关于如何在 Tkinter 父脚本中实现 `input` 方法,并将显示的提示和返回值发送回子脚本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆