2017-10-16 132 views

回答

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的上标/下标。

+0

非常感谢。我从来没有想过我可以有一个框架作为一个按钮的孩子。正如你所说,我必须小心处理事件。现在,我有了一个新想法来创建一个图像并将其放在按钮上。 非常感谢。 – Hasan

+1

伟大的方法。这个答案值得更多赞赏 –

相关问题