0

I have been working on a small program where I needed to add a column of checkboxes on the right side of the window. Although I managed to do so by referencing the code at
How to add checkbuttons to every row of a table read from csv in tkinter?, I was wondering if it is possible to justify the images of checkboxes to the left side of the column just like other texts.

Here is what I have done so far. What I have done so far.

Here is the final result that I want to achieve. The final result.

Here is my code.

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!\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!\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()
Rory
  • 661
  • 1
  • 6
  • 15
  • Actually you cannot do it with tags. See [this](https://stackoverflow.com/questions/68906464/tag-a-specific-value-column-in-treeview-python-to-color-it) post. The tags are added to the rows and not to specific cells in your treeview. This is why when you put the tags to the left, they seem to move to the first column, but actually they move to the most left position in the row. – steTATO Sep 07 '22 at 14:36
  • Look at first screenshot. You will see a semi-colon vertical dash next to ls Lv90. You can move mouse to select vertical dash to resizing. – toyota Supra Sep 07 '22 at 19:09
  • @toyotaSupra I have tried that and those checkboxes still stick to the right side of the window. – Ricky Shie Sep 07 '22 at 22:38
  • @steTATO Got it. I wish I could find a way to get around it. – Ricky Shie Sep 07 '22 at 22:39
  • I have also tried to alternate the color of each row https://stackoverflow.com/questions/61373260/tkinter-ttk-treeview-colored-rows so it will be less likely for users to check the wrong rows, but it didn't work. – Ricky Shie Sep 07 '22 at 22:51

1 Answers1

0

I was wondering if it is possible to justify the images of checkboxes to the left side of the column just like other texts.

To fix problem. You have four typo errors.

  • In line 63, keyword text="Is Lv 90" is not identical heading
  • In line 65-67, tree.column is not is not identical as heading
  • In line 66, keyword width=0 cannot be set to zero. Setting to zero, the column is not showing and cannot move column 3.

Change in line 63- 67:

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)

to:

tree.heading('Leveled up to 90', text="Leveled up to 90", anchor='w')
tree.heading('Is Lv 90', text="Is Lv 90", anchor='w')
tree.column('Character Name', stretch='no', minwidth=0, width=150)
tree.column('Leveled up to 90', stretch='no', minwidth=0, width=150)
tree.column('Is Lv 90', stretch='no', minwidth=0, width=120)

Screenshot, You can see column 1 and column 3:

enter image description here

toyota Supra
  • 3,181
  • 4
  • 15
  • 19