tkinter 突出显示一行标签 table

tkinter Highlight a row of a label table

我正在尝试突出显示使用按钮创建的 table 的整行。

代码已经突出显示了鼠标悬停的按钮,但我不仅需要突出显示此按钮,还需要突出显示整行以模拟真实的 table。

我知道使用树视图更容易做到这一点,但出于多种原因,在我的 GUI 中,我不得不使用基于按钮 table 而不是树视图。

from tkinter import *

root = Tk()

class HoverButton(Button):
    def __init__(self, master, **kw):
        Button.__init__(self,master=master,**kw)
        self.defaultBackground = self["background"]
        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)

    def on_enter(self, e):
        self['background'] = self['activebackground']

    def on_leave(self, e):
        self['background'] = self.defaultBackground

columns = ("column 1","column 2","column 3", "column 4")
first_row = ("data 1", "data 2", "data 3", "data 4")

for columns_headings in range(len(columns)):
    l = HoverButton(root, text=columns[columns_headings], relief=RIDGE, activebackground="yellow")
    l.grid(row=0, column=columns_headings, sticky=NSEW)    

for first_row_data in range(len(first_row)):
    g = HoverButton(root, text=first_row[first_row_data], relief=RIDGE, activebackground="yellow")
    g.grid(row=1, column=first_row_data, sticky=NSEW)  

mainloop()

如果您将按钮保留在带有行和列的二维列表中,那么您可以简单地访问同一行中的其他按钮。每个按钮还需要变量来保持其行号。

from tkinter import *

root = Tk()

class HoverButton(Button):
    
    def __init__(self, master, **kw):
        Button.__init__(self,master=master,**kw)
        self.defaultBackground = self["background"]
        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)

    def on_enter(self, e):
        #self['background'] = self['activebackground']
        for b in buttons[self.row_number]:
            b['background'] = self['activebackground']

    def on_leave(self, e):
        #self['background'] = self.defaultBackground
        for b in buttons[self.row_number]:
            b['background'] = self.defaultBackground

columns = ("column 1","column 2","column 3", "column 4")
first_row = ("data 1", "data 2", "data 3", "data 4")

buttons = []  # list 2D for all buttons

row = []
for columns_headings in range(len(columns)):
    l = HoverButton(root, text=columns[columns_headings], relief=RIDGE, activebackground="yellow")
    l.row_number = 0
    l.grid(row=0, column=columns_headings, sticky=NSEW)    
    row.append(l)
buttons.append(row)    
    
row = []
for first_row_data in range(len(first_row)):
    g = HoverButton(root, text=first_row[first_row_data], relief=RIDGE, activebackground="yellow")
    g.row_number = 1
    g.grid(row=1, column=first_row_data, sticky=NSEW)  
    row.append(g)
buttons.append(row)    

mainloop()

编辑:

具有更多行的版本 - 需要额外的 for-循环。

import tkinter as tk  # PEP8: `import *` is not preferred

# --- classes ---  # PEP8: all classes directly after imports

class HoverButton(tk.Button):
    
    def __init__(self, master, **kw):
        super().__init__(master=master, **kw)
        self.defaultBackground = self["background"]
        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)

    def on_enter(self, e):
        #self['background'] = self['activebackground']
        for b in buttons[self.row_number]:
            b['background'] = self['activebackground']

    def on_leave(self, e):
        #self['background'] = self.defaultBackground
        for b in buttons[self.row_number]:
            b['background'] = self.defaultBackground

# --- main ---

root = tk.Tk()


columns = ("column 1","column 2","column 3", "column 4")
rows = [
    ("data A1", "data A2", "data A3", "data A4"),
    ("data B1", "data B2", "data B3", "data B4"),
    ("data C1", "data C2", "data C3", "data C4"),
]

buttons = []

row = []
for col_number, text in enumerate(columns):
    l = HoverButton(root, text=text, relief='ridge', activebackground="yellow")
    l.row_number = 0
    #l.col_number = col_number
    l.grid(row=0, column=col_number, sticky='nsew')    
    row.append(l)
buttons.append(row)    
    
for row_number, row_data in enumerate(rows, 1):
    row = []
    for col_number, text in enumerate(row_data):
        g = HoverButton(root, text=text, relief='ridge', activebackground="yellow")
        g.row_number = row_number
        #g.col_number = col_number
        g.grid(row=row_number, column=col_number, sticky='nsew')  
        row.append(g)
    buttons.append(row)    

root.mainloop()

您可以将所有 Label 设置在与鼠标悬停的行相同的行中。我添加了几行数据以使事情更清楚。

请注意 header 行正常突出显示。

from tkinter import *

root = Tk()

class HoverButton(Button):
    def __init__(self, master, **kw):
        Button.__init__(self, master=master, **kw)
        self.defaultBackground = self["background"]
        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)

    def on_enter(self, e):
        row = e.widget.grid_info()['row']
        if not row:  # Header row?
            self['background'] = self['activebackground']
        else:
            for lbl in row_labels[row]:
                lbl['background'] = lbl['activebackground']

    def on_leave(self, e):
        row = e.widget.grid_info()['row']
        if not row:  # Header row?
            self['background'] = self.defaultBackground
        else:
            for lbl in row_labels[row]:
                lbl['background'] = lbl.defaultBackground


columns = ("column 1","column 2","column 3", "column 4")
rows = [("data 1A", "data 2A", "data 3A", "data 4A"),
        ("data 1B", "data 2B", "data 3B", "data 4B"),
        ("data 1C", "data 2C", "data 3C", "data 4C")]


# Create table of Labels.
row_labels = []  # List of lists of Labels.

labels = []
for j, column_heading in enumerate(columns):
    l = HoverButton(root, text=column_heading, relief=RIDGE, activebackground="yellow")
    l.grid(row=0, column=j, sticky=NSEW)
    labels.append(l)
row_labels.append(labels)

for i, row in enumerate(rows, start=1):
    labels = []
    for j, item in enumerate(row):
        g = HoverButton(root, text=item, relief=RIDGE, activebackground="yellow")
        g.grid(row=i, column=j, sticky=NSEW)
        labels.append(g)
    row_labels.append(labels)

root.mainloop()

截图如下:

您可以使用 .grid_info() 获取悬停按钮的行,然后更新同一行中的所有按钮(通过 .grid_slaves(row=...):

def on_enter(self, e):
    row = self.grid_info()['row']
    for w in self.master.grid_slaves(row=row):
        if isinstance(w, HoverButton):
            w['bg'] = w['activebackground']

def on_leave(self, e):
    row = self.grid_info()['row']
    for w in self.master.grid_slaves(row=row):
        if isinstance(w, HoverButton):
            w['bg'] = w.defaultBackground