Columnview confusion

It’s a complicated nightmare. All I am trying to do is add rows from an sql database to a columnview.

I can get the column headings to show but only one element from the database row to show. At this point I’m just trying to get each column to show Gtk.Labels but ultimately I’d like at least one of the columns to show something different (EditableLabel. for example).

A rough outline of what I have…

<child>
          <object class="GtkColumnView" id="columnview">
            <property name="model">
              <object class="GtkSingleSelection" id="selection">
                <property name="model">
                  <object class="GListStore" id="liststore">
                    <property name="item-type">DataObject</property>
                  </object>
                </property>
              </object>
            </property>
            <property name="row-factory">
              <object class="GtkSignalListItemFactory" id="factory"/>
            </property>
            <property name="vexpand">True</property>
          </object>
        </child>
class DataObject(GObject.Object):
    __gtype_name__ = 'DataObject'     
    
    def __init__(self, rowid, name, phone_number):
        super().__init__()
        self.rowid = rowid
        self.name = name
        self.phone_number = phone_number

        @GObject.Property(type=str)
        def rowid(self):
            return self.rowid 
        
        @GObject.Property(type=str)
        def name(self):
            return self.name

        @GObject.Property(type=str)
        def phone_number(self):
            return self.phone_number
def factory_setup(factory, item):
    label = Gtk.Label()
    item.set_child(label)
self.factory.connect("setup", factory_setup)

def factory_bind(factory, item):
    item.get_child().set_label(item.get_item().rowid)
self.factory.connect("bind", factory_bind)

headings = ["rowid", "name", "phone_number"]
        for heading in headings:
            column = Gtk.ColumnViewColumn.new(heading, self.factory)
            self.columnview.append_column(column)

for row in database_pull:
    self.liststore.append(DataObject( rowid=str(row[0]),
                                                          name = row[1],
                                                          phone_number = row[2]))

where

print(database_pull)
[(1, 'john', '0794'), (2, 'dave', '0788')]

This puts the rowid in all the cells on each row. (a full row of 1s and second row of 2s).

How do I get the name and phone_number in too ?? I’ve tried adding two more factory_setups and factory_binds for name and phone_number but unsurprisingly, it didn’t work.

As I said at the beginning, ultimately I don’t want to use Gtk.Label for all mu columns but that’s the next hurdle!

Thank you for any help

edit:
I should also add that this code throws up errors for each database row even though it seems to work…

Traceback (most recent call last):
  File "...columnview.py", line 117, in factory_setup
    item.set_child(label)
    ^^^^^^^^^^^^^^
AttributeError: 'ColumnViewRow' object has no attribute 'set_child'

Traceback (most recent call last):
  File "...columnview.py", line 121, in factory_bind
    item.get_child().set_label(item.get_item().rowid)
    ^^^^^^^^^^^^^^
AttributeError: 'ColumnViewRow' object has no attribute 'get_child'

I think I’m there! My sql database has 10 columns (inc rowid) and where it was showing an error for each column on each row it’s now just showing one error for the second column… I can’t work out why it’s picking out my second column but it must a typo somewhere, but it’s working…

<child>
          <object class="GtkColumnView" id="columnview">
            <property name="model">
              <object class="GtkSingleSelection" id="selection">
                <property name="model">
                  <object class="GListStore" id="liststore">
                    <property name="item-type">DataObject</property>
                  </object>
                </property>
              </object>
            </property>
            <property name="row-factory">
              <object class="GtkSignalListItemFactory" id="rowid_factory"/>
              <object class="GtkSignalListItemFactory" id="name_factory"/>
              <object class="GtkSignalListItemFactory" id="phone_number_factory"/>
            </property>
            <property name="vexpand">True</property>
          </object>
        </child>
class DataObject(GObject.Object):
    __gtype_name__ = 'DataObject'     
    
    def __init__(self, rowid, name, phone_number):
        super().__init__()
        self.rowid = rowid
        self.name = name
        self.phone_number = phone_number

        @GObject.Property(type=str)
        def rowid(self):
            return self.rowid 
        
        @GObject.Property(type=str)
        def name(self):
            return self.name

        @GObject.Property(type=str)
        def phone_number(self):
            return self.phone_number
factories = [self.rowid_factory,
             self.name_factory,         
             self.phone_number_factory]     
                
def factory_setup(factory, item):
    label = Gtk.Label()
    item.set_child(label)
      
def rowid_factory_bind(factory, item):
    item.get_child().set_label(item.get_item().rowid)
self.rowid_factory.connect("bind", rowid_factory_bind)

def name_factory_bind(factory, item):
    item.get_child().set_label(item.get_item().name)
self.name_factory.connect("bind", name_factory_bind)

def phone_number_factory_bind(factory, item):
    item.get_child().set_label(item.get_item().phone_number)
self.phone_number_factory.connect("bind", phone_number_factory_bind)

for factory in factories:
    factory.connect("setup", factory_setup)  
    column = Gtk.ColumnViewColumn.new("column_name", factory)
    self.columnview.append_column(column)

for row in database_pull:
    self.liststore.append(DataObject( rowid=str(row[0]), 
                                      name = row[1], 
                                      phone_number = row[2]))

where

print(database_pull)
[(1, 'john', '0794'), (2, 'dave', '0788')]

The item’s type is GObject, you should convert it to GtkListItem, then assign value to its child

void
setup (
  GtkSignalListItemFactory* self,
  GObject* object,
  gpointer user_data
)

Thanks - I ended up just making a collection of factory_setup functions for things like Gtk.DropDown and Gtk.SpinButton then adding an ‘if’ statement in my ‘for factory in factories’.

ie.

for factory in factories:
    if factory == self.rowid_factory:
        factory.connect("setup", factory_setup_spin)
    elif factory == self.name_factory:
        factory.connect("setup", factory_setup_dropdown)
    else:
        factory.connect("setup", factory_setup_entry)    

     column = Gtk.ColumnViewColumn.new("column_name", factory)

I still don’t understand it though. I want things like column 3 to be the combination of user entered data from column 1 and 2, when the user has filled out a row I want the option to create a new empty row and when finished to add each row to the sql database. It’s mind bending.

Is there an alternative to columnview? I just want to display editable row that can be saved in a database, with the option of adding more blank/empty rows.

Hi,

This part is obviously incorrect:

            <property name="row-factory">
              <object class="GtkSignalListItemFactory" id="rowid_factory"/>
              <object class="GtkSignalListItemFactory" id="name_factory"/>
              <object class="GtkSignalListItemFactory" id="phone_number_factory"/>
            </property>

It’s not possible to assign multiple objects to a single property (row-factory here). Gtk will pick only one of them.

I personally never used row-factory, but instead used different GtkListFactory per column. Something like this in XML:

<object class="GtkColumnView" id="columnview">
  <property name="model">
    <object class="GtkSingleSelection" id="selection">
      <property name="model">
        <object class="GListStore" id="liststore">
          <property name="item-type">DataObject</property>
        </object>
      </property>
    </object>
  </property>
  <child>
    <object class="GtkColumnViewColumn" id="rowid_column">
      <property name="title">RowID</property>
      <property name="factory">
        <object class="GtkBuilderListItemFactory" id="rowid_factory"/>/>
      </property>
    </object>
  </child>
  <child>
    <object class="GtkColumnViewColumn" id="name_column">
      <property name="title">Name</property>
      <property name="factory">
        <object class="GtkBuilderListItemFactory" id="name_factory"/>
      </property>
    </object>
  </child>
  <child>
    <object class="GtkColumnViewColumn" id="phone_column">
      <property name="title">Phone Number</property>
      <property name="factory">
        <object class="GtkBuilderListItemFactory" id="phone_number_factory"/>
      </property>
    </object>
  </child>
</object>

There is a good GtkColumnView example (though without XML) here: gtk4_python3_exemples/ListView/column_view.py at main · kriptolix/gtk4_python3_exemples · GitHub

All columns could share a copy of GtkSignalListItemFactory signal handlers, just set the column index for factory, you could see the code model:

Hi guys

I just wanted to pop back to say thank you for your help. I’ve been beavering away every evening at this since my first post and for the most part have done what I set out to do. Your replies certainly helped.

It seemed to work fine but I’m not sure if that was just by chance and there were problems ‘in the post’ for me. I also tried closing each property and it worked to the same effect…

<property name="row-factory">
              <object class="GtkSignalListItemFactory" id="rowid_factory"/>
</property>
<property name="row-factory">
              <object class="GtkSignalListItemFactory" id="name_factory"/>
</property>
...

In the end, I wrote out my xml file the way you suggested and the Python code ended up much neater and overall better (I think!)

I’ve one final hurdle for this columnview which I’ve almost worked out but thank you for helping me get to where I’m at!

1 Like

glad to hear it helped! :slight_smile:

Hey OP and followers. I have tackled these issues a while back, and posted an initial proof-of-concept library to automate the setup of a “datasheet” type widget:

I would greatly appreciate contributions & collaborations. I’d like to restart this work, but my time is stretched very thing. Please take a took and PM me …

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.