如何使用Tkinter停止while循环以从用户获取输入



这么基础的知识怎么会被埋藏在这么难找到的地方,真是不可思议。我花了将近一个月的时间在谷歌上寻找答案——看视频、阅读文档、书籍等——关于如何停止while循环以从使用Tkinter的用户那里获取输入。

我下面的代码循环两次,并在我能够提供输入之前离开循环!!

无论如何,理论是赞赏的,但一个示例代码将是更大的帮助。非常,非常感谢。
# Python 3.5.1
from tkinter import *
from tkinter import ttk
loop = 0
while loop < 2:
    print ('loop')
    def user_data():
        user_input = data.get()
        print (user_input)
    lb=ttk.Label(root, text="Enter data")
    data=ttk.Entry(root)
    bt=ttk.Button(root, text='Ok', command=user_data)
    lb.grid(row=0, column=1)
    data.grid(row=0, column=2)
    bt.grid(row=0, column=3)
    loop += 1
print ('left loop')
root.mainloop()

好吧,我想这个笑话终究是在我身上。我花了三天时间告诉你这不是件容易的事,结果证明我错了。

我很快就会给你代码,让我解释一下我哪里出错了。当我在写我的最后一个评论时,我想向你解释的主要事情是,当你在GUI控制台中运行控制台Python程序时,这是两个不同的进程,GUI的事件循环与内部Python程序的工作方式无关。

在GUI应用程序中,它会崩溃,因为只有一个进程,它的事件循环不能同时运行(响应正常的应用程序事件,如重新绘制窗口或处理点击/按键)并保持阻塞(等待您单击按钮)。在我看来,如果tkinter能够让用户创造额外的事件循环,事情就会变得非常简单。这不是不合理的:因为tkinter已经为自己的目的构造了一个构造函数,它只需要向用户公开该构造函数(或其他构造方法)。而且不会有任何GIL问题,因为另一个事件循环只是被阻塞(只有一个在实际执行)。

一旦我知道我在搜索什么,就不难找到了:你构造一个Tk变量(任何类型的,布尔值对这种语义都很好),切换它的值,然后在回调中切换它。与此同时,你等待着它发生变化。很容易。: -)

我试图尽可能少地修改你的代码,但是,当然,一旦你知道了它的机制,你可以做得更好。我希望我已经恢复了你对特金特的信心。: -)

from tkinter import *
from tkinter import ttk
root = Tk()
loop = 0
block = BooleanVar(root, False)
while loop < 2:
    print ('loop')
    def user_data():
        user_input = data.get()
        print (user_input)
        block.set(False)
    lb=ttk.Label(root, text="Enter data")
    data=ttk.Entry(root)
    bt=ttk.Button(root, text='Ok', command=user_data)
    lb.grid(row=0, column=1)
    data.grid(row=0, column=2)
    bt.grid(row=0, column=3)
    block.set(True)
    root.wait_variable(block)
    loop += 1
print ('left loop')
root.mainloop()

好了,经过大量的讨论,看起来您实际上不需要等待任何东西。GUI处于等待事件的永久状态,因此您不需要添加额外的等待。你所需要的只是一个"保存"按钮,以及一种让用户输入可变数量的值的方法。

为了允许用户输入多个值,您可以添加一个按钮来添加更多的输入小部件。唯一真正的技巧是保留条目小部件的列表,以便您可以稍后在程序中获得这些值。

下面是一个演示该技术的工作示例。

注意:这不是我在真正的GUI中实际做的,因为它依赖于全局变量。目的是为了说明动态添加入口小部件的一般原则。

import tkinter as tk
def add_entry():
    """
    Add two entries, one for a description, one for an amount,
    along with some labels
    """
    # create the label and entry widgets
    label1 = tk.Label(entry_frame, text="Description:")
    label2 = tk.Label(entry_frame, text="Amount:")
    entry1 = tk.Entry(entry_frame)
    entry2 = tk.Entry(entry_frame)
    # lay them out on the screen
    column, row = entry_frame.grid_size()
    label1.grid(row=row, column=0, sticky="e", pady=2)
    entry1.grid(row=row, column=1, sticky="ew", pady=2, padx=4)
    label2.grid(row=row, column=2, sticky="e", pady=2)
    entry2.grid(row=row, column=3, sticky="ew", pady=2, padx=4)
    entry_frame.grid_rowconfigure(row, weight=0)
    entry_frame.grid_rowconfigure(row+1, weight=1)
    # save the entries, so we can retrieve the values
    entries.append((entry1, entry2))
    # give focus to the new entry widget
    entry1.focus_set()
def save():
    # iterate over the entries, printing the values
    for description_entry, value_entry in entries:
        print("description: %s value: %s" % 
              (description_entry.get(), value_entry.get()))
# this is our global list of entries
entries = []
# create the main window and buttons
root = tk.Tk()
entry_frame = tk.Frame(root)
button_frame = tk.Frame(root)
entry_frame.pack(side="top", fill="both", expand=True)
button_frame.pack(side="bottom", fill="x")
add_button = tk.Button(button_frame, text="add another entry", command=add_entry)
save_button = tk.Button(button_frame, text="Save", command=save)
add_button.pack(side="left")
save_button.pack(side="right")
# create the first entry
add_entry()
# start the main loop -- this is where the GUI starts waiting,
# and why you don't need to add your own loop.
root.mainloop()

相关内容

  • 没有找到相关文章

最新更新