Home > database >  Tkinter's Widget's built in Virtual Events do not bind
Tkinter's Widget's built in Virtual Events do not bind

Time:07-20

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()
  • Related