【问题标题】:Tkinter - Retrieve Values from Dynamically Generated Widgets - CallbackTkinter - 从动态生成的小部件中检索值 - 回调
【发布时间】:2019-11-03 10:43:28
【问题描述】:

我正在尝试通过 Tkinter 制作一个 GUI,它将根据一些用户输入来计算产量。根据用户选择的系统数量,我为逆变器类型弹出了该数量的选项菜单,并为每个串的模块、每个逆变器的串和每个系统的逆变器弹出了该数量的条目小部件。如果用户选择 2 个系统,请参见图片示例。

我正在使用回调函数实时获取用户选择的系统数量,以动态生成上述逆变器/模块小部件。

我的问题是我无法从这些小部件中检索值。我的尝试显示在天气计算功能中。

我假设问题是因为我在回调函数中生成了小部件/变量。但是,我还没有找到一种方法来根据回调函数之外的用户输入动态生成小部件的数量。

对此的任何帮助将不胜感激!

  class Window:  

# Define User Inputs:  
    def __init__(self, master):  
        master.title('Production Analysis Tool')  

 # EQUIPMENT PARAMETERS         

    # callback function to create entry boxes based on number of systems  
        def callback(*args):  
            self.system_size = int(self.system_size_raw.get())  

        # Modules per String  
            self.L3 = Label(root, text = "Number of Modules Per String").grid(row=20, column=1, sticky=E)  
            self.modules_string_raw = IntVar(root)  
            modules_per_string =[]  
            for i in range(self.system_size):  
                self.label = Label(root, text = "System {}".format(i+1)).grid(row=21+i, column=1, sticky=E)  
                self.widget = Entry(root).grid(row=21+i, column=2, sticky=W)  
                modules_per_string.append(self.widget)  

    # Number of Systems  
        self.L1 = Label(root, text = "Number of Systems").grid(row=1, column=1, sticky=E)  
        self.system_size_raw = IntVar(root)  
        choices = [1,2,3,4,5,6,7,8,9,10]  
        self.popupMenu2 = OptionMenu(root, self.system_size_raw, *choices).grid(row=1, column=2, sticky=W)  
        self.system_size_raw.trace("w", callback)  


#Calculation Function  

    def weather_calculation(self):     

    # Get Values from User Input  

        self.mod_strings = np.float(self.modules_string_raw.get())  

root = Tk()  
root.configure()  
window = Window(root)  
root.mainloop()

【问题讨论】:

  • 你发布的代码太多了。请尝试将其浓缩为minimal reproducible example。如果问题是从一组动态条目中获取值,我们所需要的只是一种设置数字的方法、一个生成它们的函数以及获取值的函数。我们不需要代码来处理一个csv文件,你可以使用一些静态数据。
  • 我已将其压缩为仅显示回调函数的一部分,我在其中调用回调函数,并尝试检索值。
  • 当我运行代码并从下拉列表中选择“3”时,它只会在抛出错误之前创建一个标签。
  • 抱歉,我仍然有对那里文件的引用。我已将其更改为每个字符串输入的模块。这应该适合你了

标签: python python-3.x tkinter tk


【解决方案1】:

您需要做的就是在列表中保存对您的Entry 小部件的引用。然后,您可以遍历该列表以获取每个小部件的值。

您似乎已经将小部件保存到列表变量modules_per_string。您需要做的就是使该全局或对象属性而不是局部变量,以便其他函数可以引用它。

【讨论】:

  • 所以我以为我是用“modules_per_string = []”做的,但这必须在函数之外吗?
  • 对于 tkinter,您无需做任何特别的事情——只是普通的 python 范围规则。如果您需要从多个地方访问列表,则它需要是全局的或以两个地方都可以访问的其他形式(例如:对象属性)。
  • 我已经成功地从这个回调函数之外的小部件中存储和检索了用户输入值。但是,我仍然不知道如何存储和访问回调函数中的条目。你能提供一个如何做到这一点的例子吗?
【解决方案2】:

正如 Bryan Oakley 所说,为小部件制作列表以将条目的每个对象和标签存储在两个列表中。

例如:

import tkinter as tk
class Demo:
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry("600x600")
        systems_label = tk.Label(self.root, text="No Of Systems:")
        systems_label.place(x=100, y=20)

        no_Of_System_Ent = tk.Entry(self.root, width=15)
        no_Of_System_Ent.place(x=200, y=20)

        submit_Button = tk.Button(self.root, text="Submit", command=lambda: self.process(no_Of_System_Ent.get()))
        submit_Button.place(x=350,y=20)

    def display(self,sys_len): 
        for i in range(sys_len):
              buffer = self.obj_of_entries[i].get()
              print(buffer)

    def delete(self,sys_len):
         for i in range(sys_len):
              self.obj_of_entries[i].destroy()
              self.obj_of_labels[i].destroy()

    def process(self,length_sys):
         self.obj_of_entries = []
         self.obj_of_labels = []
         y_pos = 80
         for i in range(int(length_sys)):
              #Adding objects of label in list 'obj_of_labels'
              self.obj_of_labels.append(tk.Label(self.root,text="System "+str(i)))
              self.obj_of_labels[len(self.obj_of_labels)-1].place(x=100,y=y_pos)

              #Adding objects of entry in list 'obj_of_entries'
              self.obj_of_entries.append(tk.Entry(self.root,width=15))
              self.obj_of_entries[len(self.obj_of_entries)-1].place(x=200,y=y_pos)

              #Increments Y by 50
              y_pos = y_pos + 50

              self.delete_Button = tk.Button(self.root, text="Delete All", command=lambda: self.delete(int(length_sys)))
              self.delete_Button.place(x=200,y=400)

              self.print_Button = tk.Button(self.root, text="Print All", command=lambda: self.display(int(length_sys)))
              self.print_Button.place(x=350,y=400) 

ob=Demo()

在这个例子中:

我在 init 函数中创建了一个条目和按钮,以从用户那里获取系统。

def __init__(self):
    self.root = tk.Tk()
    self.root.geometry("600x600")

    systems_label = tk.Label(self.root, text="No Of Systems:")
    systems_label.place(x=100, y=20)

    no_Of_System_Ent = tk.Entry(self.root, width=15)
    no_Of_System_Ent.place(x=200, y=20)

    submit_Button = tk.Button(self.root, text="Submit", command=lambda: self.process(no_Of_System_Ent.get()))
    submit_Button.place(x=350,y=20)

点击提交按钮后,进入处理功能。

Ps:length_sys 是系统数。

def process(self,length_sys):
    self.obj_of_entries = []
    self.obj_of_labels = []
    y_pos = 80
    for i in range(int(length_sys)):
        #Adding objects of label in list 'obj_of_labels'
        self.obj_of_labels.append(tk.Label(self.root,text="System "+str(i)))
        self.obj_of_labels[len(self.obj_of_labels)-1].place(x=100,y=y_pos)

        #Adding objects of entry in list 'obj_of_entries'
        self.obj_of_entries.append(tk.Entry(self.root,width=15))
        self.obj_of_entries[len(self.obj_of_entries)-1].place(x=200,y=y_pos)

        #Increments Y by 50
        y_pos = y_pos + 50

        self.delete_Button = tk.Button(self.root, text="Delete All", command=lambda: self.delete(int(length_sys)))
        self.delete_Button.place(x=200,y=400)

它将在其各自的列表中附加条目和标签 obj 并将当前 obj 放置在 GUI 窗口中。 最后,它将 y 轴增加 80,以便下一个标签和条目下降到上一个。

如果用户点击删除所有按钮,那么它将删除所有条目和标签的列表obj。

Ps:sys_len 是系统数。

def delete(self,sys_len):
    for i in range(sys_len):
        self.obj_of_entries[i].destroy()
        self.obj_of_labels[i].destroy()

要查看内容,请使用以下代码:

(它将在 Python shell 中打印,以便您查看数据是否正确。)

def display(self,sys_len): 
    for i in range(sys_len):
        buffer = self.obj_of_entries[i].get()
        print(buffer)

我想我解决了这个疑问。 咻!

【讨论】:

  • 感谢您的建议。我试过了,但我仍然无法存储用户输入的值。有什么建议吗?
  • 我更改了我的答案,在其中添加了您的疑问。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2012-06-16
相关资源
最近更新 更多