====== Creazione di programmi con Perl, DBI, GTK ======
Autore: **//Fabio Di Matteo//** \\ Ultima revisione: **//03/02/2015 - 15:15//** \\ \\
In questo articolo vedremo come creare applicazioni Perl (script) che fanno uso di interfacce grafiche e di accesso a basi di dati. Espanderemo il codice dell'articolo [[programmazione:perl:intro_perl-gtk2]] con le funzionalita di DBI, il layer piu' usato per diverse tipologie di basi dati di Perl.
{{:programmazione:perl:perl-gtk-intro0.png?200|}}
===== Il codice =====
Fonti per quanto riguarda la parte DBI :[[http://zetcode.com/db/sqliteperltutorial/connect/|http://zetcode.com]]
**db.pl**
#!/usr/bin/perl
use Glib qw/TRUE FALSE/;
use Gtk2 '-init';
use Gtk2::SimpleList;
use DBI;
#Questa funzione è da usare solo su sqlite2.
#Sqlite3 supporta le query "... IF NOT EXIST..."
sub tableExist
{
#Connessione al database
my $dbh = DBI->connect(
"dbi:SQLite2:dbname=$_[0]",
"",
"",
{ RaiseError => 1 },
) or die $DBI::errstr;
#Conta le tabelle con nome $_[1]
my $sth = $dbh->prepare("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='$_[1]';");
$sth->execute();
#Mette il risultato della conta nell'array @row. Ovviamente prenderemo
#in considerazione solo @row[0] ;
my $row;
@row = $sth->fetchrow_array();
#Se @row[0] è uguale a 1 la tabella esiste, altrimenti no.
if (@row[0]=='1'){ return TRUE } else{ return FALSE} ;
}
sub createTable
{
#Se la tabella esiste non la crea
if (tableExist("test.db","persone")) { return ;}
#Connessione al database
my $dbh = DBI->connect(
"dbi:SQLite2:dbname=test.db",
"",
"",
{ RaiseError => 1 },
) or die $DBI::errstr;
#Creo la tabella
$dbh->do('CREATE TABLE "persone" (
"id" INTEGER NOT NULL ,
"nome" varchar(1) ,
"cognome" varchar(256) ,
"email" varchar(256) ,
PRIMARY KEY ("id")
);');
#Disconnessione
$dbh->disconnect();
}
sub updateGrid
{
#Cancella tutti glielementi della griglia
splice @{$slist->{data}} ;
#Connessione al database
my $dbh = DBI->connect(
"dbi:SQLite2:dbname=test.db",
"",
"",
{ RaiseError => 1 },
) or die $DBI::errstr;
my $sth = $dbh->prepare("SELECT * FROM persone;");
$sth->execute();
my $row;
while ($row = $sth->fetchrow_hashref())
{
#Prelevo i dati dalla query nella seguente forma $row->{NOMECAMPO}
#Aggiungo una riga al widget SimpleList (tratto $slist come un normalisimo array)
push @{$slist->{data}}, [ $row->{id}, $row->{nome},$row->{cognome}, $row->{email}];
}
$sth->finish();
$dbh->disconnect();
}
#Le callbacks dei bottoni
sub exit
{
my ($widget, $window) = @_;
$window->destroy;
}
sub delete_event
{
$window->destroy;
return TRUE;
}
sub add
{
my ($widget, $window) = @_;
#Connessione al database
my $dbh = DBI->connect(
"dbi:SQLite2:dbname=test.db",
"",
"",
{ RaiseError => 1 },
) or die $DBI::errstr;
#Inserisco qualche dato
$nome=$txtNome->get_text();
$cognome=$txtCognome->get_text();
$email=$txtEmail->get_text();
$dbh->do("INSERT INTO persone VALUES(null,'$nome','$cognome','$email')");
#Disconnessione
$dbh->disconnect();
clearText();
updateGrid();
}
sub del
{
#Prende il valore delle cella nascosta contenente l'id
@sel = $slist->get_selected_indices;
$id=$slist->{data}[@sel[0]][0];
#Connessione al database
my $dbh = DBI->connect(
"dbi:SQLite2:dbname=test.db",
"",
"",
{ RaiseError => 1 },
) or die $DBI::errstr;
$dbh->do("DELETE from persone where id=$id ;");
#Disconnessione
$dbh->disconnect();
clearText();
updateGrid();
clearText();#svuota le entry
}
sub get
{
#Prende l'indice selezionato e visualizza i dati nelle entry
@sel = $slist->get_selected_indices;
#Il metodo "$slist->get_selected_indices" prende un array di righe (@sel)
#selezionate. Noi andremo a prendere solo una di queste righe in quanto
#la selezione è singola nel nostro caso.
#Riga selezionata
$txtId->set_text($slist->{data}[@sel[0]][0]);
$txtNome->set_text($slist->{data}[@sel[0]][1]);
$txtCognome->set_text($slist->{data}[@sel[0]][2]);
$txtEmail->set_text($slist->{data}[@sel[0]][3]);
}
sub save
{
#Prende il valore delle cella nascosta contenente l'id
@sel = $slist->get_selected_indices;
$id=$slist->{data}[@sel[0]][0];
#Connessione al database
my $dbh = DBI->connect(
"dbi:SQLite2:dbname=test.db",
"",
"",
{ RaiseError => 1 },
) or die $DBI::errstr;
#Prendo i valori delle entry
$nome=$txtNome->get_text();
$cognome=$txtCognome->get_text();
$email=$txtEmail->get_text();
$sql="UPDATE persone SET nome = '$nome', cognome = '$cognome', email = '$email' WHERE id =$id ;";
$dbh->do($sql);
#Disconnessione
$dbh->disconnect();
clearText();
updateGrid();
}
sub clearText
{
#Questa funzione cancella soltanto il contenuto delle entry
$txtId->set_text('');
$txtNome->set_text('');
$txtCognome->set_text('');
$txtEmail->set_text('');
}
#Crea la tabella se non esiste
createTable();
# crea la finestra principale e la collega ad alcune callback
$window = Gtk2::Window->new('toplevel');
$window->signal_connect(delete_event => \&delete_event);
$window->signal_connect(destroy => sub { Gtk2->main_quit; });#alla chiusura quit
# Alcune prprietà della finestra
$window->set_border_width(10);
$window->set_size_request(640, 600);
$window->set_title("Rubrica");
$window->set_position('center');
#Entry e label per l'inserimento e modifica
$txtId = Gtk2::Entry->new();
$txtId->set_editable (FALSE);
$txtNome = Gtk2::Entry->new();
$txtCognome = Gtk2::Entry->new();
$txtEmail = Gtk2::Entry->new();
$lblId = Gtk2::Label->new ("ID:");
$lblNome = Gtk2::Label->new ("Nome:");
$lblCognome = Gtk2::Label->new ("Cognome:");
$lblEmail = Gtk2::Label->new ("Email:");
#Bottoni per le azioni
$btnDel = Gtk2::Button->new("Elimina");
$btnExit = Gtk2::Button->new("Esci");
$btnAdd = Gtk2::Button->new("Aggiungi");
$btnSave = Gtk2::Button->new("Salva");
#Callbacks bottoni
$btnExit->signal_connect(clicked => \&exit, $window);
$btnAdd->signal_connect(clicked => \&add, $window);
$btnDel->signal_connect(clicked => \&del, $window);
$btnSave->signal_connect(clicked => \&save, $window);
#Colonne della griglia e relativo tipo
$slist = Gtk2::SimpleList->new (
'ID' => 'text',
'Nome' => 'text',
'Cognome' => 'text',
'email' => 'text',
);
#Nascondo alla vista la colonna ID
$idColumn = $slist->get_column (0);
$idColumn->set_visible(FALSE);
#Aggiorno la griglia con i contnuti del db
updateGrid();
#Dimensioni della griglia
$slist->set_size_request(400,400);
#Al doppioclick su una riga esegui la funzione "get"
$slist->signal_connect(row_activated => \&get, $window);
$hbox0 = Gtk2::HBox->new(); #contenitore dell'intera area
$vbox0 = Gtk2::VBox->new(); #contenitore griglia e bottoni
$vbox1 = Gtk2::VBox->new(); #contenitore caselle di testo ed etichette
#Aggiungo ad hbox0 gli altri contenitore vbox0 e vbox1
$hbox0->pack_start($vbox0, TRUE, FALSE, 0);
$hbox0->pack_start($vbox1, TRUE, FALSE, 0);
#Aggiungo al cntenitore vbox1 i vari campi testo con le relative etichette
$vbox1->pack_start($lblId, FALSE, TRUE, 0);
$vbox1->pack_start($txtId, FALSE, TRUE, 0);
$vbox1->pack_start($lblNome, FALSE, TRUE, 0);
$vbox1->pack_start($txtNome, FALSE, TRUE, 0);
$vbox1->pack_start($lblCognome, FALSE, FALSE, 0);
$vbox1->pack_start($txtCognome, FALSE, FALSE, 0);
$vbox1->pack_start($lblEmail, FALSE, FALSE, 0);
$vbox1->pack_start($txtEmail, FALSE, FALSE, 0);
#Aggiungo al contenitore vbox0 la griglia e i bottoni sotto di essa
$vbox0->pack_start($slist, TRUE, FALSE, 0);
$vbox0->pack_start($btnAdd, TRUE, FALSE, 0);
$vbox0->pack_start($btnSave, TRUE, FALSE, 0);
$vbox0->pack_start($btnDel, TRUE, FALSE, 0);
$vbox0->pack_start($btnExit, TRUE, FALSE, 0);
# Aggiungo box0 a $window
$window->add($hbox0);
# mostra tutto
$window->show_all;
#Ciclo principale delle Gtk
Gtk2->main;
0;
==== Installazione delle dipendenze su Windows ====
Per prima cosa installare [[http://strawberryperl.com/|strawberryperl Perl]] e le runtime GTK ([[http://downloads.sourceforge.net/gladewin32/gtk-2.8.20-win32-1.exe]]) poi impartire i seguenti comandi dal terminale di windows(''cmd''):
=== Installazione delle Gtk2 per Perl ===
ppm install Glib
ppm install Cairo
ppm install Pango
ppm install Gtk2
=== Installazione DBI per sqlite2 ===
perl -MCPAN -e shell
cpan> install DBI
cpan[2]> install DBD::SQLite2
==== Caricare il tema grafico delle GTK per Windows ====
Purtroppo per utilizzare il tema grafico per windows sembra che bisogna fare alcuni interventi manuali. Prima di tutto scaricare il bundle con le [[http://www.gtk.org/download/index.php|Gtk2]], 32 o 64bit a seconda della versione installata di Strawberry Perl.
Dopodicchè entriamo nella cartella del bundle gtk e copiamo le cartelle ''"bin"'' ,''"lib"'', ''"etc"'' e "share" nella sottocartella di Strawberry ''[inst. di Strawberry]\perl\site\lib\auto\Gtk2'' .
Fatto questo possiamo caricare il tema nel nostro codice per con:
#Per caricare il tema grafico solo su windows.
if ($^O=='MSWin32') {Gtk2::Rc->set_default_files ("gtkrc")};
Il file "gtkrc" lo possiamo mettere dove vogliamo e deve contenere il
seguente testo:
gtk-theme-name = "MS-Windows"