You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:45:38