Is it possible to populate a liststore without iterating

Is there a way to populate a liststore (up to 20000+ entries) without looping though the entries
ie (in perl), wich a single element array

foreach my $v (@dataarray){

Is there a way to update the liststore directly eg: $model->set(@dataarray) or something.


No, GtkListStore does not have a “bulk insert” API, because GtkTreeView does not have a “bulk update” functionality.

My suggestion would be to implement your own GtkTreeModel-based data store, though you’ll have to emit a GtkTreeModel::row-inserted for every row you added in a bulk operation, which will end up iterating over the data store anyway.

So are there any tips to increase speed of insert for a liststore. The store in question is for an EntryCompletion widget used several places in my app.
Currently it takes 6-9 seconds to populate the backing liststore.
This is prior to the entrycompletion adding the model, so purely the model

Shoving 20k entries in a completion model is not a great plan regardless of performance. You’ll have to filter that data set to be useful, and the bigger the model is, the more expensive is going to be filtering it.

In any case, you should probably break out the population of the list store into chunks, and use the main loop to progressively fill it. An example is available here.

It might be worth putting your list in a database and have the database do the filtering. Then update a liststore with a short list that the completion can use. That way you don’t have to load a lot of data at startup and the database should be pretty fast filtering.

This is a little sqlite program to try out with the idea.


//gcc -Wall completion1.c -o completion1 `pkg-config --cflags --libs gtk+-3.0` -lsqlite3

//Ubuntu18.04 with GTK3.22


static sqlite3 *db=NULL;

static void get_sql_list(GtkEditable *entry, gpointer user_data);
static void initialize_database();
static void close_program(GtkWidget *widget, gpointer data);               

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

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Entry Completion");
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);
    gtk_window_set_default_size(GTK_WINDOW(window), 300, 100);
    g_signal_connect(window, "destroy", G_CALLBACK(close_program), NULL);


    GtkEntryCompletion *completion=gtk_entry_completion_new();

    GtkWidget *entry=gtk_entry_new();
    gtk_widget_set_hexpand(entry, TRUE);
    gtk_entry_set_completion(GTK_ENTRY(entry), completion);
    g_signal_connect(entry, "changed", G_CALLBACK(get_sql_list), completion);

    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), entry, 0, 0, 1, 1);
    gtk_container_add(GTK_CONTAINER(window), grid);

    return 0;   
static void get_sql_list(GtkEditable *entry, gpointer user_data)
    GtkTreeIter iter;
    gint ret_val=0;
    sqlite3_stmt *stmt1=NULL;
    GtkListStore *new_store=NULL;

    //Build a SQL string.
    gchar *sql_string=g_strdup_printf("SELECT CritterName FROM Critters WHERE CritterName LIKE'%s%%' LIMIT 5;", gtk_entry_get_text(GTK_ENTRY(entry)));
    //g_print("%s\n", sql_string);

    //Prepare the SQL statement.
    sqlite3_prepare_v2(db, sql_string, -1, &stmt1, 0);
    new_store=gtk_list_store_new(1, G_TYPE_STRING);

    //Load the list store.
            gtk_list_store_append(new_store, &iter);
            //g_print("Append %s\n", sqlite3_column_text(stmt1, 0));
            gtk_list_store_set(new_store, &iter, 0, sqlite3_column_text(stmt1, 0), -1);            
    if(stmt1!=NULL) sqlite3_finalize(stmt1); 

    //Set up the completion.
    gtk_entry_completion_set_model(GTK_ENTRY_COMPLETION(user_data), GTK_TREE_MODEL(new_store));
    gtk_entry_set_completion(GTK_ENTRY(entry), GTK_ENTRY_COMPLETION(user_data));
    gtk_entry_completion_set_text_column(GTK_ENTRY_COMPLETION(user_data), 0);
static void initialize_database()
    gchar *err_msg=NULL;
    gint rc=sqlite3_open(":memory:", &db);

        g_print("Cannot open database: %s\n", sqlite3_errmsg(db));

    //Add some test data.
    gchar *sql="CREATE TABLE Critters(CritterId INTEGER PRIMARY KEY, CritterName TEXT);" 
               "INSERT INTO Critters VALUES(1, 'Parrot');" 
               "INSERT INTO Critters VALUES(2, 'Chimpanzee');" 
               "INSERT INTO Critters VALUES(3, 'Crow');"
               "INSERT INTO Critters VALUES(4, 'Dolphin');" 
               "INSERT INTO Critters VALUES(5, 'Alligator');" 
               "INSERT INTO Critters VALUES(6, 'Whale');" 
               "INSERT INTO Critters VALUES(7, 'Zebra');" 
               "INSERT INTO Critters VALUES(8, 'Owl');" 
               "INSERT INTO Critters VALUES(9, 'Leopard');" 
               "INSERT INTO Critters VALUES(10, 'Koala');" 
               "INSERT INTO Critters VALUES(11, 'Eagle');" 
               "INSERT INTO Critters VALUES(12, 'Frog');" 
               "INSERT INTO Critters VALUES(13, 'Moose');" 
               "INSERT INTO Critters VALUES(14, 'Kangaroo');" 
               "INSERT INTO Critters VALUES(15, 'Tortoise');" 
               "INSERT INTO Critters VALUES(16, 'Bear');" 
               "INSERT INTO Critters VALUES(17, 'Shark');"
               "INSERT INTO Critters VALUES(18, 'Panda');" 
               "INSERT INTO Critters VALUES(19, 'Penguin');"
               "INSERT INTO Critters VALUES(20, 'Walrus');"
               "INSERT INTO Critters VALUES(21, 'Wolf');"
               "INSERT INTO Critters VALUES(22, 'Woodpecker');"
               "INSERT INTO Critters VALUES(23, 'Piranha');"
               "INSERT INTO Critters VALUES(24, 'Wolvirine');"
               "INSERT INTO Critters VALUES(25, 'Elephant');";

    rc=sqlite3_exec(db, sql, 0, 0, &err_msg);

    if (rc!=SQLITE_OK) 
        g_print("Failed to create table\n");
        g_print("SQL error: %s\n", err_msg);
static void close_program(GtkWidget *widget, gpointer data)

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