如何在Tkinter的Button小部件中创建多个Label?

时间:2017-10-16 02:16:57

标签: python user-interface button tkinter widget

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

非常感谢你。

1 个答案:

答案 0 :(得分: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())

Example

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