Switch a CellRendererCombo's model

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Switch a CellRendererCombo's model

Daniel Kasak
Hi all.

I'm having a really, *really* bad performance problem in a treeview that
has a CellRendererCombo with a large model.
The combo should really only display options that are relevant to the
current row anyway.

What I'd like to do is to run some code that replaces the model in the
CellRendererCombo with a fresh one each time a new row is selected, or
when something else happens that would affect the list of options. I
assume I can do this with:

$renderer->set( model   => $new_model );

However this will have the undesired impact of leaving all the other
CellRendererCombos in other rows in the treeview with a model that
doesn't contain the item that they're currently displaying, ie all the
cells will be blank. Is that right? Is there any way around this?

--
Daniel Kasak
IT Developer
NUS Consulting Group
Level 5, 77 Pacific Highway
North Sydney, NSW, Australia 2060
T: (+61) 2 9922-7676 / F: (+61) 2 9922 7989
email: [hidden email]
website: http://www.nusconsulting.com.au
_______________________________________________
gtk-perl-list mailing list
[hidden email]
http://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Switch a CellRendererCombo's model

muppet-6

On Jul 4, 2005, at 11:50 PM, Daniel Kasak wrote:

> I'm having a really, *really* bad performance problem in a treeview  
> that
> has a CellRendererCombo with a large model.

How bad?

> The combo should really only display options that are relevant to the
> current row anyway.
>
> What I'd like to do is to run some code that replaces the model in the
> CellRendererCombo with a fresh one each time a new row is selected, or
> when something else happens that would affect the list of options. I
> assume I can do this with:
>
> $renderer->set( model   => $new_model );
>
> However this will have the undesired impact of leaving all the other
> CellRendererCombos in other rows in the treeview with a model that
> doesn't contain the item that they're currently displaying, ie all the
> cells will be blank. Is that right?

Yes.  When you set a cell renderer property with $renderer->set(),  
that value will be used for all rows in the column.


> Is there any way around this?

Store the appropriate combo model for each row in an extra column in  
the main treemodel, and use an attribute on the TreeViewColumn to  
tell the CellRendererCombo where to find the model.  Since this has  
potential to use obscene amounts of memory, you'll want to share  
models between rows.


--
I don't like... this game... when there's cannons... being shot... at  
me.
   -- Elysse

_______________________________________________
gtk-perl-list mailing list
[hidden email]
http://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Switch a CellRendererCombo's model

Daniel Kasak
muppet wrote:

> On Jul 4, 2005, at 11:50 PM, Daniel Kasak wrote:
>
>> I'm having a really, *really* bad performance problem in a treeview
>> that
>> has a CellRendererCombo with a large model.
>
> How bad?

:)

Oh ... it's pretty bad. The model has locations and postcodes ( zip
codes ), and there are 15,000 of them in the table. If I populate a
TreeModel / TreeView with 15 records and use the postcodes model in one
of the cells, it takes about 5 seconds of 100% CPU usage just to draw
the TreeView. Other events:

- resize the TreeView - 5 seconds at 100% CPU
- click in a row - 2 second delay, CPU at 100%
- edit data in a cell - 3 to 4 second delay, CPU at 100%
- switch to another desktop and back - 5 second delay, CPU at 50%
- point mouse in general direction of TreeView, with small movements,
CPU constantly at 15%

>> Is there any way around this?
>
> Store the appropriate combo model for each row in an extra column in
> the main treemodel, and use an attribute on the TreeViewColumn to
> tell the CellRendererCombo where to find the model.  Since this has
> potential to use obscene amounts of memory, you'll want to share
> models between rows.

That sounds like what I want, but I'm a little unclear on how to get
there. At the moment, I'm setting the model with:

---

$renderer = Gtk2::CellRendererCombo->new;

$renderer->set(
            editable    => TRUE,
            model       => $field->{model},
            text_column => 1,
            has_entry   => TRUE
);

$renderer->{column} = $column_no;

$self->{columns}[$column_no] = Gtk2::TreeViewColumn->new_with_attributes(
            $field->{name},
            $renderer,
            text    => $column_no
);

---

So in my $renderer->set() line, I'd remove the model => $field->{model}
bit. And I'd replace it with something in the above
Gtk2::TreeViewColumn->new_with_attributed() line? Assuming I have packed
a model into column $combo_model_column in the main TreeModel, how do I
tell the CellRendererCombo to use it?

--
Daniel Kasak
IT Developer
NUS Consulting Group
Level 5, 77 Pacific Highway
North Sydney, NSW, Australia 2060
T: (+61) 2 9922-7676 / F: (+61) 2 9922 7989
email: [hidden email]
website: http://www.nusconsulting.com.au
_______________________________________________
gtk-perl-list mailing list
[hidden email]
http://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Switch a CellRendererCombo's model

Torsten Schoenfeld
On Wed, 2005-07-06 at 09:18 +1000, Daniel Kasak wrote:

> So in my $renderer->set() line, I'd remove the model => $field->{model}
> bit. And I'd replace it with something in the above
> Gtk2::TreeViewColumn->new_with_attributed() line? Assuming I have packed
> a model into column $combo_model_column in the main TreeModel, how do I
> tell the CellRendererCombo to use it?

You add

  model => $combo_model_column

to the new_with_attributes() call.

--
Bye,
-Torsten

_______________________________________________
gtk-perl-list mailing list
[hidden email]
http://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Switch a CellRendererCombo's model

Daniel Kasak
Torsten Schoenfeld wrote:

>On Wed, 2005-07-06 at 09:18 +1000, Daniel Kasak wrote:
>
>>So in my $renderer->set() line, I'd remove the model => $field->{model}
>>bit. And I'd replace it with something in the above
>>Gtk2::TreeViewColumn->new_with_attributed() line? Assuming I have packed
>>a model into column $combo_model_column in the main TreeModel, how do I
>>tell the CellRendererCombo to use it?
>>
>
>You add
>
>  model => $combo_model_column
>
>to the new_with_attributes() call.
>
>
I'm still not getting anywhere. Sorry.

My main TreeStore has a column at the end ( 1 from the end anyway )
that's defined as a Gtk2::ListStore ( I've also tried with a
Glib::Scalar ). I'm not sure if either of these are correct.

Basically I'm populating the main TreeStore like this:

---

    while (my @row = $sth->fetchrow_array) {
       
        my @model_row;
        my $column = 0;
       
        # Append a new treeiter, and the status indicator
        push @model_row, $liststore->append, STATUS_COLUMN, UNCHANGED;
       
        for my $field (@{$self->{fields}}) {
           
            if ( $field->{renderer} eq "model" ) {
               
                # ie this column stores the model for a combo elsewhere
                push @model_row, $column + 1, $field->{model};
               
            } else {
               
                push @model_row, $column + 1, $row[$column];
               
            }
           
            $column++;
           
        }
       
        # Append the primary key to the end
        push @model_row, $column + 1, $row[$column];
       
        $liststore->set(@model_row);
       
    }

---

This code at least runs without any errors.

I'm setting up the CellRendererCombo like this:

---

    $renderer = Gtk2::CellRendererCombo->new;
   
    if ( ! $self->{readonly} ) {
        $renderer->set(
                editable    => TRUE,
                text_column => 1,
                has_entry   => TRUE
                  );
    }
   
    $renderer->{column} = $column_no;
   
    $self->{columns}[$column_no] =
Gtk2::TreeViewColumn->new_with_attributes(
                                            $field->{name},
                                            $renderer,
                                            text    => $column_no,
                                            model   => $column_no_of_model,
                                        );
   
    $renderer->signal_connect( edited => sub {
$self->process_text_editing( @_ ); } );
   
    $self->{treeview}->append_column($self->{columns}[$column_no]);

---

When the main TreeStore is populated and gets rendered, I get a string of:

GLib-GObject-WARNING **: unable to set property `model' of type
`GtkTreeModel' from value of type `gint'

--
Daniel Kasak
IT Developer
NUS Consulting Group
Level 5, 77 Pacific Highway
North Sydney, NSW, Australia 2060
T: (+61) 2 9922-7676 / F: (+61) 2 9922 7989
email: [hidden email]
website: http://www.nusconsulting.com.au
_______________________________________________
gtk-perl-list mailing list
[hidden email]
http://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Switch a CellRendererCombo's model

muppet-6

On Jul 7, 2005, at 12:59 AM, Daniel Kasak wrote:

> My main TreeStore has a column at the end ( 1 from the end anyway )
> that's defined as a Gtk2::ListStore ( I've also tried with a
> Glib::Scalar ). I'm not sure if either of these are correct.

Gtk2::ListStore is the best; Gtk2::TreeModel and Glib::Object would  
also probably work, but ListStore is specific enough to ensure that  
the wrong type of object doesn't wind up in the column.

Glib::Scalar is not correct; that's basically "typeless" from gtk+'s  
point of view.  It's useful if you're using a cell data function with  
a native perl data structure.


>     $self->{columns}[$column_no] =
> Gtk2::TreeViewColumn->new_with_attributes(
>                                             $field->{name},
>                                             $renderer,
>                                             text    => $column_no,
>                                             model   =>  
> $column_no_of_model,
>                                         );
...
> When the main TreeStore is populated and gets rendered, I get a  
> string of:
>
> GLib-GObject-WARNING **: unable to set property `model' of type
> `GtkTreeModel' from value of type `gint'

That means you're using the wrong column number in  
$column_no_of_model, and the TreeViewColumn is trying to set the  
CellRendererCombo's "model" property from a value containing an  
integer, which it fetched from a TreeStore column containing an integer.


Here's a simple working example, maybe it will be better than trying  
to explain in prose:


#!/usr/bin/perl -w
use strict;
use Gtk2 -init;
use Glib ':constants';

#
# create a bunch of models to hold the appropriate choices for the  
various rows
#
my @combo_models;
foreach my $data ([qw(one two three four five)],
                   [qw(red orange yellow green blue indigo violet)],
                   [qw(george john paul ringo)],
                   [qw(north south east west)]) {
     my $model = Gtk2::ListStore->new (qw(Glib::String));
     foreach my $string (@$data) {
         $model->set ($model->append, 0, $string);
     }
     push @combo_models, $model;
}

#
# create and populate the main list
#
use constant NAME_COLUMN => 0;
use constant CURRENT_COLUMN => 1;
use constant MODEL_COLUMN => 2;
my @column_types;
$column_types[NAME_COLUMN] = 'Glib::String';
$column_types[CURRENT_COLUMN] = 'Glib::String';
$column_types[MODEL_COLUMN] = 'Gtk2::ListStore';
my $model = Gtk2::ListStore->new (@column_types);
foreach my $data (
     { name => 'Fred', current => 1, model => $combo_models[0] },
     { name => 'Barney', current => 2, model => $combo_models[1] },
     { name => 'Wilma', current => 3, model => $combo_models[2] },
     { name => 'Betty', current => 0, model => $combo_models[3] },
     { name => 'Pebbles', current => 2, model => $combo_models[0] },
     { name => 'Bam-Bam', current => 3, model => $combo_models[1] },
) {
     $data->{current} =
             $data->{model}->get
                 ($data->{model}->iter_nth_child (undef, $data->
{current}), 0);
     $model->set ($model->append,
                  NAME_COLUMN, $data->{name},
                  CURRENT_COLUMN, $data->{current},
                  MODEL_COLUMN, $data->{model});
}

#
# create a view for that model.
#
my $treeview = Gtk2::TreeView->new ($model);

$treeview->insert_column_with_attributes
         (-1, 'Name', Gtk2::CellRendererText->new, text => NAME_COLUMN);

my $combo_renderer = Gtk2::CellRendererCombo->new;
$combo_renderer->set (text_column => 0, # col in combo model with  
text to display
                       editable => TRUE); # without this, it's just a  
text renderer
$combo_renderer->signal_connect (edited => sub {
         my ($cell, $text_path, $new_text) = @_;
         $model->set ($model->get_iter_from_string ($text_path),
                      CURRENT_COLUMN, $new_text);
});
$treeview->insert_column_with_attributes
         (-1, 'Selection', $combo_renderer,
          text => CURRENT_COLUMN, model => MODEL_COLUMN);

#
# put all that on the screen
#
my $window = Gtk2::Window->new;
$window->signal_connect (destroy => sub { Gtk2->main_quit });
$window->add ($treeview);
$window->show_all;
Gtk2->main;



--
Our enemies are innovative and resourceful, and so are we. They never  
stop thinking about new ways to harm our country and our people, and  
neither do we.
   -- President George W. Bush

_______________________________________________
gtk-perl-list mailing list
[hidden email]
http://mail.gnome.org/mailman/listinfo/gtk-perl-list