Python Forum

Full Version: Scrollable Treeview: change behavior of Prior/Next keys?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
My program has two components I want to control via the keyboard, an image that moves up/down/left/right within a canvas, and a scrollable Treeview that controls the coloring of the image.
Treeview and movable image
Currently the Left, Right, Next, and Prior keys control the image placement, and the Up and Down keys control the selected coloring in the Treeview. It works.

But what I really want is to swap the behavior of the Up key with the Prior key, and the Down key with the Next key, so I can use the arrow keys to control the image placement, and Prior/Next to do what Up/Down would normally do in the Treeview. The problem is getting the Prior and Next keys to do what the Up and Down keys would normally do in the Treeview. Is this even possible? Here's what my current code looks like:
class PartTree(ttk.Treeview):
    """ Using code based on discussion with boughtonp at
            https://www.linuxquestions.org/questions/showthread.php?p=6235877#post6235877
            to not change selection when using <Up> and <Down>
    """

    def __init__(self, parent=None):
        super().__init__(parent, columns=('Part1', 'Part2'))

        # code omitted 
        
        # Force Treeview not to respond to PgDn/PgUp
        self.unbind_class('Treeview', '<KeyPress-Next>')
        self.unbind_class('Treeview', '<KeyPress-Prior>')
        self.unbind_class('Treeview', '<KeyPress-Next>')
        self.unbind_class('Treeview', '<KeyPress-Prior>')

        # grab focus when Up/Dn released (after highlight bar has moved)
        self.bind_class('Treeview', '<KeyRelease-Up>', self.set_selection)
        self.bind_class('Treeview', '<KeyRelease-Down>', self.set_selection)

    # ----------------------------------
    def set_selection(self,event):
        """ Set focus to currently highlighted partitioning """

        self.current_selection = event.widget.selection();
        self.focus(self.current_selection)
If you want to embed a dropbox image use the image button and replace ?dl=0 with ?raw=1


[Image: Screenshot%20at%202021-04-09%2011-56-06.png?raw=1]
Figured it out. Unbinding the ability of a PartTree's to respond to Up/Down and Prior/Next, and handling the Prior and Next keys via ConvexHull's on_tree_select method looks like it does what I want.
class PartTree(ttk.Treeview):
    """ Using code based on discussion with boughtonp at
            https://www.linuxquestions.org/questions/showthread.php?p=6235877#post6235877
            to not change selection when using <Up> and <Down>
    """

    def __init__(self, parent=None):

        # Force Treeview not to respond to Up/Down
        self.unbind_class('Treeview', '<KeyPress-Down>')
        self.unbind_class('Treeview', '<KeyPress-Up>')
        self.unbind_class('Treeview', '<KeyPress-Down>')
        self.unbind_class('Treeview', '<KeyPress-Up>')

        # Force Treeview not to respond normally to PgDn/PgUp
        self.unbind_class('Treeview', '<KeyPress-Next>')
        self.unbind_class('Treeview', '<KeyPress-Prior>')
        self.unbind_class('Treeview', '<KeyRelease-Next>')
        self.unbind_class('Treeview', '<KeyRelease-Prior>')

    # ----------------------------------
    def scroll_the_tree(self, key):
        """ Finally got this working! Tree will scroll using the
            PgUp ('Prior') and PgDown ('Next') keys.
        """
        delta = -1 if key=='Prior' else 1

        knt = len(self.get_children())

        int_cs = int(self.selected_row)
        int_cs += delta
        int_cs = max(0, int_cs)
        int_cs = min(int_cs, knt-1)

        self.selection_set(int_cs)
        self.focus(int_cs)
        self.see(int_cs)

        ...

 # ======================================================================
class ConvexHull(tk.Tk):

    def initUI(self):

        # create the partitionings tree and its scrollbar
        self.part_tree = PartTree(l_canvas)
        self.tree_scroll = ttk.Scrollbar(l_canvas, orient="vertical", command=self.part_tree.yview)
        self.part_tree.configure(yscrollcommand=self.tree_scroll.set)

        # when new partitioning selected, do what's necessary
        self.part_tree.bind('<ButtonRelease-1>',  self.on_tree_select)
        self.part_tree.bind('<KeyRelease-Prior>', self.on_tree_select)
        self.part_tree.bind('<KeyRelease-Next>',  self.on_tree_select)

    # ----------------------------------
    def on_tree_select(self, event):

        # do this only on selection by keypress
        key = event.keysym
        if key in {'Prior', 'Next'}:
            self.part_tree.scroll_the_tree(key)

        # do the following regardless of how selection was made
        ...