0

I want to implement a feature which will allow user to navigate in Gtk.TreeView widget by arrow keys, unfortunately select_iter() method is not doing what I was expecting from it, i. e. it fails to select parent node of selected node :P

And now I need explanation why it's not working or hint on some kind of workaround of this issue.

Below is ready to run test program which demonstrates this problem. Problematic line of code is tagged with #FIXME.

from gi.repository import Gtk
from gi.repository import Gdk


class WizardManager(Gtk.Dialog):
    '''Dialog window which makes possible to choose type of resource to create by editor.'''
    def __init__(self, parent):
        super().__init__('Wizard manager', parent,  Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT)
        self.set_default_response(Gtk.ResponseType.OK)
        self.set_decorated(False)
        self.set_size_request(640, 480)
        vbox = self.get_content_area()
        self.__tree_store = Gtk.TreeStore(str)
        self.__tree_view = Gtk.TreeView(self.__tree_store)
        self.__tree_view.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.__tree_view.connect('key-press-event', self.__on_tree_view_key_press)
        self.__tree_view.set_headers_visible(False)
        text_renderer = Gtk.CellRendererText()
        text_column1 = Gtk.TreeViewColumn(None, text_renderer)
        text_column1.add_attribute(text_renderer, 'text', 0)
        self.__tree_view.append_column(text_column1)
        scrolled_window = Gtk.ScrolledWindow()
        scrolled_window.add(self.__tree_view)
        vbox.pack_start(scrolled_window, True, True, 0)
        self.__populate_tree_store()
        self.show_all()

    def __on_tree_view_key_press(self, tree_view, event):
        # TODO Implement tree navigation with arrow keys
        tree_selection = tree_view.get_selection()
        selected_iter = tree_selection.get_selected()[1]
        if selected_iter:
            selected_tree_path = self.__tree_store.get_path(selected_iter)
            # Right arrow and Return should expand selected node.
            if event.keyval == Gdk.KEY_Right or event.keyval == Gdk.KEY_Return:
                tree_view.expand_row(selected_tree_path, False)
            # Left arrow should collapse node or select it parent.
            elif event.keyval == Gdk.KEY_Left:
                if not tree_view.collapse_row(selected_tree_path):
                    # Unable to collapse node it must be empty. select it's parent.
                    parent_iter = selected_iter.copy()
                    if self.__tree_store.iter_parent(parent_iter):
                        # FIXME Why select_iter() executes without error and is not able to select parent node?
                        # same goes for select_path() :P
                        tree_selection.select_iter(parent_iter)

    def __populate_tree_store(self):
        # Ordinary resources
        self.__tree_store.append(None, ('File',))
        self.__tree_store.append(None, ('Directory',))

        # Python files
        python_dir = self.__tree_store.append(None, ('Python',))
        self.__tree_store.append(python_dir, ('Python module',))
        self.__tree_store.append(python_dir, ('Python package',))

        # Django files
        django_dir = self.__tree_store.append(python_dir, ('Django',))
        self.__tree_store.append(django_dir, ('Django project',))
        self.__tree_store.append(django_dir, ('Django app',))

if __name__ == '__main__':
    app = Gtk.Window(Gtk.WindowType.TOPLEVEL)
    app.connect('destroy', lambda a: Gtk.main_quit())
    dlg = WizardManager(app)
    dlg.run()
    dlg.destroy()
    Gtk.main()
BPS
  • 1,133
  • 1
  • 17
  • 38

1 Answers1

0

Here you have a hint!

#! /usr/bin/python

###########################################################
#
# Basic Gtk.TreeView Example with two sortable columns
#
###########################################################


# use  the new PyGObject binding
from gi.repository import Gtk
import os
import getpass # this is only to automatically print your home folder.

class MyWindow(Gtk.Window):

    def __init__(self):

        Gtk.Window.__init__(self, title='My Window Title')
        self.connect('delete-event', Gtk.main_quit)        

        # Gtk.ListStore will hold data for the TreeView
        # Only the first two columns will be displayed
        # The third one is for sorting file sizes as numbers
        store = Gtk.ListStore(str, str, long)
        # Get the data - see below
        self.populate_store(store)

        treeview = Gtk.TreeView(model=store)

        # The first TreeView column displays the data from
        # the first ListStore column (text=0), which contains
        # file names
        renderer_1 = Gtk.CellRendererText()        
        column_1 = Gtk.TreeViewColumn('File Name', renderer_1, text=0)
        # Calling set_sort_column_id makes the treeViewColumn sortable
        # by clicking on its header. The column is sorted by
        # the ListStore column index passed to it 
        # (in this case 0 - the first ListStore column) 
        column_1.set_sort_column_id(0)        
        treeview.append_column(column_1)

        # xalign=1 right-aligns the file sizes in the second column
        renderer_2 = Gtk.CellRendererText(xalign=1)
        # text=1 pulls the data from the second ListStore column
        # which contains filesizes in bytes formatted as strings
        # with thousand separators
        column_2 = Gtk.TreeViewColumn('Size in bytes', renderer_2, text=1)
        # Mak the Treeview column sortable by the third ListStore column
        # which contains the actual file sizes
        column_2.set_sort_column_id(1)
        treeview.append_column(column_2)

        # Use ScrolledWindow to make the TreeView scrollable
        # Otherwise the TreeView would expand to show all items
        # Only allow vertical scrollbar
        scrolled_window = Gtk.ScrolledWindow()
        scrolled_window.set_policy(
            Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scrolled_window.add(treeview)
        scrolled_window.set_min_content_height(200)

        self.add(scrolled_window)
        self.show_all()

    def populate_store(self, store):

        directory = '/home/'+getpass.getuser()
        for filename in os.listdir(directory):
            size = os.path.getsize(os.path.join(directory, filename))
            # the second element is displayed in the second TreeView column
            # but that column is sorted by the third element
            # so the file sizes are sorted as numbers, not as strings
            store.append([filename, '{0:,}'.format(size), size])       

# The main part:
win = MyWindow()
Gtk.main()