Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
208 views
in Technique[技术] by (71.8m points)

python - Can you call a function from tk.OptionMenu's command parameter without passing an argument

I want to check if the user has changed any values in tkinter widgets and then prompt to save those values or lose changes.

A lot of applications have 3 buttons at the bottom right of their settings frame OK, Cancel, and Apply where Apply is disabled until a change has been made. I am imitating this feature in my program.

When I use tk.OptionMenu(command=function), by default it sends the current user selection to the function, however I do not need to know the current selection because regardless of what it is, I want to prompt the user to save settings.

Running the program would result in the following error:

TypeError: function() takes 0 positional arguments but 1 was given

A simple workaround I thought of would be to give an arbitrary parameter to function() like so:

def function(param=None):
    value_change.status = True

See Example Code for value_change.status usage.

However, PyCharm points out that param is not used and marks it as a weak warning. I don't have any use for the passed value so I can't do much with param except ignore it and the PyCharm warning as well. There's technically nothing wrong here but I like seeing that green checkmark at the top right of my screen so I came up with another workaround:

def function(param=None):
    value_change.status = True if param else False

Both param=None and if param else False are redundant since they're only placeholders to make the code run smoothly and not throw any warnings.

Another problem arises when I want to use function() for other widget commands which do not pass arguments such as tk.Checkbutton(command=function) and I have to change my code to the following lines which makes the code appear even more redundant than before.

def function(param=True):
    value_change.status = True if param else False

Is there a way to not pass an argument through tk.OptionMenu(command=function)?

Example Code

import time
import tkinter as tk
from threading import Thread

def value_change():
    value_change.count = 0
    value_change.status = False

    print('Has the user changed settings in the past 3 seconds?')

    while value_change.status != 'exit':
        if value_change.status:
            value_change.count += 1
            
            # Reset count if no change after 3 seconds
            if value_change.count > 3:
                value_change.count = 0
                value_change.status = False

        print(value_change.status)
        time.sleep(1)

def function(param=True):
    value_change.status = True if param else False
    value_change.count = 0


gui = tk.Tk()
gui.geometry('100x100')

"""Setup OptionMenu"""
menu_options = ['var1', 'var2', 'var3']

menu_string = tk.StringVar()
menu_string.set(menu_options[0])

option_menu = tk.OptionMenu(gui, menu_string, *menu_options, command=function)
option_menu.pack()

"""Setup CheckButton"""
check_int = tk.IntVar()

check = tk.Checkbutton(gui, variable=check_int, command=function)
check.pack()

"""Turn On Thread and Run Program"""
Thread(target=value_change).start()
gui.mainloop()

"""Signal Threaded Function to Exit"""
value_change.status = 'exit'

The above example is a minimal reproduction, I did not include the OK Cancel Apply buttons and their functions as they are not necessary and would only make the code lengthy.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can use lambda:

option_menu = tk.OptionMenu(gui, menu_string, *menu_options, command=lambda v: function())

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...