3

I'm making an application on gtk4 and I have a need to display a table with 5 columns. I realized that now the best widget for this would be columnview, I found a small working example but only for outputting directory files and could only figure out half of it. Can anyone show a working example of a widget that accepts strings in C?

In the example, I tried to change the accepted type of the g_list_store_new function from G_TYPE_FILE_INFO to G_TYPE_STRING. But when starting the program, it gave an error.

Compilation : gcc -o a e.c $(pkg-config --cflags --libs gtk4)

File example link: github repository

2
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a minimal reproducible example. Commented Oct 20, 2023 at 0:32
  • I'm having the same problem trying to populate a dropdown menu. Program compiles but at run time I get g_list_store_new: assertion 'g_type_is_a (item_type, G_TYPE_OBJECT)' failed. Commented Sep 27, 2024 at 14:40

1 Answer 1

7

Views (such as GTKColumnView) display data from a model. In GTK4, there are generic list model implementations, such as GListStore, that allow you to create lists of arbitrary objects. To add multiple columns to a GListStore, you'll need to create a custom type that contains the data for each column. This type must be derived from GObject and have the appropriate properties for each column. You can then use the g_list_store_new() function to create a new GListStore with this type as a item_type. You'll also need one factory per column. Everything else can be found in the following listing.

 /*
  * The sole purpose of this program is to test some approaches to using 
  * columnview with GTK4 and C. It may contain errors and does not 
  * claim to be considered "best practice".
  */

#include<gtk/gtk.h>

#define CAPITAL_TYPE_ITEM (capital_item_get_type())
G_DECLARE_FINAL_TYPE (CapitalItem, capital_item, CAPITAL, ITEM, GObject)

struct _CapitalItem
{
    GObject parent_instance;
    const char *name;
    const char *country;
    const char *founded;
    const char *population;
    const char *area;
};

struct _CapitalItemClass
{
    GObjectClass parent_class;
};

G_DEFINE_TYPE (CapitalItem, capital_item, G_TYPE_OBJECT)

static void capital_item_init(CapitalItem *item)
{
}

static void capital_item_class_init(CapitalItemClass *class)
{
}

static CapitalItem * capital_item_new(const char *name,
                const char *country,
                const char *founded,
                const char *population,
                const char *area )
{
    CapitalItem  *item = g_object_new(CAPITAL_TYPE_ITEM, NULL);
    item->name = g_strdup(name);
    item->country = g_strdup(country);
    item->founded = g_strdup(founded);
    item->population = g_strdup(population);
    item->area = g_strdup(area);
    return item;
}

// a funktion that creates a GListModel with capital_item  objects
GListModel * create_capital_model(void)
{
    GListStore *store = g_list_store_new(G_TYPE_OBJECT);
    g_list_store_append(store, capital_item_new("Washington,D.C.","USA","1790","712,816","177"));
    g_list_store_append(store, capital_item_new("London","Britain","43","8,799,800","1,572.03"));
    g_list_store_append(store, capital_item_new("Paris","France","3rd c. BC","2,161,000","105"));
    g_list_store_append(store, capital_item_new("Berlin","Germany","13th century","3,850,809","891.3"));
    g_list_store_append(store, capital_item_new("Rome","Italy","753 BC","2,860,009","1,285"));
    return G_LIST_MODEL(store);
}

static const char* capital_item_get_name(CapitalItem *item)
{
    return item->name;
}

static const char* capital_item_get_country(CapitalItem *item)
{
    return item->country;
}

static const char* capital_item_get_founded(CapitalItem *item)
{
    return item->founded;
}

static const char* capital_item_get_population(CapitalItem *item)
{
    return item->population;
}

static const char* capital_item_get_area(CapitalItem *item)
{
    return item->area;
}

static void setup_cb(GtkSignalListItemFactory *factory,GObject  *listitem)
{
    GtkWidget *label =gtk_label_new(NULL);
    gtk_list_item_set_child(GTK_LIST_ITEM(listitem),label);
}

static void bind_name_cb(GtkSignalListItemFactory *factory, GtkListItem *listitem)
{
    GtkWidget *label = gtk_list_item_get_child(listitem);
    GObject *item = gtk_list_item_get_item(GTK_LIST_ITEM(listitem));
    const char *string = capital_item_get_name(CAPITAL_ITEM(item));
    gtk_label_set_text(GTK_LABEL (label), string);
}

static void bind_country_cb(GtkSignalListItemFactory *factory, GtkListItem *listitem)
{
    GtkWidget *label = gtk_list_item_get_child(listitem);
    GObject *item = gtk_list_item_get_item(GTK_LIST_ITEM(listitem));
    const char *string = capital_item_get_country(CAPITAL_ITEM(item));
    gtk_label_set_text(GTK_LABEL (label), string);
}

static void bind_founded_cb(GtkSignalListItemFactory *factory, GtkListItem *listitem)
{
    GtkWidget *label = gtk_list_item_get_child(listitem);
    GObject *item = gtk_list_item_get_item(GTK_LIST_ITEM(listitem));
    const char *string = capital_item_get_founded(CAPITAL_ITEM(item));
    gtk_label_set_text(GTK_LABEL (label), string);
}

static void bind_population_cb(GtkSignalListItemFactory *factory, GtkListItem *listitem)
{
    GtkWidget *label = gtk_list_item_get_child(listitem);
    GObject *item = gtk_list_item_get_item(GTK_LIST_ITEM(listitem));
    const char *string = capital_item_get_population(CAPITAL_ITEM(item));
    gtk_label_set_text(GTK_LABEL (label), string);
}

static void bind_area_cb(GtkSignalListItemFactory *factory, GtkListItem *listitem)
{
    GtkWidget *label = gtk_list_item_get_child(listitem);
    GObject *item = gtk_list_item_get_item(GTK_LIST_ITEM(listitem));
    const char *string = capital_item_get_area(CAPITAL_ITEM(item));
    gtk_label_set_text(GTK_LABEL (label), string);
}

static void activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *scrolled_window;
    GtkListItemFactory *factory;
    GListModel *model;
    GtkSingleSelection *selection;
    GtkColumnViewColumn *column;
    GtkWidget *cv;

    model = create_capital_model();
    selection = gtk_single_selection_new(G_LIST_MODEL(model));
    gtk_single_selection_set_autoselect(selection,TRUE);

    window = gtk_application_window_new(app);
    gtk_window_set_title (GTK_WINDOW(window), "ColumnView Example");
    gtk_window_set_default_size (GTK_WINDOW(window), 470, 200);
    scrolled_window = gtk_scrolled_window_new ();
    gtk_window_set_child (GTK_WINDOW(window), scrolled_window);

    cv = gtk_column_view_new(GTK_SELECTION_MODEL (selection));
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled_window),cv);
    gtk_column_view_set_show_column_separators (GTK_COLUMN_VIEW (cv),TRUE);
    // one factory for each column
    factory = gtk_signal_list_item_factory_new();
    g_signal_connect(factory, "setup", G_CALLBACK(setup_cb),NULL);
    g_signal_connect(factory, "bind", G_CALLBACK(bind_name_cb),NULL);
    column = gtk_column_view_column_new("capital city", factory);
    gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column);
    g_object_unref (column);

    factory = gtk_signal_list_item_factory_new();
    g_signal_connect(factory, "setup", G_CALLBACK(setup_cb),NULL);
    g_signal_connect(factory, "bind", G_CALLBACK(bind_country_cb),NULL);
    column = gtk_column_view_column_new("country", factory);
    gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column);
    g_object_unref (column);

    factory = gtk_signal_list_item_factory_new();
    g_signal_connect(factory, "setup", G_CALLBACK(setup_cb),NULL);
    g_signal_connect(factory, "bind", G_CALLBACK(bind_founded_cb),NULL);
    column = gtk_column_view_column_new("founded", factory);
    gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column);
    g_object_unref (column);

    factory = gtk_signal_list_item_factory_new();
    g_signal_connect(factory, "setup", G_CALLBACK(setup_cb),NULL);
    g_signal_connect(factory, "bind", G_CALLBACK(bind_population_cb),NULL);
    column = gtk_column_view_column_new("population", factory);
    gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column);
    g_object_unref (column);

    factory = gtk_signal_list_item_factory_new();
    g_signal_connect(factory, "setup", G_CALLBACK(setup_cb),NULL);
    g_signal_connect(factory, "bind", G_CALLBACK(bind_area_cb),NULL);
    column = gtk_column_view_column_new("area (km²)", factory);
    gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column);
    g_object_unref (column);

    gtk_window_present (GTK_WINDOW (window));
}

int main (int argc, char **argv)
{
    GtkApplication *app; int status;

    app = gtk_application_new("org.gtk.columnview",G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate",G_CALLBACK(activate),NULL);
    status = g_application_run (G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}

and this is what it should look like

Sign up to request clarification or add additional context in comments.

3 Comments

If you also want to sort, look here stackoverflow.com/q/78157727/22768315
Taking this example, how can I use g_object_bind_property to change values in your CapitalItem model? Foe example, in the screenshot: Paris -> México.
Sorry. But discussions or conversations are not desired here and may be sanctioned :-(. I recommend therefore asking a new question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.