Search code examples
pythontreeviewpygobject

Different models for different level TreeView nodes


Let's say I have a TreeView (with a backing TreeStore) that represents a list of products.

A Product has the following specifications:

  1. Name
  2. Catalog Number
  3. Comment

Also, each product has a list of Components that it is constructed of. I want to display data about the components in the sub-nodes of the tree (so it would be, basically, a 2-level treeview), but then the top-level nodes will have a different model the the sub-nodes.

How can I accomplish it using Glade (Or if neccessery, through Python+PyGObjecy)?


Solution

  • You can only have one model per TreeView, but you can make a model that in realty are two (or more) models glued together, and add some boolean columns that controls which model should that line be displaying. Then, you add a set of CellRenderers and map it's visibility to those control columns.

    The difficulty of this is when you want that the column had a name displayed on the top, in that case it can be difficult to order the information. If you can wireframe how you want the Tree to look like I can offer a base example implementation.

    == EDIT ==

    This is one example:

    main.py:

    from gi.repository import Gtk
    from os.path import abspath, dirname, join
    
    WHERE_AM_I = abspath(dirname(__file__))
    
    # My Model map
    mm = {
        'name'        : 0,
        'catalog_num' : 1,
        'comment'     : 2,
        'component'   : 3,
        'is_top'      : 4,
        'is_child'    : 5,
    }
    
    class MyApp(object):
    
        def __init__(self):
            """
            Build GUI
            """
    
            # Build GUI from Glade file
            self.builder = Gtk.Builder()
            self.glade_file = join(WHERE_AM_I, 'gui.glade')
            self.builder.add_from_file(self.glade_file)
    
            # Get objects
            go = self.builder.get_object
            self.window = go('window')
            self.treestore = go('treestore')
    
            # Fill model
            self._load_model()
    
            # Connect signals
            self.builder.connect_signals(self)
            self.window.connect('delete-event', lambda x,y: Gtk.main_quit())
    
            # Everything is ready
            self.window.show()
    
    
        def _load_model(self):
    
            my_data = [
                    ['Cheese', 'F001', 'This is the best cheese ever!', '', True, False],
                    ['Pepperoni', 'F002', 'Delicious pepperoni :}', '', True, False],
                    ['Pepperonni Pizza', 'P001', 'Yes, I\'m hungry :(', '', True, False],
                    ['', '', None, 'Cheese', False, True],
                    ['', '', None, 'Pepperonni', False, True],
                ]
    
            parent = None
            for i in my_data:
                if i[mm['is_child']]:
                    self.treestore.append(parent, i)
                else:
                    parent = self.treestore.append(None, i)
    
    
    if __name__ == '__main__':
        gui = MyApp()
        Gtk.main()
    

    gui.glade:

    <?xml version="1.0" encoding="UTF-8"?>
    <interface>
      <!-- interface-requires gtk+ 3.0 -->
      <object class="GtkTreeStore" id="treestore">
        <columns>
          <!-- column-name name -->
          <column type="gchararray"/>
          <!-- column-name catalog_num -->
          <column type="gchararray"/>
          <!-- column-name comment -->
          <column type="gchararray"/>
          <!-- column-name component -->
          <column type="gchararray"/>
          <!-- column-name is_top -->
          <column type="gboolean"/>
          <!-- column-name is_child -->
          <column type="gboolean"/>
        </columns>
      </object>
      <object class="GtkWindow" id="window">
        <property name="can_focus">False</property>
        <property name="border_width">10</property>
        <property name="title" translatable="yes">TreeView test</property>
        <property name="window_position">center-always</property>
        <property name="default_width">400</property>
        <property name="default_height">300</property>
        <child>
          <object class="GtkScrolledWindow" id="scrolledwindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="shadow_type">in</property>
            <child>
              <object class="GtkTreeView" id="treeview">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">treestore</property>
                <property name="headers_visible">False</property>
                <property name="headers_clickable">False</property>
                <property name="search_column">1</property>
                <property name="tooltip_column">2</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection" id="treeview-selection"/>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="treeviewcolumn_name">
                    <property name="title" translatable="yes">Name</property>
                    <child>
                      <object class="GtkCellRendererText" id="cellrenderertext_name"/>
                      <attributes>
                        <attribute name="visible">4</attribute>
                        <attribute name="text">0</attribute>
                      </attributes>
                    </child>
                    <child>
                      <object class="GtkCellRendererText" id="cellrenderertext_component"/>
                      <attributes>
                        <attribute name="visible">5</attribute>
                        <attribute name="text">3</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="treeviewcolumn_catalog_num">
                    <property name="title" translatable="yes">Catalog #</property>
                    <child>
                      <object class="GtkCellRendererText" id="cellrenderertext_catalog"/>
                      <attributes>
                        <attribute name="visible">4</attribute>
                        <attribute name="text">1</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
        </child>
      </object>
    </interface>
    

    Code can also be found at: https://gist.github.com/carlos-jenkins/5555283