I can't seem to get tkinter's built in widget virtual events to work.
It seems that command =
works, however I cannot use it because it doesn't return the tkinter event parameters to the callback function. I need the tkinter event parameter to be returned to the callback so I can get the calling widget's instance.
Am I doing something wrong for '<<ComboboxSelected>>'
, '<<Increment>>'
, '<<Decrement>>'
to do nothing?
I need the callback to be called and the event to be passed so that I can get the widget instance. I also cannot use lambda (as all of the similar examples suggest) to return the index number as I need to access the widget directly to get its current row number as I intend on deleting rows. If I use lambda it makes a mess of things as the index is fixed. So if I click on row 5 and delete row 5, row 6 becomes row 5 and if I want to delete it deletes row 6 instead.
I was also hoping that there was a virtual event for the button to perform the same effect as command. So if you tab to the button hit spacebar or click on it, but I can't find any such virtual event. Is there something like this?
from tkinter import *
root = Tk()
omuVars = []
omuList = ['Bahamas','Canada', 'Cuba','United States']
omu = []
spb = []
cmd = []
def callSelectChanged(event):
caller = event.widget
rowNumber = caller.grid_info()['row']
print(rowNumber)
def callIncrement(event):
caller = event.widget
rowNumber = caller.grid_info()['row']
print(rowNumber)
def callDecrement(event):
caller = event.widget
rowNumber = caller.grid_info()['row']
print(rowNumber)
def callButton(event):
caller = event.widget
rowNumber = caller.grid_info()['row']
print(rowNumber)
for i in range(0,10):
omuVars.append(StringVar())
omu.append(OptionMenu(root,
omuVars[i],
*omuList))
omu[i].bind('<<ComboboxSelected>>', callSelectChanged)
omu[i].config(font='Terminal 18 bold', anchor=W, fg='blue', relief=FLAT, bg='SystemWindow', borderwidth=0, width=15)
omu[i].grid(row=i, column=0)
spb.append(Spinbox(root,
from_=00,
to=23,
wrap=True,
width=2,
font='Terminal 18 bold',
fg='blue',
format=".0f",
relief=FLAT))
spb[i].bind('<<Increment>>', callIncrement)
spb[i].bind('<<Decrement>>', callDecrement)
spb[i].grid(row=i, column=1)
cmd.append(Button(root,
text='\u2718',
font='Terminal 16 bold',
fg='blue',
width=2))
cmd[i].bind('<Button-1>',callButton)
cmd[i].bind('<space>', callButton)
cmd[i].grid(row=i, column=2)
root.mainloop()
CodePudding user response:
The tkinter OptionMenu
widget does not generate a <<ComboboxSelected>>
event, and the tkinter Spinbox
widget does not generate an <<Increment>>
or <<Decrement>>
event. Binding those events on those widgets will have no effect.
For those events and bindings to work, you need to use the Combobox
and Spinbox
widgets from ttk.
CodePudding user response:
According to the documentation for event, <<Increment>>
and <<Decrement>>
are not predefined virtual events.
Also, OptionMenu
does not support <<ComboboxSelected>>
.
That requires the ttk.Combobox
widget.
W.r.t. the spinbox, tkinter
merely invokes command
when it has changed. This call does not contain an event
, though.
My workaround to submit different parameters to the same callback this is functools.partial
.
The command
callback for OptionMenu
does not receive an event, but the selected string. See modified code below.
Modified code. I've also used the tk namespace instead of import *
.
from functools import partial
import tkinter as tk
root = tk.Tk()
omuVars = []
omuList = ["Bahamas", "Canada", "Cuba", "United States"]
omu = []
spb = []
cmd = []
def callSelectChanged(selection):
print(f"callSelectChanged: {selection}")
def callSpinChanged(index):
print(f"callSpinChanged: {index}")
def callButton(event):
caller = event.widget
rowNumber = caller.grid_info()["row"]
print(f"callButton: {rowNumber}")
for i in range(0, 10):
omuVars.append(tk.StringVar())
omu.append(tk.OptionMenu(root, omuVars[i], *omuList, command=callSelectChanged))
omu[i].config(
fg="blue",
font="Terminal 18 bold",
relief="flat",
borderwidth=0,
width=15,
)
omu[i].grid(row=i, column=0)
spb.append(
tk.Spinbox(
root,
from_=0,
to=23,
wrap=True,
width=2,
font="Terminal 18 bold",
fg="blue",
format=".0f",
relief=tk.FLAT,
command=partial(callSpinChanged, index=i),
)
)
spb[i].grid(row=i, column=1)
cmd.append(
tk.Button(root, text="\u2718", font="Terminal 16 bold", fg="blue", width=2)
)
cmd[i].bind("<Button-1>", callButton)
cmd[i].bind("<space>", callButton)
cmd[i].grid(row=i, column=2)
root.mainloop()