I have a searchable ttk.Treeview in my application that sets the selection (highlight) based on a search term.
To do this, I collect the items I want to select into a space separated string like so:
"item_a item_b item_c"
I pass this string into the selection_set
method.
The problem that I have is that this doesn't work on some computers, even though they have the same python version as far as I can tell (2.7.10).
I get an error message like:
"item_a item_b item_c": Item not found
As if it was searching for one item with that giant name.
I can achieve the same goal by creating a list and iterating through it, calling selection_add
with each item, but it is much slower.
I imagine that there may be a difference in the system Tcl / Tk version, which might be different from the python installation, but I'm not sure, and I don't know how to verify.
But even if that were the case, I have had terrible trouble finding good documentation on any of this. The idea of using a space separated string isn't even in any documentation I've found, I have just seen it referenced in other StackOverflow posts with no sources. (E.g here)
So I'm looking for a version agnostic (or at least a way to detect the version and do a different thing) solution to call selection_set
with a list of items. If anyone could tell me how to do that or point to documentation that would help me understand how to do that, I would appreciate it.
To use selection_set
in Python 2, you need to pass a tuple of items to select. You can easily convert a list into a tuple with the built in tuple
function.
If you can upgrade to Python 3, using a list directly works and is probably better.
Here is a simple test program that uses a few different methods to select items in a TreeView. This should work on both Python 2 and 3 so you can see which methods work.
try:
import Tkinter as tk
import ttk
except ImportError:
import tkinter as tk
import tkinter.ttk as ttk
import platform
class TestWindow:
def __init__(self):
self.top = tk.Tk()
self.top.title("Test TreeView selection")
self.top.minsize(450, 600)
self.root_frame = ttk.Frame(self.top, padding=5)
self.root_frame.pack(fill=tk.BOTH, expand=True)
self.python_version_label = ttk.Label(self.root_frame, text="Python Version: " + platform.python_version())
self.python_version_label.pack(fill=tk.X, expand=False)
self.version_label = ttk.Label(self.root_frame, text="TCL Version: " + tk.Tcl().eval('info patchlevel'))
self.version_label.pack(fill=tk.X, expand=False)
self.controls_frame = ttk.Frame(self.root_frame, padding=5)
self.controls_frame.pack(fill=tk.X, expand=False)
self.select_space_button = ttk.Button(self.controls_frame, text="Select Space", command=self.select_space)
self.select_space_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.select_loop_button = ttk.Button(self.controls_frame, text="Select Loop", command=self.select_loop)
self.select_loop_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.select_list_button = ttk.Button(self.controls_frame, text="Select List", command=self.select_list)
self.select_list_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.select_tuple_button = ttk.Button(self.controls_frame, text="Select Tuple", command=self.select_tuple)
self.select_tuple_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.clear_button = ttk.Button(self.controls_frame, text="Clear", command=self.clear)
self.clear_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.tree_frame = ttk.Frame(self.root_frame, padding=5)
self.tree_frame.pack(fill=tk.BOTH, expand=True)
self.tree_view = ttk.Treeview(self.tree_frame, padding=5)
self.ysb = ttk.Scrollbar(self.tree_frame, orient='vertical', command=self.tree_view.yview)
self.tree_view.configure(yscroll=self.ysb.set)
self.tree_view.pack(expand=True, fill=tk.BOTH, side=tk.LEFT)
self.ysb.pack(side=tk.RIGHT, fill=tk.Y)
self.tree_view.heading("#0", text="Test Item")
for i in range(0, 100):
name = "Item " + str(i)
item_id = self.tree_view.insert("", tk.END, str(i), text=name, open=True)
self.tree_view.insert(item_id, tk.END, str(i) + "a", text=name + ": A")
self.tree_view.insert(item_id, tk.END, str(i) + "b", text=name + ": B")
self.tree_view.insert(item_id, tk.END, str(i) + "c", text=name + ": C")
self.tree_view.insert(item_id, tk.END, str(i) + "d", text=name + ": D")
self.items = []
for i in range(4, 41):
self.items.append(str(i))
self.items.append(str(i) + "a")
self.items.append(str(i) + "b")
self.items.append(str(i) + "d")
def select_space(self):
self.tree_view.selection_set(" ".join(self.items))
def select_loop(self):
for item in self.items:
self.tree_view.selection_add(item)
def select_list(self):
self.tree_view.selection_set(self.items)
def select_tuple(self):
self.tree_view.selection_set(tuple(self.items))
def clear(self):
self.tree_view.selection_remove(self.tree_view.selection())
def run(self):
self.top.mainloop()
if __name__ == "__main__":
window = TestWindow()
window.run()
I've tested this on Windows 10, macOS 10.14, and Debian Buster, both Python 2 and 3. "Select Space" doesn't work anywhere, "Select Loop" always works, but can be slow, "Select List" only works on Python 3, and "Select Tuple" always works. If you're locked into 2.7.10, this seems to be the solution.