Home > Software engineering >  Why am I not getting the selected value from the tkinter listbox?
Why am I not getting the selected value from the tkinter listbox?

Time:06-26

`from tkinter import *
pencere = Tk()
başlık = pencere.title("deneme2")
etiket = Label(text="")
etiket.pack()

def göster(event):
    etiket["text"] = "%s seçildi."%liste.get(ACTIVE)
    etiket.pack()
liste = Listbox()
liste.insert(1, "İstanbul")
liste.insert(2, "Ankara")
liste.insert(3, "İzmir")
liste.insert(4, "İzmit")
liste.insert(5, "Antalya")
liste.insert(6, "Bursa")
liste.pack()

liste.bind("<Button-1>",göster)
mainloop()`

here is the problem! I follow an online course and couldn't figure out why it would show the wrong text. I choose İzmir it says İstanbul, I choose Ankara it says İstanbul, I choose İstanbul it says Ankara, other ones are like this too.

CodePudding user response:

Your code is working. Just double click it. You don't need etiket.pack() inside the göster function. I had to rearrange our code to make it more readable. Just double click it. I also added widget for Label and Listbox.

from tkinter import *


pencere = Tk()
başlık = pencere.title("deneme2")
 

def göster(event):
    etiket.config(text = "%s seçildi."%liste.get(ACTIVE))

etiket = Label(pencere)
etiket.pack()

liste = Listbox(pencere)
liste.insert(0, "İstanbul")
liste.insert(1, "Ankara")
liste.insert(2, "İzmir")
liste.insert(3, "İzmit")
liste.insert(4, "Antalya")
liste.insert(5, "Bursa")
 
liste.pack()
etiket.pack()

liste.bind("<Button-1>",göster)
 
mainloop()

CodePudding user response:

Let's first focus on the question

Why does the listbox not respond with the just by the click selected item, but with the last clicked one?

To change the in the listbox selected item you have to perform a click on that item. In the event-driven mechanism of tkinter the listbox will then be 'informed' about the mouse click and 'react' to it changing its value.

When you capture the mouse click by binding it to your function the function will be notified about the mouseclick before the listbox receive it. The listbox does at the time of the click not yet 'know' that it will become clicked next as the click is first processed by your function and only after passed to the listbox.

So the 'poor' listbox asked in the function about its current selected value responds with the last one clicked and from listbox perspective also current value.

On the very first click when no item is yet selected if asked using ACTIVE the listbox responds with its first value and if asked with listbox.curselection() it returns no value at all.

Checking the state of the listbox with listbox.get(ACTIVE) behaves different from checking its state with listbox.get(listbox.curselection()) where the latter responds as intuitively expected.

Please be aware that the explanation above is simplified and things are often not straightforward in event-driven programming environment, but simple explanation helps to understand the importance of doing things the right way to minimize the chances that sometimes something will go wrong.

The code you provided has two issues at the same time and you have to resolve both to get the by you expected result.

First issue is that you bind <Button-1> (i.e. the mouse click) instead of capturing the <<ListboxSelect>> event and the second issue is, that you should ask the listbox about its current selected item using listbox.get(listbox.curselection()) instead of listbox.get(ACTIVE).

The code below demonstrates all four cases showing that in only one case things work out as expected. Let's summarize all of what was said above in one simple statement:

You should use <<ListboxSelect>> event for the binding and listbox.get(listbox.curselection()) for the value of the selected item in the listbox.

from tkinter import *
list_CASE = ['']
list_CASE.append("<Button-1>(Mouse Click), liste.get(ACTIVE)")
list_CASE.append("<Button-1>(Mouse Click), liste.get(liste.curselection())")
list_CASE.append("<<ListboxSelect>>, liste.get(ACTIVE)")
list_CASE.append("<<ListboxSelect>>, liste.get(liste.curselection())")

def göster(event):
    # global indx, etiket, liste
    if indx in [1,3]: 
        etiket["text"] = "%s seçildi."%liste.get(ACTIVE)
    if indx in [2,4]: 
        etiket["text"] = "%s seçildi."%liste.get(liste.curselection())

for indx, CASE in enumerate(list_CASE): 
    if indx == 0 : continue
    pencere = Tk()
    pencere.geometry('700x400 300 300')
    pencere.title(CASE)
    # başlık = pencere.title("deneme2")
    etiket = Label(text="", font=(16)); etiket.pack()

    liste = Listbox(selectmode='browse', font=(16))
    liste.insert(1, "İstanbul")
    liste.insert(2, "Ankara")
    liste.insert(3, "İzmir")
    liste.insert(4, "İzmit")
    liste.insert(5, "Antalya")
    liste.insert(6, "Bursa")
    liste.pack()
    
    if indx in [1,2]: liste.bind("<Button-1>"       , göster)
    if indx in [3,4]: liste.bind("<<ListboxSelect>>", göster) 

    mainloop()
  • Related