如何在菜单中插入滚动条? [英] How to insert a scrollbar to a menu?

查看:32
本文介绍了如何在菜单中插入滚动条?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 tkinter 的菜单小部件中添加另一个小部件,在本例中为缩放小部件.现在我看到的唯一解决方案是创建一个新命令并打开一个带有缩放小部件的新窗口或在其他地方创建缩放小部件.两者对我来说似乎都不太吸引人.

I want to add another widget, in this case a scale widget, to a menu widget in tkinter. Right now the only solutions I see are creating a new command and open a new window with the scale widget or creating the scale widget elsewhere. Both don't seem too appealing to me.

欢迎任何关于如何存档的想法:)

Any ideas how to archive this are welcome :)

推荐答案

你不能给它添加滚动条,但是 我已经编码了一些东西类似这样.这是一种hacky方式,可能很难理解,但我可以尝试解释一下.

You cant add a scrollbar to it, but I have coded something similar to this. Its a hacky way and maybe its hard to understand but I can try to explain.

注意正如布莱恩在链接的线程中提到的那样,这似乎是一个仅限 Windows 的解决方案.

Note as Bryan mentioned in the linked Thread, this seems to be a a Windows only solution.

import tkinter as tk


def my_first_function():
    print('first')

def my_second_function():
    print('second')

def check_for_scroll(event):
    check = root.call(event.widget, "index","active")
    if check == 0: #index of button up
        scroll_up()
        root.after(100,lambda e=event:check_for_scroll(e)) # check again after 100ms
    if check == file_menu.index('end'):
        scroll_down()
        root.after(100,lambda e=event:check_for_scroll(e))

def scroll_up():
    index_of_first_command=1
    index_of_last_command=1
    label_of_last_command = file_menu.entrycget(index_of_first_command, 'label')
    try:
        for i, k in enumerate(dict_of_commands):
            if k == label_of_last_command:
                previous_command_label = list(dict_of_commands)[i-1]
                previous_command = list(dict_of_commands.values())[i-1]
                if i != 0: #avoid to get the last as first
                    file_menu.delete(index_of_first_command) #first before pull down button
                    file_menu.insert_command(index_of_first_command,
                                             label=previous_command_label,
                                             command=previous_command)
    except Exception as e:
        print(e)

def scroll_down():
    index_of_first_command=1
    index_of_last_command=1
    label_of_last_command = file_menu.entrycget(index_of_last_command, 'label')
    try:
        for i, k in enumerate(dict_of_commands):
            if k == label_of_last_command:
                next_command_label = list(dict_of_commands)[i+1]
                next_command = list(dict_of_commands.values())[i+1]

                file_menu.delete(index_of_first_command) #first after pull up button
                file_menu.insert_command(index_of_last_command,
                                         label=next_command_label,
                                         command=next_command)
    except:
        pass

space = '         '
dict_of_commands = {'first' : my_first_function,
                    'second': my_second_function}

root = tk.Tk()
menubar = tk.Menu(root)
root.config(menu=menubar)

file_menu = tk.Menu(menubar,tearoff=0)
menubar.add_cascade(label='File', menu=file_menu)
file_menu.bind('<<MenuSelect>>', check_for_scroll)

file_menu.add_command(label=space+u'\u25B2'+space, font=["Arial", 8,'bold'])

file_menu.add_command(label='first', command=my_first_function)

file_menu.add_command(label=space+u'\u25BC'+space, font=["Arial", 8,'bold'])


root.mainloop()

所以这段代码像往常一样创建了你的窗口和一个菜单栏:

So this code creates your window and a menubar on it as usal:

root = tk.Tk()
menubar = tk.Menu(root)
root.config(menu=menubar)
file_menu = tk.Menu(menubar,tearoff=0)
menubar.add_cascade(label='File', menu=file_menu)
file_menu.add_command(label=space+u'\u25B2'+space, font=["Arial", 8,'bold'])
file_menu.add_command(label='first', command=my_first_function)
file_menu.add_command(label=space+u'\u25BC'+space, font=["Arial", 8,'bold'])
root.mainloop()

对您很重要,这里是这条线吗:

Important for you, is this line here:

file_menu.bind('<<MenuSelect>>', check_for_scroll)

这一行绑定了 MenuSelect 事件,如果您的光标悬停在菜单命令上,它就会发生/触发.对于这个事件,我绑定了一个名为 check_for_scroll 的函数,它看起来像这样:

This line binds the event MenuSelect and it happens/triggers if your cursor hovers over a command of your menu. To this event I have bound a function called check_for_scroll and it looks like this:

def check_for_scroll(event):
    check = root.call(event.widget, "index","active")
    if check == 0: #index of button up
        scroll_up()
        root.after(100,lambda e=event:check_for_scroll(e)) # check again after 100ms
    if check == file_menu.index('end'):
        scroll_down()
        root.after(100,lambda e=event:check_for_scroll(e))

下面的行检查触发事件的命令的索引.用这个,我们用箭头检查我们感兴趣的按钮是第一个还是最后一个.

The line below checks for the index of the command that has triggered the event. With this we check if its button of our interest like the first or last, with the arrows.

check = root.call(event.widget, "index","active")

如果它是第一个,例如这里的代码被执行:

if its the first for example this code here is executed:

if check == 0: #index of button up
        scroll_up()
        root.after(100,lambda e=event:check_for_scroll(e)) # check again after 100ms

它调用/触发函数 scroll_up 并使用 then tkinter 的 after 方法重新触发自身,就像一个循环.scroll_up 函数的构建就像 scroll_down 的相反方向.让我们仔细看看:

it calls/triggers the function scroll_up and uses then the after method of tkinter to retrigger itself, like a loop. The scroll_up function is build like the scroll_down just in the opposite direction. Lets have a closer look:

def scroll_up():
    index_of_first_command=1
    index_of_last_command=1
    label_of_last_command = file_menu.entrycget(index_of_first_command, 'label')
    try:
        for i, k in enumerate(dict_of_commands):
            if k == label_of_last_command:
                previous_command_label = list(dict_of_commands)[i-1]
                previous_command = list(dict_of_commands.values())[i-1]
                if i != 0: #avoid to get the last as first
                    file_menu.delete(index_of_first_command) #first before pull down button
                    file_menu.insert_command(index_of_first_command,
                                             label=previous_command_label,
                                             command=previous_command)
    except Exception as e:
        print(e)

在这个函数中,我们需要知道命令的第一个和最后一个位置,因为我们想删除一个并在该位置/索引上插入另一个.为了实现这一点,我创建了一个字典,其中包含标签和 tkinter 命令项的功能,如下所示.(这可以动态创建,但让我们将其留作另一个问题)

In this function we need to know the first and the last position of commands, because we want to delete one and insert another on that position/index. To achieve this I had created a dictionary that contains the label and the the function of the command item of tkinter like below. (This could be created dynamically, but lets keep it for another question)

dict_of_commands = {'first' : my_first_function,
                    'second': my_second_function}

所以我们在我们的函数中遍历这个枚举/索引字典,并检查 k/key/labelem> 是我们感兴趣的项目.如果为真,我们通过列出字典键来获取 previous_command 并通过这一行获取之前提取的键:

So we iterate over this enumerated/indexed dictionary in our function and check if the k/key/label is our item of interest. If true, we get the previous_command by listing the dictionary keys and get the extract the key before by this line:

next_command_label = list(dict_of_commands)[i+1]

类似于字典的值有这一行:

similar to the value of the dictionary with this line:

next_command = list(dict_of_commands.values())[i+1]

毕竟我们可以删除一个并在我们喜欢的地方插入一个:

After all we can delete one and insert one where we like to with this:

file_menu.delete(index_of_first_command) #first after pull up button
file_menu.insert_command(index_of_last_command,
                         label=next_command_label,
                         command=next_command)


我知道这段代码可以改进很多,但它似乎很难理解.所以请不要评判我.


I know that this code can improved by a lot but it seems hard enough to understand as it is. So dont judge me please.

我希望这能解决您的问题,即使它不是您想要的方式.但是这段代码避免了您几乎无法编写自己的菜单栏.

I hope this solves your question, even if it isnt in the way you wanted to. But this code avoids you from hardly code a own menubar.

如果我的回答还有问题,请告诉我.

If there are questions left on my answer, let me know.

这篇关于如何在菜单中插入滚动条?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆