Tkinter:选项菜单动态链接时不打印功能

问题描述

我正在尝试创建 2 个相互依赖的 OptionMenu,第一个的选择将为第二个提供不同的选项。

我能够使用 trace 将这两个链接在一起。 两个 OptionMenu链接一个命令,无论何时做出选择,都会在终端上打印一条消息。

虽然这适用于第一个 OptionMenu,但在第二个进行选择时我无法打印任何内容。请注意,如果 I 两个 OptionMenus 没有相互动态链接(即,如果它们被构造为单独的小部件),则打印对它们都非常有用。

知道可能是什么问题吗?

这是说明问题的代码

import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter import messageBox

from PIL import ImageTk,Image

import os

#____________________________________________________________________________________________   
#This will be the main window
window = tk.Tk()
window.geometry('700x700')
window.title("daq")

#____________________________________________________________________________________________
#Lower frame
frame_main = Frame(window)
frame_main.place(rely=0.10,relx=0.0,relwidth=1.0)

#Create a tabcontrol
tabControl = ttk.Notebook(frame_main)
tabControl.grid(column=0,row=1)

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Digitizer tab
tab_Digitizer    = ttk.Frame(tabControl)
tabControl.add(tab_Digitizer,text='   Digitizer   ')
digitizer_tab_dummy_label = Label(tab_Digitizer,text="")
digitizer_tab_dummy_label.grid(column=0,row=0)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Channel settings

frame_channel_registers = Frame(tab_Digitizer)
frame_channel_registers.grid(column=0,row=4)

#Channel settings - general

frame_general_channel_registers = Frame(frame_channel_registers)
frame_general_channel_registers.grid(column=0,row=2,padx=25,sticky=W)

#Channel settings - PSD

frame_PSD_channel_registers = Frame(frame_channel_registers)
frame_PSD_channel_registers.grid(column=0,row=4,sticky=W)

#Charge sensitivity
def charge_sensitivity_selection(event):
     print ("~!@#$%^&*()_+")
     #print ("Charge sensitivity       :",var_charge_sensitivity.get() )
     pass

lbl_charge_sensitivity = Label(frame_PSD_channel_registers,text="Charge sensitivity")
lbl_charge_sensitivity.grid(column=0,row=3,sticky=W)


var_charge_sensitivity = StringVar(frame_PSD_channel_registers)
charge_sensitivity     = OptionMenu(frame_PSD_channel_registers,var_charge_sensitivity,'',command=charge_sensitivity_selection)
charge_sensitivity.grid(column=1,sticky=W)


#ADC range
def update_options(*args):
    adc_range=opt_ADC_range[var_ADC_range.get()]
    var_charge_sensitivity.set(adc_range[0])
    
    menu = charge_sensitivity['menu']
    menu.delete(0,'end')
    
    for adc in adc_range:
         menu.add_command(label=adc,command=lambda sens=adc: var_charge_sensitivity.set(sens) )
         
def ADC_range_selection(event):
    print ("ADC range                 :",var_ADC_range.get() )
    pass
    
lbl_ADC_range = Label(frame_general_channel_registers,text="ADC range")
lbl_ADC_range.grid(column=0,row=1,sticky=W)

opt_ADC_range = {'0.5':['1.25','5','20','80','320','1280'],'2':['5','1280','5120']}
var_ADC_range = StringVar(frame_general_channel_registers)
var_ADC_range.trace('w',update_options)
ADC_range     = OptionMenu(frame_general_channel_registers,var_ADC_range,*opt_ADC_range.keys(),command = ADC_range_selection)
var_ADC_range.set('2')
ADC_range.grid(column=1,sticky=W)

#This keeps the window open - has to be at the end
window.mainloop()

解决方法

如果注释掉 var_ADC_range.trace('w',update_options) 行,会发生以下情况:

  • “充电灵敏度”菜单为“空”,这意味着它只有一个空条目
  • 如果您选择此条目,则会调用 charge_sensitivity_selection 函数
  • -> 您会看到打印的 ~!@#$%^&*()_+

这意味着 update_options 函数会覆盖选择“电荷灵敏度”菜单中的条目时将调用的命令。这发生在行中:

menu.add_command(label=adc,command=lambda sens=adc: var_charge_sensitivity.set(sens) )

可以尝试用这样的函数对象替换上面一行中的 lambda 表达式:

...
charge_sensitivity.grid(column=1,row=3,sticky=W)  # <- your code

class run_on_charge_sens_selection(object):         # <- the function object

    def __init__(self,sens):
        self.sens = sens

    def __call__(self):
        # this function is called on menu selection
        var_charge_sensitivity.set(self.sens)
        charge_sensitivity_selection(self.sens)


#ADC range                                          # <- again your code
def update_options(*args):
    adc_range=opt_ADC_range[var_ADC_range.get()]
    var_charge_sensitivity.set(adc_range[0])
      
    menu = charge_sensitivity['menu']
    menu.delete(0,'end')
      
    for adc in adc_range:                           # and now we use the function object
                                                    # instead of the lambda expression
         menu.add_command(label=adc,command=run_on_charge_sens_selection(adc))
...

我用函数对象传递了sens参数,调用函数的时候好像没有event

我对 tkinter 不是很深入,而且我从未使用过 trace,所以很可能有更简单的解决方案。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...