【问题标题】:How to change the foreground or background colour of a selected cell in tkinter treeview?如何更改 tkinter 树视图中选定单元格的前景色或背景色?
【发布时间】:2018-06-29 16:43:56
【问题描述】:

我想更改 tkinter.treeview 中选定单元格的前景色或背景色。我该怎么做?

这个link 显示了更改树视图中所有单元格颜色的命令,但我无法让它适用于单个单元格。

ttk.Style().configure("Treeview", background="#383838", 
 foreground="white", fieldbackground="red")

我之前写过test code。请使用此代码得出您的解决方案/建议。谢谢。

这个link 展示了如何使用标签来改变一行数据的颜色,即一个选定的项目,而不是一个单元格。

【问题讨论】:

  • 如果您提供了最少的代码来生成要配置的单元格的示例树视图,我认为这将是一个更好的问题。
  • 您无法更改单个单元格的颜色。
  • @Nae 我想避免重复相同的代码。可以简单地将上面显示的命令添加到我之前写的test codedef selectItem(self, event):的最后一行。
  • @BryanOakley 谢谢。这意味着我可能需要查看在树视图上覆盖 tk.canvas 以更改单元格字体或背景的颜色?
  • 如果您的问题已解决,请提供答案。

标签: python tkinter colors treeview


【解决方案1】:

如果有人在寻找更改 tkinter 树视图的选定颜色的答案,您可以查看以下代码。

style = ttk.Style()
# this is set background and foreground of the treeview
style.configure("Treeview",
                background="#E1E1E1",
                foreground="#000000",
                rowheight=25,
                fieldbackground="#E1E1E1")

# set backgound and foreground color when selected
style.map('Treeview', background=[('selected', '#BFBFBF'), foreground=[('selected', 'black')])

【讨论】:

    【解决方案2】:

    我相信您可以通过非常简单的方式获得您想要的行为:

    1. 为您的单元格分配标签

    In this question you can see both how to insert tags and how to change them

    1. 为每个标签分配颜色

    Like suggested in this question

    1. 请注意,Tkinter 有点老了,解散了……你可能有一些困难,所以让我把这个链接起来:

    Why my code below may not work properly

    请注意,您是在询问“如何更改选定的单元格”,但根据您所写的内容,我相信您正在尝试更改 选定的行。我下面的代码更改了行。

    import tkinter as tk
    from tkinter import ttk
    from random import choice
    
    
    
    
    colors = ["red", "green", "black", "blue", "white", "yellow", "orange", "pink", "grey", "purple", "brown"]
    def recolor():
        for child in tree.get_children():
            picked = choice(colors)
            tree.item(child, tags=(picked), values=(picked))
        for color in colors:
            tree.tag_configure(color, background=color)
        tree.tag_configure("red", background="red")
    
    
    root = tk.Tk()
    
    tree=ttk.Treeview(root)
    
    
    tree["columns"]=("one","two","three")
    tree.column("#0", width=60, minwidth=30, stretch=tk.NO)
    tree.column("one", width=120, minwidth=30, stretch=tk.NO)
    
    tree.heading("#0",text="0",anchor=tk.W)
    tree.heading("one", text="1",anchor=tk.W)
    
    for i in range(10):
        tree.insert("", i, text="Elem"+str(i), values=("none"))
    
    tree.pack(side=tk.TOP,fill=tk.X)
    
    
    b = tk.Button(root, text="Change", command=recolor)
    b.pack()
    
    
    root.mainloop()
    

    结果:

    【讨论】:

    • 最好用示例脚本说明您的意思,以便其他人可以将您的解决方案与现有解决方案进行比较。
    • @SunBear 我们开始 ;) 完成!
    • @SunBear 哦,伙计,我在之前的回答中写了这个:“请注意,您问的是“如何更改选定的单元格”,但从您写的内容来看,我相信您正在尝试更改选定的行。我下面的代码更改了行。 这个说法完全错误。伙计,我确实浪费了我的时间......
    • 感谢您的努力。是的,设定的目标是更改 Treeview 小部件中单个选定单元格的颜色。
    【解决方案3】:
    1. @BryanOkley 分享说不能改变个人的颜色 ttk.Treeview 中的单元格。
    2. 所以我探索了使用 tk.Canvas() 和 tk.Canvas.create_text() 来 创造改变选定单元格颜色的错觉 ttk.Treeview() 小部件。我有幸过来 j08lue/ttkcalendar.py 和我有同样的目标 改编自它。
    3. 我改编的脚本(带有相关的 cmets)如下所示。一世 希望它可以帮助其他有同样想法的人。

    需要改进:我还没有弄清楚为什么我的算法不能准确地将画布文本框覆盖在图标/树列和值列中选定的树视图单元格中的值上。为此,我采用了通过反复试验确定的软糖值。然而,这并不理想。 有人可以分享我如何在不使用 fudge 值的情况下实现 canvas_textbox 叠加层与 Treeview 单元格值的准确对齐吗?

    import tkinter as tk
    import tkinter.ttk as ttk
    import tkinter.font as tkFont
    
    class App(tk.Frame):
        def __init__(self, parent, *args, **kwargs):
            ttk.Frame.__init__(self, parent, *args, **kwargs)
    
            #1. Create Treeview with binding
            self.tree = ttk.Treeview(parent, columns=("size", "modified"))
            self.tree["columns"] = ("date", "time", "loc")
    
            self.tree.column("#0",   width=100, anchor='center')
            self.tree.column("date", width=100, anchor='center')
            self.tree.column("time", width=100, anchor='center')
            self.tree.column("loc",  width=100, anchor='center')
    
            self.tree.heading("#0",   text="Name")
            self.tree.heading("date", text="Date")
            self.tree.heading("time", text="Time")
            self.tree.heading("loc",  text="Location")
    
            self.tree.insert("","end", text = "Grace",
                             values = ("2010-09-23","03:44:53","Garden"))
            self.tree.insert("","end", text = "John" ,
                             values = ("2017-02-05","11:30:23","Airport"))
            self.tree.insert("","end", text = "Betty",
                             values = ("2014-06-25","18:00:00",""))
    
            self.tree.grid()
            self.tree.bind('<ButtonRelease-1>', self.selectItem)
    
            #2. Create a Canvas Overlay to show selected Treeview cell 
            sel_bg = '#ecffc4'
            sel_fg = '#05640e'
            self.setup_selection(sel_bg, sel_fg)
    
    
        def setup_selection(self, sel_bg, sel_fg):
            self._font = tkFont.Font()
    
            self._canvas = tk.Canvas(self.tree,
                                     background=sel_bg,
                                     borderwidth=0,
                                     highlightthickness=0)
    
            self._canvas.text = self._canvas.create_text(0, 0,
                                                         fill=sel_fg,
                                                         anchor='w')
    
        def selectItem(self, event):
            # Remove Canvas overlay from GUI
            self._canvas.place_forget()
    
            # Local Parameters
            x, y, widget = event.x, event.y, event.widget
            item = widget.item(widget.focus())
            itemText = item['text']
            itemValues = item['values']
            iid = widget.identify_row(y)
            column = event.widget.identify_column(x)
            print ('\n&&&&&&&& def selectItem(self, event):')
            print ('item = ', item)
            print ('itemText = ', itemText)
            print('itemValues = ',itemValues)
            print ('iid = ', iid)
            print ('column = ', column)
    
            #Leave method if mouse pointer clicks on Treeview area without data
            if not column or not iid:
                return
    
            #Leave method if selected item's value is empty
            if not len(itemValues): 
                return
    
            #Get value of selected Treeview cell
            if column == '#0':
                self.cell_value = itemText
            else:
                self.cell_value = itemValues[int(column[1]) - 1]
            print('column[1] = ',column[1])
            print('self.cell_value = ',self.cell_value)
    
            #Leave method if selected Treeview cell is empty
            if not self.cell_value: # date is empty
                return
    
            #Get the bounding box of selected cell, a tuple (x, y, w, h), where
            # x, y are coordinates of the upper left corner of that cell relative
            #      to the widget, and
            # w, h are width and height of the cell in pixels.
            # If the item is not visible, the method returns an empty string.
            bbox = widget.bbox(iid, column)
            print('bbox = ', bbox)
            if not bbox: # item is not visible
                return
    
            # Update and show selection in Canvas Overlay
            self.show_selection(widget, bbox, column)
    
            print('Selected Cell Value = ', self.cell_value)
    
    
        def show_selection(self, parent, bbox, column):
            """Configure canvas and canvas-textbox for a new selection."""
            print('@@@@ def show_selection(self, parent, bbox, column):')
            x, y, width, height = bbox
            fudgeTreeColumnx = 19 #Determined by trial & error
            fudgeColumnx = 15     #Determined by trial & error
    
            # Number of pixels of cell value in horizontal direction
            textw = self._font.measure(self.cell_value)
            print('textw = ',textw)
    
            # Make Canvas size to fit selected cell
            self._canvas.configure(width=width, height=height)
    
            # Position canvas-textbox in Canvas
            print('self._canvas.coords(self._canvas.text) = ',
                  self._canvas.coords(self._canvas.text))
            if column == '#0':
                self._canvas.coords(self._canvas.text,
                                    fudgeTreeColumnx,
                                    height/2)
            else:
                self._canvas.coords(self._canvas.text,
                                    (width-(textw-fudgeColumnx))/2.0,
                                    height/2)
    
            # Update value of canvas-textbox with the value of the selected cell. 
            self._canvas.itemconfigure(self._canvas.text, text=self.cell_value)
    
            # Overlay Canvas over Treeview cell
            self._canvas.place(in_=parent, x=x, y=y)
    
    
    
    if __name__ == "__main__":
        window = tk.Tk()
        app = App(window)
        window.mainloop()
    

    【讨论】:

      【解决方案4】:

      如果您准备叠加小部件,您可能有非常自定义的要求,或者可能有更适合您需要的小部件。如果您不打算使用树视图,那么表格小部件可能会提供您想要的。您可以控制单个单元格的内容,它允许用户编辑单元格(默认情况下),并且您可以将“活动”单元格属性与其他单元格分开控制。使用此代码将您的数据放在一个表中。

      import tkinter as tk
      import tkinter.ttk as ttk
      from tkinter.tktable import Table as ttkTable
      from tkinter.tktable import ArrayVar
      
      class App(tk.Frame):
          def __init__(self, parent, *args, **kwargs):
              ttk.Frame.__init__(self, parent, *args, **kwargs)
              self.grid_columnconfigure(0, weight=1)
              self.grid_rowconfigure(0, weight=1)
              parent.grid_columnconfigure(0, weight=1)
              parent.grid_rowconfigure(0, weight=1)
              self.content = ArrayVar(parent)
              self.table = ttkTable(rows=4,  cols=4,  titlerows=1,
                  titlecols=0,    roworigin=0,    colorigin=0,   anchor='w', 
                  selecttype='cell',   rowstretch='none',  colstretch='unset',
                  flashmode='off', ellipsis='...', ipadx=2,    colwidth=12,
                  multiline=False, resizeborders='col',   selectmode='browse',
                  cursor='arrow', insertwidth=2, variable=self.content,
                  insertbackground='white'
              )
              self.table.tag_configure('title', relief='raised', anchor='center', bg='blue',
                  fg='white', state='disabled'
              )
              self.table.tag_configure('active', bg='gray30', fg='white')
      
              c_headers = ["Name", "Date", "Time", "Loc"]
              for col, word in enumerate(c_headers, start=0):
                  index = '0,' + str(col)
                  self.table.set('col', index, word)
      
              self.table.width((0,1,2,3), (30,30,30,40))
      
              self.table.set('row','1,0', "John","2017-02-05","11:30:23","Airport")
              self.table.set('row','2,0', "Betty","2014-06-25","18:00:00","Orchard Road")
      
              self.table.grid(sticky='news')
      

      【讨论】:

      • 我在Tk8.5Tk8.6 中找不到tktablettkTableImportError: No module named 'tkinter.tktable'。你能告诉我这个小部件的文档吗?
      • 很抱歉,我忘记了我专门在 pypy 之外下载了这个。它是受版权保护的软件,但许可证相当开放。阅读。这是使您能够下载它的链接。它只是一个 tktable.py 文件。因此,您应该将其移动/复制到系统上的 tkinter 文件夹中。它使用 Tk Widget 来构建表,因此它应该可以移植到 tkinter 支持的所有系统sourceforge.net/p/tktable/wiki/Home
      • 感谢您向我介绍了一个新的小部件。我选择继续使用 tk.Treeview 并上传了满足我需求的解决方案。与您分享,以防您感兴趣。
      猜你喜欢
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多