Re: Question about TreeView particularly GtkCellRendererCombo



Please excuse me asking 3 further questions on this excellent example
which does just what I want:

1. Given that this is a dialog which may be popped up and dismissed
several times whilst the application runs, do I need to do any
g_object_unrefs on any of the list stores or other parts to avoid memory
leaks?

2. Given that the type field in my structure is an integer, do I take it
that the appropriate starting type cannot be selected nor the final
value extracted when the dialog completes out of the combo as an
integer, I have to make the list column a string and insert the
appropriate string and decipher the appropriate string at the end as the
Combo renderer is based on a text entry so there is no equivalent of
xxxx_get_active() like I have with a "standalone" combo box?

3. Is there a sensible way without speaking pixels that I can say "allow
for at least n rows initially" as if my initial list is empty or has
only one row the thing is stupidly small (I am using a scroll on the
treeview as it could get arbitrarily large).

On Wed, 2008-12-10 at 20:13 +0100, Tadej BorovÅak wrote:

Hi.

I'm afraid that the ideal solution cannot be achieved since you would
need 2 different renderers on the same place. The second proposed
solution can be achieved and it's quite simple to code.

And since the example can say more than a thousand words, I wrote a
simple application to demonstrate some techniques I use (they may not
be the best, but they work).

---------------
#include <gtk/gtk.h>

enum
{
    TYPE_COL,
    TEXT_COL,
    TEXT_SENS_COL,
    INT_COL,
    INT_SENS_COL,
    NO_COLS
};


static void
cb_type_changed( GtkCellRendererText *renderer,
                 gchar               *path,
                 gchar               *new_text,
                 GtkListStore        *master )
{
    GtkTreeIter   iter;
    gchar        *old_text;
    gboolean      text_sens = FALSE;
    gboolean      int_sens = FALSE;

    /* Get previous value from master model */
    gtk_tree_model_get_iter_from_string( GTK_TREE_MODEL( master ),
                                         &iter, path );
    gtk_tree_model_get( GTK_TREE_MODEL( master ), &iter,
                        TYPE_COL, &old_text, -1 );

    /* Do we need to change anything? */
    if( ! g_strcmp0( old_text, new_text ) )
        return;

    /* What changes are needed? */
    if( ! g_strcmp0( new_text, "String" ) )
        text_sens = TRUE;
    else if( ! g_strcmp0( new_text, "Integer" ) )
        int_sens = TRUE;

    /* Update master model */
    gtk_list_store_set( master, &iter, TYPE_COL, new_text,
                                       TEXT_SENS_COL, text_sens,
                                       INT_SENS_COL, int_sens,
                                       -1 );
}


static void
cb_string_param_changed( GtkCellRendererText *renderer,
                         gchar               *path,
                         gchar               *new_text,
                         GtkListStore        *master )
{
    GtkTreeIter   iter;

    /* Update master model */
    gtk_tree_model_get_iter_from_string( GTK_TREE_MODEL( master ),
                                         &iter, path );
    gtk_list_store_set( master, &iter, TEXT_COL, new_text, -1 );
}

static void
cb_integer_param_changed( GtkCellRendererText *renderer,
                          gchar               *path,
                          gchar               *new_text,
                          GtkListStore        *master )
{
    GtkTreeIter   iter;
    gint          value;

    /* Update master model */
    gtk_tree_model_get_iter_from_string( GTK_TREE_MODEL( master ),
                                         &iter, path );
    value = (gint)strtol( new_text, NULL, 10 );
    gtk_list_store_set( master, &iter, INT_COL, value, -1 );
}

int
main( int    argc,
      char **argv )
{
    GtkWidget         *window;
    GtkWidget         *treeview;
    GtkListStore      *model;
    GtkListStore      *master;
    GtkTreeIter        iter;
    GtkCellRenderer   *renderer;
    GtkAdjustment     *adj;
    GtkTreeViewColumn *col;

    gtk_init( &argc, &argv );

    window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
    g_signal_connect( G_OBJECT( window ), "destroy",
                      G_CALLBACK( gtk_main_quit ), NULL );


    /* create treeview */
    treeview = gtk_tree_view_new();
    gtk_tree_view_set_reorderable( GTK_TREE_VIEW( treeview ), TRUE );
    gtk_container_add( GTK_CONTAINER( window ), treeview );

    /* Create "master" model for treeview and add 2 entries */
    master = gtk_list_store_new( NO_COLS, G_TYPE_STRING,
                                          G_TYPE_STRING,
                                          G_TYPE_BOOLEAN,
                                          G_TYPE_INT,
                                          G_TYPE_BOOLEAN );
    gtk_list_store_append( master, &iter );
    gtk_list_store_set( master, &iter, TYPE_COL, "None",
                                       TEXT_COL, "Parameter 1",
                                       TEXT_SENS_COL, FALSE,
                                       INT_COL, 0,
                                       INT_SENS_COL, FALSE,
                                       -1 );
    gtk_list_store_append( master, &iter );
    gtk_list_store_set( master, &iter, TYPE_COL, "Integer",
                                       TEXT_COL, "Parameter 1",
                                       TEXT_SENS_COL, FALSE,
                                       INT_COL, 5,
                                       INT_SENS_COL, TRUE,
                                       -1 );
    gtk_tree_view_set_model( GTK_TREE_VIEW( treeview ),
                             GTK_TREE_MODEL( master ) );

    /* column 1 */
    /* Create model for combo renderer and populate it */
    model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
    gtk_list_store_append( model, &iter );
    gtk_list_store_set( model, &iter, 0, "None", 1, 0, -1 );
    gtk_list_store_append( model, &iter );
    gtk_list_store_set( model, &iter, 0, "String", 1, 1, -1 );
    gtk_list_store_append( model, &iter );
    gtk_list_store_set( model, &iter, 0, "Integer", 1, 2, -1 );

    /* Create column and add renderer to it */
    col = gtk_tree_view_column_new();
    gtk_tree_view_column_set_resizable( col, TRUE );

    renderer = gtk_cell_renderer_combo_new();
    g_signal_connect( G_OBJECT( renderer ), "edited",
                      G_CALLBACK( cb_type_changed ), master );
    g_object_set( G_OBJECT( renderer ), "model", GTK_TREE_MODEL( model ),
                                        "text-column", 0,
                                        "editable", TRUE,
                                        "has_entry", FALSE,
                                        NULL );
    gtk_tree_view_column_pack_start( col, renderer, TRUE );
    gtk_tree_view_column_set_attributes( col, renderer, "text", TYPE_COL,
                                         NULL );
    gtk_tree_view_append_column( GTK_TREE_VIEW( treeview ), col );

    /* column 2 */
    /* Again create model for combo renderer and populate it */
    model = gtk_list_store_new( 1, G_TYPE_STRING );
    gtk_list_store_append( model, &iter );
    gtk_list_store_set( model, &iter, 0, "Parameter 1", -1 );
    gtk_list_store_append( model, &iter );
    gtk_list_store_set( model, &iter, 0, "Parameter 2", -1 );
    gtk_list_store_append( model, &iter );
    gtk_list_store_set( model, &iter, 0, "Parameter 3", -1 );

    /* Create column and add renderer to it */
    col = gtk_tree_view_column_new();
    gtk_tree_view_column_set_resizable( col, TRUE );

    renderer = gtk_cell_renderer_combo_new();
    g_signal_connect( G_OBJECT( renderer ), "edited",
                      G_CALLBACK( cb_string_param_changed ), master );
    g_object_set( G_OBJECT( renderer ), "model", GTK_TREE_MODEL( model ),
                                        "text-column", 0,
                                        "has_entry", FALSE,
                                        NULL );
    gtk_tree_view_column_pack_start( col, renderer, TRUE );
    gtk_tree_view_column_set_attributes( col, renderer,
                                         "text", TEXT_COL,
                                         "sensitive", TEXT_SENS_COL,
                                         "editable", TEXT_SENS_COL,
                                         NULL );
    gtk_tree_view_append_column( GTK_TREE_VIEW( treeview ), col );

    /* column 3 */
    /* Create adjustment for spin renderer */
    adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 100, 1, 10, 0 ) );

    /* Create column and add renderer to it */
    col = gtk_tree_view_column_new();
    gtk_tree_view_column_set_resizable( col, TRUE );

    renderer = gtk_cell_renderer_spin_new();
    g_signal_connect( G_OBJECT( renderer ), "edited",
                      G_CALLBACK( cb_integer_param_changed ), master );
    g_object_set( G_OBJECT( renderer ), "adjustment", adj,
                                        "editable", TRUE,
                                        NULL );
    gtk_tree_view_column_pack_start( col, renderer, TRUE );
    gtk_tree_view_column_set_attributes( col, renderer,
                                         "text", INT_COL,
                                         "sensitive", INT_SENS_COL,
                                         "editable", INT_SENS_COL,
                                         NULL );
    gtk_tree_view_append_column( GTK_TREE_VIEW( treeview ), col );


    gtk_widget_show_all( window );

    gtk_main();

    return( 0);
}
------------------

Hope you'll find it useful.



2008/12/10 John M Collins <jmc xisl com>:
In my application I am trying to build a dialog box to display and allow
the user to create/delete/edit a list of some structures.

According to the "type" field in the structures, some variants of the
structures use a string as a parameter, others use an integer. (There is
a "null" option which doesn't take anything).

Ideally I'd like to have a TreeView with 2 columns (there are some other
ones too relating to other fields in the structure but we'll ignore them
for the purposes of the question), with a GtkCellRenderCombo for the
"type" and the second column either an editable text field or a spin box
depending on what was selected in the ComboBox. Obviously it would be
different for each row depending on what "type" was selected for the
structure represented by that row.

If that can't be done simply - and it probably isn't worth having huge
lumps of code to do just one bit of one dialog the way I want it in one
part of one application - is it possible to selectively make a given
cell non-sensitive or invisible according to the selected value of the
combo box without affecting different rows in the same column? And how
do I reach the "changed" signal for the ComboBox?

Another more trivial question relates to the initial size of the
TreeView (I am using a scroll as well) which is fine if I have existing
structures to display when I start, but if the list is empty to start
with I get a pathetic weedy little window I can only see half a line in.
Is there a nice clean way I can set a minimum size - preferably not
mentioning pixels for the benefit of people using big default fonts?


John Collins Xi Software Ltd www.xisl.com

_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list





John Collins Xi Software Ltd www.xisl.com




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]