Re: Creating new widgets



Hi again,

Thanks for that - it's got me on the right track (I think :) ) but I have run into a couple of problems.

As I mentioned before I want the MEF to have the ability to have rows of entries, comboboxes and comboentries. This is defined by the column_types property which is a string of E's (for Entry), C's (for Comboboxes) and c's (for comboentries), which is a creation-time-only setter. So someone could do:

my $mef = My::MEF->new(column_types => 'EEC');

and get a MEF in which each row contains two entries and a combobox. Obviously I haven't gotten to the 'how to set the combobox's models etc' yet, but one step at a time :)

Now, the problem I've hit here is that the column_types property seems to be set _after_ INIT_INSTANCE is called, which means when I'm building the first row (which must always be shown - at the moment I don't enforce that but I will) I don't know what to build.

One workaround I've found is to remove the initial add_row from INIT_INSTANCE and instead put it in the set function for the column_types property. This seems just a tad hacky to me, but does seem to work.

Anyway, below is my code so far. If there are any obvious wrongnesses I'd appreciate pointers :)

MB

use strict;
package My::MEF;

use Glib::Object::Subclass
  Gtk2::VBox::,
  signals => {row_deleted => {},   # TBC
              row_added   => {},   # TBC
              row_changed => {}},  # TBC
  properties =>
  [{pspec => (Glib::ParamSpec->
              string('column_types', 'Column Types',
                     ('The column types as a string of E, C and c. Each ' .
                      'character represents an (E)ntry, (C)ombobox or ' .
                      '(e)ntrycombo. Default is a single entry (E).'),
                     'E', [qw(readable writable construct-only)])),
    set => sub {
      my $self = shift;
      my ($newval) = @_;
      die "Invalid column_types" if $newval !~ /^[ECc]+\z/;
      $self->{column_types} = $newval;
      $self->add_row if not defined $self->{num_rows};
    },
   }];

sub INIT_INSTANCE {
  my $self = shift;
  # Build the initial line
#  $self->add_row(undef); MOVED TO column_types set ^
}

#sub GET_PROPERTY {
#}

#sub SET_PROPERTY {
#}

#sub FINALIZE_INSTANCE {
#}

sub add_row {
  my $self = shift;
  my ($previous) = @_;
  my $hbox = Gtk2::HBox->new;
  my $entry = Gtk2::Entry->new;
  my $add = Gtk2::Button->new("V");
  my $del = Gtk2::Button->new("X");
  my @ents = $self->_build_entries;
  for my $ent (@ents) {
    $hbox->pack_start($ent, 1, 1, 0);
  }
  $hbox->pack_start($add, 0, 0, 0);
  $hbox->pack_start($del, 0, 0, 0);
  $add->signal_connect(clicked => sub {
                         my $row = $_[0]->get_parent;
                         $self->add_row($row);
                       });
  $del->signal_connect(clicked => sub {
                         my $row = $_[0]->get_parent;
                         my $box = $row->get_parent;
                         $box->remove($row);
                         --$self->{num_rows};
                       });
  my $i = 0;
  if (defined $previous) {
    for my $c ($self->get_children) {
      if ($c == $previous) {
        last;
      } else {
        $i++;
      }
    }
  }
  $self->pack_start ($hbox, 0, 0, 0);
  $self->reorder_child ($hbox, $i + 1);
  $hbox->show_all;
  ++$self->{num_rows};
  return \ ents;
}

sub _build_entries {
  my $self = shift;
  my @ents;
  for my $etype (split //, $self->{column_types}) {
    if ($etype eq 'E') {
      push @ents, Gtk2::Entry->new;
    } elsif ($etype eq 'C') {
      # TBC
    } elsif ($etype eq 'c') {
      #TBC
    }
  }
  return @ents;
}

1;
__END__


On 10/11/06, muppet <scott asofyet org > wrote:

On Oct 11, 2006, at 1:42 AM, Matthew Braid wrote:

> There's also the possibility of doing the same thing inside a
> ListView with editable cells for the
> entires. But from what I've seen there are problems with combobox/
> entries in listviews, and I haven't seen a cell renderer for buttons.

You'd have to write a CellRendererButton.  It's actually not very
hard.  Entries are easy (CellRendererText), and as of later versions
of gtk+, so are comboboxes (CellRendererCombo).


> Can anyone point me in the right direction? I can work around this
> but I've found this MEF widget quite handy in the past.

If you're not willing to use a TreeView, then it sounds to me like a
job for boxes and the handy method Gtk2::Container::remove.

Here's a short procedural example.  I'll leave turning it into a
flexible and reusable class as an exercise for you.  (Things you
could do with it as a class:  emit signals when rows are added and
removed, decouple the created widget from the add_row() method so you
can create things other than just entries, etc, etc.)


#!/usr/bin/perl -w
use strict;
use Gtk2 -init;

my $window = Gtk2::Window->new;
$window->signal_connect (destroy => sub { Gtk2->main_quit });


sub add_row {
        my ($vbox, $previous) = @_;
        my $hbox = Gtk2::HBox->new;
        my $entry = Gtk2::Entry->new;
        my $add = Gtk2::Button->new ("V");
        my $del = Gtk2::Button->new ("X");
        $hbox->pack_start ($entry, 1, 1, 0);
        $hbox->pack_start ($add, 0, 0, 0);
        $hbox->pack_start ($del, 0, 0, 0);
        $add->signal_connect (clicked => sub {
                my $row = $_[0]->get_parent;
                my $box = $row->get_parent;
                add_row ($box, $row);
        });
        $del->signal_connect (clicked => sub {
                my $row = $_[0]->get_parent;
                my $box = $row->get_parent;
                $box->remove ($row);
        });

        my $i = 0;
        if (defined $previous) {
                foreach my $c ($vbox->get_children) {
                        if ($c == $previous) {
                                last;
                        } else {
                                $i++;
                        }
                }
        }
        $vbox->pack_start ($hbox, 0, 0, 0);
        $vbox->reorder_child ($hbox, $i+1);
        $hbox->show_all;
        return $entry;
}


my $box = Gtk2::VBox->new;
add_row ($box, undef);

$window->add ($box);

$window->show_all;
Gtk2->main;
__END__


--
Without treatment, a common cold will last about seven days.
With treatment, it will last about a week.
   -- conventional wisdom




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