Ваш вопрос (и решение) мало похож на этот .Таким образом, советы и идеи оттуда применимы и к вашей проблеме.
Прежде всего, такая функциональность, как вы описали, уже есть: когда вы находитесь на b1-движении на границах списка - списокавтоматически прокручиваетсяНо хорошо, давайте реализуем что-то самостоятельно.
Для начала нам нужно понять, что комбинированный список - это не что иное, как комбинация виджетов входа и списка, и нам нужна часть, которая является списком (всплывающим списком).окно).К счастью, есть нативная функция , которая позволяет вам вырвать ее:
popdown = combobox.tk.eval('ttk::combobox::PopdownWindow %s' % combobox)
После этого вы можете свободно связывать что-то с этим виджетом, когда отображается наш комбинированный список:
class CustomBox(ttk.Combobox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.bind('<Map>', self._handle_popdown_bind_on_initialisation)
def _handle_popdown_bind_on_initialisation(self, *args):
popdown = self.tk.eval('ttk::combobox::PopdownWindow %s' % self)
self._bind(('bind', '%s.f.l' % popdown), '<B1-Motion>', <callback_function>, None)
Чтобы уточнить немного: popdown
- это окно верхнего уровня, которое буквально выскакивает при щелчке по списку, f
контейнер-рамка для списка и l
- фактический список., который содержит ваши ценности.Выглядит просто.
Итак, давайте что-нибудь кодируем:
import tkinter as tk
import tkinter.ttk as ttk
import random
import string
class CustomBox(ttk.Combobox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# schedule bind to handle popdown
self.bind('<Map>', self._handle_popdown_bind_on_initialisation)
def _handle_popdown_bind_on_initialisation(self, *args):
# once combobox is drawn bind callback function
popdown = self.tk.eval('ttk::combobox::PopdownWindow %s' % self)
self._bind(('bind', '%s.f.l' % popdown), '<B1-Motion>', drag, None)
def insert_something_to_combobox(box, count=30):
# just to insert some random stuff
box['values'] = [gen_key() for _ in range(count)]
def gen_key(size=6, chars=string.ascii_uppercase + string.digits):
# just to generate some random stuff
return ''.join(random.choice(chars) for _ in range(size))
def drag(event):
# test-event for B1-Motion over popdown
# get index of the nearest item
nearest_item = root.tk.call(event.widget, 'nearest', event.y)
# get actual size of listbox
actual_size = root.tk.call(event.widget, 'size')
# get current boundary positions for listbox
current_yview = root.tk.call(event.widget, 'yview')
# get current boundary items
current_items = [int(fraction * actual_size) for fraction in current_yview]
# get decider-item for scrolling
decider_item = sum(current_items) // 2
# debug-configure current item
mouse_over_label.configure(text='B1 over item: %s' % root.tk.call(event.widget, 'get', nearest_item))
if nearest_item < decider_item:
# scroll-up
root.tk.call(event.widget, 'see', current_items[0] - 1)
elif nearest_item > decider_item:
# scroll-down
root.tk.call(event.widget, 'see', current_items[1] + 1)
root = tk.Tk()
mouse_over_label = tk.Label()
mouse_over_label.pack()
combo_box = CustomBox()
combo_box.pack()
insert_something_to_combobox(combo_box)
root.mainloop()
Идея проста: получить решающий элемент, который находится на полпути через список, и, в зависимости от положениятекущий элемент, решите прокрутить вверх или вниз.