2017-10-16 119 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

偉大的方法。這個答案值得更多讚賞 –

相關問題