简体   繁体   English

Tkinter 如何将 B1-Motion 绑定到 Combobox

[英]Tkinter how to bind B1-Motion to Combobox

so I have a combobox in an app I am putting on a tablet, I'm wanting to make it so that I can drag on the combobox that it will scroll down it.所以我在平板电脑上的应用程序中有一个组合框,我想制作它以便我可以拖动组合框向下滚动它。

So far I have this function:到目前为止,我有这个功能:

def tablet_drag_y(event):
    global last_y
    if event.y_root-last_y>20 or event.y_root-last_y<-20:
        last_y=event.y_root
        event.widget.tag_remove(Tk.SEL, "1.0", Tk.END)
        return "break"
    event.widget.yview(Tk.SCROLL,-1*(event.y_root-last_y), "units")
    last_y=event.y_root
    event.widget.tag_remove(Tk.SEL, "1.0", Tk.END)
    return "break"

This works on Text widgets (the majority of widgets I need this for), but I only know how to bind the combo box with this:这适用于 Text 小部件(我需要它的大多数小部件),但我只知道如何用这个绑定组合框:

book_drop_down.bind("<<ComboboxSelected>>", tablet_drag_y)

Idk how to bind any sort of motion to the combobox, how would I go about doing this?我不知道如何将任何类型的动作绑定到组合框,我将如何去做?

Your question (and solution) is little similar to this one .您的问题(和解决方案)与问题有点相似。 Thus, tips and ideas from there apply to your problem as well.因此,那里的提示和想法也适用于您的问题。

First of all, such functionality like you described is already there: when you are on b1-movement at the borders of the list - the list is automatically scrolled.首先,像您描述的这样的功能已经存在:当您在列表边界进行 b1 移动时 - 列表会自动滚动。 But ok, let's implement something on our own.但是好吧,让我们自己实现一些东西。

To start with we need to comprehend that combobox is nothing, but a combo of entry and listbox widgets, and we need a part, that is a listbox (a popdown window).首先,我们需要理解组合框不是什么,而是条目和列表框小部件的组合,我们需要一个部分,即列表框(弹出窗口)。 Fortunately, there is a native function that allows you to tear it out:幸运的是,有一个原生函数可以让你把它撕掉:

popdown = combobox.tk.eval('ttk::combobox::PopdownWindow %s' % combobox)

After that your a free to bind something to that widget, when our combobox is mapped:之后,当我们的组合框被映射时,您可以自由地将某些内容绑定到该小部件:

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)

To elaborate a little more: popdown is the toplevel window, that literally pops down on your click on the combobox, f a frame-container for listbox, and l - the actual listbox, which contains your values.再详细说明一点: popdown是顶级窗口,它在您单击组合框时从字面上弹出, f是列表框的框架容器,而l - 实际列表框,其中包含您的值。 Looks simple.看起来很简单。

So let's code something:所以让我们编码一些东西:

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

The idea is simple: get a decider item, that is half-way-thru listbox, and, depending on the position of the current element, decide to scroll up or down.想法很简单:获取一个决策项,即中间列表框,然后根据当前元素的位置决定向上或向下滚动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM