Python tkinter多窗口的交互问题:子窗口无法获取数据

Python tkinter多窗口的交互问题:子窗口无法获取数据

tkinter第二个、第三个子窗口数据不能交互响应的解决方法

先说结论:第二个、第三个子窗口生成时,不能用tk.Tk(),而应改为tk.Toplevel(),问题解决。

问题描述

最近在用tk、ttk开发一个仿真软件时,当在主窗口(tk.Tk()生成)点击相关设置按键时,调用另一模块中的函数(通过import导入),函数执行过程中弹出第二个或更多的子窗口,在子窗口输入数据或点击相关按键时,发现子窗口的交互数据无法获得!而同样的代码段如果放入主窗口则没有问题!
下图为问题出现的场景
在这里插入图片描述
点击person行的参数设置,选择自定义模式时,调用另一模块中的函数,弹出新的窗口。
主脚本代码为:

person_par_set = ttk.Combobox(type_table, width=10)  # 初始化
person_par_set["values"] = ("Default", "User-defined")
person_par_set.current(0)  # 选择第一个
def go_person_par_set(*args):  # 事件
    var_number = eval(number_set.get())  # 将对应的字符型数值转换为数字
    var_person_prop = eval(person_prop.get())
    var_person_par = person_par_set.get()
    var_person_label = person_label.cget("text")
    var_person = {'label': var_person_label, 'prop': var_person_prop, 'par': var_person_par}
    person_row.set(var_person)  # 将字典型以字符串形式赋值给控件型变量
    set_person(var_number, var_person)  # 调用另一模块中的函数,实现person的设置
person_par_set.bind("<<ComboboxSelected>>", go_person_par_set)  # 绑定事件,(下拉列表框被选中时,绑定go()函数)

调用的函数代码为:

def set_person(var_number, var_person):  # 进行person型成员的设置
    person_number = round(var_number * var_person['prop'] * 0.01, 0)  # 四舍五入取0位小数
    p = int(person_number)
    if var_person['par'] == "Default":
        tf_data = np.random.uniform(0, 1, p)  # 生成0~1之间,p个均匀分布的随机数
        # 为将list中每个数字保留2位,将list转为numpy数组,然后对numpy进行操作,最后将numpy再转为数组。
        tf_data = np.array(tf_data)
        tf_data = np.round(tf_data, 2)  # round不能用于list,可用于array
        tf_data = list(tf_data)
        np.save('person_par.npy', tf_data)
    elif var_person['par'] == "User-defined":
        win_person = tk.Tk()  # 待详细设置person属性的子窗口
        win_person.title('Person Properties Settings')
        wid = sub_window(win_person)  # 调用sub_window函数,设置窗口,并返回窗口的宽度值

        tf_table = ttk.LabelFrame(win_person, text='information set', labelanchor='n')
        tf_table.grid(column=0, row=3, padx=8, pady=15)  # row,column指示相对行号和列号,非绝对位置;padx,y为挂靠坐标位置
        tf_radva = tk.IntVar()
        tf_radva.set(99)
        def radCall(*args):
            print(tf_radva.get())
        curRad1 = ttk.Radiobutton(tf_table, text="平均分布", value=1, variable=tf_radva, command=radCall)
        curRad1.grid(column=0, row=0, sticky=tk.W)
        curRad2 = ttk.Radiobutton(tf_table, text="正态分布", value=2, variable=tf_radva, command=radCall)
        curRad2.grid(column=0, row=1, sticky=tk.W)

        tf_data = np.random.normal(0.5, 0.1, p)  # 生成0~1之间,p个均匀分布的随机数
        # 为将list中每个数字保留2位,将list转为numpy数组,然后对numpy进行操作,最后将numpy再转为数组。
        tf_data = np.array(tf_data)
        tf_data = np.round(tf_data, 2)  # round不能用于list,可用于array
        tf_data = list(tf_data)
        np.save('person_par.npy', tf_data)

弹出设置窗口
在这里插入图片描述
上述代码设计为:tf_radva初值设置为99;当radio按钮被选中时,其值(分别为1,2)会赋给tf_radva,通过tf_radva这个IntVar型控件变量指向radio的variable的方式。拟实现的效果为,当选中<平均分布radio>时,打印1;选中<正态分布>时,打印2。而真实情况是,无论选中哪个radio,都打印99,功能不能实现。而将此段代码放于主窗口的某个位置而不弹出新窗口的话,则功能能够实现。

问题分析

  1. 经反复测试,代码功能没有问题。我一度认为是,调用后台函数时,后台函数使用变量的生存周期问题,“在次脚本中tf_radva不能指向对应radio的variable(或者说,这种指向是临时性的,因为次脚本的函数生存周期是临时性,临时性的内存分配,在窗口响应时,该临时内存存储地址未持续到响应事件进行时却已结束)”,——如果说是变量生存周期的问题,那么每次点击radio时,却有事件的响应,每次都打印99,而不是不打印。即事件有响应,那么在响应期,变量是生存的——不是该原因。既然不是变量的生存周期问题,而确实tf_radva未指向对应radio的variable,即程序在执行variable=tf_radva时,未能将tf_radva指向当前窗口radio的变量,而此问题出现在两个窗口共存的情况下。或者可以这样认为,系统此时在确认哪一个是“活跃窗口”发生了问题,需要确定哪一个窗口是active的。
  2. 耗费了一上午的时间,经反复查阅与搜索论坛,发现问题所在。将子窗口生成时代码改为tk.Toplevel()即可
win_person = tk.Toplevel()  # 待详细设置person属性的子窗口

——Toplevel(顶级窗口)组件是一个独立的顶级窗口,这种窗口通常拥有标题栏、边框等部件。
——何时使用 Toplevel 组件?
——Toplevel 组件通常用在显示额外的窗口、对话框和其他弹出窗口上。
——Tkinter Toplevel:顶层部件的工作,直接由窗口管理器管理的窗口。他们不必在它们上面的父widget

参考博文

参考博文
https://blog.csdn.net/liyuan3970/article/details/82874653
Toplevel(顶层)
https://blog.csdn.net/m0_37264397/article/details/79101630

  • 10
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值