如何将Tkinter Treeview列中的复选框左对齐?
解决Tkinter Treeview复选框左对齐问题
我在开发一个小程序时,需要给窗口右侧的Treeview列添加复选框。参考相关代码实现功能后,发现复选框是右对齐的,希望调整为左对齐,和其他列的文本对齐方式保持一致。
当前效果
复选框位于对应列的右侧,与左对齐的文本列视觉不一致。
目标效果
复选框在对应列内左对齐,和其他列文本的对齐方式统一。
原实现代码
import tkinter as tk from tkinter import ttk root = tk.Tk() class CbTreeview(ttk.Treeview): def __init__(self, master=None, **kw): kw.setdefault('style', 'cb.Treeview') kw.setdefault('show', 'headings') # hide column #0 ttk.Treeview.__init__(self, master, **kw) # create checheckbox images self._im_checked = tk.PhotoImage('checked', data=b'GIF89a\x0e\x00\x0e\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x0e\x00\x0e\x00\x00\x02#\x04\x82\xa9v\xc8\xef\xdc\x83k\x9ap\xe5\xc4\x99S\x96l^\x83qZ\xd7\x8d$\xa8\xae\x99\x15Zl#\xd3\xa9"\x15\x00;', master=self) self._im_unchecked = tk.PhotoImage('unchecked', data=b'GIF89a\x0e\x00\x0e\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x0e\x00\x0e\x00\x00\x02\x1e\x04\x82\xa9v\xc1\xdf"|i\xc2j\x19\xce\x06q\xed|\xd2\xe7\x89%yZ^J\x85\x8d\xb2\x00\x05\x00;', master=self) style = ttk.Style(self) style.configure("cb.Treeview.Heading", font=(None, 13)) # put image on the right style.layout('cb.Treeview.Row', [('Treeitem.row', {'sticky': 'nswe'}), ('Treeitem.image', {'side': 'right', 'sticky': 'e'})]) # use tags to set the checkbox state self.tag_configure('checked', image='checked') self.tag_configure('unchecked', image='unchecked') def tag_add(self, item, tags): new_tags = tuple(self.item(item, 'tags')) + tuple(tags) self.item(item, tags=new_tags) def tag_remove(self, item, tag): tags = list(self.item(item, 'tags')) tags.remove(tag) self.item(item, tags=tags) def insert(self, parent, index, iid=None, **kw): item = ttk.Treeview.insert(self, parent, index, iid, **kw) self.tag_add(item, (item, 'unchecked')) self.tag_bind(item, '<ButtonRelease-1>', lambda event: self._on_click(event, item)) def _on_click(self, event, item): """Handle click on items.""" if self.identify_row(event.y) == item: if self.identify_column(event.x) == '#3': # click in 'Served' column # toggle checkbox image if self.tag_has('checked', item): self.tag_remove(item, 'checked') self.tag_add(item, ('unchecked',)) else: self.tag_remove(item, 'unchecked') self.tag_add(item, ('checked',)) tree = CbTreeview(root, columns=("Character Name", "Leveled up to 90", "Is Lv 90"), height=20, selectmode="extended") tree.heading('Character Name', text="Character Name", anchor='w') tree.heading('Leveled up to 90', text="Is Lv 90", anchor='w') tree.heading('Is Lv 90', text="Is Lv 90", anchor='w') tree.column('#1', stretch='no', minwidth=0, width=150) tree.column('#2', stretch='no', minwidth=0, width=0) tree.column('#3', stretch='no', minwidth=0, width=120) tree.pack(fill='both') tree.insert('', 'end', values=('Amber', True, '')) tree.insert('', 'end', values=('Jean', False, '')) tree.insert('', 'end', values=('Lisa', True, '')) tree.insert('', 'end', values=('Keqing', True, '')) tree.insert('', 'end', values=('Ganyu', True, '')) # for i in range(5): # tree.insert('', 'end', values=(i, i, i)) root.mainloop()
修改方案
只需要调整Treeview的样式布局,将复选框的位置从右侧改为左侧,并设置左对齐:
在CbTreeview类的__init__方法中,找到以下代码:
style.layout('cb.Treeview.Row', [('Treeitem.row', {'sticky': 'nswe'}), ('Treeitem.image', {'side': 'right', 'sticky': 'e'})])
替换为:
style.layout('cb.Treeview.Row', [('Treeitem.row', {'sticky': 'nswe'}), ('Treeitem.image', {'side': 'left', 'sticky': 'w'})])
修改后的完整代码
import tkinter as tk from tkinter import ttk root = tk.Tk() class CbTreeview(ttk.Treeview): def __init__(self, master=None, **kw): kw.setdefault('style', 'cb.Treeview') kw.setdefault('show', 'headings') # hide column #0 ttk.Treeview.__init__(self, master, **kw) # create checheckbox images self._im_checked = tk.PhotoImage('checked', data=b'GIF89a\x0e\x00\x0e\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x0e\x00\x0e\x00\x00\x02#\x04\x82\xa9v\xc8\xef\xdc\x83k\x9ap\xe5\xc4\x99S\x96l^\x83qZ\xd7\x8d$\xa8\xae\x99\x15Zl#\xd3\xa9"\x15\x00;', master=self) self._im_unchecked = tk.PhotoImage('unchecked', data=b'GIF89a\x0e\x00\x0e\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x0e\x00\x0e\x00\x00\x02\x1e\x04\x82\xa9v\xc1\xdf"|i\xc2j\x19\xce\x06q\xed|\xd2\xe7\x89%yZ^J\x85\x8d\xb2\x00\x05\x00;', master=self) style = ttk.Style(self) style.configure("cb.Treeview.Heading", font=(None, 13)) # 调整复选框为左对齐 style.layout('cb.Treeview.Row', [('Treeitem.row', {'sticky': 'nswe'}), ('Treeitem.image', {'side': 'left', 'sticky': 'w'})]) # use tags to set the checkbox state self.tag_configure('checked', image='checked') self.tag_configure('unchecked', image='unchecked') def tag_add(self, item, tags): new_tags = tuple(self.item(item, 'tags')) + tuple(tags) self.item(item, tags=new_tags) def tag_remove(self, item, tag): tags = list(self.item(item, 'tags')) tags.remove(tag) self.item(item, tags=tags) def insert(self, parent, index, iid=None, **kw): item = ttk.Treeview.insert(self, parent, index, iid, **kw) self.tag_add(item, (item, 'unchecked')) self.tag_bind(item, '<ButtonRelease-1>', lambda event: self._on_click(event, item)) def _on_click(self, event, item): """Handle click on items.""" if self.identify_row(event.y) == item: if self.identify_column(event.x) == '#3': # click in target column # toggle checkbox image if self.tag_has('checked', item): self.tag_remove(item, 'checked') self.tag_add(item, ('unchecked',)) else: self.tag_remove(item, 'unchecked') self.tag_add(item, ('checked',)) tree = CbTreeview(root, columns=("Character Name", "Leveled up to 90", "Is Lv 90"), height=20, selectmode="extended") tree.heading('Character Name', text="Character Name", anchor='w') tree.heading('Leveled up to 90', text="Is Lv 90", anchor='w') tree.heading('Is Lv 90', text="Is Lv 90", anchor='w') tree.column('#1', stretch='no', minwidth=0, width=150) tree.column('#2', stretch='no', minwidth=0, width=0) tree.column('#3', stretch='no', minwidth=0, width=120) tree.pack(fill='both') tree.insert('', 'end', values=('Amber', True, '')) tree.insert('', 'end', values=('Jean', False, '')) tree.insert('', 'end', values=('Lisa', True, '')) tree.insert('', 'end', values=('Keqing', True, '')) tree.insert('', 'end', values=('Ganyu', True, '')) root.mainloop()
说明
- 修改
style.layout中的Treeitem.image参数:将side从right改为left,sticky从e(右对齐)改为w(左对齐),这样复选框就会在对应列内左对齐显示。 - 其他代码无需调整,点击事件的判断逻辑依然有效,因为是基于列的位置(
#3)进行判断,和复选框的对齐方式无关。
内容的提问来源于stack exchange,提问作者Ricky Shie
相关产品推荐
相关产品推荐

