1

I'm a newbie to Gtk3 but I can't find how to do what I want anywhere. I'm trying to get a tree view representing article citations.

Desired outcome:

  • columns are resizable
  • no horizontal scrollbar
  • columns take only as much space as needed, they don't expand the window if content is too long
  • in case a cell's content is too long, either break the text over several lines (best) or trim it and add "..." (ok), just trim it (I could settle for that)

As an example of what I want, here's Zotero trimming columns with "..."

Zotero can do it, why not me?

This is my widget hierarchy:

Widget hierarchy

What I tried (using Glade + C):

  1. Default settings: a horizontal scrollbar appears
  2. Set ScrolledWindow horizontal scroll policy to "Never", auto sizing to column: window expands to fit content, e.g. A tragically wide window
  3. Set ScrolledWindow horizontal scroll policy to "Never", fixed sizing columns, with maximum width: contents is trimmed (not "...", no text reflow), but I can only resize columns to the arbiratry size I've given them.
  4. Set ScrolledWindow horizontal scroll policy to "External", auto sizing columns, columns set to resizable: columns are not resizable, contents is not trimmed.

Here's variation 4 with source + XML file generated by Glade:

#include <gtk/gtk.h>

void on_window_main_destroy();

enum {
    AUTHORS_COLUMN = 0,
    TITLE_COLUMN,
    N_COLUMNS
};

static void init_reference_list(GtkBuilder* builder)
{
    GtkCellRenderer*   renderer;
    GtkWidget*         tree_widget;
    tree_widget = GTK_WIDGET(gtk_builder_get_object(builder, "tree_view"));

    // -- Add attributes to Glade-generated columns
    GtkTreeViewColumn* column;
    renderer = gtk_cell_renderer_text_new();
    column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "title"));
    gtk_tree_view_column_pack_start(column, renderer, FALSE);
    gtk_tree_view_column_add_attribute(column, renderer, "text", TITLE_COLUMN ); 
    column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "authors"));
    gtk_tree_view_column_pack_start(column, renderer, FALSE);
    gtk_tree_view_column_add_attribute(column, renderer, "text", AUTHORS_COLUMN );
    // -- Set up store and connect it to view
    GtkListStore* store;
    store = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING ); 
    gtk_tree_view_set_model(GTK_TREE_VIEW(tree_widget), GTK_TREE_MODEL(store));


    // -- Placing fake data in store
    char title[]   =  "A long long long long long long long long long long long long long long long long long long long long long long long long  long long long long long long long long long long title";
    char authors[] =  "Me You Us Them All of us";
    GtkTreeIter iter;
    int i;
    for (int i = 0; i < 500; ++i)
    {
        gtk_list_store_append(store, &iter);
        gtk_list_store_set(store, &iter, AUTHORS_COLUMN, authors, TITLE_COLUMN,   title, -1 );
    }

}

// called when window is closed
void on_window_main_destroy()
{
    gtk_main_quit();
}


int main(int argc, char *argv[])
{
        gtk_init(&argc, &argv);

        // -- load builder
        GtkBuilder* builder; 
        builder = gtk_builder_new();
        gtk_builder_add_from_file (builder, "resources/ui/ref_search.glade", NULL);
        gtk_builder_connect_signals(builder, NULL);

        // -- Cell Renderer and fake data
        init_reference_list(builder);

        // -- Launch
        GtkWidget         *window;
        window  = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
        gtk_widget_show(window);     
        g_object_unref(builder);
        gtk_main();

        return 0;
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkEntryBuffer" id="search_buffer"/>
  <object class="GtkWindow" id="window_main">
    <property name="can_focus">False</property>
    <property name="halign">baseline</property>
    <property name="valign">baseline</property>
    <property name="title" translatable="yes">Reference Manager</property>
    <property name="resizable">False</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkSearchEntry" id="search_bar">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="buffer">search_buffer</property>
            <property name="primary_icon_name">edit-find-symbolic</property>
            <property name="primary_icon_activatable">False</property>
            <property name="primary_icon_sensitive">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="hscrollbar_policy">external</property>
            <property name="shadow_type">in</property>
            <property name="max_content_height">500</property>
            <child>
              <object class="GtkTreeView" id="tree_view">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="rules_hint">True</property>
                <property name="enable_search">False</property>
                <property name="show_expanders">False</property>
                <property name="enable_grid_lines">horizontal</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection"/>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="authors">
                    <property name="resizable">True</property>
                    <property name="sizing">autosize</property>
                    <property name="title" translatable="yes">Author(s)</property>
                    <property name="expand">True</property>
                    <property name="clickable">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="title">
                    <property name="resizable">True</property>
                    <property name="sizing">autosize</property>
                    <property name="title" translatable="yes">Title</property>
                    <property name="expand">True</property>
                    <property name="clickable">True</property>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Apologies if I'm missing the obvious!

Ahmad B
  • 117
  • 7
  • When you get to this level or formatting, builder scripts are worthless, go to the manual. I'd start with [gtk_tree_view_column_set_fixed_width ()](https://developer.gnome.org/gtk3/stable/GtkTreeViewColumn.html#gtk-tree-view-column-set-fixed-width) – David C. Rankin Jun 05 '21 at 01:56

1 Answers1

0

This might be closer to what you are looking for in the Glade file:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkListStore" id="liststore1">
    <columns>
      <!-- column-name authors -->
      <column type="gchararray"/>
      <!-- column-name titles -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0" translatable="yes">Me You Us Them All of us</col>
        <col id="1" translatable="yes">A long long long long long long long long long long long long long long long long long long long long long long long long  long long long long long long long long long long title</col>
      </row>
    </data>
  </object>
  <object class="GtkEntryBuffer" id="search_buffer"/>
  <object class="GtkWindow" id="window_main">
    <property name="can_focus">False</property>
    <property name="halign">baseline</property>
    <property name="valign">baseline</property>
    <property name="title" translatable="yes">Reference Manager</property>
    <property name="resizable">False</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkSearchEntry" id="search_bar">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="buffer">search_buffer</property>
            <property name="primary_icon_name">edit-find-symbolic</property>
            <property name="primary_icon_activatable">False</property>
            <property name="primary_icon_sensitive">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="hscrollbar_policy">external</property>
            <property name="shadow_type">in</property>
            <property name="max_content_height">500</property>
            <child>
              <object class="GtkTreeView" id="tree_view">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">liststore1</property>
                <property name="rules_hint">True</property>
                <property name="enable_search">False</property>
                <property name="show_expanders">False</property>
                <property name="enable_grid_lines">horizontal</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection"/>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="authors">
                    <property name="resizable">True</property>
                    <property name="sizing">fixed</property>
                    <property name="title" translatable="yes">Author(s)</property>
                    <property name="expand">True</property>
                    <property name="clickable">True</property>
                    <child>
                      <object class="GtkCellRendererText">
                        <property name="ellipsize">middle</property>
                      </object>
                      <attributes>
                        <attribute name="text">0</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="title">
                    <property name="resizable">True</property>
                    <property name="sizing">fixed</property>
                    <property name="title" translatable="yes">Title</property>
                    <property name="expand">True</property>
                    <property name="clickable">True</property>
                    <child>
                      <object class="GtkCellRendererText">
                        <property name="ellipsize">middle</property>
                      </object>
                      <attributes>
                        <attribute name="text">1</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Edit with another attempt:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkListStore" id="liststore1">
    <columns>
      <!-- column-name authors -->
      <column type="gchararray"/>
      <!-- column-name titles -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0" translatable="yes">Me You Us Them All of us</col>
        <col id="1" translatable="yes">A long long long long long long long long long long long long long long long long long long long long long long long long  long long long long long long long long long long title</col>
      </row>
    </data>
  </object>
  <object class="GtkEntryBuffer" id="search_buffer"/>
  <object class="GtkWindow" id="window_main">
    <property name="width_request">250</property>
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Reference Manager</property>
    <property name="resizable">False</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkSearchEntry" id="search_bar">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="buffer">search_buffer</property>
            <property name="primary_icon_name">edit-find-symbolic</property>
            <property name="primary_icon_activatable">False</property>
            <property name="primary_icon_sensitive">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="hscrollbar_policy">never</property>
            <property name="shadow_type">in</property>
            <property name="max_content_height">500</property>
            <child>
              <object class="GtkTreeView" id="tree_view">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">liststore1</property>
                <property name="rules_hint">True</property>
                <property name="enable_search">False</property>
                <property name="show_expanders">False</property>
                <property name="enable_grid_lines">horizontal</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection"/>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="authors">
                    <property name="resizable">True</property>
                    <property name="sizing">fixed</property>
                    <property name="min_width">25</property>
                    <property name="title" translatable="yes">Author(s)</property>
                    <property name="expand">True</property>
                    <property name="clickable">True</property>
                    <child>
                      <object class="GtkCellRendererText">
                        <property name="ellipsize">middle</property>
                      </object>
                      <attributes>
                        <attribute name="text">0</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="title">
                    <property name="resizable">True</property>
                    <property name="min_width">25</property>
                    <property name="title" translatable="yes">Title</property>
                    <property name="expand">True</property>
                    <property name="clickable">True</property>
                    <child>
                      <object class="GtkCellRendererText">
                        <property name="ellipsize">middle</property>
                      </object>
                      <attributes>
                        <attribute name="text">1</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
theGtknerd
  • 3,647
  • 1
  • 13
  • 34
  • Ah almost! (For those who missed it, like me, the "..." options is a property of the cell renderer not the column ; it's called ellipsizing). There is one remaining problem: after resizing the column, the "..." just disappears and the overflow content is hidden. [Here](https://imgur.com/JJmygh6) for demo. Can we ensure that ellipsizing happens for narrow columns no matter how narrow? – Ahmad B Jun 05 '21 at 14:44
  • Change the horizontal scroll property on the ScrolledWindow to `Never`. And the final Gtk.Treeview column has some nuances I don't totally understand yet. You may have to add one more blank column. – theGtknerd Jun 06 '21 at 02:16
  • I tried changing the horizontal scroll policy to Never ; the result is the same. I added a blank column, but that did not help either and the dummy column is visible on resizing. – Ahmad B Jun 14 '21 at 00:35
  • Try my changes. You know, a bit of fiddling on your part would probably be a good learning tool. We aren't a replacement for hands on learning. – theGtknerd Jun 14 '21 at 11:50
  • I am aware of the educational value of fiddling, thanks! I did attempt a number of modifications using your original Glade file and comments as a starting point. I actually came up with what you suggest but was dissatisfied with the fact that after a certain point, resizing the column resizes the whole window. Since this desideratum was not part of the original question, I'll validate your answer. – Ahmad B Jun 16 '21 at 22:27
  • Hmmm, yeah I can't figure out any way to prohibit the window from widening. – theGtknerd Jun 18 '21 at 16:17