【问题标题】:only first tag_configure gets executed on click event within treeview widget/tkinter只有第一个 tag_configure 在 treeview 小部件/tkinter 中的点击事件上执行
【发布时间】:2021-07-10 05:45:04
【问题描述】:

在过去的几个小时里,我一直被困在这个问题上,似乎无法弄清楚为什么代码的行为如此,因此寻求任何帮助。基本上我在 tkinter python 3.6 中有一个包含 60000 多个项目的树视图小部件。我创建了一个函数 onTripleClick ,“理想情况下”应该突出显示具有特定样式(使用标签)的第一个单击项目,并且当下一个项目被三次单击时,先前样式的项目应该回到原始状态(使用另一个标签),而新点击应该采用样式化状态。出于某种原因,只有第一个 tag_configure 被执行——如果我注释掉第一个 tag_configure,那么第二个 tag_configure 也会被执行——当第二个 tag_configure 满足 IF 条件时,我需要它们都被执行。非常感谢任何建议!

编辑: 根据要求 - 我已经包含了一个最小版本的工作代码,上面解释的想法是用一种样式(trClicked 标记)突出显示左键单击的三次行,而当另一行被三次点击,之前点击的项目返回到原始状态(普通标签),而新的项目采用样式(trClicked 标签)。按原样运行代码,然后注释掉第 9 行的第一个 tree.tag_configure() 位 - 并重新运行。这次第二个 tree.tag_configure(){line14} 被执行——我需要它们同时执行。谢谢!

from tkinter import *
from tkinter import ttk

def onTripleClick(event):
    global selectedSigName, selectedSigPath, trClickedItemiid, toBeClearedItemiid
    itemSelection = tree.selection()[0] 
    
    trClickedItemiid = tree.focus()
    tree.tag_configure('trClicked'+str(trClickedItemiid), background='light green', foreground='black', font=( 'Helvetica' ,8, 'bold', 'italic')) # font=(family, size, weight, slant, underline, overstrike) 
    # tree.tag_bind('trClicked'+str(trClickedItemiid),'<1>', trClickedItemiid)
    prevTrClicked.append(trClickedItemiid)
    if len(prevTrClicked) > 1:
        toBeClearedItemiid = prevTrClicked.pop(0) # pop the 0th index and pass it to normal
        tree.tag_configure('normal'+str(toBeClearedItemiid), background='pink', foreground='black', font=( 'Courier' ,8, 'normal', 'roman'))
        # tree.tag_bind('normal'+str(toBeClearedItemiid),'<1>', toBeClearedItemiid)


# Create main root object of TK class
root = Tk()
root.title('MyTreeview')
root.geometry("700x500")

# create frame to house treeview AND scrollbar
frame = Frame(root)
frame.pack(pady=5)

tree = ttk.Treeview(frame, height=20, selectmode="browse")
tree.pack(side=LEFT)
tree['columns'] = ("Column1", "Column2", "Column3")

#Format Columns
tree.column("#0", width=10, minwidth=10) # this is where the plus icon will live
tree.column("Column1", anchor=W, width=150)
tree.column("Column2", anchor=W, width=300)
tree.column("Column3", anchor=W, width=120)

# Create headings
tree.heading("#0", text="", anchor=W)
tree.heading("Column1", text="Column1", anchor=W)
tree.heading("Column2", text="Column2", anchor=W)
tree.heading("Column3", text="Column3", anchor=W)

# to be used by TrClicked Function for helping clear older clicked items
global prevTrClicked
prevTrClicked = [] #

rows= [
    ['TopMostParent1', '2ndParent-ColE', 'ColF-3rdParent'],
    ['TopMostParent2', '5thParent-ColE', 'ColF-1stParent'],
    ['TopMostParent3', '4thParent-ColE', 'ColF-2ndParent'],
    ['TopMostParent4', '2ndParent-ColE', 'ColF-3rdParent'],
    ['TopMostParent4', '4thParent-ColE', 'ColF-1stParent'],
    ['TopMostParent6', '3rdParent-ColE', 'ColF-2ndParent'],
    ['TopMostParent5', '3rdParent-ColE', 'ColF-1stParent'],
    ['TopMostParent4', '3rdParent-ColE', 'ColF-3rdParent'],
    ['TopMostParent2', '3rdParent-ColE', 'ColF-3rdParent']
]
count=0
for row in rows:
    tree.insert(parent='', index='end', iid=count, text='', tags=('trClicked'+str(count), 'normal'+str(count)), values=(row[0], row[1], row[2]))
    count+=1


tree.bind("<Triple-1>", onTripleClick)
# tree.tag_bind('trClicked'+str(trClickedItemiid),'<1>', trClickedItemiid)
# tree.tag_bind('normal'+str(toBeClearedItemiid),'<1>', toBeClearedItemiid)

root.mainloop()

【问题讨论】:

  • 请尽量提供完整的minimal reproducible example
  • 您向我们展示的代码配置标签,但从未将它们添加到一个或多个项目。请在您的示例中展示您如何将标签添加到项目中。
  • @BryanOakley - 我已经编辑了我的原始帖子以反映代码的最低工作版本和一些解释 - 抱歉,我最初没想过这样做!

标签: python tkinter treeview


【解决方案1】:

在您的情况下,列表中标签的顺序很重要

如果我们改变这个


tags=('trClicked'+str(count), 'normal'+str(count))

到这里


tags=('normal'+str(count), 'trClicked'+str(count))

替换后,之前的元素变为粉红色。 您将看到相反的结果:变为粉红色的元素将不再变为绿色。


解决方案

您对两个标签(背景、前景、字体)使用相同的样式属性。 在这种情况下,一个trClicked 标签就足够了。 您只会根据事件更改样式属性值。

如果你使用一个标签('trClicked'):


tree.tag_configure('trClicked'+str(trClickedItemiid), background='light green', foreground='black', font=( 'Helvetica' ,8, 'bold', 'italic'))

...

tree.tag_configure('trClicked'+str(toBeClearedItemiid), background='pink', foreground='black', font=( 'Courier' ,8, 'normal', 'roman'))

然后,总的来说,一切正常。


完整示例


from tkinter import *
from tkinter import ttk


# to be used by TrClicked Function for helping clear older clicked items
global clicked_queue
clicked_queue = [] # last 3 items


def onTripleClick(event):
    global clicked_queue
    # 'trClicked'+iid  - a unique tag for each item

    # the iid (string) of the item that currently has focus, or '' if no item has focus 
    current_item_iid = event.widget.focus()
    if not current_item_iid:
        return
    print(event.widget.item(current_item_iid))
    print("current:", current_item_iid) # iid=count   

    if clicked_queue:
        # get the previous item, the last one in the queue
        prev_item_iid = clicked_queue[-1]
        print("prev item:", prev_item_iid)
        
        if prev_item_iid == current_item_iid:
            return
        
        tree.tag_configure('trClicked'+prev_item_iid, background='pink',
                           foreground='black', font=( 'Courier' , 8, 'normal', 'roman'))
    
    tree.tag_configure('trClicked'+current_item_iid, background='light green',
                       foreground='black', font=( 'Helvetica' , 8, 'bold', 'italic'))

    # add current item to the right side of the queue
    clicked_queue.append(current_item_iid)
    print("new prev item:", current_item_iid)
    
    if len(clicked_queue) == 3:
        # get and remove an element from the left side of the queue
        prev_prev_item_iid = clicked_queue[0]
        clicked_queue.remove(prev_prev_item_iid)
        
        if prev_prev_item_iid == current_item_iid:
            return
        
        # return to the default style
        tree.tag_configure('trClicked'+prev_prev_item_iid, background='white',
                           foreground='black', font=( 'Courier' , 8, 'normal', 'roman'))


# Create main root object of TK class
root = Tk()
root.title('MyTreeview')
root.geometry("700x500")

# create a consistent style for the background and font
style = ttk.Style()
style.configure('Treeview', background='white', foreground='black', font=( 'Courier' , 8, 'normal', 'roman'))

# create frame to house treeview AND scrollbar
frame = Frame(root)
frame.pack(pady=5)

tree = ttk.Treeview(frame, height=20, selectmode="browse")
tree.pack(side=LEFT)
tree['columns'] = ("Column1", "Column2", "Column3")

#Format Columns
tree.column("#0", width=10, minwidth=10) # this is where the plus icon will live
tree.column("Column1", anchor=W, width=150)
tree.column("Column2", anchor=W, width=300)
tree.column("Column3", anchor=W, width=120)

# Create headings
tree.heading("#0", text="", anchor=W)
tree.heading("Column1", text="Column1", anchor=W)
tree.heading("Column2", text="Column2", anchor=W)
tree.heading("Column3", text="Column3", anchor=W)


rows= [
    ['TopMostParent1', '2ndParent-ColE', 'ColF-3rdParent'],
    ['TopMostParent2', '5thParent-ColE', 'ColF-1stParent'],
    ['TopMostParent3', '4thParent-ColE', 'ColF-2ndParent'],
    ['TopMostParent4', '2ndParent-ColE', 'ColF-3rdParent'],
    ['TopMostParent4', '4thParent-ColE', 'ColF-1stParent'],
    ['TopMostParent6', '3rdParent-ColE', 'ColF-2ndParent'],
    ['TopMostParent5', '3rdParent-ColE', 'ColF-1stParent'],
    ['TopMostParent4', '3rdParent-ColE', 'ColF-3rdParent'],
    ['TopMostParent2', '3rdParent-ColE', 'ColF-3rdParent']
]
count = 1  # <- start at 1 or set iid=str(count), otherwise iid=0 will default to "I001"
for row in rows:
    tree.insert(parent='', index='end', iid=count, text='', tags=('trClicked'+str(count),), values=(row[0], row[1], row[2]))
    count += 1

tree.bind("<Triple-1>", onTripleClick)

root.mainloop()

【讨论】:

  • 感谢您发布有效的解决方案!我确实理解你的逻辑,但我仍然不明白我的逻辑有什么问题 - 基本上就像 - 为每个树元素分配 2 个唯一标签,使用 1 个唯一标签设置特定样式,使用另一个标签设置另一种样式满足条件后标记?那里的逻辑有什么问题?我还注意到您添加了样式-在我的实际代码中,我使用了蛤蜊主题,并试图找到它用来恢复的字体,但一直没能做到,您知道在哪里可以找到每个主题的样式属性(字体、颜色等)?TY!
  • 你的逻辑没问题,但实际上这段代码不起作用。这是软件内部的东西。您可以在 PC 上找到内置主题的样式设置(例如 \path\to\python\tcl\tk8.6\ttk\themename.tcl 或 /usr/share/tcltk/tk8.6/ttk/主题名.tcl)。您也可以尝试使用style.lookup()
  • 知道了 - 非常感谢您花时间解释!
猜你喜欢
  • 1970-01-01
  • 2016-12-04
  • 1970-01-01
  • 2020-05-20
  • 2017-11-24
  • 1970-01-01
  • 2011-07-17
  • 2017-12-13
  • 1970-01-01
相关资源
最近更新 更多