Slide: 1
+
Dov Grobgeld
<dov.grobgeld@gmail.com>
JAPC Israel 2004

Slide: 2

Table of contents


Slide: 3

GTK History

Example of gtk programs


Slide: 4

Gtk+ Perl History and Philosophy


Slide: 5

Gtk+ related modules


Slide: 6

Hello world

Listing: hello_world
#!/usr/bin/perl

use Gtk2 '-init';

my $window = Gtk2::Window->new;
my $label = Gtk2::Label->new("Hello world!");
$window->add($label);
$window->show_all();

Gtk2->main;


Slide: 7

Hello world with callbacks

Listing: hello_world2
#!/usr/bin/perl

use Gtk2 '-init';

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

my $button = Gtk2::Button->new("Hello world!");
$button->signal_connect(clicked=> sub { Gtk2->main_quit; });

$window->add($button);
$window->show_all();

Gtk2->main;


Slide: 8

The world of GObjects

Signals

Properties


Slide: 9

Packing widgets

Listing: hello_world_pack
#!/usr/bin/perl

use Gtk2 '-init';

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

my $vbox = Gtk2::VBox->new();
$vbox->set("border_width"=> 10);
$window->add($vbox);

my $label = Gtk2::Label->new("Hello world");
$vbox->pack_start($label,0,0,5); # expand?, fill?, padding

my $button = Gtk2::Widget->new("Gtk2::Button",
			       label=>"Quit");
$button->signal_connect(clicked=>\&my_quit);

$vbox->pack_start($button, 0,0,5);

$window->show_all();

Gtk2->main;

sub my_quit {
    print "Good bye!\n";
    exit;
}


Slide: 10

Unicode!

Listing: hello_world_hebrew
#!/usr/bin/perl

BEGIN { $ENV{LC_ALL} = "he_IL"; }

use utf8;   # Needed for Hebrew
use Gtk2 '-init';

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

my $vbox = Gtk2::VBox->new();
$vbox->set("border_width"=> 10);
$window->add($vbox);

my $label = Gtk2::Label->new("שלום עולם!");
$vbox->pack_start($label,0,0,5); # expand?, fill?, padding

my $entry = Gtk2::Entry->new();
$vbox->pack_start($entry,0,0,5);

my $button = Gtk2::Widget->new("Gtk2::Button",
			       label=>"יציאה");
# Note how additional parameters are passed in callback
$button->signal_connect(clicked=>\&my_quit, [$label, $entry]);

$vbox->pack_start($button, 0,0,5);

$window->show_all();

Gtk2->main;

sub my_quit {
    my ($self, $args) = @_;
    my ($label, $entry) = @$args;

    $label->set(label=>$entry->get_text());
    $entry->set_text("");
    # Add a timeout event
    Glib::Timeout->add(1500, sub { exit });
}

LC_ALL=CLC_ALL=he_IL

Slide: 11

Styles

Listing: hello_style
#!/usr/bin/perl

BEGIN { $ENV{LC_ALL} = "he_IL"; }

use utf8;   # Needed for Hebrew
use Gtk2 '-init';

Gtk2::Rc->parse_string(<<__);
include "/usr/local/share/themes/Bumblebee/gtk-2.0/gtkrc"

style "normal" {
    font_name ="serif 30"
}

style "my_entry" {
    font_name ="sans 25"
    text[NORMAL] = "#FF0000"
}

widget "*" style "normal"
widget "*Entry*" style "my_entry"
__


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

my $vbox = Gtk2::VBox->new();
$vbox->set("border_width"=> 10);
$window->add($vbox);

my $label = Gtk2::Label->new("שלום עולם!");
$vbox->pack_start($label,0,0,5); # expand?, fill?, padding

my $entry = Gtk2::Entry->new();
$vbox->pack_start($entry,0,0,5);

my $button = Gtk2::Widget->new("Gtk2::Button",
			       label=>"יציאה");
$button->signal_connect(clicked=>\&my_quit);

$vbox->pack_start($button, 0,0,5);

$window->show_all();

Gtk2->main;

sub my_quit {
    print "Lehitraot!\n";
    exit;
}


Slide: 12

Connecting a style to a widget

Listing: attach_style
:
Gtk2::Rc->parse_string(<<__);
style "big" {
    font_name ="serif 80"
}

style "normal" {
    font_name ="serif 30"
}

widget "*" style "normal"
widget "*big*" style "big"
__

:
my $label = Gtk2::Label->new("Name:");
$label->set_name("big");
:

Slide: 13

Images and markup

Listing: button-with-image
#!/usr/bin/perl
######################################################################
# An example illustrating images and markup.
######################################################################
use Gtk2 '-init';

my $window = Gtk2::Window->new;
my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file("gtk-logo-rgb.png");
my $image = Gtk2::Image->new_from_pixbuf($pixbuf);
my $button = Gtk2::Button->new();
my $vbox = Gtk2::VBox->new();
my $label = Gtk2::Label->new("Press this button!");
$vbox->pack_start($label, 0,0,0);
$vbox->pack_start($image, 0,0,0);
$window->set(border_width=>15);
$button->add($vbox);    # <- You can pack any widget inside a button!
$window->add($button);

$button->signal_connect(clicked=>
    sub { $label->set_markup("<b>Thank ".
			     "<span foreground=\"blue\">".
			     "you</span>!</b>");
      });

$window->show_all();

Gtk2->main;


Slide: 14

More widgets


Slide: 15

Connecting to Glade

Listing: sms
#!/usr/bin/perl

BEGIN {
    $ENV{LC_ALL} = "he_IL";
}

use Gtk2 -init;
use Gtk2::GladeXML;
use strict;

my $receiver;   # Global variable for receiver
my %db;

sub read_db {
    open(DB, "<:utf8", "mysms.dat");
    while(<DB>) {
	chomp;
	my($name, $number) = split(/,/);
	$db{$name} = $number;
    }
    close(DB);
}

# Autoconnect routines
sub cb_quit {
    Gtk2->main_quit;
}

sub on_send_clicked {
    print "Sending sms to ", $db{$receiver}, "\n";
}

# main
read_db();
my $gladexml = Gtk2::GladeXML->new('sms.glade');
$gladexml->signal_autoconnect_from_package('main');

my $menu = $gladexml->get_widget('optionmenu1')->get_menu;
for my $name (sort keys %db) {
    my $item = Gtk2::MenuItem->new("$name - " . $db{$name});
    $item->signal_connect(activate => sub { $receiver = $name });
    $item->show();
    $menu->append($item);
}

Gtk2->main;

Slide: 16

The Canvas widget

Listing: canvas_example
#!/usr/bin/perl

use Gtk2 '-init';
use Gnome2::Canvas;

my($w_top, $w_canvas);

sub create_widgets {
    $w_top = Gtk2::Window->new;
    $w_top->signal_connect(destroy=> sub { exit });

    my $vbox = Gtk2::VBox->new(0,0);
    $w_top->add($vbox);

    $w_canvas = Gnome2::Canvas->new_aa();
    $vbox->pack_start($w_canvas, 1,1,0);
    $w_canvas->set_size_request(300,300);
    $w_canvas->set_scroll_region (0, 0, 300, 300);

    my $quit = Gtk2::Button->new("Quit");
    $quit->signal_connect(clicked=> sub { exit });
    $vbox->pack_start($quit, 0, 0, 0);

    $w_top->show_all();
}

# Callback for moving items on the canvas
my ($dragging, $last_x, $last_y);   # item_move static data
sub item_move {
    my($item, $event) = @_;

    if ($event->type eq "button-press") {
	$item->raise_to_top();
	$last_x = $event->x;
	$last_y = $event->y;
	$dragging=1;
    }
    elsif ($event->type eq "motion-notify") {
	if ($dragging) {
	    my $new_x = $event->x;
	    my $new_y = $event->y;

	    $item->move($new_x - $last_x,$new_y-$last_y);
	    $last_x = $new_x;
	    $last_y = $new_y;
	}
    }
    elsif ($event->type eq "button-release") {
	$dragging = 0;
    }
}

sub place_objects_on_canvas {
    my $root = $w_canvas->root();

    for my $p ([50,50,  "green"],
	       [50,250, "orange"],
	       [250,50, "yellow"],
	       [250,250, "blue"]) {

	my($x,$y,$color) = @$p;

	# Put a circle on the graph
	my $item = Gnome2::Canvas::Item->new(
		    $root, "Gnome2::Canvas::Ellipse",
                    x1=> $x-16,
                    y1=> $y-16,
                    x2=> $x+16,
                    y2=> $y+16,
                    fill_color => $color,
                    outline_color=>"black");

	# Make it movable
	$item->signal_connect("event", \&item_move);
    }
}

create_widgets();
place_objects_on_canvas();

Gtk2->main();

Slide: 17

Animation on the canvas

Listing: canvas_motion
#!/usr/bin/perl
############################################################
#  Example of animation on the gnome canvas.
#
#  Dov Grobgeld
############################################################

use Gtk2 '-init';
use Gnome2::Canvas;
use strict;

my($w_top, $w_canvas);
my $min_x = 5;
my $max_x = 500;
my ($rect_green, $rect_orange);

############################################################
#  Create the widgets
############################################################
sub create_widgets {
    $w_top = Gtk2::Window->new;
    $w_top->signal_connect(destroy=> sub { exit });

    my $vbox = Gtk2::VBox->new(0,0);
    $w_top->add($vbox);

    $w_canvas = Gnome2::Canvas->new_aa();
    $vbox->pack_start($w_canvas, 1,1,0);
    $w_canvas->set_size_request(600, 300);
    $w_canvas->set_scroll_region(0, 0, 600, 300);

    my $quit = Gtk2::Button->new("Quit");
    $quit->signal_connect(clicked=> sub { exit });
    $vbox->pack_start($quit, 0, 0, 0);

    $w_top->show_all();
}

sub place_objects_on_canvas {
    my $root = $w_canvas->root();

    $rect_green =
	Gnome2::Canvas::Item->new($root,
				  "Gnome2::Canvas::Rect",
				  x1=> 240,
				  y1=> 90,
				  x2=> 440,
				  y2=> 180,
				  fill_color_rgba=> 0x3cb37180,
				  outline_color => "black",
				  width_units =>2.0);
    # Add user data
    $rect_green->{dir}=1;
    $rect_green->{speed}=5;

    $rect_orange =
	Gnome2::Canvas::Item->new($root,
				  "Gnome2::Canvas::Ellipse",
				  x1=> 30,
				  y1=> 150,
				  x2=> 250,
				  y2=> 240,
				  fill_color_rgba=> 0xb3713c80,
				  outline_color => "black",
				  width_units =>2.0);

    $rect_orange->{dir} = -1;
    $rect_orange->{speed} = 8;

    Glib::Timeout->add(10, \&cb_animation_step);
}

############################################################
#  Takes one step of the animation. rect_green is moved by
#  DELTA_Y_GREEN and rect_orange by DELTA_Y_ORANGE. When they
#  meet the borders, their direction change
############################################################
sub cb_animation_step {
    foreach my $r ($rect_green, $rect_orange) {
	# Get old values
	my ($old_x1, $old_x2) = $r->get("x1", "x2");

	# Get user data
	my $dir = $r->{dir} || 1;
	my $speed = $r->{speed};

	# Move the object
	my $new_x1 = $old_x1 + $dir * $speed;
	my $new_x2 = $old_x2 + $dir * $speed;

	# Check if we hit a wall
	if ($new_x1 < $min_x || $new_x2 > $max_x) {
	    $dir = -$dir;
	    $r->{dir} = $dir;

	    $new_x1 = $old_x1 + $dir * $speed;
	    $new_x2 = $old_x2 + $dir * $speed;
	}

	# Update new parameter data
	$r->set(x1 => $new_x1,
		x2 => $new_x2);
    }

    # As long as this routine returns TRUE, it will be
    # called again
    return 1;
}

create_widgets();
place_objects_on_canvas();

Gtk2->main();

Slide: 18

Documentation

Gtk++ c-documentation

Perl-Gtk pod documentation


Slide: 19
תודה רבה!

Thank you!

Danke Schön!

Tack så mycket!