По умолчанию и выберите первый элемент в списке Tkinter

Я хочу автоматически выбрать первый элемент в списке. Под выбором первого элемента я не подразумеваю простое использование первого элемента по умолчанию или настройку фокуса на нем. Я уже добился этого, выполнив self.listbox.select_set(0). Я хочу, чтобы элемент по умолчанию также был выбран. Другими словами, когда я запускаю свой код ниже, я хочу, чтобы print(value) напечатало значение выбора по умолчанию. Если в меню параметров выбрана Азия, Япония должна автоматически печатать на консоли. Если Африка, то Нигерия должна печатать, а Германия для Европы.

Любое предложение о том, как я могу этого добиться? Спасибо.

from tkinter import *
from tkinter import ttk
import tkinter.messagebox

class App:
    def __init__(self):
        self.master = Tk()
        self.di = {'Asia': ['Japan', 'China', 'Malaysia', 'India', 'Korea',
                            'Vietnam', 'Laos', 'Thailand', 'Singapore',
                            'Indonesia', 'Taiwan'],
                     'Europe': ['Germany', 'France', 'Switzerland'],
                     'Africa': ['Nigeria', 'Kenya', 'Ethiopia', 'Ghana',
                                'Congo', 'Senegal', 'Guinea', 'Mali', 'Cameroun',
                                'Benin', 'Tanzania', 'South Africa', 'Zimbabwe']}
        self.variable_a = StringVar()
        self.frame_optionmenu = ttk.Frame(self.master)
        self.frame_optionmenu.pack()
        options = sorted(self.di.keys())
        self.optionmenu = ttk.OptionMenu(self.frame_optionmenu, self.variable_a, options[0], *options)

        self.variable_a.set('Asia')
        self.optionmenu.pack()
        self.btn = ttk.Button(self.master, text="Submit", width=8, command=self.submit)
        self.btn.pack()

        self.frame_listbox = ttk.Frame(self.master)

        self.frame_listbox.pack(side=RIGHT, fill=Y)
        self.scrollbar = Scrollbar(self.frame_listbox )
        self.scrollbar.pack(side=RIGHT, fill=Y)
        self.listbox = Listbox(self.frame_listbox, selectmode=SINGLE, yscrollcommand=self.scrollbar.set)
        self.variable_a.trace('w', self.updateoptions)

        self.scrollbar.config(command=self.listbox.yview)
        self.listbox.pack()

        #Populate listbox
        for each in self.di[self.variable_a.get()]:
            self.listbox.insert(END, each)
            self.listbox.select_set(0) #This only sets focus on the first item.
        self.listbox.bind("<<ListboxSelect>>", self.OnSelect)

        self.master.mainloop()

    def updateoptions(self, *args):
        #countries = self.di[self.variable_a.get()]
        self.listbox.delete(0, 'end')
        for each in self.di[self.variable_a.get()]:
            self.listbox.insert(END, each)
            self.listbox.select_set(0) #This only sets focus on the first item.
        self.listbox.pack()

    def submit(self, *args):
        var = self.variable_a.get()
        if messagebox.askokcancel("Selection", "Confirm selection: " + var):
            print(var)

    def OnSelect(self, event):
        widget = event.widget
        value = widget.get(widget.curselection()[0])
        print(value)

App()

Запуск Python 3.4.1


person sedeh    schedule 20.08.2014    source источник


Ответы (2)


Самое простое решение — генерировать событие <<ListboxSelect>> одновременно с изменением выбора:

def updateoptions(self, *args):
    ...
    self.listbox.select_set(0) #This only sets focus on the first item.
    self.listbox.event_generate("<<ListboxSelect>>")
    ...
person Bryan Oakley    schedule 22.08.2014
comment
Идеально! Вы заставляете эти вещи казаться обманчиво легкими. - person sedeh; 22.08.2014
comment
Просто и эффективно... Спасибо. - person Fejs; 16.12.2016

# add before .mainloop()
self.listbox.selection_set( first = 0 )

EDIT#1 2014-08-21 13:50 [UTC+0000]

Tkinter.Listbox()-es имеют довольно сложное поведение MVC-Model-Part. Таким образом, его часть-контроллер .methods() немного сложнее в обращении.

Параметр Listbox() по умолчанию select-mode позволяет выбрать только один элемент, но аргумент select-mode поддерживает четыре параметра: SINGLE, BROWSE, MULTIPLE и EXTENDED (по умолчанию BROWSE). Из них первые два являются режимами одиночного выбора, а последние два позволяют выбирать несколько элементов.

Эти режимы различаются тонкими способами.

Например, BROWSE похож на SINGLE, но он также позволяет перетаскивать выделение.

Щелчок по элементу в режиме MULTIPLE меняет его состояние, не затрагивая другие выбранные элементы.

А режим EXTENDED допускает множественный выбор и работает как графический интерфейс проводника Windows: вы выбираете один элемент с помощью простого click, несколько элементов с комбинацией Ctrl-click и диапазоны элементов с Shift -click-с.

Множественный выбор может быть запрограммирован с помощью кода такого типа:

listbox = Listbox( aWindow, bg = 'white', font = ( 'courier', fontsz ) )
listbox.config( selectmode = EXTENDED )                         # see above
listbox.bind( '<Double-1>', ( lambda event: onDoubleClick() ) ) # a lambda-wrapped CallBackHANDLER()
# onDoubleClick: get messages selected in listbox               # not listed here
selections = listbox.curselection()                             # tuple of digit-string(s), aTupleOfSTRINGs, where digit-string(s) range from { 0, 1, .., N-1 }
selections = [ int( x ) + 1 for x in selections ]               # transform string(s) to shifted int(s), make 'em { 1, 2, .., N }

Если включен множественный выбор, метод .curselection() возвращает список строк цифр, указывающих относительные номера выбранных элементов, или возвращает пустой кортеж, если ни один из них не выбран.

Остерегайтесь, что этот метод всегда возвращает кортеж строк цифр, даже в режиме одиночного выбора.

Таким образом, симметрично метод Listbox().selection_set() должен быть многофункциональным, чтобы иметь возможность настроить все возможные состояния для значения ‹aSelectionSET>.

КЭД выше в начальном посте.

person user3666197    schedule 21.08.2014
comment
Спасибо за ваш ответ. При публикации кода также постарайтесь объяснить его, чтобы ОП мог понять данный код. - person Eduard Luca; 21.08.2014
comment
Какое отношение все комментарии к режимам имеют к выбору первого пункта? Этот ответ кажется слишком сложным для такой простой проблемы. - person Bryan Oakley; 21.08.2014
comment
@ user3666197 Спасибо за объяснение. В данный момент я не хочу использовать режим MULTIPLE. Во всяком случае, я добавил self.listbox.selection_set( first = 0 ) перед self.master.mainloop(), как вы предложили, но поведение не изменилось. Вы можете скопировать измененный код с сайта ideone.com/8VzU3p и протестировать его. Любые дальнейшие мысли? Спасибо. - person sedeh; 21.08.2014
comment
@BryanOakley Есть идеи, как я могу это решить? Спасибо. - person sedeh; 21.08.2014