【问题标题】:How to create multiple Label in Button widget of Tkinter?如何在 Tkinter 的 Button 小部件中创建多个标签?
【发布时间】:2018-03-27 11:41:59
【问题描述】:

我想知道如何在 Tkinter 中创建具有多个标签的按钮小部件,如下图所示。 Buttons with sub-label. 如您所见,在某些按钮中有一个子标签,例如,按钮“X”有另一个小标签“A”。我试图搜索解决方案,但没有找到。

非常感谢您。

【问题讨论】:

    标签: python user-interface button tkinter widget


    【解决方案1】:

    您可以将标签放在Frame 中,并让Button 成为该框架的父级。但是,您需要有点聪明,并克服一些问题,例如:

    • 无法正确单击按钮(您只能单击边缘,因为包含标签的框架位于中间),这意味着您必须进行一些事件处理(单击框架和里面的标签需要触发与单击按钮相同的事件)
    • 将鼠标悬停在按钮本身上时颜色不同步
    • 以及其他一些小细节,例如在单击按钮时正确配置按钮的 relief(不要忘记,您可能正在单击框架或标签!)等。

    这是一个 MCVE:

    import sys
    import string
    import random
    
    try:
        import tkinter as tk
        from tkinter import ttk
    except ImportError:
        import Tkinter as tk
        import ttk
    
    CHARS = string.ascii_letters + string.digits
    
    class CustomButton(tk.Button):
        """
        CustomButton class inherits from tk.Button, which means it
        behaves just like an ordinary tk.Button widget, but it also
        has some extended functionality.
        """
    
        def __init__(self, parent, *args, **kwargs):
            super().__init__()
            self.command = kwargs.get('command')
            self.frame = tk.Frame(self)
            self.frame.pack(fill='none', expand=False, pady=(3, 0))
            self.upper_label = ttk.Label(self.frame, text=kwargs.get('upper_text'))
            self.upper_label.grid(row=0, column=0)
            self.bottom_label = ttk.Label(self.frame, text=kwargs.get('bottom_text'))
            self.bottom_label.grid(row=1, column=1)
            self.frame.pack_propagate(False)
            self.configure(width=kwargs.get('width'), height=kwargs.get('height'))
            self.pack_propagate(False)
            self.clicked = tk.BooleanVar()
            self.clicked.trace_add('write', self._button_cmd)
            self.bind('<Enter>', self._on_enter)
            self.bind('<Leave>', self._on_leave)
            self.frame.bind('<Enter>', self._on_enter)
            self.frame.bind('<Button-1>', self._on_click)
            self.upper_label.bind('<Button-1>', self._on_click)
            self.bottom_label.bind('<Button-1>', self._on_click)
    
        def _button_cmd(self, *_):
            """
            Callback helper method
            """
            if self.clicked.get() and self.command is not None:
                self.command()
    
        def _on_enter(self, _):
            """
            Callback helper method which is triggered
            when the cursor enters the widget's 'territory'
            """
            for widget in (self, self.frame, self.upper_label, self.bottom_label):
                widget.configure(background=self.cget('activebackground'))
    
        def _on_leave(self, _):
            """
            Callback helper method which is triggered
            when the cursor leaves the widget's 'territory'
            """
            for widget in (self, self.frame, self.upper_label, self.bottom_label):
                widget.configure(background=self.cget('highlightbackground'))
    
        def _on_click(self, _):
            """
            Callback helper method which is triggered
            when the the widget is clicked
            """
            self.clicked.set(True)
            self.configure(relief='sunken')
            self.after(100, lambda: [
                self.configure(relief='raised'), self.clicked.set(False)
            ])
    
    
    class KeyboardMCVE(tk.Tk):
        """
        MCVE class for demonstration purposes
        """
        def __init__(self):
            super().__init__()
            self.title('Keyboard')
            self._widgets = []
            self._create_widgets()
    
        def _create_widgets(self):
            """
            Instantiating all the "keys" (buttons) on the fly while both
            configuring and laying them out properly at the same time.
            """
            for row in range(5):
                current_row = []
                for column in range(15):
                    button = CustomButton(
                        self,
                        width=1, height=2,
                        upper_text=random.choice(CHARS),
                        bottom_text=random.choice(CHARS)
                    )
                    button.grid(row=row, column=column, sticky='nswe')
                    current_row.append(button)
                self._widgets.append(current_row)
    
    if __name__ == '__main__':
        sys.exit(KeyboardMCVE().mainloop())
    

    或者,一个简单的解决方法是使用 Unicode 上标/下标。

    【讨论】:

    • 非常感谢。我从没想过我可以有一个框架作为按钮的孩子。正如你所说,我必须小心处理这些事件。现在,我有了一个创建图像并将其放在按钮上的新想法。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    • 2019-12-29
    • 1970-01-01
    相关资源
    最近更新 更多