Получить выбранный элемент в списке и вызвать другую функцию, сохраняющую выбранный элемент - PullRequest
5 голосов
/ 01 октября 2011

У меня есть холст, который вызывает createCategoryMeny(x) при нажатии.

Эта функция просто создает окно Toplevel(),

def createCategoryMenu(tableNumber):

    ##Not interesting below:
    categoryMenu = Toplevel()
    categoryMenu.title("Mesa numero: " + str(tableNumber))
    categoryMenu.geometry("400x400+100+100")

    categoryMenu.focus()
    categoryMenu.grab_set()

    Label(categoryMenu, text="Elegir categoria \n Mesa numero: " + str(tableNumber)).pack()


    ## RELEVANT CODE BELOW:
    listbox = Listbox(categoryMenu, width=50, height=len(info.listaCategorias))
    listbox.pack(pady=20)

    for item in info.listaCategorias:
        listbox.insert(END, item)

    listbox.selection_set(first=0)

    ##My attempt to solve it
    callback = lambda event, tag= "ThisShouldBeTheSelected!!": do(event, tag)
    listbox.bind("<Double-Button-1>", callback)

Затем функция do:

def do(event, tag):
    print tag

Это успешно печатает `" ThisShouldBeTheSelected !! "` `.

И это то, где я застрял.

Я не могу получить элемент с двойным щелчком (выбранный).

Я хочу передать его как tag=.

Я пытался:

listbox.curselection()

, который всегда печатает ('0',)

ЕслиЯ удаляю listbox.selection_set(first=0), я получаю только это: ()

Итак, вопросы:

  • Как я могу получить выбранный предмет (дважды щелкнув)
  • (не так важно) Разумно ли передавать его другой функции, как я?

Примечание:

Я нашел this :

8,5.Почему при выборе привязки или выбора элемента списка .listbox не отображается нужный элемент, когда я делаю привязку кнопки к списку?

Лучший способ получить выбранный элемент во время события нажатия кнопки в списке -использовать следующий код:

bind .listbox {установить элемент [% W получить [% W ближайший% y]]}}

Это гарантирует, что элемент под указателем будет тем, что будет возвращенокак предметПричина, по которой может произойти сбой curselection .listbox, состоит в том, что элементы в curselection не устанавливаются до тех пор, пока не сработает привязка класса Listbox, то есть после привязки экземпляра по умолчанию.Это та же самая причина, по которой выбор может получить сбой, но он также потерпит неудачу, если вы установите для параметра -exportselection значение 0.

Я не уверен, что это полезно, я не оченьпонять, что он говорит.

Ответы [ 3 ]

15 голосов
/ 01 октября 2011

Для одного не используйте lambda. Это полезно для узкого круга проблем, и это не одна из них. Создайте правильную функцию, их гораздо проще написать и поддерживать.

Как только вы это сделаете, вы можете позвонить curselection, чтобы получить текущий выбор. Вы говорите, что пробовали это, но ваш пример кода не показывает то, что вы пробовали, поэтому я могу только предположить, что вы сделали это неправильно.

Что касается довольно необычного совета по использованию nearest ... все, что он говорит, это то, что привязки, которые вы накладываете на виджет, происходят до привязок по умолчанию для того же события. Это привязки по умолчанию, которые устанавливают выбор, поэтому, когда вы привязываетесь к одиночному нажатию кнопки , ваша привязка срабатывает до того, как выбор обновляется привязками по умолчанию. Есть много способов обойти это, лучшим из которых является , а не привязка одним щелчком мыши, а привязка <<ListboxSelect>>, которая срабатывает после изменения выбора.

Однако у вас нет этой проблемы. Поскольку вы привязываете двойной щелчок, выбор будет установлен привязкой по одному щелчку по умолчанию, и curselection вернет правильное значение. То есть, если у вас нет собственных привязок одним щелчком, которые предотвращают срабатывание привязки по умолчанию.

Вот простой пример, который распечатывает выбор, чтобы вы могли видеть, что он правильный. Запустите его из командной строки, чтобы увидеть stdout:

import Tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        lb = tk.Listbox(self)
        lb.insert("end", "one")
        lb.insert("end", "two")
        lb.insert("end", "three")
        lb.bind("<Double-Button-1>", self.OnDouble)
        lb.pack(side="top", fill="both", expand=True)

    def OnDouble(self, event):
        widget = event.widget
        selection=widget.curselection()
        value = widget.get(selection[0])
        print "selection:", selection, ": '%s'" % value

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()
0 голосов
/ 06 июня 2018

Хотя у вас есть только один список для управления, довольно хорошо использовать что-то вроде этого (Python 3):

import tkinter as tk

root = tk.Tk()
box = tk.Listbox(root)
box.insert(tk.END, 'First')
box.insert(tk.END, 'Second')
box.insert(tk.END, 'Third')
box.pack()


def onselect(event):
    w = event.widget
    idx = int(w.curselection()[0])
    value = w.get(idx)
    print(value)


box.bind('<<ListboxSelect>>', onselect)

root.mainloop()

Но когда вы добавляете другой список или \ и сталкиваетесь с ситуацией, когда список теряет свой выбор, возникает IndexError. Чтобы избежать этого и управлять различными обратными вызовами для разных списков, я предлагаю что-то вроде этого:

import tkinter as tk

root = tk.Tk()
box = tk.Listbox(root)
box.insert(tk.END, 'First')
box.insert(tk.END, 'Second')
box.insert(tk.END, 'Third')
box.pack()

box2 = tk.Listbox(root)
box2.insert(tk.END, 'First')
box2.insert(tk.END, 'Second')
box2.insert(tk.END, 'Third')
box2.pack()


def on_first_box(idx, val):
    print('First box idx: %s, value: %s' % (idx, val))


def on_second_box(idx, val):
    print('Second box idx: %s, value: %s' % (idx, val))


def onselect(event, listbox):
    w = event.widget
    try:
        idx = int(w.curselection()[0])
    except IndexError:
        return
    if listbox is box:
        return on_first_box(idx, w.get(idx))
    if listbox is box2:
        return on_second_box(idx, w.get(idx))


box.bind('<<ListboxSelect>>', lambda e: onselect(e, box))
box2.bind('<<ListboxSelect>>', lambda e: onselect(e, box2))

root.mainloop()
0 голосов
/ 22 августа 2017

Для spyder и python 3.6 этот следующий код работал.

import tkinter as tk
root = tk.Tk()
root.geometry("612x417")
root.title("change label on listbox selection")
root.resizable(0,0)
root.configure(background='lightgrey')


#Show selected currency for from in label
frmcur_text = tk.StringVar()
frmcur = tk.Label(root, textvariable=frmcur_text, font="Helvetica 10 bold", anchor='w', background='lightgrey').place(x=195,y=50)

def onselect(evt):
    # Note here that Tkinter passes an event object to onselect()

    w = evt.widget
    index = int(w.curselection()[0])
    value = w.get(index)
#    print ('You selected item %d: "%s"' % (index, value))
    frmcur_text.set(value)

#Create listboxes for xurrency selection
listbox1 = tk.Listbox(root, font="Helvetica 11 bold", height=3, width=10)
listbox2 = tk.Listbox(root, font="Helvetica 11 bold", height=3, width=10)
listbox1.place(x=300,y=50)
listbox2.place(x=300,y=125)


for i in range(20):
    i = i + 1
    listbox1.insert(1, i)
    listbox2.insert(1, i)


listbox1.bind('<<ListboxSelect>>', onselect)    

cs = listbox1.curselection()

frmcur_text.set(cs)

root.mainloop()
...