Sei sulla pagina 1di 93

www.edmaster.

it
Poste Italiane S.p.ASpedizione in A.P. D.L. 353/2003 (conv.in L.27/02/2004 n.46) art.1 comma 2 DCB ROMA Periodicit mensile APRILE 2007 ANNO XI N.4 (113)
PER ESPERTI E PRINCIPIANTI
RIVISTA+CD E4,90 RIVISTA+LIBRO+CD E7,90
VERSIONE PLUS VERSIONE STANDARD
Poste Italiane S.p.A Spedizione in A.P. D.L. 353/2003 (conv.in L.27/02/2004 n.46) art.1 comma 2 DCB ROMA Periodicit mensile MAGGIO 2008 ANNO XII, N.5 (126)
PER ESPERTI E PRINCIPIANTI
SOLUZIONI RIPORTA IN UN LOG I DATI DI UNA PARTITA DI TENNIS VIRTUALE
ANALIZZALI E RECUPERA LE INFORMAZIONI STATISTICHE SULL'ANDAMENTO DEL GIOCO
DRAG & DROP CON SCRIPTACULOUS
SPOSTA GLI ELEMENTI DI UNA PAGINA INTERNET
SEMPLICEMENTE TRASCINANDOLI
i
o
P
r
o
g
r
a
m
m
o






A
n
n
o

X
I
I

-

N

5

(
1
2
6
)

















































E
D
I
Z
I
O
N
I

M
A
S
T
E
R
W
O
R
D

&

E
X
C
E
L
L

D
A
L

W
E
B


M
P
3

F
L
A
S
H

P
L
A
Y
E
R


D
R
A
G

&

D
R
O
P

C
O
N

S
C
R
I
P
T
A
C
U
L
O
U
S


S
T
O
P

A
L
L
E

T
A
B
E
L
L
E
.


L
'
O
R
A

D
E
I

C
S
S
VISUAL BASIC.NET
COMPONI REPORT
EFFICACI CON CRYSTAL
REPORTS
Dai dati alla loro rappresentazione
come farlo in modo semplice
ASP.NET
UN SERVIZIO DI FAX
CENTRALIZZATO
Primi passi per costruire
un'applicazione per l'invio
dei documenti via Web
DEPLOYMENT
DELLE APPLICAZIONI
Ti spieghiamo come mettere online
il sito che hai sviluppato in locale
C#
UN CATTURA SCHERMO
TUTTO TUO
Scopri come funzionano le librerie
per la gestione della grafica
in ambiente Windows
RUBY ON RAILS
IL CORSO PER
IMPARARE SUBITO
In questa puntata: database
e relazioni, come gestirli con
poche e chiare righe di codice
MP3 FLASH PLAYER
Come sviluppare il riproduttore perfetto, personalizzando
le funzionalit e la grafica esattamente come piace a te!
TEORIA Anatomia
dei formati XLSX e DOCX
SISTEMA Il setup dell'ambiente
e le operazioni preliminari
CODICE Le librerie da utilizzare
e gli algoritmi di base
ESEMPI Gestisci le celle
di Excel, inserisci immagini
in Word e molto altro ancora...
WORD & EXCEL
DAL WEB
CREA DOCUMENTI OFFICE DIRETTAMENTE
DALLE TUE APPLICAZIONI PHP
JAVA
WICKET: IL NUOVO
WEB FRAMEWORK
Pratico, veloce, innovativo:
noi ti spieghiamo come utilizzarlo
STOP ALLE TABELLE
E L'ORA DEI CSS
Dalla programmazione classica
a quella moderna con i DIV e gli stili
WEB DESIGN
1
2
SN
IP
P
ETT
D
I CO
D
IC
E
da usare subito nei tuoi lavori
TU
TTI i CO
D
ICI
pronti alluso
nel CD
IL CODICE
COMPLETO
NEL CD
Per questo m
ese
ioProgram
m
o + CD
a soli 4,90 anzich 6,90
PREZZO PROM
OZIONE
PREZZO PROM
OZIONE
001_ioprog126.indd 1 2-04-2008 17:21:29
Anno XII - N.ro 05 (126) - Maggio 2008 -
Periodicit: Mensile
Reg. Trib. di CS al n.ro 593 del 11 Febbraio 1997
Cod. ISSN 1128-594X
E-mail: ioprogrammo@edmaster.it
http://www.edmaster.it/ioprogrammo
http://www.ioprogrammo.it
Direttore Editoriale: Massimo Sesti
Direttore Responsabile: Massimo Sesti
Responsabile Editoriale: Gianmarco Bruni
Vice Publisher: Paolo Soldan
Redazione: Fabio Farnesi
Collaboratori: R. Allegra, O Peli, F. Grimaldi,
C. Lollo, E. Bottari, P. Perrotta, G. Fiore
Consulenza Redazionale: SET S.r.l.
G. Forlino, P. Mannelli
Segreteria di Redazione: Emanuela Giordano
Realizzazione grafica: Cromatika S.r.l.
Art Director: Paolo Cristiano
Responsabile grafico di progetto: Salvatore Vuono
Responsabile area tecnica: Giancarlo Sicilia
Illustrazioni: M. Veltri
Impaginazione elettronica: Francesco Cospite, Lisa Orrico,
Nuccia Marra, Luigi Ferraro
Realizzazione Multimediale: SET S.r.l.
Realizzazione CD-Rom: Paolo Iacona
Pubblicit: Master Advertising s.r.l.
Via C. Correnti, 1 - 20123 Milano
Tel. 02 831212 - Fax 02 83121207
e-mail advertising@edmaster.it
Sales Director: Max Scortegagna
Editore: Edizioni Master S.p.a.
Sede di Milano: Via Ariberto, 24 - 20123 Milano
Sede di Rende: C.da Lecco, zona ind. - 87036 Rende (CS)
Presidente e Amministratore Delegato: Massimo Sesti
Direttore Generale: Massimo Rizzo
ABBONAMENTO E ARRETRATI
ITALIA: Abbonamento Annuale: IOPROGRAMMO (11 NUMERI)
E59,90 SCONTO 21% SUL PREZZO DI COPERTINA DI E75,90
IOPROGRAMMO CON LIBRO (11 NUMERI) E75,90 SCONTO 30%
SUL PREZZO DI COPERTINA DI E108,90
Abbonamento Biennale: IOPROGRAMMO (22 NUMERI) E75,90
SCONTO 50% SUL PREZZO DI COPERTINA DI E151,80
IOPROGRAMMO CON LIBRO (22 NUMERI) E108,90 SCONTO 50%
SUL PREZZO DI COPERTINA DI E217,80 OFFERTE VALIDE FINO AL
30/06/2008.
Costo arretrati (a copia): il doppio del prezzo di copertina + E
5. 32 spese (spedizione con corriere). Prima di inviare i
pagamenti, verificare la disponibilit delle copie arretrate allo 02
831212.
La richiesta contenente i Vs. dati anagrafici e il nome della riv-
ista, dovr essere inviata via fax allo 02 83121206, oppure via
posta a EDIZIONI MASTER via C. Correnti, 1 - 20123 Milano, dopo
avere effettuato il pagamento, secondo le modalit di seguito
elencate:

cc/p n.16821878 o vaglia postale (inviando copia della ricevuta


del versamento insieme alla richiesta);

assegno bancario non trasferibile (da inviarsi in busta chiusa


insieme alla richiesta);

carta di credito, circuito Visa, Cartas, o Eurocard/Mastercard


(inviando la Vs. autorizzazione, il numero di carta di credito, la
data di scadenza, l'intestatario della carta e il codice CVV2, cio le
ultime 3 cifre del codice numerico riportato sul retro della carta).

bonifico bancario intestato a Edizioni Master S.p.A. c/o BCC


MEDIOCRATI S.C.AR.L. IBAN: IT 85 Q 07062 80881 000000012000
(inviando copia della distinta insieme alla richiesta).
SI PREGA DI UTILIZZARE IL MODULO RICHIESTA ABBONAMENTO PO -
STO NELLE PAGINE INTERNE DELLA RIVISTA. Labbonamento ver r
attivato sul primo numero utile, successivo alla data della ri chiesta.
Sostituzioni: qualora nei prodotti fossero rinvenuti difetti o
imperfezioni che ne limitassero la fruizione da parte dellutente,
prevista la sostituzione gratuita, previo invio del materiale
difettato.
La sostituzione sar effettuata se il problema sar riscontrato e
segnalato entro e non oltre 10 giorni dalla data effettiva di acqui-
sto in edicola e nei punti vendita autorizzati, facendo fede il tim-
bro postale di restituzione del materiale.
Inviare il CD-Rom difettoso in busta chiusa a:
Edizioni Master - Servizio Clienti - Via C. Correnti, 1 - 20123
Milano
Assistenza tecnica: ioprogrammo@edmaster.it
Stampa: Arti Grafiche Boccia S.p.a. Via Tiberio Felice, 7 Salerno
Duplicazione CD-Rom: Neotek S.r.l. - C.da Imperatore - Bisignano
(CS)
Distributore esclusivo per lItalia: Parrini & C S.p.A.
Via Vitorchiano, 81 - Roma
Finito di stampare nel mese di Aprile 2008
Nessuna parte della rivista pu essere in alcun modo riprodotta
senza auto riz zazione scritta della Edizioni Master. Manoscritti e
foto originali, anche se non pubblicati, non si restituiscono.
Edizioni Ma ster non sar in alcun caso responsabile per i danni
diretti e/o indiretti derivanti dallu ti lizzo dei pro gram mi contenuti
nel supporto mul ti me dia le allegato alla rivista e/o per even tua li
anomalie degli stessi. Nessuna responsabilit , inol tre, assunta
dalla Edizioni Master per danni o altro derivanti da virus
informatici non riconosciuti dagli antivirus ufficiali allatto della
ma ste riz zazione del supporto. Nomi e mar chi protetti sono citati
senza indicare i relativi brevetti.
Rispettare luomo e lambiente in cui esso vive e lavora una parte
di tutto ci che facciamo e di ogni decisione che prendiamo per
assicurare che le nostre operazioni siano basate sul continuo
miglioramento delle performance ambientali e sulla prevenzione
dellinquinamento
M
Strano a dirsi, si ha la percezione che i virus non sia-
no pi un problema, che i dati siano al sicuro e che si
sia creato un certo equilibrio fra le forze del male e le
forze del bene! Proviamo a fare un salto indietro nel
tempo. Fino a due anni fa l'argomento del giorno era-
no gli antivirus. Chi non aveva l'antivirus pi aggior-
nato, pi efficace, pi innovativo era un uomo finito,
intrappolato nelle maglie degli hacker. Fino a qual-
che anno fa, chi non metteva in sicurezza, persino il
proprio computer di casa, con un super firewall era con-
siderato un pivello nelle mani delle forze oscure. E
infine, sempre fino a pochi anni fa, di tanto in tanto
si diffondeva la notizia che questo o quel virus era
pronto a mettere in ginocchio la rete in meno di un bat-
tito di ciglia. Ed ora? Ora la percezione rispetto ai pro-
blemi della sicurezza cambiata. Non dico che non
si parli pi di virus, hacking e sicurezza, ma si ha la
percezione che le contromisure adottate siano effi-
caci. Perch? Una prima risposta chiara: Microsoft
ha rilasciato Windows Vista, ed effettivamente il si-
stema sembra essere blindato. Anche troppo secon-
do alcuni, pi protetto dalle disattenzioni dell'uten-
te inesperto che dagli attacchi degli hacker secondo
altri, e tuttavia la prima protezione sempre la pi
efficace. Una seconda risposta che ormai l'hacking
diventato un business per cui gli attacchi sono pi
rivolti alle aziende che agli utenti. Altri potrebbero
pensare, maliziosamente, che dopo il rilascio di Vi-
sta la parola insicurezza sia diventata improvvisamente
bandita dal tam tam della comunicazione in rete. In
tutto questo mi fa sorridere l'idea che in una recente
sfida proprio in materia di sicurezza, gli hacker ab-
biamo affossato per primo Mac OSX, per secondo Vi-
sta ed infine una Ubuntu. D'altra parte c il sospet-
to che per un hacker affondare il sistema che ama di
pi sarebbe un po' come darsi una coltellata...
LUniverso Tecnologico
www.itportal.it
Servizio Abbonati:
(tel. 02 831212
@ e-mail: servizioabbonati@edmaster.it
Allinizio di ogni articolo, troverete un simbolo
che indicher la presenza di codice e/o software
allegato, che saranno presenti sia sul CD (nella
posizione di sempre \soft\codice\ e \soft\tools\)
sia sul Web, allindirizzo
http://cdrom.ioprogrammo.it
J CD J WEB
nome_file.zip
Questo mese su ioProgrammo
SICUREZZA, UN'OSSESSIONE!
Certificato n.6168
del 11/12/2007
TEORIA Anatomia dei formati
XLSX e DOCX
SISTEMA Il setup dellambiente
e le operazioni preliminari
CODICE Le librerie da utilizzare
e gli algoritmi di base
ESEMPI Gestisci le celle
di Excel, inserisci
immagini in Word
e molto altro ancora...

Certificato UNI EN ISO 14001


N.9191.EMAS
WORD & EXCEL
DAL WEB
CREA DOCUMENTI OFFICE DIRETTAMENTE
DALLE TUE APPLICAZIONI PHP
004-005 editoriale:004-005 editoriale 2-04-2008 18:34 Pagina 4
Questo mese su ioProgrammo
QUALCHE CONSIGLIO UTILE
I nostri articoli si sforzano di
essere com prensibili a tutti coloro
che ci seguono. Nel caso in cui
abbiate difficolt nel comprendere
esattamente il senso di una
spiegazione tecnica, utile aprire
il codice allegato allarticolo e
seguire passo passo quanto viene
spiegato tenendo docchio lintero
progetto.
http://forum.ioprogrammo.it
stile. Abbandoniamo luso delle tabelle
per disegnare il layout della pagina Web
e vediamo come utilizzare i CSS per
creare siti Web pi accessibili e gestibili.
Dimentichiamo il tag table
SISTEMA
Creare report con Visual Basic.Net
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 72
Grafici e reportistica rappresentano una
parte importante di ogni applicazione.
Visual Studio offre strumenti avanzati
per la creazione di report professionali.
In questo articolo spiegheremo passo
dopo passo come usarli
MULTIMEDIA
Dotare una pagina Web di un MP3
Player . . . . . . . . . . . . . . . . . . . . pag. 80
In questo articolo descriveremo come
realizzare un lettore MP3 per i nostri siti
Web. Utilizzeremo la tecnologia messa a
disposizione da macromedia Flash e
Come sviluppare il produttore perfetto, personalizzando
le funzionalit e la grafica esattamente come piace a te!
pag. 80
integreremo il tutto con una struttura
XML di supporto
GRAFICA
Andiamo a caccia per il desktop
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 92
Creiamo in modo semplice e veloce un
progetto C# in grado di catturare e
salvare, nel formato che preferiamo,
singole porzioni o tutta larea di lavoro
del nostro desktop
SISTEMA
Ruby on rails: oggetti e relazioni
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 96
Conservare dati Object-Oriented in un
database relazionale spesso un lavoro
difficile e complicato. Ma non con la
libreria activerecord di rails, che rende
questo compito gravoso addirittura
divertente
SOLUZIONI
Simulazione random di giochi
. . . . . . . . . . . . . . . . . . . . . . . . . pag. 111
Come comandare dei client di
animazione come Flash simulando giochi
o sport. La soluzione produrre file di
log costruiti intorno a dei parametri di
gioco e con una forte componente
casuale
MP3 FLASH PLAYER
Gli allegati di ioProgrammo
pag. 8
Il software in allegato alla rivista
Il libro di ioProgrammo
pag. 6
Il contenuto del libro in allegato
alla rivista
News pag. 10
Le pi importanti novit del
mondo della programmazione
Tips & Tricks pag. 48
Una raccolta di trucchi da tenere
a portata di... mouse
Software pag. 106
I contenuti del CD allegato
ad ioProgrammo.
RUBRICHE
IOPROGRAMMO WEB
Creare un file Word da PHP
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 20
Non solo testo, ma anche immagini,
tabelle e altre strutture. Sono solo alcune
delle informazioni che possono essere
contenute in un file Word. In questo
numero impareremo come creare con
PHP documenti di questo tipo
Invia i tuoi fax tramite Asp.Net
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 28
Alla scoperta del servizio fax integrato in
Windows. Vedremo come utilizzare
interfacce specifiche per accedere alle
funzioni supportate. Inoltre getteremo le
basi per costruire unapplicazione Web
che ne faccia uso
Web application con asp.net 2.0
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 38
In questa puntata, che conclude il nostro
percorso di analisi della tecnologia
Asp.Net 2.0, affronteremo le modalit di
installazione di una Web Application.
Ripercorreremo,inoltre, i passi da
eseguire per il deployment su un server
Drag & Drop nelle applicazioni Web
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 43
Per gli ambienti desktop siamo abituati a
usare il Drag & Drop ogni giorno.
Muoviamo file da una cartella allaltra,
ecc. In questarticolo vedremo come
poter usare questa potente feature
anche in applicazioni Web
SISTEMA
Il Webframework per tutti i gusti
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 52
Sono molti i Web Framework offerti dal
mondo Open Source agli sviluppatori
Java. Wicket lemergente che presenta
molte caratteristiche che lo rendono
unico e facile da utilizzare oltre che
conforme al pattern MVC
IOPROGRAMMO WEB
Stop alle tabelle pagine Web con i CSS
. . . . . . . . . . . . . . . . . . . . . . . . . . pag. 63
Penultimo appuntamento con i fogli di
004-005 editoriale:004-005 editoriale 2-04-2008 18:35 Pagina 5
ht t p: / / www. i opr ogr ammo. i t
G
6
/Maggio 2008
Le versioni di ioProgrammo
RIVISTA
+
LIBRO
+
CD-ROM
in edicola
7
,90
h
V
e
r
s
io
n
e
P
L
U
S
I contenuti del libro
S
QL, acronimo di Structured Query Language,
il linguaggio standard per l'interrogazione di
database, che sta alla base di tutti i programmi
di gestione, da Access a Oracle fino a MySQL. La sua
diffusione assolutamente indiscutibile: chiunque
abbia a che fare con i database deve, prima o poi,
relazionarsi con questo linguaggio. Questo volume
offre un'introduzione a SQL agile ed efficace per chi
voglia impararlo da zero, e una guida di riferimento
ragionata che pu essere molto comoda e utile
anche per chi conosce gi il linguaggio e ha bisogno
di un riferimento veloce e completo, di
consultazione immediata. Vengono presentate la
sintassi del linguaggio ma anche una serie di
esempi e applicazioni mirati a risolvere una
casistica piuttosto ampia di problemi. Si tratta di un
handbook da tenere sempre a portata di mano...
LA GUIDA TASCABILE AL LINGUAGGIO
DEI DATABASE RELAZIONALI
Le caratteristiche dei database
relazionali, i concetti base di SQL
Il controllo dellesecuzione, la gestione
delle eccezioni
Funzioni, array, classi e oggetti
Lavorare con le stringhe e con le date
Database (con MySQL, ODBC, Oracle)
Algoritmi: ordinamento, ricerca...
SQL - GUIDA TASCABILE
006 Presentaz Libro:008 2-04-2008 18:37 Pagina 6
ht t p: / / www. i opr ogr ammo. i t
G
8
/Maggio 2008
Posta elettronica con Visual basic
Le versioni di ioProgrammo
Come usare linterfaccia del CDRom
V
e
r
s
io
n
e
B
A
S
E
4
,90
h
RIVISTA
+
CD-ROM
in edicola
4
TOOL INDISPENSABILI
PER SEMPLIFICARE IL LAVORO
DI OGNI GIORNO
.NET
ESSENTIAL PACK
Il top software del mese
individuato dalla redazione
IN EVIDENZA
Il software diviso
in categorie per
una comoda consultazione
IL SOFTWARE
Torna alla pagina iniziale
del CD-ROM
HOME
Vuoi inviare una email alla
redazione con le tue richieste
CONTATTACI
I siti pi interessanti
del mese selezionate
per te
TOP SITES
Il database di tutti i software
pubblicati da ioProgrammo
anche gli arretrati
RICERCA SOFTWARE
Abbonamenti informazioni
e servizi utili
INFO
Lelenco del software
contenuto nelle categorie
IL SOFTWARE
La dimensione
del software sul CD
DIMENSIONE
Clicca qui per installare o
salvare il software sul tuo PC
SALVA
Una accurata recensione
dei contenuti
IL SOFTWARE
ASP.NET Switcher
Cambia la versione di .NET al volo
NANT 0.86
Compila il codice ad orari prestabiliti
NUNIT 2.4.6
Il software per creare test
automatizzati per i tuoi programmi
.NET Reflector
Decompila e risali al sorgente
anche quando non hai l'originale

008 Presentaz CDRom 1:010 2-04-2008 18:19 Pagina 8


ht t p: / / www. i opr ogr ammo. i t
NEWS M
G
10
/Maggio 2008
News
LE LIBRERIE QT
ANCHE PER
WINDOWS CE
T
rolltech ha rilasciato una preview
delle librerie QT 4.4 compatibili anche
con sistemi Windows CE e Windows Mo-
bile versione 5.0 e 6.0. Le Qt offrono un
framework che permette agli sviluppa-
tori di compilare software per diverse
piattaforme, senza dover riscrivere il co-
dice ad hoc per ciascuna di esse. E cos pos-
sibile scrivere unapplicazione C++ e ve-
derla girare indifferentemente su Win-
dows, Mac, Linux e ora anche su siste-
mi equipaggiati con Windows CE. Que-
sto il link per il download
http://trolltech.com/downloads/opensource
LIMO FOUNDATION
PRESENTA UN
RIVALE DI GOOGLE
ANDROID
L
iMo Foundation (http://www.limofoun -
dation.org) ha dichiarato di aver con-
cluso lo sviluppo di un sistema operati-
vo Linux rivolto al mercato mobile.
Lapplicazione, denominata LiMo Platform
Release 1, mette a disposizione un vero
e proprio sistema operativo orientato al
mondo mobile ed gi stata fornita a
societ come Motorola, Texas Instru-
ments e Samsung nonch alloperatore
Vodafone e NTT DoCoMo. LiMo Platform
integra il framework GTK di GNOME e
diverse API che permettono di accedere
nativamente alle funzioni dei vari di-
spositivi. Insomma, un concorrente che
sicuramente potr dare filo da torcere a
Google Android, progetto similare mol-
to chiacchierato. I primi cellulari basati
sulla nuova piattaforma dovrebbero ve-
dere la luce entro fine anno, tra questi i
nuovi Motorola Rokr e RAZR.
SVILUPPARE PER LA CONSOLE
NINTENDO WII
N
intendo, in occasione della
Game Developers Conference
ha annunciato che entro il prossi-
mo maggio rilascer una nuova
piattaforma di sviluppo che per-
metter di creare videogame per la
console Wii. Gli utenti potranno
quindi collegarsi a una pagina web
e scaricare i diversi giochi realizzati
da terze parti. "WiiWare permetter
a piccoli sviluppatori dotati di
grandi idee ma scarsi fondi di rea-
lizzare finalmente i propri progetti e
renderli disponibili a un vastissimo
pubblico e vedere se riuscire a tro-
vare il prossimo titolo di successo.
WiiWare porta la creativit a nuovi
livelli e aumenta il valore della sem-
pre crescente popolazione di pos-
sessori di Wii", queste quanto
dichiarato il presidente di Nintendo
America Reggie Fils-Aime.
PHP SU WINDOWS SERVER 2008
GIRA PI VELOCE DEL 130%
A
rriva direttamente dal blog di
MSDN la notizia: PHP pi veloce
del 130% su Windows Server 2008.
Microsoft, infatti, da test effettuati su
un cliente, Virtual Maps, che gestisce
e mantiene un sito di viaggi a
Singapore, ha appurato che grazie al
supporto integrato di FastCGI, il
sistema operativo by Microsoft per-
metterebbe di incrementare notevol-
mente la velocit di esecuzione degli
script. Sul blog presente un grafico
dettagliato dei test effettuati. Il case
study completo reperibile a questo
indirizzo web:
http://tinyurl.com/3xcpup
HACKER SCOPRONO SU UN SERVER
DI MICROSOFT IL CODICE SORGENTE
DI WINDOWS VISTA
U
n hacker afferente ad un gruppo
macedone, capeggiato da Loo
Flirpa, ha scoperto un server Microsoft,
ora patchato, che per un certo periodo di
tempo ha dato modo ad alcuni hacker di
scaricare il codice sorgente di Windows
Vista. Flirpa ha commentato: Questi
Windows Server, sono giocattoli per i
bambini, violarli davvero fin troppo
semplice. Microsoft afferma per che il
furto non sia dovuto a problemi di sicu-
rezza dei server, dichiarando che far di
tutto per far valere il proprio copyright.
Il file, di circa 4.2GB, presente su diver-
si circuiti torrent con il nome
Ballmers_Balls.zip.
010-011:014-015 1-04-2008 18:12 Pagina 10
ht t p: / / www. i opr ogr ammo. i t
NEWS M
Maggio 2008/
11
G
News
A
dobe ha annunciato una versione alpha di Ado-
be Air (Adobe Integrated Runtime ) per Linux.
Grazie al software, presentato per Windows e Mac
OS X circa un anno fa, anche gli utenti del pingui-
no avranno modo di creare Rich Internet Applica-
tion per desktop o progettare applicazioni per il
Web, il tutto sfruttando un framework capace di
fornire tutti gli strumenti necessari. Sar cos possibile
far girare sul proprio desktop applicazioni general-
mente appannaggio del solo web. Adobe Air si po-
ne, di fatto, come diretto concorrente di altre ap-
plicazioni similari, in primis Silverlight e Google
Gears.
Air permetter di utilizzare indipendente HTML/AJAX o
Flash/ Flex. Link per download:
RILASCIATA
LA VERSIONE 2.5
DI WORDPRESS
I
n anticipo rispetto ai normali tempi di lavora-
zione, stata rilasciata la nuova versione di Word-
press, la 2.5 . La popolarissima piattaforma per
creare e gestire blog. Numerose le migliore e mo-
difiche effettuate, in particolare, nella zona di am-
ministrazione. Dalla nuova organizzazione della
Dashboard (ora dotata di molti widgets), alla pos-
sibilit di effettuare upload multipli per una pi
veloce creazione di gallerie fotografiche. Leditor
per scrivere e correggere i post utilizza lultima
versione di TinyMCE (la 3.0); migliorata anche la
gestione dei TAG, che limiter lutilizzo di plugin ag-
giuntivi.
ADOBE ANNUNCIA UNA PRE-RELEASE
DI AIR PER AMBIENTI LINUX
I
l vero aggiornamento del sistema
operativo della casa di Redmond per
palmari sar quello di Windows Mo-
bile 7, ma nel frattempo Microsoft ag-
giunge alcune migliorie allattuale ver-
sione. Con luscita della 6.1 sar possibile
usufruire di una migliore interfaccia
per la fotocamera e di una probabile
uscita TV per collegare il palmare al-
lo schermo del salotto sar possibile
interagire meglio con Windows Live,
inviando direttamente e a questultimo
foto e filmati da pubblicare sul web.
L
a casa di Mountain View (in particolare la sezione Google Government)
ha stretto un accordo con la CIA (Central Intelligence Agency) per
linstallazione di alcuni server che utilizzano il motore di Google per effet-
tuare ricerche. Grazie alla tecnologia di Google ogni agente della CIA potr
condividere con i colleghi il bagaglio di esperienza e informazioni raccolte
nellarco della carriera. Al momento sono quasi 40.000 gli utenti che si so-
no registrati, creando oltre 30.000 voci nel database. Intellipedia (cos si
chiamer questa sorta di Wikipedia riservata agli 007 americani) raccoglier
dati, storie e informazioni riguardo persone, luoghi ed eventi interessanti
per il lavoro spionistico.
NUOVE FEATURE MULTIMEDIALI
PER WINDOWS MOBILE 6.1
GOOGLE VENDE LA SUA
TECNOLOGIA ALLA CIA
010-011:014-015 1-04-2008 18:12 Pagina 11
ht t p: / / www. i opr ogr ammo. i t
COVER STORY M
G
12
/Maggio 2008
Interfacciare PHP con Excel
C
ome si visto in precedenti articoli, il nuovo
formato di Office 2007 non prevede pi dei
file binari, difficilmente accessibili, ma dei
file compressi di tipo ZIP, al cui interno si trova una
ben precisa gerarchia di directory, file XML e file di
immagini che risponde ad uno standard (l ECMA
TC45 Open Office XML). Questo nuovo formato,
per sua natura, quindi facilmente accessibile da
qualsiasi programma ed altrettanto facile costruire
un file da un software che non sia lo stesso Office
2007, basta infatti rispettare i canoni imposti dallo
standard nel costruirlo che questo sar facilmente
riconoscibile dallapplicazione Office per il quale
destinato. Mentre nei precedenti articoli si esami-
nato come sia possibile creare dei file Word (forma-
to DOCX), in questo iniziamo ad esaminare come
siapossibile creare un file Excel (formato XLSX).
Come linguaggio di programmazione useremo
ancora il PHP, rilevando come comunque facile
portare il codice in altri linguaggi.
BREVE ANATOMIA
DI UN DOCUMENTO XLSX
Come detto, un documento di Office Open XML
costruito da una serie di elementi relazionati tra loro
in modo noto a priori, archiviati in un contenitore
detto package. Aprendo un file XLSX con un pro-
gramma di gestione di file compressi, come ad
esempio 7-ZIP, la struttura interna del documento
appare a prima vista analoga a quella di un file
DOCX. Infatti nella root del file ZIP troviamo gli stes-
si file e le stesse directory di un documento Word
(fatta eccezione per la directory word che viene
sostituita dalla directory xl).
Esaminando il contenuto della directory xl si nota-
no immediatamente le differenze rispetto a quanto
visto per un file di Word, come si pu vedere in
Figura 1. Allinterno di questa troviamo infatti solo
due file: styles.xml (analogo a quello presente in un
file DOCX, contiene solo delle informazioni sugli
stili dei font) e workbook.xml. In questo secondo
sono contenute le informazioni inerenti a di vari
fogli di lavoro Excel (in inglese: worksheets) pre-
senti nel file. Il contenuto di questultimi si trova
nella directory worksheets e, come si vede nella
Figura 2, avremo un file XML dal nome sheetN.xml,
con N pari al numero del foglio. Si noti come il caso
particolare che stiamo esaminando quello di un
documento Excel di default, dove vengono creati di
base tre fogli di lavoro.
STRUTTURA BASE DEL
FILE WORKBOOK.XML
Come detto, compito di questo file di gestire i pun-
tatori ad i vari sheet del documento Excel. La struttu-
ra interna di questo file molto semplice e di facile
costruzione ed i tag XML presenti allinterno di que-
sto e degli altri file rispondono ad una ben precisa
sezione dello standard che prende il nome di
SpreadsheetML.
La prima riga di questo file deve, ovviamente, conte-
nere il classico tag di apertura di un file XML, dove
Conoscenze richieste
Conoscenza di base di
PHP
Software
PHP, APACHE, 7-ZIP
Impegno
Tempo di realizzazione
REQUISITI
FOGLI ELETTRONICI
USANDO PHP
IMPARIAMO COME STRUTTURATO INTERNAMENTE UN FILE NEL NUOVO FORMATO DI EXCEL
2007 E COME POSSIBILE, GRAZIE A TALE STRUTTURA, CREARE UN FILE XLSX DA PHP O DA
ALTRI LINGUAGGI SENZA DISPORRE DI EXCEL INSTALLATO
J CD J WEB
class_phpxlsx.php
cdrom.ioprogrammo.it
Fig. 1: Dettaglio del contenuto della cartella xl di
un file XLSX
Fig. 2: Dettaglio del contenuto della cartella
xl/worksheets di un file XLSX
012-017:032-035 1-04-2008 16:06 Pagina 12
specifichiamo la versione e la codifica di ISO per
linterpretazione dei dati.
<?xml version="1.0" encoding="iso-8859-1" ?>
Lelemento radice seguito dal tagworkbook, per
cui il nostro file (fatta eccezione per la prima riga)
deve avere i vari tag contenuti in una sequenza
< workbook>
.
</ workbook>
Tuttavia sempre bene specificare i diversi name-
space dei tag avanzati che verranno eventualmente
usati successivamente (che non verranno trattati in
questo articolo). Per non sbagliare, sempre bene
inserire la lista completa, come segue:
<workbook
xmlns="http://schemas.openxmlformats.org/spreads
heetml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeD
ocument/2006/relationships">
Di base, allinterno dei tag visti, supponendo di
avere un singolo foglio di lavoro e non volendo
impostare una serie di parametri per effettuare delle
gestioni avanzate del foglio, troveremo semplice-
mente lindicazione del suddetto foglio come segue:
<sheets>
<sheet name="Sheet1" sheetId="1" r:id="rId1"/>
</sheets>
Si noti come lattributo name il nome che appa-
re sulla targhetta del foglio di lavoro, posta in basso
a sinistra. Oltre alla collezione dei fogli vista, possi-
bile impostare alcune propriet avanzate, come ad
esempio istruire lapplicazione che apre il file di
creare un backup nel momento in cui si effettua un
salvataggio, che vedremo in occasioni successive.
WORKBOOK.XML.RELS:
IL FILE DELLE RELAZIONI
Prima di esaminare in dettaglio come costruire il file
xml di un foglio di lavoro, necessario identificare
come viene associato il file xml particolare al foglio
definito in workbook.xml. Infatti allinterno di que-
stultimo si impostato solo il nome dello sheet ed
un ID. Lanello mancante tra il file sheet1.xml e
lentry vista si imposta allinterno del file che pilota
le relazioni interne al documento XLSX; questo si
trova allinterno della sottodirectory _rels e si chia-
ma workbook.xml.rels. Nel caso particolare in
esame, a valle del solito tag di apertura di un file
XML, troveremo la seguente sequenza di tag:
<Relationships
xmlns="http://schemas.openxmlformats.org/package
/2006/relationships"><Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDoc
ument/2006/relationships/worksheet"
Target="worksheets/sheet1.xml"/><Relationship
Id="rId5"
Type="http://schemas.openxmlformats.org/officeDoc
ument/2006/relationships/styles"
Target="styles.xml"/><Relationship Id="rId4"
Type="http://schemas.openxmlformats.org/officeDoc
ument/2006/relationships/theme"
Target="theme/theme1.xml"/></Relationships>
Si noti il tag iniziale che specifica il namespace dei
dati inseriti ed il secondo che connette lID prima
visto con il file sheet1.xml, posto nella sottodirectory
worksheets.
SHEET1.XML: IL FILE
EFFETTIVO DEL FOGLIO
A questo punto possiamo esaminare il file
sheet1.xml, che contiene i dati del nostro foglio di
lavoro. Al solito, le prime righe sono occupate dal tag
di apertura di un file XML e da un tag di namespace,
che specifica che stiamo dettagliano un worksheet.
Questultimo in particolare assume la seguente
forma.
<worksheet
xmlns="http://schemas.openxmlformats.org/spreads
heetml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/office
Document/2006/relationships">
Il tag successivo, detto dimension, ci permette di
specificare tramite lattributo ref larea effettiva del
nostro foglio dove sono contenuti i dati. Tale area
viene specificata usando il sistema di coordinate
dello stesso Excel, che usa le lettere sullasse delle
ascisse ed i numeri su quello delle ordinate. Per cui
se i dati che vogliamo inserire occupano un quadra-
to 4x4
ht t p: / / www. i opr ogr ammo. i t
M
COVER STORY
Maggio 2008/
13
G
Interfacciare PHP con Excel
NOTA
CHIAMATE
ASINCRONE
IN ASP.NET
Per approfondire
largomento
ICallbackEventHandler
e, pi in generale,
limplementazione
delle chiamate
asincrone, possiamo
fare riferimento
allarticolo
Implementing Client
Callbacks
Programmatically
Without Postbacks in
ASP.NET Web Pages
della libreria MSDN
allindirizzo:
http://msdn2.microsoft
.com/en-
us/library/ms178208.as
px).
Alla definizione dello standard
TC45 (Office Open XML File
Formats) non ha ovviamente
partecipato solo la Microsoft, ma
anche le seguenti
aziende/organizzazioni: Apple,
Barclays Capital, BP, The British
Library, Essilor, The Gnome
Foundation, Intel, The Library of
Congress, NextPage, Novell,
Statoil, and Toshiba. Lo standard
in se stato approvato da una
assemblea generale dellEcma nel
dicembre 2006.
LOGGETTO XMLHTTPREQUEST
012-017:032-035 1-04-2008 16:06 Pagina 13
ht t p: / / www. i opr ogr ammo. i t
COVER STORY
M
G
14
/Maggio 2008
Interfacciare PHP con Excel
<dimension ref="A1:D4"/>
Di seguito, bene inserire dei tag che indicano
quale sar la cella attiva quando andremo ad aprire
il nostro documento XLSX. Supponendo di avere
come cella attiva la C3, avremo bisogno della
seguente sequenza:
<sheetViews>
<sheetView tabSelected="1"
workbookViewId="0">
<selection activeCell="C3"
sqref="C3"/>
</sheetView>
</sheetViews>
Ultimo elemento da inserire, prima di iniziare a
popolare il foglio di dati, lindicazione dellaltezza
delle celle in punti. Di base questo deve essere come
segue:
<sheetFormatPr defaultRowHeight=15/>
E ora finalmente possibile iniziare a popolare il
nostro foglio coi dati Di default, le celle di Excel sono
vuote, quindi ci che bisogna indicare sono le celle
che contengono qualcosa. Queste indicazioni
saranno raccolti tra due tag di tipo
<sheetData>
.
</sheetData>
Allinterno di questi, troviamo le informazioni sulle
celle organizzate per righe. Per ognuna di queste
avremo una sequenza di tipo
<row r=".." spans=".">
.
</row>
Dove la propriet r (reference) specifica il numero
della riga e spans specifica gli indici (numerici)
delle colonne tra cui sono compresi i dati, separate
da :. Per cui, nel caso particolare in esame (in cui
supponiamo di avere popolate le celle del quadrato
4x4 superiore), per la prima riga avremo:
<row r=1 spans=1:4>
Le varie celle sono poi specificate col tag
<c r="" t="." >
.
</c>
In questo caso la propriet r specifica la cella con
le coordinate di Excel, per cui nel caso della prima
cella in alto a sinistra avremo un
r=A1
Mentre la propriet t indica il tipo di dati che tro-
viamo allinterno della cella. Supponendo di voler
gestire del testo o valori numerici, la propriet t
pu assumere rispettivamente il valore inlineStr e
n (se si omette di specificare il valore di t Excel
supporr che vi siano dei valori numerici). Nel caso
si sia specificato del testo, allora questo sar rac-
chiuso tra la seguente sequenza di tag
<is><t>TESTO</t></is>
Mentre se stiamo inserendo un valore numerico,
dovremo usare i tag
<v>VALORE</v>
Infine, se si vuole inserire una formula, allora la
sequenza sar:
<f>FORMULA</f>
<v>VALORE</v>
Dove il VALORE leventuale risultato delle formula
stessa.
Terminati i dati delle celle, il file si chiude con una
indicazione sui margini di stampa, usando il
seguente tag.
<pageMargins left="0.7" right="0.7" top="0.75"
bottom="0.75" header="0.3" footer="0.3"/>
SETUP DELLAMBIENTE
Per poter manipolare un file XLSX lapproccio pi
semplice da seguire costruire un archivio ZIP con
la struttura delle directory gi pronta e, una volta
costruiti i vari file previsti al suo interno in base alle
necessit, aggiungere questi file allarchivio in
modo batch. In particolare possibile prendere un
vero file XLSX e spogliarlo dei vari file che si inten-
LEcma una associazione
internazionale il cui scopo la
standardizzazione in ambito
tecnologico, come software,
hardware e comunicazioni. I
membri non sono singole
persone ma
organizzazioni/aziende. Alcuni
degli standard definiti da
questa associazione vengono
poi sottomessi anche ad altri
enti, come ISO, IEC, ETSI ed
altri. Si noti come, a differenza
delle altre organizzazioni, gli
standard Ecma sono sempre
liberamente scaricabili dal sito
dellassociazione http://www.ecma-
international.org
LASSOCIAZIONE ACMA
012-017:032-035 1-04-2008 16:06 Pagina 14
ht t p: / / www. i opr ogr ammo. i t
de sostituire, in modo da avere rapidamente la cor-
retta gerarchia interna del file a disposizione; di
seguito, indicheremo questo file come
master_xls.xlsx, o semplicemente master file.
Oltretutto questo semplice approccio permette la
costruzione del file XLSX a prescindere dallam-
biente di programmazione scelto, infatti in questo
modo possibile concentrarsi sulla sola creazione
dei file XML necessari, lasciando ad un software
esterno di gestione di file compressi lonere di
aggiornare larchivio ZIP. Tale operazione di aggior-
namento pu essere demandata allefficiente 7-ZIP,
del quale esiste una versione da riga di comando
con lo stesso nome sia per ambiente Windows che
per Linux, che sfrutteremo nel nostro codice. E
chiaramente necessario assicurarsi di poter lancia-
re in esecuzione il suddetto programma dal nostro
software, ponendolo in una directory inclusa nel
PATH degli eseguibili.
Supponendo di voler costruire il nostro file da un
sistema LAMP/WAMP, altra impostazione da effet-
tuare quella per indicare ad APACHE che un file
XLSX cos manipolato non un file ZIP, ma un file
che deve essere aperto da Excel 2007 (o dalle prece-
denti versioni di Excel, a patto di aver installato una
patch della Microsoft), altrimenti Internet Explorer,
che segue un link che punta ad un file di quel tipo,
segnaler che vuole aprirlo non con Excel, ma col
gestore dei file ZIP presente sul computer. Per far
ci necessario editare il file MIME.TYPES dello
stesso APACHE ed inserire in coda la seguente riga:
application/vnd.openxmlformats docx pptx xlsx
E poi necessario riavviare il Web Server per fargli
digerire la modifica. Infine, per facilitare il compi-
to a 7-ZIP, bene costruire sul file system una direc-
tory di lavoro, dove porremo nella root il master
file ed i file XML costruiti in sottodirectory che
ricalcano la gerarchia di quelle previste nello ZIP, in
modo che laggiornamento/inserimento del file
allinterno dellarchivio avvenga senza dover speci-
ficare una destinazione relativa diversa da quella sul
file system. Per poter fare in modo che due utenti
possano creare in contemporanea dei file, bene
che tale directory di lavoro sia personalizzata in
base allutente ed al documento che si vuole creare.
PHPXLSX: LA CLASSE PHP
PER LA MANIPOLAZIONE
DEI FOGLI DI LAVORO
Per semplicit, supporremo di voler gestire con la
nostra classe, un documento Excel composto di un
solo foglio di lavoro. Come visto, costruire un simile
documento vuol dire:
1. Inizializzazione del documento, popolando i file
ausiliari e costruendo la sezione iniziale del file
sheet1.xml;
2. Costruzione della sezione sheetData del file, in
base alle necessit;
3. Terminazione del file tramite la corretta chiusura
dei tag e inserimento/aggiornamento dei file
costruiti allinterno del master file.
Il passo 1 della sequenza facilmente gestibile dal
costruttore di una classe, mentre il passo 3 pu
essere gestito da distruttore della stessa. A seconda
delle celle che si vuole popolare nel passo 2 (che di
fatto composto da una lunga serie di sottopassi)
potremo invece costruire diversi metodi della
nostra classe.
COSTRUTTORE
E DISTRUTTORE
Analogamente a quanto visto per i documenti
DOCX, per poter rendere la classe pi flessibile pos-
sibile, bene definire una serie di propriet che
gestiscono il master file (nome, senza estensione
docx, e path), il file di output (ancora, nome e path
senza estensioni), gli estremi delle celle da popola-
re (la var_cella_min sar quella pi in alto a sinistra,
la var_cella_max quella pi in basso a destra, secon-
do le coordinate di Excel) ed il nome del foglio di
lavoro. Questi possono essere passati al costruttore
come parametri
class phpxlsx {
var $master_file;
var $master_path;
var $current_file;
var $current_path;
function
__construct($var_current_file,$var_current_path,$var
_master_file,$var_master_path,$var_cella_min,$var_
cella_max,$nome_foglio) {
.
In questo modo possiamo avere pi di un master
file pronto alluso. Chiaramente, i vari parametri
passati al costruttore devono, per robustezza, esse-
re controllati ed in caso di valore nullo gli si pu
attribuire in valore di default. Inoltre, sempre per
robustezza del codice, per le directory (soprattutto
quella di output) bene effettuare un controllo di
esistenza. Ad esempio, per controllare il valore pas-
sato al PATH di output, il codice PHP sar:
if ( is_null($var_current_path) ) {
$this->current_path = "./output";
} else {
$this->current_path = $var_current_path;
}
M
COVER STORY
Maggio 2008/
15
G
Interfacciare PHP con Excel
NOTA
7-ZIP
Si tratta di un
software di gestione
di file compressi
sviluppato da Igor
Pavlov e rilasciato con
licenza GNU. Questo
non solo gestisce la
compressione nei
formati ZIP/BZIP ed in
un formato 7z (basato
sullalgoritmo LZMA),
ma anche in grado di
decomprimere altri
formati, come RAR e
RPM. Sul sito
http://www.7-zip.org,
oltre a poter scaricare
il software, possibile
trovare anche un SDK
per gestire file con
lalgoritmo LZMA.
012-017:032-035 1-04-2008 16:06 Pagina 15
ht t p: / / www. i opr ogr ammo. i t
Creiamo ora la directory di lavoro, supponendo che
questa abbia un nome dato da un prefisso noto e dal
nome stesso del file che vogliamo creare. Il codice
per fare ci sar:
if (!file_exists("./stage_area")) {
mkdir("./stage_area");
}
$newdir = "./stage_area/" . $this->current_file;
mkdir($newdir);
Creiamo ora la directory xl allinterno di quella di
lavoro ed inizializziamo il file workbook.xml.
$newworddir = $newdir . "/xl";
mkdir($newworddir);
$newfile = "./stage_area/" . $this->current_file .
"/xl" . "/workbook.xml";
$handle = fopen($newfile, 'w');
$content = "<?xml version=\"1.0\" encoding=\"iso-
8859-1\" ?>\n";
$content .= "<workbook
xmlns=\"http://schemas.openxmlformats.org/spreads
heetml/2006/main\"
xmlns:r=\"http://schemas.openxmlformats.org/office
Document/2006/relationships\"> \n";
$content .= "<sheets><sheet name=\"" .
$nome_foglio . "\" sheetId=\"1\"
r:id=\"rId1\"/></sheets> \n";
$content = "</workbook>\n";
fwrite($handle, $content);
fclose($handle);
Dopo di questo necessario creare il file delle rela-
zioni workboox.xml.rels
$newworddir = $newdir . "/xl/_rels";
mkdir($newworddir);
$newfile = "./stage_area/" . $this->current_file .
"/xl/_rels" . "/workbook.xml.rels";
$handle = fopen($newfile, 'w');
$content = "<?xml version=\"1.0\" encoding=\"iso-
8859-1\" ?>\n";
$content .= "<Relationships
xmlns=\"http://schemas.openxmlformats.org/packag
e/2006/relationships\">
<Relationship Id=\"rId1\"
Type=\"http://schemas.openxmlformats.org/officeDoc
ument/2006/relationships/worksheet"
Target=\"worksheets/sheet1.xml\"/>
<Relationship Id=\"rId5\"
Type=\"http://schemas.openxmlformats.org/officeDoc
ument/2006/relationships/styles\"
Target=\"styles.xml\"/>
<Relationship Id=\"rId4\"
Type=\"http://schemas.openxmlformats.org/officeDoc
ument/2006/relationships/theme\"
Target=\"theme/theme1.xml\"/>\n";
$content .= "</Relationships>\n";
fwrite($handle, $content);
fclose($handle);
Infine, possiamo inizializzare il file sheet1.xml
$newworddir = $newdir . "/xl/worksheets";
mkdir($newworddir);
$newfile = "./stage_area/" . $this->current_file .
"/xl/worksheets/sheet1.xml ";
$handle = fopen($newfile, 'w');
$content = "<?xml version=\"1.0\" encoding=\"iso-
8859-1\" ?>\n";
$content .= "<worksheet
xmlns=\"http://schemas.openxmlformats.org/spreads
heetml/2006/main\"
xmlns:r=\"http://schemas.openxmlformats.org/office
Document/2006/relationships\">\n";
$content .= "<dimension ref=\"" . $var_cella_min .
":" . $var_cella_max . "\"/>\n";
$content .= "<sheetViews><sheetView
tabSelected=\"1\" workbookViewId=\"0\">";
$content .= "<selection activeCell=\"" .
$var_cella_max . "\" sqref=\"" . $var_cella_max .
"\"/></sheetView></sheetViews>";
$content .= "<sheetFormatPr
defaultRowHeight=\"15\"/>\n";
$content .= "<sheetData>\n";
fwrite($handle, $content);
fclose($handle);
Ultimo passo, portiamo il master file nella root della
directory di lavoro, rinominandolo in base al file di
output.
$fullfile = $this->master_path . "/" . $this-
>master_file . ".xlsx";
$newfile = $newdir . "/" . $this->current_file . ". xlsx";
copy($fullfile,$newfile);
}
A questo punto il lavoro del costruttore completa-
to. Esaminiamo immediatamente il distruttore, che
si deve occupare semplicemente di chiudere i tag di
sheet1.xml ed invocare il gestore dei file compressi
per aggiungere i visti al master.
function __destruct() {
$newfile = "./stage_area/" . $this->current_file .
"/xl/worksheets/sheet1.xml ";
$handle = fopen($newfile, 'a');
$content = " </sheetData><pageMargins
left=\"0.7\" right=\"0.7\" top=\"0.75\"
bottom=\"0.75\" header=\"0.3\"
footer=\"0.3\"/></worksheet>\n";
fwrite($handle, $content);
fclose($handle);
$newdir = "./stage_area/" . $this->current_file;
COVER STORY
M
G
16
/Maggio 2008
Interfacciare PHP con Excel
NOTA
VECCHI
FORMATI
Se si dispone solo di
Excel 2003 (o 2002 o
2000), per poter aprire
un file in formato
DOCX necessario
installare un pacchetto
aggiuntivo della
Microsoft. Tramite
questo sar anche
possibile salvare da un
vecchio Word nel
nuovo formato. Tale
pacchetto
installabile a patto di
avere un sistema
Windows ed Office
pienamente
aggiornati. Per
trovarlo sufficiente
andare sul sito
Microsoft e cercare il
Microsoft Office
Compatibility Pack.
012-017:032-035 1-04-2008 16:06 Pagina 16
ht t p: / / www. i opr ogr ammo. i t
chdir($newdir);
$to_run1 = '7za a ' . $this->current_file . '.xlsx
xl/workbook.xml';
$to_run2 = '7za a ' . $this->current_file . '.xlsx
xl/_rels/workbook.xml.rels';
$to_run3 = '7za a ' . $this->current_file . '.xlsx
xl/worksheets/sheet1.xml';
Chiaramente, se al posto di 7-ZIP si usato un altro
gestore, sar necessario sostituire lultima riga con la
chiamata a questo. In alternativa, possibile rende-
re la classe pi flessibile passando come parametro
al costruttore come richiamare il gestore di file ZIP
(che quindi deve divenire una propriet della classe
stessa). Eseguiti i comandi e controllato che questi
abbiano avuto buon fine, finalmente possibile
copiare il file nella directory di output desiderata e
ripulire la directory di lavoro. In alternativa possi-
bile inserire il codice visto del distruttore in un
metodo flush_file (e poi far semplicemente richia-
mare questo metodo al distruttore), in modo che il
file sia creabile anche senza distruggere la classe.
METODI PER LA
GESTIONE DI INSERIMENTO
DELLE CELLE
In base alla struttura del file sheet1.xml, aggiungere
delle celle vuol dire
1. Gestire linizializzazione della riga.
2. Gestire linserimento delle varie celle.
3. Gestire la chiusura della riga.
Per far ci possibile costruire tre metodi che effet-
tuano le funzioni richieste. Il primo metodo sar
semplicemente il seguente:
function
start_row($var_riga,$var_cella_min,$var_cella_max)
{
$newfile = "./stage_area/" . $this->current_file
. "/xl/worksheets/sheet1.xml";
$handle = fopen($newfile, 'a');
$content = <row r=\"" . $var_riga . "\"
spans=\"" . $var_cella_min . ":" . $var_cella_max .
"\"> ";
fwrite($handle, $content);
fclose($handle);
}
Questo prende in ingresso i tre elementi che caratte-
rizzano la riga visti prima. Il corrispondente metodo
di chiusura di una riga sar, semplicemente:
function end_row() {
$newfile = "./stage_area/" . $this->current_file
. "/xl/worksheets/sheet1.xml";
$handle = fopen($newfile, 'a');
$content = "</row>\n";
fwrite($handle, $content);
fclose($handle);
}
Come si vede, questo semplicemente chiude il tag
del paragrafo. Infine il metodo cardine di aggiunta
delle celle sar il seguente:
function
add_cell($var_tipo,$var_value,$var_formula,$var_
cella) {
$newfile = "./stage_area/" . $this->current_file
. "/xl/worksheets/sheet1.xml";
$handle = fopen($newfile, 'a');
if ( $var_tipo == "testo" ) {
$content = "<c r=\"" . $var_cella . "\"
t=\"inlineStr\" >\n";
$content .= "<is><t>" . $var_value .
"</t></is>\n";
} else {
$content = "<c r=\"" . $var_cella . "\" >\n";
if ( !is_null($var_formula) ) {
$content .= "<f>" . $var_formula .
"</f>\n";
}
$content .= "<v>" . $var_value . "</v>\n";
}
$content .= "</c>\n";
fwrite($handle, $content);
fclose($handle);
}
CONCLUSIONI
Come si visto, la struttura non binaria, aderen-
te ad uno standard ben definito, dei nuovi file
XLSX permette di costruire del codice in grado di
generare un documento per Excel senza che que-
sti sia presente sul computer (come ad esempio
nel caso si usi Linux). Si dispone inoltre di una
classe in grado di creare un documento XLSX e di
popolarne le celle con testo, formule e valori
numerici. Si noti come anche se il codice visto
in PHP, la classe costruita sia facilmente esten-
dibile (come vedremo in altri articoli), sia porta-
bile (le strutture usate si ritrovano facilmente in
diversi linguaggi di programmazione ed il meto-
do di aggiunta dei file al contenitore XLSX fun-
ziona sia su Windows che su Linux).
Guido Pennella
M
COVER STORY
Maggio 2008/
17
G
Interfacciare PHP con Excel
LAUTORE
Guido Pennella un
ingegnere esperto di
informatica, laureato
allUniversit di Roma
La Sapienza. Si
occupa principalmente
dello sviluppo di
sistemi sia via Web, sia
di applicazioni
embedded real time
distribuite. E possibile
contattarlo
allindirizzo di posta
elettronica
guidopennella@virgilio.it
012-017:032-035 1-04-2008 16:06 Pagina 17
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web M
G
20
/Maggio 2008
I nuovi formati di Microsoft gestiti da PHP
N
el precedente articolo, abbiamo visto
come file DOCX non sia nientaltro che
un file compresso nel formato ZIP, al cui
interno si trova una ben precisa gerarchia di di-
rectory e file. Creando un file ZIP che rispetta
questi canoni, si ottiene un file che Word rico-
nosce a tutti gli effetti come un suo documen-
to. Per poter manipolare un file DOCX lapproccio
pi semplice da seguire costruire un archivio ZIP
con la struttura delle directory gi pronta e, una
volta costruiti i vari file previsti al suo interno in
base alle necessit, aggiungere questi file allar-
chivio in modo batch. In particolare possibile
prendere un vero file DOCXe spogliarlo dei va-
ri file che si intende sostituire, in modo da avere
rapidamente la corretta gerarchia interna del fi-
le a disposizione; di seguito, indicheremo questo
file come master_doc.docx, o semplicemente
master file. Tale operazione di aggiornamento
pu essere demandata allefficiente 7-ZIP, del
quale esiste una versione da riga di comando
con lo stesso nome sia per ambiente Windows
che per Linux. Infine, per facilitare il compito a
7-ZIP, bene costruire sul file system una direc-
tory di lavoro, dove porremo nella root il ma-
ster file ed i file XML costruiti in sottodirectory
che ricalcano la gerarchia di quelle previste nel-
lo ZIP, in modo che laggiornamento/inserimento
del file allinterno dellarchivio avvenga senza
dover specificare una destinazione relativa di-
versa da quella sul file system.
In questo articolo vedremo come possibile
estendere la classe PHP creata per costruire il fi-
le DOCXper fare in modo di gestire linserimento
di tabelle ed immagini nel documento.
TAG DI GESTIONE
DELLE TABELLE
IN UN DOCUMENTO
Il WordprocessingML, che come si visto fa
parte dello standard ECMA TC45, prevede una
gestione delle tabelle molto simile a quella
dellHTML. La differenza fondamentale dovuta
come possibile controllare elementi quali i
bordi e lo sfondo; infatti, analogamente a
quanto visto per le sezioni di test, dove
necessario definire una sequenza
PARAGRAPH/RUN/TEXT, per le tabelle avremo:
1. Una sequenza di inizializzazione della tabel-
la, dove, a valle del tag di apertura della ta-
bella, possibile definire una serie di pro-
priet generali della tabella stessa (come ad
esempio i bordi);
2. Una serie di righe, definite dai tag
<w:tr>
...
</w:tr>
3. Racchiusi tra i tag di riga, troveremo una serie
di celle caratterizzate dai tag
<w:tc>
...
</w:tc>
4. Il tag di chiusura della tabella, in modo che la
tabella tutta sia racchiusa tra i tag
<w:tbl>
...
</w:tbl>
Tramite queste sequenze possibile controllare in
modo molto fine loutput desiderato. Si noti come
aggiungere del testo ad una cella vuol semplice-
mente dire attivare la sequenza PARA-
GRAPH/RUN/TEXT vista in precedenza nel prece-
dente articolo. Nel nostro caso di esempio, valu-
teremo la creazione di una tabella con celle di di-
mensioni tutte eguali, con o senza bordi. Inoltre,
per il bordo inferiore di celle specifiche, vogliamo
poter avere una linea pi marcata (utile per la pri-
ma riga di una tabella, dove vengono inseriti i ti-
toli delle colonne).
CREARE UN FILE
WORD DA PHP
NON SOLO TESTO, MA ANCHE IMMAGINI, TABELLE, ALTRE INFORMAZIONI. SONO SOLO
ALCUNE DELLE INFORMAZIONI CHE POSSONO ESSERE CONTENUTE IN UN FILE WORD.
IN QUESTO NUMERO IMPAREREMO COME CREARE DOCUMENTI WORD DA PHP
Conoscenze richieste
Conoscenza di base di
PHP
Software
PHP, APACHE, 7-ZIP
Impegno

Tempo di realizzazione
REQUISITI
020-026:072-080 1-04-2008 16:09 Pagina 20
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
21
G
I nuovi formati di Microsoft gestiti da PHP
ESTENSIONE DELLA
CLASSE PHPDOCX PER
GESTIRE UNA TABELLA
In base alla sequenza vista, la classe verr estesa con
un meccanismo analogo a quello usato per la gestio-
ne del testo, ovvero avremo: un metodo per inizializ-
zare la tabella, uno per inizializzare la riga, uno per
inizializzare la singola cella ed i corrispondenti meto-
di che chiudono correttamente i tag aperti. Comin-
ciamo a vedere il primo:
function start_table($n_colonne,$borders) {
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
// Apertura del file in append
$handle = fopen($newfile, 'a');
$this->tabelle = 1;
$content = "<w:tbl>\n<w:tblPr>\n<w:tblStyle
w:val=\"TableGrid\"/>\n<w:tblW w:w=\"0\"
w:type=\"auto\"/>\n";
if ( $borders == 0 ) {
$content .= "<w:tblBorders>\n";
$content .= "<w:top w:val=\"none\" w:sz=
\"0\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:left w:val=\"none\" w:sz=
\"0\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:bottom w:val=\"none\" w:
sz=\"0\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:right w:val=\"none\" w:
sz=\"0\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:insideH w:val=\"none\" w:
sz=\"0\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:insideV w:val=\"none\" w:
sz=\"0\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "</w:tblBorders>\n";
} else {
$content .= "<w:tblBorders>\n";
$content .= "<w:top w:val=\"single\" w:sz=
\"4\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:left w:val=\"single\" w:sz=
\"4\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:bottom w:val=\"single\"
w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:right w:val=\"single\" w:
sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:insideH w:val=\"single\"
w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "<w:insideV w:val=\"single\"
w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n";
$content .= "</w:tblBorders>\n";
}
$content .= "</w:tblPr>\n";
$n_colonne = intval($n_colonne);
$dimensione_cella = 9780/$n_colonne;
$dimensione_cella = intval($dimensione_cella);
$content .= "<w:tblGrid>\n";
for ( $i = 0; $i < $n_colonne; $i++ ) {
$content .= "<w:gridCol w:w=\"" .
$dimensione_cella . "\"/>\n";
}
$content .= "</w:tblGrid>\n";
$this->dimensione_cella = $dimensione_cella;
fwrite($handle, $content);
fclose($handle);
}
La funzione vista apre il tagdella tabella e definisce, tra-
mite la sequenza
<w:tblPr>
...
</w:tblPr>
una serie di propriet. La prima di questa lo stile del-
la tabella, che prevede una griglia fissa,
<w:tblStyle w:val="TableGrid"/>
seguita da una indicazione della larghezza, che faremo
in modo sia auto-adattante rispetto alla pagina.
<w:tblW w:w="0" w:type="auto"/>
Come detto, vogliamo poi poter definire la presenza dei
bordi. In base al parametro passato attiveremo quin-
di una sequenza di tag, dove possiamo indicare i vari
tipi di bordi possibili e per ognuno di questi sar pos-
sibile indicare il tipo di linea del bordo (w:val), quan-
to questa deve essere spessa (w:sz), il colore (w:color)
e lo spazio di offset (w:space). Per fare in modo di ave-
re una griglia fissa a celle tutte eguali, la successiva se-
quenza di tag <w:tblGrid> </w:tblGrid> deve conte-
nere le indicazioni di dimensioni delle colonne con
larghezza data dalla dimensione massima possibile
per una riga, divisa per il numero di colonne. In ter-
mini del WordprocessingML, una pagina A4 larga
10296 ventesimi di pollice (tale lunit di misura).
Considerando per i margini standard con cui si scri-
ve, tale larghezza si abbassa a 9780 ventesimi di polli-
ce. Per cui in una tabella di N colonne le celle avranno
una larghezza di 9780/N.
Il secondo metodo, per definire la riga, conterr sem-
plicemente il tag di apertura della riga stessa ed un
tag delle propriet della riga che permette di indicare
che non deve essere possibile suddividere la stessa ri-
ga in pagine diverse (cosa che accade in caso di celle
con contenuto troppo lungo, che possono eventualmente
finire su due pagine diverse):
function add_row() {
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
020-026:072-080 1-04-2008 16:09 Pagina 21
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web M
G
22
/Maggio 2008
I nuovi formati di Microsoft gestiti da PHP
// Apertura del file in append
$handle = fopen($newfile, 'a');
$content = "<w:tr> <w:trPr><w:cantSplit />
</w:trPr>";
fwrite($handle, $content);
fclose($handle);
}
Mentre quello che definisce una cella, considerando
il requisito di poter gestire un bordo inferiore pi mar-
cato, sar:
function add_cell($border) {
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
// Apertura del file in append
$handle = fopen($newfile, 'a');
$content = "<w:tc>\n";
$content .= "<w:tcPr>\n";
$content .= "<w:tcW w:w=\"" . $this->
dimensione_cella . "\" w:type=\"dxa\"/>\n";
if ( $border == 1 ) {
$content .= "<w:tcBorders>\n";
$content .= "<w:bottom w:val=\"thinThick
SmallGap\" w:sz=\"24\" w:space=\"0\"
w:color=\"auto\"/>\n";
$content .= "</w:tcBorders>\n";
}
$content .= "</w:tcPr>\n";
fwrite($handle, $content);
fclose($handle);
}
In pratica, possibile ridefinire il parametro del bor-
do inferiore (w:bottom) andando cos in override ri-
spetto a quello impostato per tutta la tabella. Nel ca-
so particolare abbiamo scelto una linea di tipo
thinThickSmallGap, ovvero una linea composta
da una pi sottile sopra una pi spessa.
I corrispondenti metodi di chiusura dei tag saranno
semplicemente:
function end_cell() {
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
// Apertura del file in append
$handle = fopen($newfile, 'a');
$content = "</w:tc>\n";
fwrite($handle, $content);
fclose($handle);
}
function end_row() {
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
// Apertura del file in append
$handle = fopen($newfile, 'a');
$content = "</w:tr>\n";
fwrite($handle, $content);
fclose($handle);
}
function end_table() {
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
// Apertura del file in append
$handle = fopen($newfile, 'a');
$content = "</w:tbl>\n";
fwrite($handle, $content);
fclose($handle);
}
ESEMPIO DI USO
DELLA CLASSE ESTESA
PER GESTIRE LE TABELLE
In base a quanto definito, per poter inserire la seguente
tabella in un documento DOCX:
La sequenza dei comandi per la prima riga (suppo-
nendo che la classe sia instanziata dalloggetto doc)
sar:
$doc->start_table(4,1);
$doc->add_row();
$doc->add_cell(1);
$doc->start_paragraph(0,center);
$doc->add_text(Titolo 1,bold);
$doc->end_paragraph();
$doc->end_cell();
$doc->add_cell(1);
$doc->start_paragraph(0,center);
$doc->add_text(Titolo 2,bold);
$doc->end_paragraph();
$doc->end_cell();
$doc->add_cell(1);
$doc->start_paragraph(0,center);
NOTA
Alla definizione dello
standard TC45 (Office
Open XML File
Formats) non ha
ovviamente
partecipato solo la
Microsoft, ma anche le
seguenti
aziende/organizzazioni
: Apple, Barclays
Capital, BP, The British
Library, Essilor, The
Gnome Foundation,
Intel, The Library of
Congress, NextPage,
Novell, Statoil, and
Toshiba. Lo standard in
se stato approvato
da una assemblea
generale dellEcma nel
dicembre 2006.
A11
A21
A31
A12
A22
A32
A13
A23
A33
A14
A24
A34
Titolo 1 Titolo 2 Titolo 3 Titolo 4
020-026:072-080 1-04-2008 16:09 Pagina 22
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
23
G
I nuovi formati di Microsoft gestiti da PHP
$doc->add_text(Titolo 3,bold);
$doc->end_paragraph();
$doc->end_cell();
$doc->add_cell(1);
$doc->start_paragraph(0,center);
$doc->add_text(Titolo 4,bold);
$doc->end_paragraph();
$doc->end_cell();
$doc->end_row();
Per la seconda riga avremo:
$doc->add_row();
$doc->add_cell(0);
$doc->start_paragraph(0,center);
$doc->add_text(A11,null);
$doc->end_paragraph();
$doc->end_cell();
$doc->add_cell(0);
$doc->start_paragraph(0,center);
$doc->add_text(A12,null);
$doc->end_paragraph();
$doc->end_cell();
$doc->add_cell(0);
$doc->start_paragraph(0,center);
$doc->add_text(A13,null);
$doc->end_paragraph();
$doc->end_cell();
$doc->add_cell(0);
$doc->start_paragraph(0,center);
$doc->add_text(A14,null);
$doc->end_paragraph();
$doc->end_cell();
$doc->end_row();
E cos via per le altre righe. Quando avremo finito di ag-
giungere righe e celle, potremo chiudere la tabella con
$doc-> end_table();
GESTIONE
DELLE IMMAGINI
La gestione delle immagini allinterno di un do-
cument DOCX prevede dei passi aggiuntivi a
quanto visto per testo e tabelle. Infatti fino ad
ora stato necessario e sufficiente agire su un
singolo file (document.xml) di quelli che com-
pongono il documento DOCX, mentre
lintroduzione di una immagine prevede sia la
modifica di altri file, sia linserimento dellim-
magine stessa nel file ZIP (ovvero limmagine
viene embedded nel file). Cominciamo col no-
tare come le varie immagini verranno archivia-
te anche loro allinterno del file ZIP nella sotto-
directory word/media ed previsto che queste sia-
no in formato PNG. A prescindere dal nome ori-
ginale dellimmagine, nellarchiviazione queste
prendono tutte nome imageX.png (dove X un nu-
mero intero a partire da 1), in modo che possa-
no poi essere facilmente gestite.
Andiamo a vedere quali sono i file che vengono
modificati con linserimento di una immagine. Il
primo [Content_Types].xml, che si trova nella root
del file e contiene una serie di tag che indicano
diversi tipi di elementi contenuti nel documen-
to. Nel momento in cui abbiamo una immagine
dovremo aggiungere alla lista dei tipi il seguen-
te:
<Default Extension="png" ContentType=
"image/png"/>
Il secondo il file delle relazioni, ovvero il file
che associa i tipi del file [Content_Types].xml con
degli elementi allinterno dello ZIP, il cui nome
document.xml.rels e si trova nella sottodirectory
word/_rels. Per le varie immagini presenti do-
vremo prevedere di aggiungere una riga del tipo
<Relationship Id="rId4"
Type="http://schemas.openxmlformats.org/officeD
ocume
nt/2006/relationships/image"
Target="media/image1.png"/>
Come si vede, stiamo indicando che me-
dia/image1.png un tipo immagine e sar rico-
nosciuta da un ID pari a rId4, pertanto allinterno
del file document.xml ci aspettiamo di ritrovare
tale ID quando andremo a specificare linserimento
dellimmagine allinterno del documento. Rela-
tivamente ad i tag da usare, lapproccio scelto
per gestire una immagine molto simile a quel-
lo usato per il testo. Mentre in questultimo caso
prevista la sequenza PARAGRAPH/RUN/TEXT,
per le immagini vi la sequenza PARA-
GRAPH/RUN/DRAWING.
Si noti come la parte di DRAWING fa riferimen-
to ad un markup-language, detto DrawingML;
mentre per il WordprocessingML abbiamo dei
tag che iniziano per w, il DrawingML prevede
dei tag che iniziano per a. Allinterno di DRAW-
ING andremo a specificare che si tratta di una
PICTURE e che quindi i tag si devono riferire ad
un altra sezione del DrawingML i cui tag inizia-
no per pic.
Per brevit non si riporta tutta la lunga sequen-
za di tag necessaria per inserire una immagine
(sequenza che possibile vedere nel codice del-
la classe).
E per bene rilevare alcuni elementi specifici;
ad esempio, nella sezione PICTURE, i tag che
fanno riferimento allimmagine prima inserita
sono i seguenti:
020-026:072-080 1-04-2008 16:09 Pagina 23
ht t p: / / www. i opr ogr ammo. i t
<p:pic>
..
<p:blipFill>
<a:blip r:embed="rId4"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</p:blipFill>
..
</p:pic>
Si noti la presenza dellID prima definito nel punto
dove viene specificata limmagine da inserire. La sezione
stretch quella che indica a Word di posizionare
limmagine in linea col testo.
Altri tag da esaminare sono i tag che specificano da
dimensione del paragrafo e dellimmagine stessa: in ge-
nere dovrebbero coincidere, a meno che non si voglia
avere dei margini del paragrafo pi grandi, per avere
una sorta di bordo rispetto allimmagine. Tali tag sono
rispettivamente:
<wp:extent cx="X" cy="Y" />
<a:ext cx="X" cy="Y" />
Dove al posto di X ed Y vi devono essere delle dimen-
sioni in DPI. Per una immagine larga orizzontalmen-
te come i margini standard di una pagina A4, il valore
di X in DPI di 6120130; (quindi se vogliamo inserire
una immagine larga la un quarto della pagina avre-
mo una X pari a 6120130/4).
ESTENSIONE DELLA
CLASSE PHPDOCX PER
GESTIRE LE IMMAGINI
In base a quanto visto, laggiunta di una imma-
gine prevede radicali modifiche al file ZIP, che si
riflettono in non trascurabili modifiche alla no-
stra classe. Per prima cosa, sar necessario di-
sporre di una nuova propriet della classe: un
intero che chiameremo images che conterr il
numero delle immagini inserite. Nel costruttore
inizializzeremo questa propriet a zero. Altra
modifica al costruttore da apportare sar quella
di costruire i file [Content_Types].xml e docu-
ment.xml.rels con i tag standard che si avrebbe-
ro in assenza di immagini, senza per chiudere
lultimo tag (cosa che dovr essere fatta dal di-
struttore).
Inoltre, bene disporre di un metodo per inserire
le immagini allinterno del file ed uno per spe-
cificare dove limmagine va messa allinterno del
testo. In questo modo, una immagine potr essere
facilmente messa in pi punti del documento.
Nel metodo di inserimento immagini, oltre a por-
re limmagine PNG nel punto corretto della sta-
ge area, dovremo
1) Aggiornare la propriet del numero corrente
di immagini inserite.
2) Se la prima volta che si inserisce una im-
magine, allora necessario aggiornare il con-
tenuto del file [Content_Types].xml.
3) Per ogni nuova immagine creata, necessario
inserire un ID nel file document.xml.rels. A
tal pro, sar necessario poter generare auto-
maticamente i vari ID.
Infine, il distruttore deve essere esteso in modo
da
1) Chiudere correttamente anche i due nuovi
file da trattare,
2) Aggiungere al file ZIP sia i nuovi file, sia i file
delle immagini.
Nella sostanza, al costruttore per gestire [Con-
tent_Types].xml e per inizializzare la nuova pro-
priet verranno aggiunte le seguenti righe:
$this->images = 0;
$newfile = "./stage_area/" . $this->current_file .
"/[Content_Types].xml";
$handle = fopen($newfile, 'w');
$content = "<?xml version="1.0" encoding="iso-
8859-1" ?>\n";
$content .= " <Types xmlns=\"http://schemas.
openxmlformats.org/package/2006/
content-types\">\n;
$content .= "<Default Extension=\"rels\" Content
Type=\"application/vnd.openxmlformats-
package.relationships+xml\" />\n";
$content .= "<Default Extension=\"xml\" Content
Type=\"application/xml\" />\n";
$content .= "<Override PartName=\"/word/
document.xml\" ContentType=\"application/
vnd.openxmlformats-officedocument.
wordprocessingml.document.main+xml\" />\n";
$content .=<Override PartName=\"/word/styles.
xml\" ContentType=\"application/vnd.
openxmlformats-officedocument.
wordprocessingml.styles+xml\" />\n";
$content .= "<Override PartName=\"/docProps/
app.xml\" ContentType=\"application/vnd.
openxmlformats-officedocument.extended-
properties+xml\" />\n";
$content .= "<Override PartName=\"/word/
settings.xml\" ContentType=\"application/
vnd.openxmlformats-officedocument.word
processingml.settings+xml\" />\n";
ioProgrammo Web M
G
24
/Maggio 2008
I nuovi formati di Microsoft gestiti da PHP
NOTA
Se si dispone solo di
Word 2003 (o 2002 o
2000), per poter aprire
un file in formato
DOCX necessario
installare un pacchetto
aggiuntivo della
Microsoft. Tramite
questo sar anche
possibile salvare da un
vecchio Word nel
nuovo formato. Tale
pacchetto
installabile a patto di
avere un sistema
Windows ed Office
pienamente
aggiornati. Per
trovarlo sufficiente
andare sul sito
Microsoft e cercare il
Microsoft Office
Compatibility Pack.
020-026:072-080 1-04-2008 16:09 Pagina 24
ht t p: / / www. i opr ogr ammo. i t
$content .= "<Override PartName=\"/word/theme/
theme1.xml\" ContentType=\"application/
vnd.openxmlformats-officedocument.
theme+xml\" />\n;
$content .= "<Override PartName=\"/word/fontTable.
xml\" ContentType=\"application/vnd.
openxmlformats-officedocument.wordprocessingml.
fontTable+xml\" />\n";
$content .= "<Override PartName=\"/word/
webSettings.xml\" ContentType=\"application/
vnd.openxmlformats-officedocument.
wordprocessingml.webSettings+xml\" />\n";
$content .= "<Override PartName=\"/docProps/core.
xml\" ContentType=\"application/vnd.
openxmlformats-package.core-properties+
xml\" /> \n";
fwrite($handle, $content);
fclose($handle);
Mentre per gestire document.xml.rels le righe sono
le seguenti:
$newfile = "./stage_area/" . $this->current_file .
"/word/_rels/" . "/document.xml.rels";
$handle = fopen($newfile, 'w');
$content = "<?xml version="1.0" encoding=
"iso-8859-1" ?>\n";
$content .= "<Relationships xmlns=\"http://
schemas.openxmlformats.org/
package/2006/relationships\">\n";
$content .= "<Relationship Id=\"rId3\" Type=\"http:
//schemas.openxmlformats.org/officeDocument/
2006/relationships/webSettings\"
Target=\"webSettings.xml\" />\n";
$content .= "<Relationship Id=\"rId2\" Type=\"http:
//schemas.openxmlformats.org/officeDocument/
2006/relationships/settings\" Target=\
"settings.xml\" />\n";
$content .= "<Relationship Id=\"rId1\" Type=\"http:
//schemas.openxmlformats.org/officeDocument/2006
/relationships/styles\" Target=\"styles.xml\" />\n";
$content .= "<Relationship Id=\"rId6\" Type=\"http:
//schemas.openxmlformats.org/officeDocument/
2006/relationships/theme\" Target=\
"theme/theme1.xml\" />\n";
$content .= "<Relationship Id=\"rId5\" Type=\
"http://schemas.openxmlformats.org/office
Document/2006/relationships/fontTable\"
Target=\"fontTable.xml\" />\n";
fwrite($handle, $content);
fclose($handle);
Il metodo di aggiunta di una immagine sar invece il
seguente:
function insert_image($image_file,$image_id) {
$newdir = "./stage_area/" . $this-
>current_file;
$newimagedir = $newdir . "/media";
mkdir($newimagedir);
$this->images++;
$newfile = $newimagedir. "/image" . $this-
>images ".png";
copy($image_file,$newfile);
if ( $this->images == 1 ) {
$newfile = "./stage_area/" . $this-
>current_file . "/[Content_Types].xml";
$handle = fopen($newfile, 'w');
$content =" <Default Extension=\"png\"
ContentType=\"image/png\" />\n";
fwrite($handle, $content);
fclose($handle);
}
$newfile = "./stage_area/" . $this->current_file
. "/word/_rels/" . "/ document.xml.rels";
$handle = fopen($newfile, 'a');
$content = <Relationship Id=\"" . $image_id .
"\" Type=\"http://schemas.openxmlformats.
org/officeDocument/2006/relationships/image\"
Target=\"media/image" . $this->images . ".png"
/>\n";
fwrite($handle, $content);
fclose($handle);
}
Mentre quello che inserisce effettivamente limmagine
nel documento sar:
function put_image($vdim,$hdim,$image_id) {
// Gestione variabili
if ( $vdim == "" || is_null($vdim) ) {
$vdim = 6120130;
}
if ( $hdim == "" || is_null($hdim) ) {
$hdim = 2209165;
}
// Variabile del file XML corrente
$newfile = "./stage_area/" . $this->current_file
. "/word" . "/document.xml";
// Apertura del file in append
$handle = fopen($newfile, 'a');
$content = "<w:p>\n";
$content .= "<w:r><w:rPr><w:noProof/
><w:lang w:eastAsia=\"it-IT\"/>\n";
$content .= "</w:rPr><w:drawing>\n";
$content .= "<wp:inline distT=\"0\" distB=
\"0\" distL=\"0\" distR=\"0\">\n";
$content .= "<wp:extent cx=\"" . $vdim . "\"
M
ioProgrammo Web
Maggio 2008/
25
G
I nuovi formati di Microsoft gestiti da PHP
LAUTORE
Guido Pennella un
ingegnere esperto di
informatica, laureato
allUniversit di Roma
La Sapienza. Si
occupa principalmente
dello sviluppo di
sistemi sia via Web, sia
di applicazioni
embedded real time
distribuite. E possibile
contattarlo
allindirizzo di posta
elettronica
guidopennella@
virgilio.it
020-026:072-080 1-04-2008 16:09 Pagina 25
ht t p: / / www. i opr ogr ammo. i t
cy=\"" . $hdim . "\"/>\n";
$content .= "<wp:effectExtent l=\"19050\"
t=\"0\" r=\"0\" b=\"0\"/>\n";
$content .= "<wp:docPr id=\"" . $this->images
. "\" name=\"Picture " . $this->images . "\" descr=
\"Immagine " . $this->images . " aggiunta
automaticamente\"/>\n";
$content .= "<wp:cNvGraphicFramePr><a:
graphicFrameLocks xmlns:a=\"http://schemas.
openxmlformats.org/drawingml/2006/main\"
noChangeAspect=\"1\"/>\n";
$content .= "</wp:cNvGraphicFramePr>
<a:graphic xmlns:a=\"http://schemas.
openxmlformats.org/drawingml/2006/main\">\n";
$content .= "<a:graphicData uri=\"http://
schemas.openxmlformats.org/drawingml/
2006/picture\">\n";
$content .= "<pic:pic xmlns:pic=\"http://
schemas.openxmlformats.org/drawingml/
2006/picture\">\n";
$content .= "<pic:nvPicPr><pic:cNvPr id=\"0\"
name=\"intestazione.png\"/><pic:cNvPicPr/>
</pic:nvPicPr>\n";
$content .= "<pic:blipFill><a:blip r:embed=\""
. $image_id. "\"/>\n";
$content .= "<a:stretch><a:fillRect/></a:
stretch></pic:blipFill>\n";
$content .= "<pic:spPr><a:xfrm><a:off x=\
"0\" y=\"0\"/>\n";
$content .= "<a:ext cx=\"" . $vdim . "\" cy=
\"" . $hdim . "\"/>\n";
$content .= "</a:xfrm><a:prstGeom prst=\
"rect\">\n";
$content .= "<a:avLst/></a:prstGeom>
</pic:spPr></pic:pic>\n";
$content .= "</a:graphicData></a:graphic>
</wp:inline></w:drawing></w:r></w:p>\n";
fwrite($handle, $content);
fclose($handle);
}
Infine, nel distruttore sar necessario inserire le se-
guenti righe:
$newfile = "./stage_area/" . $this->current_file .
"/word/_rels/" . "/document.xml.rels";
$handle = fopen($newfile, 'a');
$content .= "</Relationships>\n";
fwrite($handle, $content);
fclose($handle);
chdir($newdir);
$to_run = '7za a ' . $this->current_file . '.docx
word/_rels/ document.xml.rels';
$newfile = "./stage_area/" . $this->current_file .
"/[Content_Types].xml";
$handle = fopen($newfile, 'a');
$content .= "</Types>\n";
fwrite($handle, $content);
fclose($handle);
$to_run = '7za a ' . $this->current_file . '.docx
word/[Content_Types].xml ';
for ( $i = 0; $i < $this->images; $i++ ) {
$to_run = '7za a ' . $this->current_file . '.docx
word/media/image' . $i . '.png ';
CONCLUSIONI
Come si potuto vedere, estendere la classe
PHP di gestione di documenti DOCX per poter
aggiungere delle tabelle non presenta reali dif-
ficolt. Estendere invece la classe per poter ge-
stire linserimento di immagini prevede modi-
fiche di entit non trascurabile (anche se non
vi sono particolari difficolt in tali modifiche).
Grazie a tali estensioni, siamo ora in possesso di
una classe che permette di creare documenti
DOCX sufficientemente strutturati.
E fondamentale rilevare come inserire testo e
immagini allinterno di una cella analogo ad
inserirle allinterno del corpo del documento.
Anche con tali estensioni, dato che non si sono
usate caratteristiche peculiari del PHP, la clas-
se facilmente portabile in altri ambienti e lin-
guaggi. Si noti infine come la gestione delle im-
magini proposta nellarticolo prevede il sem-
plice inserimento delle stesse, mentre lo stan-
dard prevede anche la possibilit di effettuare del-
le manipolazioni, come ad esempio reimpo-
stare i colori ed inserire ombreggiature sul bor-
do dellimmagine, sempre inserendo una serie
di appositi tag, che saranno esaminati in suc-
cessivi articoli.
A tutto ci si pu aggiungere una buona dose di Ajax,
che pu essere utilizzata per limmissione di conte-
nuti. A tal proposito esistono moltissime librerie che
possono essere utilizzate, alcune delle quali vengono
analizzate anche allinterno di questo stesso numero
di ioProgrammo. A titolo di esempio citiamo le yahoo
library, oppure scriptaculous. Entrambe presentano
numerosi metodi per limmissione dei contenuti sia in
forma tabellare sia sotto forma di un completo editor
di testi che emula in tutto e per tutto il formato di word.
Unendo le tecniche ajax a quelle espresse in questo
articolo, possibile quasi completamente svincolar-
si dallinstallare software in locale, piuttosto possibile
utilizzare direttamente applicazioni localizzate sul
web. il concetto di applicazione in ASP di cui si par-
la ormai da moltissimo tempo
Guido Pennella
ioProgrammo Web
M
G
26
/Maggio 2008
I nuovi formati di Microsoft gestiti da PHP
020-026:072-080 1-04-2008 16:09 Pagina 26
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web M
G
28
/Maggio 2008
Usare i servizi di Windows
C
ostruire unapplicazione che gestisca in
modo centralizzato linvio dei Fax, una
attivit facile da immaginare ma molto
meno semplice da realizzare. In questo artico-
lo analizzeremo una soluzione che si basa sul
Servizio Fax di Windows Server 2003 (o Windows
XP nel caso in cui volessimo implementare una
postazione di test).
La soluzione composta dai seguenti componenti:
Un servizio Windows che tiene traccia delle
attivit del Fax, implementato mediante gli
oggetti Fax Service Extended COM API;
Una classe FaxHelper che espone tutti i me-
todi relativi allinvio dei Fax;
Un controllo FaxMonitor, basato su AJAX, che
mostra lo stato del Fax;
Una pagina web che rappresenta linterfaccia
utente dellapplicazione.
A causa della complessit della soluzione, larticolo
verr suddiviso in due parti; nella prima parte avre-
mo modo di analizzare lintera infrastruttura
dellapplicazione e i primi due componenti.
Nella seconda parte analizzeremo il controllo
che traccia lo stato del Fax e la pagina web at-
traverso cui avremo modo di effettuare alcuni te-
st.
LINFRASTRUTTURA
In Windows Server 2003 ed in Windows XP, se
apriamo la cartella Stampanti e fax, presente
nel gruppo Impostazioni, possiamo trovare una
icona Fax che rappresenta la console del servi-
zio Fax
Qualora non sia presente la suddetta icona, pos-
siamo installare il servizio Fax attraverso lutilit
Installazione applicazioni del Pannello di
Controllo. Il servizio Fax fa parte dei Compo-
nenti di Windows quindi facilmente instal-
labile (Figura 2).
Linstallazione del servizio Fax e del relativo mo-
dem (locale o di rete), sono argomenti che esu-
lano dalla trattazione (anche per motivi di spa-
zio); nel caso in cui sia necessario eseguire an-
che queste operazioni preventive, si consiglia
di seguire la documentazione in linea del siste-
ma operativo.
Se il servizio installato e funzionante, un dop-
pio clic sullicona del Fax ci consente di acce-
dere alla consolle del servizio Fax.
Questo servizio rappresenta una soluzione com-
pleta per la gestione dei Fax; gli utenti possono
inviare e ricevere Fax, monitorare le attivit del-
lapparecchiatura ed accedere allarchivio dei
Fax. Il servizio consente di inviare e ricevere Fax
attraverso un dispositivo direttamente connesso
alla postazione o attraverso un dispositivo re-
moto, raggiungibile via rete. Una descrizione
completa del servizio Fax e della sua configu-
razione, esula dagli obiettivi della trattazione;
per approfondire largomento, per, possibi-
le far riferimento alla documentazione in linea.
Per sviluppare il presente articolo, la configu-
INVIA I TUOI FAX
TRAMITE ASP.NET
ALLA SCOPERTA DEL SERVIZIO FAX INTEGRATO IN WINDOWS. VEDREMO COME UTILIZZARE
INTERFACCE SPECIFICHE PER ACCEDERE ALLE FUNZIONI SUPPORTATE. INOLTRE GETTEREMO
LE BASI PER COSTRUIRE UNAPPLICAZIONE WEB CHE NE FACCIA USO
Conoscenze richieste
ASP.NET, C#
Software
Visual Studio 2005
Impegno

Tempo di realizzazione
REQUISITI
Figura 1: Il servizio Fax gi installato.
028-036:072-080 2-04-2008 11:52 Pagina 28
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
29
G
Usare i servizi di Windows
razione di base utilizzata, composta da un
computer portatile con Windows XP Professio-
nal con modem/fax incorporato.
Dato che dobbiamo costruire una applicazio-
ne che interagisca con il servizio Fax, abbiamo
bisogno di una interfaccia di programmazione
al fine di poter operare a livello di codice. Ci
che fa al nostro caso sono le Fax Service Ex-
tended COM API (FAXCOMEXLib) ovvero le in-
terfacce di programmazione COMdel servizio
Fax. La libreria FAXCOMEXLib, inclusa come ri-
sorsa nella dll Fxscomex.dll, una risorsa ricca
di oggetti che ci consentono di gestire tutti gli
aspetti del servizio Fax. Gli oggetti sono rag-
gruppati in insiemi funzionali a partire dal-
loggetto principale, FaxServer, che ci consen-
te di connetterci ad un Fax Server attivo. Pos-
siamo individuare altre famiglie di oggetti per ge-
stire la messaggistica, la configurazione del Fax
e la gestione delle notifiche.
La libreria FAXCOMEXLib la base dei due pri-
mi componenti della soluzione; il primo un
servizio Windows che tiene traccia delle attivit
del Fax e memorizza tutti i documenti inviati
tramite il servizio Fax; questo servizio neces-
sario per gestire la differente natura di una
applicazione web rispetto ad un servizio Fax.
Una applicazione web, infatti, un processo
sincrono privo di stato; il servizio Fax, al con-
trario, un processo asincrono basato su code.
In altre parole, possiamo facilmente inviare un
Fax attraverso una applicazione web, ma ab-
biamo, altres, bisogno di un meccanismo che
ci consenta di controllare lo stato della tra-
smissione del documento finch questo non sia
stato effettivamente inviato.
Il secondo componente della soluzione una
classe FaxHelper, basata sulla libreria FAX-
COMEXLib; utilizzeremo la classe per incapsu-
lare la complessit della libreria e per esporre
solo quelle funzionalit necessarie per inviare
un Fax.
Il terzo componente della soluzione il con-
trollo FaxMonitor, che viene utilizzato per in-
terrogare la lista delle registrazioni effettuate
dal servizio Windows; in questo modo avremo
la possibilit di verificare lo stato di avanza-
mento della trasmissione. Al fine di aumentare
la fruibilit della soluzione, il controllo utiliz-
zer AJAX per aggiornare la lista delle registra-
zioni relative al nostro documento; in questo
modo lutente non dovr ricaricare la pagina
per controllare lo stato di avanzamento della
trasmissione.
Lultimo componente che andremo ad analizzare
una pagina web che funge da tester della so-
luzione; vedremo come selezionare un docu-
mento dal nostro disco e come riusciremo ad
inviarlo via Fax.
IL SERVIZIO
FAX MONITOR
Iniziamo con lanalizzare a fondo il primo com-
ponente: il Servizio Fax Monitor.
Ci di cui abbiamo bisogno un servizio che
registri le attivit del Fax; a tal proposito, quin-
di, abbiamo bisogno di individuare un suppor-
to su cui effettuare le registrazioni.
Ci sono diverse alternative per risolvere questo
NOTA
FAX SERVICE
EXTENDED
COM API
Per approfondire la
conoscenza delle
interface di
programmazione del
servizio Fax,
possibile far
riferimento alla library
msdn allindirizzo:
http://msdn2.microsoft.co
m/en-
us/library/ms684513(VS.8
5).aspx.
Figura 2: Il servizio Fax non installato quindi lo selezioniamo dai componenti di
Windows.
Figura 3: La consolle del servizio Fax.
028-036:072-080 1-04-2008 18:44 Pagina 29
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web M
G
30
/Maggio 2008
Usare i servizi di Windows
problema; tutte hanno lati positivi e negativi;
prima di effettuare la scelta, dobbiamo anche
tenere a mente che le registrazioni verranno in-
terrogate pesantemente dalle pagine web, al fi-
ne di mostrare lo stato di avanzamento della
trasmissione.
Consideriamo le seguenti alternative:
Event Log: il gestore degli eventi il supporto
utilizzato normalmente dai servizi per regi-
strare le rispettive attivit; laspetto negativo
di questa modalit risiede nella difficile in-
terrogazione delle registrazioni.
File di testo: i file di testo sono stati utilizzati
per anni come supporti per memorizzare da-
ti non strutturati; proprio la mancanza di qual-
siasi infrastruttura per gestire i dati ci costringe
a costruire da zero un meccanismo che ci con-
senta una facile interazione sia nella regi-
strazione che nellinterrogazione.
Base Dati: indubbiamente il miglior suppor-
to per memorizzare informazioni strutturate
una base dati; allo stesso tempo, indubbia-
mente, questa soluzione la pi onerosa dal
punto di vista della gestione e della configu-
razione della soluzione, dato che ci costrin-
ge a prevedere anche un ulteriore prodotto
come SQL Server piuttosto che MySql, con tut-
te le sue problematiche.
In questo articolo utilizzeremo lEvent Log da-
to che ci consente di organizzare i dati in modo
strutturato, ma allo stesso tempo ci evita di in-
stallare ulteriori prodotti (come SQL Server o
MySql).
Per implementare un servizio Windows in Vi-
sual Studio 2005, aggiungiamo un nuovo pro-
getto alla soluzione; nel dialogo New Project,
selezioniamo il linguaggio che preferiamo dal
pannello Project types, quindi selezioniamo
il ramo Windows. Scegliamo il template Win-
dows Services dal pannello Templates ed in-
dichiamo come nome del progetto FaxMoni-
torServiceCs se abbiamo scelto di utilizzare C#
come linguaggio di sviluppo, oppure FaxMon-
itorServiceVb se utilizziamo Visual Basic.NET.
In funzione del linguaggio scelto, Visual Studio
2005 aggiunge alcuni file alla nostra soluzione.
Rinominiamo il file Service1.cs (o Service1.vb)
in FaxMonitorService.cs (o FaxMonitorService.vb)
quindi passiamo alla visualizzazione del codi-
ce. Come possiamo vedere dal codice che se-
gue, lo strumento di sviluppo ha gi compilato
alcuni metodi; a noi resta da completare il mo-
dello gi impostato.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using FAXCOMEXLib;
namespace FaxMonitorServiceCs
{
public partial class FaxMonitorService :
ServiceBase
{
FaxServer oFaxServer;
public FaxMonitorService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
// TODO: Add code here to start your service.
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-
down
// necessary to stop your service.
}
}
}
Innanzitutto dobbiamo aggiungere un riferi-
mento al namespace System.Diagnostics ed al- Fig.4: Aggiungiamo un progetto per lo sviluppo di un servizio Windows.
NOTA
IL CODICE
DELLA
SOLUZIONE
Nel corso della
trattazione verranno
descritti gli esempi
sviluppati utilizzando
il linguaggio C#. Gli
sviluppatori che
prediligono il
linguaggio Visual
Basic.NET, possono far
riferimento ai file di
supporto allegati al
presente articolo per
analizzare il codice
sviluppato in Visual
Basic.NET. Le
funzionalit, i
componenti ed il
comportamento della
soluzione sono
analoghi nei due
linguaggi.
028-036:072-080 1-04-2008 18:44 Pagina 30
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
31
G
Usare i servizi di Windows
la libreria FAXCOMEXLib (ricordiamoci di ag-
giungere, preventivamente, un riferimento alla
libreria Fxscomex.dll nel Solution Explorer); in
questo modo ci predisponiamo allutilizzo del-
lEvent Log e delle interfacce Fax Service Ex-
tended COM API.
Quindi dobbiamo definire una variabile globa-
le, ovvero un oggetto di tipo FaxServer che uti-
lizzeremo per connetterci al dispositivo fisico.
Come possiamo notare dal codice precedente,
Visual Studio 2005 predispone due metodi, On-
Start ed OnStop, che verranno eseguiti, rispet-
tivamente, nel momento in cui il servizio vie-
ne avviato e nel momento in cui il servizio vie-
ne fermato.
In fase di avvio del servizio, dobbiamo connet-
terci al Fax Server e dobbiamo sottoscrivere al-
cune notifiche al fine di eseguire del codice al mo-
mento opportuno.
In fase di arresto del servizio, al contrario, non
dobbiamo eseguire nessuna particolare opera-
zione.
protected override void OnStart(string[] args)
{
oFaxServer = new FaxServer();
//Connettiamo il Fax Server locale.
oFaxServer.Connect("");
//Sottoscriviamo le notifiche.
oFaxServer.ListenToServerEvents(
FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_
QUEUE);
//Aggiungiamo gli Event Handlers
oFaxServer.OnOutgoingJobAdded +=
new IFaxServerNotify_
OnOutgoingJobAddedEventHandler(
oFaxServer_OnOutgoingJobAdded);
oFaxServer.OnOutgoingJobChanged +=
new IFaxServerNotify_
OnOutgoingJobChangedEventHandler(
oFaxServer_OnOutgoingJobChanged);
}
protected override void OnStop()
{
// TODO: Add code here to perform any
tear-down
// necessary to stop your service.
}
La configurazione predefinita delloggetto
FaxServer, non comporta la ricezione di alcun
evento scaturito dal Server. Al fine di ricevere i
messaggi di notifica scaturiti dalle attivit del
Fax, necessario invocare il metodo Listen-
ToServerEvents delloggetto di tipo FaxServer
passando in ingresso i tipi di eventi che ci ver-
ranno notificati.
Ci sono diversi tipi di evento che il servizio Fax
pu notificare alle applicazioni in ascolto; que-
sti tipi sono definiti dallenumeratore
FAX_SERVER_EVENTS_ TYPE_ENUMi cui mem-
bri sono definiti come maschere di bit che pos-
sono essere utilizzati in combinazione.
Dopo aver sottoscritto uno o pi eventi, dob-
biamo implementare i relativi gestori (hand-
lers) che saranno invocati allesecuzione di par-
ticolari attivit. In questo modo potremo gesti-
re levento, effettuando una registrazione o, co-
munque, eseguendo del codice.
Nellesempio che stiamo analizzando, dobbia-
mo sottoscrivere solo levento fsetOUT_QUEUE
ovvero richiediamo una notifica quando un do-
cumento viene inviato alla coda dei Fax in usci-
ta.
Quando cambia lo stato di un Fax in uscita, il
servizio Fax invia una notifica ed invoca i se-
guenti gestori: OnOutgoingJobAdded, OnOut-
goingJobRemoved e OnOutgoingJobChanged. Il
metodo OnOutgoingJobAdded viene invocato
ogniqualvolta viene inviato un documento alla
coda dei Fax in uscita mentre il metodo OnOut-
goingJobChanged viene invocato ogniqualvolta
un documento in coda, cambia il suo stato.
Lobiettivo del nostro servizio proprio quello
di registrare questo tipo di attivit quindi, pre-
supponendo di incapsulare la logica di regi-
strazione in un metodo privato WriteLog, il cor-
po dei suddetti gestori sar composto da una
sola invocazione del suddetto metodo.
public void oFaxServer_OnOutgoingJobAdded(
FaxServer pFaxServer, string sJobId)
{
//Registriamo lattivit
WriteLog(sJobId, "Added To Queue");
}
public void oFaxServer_OnOutgoingJobChanged(
FaxServer pFaxServer, string sJobId,
FaxJobStatus pFaxJobStatus)
{
//Registriamo lattivit
WriteLog(sJobId,pFaxJobStatus.Status.
ToString());
}
Quando trasmettiamo un documento, il servi-
zio Fax crea un job a cui assegna un identifica-
tivo univoco (JobId). Il suddetto identificativo
passato ai gestori degli eventi; ci ci consen-
te, come vedremo tra un attimo, di organizzare
le registrazioni in modo strutturato. Il gestore
OnOutgoingJobChanged riceve in input anche un
oggetto di tipo FaxJobStatus che contiene le
NOTA
IL TIPO
FAX_SERVER_
EVENTS_TYPE_
ENUM
Per comprendere il
significato di tutti i
componenti del tipo
FAX_SERVER_EVENTS_T
YPE_ENUM, possibile
far riferimento alla
library msdn
allindirizzo:
http://msdn2.microsoft.
com/en-us/library/ms689
206(VS.85).aspx.
028-036:072-080 1-04-2008 18:44 Pagina 31
ht t p: / / www. i opr ogr ammo. i t
informazioni relative al cambiamento di stato del
relativo job. Loggetto contiene lo stato corren-
te del job, la pagina che attualmente in fase
di trasmissione ed il numero di tentativi di tra-
smissione effettuati dal servizio. Nella soluzio-
ne che stiamo analizzando, abbiamo bisogno
di gestire solo la propriet Status delloggetto
FaxJobStatus, che un enumeratore che speci-
fica lo stato attuale del job in coda.
Lultimo frammento di codice da analizzare il
metodo privato che incapsula la logica di regi-
strazione delle attivit. Possiamo interagire con
lEvent Log di Windows attraverso loggetto
EventLog appartenente al namespace Sys-
tem.Diagnostics. Attraverso loggetto EventLog
possiamo leggere o scrivere i valori dei log esi-
stenti, piuttosto che scrivere o cancellare nuo-
vi log.
Al fine di isolare la gestione delle registrazioni del-
la nostra applicazione dal resto dei log del si-
stema, creeremo uno spazio dedicato, chiama-
to FaxMonitor; ogni trasmissione sar registra-
ta nel nuovo log e nominata con lidentificativo
del job (JobId), in modo da poter individuare
univocamente le registrazioni relative ad una
particolare trasmissione.
Il metodo WriteLog riceve in input due strin-
ghe: lidentificativo univoco del job (JobId) ed
il suo stato. In primo luogo dobbiamo verifica-
re se abbiamo gi effettuato registrazioni per il
suddetto job; se non esistono registrazioni dob-
biamo invocare il metodo statico Cre-
ateEventSource, delloggetto EventLog, che as-
socia la nostra applicazione allEvent Log chia-
mato FaxMonitor per mezzo della sorgente spe-
cificata come primo parametro.
Da notare che se lEvent Log FaxMonitor non
esiste, allatto dellinvocazione del metodo, que-
sto ne crea uno al momento.
Se la sorgente gi presente nellEvent Log (ov-
vero avevamo gi effettuato qualche registra-
zione), dobbiamo creare un oggetto di tipo Event-
Log che punti allEvent Log FaxMonitor, quin-
di, dopo aver definito su quale sorgente effet-
tuare la registrazione, andiamo a scrivere lo sta-
to del job per mezzo del metodo
WriteEntry.
private void WriteLog(string sJobId, string
sJobStatus)
{
// Verifichiamo se sono gi state effettuate
registrazioni
if (!EventLog.SourceExists(sJobId))
{
// Creiamo una nuova sorgente ed,
eventualmente, un nuovo log
// se "FaxMonitor" non esiste
EventLog.CreateEventSource(sJobId,
"FaxMonitor");
}
EventLog oEventLog = new
EventLog("FaxMonitor");
oEventLog.Source = sJobId;
// Effettuiamo la registrazione
oEventLog.WriteEntry("Your fax reached
this status: "
+ sJobStatus);
}
Dopo aver scritto il codice funzionale del no-
stro servizio, prima di poter effettuare la creazione
del pacchetto, dobbiamo eseguire alcune altre
operazioni; in particolare dobbiamo aggiunge-
re un installer per il nostro servizio. Questa ope-
razione necessaria per far si che il sistema ope-
rativo sappia che il programma che scaturir
dalloperazione di build, deve essere eseguito
proprio come servizio.
In Visual Studio 2005, attiviamo la modalit de-
sign e facciamo clic con il tasto destro sul pan-
nello di design in modo da visualizzare il men
contestuale; quindi facciamo clic sulla voce Add
Installer. Visual Studio 2005 aggiunge un nuo-
vo file, ProjectInsaller.cs (o ProjectInsaller.vb se
ioProgrammo Web M
G
32
/Maggio 2008
Usare i servizi di Windows
Figura 5: Le propriet delloggetto ServiceInstaller.
028-036:072-080 1-04-2008 18:44 Pagina 32
ht t p: / / www. i opr ogr ammo. i t
abbiamo scelto il Visual Basic.NET come lin-
guaggio di sviluppo), che include due oggetti:
ServiceProcessInstaller e ServiceInstaller. Il pri-
mo oggetto gestisce linterazione con le utilit
di installazione come Windows Installer o in-
stallutil.exe. Il secondo oggetto conserva i dati
specifici del servizio che saranno necessari al
ServiceProcessInstaller. Selezioniamo loggetto
ServiceInstaller e portiamoci sul pannello delle
propriet (Figura 3); qui definiamo alcune pro-
priet come DisplayName e ServiceName (va-
lorizziamole FaxMonitorCs o FaxMonitorVb in
funzione del linguaggio scelto per lo sviluppo
dellapplicazione). Possiamo definire anche ul-
teriori propriet come la descrizione del servi-
zio piuttosto che la modalit di avviamento
Manual/Automatic/Disabled); troveremo que-
ste propriet nel Windows Service Control Ma-
nager.
Relativamente alloggetto ServiceProcessInstaller,
lunica propriet che dobbiamo valorizzare
Account, che porremo pari a LocalSystem, in
modo che il servizio abbia accesso a tutte le ri-
sorse di cui necessita (Figura 4).
TESTIAMO IL NOSTRO
SERVIZIO
Ora possiamo lanciare il build della soluzione,
quindi installare e testare il nostro servizio.
Apriamo una finestra di commando e posizio-
niamoci nella cartella Bin\Debug allinterno del-
la cartella del progetto. Lanciamo il program-
ma installutil.exe per installare il nostro servi-
zio:
installutil.exe FaxMonitorServiceCs.exe
oppure
installutil.exe FaxMonitorServiceVb.exe
Controlliamo che il programma abbia esegui-
to la procedura di installazione in maniera cor-
retta quindi andiamo a verificare che il nostro ser-
vizio sia effettivamente presente nella lista dei
servizi installati sulla nostra macchina.
Possiamo avviare lo snap-in Servizi dal grup-
po Strumenti di amministrazione a sua volta
contenuto nel gruppo Programmi.
M
ioProgrammo Web
Maggio 2008/
33
G
Usare i servizi di Windows
Figura 6: Le propriet delloggetto ServiceProcess
Installer.
Figura 8: Nel Visualizzatore Eventi presente il nuovo Event Log.
Figura 7: Il nostro servizio stato installato e avviato correttamente.
NOTA
INTERAZIONE
CON LEVENT
LOG DI
WINDOWS
Per ottenere la
descrizione completa
della classe EventLog e
di tutti i suoi
componenti,
possibile far
riferimento alla library
msdn allindirizzo:
http://msdn2.microsoft.
com/en-us/library/system.
diagnostics.eventlog(vs.
71).aspx.
028-036:072-080 2-04-2008 11:57 Pagina 33
ht t p: / / www. i opr ogr ammo. i t
Se linstallazione andata a buon fine, possia-
mo posizionarci sulla voce FaxMonitorCs (o Fax-
MonitorVb), quindi possiamo avviare il servi-
zio.
Se il servizio si avvia correttamente, avremo mo-
do di visualizzare qualcosa di simile alla Figu-
ra 5.
Ora che il servizio attivo sulla nostra mac-
china, possiamo testarlo immediatamente
dato che ci che abbiamo realizzato un
componente autonomo dal resto dellapplica-
zione. Ci significa che non abbiamo la
necessit di sviluppare ulteriore codice per
provarlo; se ci pensiamo, in effetti, il servizio
effettua il monitoraggio di ogni Fax inviato
tramite il servizio Fax, quindi non necessaria-
mente inviato tramite la nostra applicazione.
Per fare una prova, allora, possiamo tentare di
inviare un Fax attraverso la console del servi-
zio Fax vista in Figura 1. Possiamo effettuare
la prova anche senza essere effettivamente
connessi ad una linea telefonica. Ci che
vogliamo verificare che il servizio cominci a
registrare le attivit del servizio nellapposito
Event Log. Per verificare quanto sopra, pos-
siamo aprire il Visualizzatore Eventi per
accertare se il nuovo Event Log, FaxMonitor,
stato creato e se, eventualmente contiene
delle registrazioni. Se il servizio ha funzionato
correttamente, potremo allora vedere, come
da Figura 6, che le registrazioni sono effettiva-
mente presenti.
Se facciamo doppio clic su una delle registra-
zioni, potremo visualizzare il relativo detta-
glio, che ci informa in merito allo stato rag-
giunto dal job.
LA CLASSE FAXHELPER
Terminata lanalisi del servizio FaxMonitor, ini-
ziamo lo sviluppo della classe FaxHelper che
il secondo componente che si basa sulla libre-
ria FAXCOMEXLib. Vogliamo sviluppare questa
classe per incapsulare la complessit della li-
breria FAXCOMEXLib, in modo da esporre so-
lo i metodi che ci servono per inviare un Fax. Al
fine di semplificare il processo di trasmissione
dei documenti, implementeremo la classe im-
ponendo alcuni vincoli; chiaramente i suddet-
ti vincoli potranno essere modificati a cura del-
lo sviluppatore che volesse implementare so-
luzioni differenti.
I vincoli che imponiamo sono:
Restrizione del tipo di documento inviabile
via Fax; i tipi concessi sono pdf, tiff e txt;
I documenti che potremo inviare devono es-
sere memorizzati in una sotto-cartella della
nostra applicazione.
Il primo vincolo stabilito in funzione del pro-
cesso di conversione che il servizio Fax attua
prima di trasmettere il documento se questo
in formato differente da quello predefinito, ov-
vero tiff. I documenti pdf e txt possono essere tra-
smessi senza particolari operazioni di conver-
sione, quindi il processo gestito automatica-
mente senza aver bisogno dellausilio di parti-
colari programmi (a differenza dei documenti
Word, ad esempio). Nel caso di documenti pdf
necessario che sulla macchina sia installato
lAdobe Reader scarcabile gratuitamente dal si-
to del produttore.
Considerando, tra laltro, che attualmente esi-
stono diversi plug-in gratuiti che consentono
la conversione in formato pdf di praticamente
ogni formato di documento, questo vincolo
da considerarsi molto lasco. Il secondo vincolo
ioProgrammo Web
M
G
34
/Maggio 2008
Usare i servizi di Windows
LA CLASSE FAXDOCUMENT
La classe FaxDocument un
altro componente della libreria
FAXCOMEXLib e, come vedremo,
ci sar utile per comporre un
documento Fax da sottoporre al
servizio Fax per la trasmissione.
La classe molto ricca e
consente di specificare ogni
aspetto del documento da
trasmettere; possibile definire
dettagliate informazioni sul
mittente, possibile inviare lo
stesso documento a pi
destinatari, possibile altres
definire una copertina per il
Fax.
Per approfondire la conoscenza
della classe FaxDocument
possibile far riferimento alla
library msdn allindirizzo
http://msdn2.microsoft.com/en-
us/library/ms685958(VS.85).aspx.
Figura 9: Il Fax stato accodato.
028-036:072-080 1-04-2008 18:44 Pagina 34
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
35
G
Usare i servizi di Windows
, in verit, un puro compromesso per rendere
lo sviluppo dellapplicazione pi rapido e, so-
prattutto, consente al lettore di concentrarsi
sulle parti rilevanti ed originali della trattazio-
ne. La classe FaxHelper eredita dalla classe ba-
se Control dato utilizza il View State per me-
morizzare i valori delle propriet. Le due pro-
priet della classe sono DocToFax, che contie-
ne il nome del documento da trasmettere e
RecipentNumber che contiene il numero a cui in-
viare il Fax.
namespace FaxHelperCs
{
public class FaxHelperClass : Control
{
public string DocToFax
{
get
{
object o = ViewState["DocToFax"];
return (o != null ? o.ToString() : "");
}
set { ViewState["DocToFax"] = value; }
}
public string RecipientNumber
{
get
{
object o = ViewState["RecipientNumber"];
return (o != null ? o.ToString() : "");
}
set { ViewState["RecipientNumber"] = value; }
}

}
}
La classe espone solo un metodo, SendFax che
utilizzeremo per trasmettere un documento.
I passi necessari per trasmettere un Fax sono
relativamente semplici; in primo luogo creia-
mo una istanza della classe FaxServer ed una
istanza della classe FaxDocument (che utiliz-
zeremo a breve); quindi dobbiamo verificare se
il documento che stiamo per trasmettere di
tipo corretto; in caso negativo terminiamo il
metodo impostando un messaggio di errore.
Nel caso in cui il tipo di documento che stiamo
per trasmettere di tipo corretto, ci connettia-
mo al servizio Fax tramite linvocazione del me-
todo Connect delloggetto di tipo FaxServer. Di
seguito verifichiamo se il documento presen-
te nella sotto-cartella Faxes; in caso positivo va-
lorizziamo la propriet Body delloggetto di ti-
po FaxDocument con il percorso al suddetto
documento. Dobbiamo ricordarci che con la
propriet Body indichiamo le pagine del Fax a me-
no della copertina; sebbene nessuno ci vieti di
incorporare la copertina del Fax allinterno del
documento stesso, bene precisare che la clas-
se FaxDocument espone due propriet Cover-
Page e 7 che consentono di definire in modo
opportuno la copertina del Fax da trasmettere.
La descrizione dettagliata delle due propriet
reperibile, rispettivamente agli indirizzi:
http://msdn2.microsoft.com/en-us/library/ ms687493
(VS.85).aspx e http://msdn2.microsoft.com/en-
us/library/ms686003 (VS.85).aspx.
LA PROPRIET BODY
Un altro dettaglio importante da tenere a men-
te quando vogliamo trasmettere un documen-
to via Fax, riguarda il tipo di documento che as-
sociamo alla propriet Body. Abbiamo gi ac-
cennato, quando abbiamo parlato dei vincoli
del progetto, che il tipo di documento che vo-
gliamo trasmettere influisce in modo determi-
nante sul processo di trasmissione. Ebbene a
questo punto possiamo enunciare la regola ge-
nerale che deve essere soddisfatta affinch il
documento venga trasmesso correttamente: il
tipo di documento che intendiamo trasmette-
re deve essere associato ad una applicazione,
installata sulla stessa macchina in cui instal-
lata la nostra applicazione, e la suddetta appli-
cazione deve supportare il verbo PrintTo.
Continuando nella descrizione del metodo Send-
Fax, ci resta da vedere come indicare il numero
del destinatario e come attivare il processo di
trasmissione. Nel primo caso, per rendere pi
semplice la soluzione, imponiamo un solo de-
stinatario il cui numero memorizzato nella
propriet RecipientNumber. I destinatari ven-
gono indicati attraverso la collezione Recipients
delloggetto di tipo FaxDocument; laggiunta di
ogni destinatario la si effettua invocando il me-
todo Add della collezione, a cui passiamo il nu-
mero del destinatario. Il primo parametro del
metodo Add rappresenta il numero del desti-
natario, il secondo parametro rappresenta il no-
me del destinatario (per semplicit passiamo
al metodo lo stesso valore per i due parametri).
Dopo aver definito tutti gli aspetti del Fax da
trasmettere, possiamo effettivamente inviare il
comando di trasmissione al servizio Fax invocando
il metodo ConnectedSubmit delloggetto di ti-
po FaxDocument a cui passiamo, come argo-
mento, proprio listanza delloggetto ti tipo
FaxServer che abbiamo creato in testa al meto-
do SendFax.
028-036:072-080 1-04-2008 18:44 Pagina 35
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web M
G
38
/Maggio 2008
Usare le tecnologie Microsoft per il Web
C
ome si evince dal titolo, lo scopo principa-
le di questo articolo trattare in modo
sistematico le fasi di deploying e installa-
zione di una Web Application sul server di desti-
nazione. Tuttava, evidente che largomento
Asp.Net non si pu considerare esaurito con le
puntate precedenti, vista la cospicua mole di
funzionalit di cui dispone il framework (alcune
delle quali, come i temi, le web parts, i servizi
web, ecc, non potremo neppure affrontare in
questa sede per mancanza di spazio o perch
fuori tema rispetto allo scopo dellarticolo): ci
riserviamo, pertanto, di accennare brevemente
ad alcuni di questi argomenti nei box laterali.
Un argomento che dobbiamo, invece, affrontare
un po pi da vicino lo sviluppo dei controlli
personalizzati. Se, infatti, abbiamo bisogno di un
controllo con particolari caratteristiche (non
presente tra i componenti standard .Net), possia-
mo allora pensare di svilupparne uno persona-
lizzato (quindi crearlo da zero), oppure possiamo
limitarci ad estenderne uno gi presente, inte-
grandolo con nuove funzionalit. Lo User
Control il modo pi semplice di realizzare un
controllo personalizzato: esso, infatti, un con-
trollo che si limita ad incorporare, a sua volta,
vari altri componenti. Ciascuno di questi com-
ponenti, in particolare, associato a determinati
eventi, che possono modificare lo stato dello
User Control stesso e, ovviamente, anche del
resto della pagina. Costruire uno User Control
molto facile: si tratta di un file .ascx, che comin-
cia di solito con una riga simile alla seguente:
<%@ Control Language="C#"
AutoEventWireup="true" %>
Il resto del controllo , invece, costituito da altri
componenti .Net (anche associati a eventi), codi-
ce HTML, codice lato-server, ecc Creare uno
User Control unoperazione in tutto simile alla
realizzazione di una pagina .aspx: nel file .ascx
trasciniamo i componenti, nel .ascx.cs inseriamo
il codice lato-server.
Linclusione del controllo nella pagina si effettua
aggiungendo le seguenti righe (naturalmente,
prima dobbiamo registrare il controllo, e solo
dopo lo possiamo istanziare):
<%@ Register Src="UserControl.ascx"
TagName="banner" TagPrefix="uc1" %>

<uc1:banner ID="banner1" runat="server" />


Unaltra tipologa di controllo personalizzato ,
invece, rappresentata dai Custom Control, che
derivano direttamente da una delle seguenti due
classi: System.Web.UI.Control o System.Web.UI.
WebControls.WebControl. Realizzare compo-
nenti di questo tipo (totalmente basati su codice)
sicuramente pi semplice se si usa Visual
Studio (che crea gi in automatico la struttura
delle classi da utilizzare); se si parte da un pro-
getto Web Control Library, inoltre, possibile
compilare il componente e riutilizzarlo in qual-
siasi altro progetto. Se tuttava questultimo
aspetto non poi cos realmente necessario, allo-
ra si pu tranquillamente creare una semplice
classe con le caratteristiche richieste, avendo
cura, naturalmente, di inserirla nella directory
riservata App_Code. Ed ecco un esempio di
Custom Control, presente anche nel codice sor-
gente (in questo caso ci basta derivare il control-
lo dalla classe TreeView, che gi possiede tutti gli
attributi necessari):
public class TreeViewCat : TreeView
{
protected override TreeNode CreateNode()
{
return new Model.Categoria();
}
}
Una trattazione sistematica ed esauriente dei
controlli personalizzati esula, tuttava, dagli
Conoscenze richieste
Conoscenze medie di
.Net Framework (C#) ,
MS Sql Server 2005,
Asp.Net
Software
Windows Home
Edition (o sup.), Visual
Web Developer, Sql
Server Management Studio
Express, West Wind ASP.NET
Compiler UI
Impegno
Tempo di realizzazione
REQUISITI
WEB APPLICATION
CON ASP.NET 2.0
IN QUESTA PUNTATA, CHE CONCLUDE IL NOSTRO PERCORSO DI ANALISI DELLA TECNOLOGIA
ASP.NET 2.0, AFFRONTEREMO LE MODALIT DI INSTALLAZIONE DI UNA WEB APPLICATION.
RIPERCORREREMO, INOLTRE, I PASSI DA ESEGUIRE PER IL DEPLOYMENT SU UN SERVER
038-042:032-035 1-04-2008 16:22 Pagina 38
scopi dellarticolo, e pertanto non ci addentria-
mo ulteriormente nei meandri della programma-
zione basata sui componenti.
INSTALLAZIONE
E CONFIGURAZIONE
DEL SITO
Finora, nelle scorse puntate, abbiamo lavorato
sulla nostra Web Application direttamente allin-
terno di un ambiente di sviluppo integrato,
com Visual Web Developer (il tool gratuito di
Visual Studio specifico per il web). Quando lan-
ciavamo lapplicazione, pertanto, veniva avviato
in modo automatico un Application Server gesti-
to dallambiente di sviluppo, che simulava in
tutto e per tutto il comportamento di IIS (il web-
server predefinito di casa Microsoft). Questo
accorgimento, da parte di Microsoft, introdotto
nella versione 2005 di Visual Studio, sicuramente
agevola molto lattivit dello sviluppatore (che
pu lavorare, ad esempio, anche con una versio-
ne Home Edition di Windows, di solito non dota-
ta di IIS), ma non elimina il problema del
deployment del sito e della sua configurazione
sul sistema host di destinazione. Linsieme di
attivit legate a questultima fase della realizza-
zione di una Web Application pu essere suddivi-
so, sostanzialmente, in tre macrocategorie:
G interventi diretti sullapplicazione: sono desti-
nati ai singoli file e cartelle che compongono la
Web Application (es. attribuzione di permessi
sulle cartelle, ecc);
G interventi su IIS: riguardano la configurazione
del webserver;
G interventi sul DB: si riferiscono a tutte quelle
attivit volte a permettere al sistema di inter-
facciarsi nel migliore dei modi con il program-
ma di gestione dei database (nel nostro caso,
Sql Server 2005).
Nei prossimi paragrafi analizzeremo pertanto
queste attivit, con un occhio di riguardo, in par-
ticolare, agli aspetti legati alla messa in sicurezza
della Web Application. Va precisato che nel
nostro studio faremo riferimento ad una piat-
taforma di test basata su Windows XP
Professional, per consentire a chiunque di effet-
tuare le prove sul proprio pc, ma ove necessario
faremo le dovute modifiche ed integrazioni per
estendere il discorso anche ai sistemi operativi
lato-server.
IDENTITA
DELLASP.NET PROCESS
Di norma il processo di elaborazione di Asp.Net
viene eseguito da un utente di Windows definito
ASPNET (su IIS 5) o Network Service (su IIS 6.0).
Questi due utenti sono abilitati in modo automa-
tico alla lettura ed esecuzione delle pagine .aspx,
tuttava in certi casi (come quando si lavora con
delle virtual directory, ossa applicazioni che pun-
tano su IIS ma che possono essere localizzate in
un qualsiasi path della rete, anche remoto)
occorre inserirli manualmente, e ovviamente
assegnare loro i giusti permessi.
Dal tab Protezione (nei sistemi in lingua inglese
Security) della finestra Propriet (Properties) del-
lapplicazione (ci si arriva cliccandoci sopra con
il tasto destro del mouse), possiamo facilmente
accorgerci se lutente di Asp.Net ha o meno i
diritti di lettura ed esecuzione sulla cartella; in
caso, tuttava, non trovassimo laccount in que-
stione, dobbiamo premere il pulsante Aggiungi, e
quindi ricercare lutente desiderato.
Una volta inserito laccount nella lista, dobbiamo
assegnargli tutti i permessi, ottenendo una
videata simile a quella presente in fig. 3.
Per trasformare la cartella dellapplicazione in una
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
39
G
Usare le tecnologie Microsoft per il Web
NOTA
COSA SONO LE
WEB PARTS ?
Le Web Parts sono
componenti della
pagina il cui aspetto
pienamente
configurabile da parte
dellutente. Una Web
Part pu, quindi,
essere rimossa dalla
pagina, minimizzata,
spostata a piacimento,
secondo le proprie
preferenze.
Le Web Parts nascono
proprio con lidea di
fondo di offrire
allutente finale la
massima libert nella
gestione della pagina
web, consentendogli
di aggiungere solo i
servizi effettivamente
richiesti, dare a
ciascuno di essi la
collocazione voluta,
ecc
Fig. 1: La prima finestra di inserimento del nuovo
utente
Fig. 2: Mediante questa finestra, raggiungibile dal
pulsante Avanzate illustrato in figura 1, possiamo
agevolmente selezionare lutente interessato
038-042:032-035 1-04-2008 16:22 Pagina 39
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web
M
G
40
/Maggio 2008
Usare le tecnologie Microsoft per il Web
directory virtuale su IIS, basta attivare la condivi-
sione sul Web (tramite lapposito tab). A questo
punto, aprendo lo snap-in di IIS (Pannello di con-
trollo -> Strumenti di amministrazione -> Internet
Information Services), possiamo verificare
lesistenza della nostra Web Application (fig. 4), che
abbiamo inserito nel Sito Web predefinito.
bene precisare, tuttava, che anche possibile
modificare il comportamento predefinito di
Asp.Net, basato di default sullimpiego degli
utenti ASPNET o Network Service.
Se intendiamo effettuare la personificazione del
processo Asp.Net con un altro utente, infatti,
possiamo semplicemente inserire questa riga
nel web.config:
<identity impersonate=true />
Lattributo impersonate, in particolare, permette
di svincolare lesecuzione del processo di
Asp.Net dallutente predefinito, attribuendo
questultima, invece, allutente che ha realmente
effettuato la richiesta. Nel caso, ad esempio, sa
configurato laccesso anonimo nel pannello di
IIS (come in figura 5), o si abbia avuto accesso
allapplicazione tramite la finestra di autentica-
zione di Windows (Windows Logon Screen), il
processo di Asp.Net sar eseguito dallutente
selezionato (e questo discorso vale anche per
laccesso al database). Va da s che tale utente
dovr avere tutti i permessi di accesso riguardo
allapplicazione e al DB, altrimenti incorrer in
eccezioni che ne bloccheranno irrimediabil-
mente la navigazione.Oltre allattributo imper-
sonate, inoltre, possibile anche specificare,
mediante gli attributi userName e password,
quale utente si desidera che effettui la personifi-
cazione del processo Asp.Net. Un cenno a parte
merita, infine, la gestione della sicurezza di IIS in
ambito server (es. Windows 2003): possibile,
infatti, sempre agendo sul tab di gestione della
sicurezza dello strumento di configurazione,
attivare delle restrizioni degli indirizzi IP e dei
nomi di dominio, per garantire o limitare
laccesso al sistema da parte di determinati sog-
getti.
INTERFACCIAMENTO
CON IL DATABASE
Per quello che riguarda linterfacciamento con il
DB, occorre ricordare che sono presenti due tipi di
autenticazione in Sql Server 2005:
G Autenticazione di Windows: lutente accede alli-
stanza di Sql Server tramite un account di acces-
so del sistema operativo ( la modalit consigliata
da Microsoft, perch permette di usufruire di
NOTA
LIBRI E ALTRE
RISORSE SU
.NET
Per il principiante,
consiglio la lettura di
qualsiasi manuale
anche tascabile su
Asp.Net, o la
consultazione delle
tante guide in linea
presenti sul Web (es.
quelle su Html.it).
Per chi desidera
approfondire gli
argomenti trattati:
G ASP.NET 2.0 GUIDA
PER LO SVILUPPATO-
RE
(Hoepli Informatica):
per chi ha gi fami-
liarit con la pro-
grammazione Web
(meglio se Asp.Net);
G Programmare
Microsoft ASP.NET
AJAX
(Dino Esposito):
legato esplicitamen-
te ad Ajax su .Net.
Fig. 3: Assegnazione dei permessi allutente
Fig. 4: IIS in azione
I controlli Wizard generici
permettono di sviluppare una
sorta di procedura guidata, che
necessario percorrere per
arrivare ad un determinato
risultato finale:
<asp:Wizard id=Wiz1
runat=server>
<WizardSteps>
<asp:WizardStep
title=Fase n. 1 runat=server>
Questa
la fase n. 1
</asp:WizardStep>
<asp:WizardStep
title=Fase n. 2 runat=server>
Questa
la fase n. 2
</asp:WizardStep>

E importante sottolineare che


nella scorsa puntata abbiamo
gi affrontato dei controlli
simili (PasswordRecovery,
CreateUserWizard), che sono
tuttava specializzati solo in un
determinato compito (come,
appunto, restituire le password
dimenticate o definire nuovi
utenti).
COSA SONO I CONTROLLI WIZARD ?
038-042:032-035 1-04-2008 16:22 Pagina 40
ht t p: / / www. i opr ogr ammo. i t
utenti gi presenti nel sistema informatico azien-
dale, evitando linserimento delle credenziali
nella stringa di connessione, e di conseguenza il
loro transito in rete);
G Autenticazione mista: offre anche la possibilit di
autenticarsi tramite account di Sql Server ( utile
in particolare quando occorre fornire un accesso
diretto al DB anche a utenti esterni alla propria
rete aziendale).
Senza scendere troppo nei meandri della configu-
razione di Sql Server 2005 (non questo lobiettivo
dellarticolo), definiamo invece i passaggi fonda-
mentali per labilitazione di un utente allaccesso a
un database:
1) innanzitutto, occorre creare, per lutente in
questione (es. Nome computer\aspnet), un
accesso allistanza di Sql Server (login):
CREATE LOGIN [<utente di Windows>] FROM
WINDOWS
2) Quindi dobbiamo creare un utente allinterno
del DB, e mapparlo con laccount di accesso
appena creato:
CREATE USER <nome utente> FOR LOGIN
<nome_login>
3) A questo punto, dobbiamo associare allutente
le giuste autorizzazioni e limitazioni di accesso.
Di solito conviene associare solo i ruoli
db_datareader e db_datawriter, che consentono
le operazioni minime di manipolazione dei dati,
ma se (come nellapplicazione di esempio) fac-
ciamo uso di stored procedure (ossa veri e propri
programmi che possono effettuare operazioni di
vario tipo), allora occorre rilasciare delle autoriz-
zazioni particolari. Le stored procedure, infatti,
sono assoggettate ad un livello di protezione
superiore rispetto alle semplici operazioni di let-
tura/scrittura, e quindi lutente che cerca di ese-
guirle senza i giusti privilegi incappa sicuramen-
te in uneccezione simile alla seguente: The EXE-
CUTE permission was denied on the object <pro-
cedura>, database <database>, schema
<schema>. Ecco un comando SQL che ci permet-
te di risolvere il problema:
GRANT EXECUTE ON dbo.nomeProcedura TO <nome
utente>
In questo modo abbiamo accordato le autorizza-
zioni di sola esecuzione della stored procedure
nomeProcedura allutente in riferimento (esisto-
no anche le autorizzazioni di modifica, acquisi-
zione privilegi di tipo proprietario, ecc...)
In ogni caso, lutilizzo di un tool grafico come Sql
Server Management Studio Express ci evita la digi-
tazione diretta di tutti questi comandi, fornendoci
invece una comoda interfaccia grafica e interattiva
(vedere fig. 6).
Naturalmente le possibilit offerte da Sql Server
2005 sono davvero sterminate, e quelli da noi citati
non sono che dei semplici assaggi di ci che que-
sto formidabile RDBMS in grado di offrire.
COMPILAZIONE
DELLA WEB APPLICATION
Chi solito programmare in modo desktop sar
abituato a ragionare in unottica di:
M
ioProgrammo Web
Maggio 2008/
41
G
Usare le tecnologie Microsoft per il Web
Fig. 5: il pannello di configurazione di IIS permette
di specificare le modalit con le quali viene garanti-
to laccesso alla Web Application
Fig. 6: con Sql Server Management Studio Express
effettuare le normali operazioni di manutenzione di
un DB reso molto pi semplice grazie ad una
comoda interfaccia grafica
LAUTORE
Enrico Viale
specializzato nello
sviluppo di
applicazioni sa web-
oriented che desktop
in ambiente Windows.
Chi desidera
contattarlo per
chiarimenti riguardo
allarticolo, o per
qualsiasi altro motivo,
pu farlo allindirizzo
enrico.viale@yahoo.it .
038-042:032-035 1-04-2008 16:22 Pagina 41
ht t p: / / www. i opr ogr ammo. i t
1) sviluppo: la fase di stesura del codice sorgente;
2) compilazione: la fase di trasformazione del
programma in un eseguibile a basso livello.
La fase di compilazione, in particolare, rende
lesecuzione del programma molto pi rapida e ne
offusca totalmente il codice sorgente. In ambito web,
invece, le cose sono un po diverse. La pagina, infatti,
non appena viene richiesta la prima volta, viene par-
serizzata e trasformata in una DLL (assembly), quin-
di viene istanziata, e infine viene eseguita restituen-
do il codice HTML risultante al client. Le volte suc-
cessive, tuttava, verr riutilizzata sempre la stessa
istanza (a meno che non intervengano modifiche nel
codice sorgente, che determinano nuovamente la
ricompilazione automatica al primo accesso), e
quindi le operazioni di parsing e creazione nuova
istanza non avvengono, a tutto vantaggio delle pre-
stazioni. La precompilazione di una Web Application
ha proprio lo scopo, quindi, di evitare il deployment
di pagine contenenti codice in chiaro (misura, que-
sta, molto utile per la sicurezza), e consente di mette-
re in produzione codice esente da bug (perch gi
testato e compilato in locale) e di immediata esecu-
zione. Pur essendo prevista anche nelle versioni pre-
cedenti di Asp.Net, la precompilazione delle Web
Application riceve, con lavvento della release 2.0,
una serie di miglioramenti davvero significativi: in
pratica, ogni pagina compilata in un assembly
diverso (mentre prima veniva creata ununica DLL
che costringeva tutte le volte a ricompilare lintera
applicazione), inoltre stato introdotto un comando
che manda in pensione lhandler precompile.axd
(che veniva digitato direttamente nella querystring
del browser nelle versioni precedenti di .Net): asp-
net_compiler. Questo eseguibile, da usarsi a riga di
comando, consente una discreta variet di opzioni,
che schematizzo in modo riassuntivo nella tabella
sottostante (cito solo le opzioni pi ricorrenti): Chi
usa Visual Studio in versione completa, potr avvan-
taggiarsi del menu Publish, che in grado di effettua-
re la precompilazione; Visual Web Developer, invece,
non possiede tale opzione (consente, infatti, solo la
copia del sito sul server con il menu Copy Web
Site).
E comunque possibile evitare lutilizzo diretto del
tool a riga di comando: possiamo, infatti, scaricare
un programma denominato West Wind ASP.NET
Compiler UI (sito web di riferimento http://www.west-
wind.com/tools/aspnetcompiler.asp), che presenta una
comoda interfaccia grafica molto semplice da utiliz-
zare. Ipotizziamo, a questo riguardo, di avere sul
desktop la cartella esempioComp, che dovr ospitare
il sito compilato.
La prima cosa da fare, innanzitutto, creare una
directory virtuale in IIS che punta su esempioComp:
fatto anche questo, possiamo ora aprire ASP.NET
Compiler UI e provare ad effettuare la compilazione.
Come si pu osservare facilmente aprendo la cartel-
la compilata, tutti i file sono ora offuscati: senza
l'opzione u (updatable), inoltre, non solo il Code
Behind stato compilato, ma anche le pagine .aspx,
il cui contenuto quindi non pi visibile (al loro
interno presente infatti la scritta This is a marker
file generated by the precompilation tool, and should
not be deleted!, che invita a non fare modifiche).
Infine, nella cartella bin si possono chiaramente
vedere le DLL generate dal processo di compilazione.
CONCLUSIONI
Il nostro viaggio allinterno della tecnologia ASP.NET
per ora termina qui. Abbiamo iniziato a gettare le basi
che vi consentono di scrivere la vostra prima applica-
zione per il Web in tecnologia Microsoft. Nel futuro
non mancheremo di approfondire le tematiche lega-
te ad ASP.NET
Enrico Viale
ioProgrammo Web
M
G
42
/Maggio 2008
Usare le tecnologie Microsoft per il Web
NOTA
COME SI CREA
UNA
DIRECTORY
VIRTUALE IN
IIS ?
Per creare una
directory virtuale,
basta semplicemente
aprire il pannello di
configurazione di IIS,
cliccare con il tasto
destro sul Sito Web a
cui si desidera
associare la directory,
e quindi selezionare la
voce: Nuova directory
virtuale. Verr attivata
una procedura guidata
che consente di
definire un alias per la
directory, e il percorso
fisico della cartella di
origine su disco.
In alternativa,
possibile anche
attivare la
Condivisione sul web
direttamente da tasto
destro sulla cartella
stessa.
Specica il percorso della metabase di IIS (il
database gerarchico contenente le informa-
zioni di congurazione di IIS). Questa op-
zione non combinabile con v o -p
Specica il percorso virtuale dellapplica-
zione da compilare (path di IIS)
Specica il percorso assoluto (da disco) del-
lapplicazione da compilare
Specica che lapplicazione aggiornabile
(omettendolo, anche le pagine .aspx vengo-
no compilate)
Rappresenta il path sico della cartella di
destinazione della compilazione
Indica che la cartella pu essere sovrascrit-
ta
-m
-v
-p
-u
targetDir
-f
Per evitare che, sul verificarsi di
un qualsiasi tipo di eccezione,
venga visualizzata la pagina
contenente il dettaglio
dellerrore (utile ai tecnici ma
decisamente inopportuno per
lutente generico), possibile
adottare varie soluzioni. Una
delle vie pi rapide ed efficaci
, sicuramente, prevedere un
blocco customErrors allinterno
del web.config:
<customErrors mode="On"
defaultRedirect="~/errori/ErroreGener
ico.aspx">
<error statusCode="404"
redirect="~/errori/PaginaInesistente.a
spx"></error>
</customErrors>
In particolare, se si verifica un
errore generico, si viene
redirezionati alla pagina
ErroreGenerico.aspx; nel caso
dellerrore 404 (Page Not
Found), invece, gestiamo in
modo specifico il
redirezionamento alla pagina
PaginaInesistente.aspx
(ovviamente possiamo gestire
allo stesso modo tutti gli errori
che vogliamo) .
COME POSSO FARE PER INTERCETTARE
GLI ERRORI ?
038-042:032-035 1-04-2008 16:22 Pagina 42
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
43
G
Drag & Drop facile nelle applicazioni Web
S
i amo arri vati al l ul ti ma puntata
della serie dedicata a Scriptaculous.
Negli articoli precedenti abbiamo
avuto modo di esaminare la parte con-
cernente gli effetti ed i controlli offerti da
questa complessa libreria. In questulti-
mo articolo analizzeremo una delle fea-
ture pi potenti ed appetibili, vale a dire
il drag & drop (trascinamento e rilascio).
In realt siamo gi abituati ad utilizzare
questo strumento per l e appl i cazi oni
desktop. Come sappiamo, tuttavia, non
esi stono control l i HTML/JavaScri pt
/CSS nativi per implementare il drag &
drop nel l e pagi ne web. Trami te
Scriptaculous potremo munire le nostre
applicazioni web di questa comodissima
feature.
Gli attori principali del drag & drop sono
sostanzialmente due:
G Gli elementi da trascinare.
G Lelemento su cui rilasciare gli item del
punto precedente.
In queste pagine procederemo come segue.
Esamineremo prima il concetto di trascina-
mento (drag) da solo e poi combinato al rila-
scio (drop).
OGGETTI
TRASCINABILI
Rendere un oggetto trascinabile (draggable)
con Scriptaculous un gioco da ragazzi, gra-
zie alla classe Draggable. La sintassi di base
che permette di convertire un elemento da
normale a trascinabile la seguente:
new Draggable(element, options);
Il primo parametro lID dellelemento (o il
riferimento) che vogliamo rendere trascinabi-
le, mentre il secondo il classico oggetto let-
terale alla cui sintassi siamo gi abituati dai
precedenti articoli. Per chi se li persi niente
paura, avremo modo di vedere le opzioni che
possibile impiegare, per customizzare tra-
scinamento e rilascio, nel corso del presente
articolo. Vediamo, ora, un primo semplice
esempio:
<html>
<head>
<style type="text/css">
#draggableBox
{
border: 1px solid #000;
background: #06f;
color: #fff;
padding: 5px;
width: 200px;
font-weight: bold;
cursor: move;
}
</style>
<script type="text/javascript"
src="./scripts/prototype.js"></script>
<script type="text/javascript"
src="./scripts/scriptaculous.js?load=effects,dragdr
op"></script>
<script type="text/javascript">
function
makeDraggable(elemId)
{
new
Draggable(elemId);
}
Event.observe(window, "load",
function(){makeDraggable("draggableBox")});
</script>
</head>
<body>
<div id="draggableBox">
Trascinami dove vuoi
</div>
Conoscenze richieste
JavaScript
Software
Prototype,
Scriptaculous
Impegno
Tempo di realizzazione
REQUISITI
DRAG & DROP NELLE
APPLICAZIONI WEB
PER GLI AMBIENTI DESKTOP SIAMO ABITUATI A USARE IL DRAG & DROP OGNI GIORNO.
MUOVIAMO FILE DA UNA CARTELLA ALLALTRA, ECC. IN QUESTARTICOLO VEDREMO COME
POTER USARE QUESTA POTENTE FEATURE ANCHE IN APPLICAZIONI WEB
J CD J WEB
Script-Drag&Drop.zip
cdrom.ioprogrammo.it
043-047:032-035 1-04-2008 17:02 Pagina 43
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web
M
G
44
/Maggio 2008
Drag & Drop facile nelle applicazioni Web
</body>
</html>
Come per gli articoli precedenti consiglio di
provare gli esempi per questarticolo conte-
stualmente alla sua lettura, per rendersi conto
dei reali effetti visivi da essi prodotti. Il codice
precedente disponibile nel file simple-
drag.htm. E una semplice pagina HTML che
contiene anche codice CSS e JavaScript.
Questultimo codice quello che concerne
Scriptaculous. La prima cosa da fare inclu-
dere Prototype e la parte di Scriptaculous
necessaria ad usare il drag & drop tramite le
seguenti righe di codice:
<script type="text/javascript"
src="./scripts/prototype.js"></script>
<script type="text/javascript"
src="./scripts/scriptaculous.js?load=effects,dragdr
op"></script>
Dopodich bisogna creare la funzione
makeDraggable che prende come parametro
lID di un elemento e lo rende draggable.
Come si noter, bastata una sola riga di
codice per far diventare trascinabile tale item:
new Draggable(elemId);
Il secondo parametro della classe Draggable,
infatti, opzionale. Il comportamento stan-
dard del dragging tale da rendere lelemento
un po pi opaco durante il suo trascinamen-
to. Per quanto riguarda il CSS usato, faccio
notare solo un attributo, vale a dire:
cursor: move;
Esso fa s che il puntatore del mouse passi
dallo stato di freccetta classica a quello di cro-
cetta tipicamente utilizzata per indicare che
un elemento pu essere spostato.
Notare inoltre luso di Event.observe, che fa
parte di Prototype piuttosto che di
Scriptaculous. Lo abbiamo utilizzato per
osservare levento load della pagina. In pra-
tica non appena la pagina caricata, viene
invocata la funzione make Draggable passan-
dole la stringa draggableBox come parametro.
In figura 1 si pu vedere lo stato del <div>
durante il suo trascinamento. Provate il codi-
ce che trovate sul CD allegato per poter
apprezzare leffetto ottico prodotto dagli
esempi proposti.
Ho ritenuto opportuno analizzare il trascina-
mento da solo, poich vi sono diverse applica-
zioni dove ha senso utilizzare solo il drag
senza la necessit di rilasciare loggetto trasci-
nato. Un esempio di tale applicazione si trova
su un motore di ricerca di voli e hotel low cost
che fa un intensivo uso di Scriptaculous. Il
sito : http://www.weefly.com.
La scorsa puntata abbiamo esaminato
lautocompleter utilizzato negli aeroporti di
partenza e arrivo. In WeeFly, per, possibile
scegliere gli aeroporti di arrivo, oltre che con
lautocompleter, tramite una lista caricata
non appena si clicca su Mostra Tutti Gli
Aeroporti. Dal link appena citato si arriver
alla suddetta lista, formata da tutti gli aero-
porti raggiungibili da quelli di partenza sele-
zionati.
Questa lista ha la simpatica peculiarit di
essere trascinabile dove meglio si crede. Vi
invito a provarla di persona anche se la figura
2 illustra tale situazione. La lista draggable
quella indicata dalla freccia rossa.
Fig. 1: Trascinamento in azione.
Fig. 2: Lista trascinabile di aeroporti di arrivo.
NOTA
SITOGRAFIA
Prototype Home Page:
http://www.prototypejs.o
rg/
Scriptacuolus Home
Page:
http://script.aculo.us/
Esempi di siti che
usano Scriptaculous:
Motore di ricerca per
voli e hotel low cost:
http://www.weefly.com
Esempio di sito web
convertito da Flash a
Scriptaculous:
http://www.dianamiller.m
e.uk/index.html
Sito della Apple:
http://www.apple.com/ap
erture/
Ne trovate molti altri
su:
http://wiki.script.aculo.us/
scriptaculous/show/Real
WorldUsage
043-047:032-035 1-04-2008 17:02 Pagina 44
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
45
G
Drag & Drop facile nelle applicazioni Web
CUSTOMIZZARE
IL TRASCINAMENTO
Come gi accennato, possibile personaliz-
zare il comportamento degli oggetti dragga-
ble tramite lutilizzo di un oggetto letterale
passato come secondo parametro opzionale
al costruttore della classe Draggable. La tabel-
la 1 riassume i campi che possiamo impiega-
re per tale oggetto.
Ecco la funzione makeDraggable modificata
leggermente di modo che usi alcune delle
opzioni di tabella 1:
function makeDraggable(elemId)
{
new Draggable(elemId,
{
ghosting: true,
snap : [200, 100],
revert : true
}
);
}
Il codice completo si trova nel file drag-
options.htm. Traducendo in parole il codice
precedente abbiamo: Crea un elemento tra-
scinabile tale che mantenga una copia di esso
nella sua posizione originale durante il trasci-
namento (opzione ghosting). Inoltre, fa s che
si muova con posizioni discrete su una griglia
ad intervalli di 200 pixel sullasse delle ascisse
e 100 pixel sulle ordinate (opzione snap).
Infine, non appena lutente rilascia
lelemento, riporta questultimo alla sua posi-
zione originale (opzione revert).. Vi invito a
provare questesempio e sperimentare un po
le altre opzioni per prenderci la mano.
RILASCIO DEGLI
ELEMENTI TRASCINATI
Abbiamo imparato a trascinare gli elementi e
customizzarne il comportamento tramite le
opzioni. Ora, per, servono dei contenitori
dentro i quali rilasciare gli elementi trascina-
ti. In Scriptaculous possiamo creare tali con-
tenitori utilizzando il metodo add di
Droppables. La sintassi la seguente:
Droppables.add(element, options);
Dove element lID dellelemento o il referen-
ce e options il classico oggetto letterale utiliz-
zato per customizzazioni varie. La tabella 2
starteffect
endeffect
revert
reverteffect
snap
zindex
constraint
ghosting
handle
change
Opzione Descrizione
Una funzione di callback che viene invocata allinizio del trasci-
namento di modo da applicare un effetto allelemento oggetto
del trascinamento. Leffetto applicato di default Effect.Opacity.
Una funzione di callback che viene invocata al termine del trasci-
namento di modo da applicare un effetto allelemento oggetto
del trascinamento. Di default leffetto applicato far tornare
lelemento trascinato alla sua opacit originale.
Un booleano che indica se invocare la funzione specicata in re-
verteffect quando il trascinamento termina. Il suo valore di de-
fault false ed in questo caso reverteffect non invocata.
Una funzione di callback invocata al termine del trascinamento
nel caso in cui revert valorizzato a true. E possibile denire
qualsiasi funzione per questo parametro. La funzione di default
riporta lelemento alla sua posizione originale.
Consente di imporre una griglia virtuale sul movimento consen-
tito alloggetto trascinato. In sostanza possibile far muovere
lelemento su posizioni. Vedremo un esempio che render pi
chiaro luso di questa opzione.
Lo z-index da applicare allelemento durante il trascinamento. Di
default impostato a 1000 di modo che loggetto trascinato vada
on top degli elementi su cui passa.
Tale propriet pu essere usata per limitare il movimento delle-
lemento trascinato sullasse orizzontale o verticale a seconda se
valorizzata a 'horizontal' piuttosto che a 'vertical'. Di default non
applicata nessuna restrizione di movimento.
Un booleano che indica se abilitare o meno il ghosting. In sostan-
za, se valorizzato a true, durante il trascinamento rimane nella
posizione originale una copia dellelemento trascinato nch
questultimo non rilasciato. Di default false.
Lelemento da utilizzare come maniglia per trascinare loggetto.
Se omesso, loggetto trascinato costituisce anche la sua maniglia.
Funzione di callback da invocare durante il trascinamento, ossia
ogni qualvolta la posizione dellelemento cambia.
Tab.1: Opzioni per customizzare il trascinamento (drag).
hoverclass
accept
onHover
onDrop
Opzione Descrizione
Una stringa che costituisce il nome di
una classe CSS che sar applicata alle-
lemento droppable quando un oggetto
trascinato entra nella sua area
dinteresse.
Il nome di una classe CSS (o array di
classi) che gli elementi draggable devo-
no possedere per essere accettati dalla
zona di rilascio. Di default tutti gli og-
getti sono gettabili nella drop zone. Se
si vuole accettare solo alcuni elementi
basta assegnargli una classe CSS e de-
nirla tramite il parametro accept.
Una funzione di callback invocata non
appena un elemento trascinabile si tro-
va sopra la zona di rilascio.
Una funzione di callback chiamata non
appena lutente rilascia loggetto. Si po-
trebbe utilizzare questa funzione per
noticare il server tramite una chiama-
ta Ajax ed aggiornare, ad esempio, un
carrello della spesa.
Tab.2: Opzioni per customizzare il rilascio (drop).
043-047:032-035 1-04-2008 17:02 Pagina 45
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web
M
G
46
/Maggio 2008
Drag & Drop facile nelle applicazioni Web
illustra alcune delle opzioni che possibile
utilizzare.
Segue un esempio che fa uso del drag & drop.
<html>
<head>
<style type="text/css">
/* CSS omesso per brevit */
</style>
<script type="text/javascript"
src="./scripts/prototype.js"></script>
<script type="text/javascript"
src="./scripts/scriptaculous.js?load=effects,dragd
rop"></script>
<script type="text/javascript">
function
makeDraggable(elemId)
{
new
Draggable(elemId,
{
revert: true
}
);
}
function
makeDroppable(elemId)
{
Droppables.add(elemId,
{
accept: "draggable",
onDrop : function(elem, droppableElem)
{
droppableElem.innerHTML +=
elem.innerHTML;
droppableElem.innerHTML += "<br />";
},
}
);
}
Event.observe(window, "load",
function()
{
makeDraggable("draggableBox1");
makeDraggable("draggableBox2");
makeDroppable("droppableBox");
}
);
</script>
</head>
<body>
<div style="width: 600px;">
<div
id="draggableBox2" class="draggable"
style="float: right;">
Elemento 2
</div>
<div
id="draggableBox1" class="draggable">
Elemento 1
</div>
</div>
<br /><br />
<div id="droppableBox">
</div>
</body>
</html>
In sostanza il codice precedente crea due ele-
menti trascinabili e uno in cui possibile rila-
sciare gli elementi trascinati. Per quanto riguar-
da il codice JavaScript abbiamo la funzione
makeDraggable, gi vista nel paragrafo preceden-
te, e la funzione makeDroppable, oltre allutilizzo
di Event.observe per inizializzare lapplicazione al
caricamento della pagina. La funzione
makeDroppable trasforma in area di rilascio
Prototype un framework scritto
in JavaScript. I framework sono
progettati con lo scopo di
facilitare lo sviluppo di software.
Essi permettono agli sviluppatori
di spendere pi tempo a risolvere
problemi legati alla soddisfazione
dei requisiti che non a trattare
con dettagli di basso livello che
non hanno nulla a che vedere con
i requisiti.
Scriptaculous, invece, una
libreria grafica JavaScript, vale a
dire un insieme di utility e
controlli per lo sviluppo di
applicazioni web altamente
interattive che contengono
effetti grafici molto accattivanti.
Come si pu notare, quindi, vi
differenza fra framework e
libreria, anche se tale differenza
cos sottile che molte persone
usano i due termini in modo
interscambiabile.
I FRAMEWORK E LIBRERIE GRAFICHE
Framework come Prototype e
librerie quali Scriptaculous
possono rendere lo sviluppo di
web application abbastanza
piacevole ed agevolato e ci
permettono di usare, molto
facilmente, controlli molto
apprezzati come il drag & drop,
che in passato erano disponibili
solo per le applicazione desktop.
APPLICAZIONI WEB E DESKTOP
BIBLIOGRAFIA
Prototype and
Scriptaculous in Action
D. Crane, B. Bibeault,
T. Locke
Manning
ISBN: 1-933988-03-7
043-047:032-035 1-04-2008 17:02 Pagina 46
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
47
G
Drag & Drop facile nelle applicazioni Web
lelemento che ha lID passato come parametro.
Notare luso di due opzioni, vale a dire accept e
onDrop. La prima significa che gli oggetti rilascia-
bili sono solo quelli che hanno classe CSS pari a
draggable. Per provare ci si crei un <div> trasci-
nabile, ma che non possegga la classe draggable.
Si noti che tale elemento sar trascinabile, ma il
suo rilascio nella drop zone non scatener
levento onDrop, proprio perch tale oggetto non
sar accettabile dalla zona di rilascio. A propo-
sito di onDrop, alla funzione di callback ad essa
associata sono passati in automatico due para-
metri: il reference allelemento trascinato e quel-
lo alla drop zone. Noi abbiamo sfruttato questi
parametri per aggiungere allHTML della zona di
rilascio lHTML contenuto nellelemento trasci-
nato. In unapplicazione per il mondo reale
molto probabilmente questa funzione farebbe
partire una chiamata, tramite Ajax, ad un com-
ponente server (script PHP, pagina JSP, Servlet o
qualsiasi altra cosa) passandogli i valori
dinteresse.
In figura 3 uno screenshot relativo al codice
precedente dopo aver trascinato e rilasciato
nellarea di drop sia lelemento 1 sia
lelemento 2.
CONCLUSIONI
In questarticolo abbiamo avuto modo di esa-
minare la parte di Scriptaculous concernente il
drag & drop. Come si intuisce, il campo
dapplicazione di questo potente strumento
virtualmente illimitato. Con Scriptaculous si
possono realizzare carrelli della spesa, liste tra-
scinabili in lungo e in largo, applicazioni che
simulano i post-it e chi pi ne ha pi ne metta.
La fantasia di chi programma costituisce
lunico limite che separa lo sviluppatore dal
realizzare una web application di successo.
Alessandro Lacava
Fig. 3: Drag & Drop completo.
Fig. 4: La Home Page di Scriptaculous
Per provare gli esempi proposti
in questo articolo servono
Prototype e Scriptaculous. Al
momento in cui scrivo, lultima
versione stabile di Prototype
la 1.6.0 e la potete trovare
allindirizzo
http://www.prototypejs.org/.
Vi un solo file da scaricare,
prototype.js. Una volta
effettuato il download si dovr
includere nelle pagine in cui si
intende utilizzarlo. Se, ad
esempio, avete posto il file
sotto la directory scripts, il
codice da usare il seguente:
<script type="text/javascript"
src="./scripts/prototype.js"></script
>
Per quanto riguarda
Scriptaculous bisogna scaricare
lultima versione dal sito
ufficiale allindirizzo
http://script.aculo.us/. Al momento in
cui scrivo la 1.8.1.
Scriptaculous pi modulare
rispetto a Prototype e quindi
composta da diversi file che
possono essere inclusi
separatamente a seconda le
esigenze. Una volta scaricato e
decompresso larchivio si noter
che, sotto la directory src, vi
sono diversi file JavaScript. Per
semplicit, prendeteli tutti e
metteteli sotto la directory
scripts dove si trova
prototype.js. Come dicevo, con
Scriptaculous possibile
includere, tramite una sintassi
particolare, solo i file che
servono. Ad esempio, se si vuole
usare solo il drag & drop,
baster una sintassi simile alla
seguente:
<script
src="./scripts/scriptaculous.js?load=ef
fects,dragdrop"
type="text/javascript"></script>
E stato necessario includere
anche gli effetti in quanto usati
internamente dal drag & drop.
Se, invece, si ha bisogno
dellintera libreria allora si
include solo scriptaculous.js:
<script src="./scripts/scriptaculous.js"
type="text/javascript"></script>
Chiaramente, dato che
Scriptaculous dipende da
Prototype, si dovr includere
prima questultimo.
SOFTWARE NECESSARIO
043-047:032-035 2-04-2008 12:01 Pagina 47
ht t p: / / www. i opr ogr ammo. i t
TIPS&TRICKS M
G
48
/Maggio 2008
Una raccolta di trucchi da tenere a portata di mouse
JAVA
UN SCRIPT PER VALIDARE UNA
DATA IMMESSA DA UN UTENTE
private static boolean DataValida(int year, int month, int day)
{
boolean result = true;
try
{
DateFormat df =
DateFormat.getDateInstance(DateFormat.SHORT,
Locale.US);
df.setLenient(false);
final String dateString = month + "/" + day +
"/" + year;
df.parse(dateString);
}
catch (Exception e)
{
result = false;
}
return result;
}
COME AVVIARE
UNAPPLICAZIONE A RIGA DI
COMANDO IN MODO SINCRONO
public class Test
{
public static void main(String[] args)
{
System.out.println("Before Call");
Runtime r = Runtime.getRuntime();
try
{
// Call the command-line program.
Process p =
r.exec("C:/JavaExecTest/bin/Debug/JavaExecTest.exe ARG1 ARG2
ARG3");
// Wait for it to complete.
p.waitFor();
// Get program's exit code.
final int exitValue = p.exitValue();
}
catch (Exception ex)
{
System.out.println("Caught exception
" + ex.getMessage());
}
System.out.println("After Call");
}
}
COME RECUPERARE IL NUMERO
DI CPU PRESENTI NEL SISTEMA
static private isWindows =
System.getProperty("os.name").startsWith("Windows");;
static private int n_CPUs = 0;
static public int getCPUCount() {
if (n_CPUs > 0) return n_CPUs;
if (isWindows) return 1; // no clue
// POSIX systems, attempt to count CPUs from /proc/stat
try {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("cat
/proc/stat");
InputStream is = process.getInputStream();
InputStreamReader isr = new
InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
n_CPUs = 0;
// valid cores will print as cpu0, cpu1. cpu2 ...
I trucchi del mestiere
Tips & Tricks
Questa rubrica raccoglie trucchi e piccoli pezzi di codice, frutto dellesperienza di chi programma, che solitamente non
trovano posto nei manuali. Alcuni di essi sono proposti dalla redazione, altri provengono da una ricerca su Internet, altri
ancora ci giungono dai lettori. Chi volesse contribuire, potr inviare i suoi Tips&Tricks preferiti. Una volta selezionati,
saranno pubblicati nella rubrica.
048-051:082-083 1-04-2008 18:29 Pagina 48
ht t p: / / www. i opr ogr ammo. i t
while ((line = br.readLine()) != null) {
if (0 == line.indexOf("cpu") &&
line.length() > 3
&& Character.isDigit(line.charAt(3))) {
n_CPUs++;
}
}
// fix possible errors
if (0 == n_CPUs) n_CPUs = 1;
return n_CPUs;
} catch (Exception e) {
Utils.log(e.toString()); // just one line
return 1;
}
}
CREARE UN FILE E RENDERLO DI
SOLA LETTURA
import java.io.File;
import java.io.IOException;
public class FileAttributesDemo {
public static void main (String[] args) throws IOException {
readonly=false
File file = new File ("test.txt");
if (file.exists ()) {
file.delete ();
}
file.createNewFile ();
System.out.println ("Before. canWrite?" + file.canWrite ());
// imposta il file di sola lettura */
file.setWritable (false);
System.out.println ("After. canWrite?" + file.canWrite ());
}
}
COME APRIRE UN DOCUMENTO
MICROSOFT WORD
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
public class Test {
public static void main(String[] a) {
try {
Desktop desktop = null;
if (Desktop.isDesktopSupported()) {
desktop = Desktop.getDesktop();
}
desktop.open(new File("nome_del_file.doc"));
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
COME CREARE E INVIARE UN
MESSAGGIO E-MAIL DI SOLO
TESTO
import java.util.Date;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
* utilizzo: <code>java msgsendsample <i>to from smtphost
true|false</i></code> */
public class MainClass {
static String msgText = "Corpo del messaggio.\n";
public static void main(String[] args) {
if (args.length != 4) {
usage();
System.exit(1);
}
System.out.println();
String to = args[0];
String from = args[1];
String host = args[2];
boolean debug = Boolean.valueOf(args[3]).booleanValue();
Properties props = new Properties();
props.put("mail.smtp.host", host);
if (debug)
props.put("mail.debug", args[3]);
Session session = Session.getInstance(props, null);
session.setDebug(debug);
try {
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
InternetAddress[] address = { new InternetAddress(args[0]) };
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("JavaMail APIs Test");
msg.setSentDate(new Date()); msg.setText(msgText);
Transport.send(msg);
} catch (MessagingException mex) {
System.out.println("\n--Exception handling in
msgsendsample.java");
mex.printStackTrace();
System.out.println();
Exception ex = mex;
M TIPS&TRICKS
Maggio 2008/
49
G
Una raccolta di trucchi da tenere a portata di mouse
048-051:082-083 1-04-2008 18:29 Pagina 49
ht t p: / / www. i opr ogr ammo. i t
do {
if (ex instanceof SendFailedException) {
SendFailedException sfex = (SendFailedException) ex;
Address[] invalid = sfex.getInvalidAddresses();
if (invalid != null) {
System.out.println(" ** Indirizzo non valido");
if (invalid != null) {
for (int i = 0; i < invalid.length; i++)
System.out.println(" " + invalid[i]);
}
}
Address[] validUnsent = sfex.getValidUnsentAddresses();
if (validUnsent != null) {
System.out.println(" ** Errore nellindirizzo");
if (validUnsent != null) {
for (int i = 0; i < validUnsent.length; i++)
System.out.println(" " + validUnsent[i]);
}
}
Address[] validSent = sfex.getValidSentAddresses();
if (validSent != null) {
System.out.println(" ** ValidSent Addresses");
if (validSent != null) {
for (int i = 0; i < validSent.length; i++)
System.out.println(" " + validSent[i]);
}
}
}
System.out.println();
if (ex instanceof MessagingException)
ex = ((MessagingException) ex).getNextException();
else
ex = null;
} while (ex != null);
}
}
private static void usage() {
System.out.println("utilizzo: java msgsendsample <to> <from>
<smtp> true|false");
}
}
C#
FAR IN MODO CHE UN TEXBOX
ACCETTI SOLO DETERMINATI
CARATTERI
private void textBox1_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
e.Handled = e.KeyChar < '0' || e.KeyChar > '9';
}
// in questo caso il textbox1 accetter solo caratteri compresi tra lo
0 e il 9
COME PIANIFICARE LA
CANCELLAZIONE AUTOMATICA
DI CARTELLE E/O FILE
private const int FO_DELETE = 3;
private const int FOF_ALLOWUNDO = 0x40;
private const int FOF_NOCONFIRMATION = 0x0010;
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto,
Pack=1)]
public struct SHFILEOPSTRUCT
{
public IntPtr hwnd;
[MarshalAs(UnmanagedType.U4)] public int wFunc;
public string pFrom;
public string pTo;
public short fFlags;
[MarshalAs(UnmanagedType.Bool)] public bool
fAnyOperationsAborted;
public IntPtr hNameMappings;
public string lpszProgressTitle;
}
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);
...
SHFILEOPSTRUCT fileop = new SHFILEOPSTRUCT();
fileop.wFunc = FO_DELETE;
fileop.pFrom = filePath + '\0' + '\0';
fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
SHFileOperation(ref fileop);
VB.NET
COME RIDIMENSIONARE
UNIMMAGINE IN FORMATO
THUMBNAIL
Private Function ThumbnailCallback() As Boolean
End Function
Private Sub CreateThumbnail()
Dim myCallback As Image.GetThumbnailImageAbort = AddressOf
ThumbnailCallback
Dim myBitmap As Bitmap = New Bitmap("c:\\prova.jpg")
Dim myThumbnail As Image = myBitmap.GetThumbnailImage(64,
64,myCallback, IntPtr.Zero)
PictureBox1.Image = myThumbnail
End Sub
Private WithEvents MyColumn As TextBox
Private TempColumn As DataGridTextBoxColumn
TIPS&TRICKS M
G
50
/Maggio 2008
Una raccolta di trucchi da tenere a portata di mouse
048-051:082-083 1-04-2008 18:29 Pagina 50
ht t p: / / www. i opr ogr ammo. i t
COME INTERCETTARE IL TASTO
PREMUTO ALLINTERNO DI UNA
CELLA DI UN CONTROLLO
DATAGRID
Private Sub DataGrid1_MouseLeave(ByVal sender As Object, ByVal e
As System.EventArgs) Handles DataGrid1.MouseLeave
Dim MyCell As Integer = (CType(sender,
DataGrid).CurrentCell.ColumnNumber)
ColumnSetup (MyCell)
End Sub
Private Sub ColumnSetup(ByVal MyCol As Integer)
TempColumn =
DataGrid1.TableStyles(0).GridColumnStyles(MyCol)
MiaColonna = TempColumn.TextBox
End Sub
Private Sub MiaColonna _Keypress(ByVal sender As Object, ByVal e As
System.Windows.Forms.KeyPressEventArgs) Handles
MiaColonna.KeyPress
MsgBox("Si premuto il tasto " & e.KeyChar)
End Sub
ASP.NET
UTILIZZARE MYSQL COME
DATABASE PREDEFINITO
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ODBC" %>
<script language="VB" Runat="server">
Sub Page_Load(Source as Object, E as EventArgs)
BindData
End Sub
Sub BindData()
Dim strConn as string
strConn =
"DRIVER={MySQL};SERVER=IP_Address;DATABASE=nome_db;" & _
"USER=id_utente;PASSWORD=password_scelta;
OPTION=3;"
Dim MySQL as string = "Select CustomerID,
CompanyName, ContactTitle, " & _
"Address, City, Phone from Customers"
Dim MyConn as New ODBCConnection(strConn)
Dim ds as DataSet=New DataSet()
Dim Cmd as New
ODBCDataAdapter(MySQL,MyConn)
Cmd.Fill(ds,"Customers")
MyDataGrid.Datasource=ds.Tables("Customers").DefaultView
MyDataGrid.DataBind()
End Sub
Sub Page_Change(sender As Object, e As
DataGridPageChangedEventArgs)
MyDataGrid.CurrentPageIndex = e.NewPageIndex
BindData
End Sub
</script>
<html>
<head>
<meta name="GENERATOR" Content="ASP Express
4.0">
<title>MySQL with ASP.Net</title>
</head>
<body>
<form id="form1" Runat="server">
<asp:Datagrid Runat="server"
Id="MyDataGrid"
GridLines="Both"
cellpadding="0"
cellspacing="0"
Headerstyle-
BackColor="#BDCFE7"
Headerstyle-Font-
Name="Arial"
Headerstyle-Font-Size="12"
BackColor="#E7EFFF"
Font-Name="Arial"
Font-Size="10"
AlternatingItemStyle-
BackColor="#E7EFFF"
AlternatingItemStyle-Font-
Name="Arial"
AlternatingItemStyle-Font-
Size="10"
BorderColor="Black"
AllowPaging = "True"
PageSize = "10"
PagerStyle-Mode =
"NumericPages"
PagerStyle-
HorizontalAlign="Center"
PagerStyle-PageButtonCount =
"10"
OnPageIndexChanged =
"Page_Change">
</asp:DataGrid>
</form>
</body>
</html>
COME MANTENERE LA SCROLL
POSITION DOPO UNOPERAZIONE
DI POST BACK
Generalmente, quando si effettua il post back di una pagina e
magari si in fondo alla stessa, IE restituisce la pagina azzerando
la posizione di scroll, riportato il focus a inizio pagina. Per ovviare
basta aggiungere lattributo che segue nella direttiva @page
<%@ Page Language=VB
MaintainScrollPositionOnPostback=true
M TIPS&TRICKS
Maggio 2008/
51
G
Una raccolta di trucchi da tenere a portata di mouse
048-051:082-083 1-04-2008 18:29 Pagina 51
ht t p: / / www. i opr ogr ammo. i t
SISTEMA M
G
52
/Maggio 2008
Guida ad Apache Wicket
T
ra i web framework distribuiti con licenza open
source sta acquisendo sempre maggior consi-
derazione Wicket. In questo articolo vedremo
come Wicket si distingua per facilit di apprendimento
ed utilizzo e soprattutto per leleganza e la pulizia con
cui stato progettato.
CREIAMO UNA CLASSE
HELLONUMBER
La funzionalit che ci prefissiamo di realizzare quel-
la di una pagina web in cui lutente clicca su un button
e visualizza un numero random su una label. Il tutto
sar contenuto in una web application che presen-
ter il seguente file di deploy web.xml.
<servlet>
<servlet-name> WicketOneHello </servlet-name>
<servletclass>org.apache.wicket.protocol.http.WicketSer
vlet</servlet-class>
<init-param>
<param-name>applicationClassName
</param-name>
<paramvalue>roby.wicketone.client.WicketOneHello
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>WicketOneHello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
Nella sezione servlet-mappingassociamo ad un pattern,
relativo allurl della richiesta http, la servlet denomi-
nata WicketOneHello; nella definizione della servlet
stabiliamo quale classe Java dovr prendersi cura del-
le richieste http in arrivo. A questo punto non ci resta
che prendere in esame la classe WicketOneHello; la
sua definizione molto semplice in quanto estende
WebApplication e prevede un solo metodo getHome-
Page che restituisce la classe a cui associata la home
page dellapplicazione.
public class WicketOneHello extends WebApplication{
public Class getHomePage() {
return HelloNumber.class;
}
}
A questo punto facile immaginare che nella classe
HelloNumber troveremo i componenti salienti della no-
stra applicazione.
public class HelloNumber extends WebPage{
private int getRandom(){
return (int)Math.round(Math.random()*1000)%100;
}
public HelloNumber(){
final IModel numModel=new Model("Numero: ");
Label number=new Label("numLabel",numModel);
Form f=new Form("webForm"){
public void onSubmit() {
int num=getRandom();
numModel.setObject("Numero: "+num);
}
};
f.add(number);
add(f);
}
}
Analizzando il costruttore si nota che per prima cosa
viene dichiarato un oggetto numModel di tipo Model;
il valore passato nel suo costruttore rappresenta la
stringa utilizzata da uno dei tanti tipi di widget grafi-
ci presenti nel framework. Nel nostro esempio il pre-
cedente numModel viene associato alla Label num-
ber; infatti vediamo che al suo costruttore vengono
passati la stringa numModel e loggetto numModel.
Il primo valore rappresenta il riferimento (wickewt:id)
che bisogna utilizzare nel file html per referenziare la
Label in questione, mentre il secondo rappresenta il mo-
dello associato al widget. Successivamente viene di-
chiarato un oggetto f istanza di una classe anonima che
estende Form. In tale classe viene effettuato loverriding
del metodo onSubmit; questo metodo invocato dal-
la piattaforma quando sulla form html in questione
IL WEBFRAMEWORK
PER TUTTI I GUSTI
SONO MOLTI I WEB FRAMEWORK OFFERTI DAL MONDO OPEN SOURCE AGLI SVILUPPATORI
JAVA. WICKET LEMERGENTE CHE PRESENTA MOLTE CARATTERISTICHE CHE LO RENDONO
UNICO E FACILE DA UTILIZZARE OLTRE CHE CONFORME AL PATTERN MVC
Conoscenze richieste
Java, Servlet e Tomcat
Software
JDK 1.5, Tomcat ed
Eclipse 3.x
Impegno

Tempo di realizzazione
REQUISITI
052-059:072-080 1-04-2008 16:31 Pagina 52
ht t p: / / www. i opr ogr ammo. i t
M SISTEMA
Maggio 2008/
53
G
Guida ad Apache Wicket
viene effettuato il submit. E proprio alla fine dellese-
cuzione di questo metodo che il framework ridisegna
tutti i componenti grafici controllando che i model a
loro associati non abbiano cambiato valore. Ecco per-
ch proprio in questo metodo che calcoliamo un
numero random e lo utilizziamo per cambiare la strin-
ga associata al modello numModel. A questo punto
non ci resta che aggiungere la Label alla Form e la Form
alla nostra WebPage. Lesempio non ancora com-
pleto, infatti Wicket prevede una parte implementati-
va riservata al codice html da associare ad ogni pagi-
na; quindi nello stesso package in cui collocato il fi-
le HelloNumber.java bisogna editare ed inserire un fi-
le HelloNumber.html.
<html><head>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1">
<title>HelloNumber with Wicket 1.3</title>
</head><body>
<form wicket:id="webForm">
<h2>Hello <span wicket:id="numLabel"/></h2>
<input type="submit" value="random"/>
</form></body></html>
Come possiamo notare ci troviamo alle prese con un
semplice file html che presenta alcuni wicket:id valo-
rizzati in maniera opportuna. I valori associati sono e
devono essere le stringhe utilizzate come primo pa-
rametro nella costruzione dei vari componenti grafi-
ci. Oltre a questo primo vincolo bisogna notare che i
tag hrml, che utilizzano il parametro wicket:id, ri-
specchiano la struttura utilizzata dai corrispondenti com-
ponenti nel codice Java. Infatti, nel file html, il tag form
(con wicketd:id=webForm) racchiude un tag span
che contiene anchesso un parametro wicket:id; nel
codice Java corrispondente notiamo che la Label ini-
zializzata con la stringa numLabel viene aggiunta,
tramite il metodo add, alloggetto istanza di Form. In
questo caso sarebbe stato rilevato un errore se avessimo
aggiunto direttamente alla WebPage la Label in questione.
UNAPPLICAZIONE CHE
GESTISCE I TALK
Visti i caratteri salienti di questo framework possia-
mo cimentarci nellimplementazione di unapplica-
zione web un po pi complessa. Ci che vogliamo
implementare unapplicazione che gestisca i talk,
ovvero le conferenze o le presentazioni, tramite fun-
zionalit quali linserimento, la modifica, la visualiz-
zazione e la ricerca degli stessi.
Il nostro ambiente di sviluppo sar composto da Wicket
1.3 e da Eclipse per lediting del codice Java e delle pa-
gine HTML; per quanto riguarda la persistenza dei da-
ti utilizzeremo HSQLDB come DBMS e Hibernate per
il mapping. Lapplicazione inoltre presenter i cano-
nici tre livelli; il presentation layer sar composto da
wicket, il business layer sar rappresentato da una clas-
se che espone i servizi essenziali, mentre il data layer
da Hibernate e da un DAO (Data Access Object) che
ne filtra le funzionalit.
Lo schema dei dati da utilizzare sar semplificato al
massimo riducendo il tutto ad una tabella avente la
seguente struttura:
ID: chiave della tabella
SPEAKER: Stringa che indica la persona che presenter
la conferenza
PLACE: il posto in cui si terr la conferenza
TOPIC: largomento del talk
ABSTRACT: un descrizione abbastanza dettagliata
della presentazione
STARTDATE: il giorno in cui si terr
STARTHOUR: lora di inizio della presentazione
DURATION: la durata in minuti del talk
Tale tabella sar mappata tramite Hibernate su una
semplice classe Java.
public class TalkDTO implements Serializable{
private String id=null;
private String speaker=null;
private Date startDate=null;
private String startHour=null;
private String place=null;
private String topic=null;
private String abstractText=null;
private Integer duration=null;
. . .
//metodi set e get
. . .
}
La classe un semplice Java Bean che contiene tanti
campi quante sono le colonne della tabella vista in
precedenza. Ovviamente tali campi sono utilizzabili tra-
mite i rispettivi metodi set e get ad essi associati.
IMPLEMENTAZIONE
DEL BUSINESS LAYER
Il business layer espone i servizi che sono utilizzati dal
presentation layer; nel nostro caso linterfaccia che
ne riassume le funzionalit TalkService.
public interface TalkService {
public void addTalk(TalkDTO talk) throws
TalkServiceException;
public TalkDTO getTalkByID(String talkID) throws
TalkServiceException;
public List<TalkDTO> findAllTalks() throws
TalkServiceException;
public void updateTalk(TalkDTO talk) throws
052-059:072-080 1-04-2008 16:31 Pagina 53
ht t p: / / www. i opr ogr ammo. i t
SISTEMA M
G
54
/Maggio 2008
Guida ad Apache Wicket
TalkServiceException;
public void deleteTalk(TalkDTO talk) throws
TalkServiceException;
public List<TalkDTO> findTalksBE(TalkDTO tEx)
throws TalkServiceException;
}
I metodi e la loro semantica sono di immediata com-
prensione; infatti addTalk viene utilizzato per ag-
giungere un oggetto istanza di TalkDTO, getTalkByID
serve a leggere un TalkDTO usando la sua chiave, find-
AllTalks serve a leggere tutti i TalkDTO presenti sul DB.
updateTalkinvece invocato dal presentation layer per
modificare un TalkDTO gi esistente e deleteTalk per
cancellarlo. Il metodo findTalksBE implementa una
ricerca by example; questa tipologia di ricerca preve-
de lutilizzo di una entit del dominio di ricerca come
esempio da utilizzare nella ricerca stessa. In pratica si
usa una istanza di TalkDTO con un sottoinsieme dei cam-
pi valorizzati e si usa questo sottoinsieme nella sezio-
ne where dellinterrogazione sql. Ovviamente esiste
una classe concreta che implementa linterfaccia Talk-
Service.
public class TalkServiceImpl implements TalkService{
public static TalkService ts=new TalkServiceImpl();
private TalkServiceImpl(){}
public static TalkService sing(){
return ts;
}
. . .
}
La classe in questione stateless , quindi ne pu esse-
re condivisa una sola istanza da chiunque la voglia
utilizzare. Questa caratteristica spiega il perch si sia
scelto di implementarla come singleton; nel nostro
caso realizzato un costruttore privato ed un metodo
statico sing che ne restituisce lunica istanza statica a
disposizione.
PRESENTATION LAYER:
IL LAYOUT
Ma come si presenter la nostra applicazione agli oc-
chi degli utenti? Per rispondere a questa domanda bi-
sogna progettare sin da ora il layout da utilizzare nel-
limplementazione del presentation layer. Allora stabiliamo
una volta per tutte che le pagine che stiamo per im-
plementare saranno divise verticalmente in tre zone.
In alto prevista una zona contenente il logo dellap-
plicazione, un po pi in basso ci sar un pannello con-
tenente il men delle funzionalit principali; sotto il me-
nu e per tutto il resto della pagina ci sar la zona variabile
riservata alla funzionalit corrente. Quindi sono pre-
viste due zone che saranno presenti in tutte le pagine
ed una variabile. Per implementare questo requisito sfrut-
teremo una delle caratteristiche pi avanzate di Wicket
ovvero la markupinheritance; noi la chiameremo ere-
ditariet tra pagine web. Questa feature consente di
definire pagine web come template (modelli) per altre
pagine web; a livello di classi Java si sfrutta lereditariet
tra classi propria del linguaggio.
public class TalkPageTemplate extends WebPage{
public TalkPageTemplate(){
Label title=new Label("titleLabel","Wicket4Talk");
this.add(title);
TopMenuPanel tmp=new TopMenuPanel("panelMenu");
this.add(tmp);
}
}
Il template in questione molto semplice, infatti de-
finiamo una label per il titolo delle pagine web; il logo
dellapplicazione come vedremo lo definiremo diret-
tamente nellHTML, invece utilizzeremo un TopMe-
nuPanel per linserimento del menu delle funzionalit.
Il file HTML associato al template deve avere lo stes-
so nome (TalkPageTemplate.html) del file Java (cam-
bia lestensione ovviamente) e deve contenere i com-
ponenti definiti nel file Java.
<html><head>
<title wicket:id="titleLabel"></title>
</head>
<body>
. . .
<table><tr>
<td><img src="wicket4t.jpg"/></td>
</tr><tr>
<td><span wicket:id="panelMenu"/></td>
</tr><tr>
<td><wicket:child/>
</td></tr>
</table>
. . .
</body></html>
Il titolo della pagina viene definito tramite il wicket:id
valorizzato con la stringa titleLabel, il tutto serve a
referenziare la stringa Wicket4Talk passata come se-
condo parametro nel costruttore della Label title al-
Figura 1: Lapplicazione Wicket4Talks
052-059:072-080 1-04-2008 16:31 Pagina 54
ht t p: / / www. i opr ogr ammo. i t
M SISTEMA
Maggio 2008/
55
G
Guida ad Apache Wicket
linterno del file Java. Il resto della pagina presenta
una <table> HTML avente tre righe; nella prima viene
introdotta unimmagine rappresentante il logo del-
lapplicazione. Nella seconda riga viene inserito, tra-
mite il parametro wicket:id valorizzato con la stringa
panelMenu, il pannello con il menu associato alle
funzionalit dellapplicazione stessa. Nella terza riga
possiamo notare lutilizzo del tag <wicket:child/>; que-
sto tag delimita la zona della pagina html che verr
riempita con il contenuto previsto dalle pagine wicket
che estendono la pagina che funge da modello. In pra-
tica ogni pagina, che utilizza il template in questione,
andr a riempire solo questa parte del template.
Anche limplementazione del pannello che contiene
il menu orizzontale molto semplice.
public class TopMenuPanel extends Panel{
public TopMenuPanel(String id){
super(id);
PageLink talksLink=new
PageLink("talks",ListTalksPage.class);
PageLink editTalkLink=new
PageLink("createTalk",CreateTalkPage.class);
PageLink searchTalksLink=new
PageLink("searchTalks",SearchTalksPage.class);
this.add(talksLink);
this.add(editTalkLink);
this.add(searchTalksLink);
}
}
La classe TopMenuPanel estende Panel, come para-
metro del costruttore viene utilizzata una stringa che
deve coincidere con il valore che si d al wicket:id as-
sociato al pannello. Successivamente vengono istan-
ziati ad aggiunte alla pagina tre istanze della classe Pa-
geLink. Loggetto talksLink serve a definire un colle-
gamento ipertestuale con la pagina che visualizza tut-
ti talks memorizzati. Ce da notare che il costruttore del-
la classe PageLink accetta in input due parametri: il
primo, come al solito, determina il valore con cui va-
lorizzare il wicket:id associato, il secondo invece spe-
cifica la classe rappresentante la pagina da visualiz-
zare cliccando sul link. Loggetto editTalkLink con-
sente di accedere alla pagina che implementa
linserimento di un nuovo talk. Invece searchTalksLink
definisce un link alla pagina contenente la funziona-
lit di ricerca. Ovviamente i tre oggetti una volta istan-
ziati vanno aggiunti al Panel tramite il metodo add.
Per quanto riguarda la parte HTML del pannello, ab-
biamo tre semplici tag <a> che utilizzano il wicket:id
valorizzato ognuno con la corrispondente stringa usa-
ta nel codice Java.
<wicket:panel>
<a wicket:id="talks">All Talks</a><a
wicket:id="createTalk">Create Talk</a><a
wicket:id="searchTalks">Search</a>
</wicket:panel>
Il codice HTML delimitato dal tag <wicket:panel>
VISUALIZZARE I DATI
La nostra applicazione prevede sia una funzionalit
che mostra un elenco dei talk presenti sul DB, sia una
funzionalit di ricerca che visualizza un elenco dei talk
che rispondono ai requisiti della ricerca stessa. Le due
fasi di visualizzazione possono essere implementate
dalla stessa classe. Nel nostro caso si tratta della clas-
se ListTalksPage.
public class ListTalksPage extends TalkPageTemplate{
public ListTalksPage(){
super();
try {
List<TalkDTO> talks =
TalkServiceImpl.sing().findAllTalks();
init(talks);
} catch (TalkServiceException e) {
e.printStackTrace();
}
}
public ListTalksPage(List<TalkDTO> talks){
super();
init(talks);
}
. . . metodo init . . .
}
La classe estende il template di pagina che abbiamo ana-
lizzato in precedenza; il primo costruttore viene utilizzato
quando si vogliono visualizzare tutti i talk. I dati ne-
cessari vengono recuperati tramite il metodo find-
AllTalks della classe TalkServiceImpl. Il secondo co-
struttore accetta come parametro una List<TalkDTO>;
questo costruttore si presta ad essere utilizzato per vi-
Figura 2: Il progetto visto da Eclipse
052-059:072-080 1-04-2008 16:31 Pagina 55
ht t p: / / www. i opr ogr ammo. i t
sualizzare una lista di talk recuperati come risultato
di una ricerca. Vediamo adesso come stato imple-
mentato il metodo init.
private void init(final List<TalkDTO> talks){
PageableListView listView=new
PageableListView("talks",talks,10){
public void populateItem(final ListItem item){
final TalkDTO talk =
(TalkDTO)item.getModelObject();
item.add(new Label("speaker", talk.getSpeaker()));
item.add(new Label("place", talk.getPlace()));
item.add(new Label("topic", talk.getTopic()));
item.add(new Label("startDate",
ClientUtils.toString(talk.getStartDate())));
item.add(new Label("startHour",
talk.getStartHour()));
Per prima cosa viene creato un oggetto di tipo Pagea-
bleListView; questa classe, definita nel framework
Wicket, permette di visualizzare tabelle di dati e pa-
ginarli in base alle esigenze del programmatore. Il pri-
mo parametro passato rappresenta la stringa che do-
vr valorizzare il parametro wicket:id allinterno del
codice HTML. Il secondo parametro la lista di og-
getti da visualizzare; il terzo rappresenta il numero
massimo di oggetti che si possono visualizzare con la
paginazione. Per personalizzare il rendering dellog-
getto listView necessario effettuare loverriding del
metodo populateItem. Questo metodo viene invoca-
to dal framework tante volte quanti sono gli oggetti
contenuti in talks. Al suo interno vengono creati cin-
que oggetti istanze di Label, c da notare che i para-
metri utilizzati nei loro costruttori sono la solita strin-
ga da associare ai wicket:id ed i valori da visualizzare
nella tabella recuperandoli dalloggetto talk. Questi
oggetti una volta creati vanno aggiunti tramite il me-
todo addal ListItempassato come parametro nel me-
todo populateItem.
Link viewLink=new Link("viewLink"){
public void onClick(){
setResponsePage(new
ViewTalkPage(talk.getId()));
}
};
item.add(viewLink);
Link updateLink=new Link("updateLink"){
public void onClick(){
setResponsePage(new
UpdateTalkPage(talk.getId()));
}
};
item.add(updateLink);
Link deleteLink=new Link("deleteLink"){
public void onClick(){
try {
TalkServiceImpl.sing().deleteTalk(talk);
talks.remove(talk);
} catch (TalkServiceException e) {
e.printStackTrace();
}
setResponsePage(new ListTalksPage(talks));
}
};
item.add(deleteLink);
}
};
this.add(listView);
this.add(new PagingNavigator("navigator", listView));
}
Ogni riga della tabella di visualizzazione conterr tre
link denominati view, update e delete. La semantica e
la creazione dei tre link abbastanza semplice, c da
notare come per ogni Link venga effettuato loverriding
del metodo onClick. Inoltre tramite il metodo setRe-
sponsePage viene rediretto il browser alla pagina cor-
rispondente al parametro passato al metodo stesso.
Lultima istruzione presente nel metodo init evidenzia
lutilizzo di un PagingNavigator, questo oggetto con-
sente di navigare la tabella quando gli elementi con-
tenuti superano la capacit massima prevista per la
paginazione. Ovviamente nello stesso package va de-
finito un file ListTalksPage.html che viene utilizzato
per visualizzare i dati gestiti dalla classe appena ana-
lizzata.
<wicket:extend>
. . .
<table><tr>
. . .
<tr wicket:id="talks">
<td><span wicket:id="topic"></span></td>
<td><span wicket:id="speaker"></span></td>
<td><span wicket:id="place"></span></td>
SISTEMA M
G
56
/Maggio 2008
Guida ad Apache Wicket
DEPLOYARE LE DUE APPLICAZIONI
Sotto la directory wicket/src
troverete le due applicazioni
descritte in questo articolo; sotto
la directory wicket/wicketone
troverete invece la web-app che
contiene le due applicazioni.
Per veder funzionare le due
applicazioni necessario copiare
la webapp sotto la cartella
webapps della propria istanza di
Tomcat; a questo punto bisogna
configurare in modo opportuno
il file
<tomcat>/webapps/wicketone/WE
B-INF/classes/hibernate.cfg.xml
Supponiamo che il path di
Tomcat sia C:\tomcat, allora
bisogna modificare il suddetto
file in modo che contenga il
seguente tag xml:
. . .
<property
name="hibernate.connection.
url">jdbc:hsqldb:file:/tomcat/
webapps/wicketone/WEB-
INF/db/wicketone</property>
. . .
A questo punto sufficiente
avviare Tomcat e visitare gli url
http://127.0.0.1:8080/wicketone/app/ e
http://127.0.0.1:8080/wicketone/hello/
per veder funzionare le due
applicazioni.
052-059:072-080 1-04-2008 16:31 Pagina 56
ht t p: / / www. i opr ogr ammo. i t
<td><span wicket:id="startDate"></span></td>
<td><span wicket:id="startHour"></span></td>
<td><a wicket:id="viewLink">view</a></td>
<td><a wicket:id="updateLink">update</a></td>
<td><a wicket:id="deleteLink">delete</a></td>
</tr>
</table>
<span wicket:id="navigator"/>
</wicket:extend>
I tag HTML sono delimitati dal tag <wicket:extend>
che necessario ad implementare lereditariet tra
pagine web. In pratica tutto ci che delimitato da
questo tag viene sostituito al tag <wicket:child/> pre-
sente nel codice html del template (TalkPageTempla-
te.html). Allinterno del tag <tr> troviamo il parametro
wicket:id=talks; esso indica che le righe della tabel-
la in questione saranno popolate con loggetto Pa-
geableListView. Ovviamente lassociazione dovuta
al fatto che loggetto stato costruito con lo stesso va-
lore passatogli come primo parametro nel costrutto-
re. Analogamente le colonne delle righe prodotte sa-
ranno associate agli oggetti istanze di Label e di Link
create nel metodo populateItem. Sotto la tabella sta-
to collocato il PagingNavigator referenziato dal para-
metro wicket:id=navigator.
RIUTILIZZO
DEI COMPONENTI
Tra le funzionalit che ci siamo prefissati di imple-
mentare ci sono la creazione, la modifica e la ricerca;
queste funzionalit hanno in comune lutilizzo di una
form per limmissione dei dati relativi ad un talk, ov-
vio che lazione da eseguire dopo la submit della form
diversa. Con le dovute accortezze possiamo imple-
mentare una sola form che di volta in volta esegua
azioni diverse in base al contesto in cui utilizzata.
Noi ci concentreremo sulla funzionalit di modifica
tralasciando lanalisi delle altre in quanto i cambia-
menti riguardano solo linterazione con il Business
Layer. Partiamo questa volta dallimplementazione
delle pagine html, iniziando da UpdateTalkPage.html.
<wicket:extend>
<div align="center"><b>Update Talk</b></div>
<span wicket:id="updatePanel"/>
</wicket:extend>
Ovviamente il tag <wicket:extend> serve a definire
una pagina che ne usa unaltra come template; men-
tre wicket:id=editPanel definisce lutilizzo di un Pa-
nel. La corrispondente classe (UpdateTalkPage.java),
che estende TalkPageTemplate, presenta soltanto
limplementazione del costruttore; loggetto id pas-
sato come parametro serve per recuperare loggetto
tdtodal DB . Successivamente viene costruito un Edi-
TalkFormPanel e lo si aggiunge alla pagina.
public class UpdateTalkPage extends TalkPageTemplate{
public UpdateTalkPage(String id){
super();
UpdateTalkOperation uOperation=new
UpdateTalkOperation();
TalkDTO tdto=null;
try {
tdto=TalkServiceImpl.sing().getTalkByID(id);
} catch (TalkServiceException e) {
e.printStackTrace();
}
EditTalkFormPanel etfp=new
EditTalkFormPanel("updatePanel",true,
uOperation,tdto);
add(etfp);
}
}
Come possiamo notare la stringa updatePanel, pas-
sata come primo argomento al costruttore, corrisponde
al valore associato al parametro wicket:id presente nel
file HTML. Il secondo parametro invece definisce qua-
le operazione deve essere eseguita al submit della form.
La sua implementazione prevede la definizione di un
solo metodo come previsto dallinterfaccia Stra-
tegyOperation.
public class UpdateTalkOperation implements
StrategyOperation{
public void exeOperation(Component
source,TalkDTO tdto) {
try {
TalkServiceImpl.sing().updateTalk(tdto);
source.setResponsePage(new
ViewTalkPage(tdto.getId()));
catch (TalkServiceException e) {
e.printStackTrace();
}
}
}
La prima istruzione effettua lupdate delloggetto sul
DB, successivamente si forza la risposta http verso la
pagina ViewTalkPage.
La classe EditTalkFormPanel estende Panel ed il suo co-
struttore accetta tre parametri.
public class EditTalkFormPanel extends Panel{
public EditTalkFormPanel(String
panelID,StrategyOperation so,TalkDTO td){
super(panelID);
EditTalkForm etf=new
EditTalkForm("editForm",true,so,td);
this.add(etf);
}
M SISTEMA
Maggio 2008/
57
G
Guida ad Apache Wicket
052-059:072-080 2-04-2008 12:11 Pagina 57
ht t p: / / www. i opr ogr ammo. i t
}
Al suo interno viene istanziato un oggetto di tipo Edit-
TalkForm e successivamente viene aggiunto al pan-
nello stesso. La classe EditTalkForm prevede un co-
struttore ed il metodo onSubmit.
class EditTalkForm extends Form{
private StrategyOperation so=null;
private TalkDTO tdto=null;
public EditTalkForm(String formID,boolean
checkFields,StrategyOperation so,TalkDTO td){
super(formID);
this.tdto=(td!=null?td:new TalkDTO());
setModel(new CompoundPropertyModel(tdto));
TextField place=new TextField("place");
TextField speaker=new TextField("speaker");
TextArea abstractText=new TextArea ("abstractText");
TextField topic=new TextField("topic");
DateTextField startDate = new
DateTextField("startDate", new
PrortyModel(tdto,"startDate"), new
StyleDateConverter("S-", true));
startDate.add(new DatePicker());
TextField startHour=new TextField("startHour");
TextField duration=new TextField("duration");
this.add(place);
this.add(speaker);
this.add(abstractText);
this.add(topic);
this.add(startDate);
this.add(startHour);
this.add(duration);
this.so=so;
this.add(new FeedbackPanel("message"));
if(checkFields){
startDate.setRequired(true);
place.setRequired(true);
topic.setRequired(true);
}
}
. . .
}
Una parte cruciale del costruttore quando viene in-
vocato il metodo setModel; infatti viene stabilito che
il Model per la Form in questione loggetto tdtoistan-
za di TalkDTO. In seguito vengono creati ed aggiunti al-
la Form tanti oggetti quanti sono i campi della classe
TalkDTO. Questi Component non vengono inizializzati
con un Model in quanto utilizzano il CompoundPro-
pertyModel passato nel metodo setModel. Loggetto start-
Date costituisce una eccezione a quanto appena det-
to; infatti per i textfield, che contengono delle date, il
framework prevede una specializzazione molto utile:
DateTextField. Questa consente di definire anche lo
stile con cui vengono convertite le date in stringhe. Al
DateTextField stato associato un DatePicker ovvero
un widget grafico che consente di scegliere una data da
un Calendario navigabile che appare come popup.
Nella form viene inserito, tramite loggetto istanza di
FeedbackPanel, anche un campo di testo visualizzato
nel caso in cui ci sia un campo di input che non sta-
to validato. Nel nostro esempio abbiamo utilizzato un
RequiredValidator (il framework ne prevede altri, mol-
to pi complessi); questo validator viene sfruttato so-
lo per i campi in cui viene invocato il metodo setRe-
quired(true). Infatti nel caso in cui lutente non inse-
risce i suddetti campi, viene visualizzato il messaggio
presente nel file EditTalkFormPanel.properties.
RequiredValidator=${label} is a required field
SISTEMA M
G
58
/Maggio 2008
Guida ad Apache Wicket
Figura 3: La form di immissione dati arricchita dal
DatePicker.
Figura 4: Il sito di riferimento del framework Wicket.
PROPERTYMODEL
E COMPOUNDPROPERTYMODEL
Il framework Wicket
fortemente basato sul concetto
di Model; per questo motivo ne
sono previsti di vario tipo e con
caratteristiche molto diverse
tra loro. PropertyModel
definisce un tipo di Model che
associa ad un Component la
propriet (utilizzando i metodi
set e get) di un oggetto
corrispondente alla stringa
passata come secondo
argomento al suo costruttore:
DateTextField startDate = new
DateTextField("startDate", new
PrortyModel(tdto,"startDate"));
Mentre la classe
CompoundPropertyModel
associa ad un insieme di
Component le propriet di un
oggetto utilizzato come
parametro nel suo costruttore, in
questi casi il nome del
Component deve corrispondere
alla propriet delloggetto.
NOTA
IL SITO DI
RIFERIMENTO
Da quasi un anno
Wicket un progetto
open source della
comunit Apache;
pertanto il suo sito di
riferimento
raggiungibile
allindirizzo
http://wicket.apache.
org
052-059:072-080 1-04-2008 16:31 Pagina 58
Il messaggio viene associato al particolare Validator
utilizzato nel file Java che porta lo stesso nome del fi-
le properties. Il metodo onSubmit non fa altro che in-
vocare il metodo exeOperationsulloggetto istanza di
una classe che implementa StrategyOperation.
public final void onSubmit(){
so.exeOperation(this,tdto);
}
Ormai abbiamo imparato che le classi che estendo-
no direttamente o indirettamente Panel o WebPage
devono avere un file html associato. Analizziamo le
caratteristiche salienti di EditTalkFormPanel.html.
<wicket:panel>
<span wicket:id="message"/>
<form wicket:id="editForm">
<table>
<tr><td>TOPIC</td><td>
<input wicket:id="topic"/>
</td></tr>
<tr><td>SPEAKER</td>
<td><input wicket:id="speaker"/>
</td></tr>
<tr><td>ABSTRACT</td>
<td> <TEXTAREA
wicket:id="abstractText"></TEXTAREA></td></tr>
. . .
</table>
</form>
</wicket:panel>
Il tag <wicket:panel> racchiude il contenuto html re-
lativo ad un panel. Il wicket:id=message serve a vi-
sualizzare gli eventuali messaggi di errore commessi
dallutente nel compilare la form; mentre il
wicket:id=editForm collega la form html alla classe
EditTalkForm. La stessa form, come avevamo gi visto
nel codice Java, contiene tutti i campi di input asso-
ciati ai campi della classe TalkDTO.
CONCLUSIONI
In questo articolo abbiamo visto le caratteristiche prin-
cipali di Wicket; ci siamo resi conto che il suo utilizzo
prevede una netta separazione tra la logica di presen-
tazione dei dati, realizzata in puro HTML, e la logica ap-
plicativa implementata in Java. Per quanto riguarda
lapproccio imposto dal framework palese che i con-
cetti fondamentali sono quello di model e quello di
componente grafico; questi delineano un alto grado di
riutilizzo del codice che va al di la dei principi base
della programmazione OO.
Roberto Sidoti
M SISTEMA Guida ad Apache Wicket
LAUTORE
Roberto Sidoti
Ingegnere
Informatico, in
passato si occupato
di servizi VoIP;
attualmente lavora
come Functional
Designer per Herzum
Software, una
multinazionale di
consulenza
specializzata nello
sviluppo di
componenti per
applicazioni SOA.
052-059:072-080 1-04-2008 16:31 Pagina 59
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
63
G
Progettare una pagina web
A
l terzo appuntamento del nostro mini-
corso sui fogli di stile siamo arrivati ad
affrontare uno dei pi affascinanti (e anche
complessi) temi con cui si trova a che fare chi lavora
con i CSS: il layout.
IL LAYOUT
DELLA PAGINA WEB
Per layout della pagina Web intendiamo tutto quel-
l'insieme di tecniche che riguardano il posiziona-
mento degli elementi nella pagina e la struttura della
stessa. Agli albori del web il problema non si poneva
nemmeno : la struttura era pi o meno quella di un
documento di testo, al massimo si poteva agire sulla
dimensione ed il colore dei caratteri. I Menu erano
rappresentati come elenchi puntati. Poi, a partire
dalla versione 3.2 di HTML (rilasciata dal W3C nel
1997), venne rilasciato un nuovo elemento ovvero
<table>. Nelle intenzioni dei progettisti delle specifi-
che di HTML 3.2 il tag <TABLE> doveva servire a rap-
presentare dei dati in forma di struttura riga/colonna
(come una tabella di database o di excel per capirsi).
Ad esempio per rappresentare alcuni dati statistici in
HTML si pu usare un markup come questo:
<table border="1"><caption><em>Dati
popolazione</em> </caption><tr>
<th rowspan="2"></th>
<th colspan="2">Media </th>
<th rowspan="2">Occhi<br />
celesti </th></tr><tr>
<th>altezza </th><th>peso </th>
</tr><tr> <th>Maschi </th>
<td>1,78 </td>
<td>75 kg </td>
<td>20% </td>
</tr><tr><th>Femmmine </th>
<td>1,70 </td><td>60 kg </td>
<td>23% </td></tr>
</table>
Che d luogo ad un output come quello mostrato in
figura 1. Questo tag ha da subito attirato l'attenzione
dei web designer. L'elemento table infatti consente
di disporre a piacimento gli elementi nella pagina
controllandone in modo molto preciso la posizione.
Uno dei principali utilizzi di table il posizionamen-
to dei menu del sito a destra o sinistra del contenu-
to principale della pagina web. Poniamo ad esempio
di dover realizzare un layout del tipo di quello
mostrato in figura 2. Utilizzando una tabella di
layout si sarebbe impostato con :
<table border="0" cellspacing="2" cellpadding="2"
width="100%">
<tr valign="top"><td bgcolor="#EEEEEE"
width="180px">
<h2>Menu</h2><div><a href="#">Chi siamo</a>
</div><div><a href="#">Dove siamo</a></div>
<div><a href="#">I prodotti</a></div><div>
<a href="#">Contatti</a></div></td><td>
<h2>Contenuti</h2><p><!testo -->
</p>
</td>
</tr>
</table>
Conoscenze richieste
Conoscenza di base di
HTML
Software
Nessuno
Impegno
Tempo di realizzazione
REQUISITI
STOP ALLE TABELLE
PAGINE WEB CON I CSS
PENULTIMO APPUNTANTAMENTO CON I FOGLI DI STILE. ABBANDONIAMO L'USO DELLE TABELLE
PER DISEGNARE IL LAYOUT DELLA PAGINA WEB E VEDIAMO COME UTILIZZARE I CSS PER CREARE
SITI WEB PI ACCESSIBILI E GESTIBILI. DIMENTICHIAMO IL TAG TABLE.
Fig. 1: Una <table> nel browser
Fig. 2: Un semplice layout con menu laterale creato
utilizzando <table>
063-067:032-035 1-04-2008 16:54 Pagina 63
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web
M
G
64
/Maggio 2008
Progettare una pagina web
Questo solo un esempio semplicistico, in realt le
table sono state spesso usate (e abusate) dai web
designer per comporre delle pagine ad elevato con-
tenuto grafico. Prendiamo ad esempio l'orribile
layout grafico mostrato in figura 3 A prescindere
dalla sua bruttezza, pone comunque problemi teori-
ci di non poco conto : elementi sovrapposti, semitra-
sparenze e altro ancora.Il web designer non faceva
che disegnare la pagina in un programma grafico
come Photoshop e poi, usando gli strumenti messi a
disposizione degli stessi tool grafici, suddivideva
l'immagine in tanti "pezzetti" che venivano riassem-
blati in una table. Il programma si occupava di split-
tare l'immagine in vari pezzetti e di produrre il codi-
ce HTML. Il codice HTML corrispondente all'output
di figura 3 qualcosa come:
<table id="Table_01" width="801" height="601"
border="0" cellpadding="0" cellspacing="0">
...
<tr>
<td colspan="8">
<img
src="images/Splitted_table_06.jpg" width="687"
height="1" alt=""></td>
<td>
<img
src="images/spacer.gif" width="1" height="1"
alt=""></td>
</tr>
<tr>
<td rowspan="6">
<img
src="images/Splitted_table_07.jpg" width="1"
height="157" alt=""></td>
<td colspan="2" rowspan="2"
background="images/Splitted_table_08.jpg"
width="194" height="76">
<div
id="azienda">l'azienda</div></td>
<td rowspan="11">
<img
src="images/Splitted_table_09.jpg" width="2"
height="500" alt=""></td>
<td colspan="2" valign="top"
rowspan="7" width="269" height="354"
background="images/Splitted_table_10.jpg">
<!-- <img
src="images/Splitted_table_10.jpg" width="269"
height="354" alt=""> -->
<p>
<!--testo-->
</p>
</td>
<td colspan="2">
<img
src="images/Splitted_table_11.jpg" width="221"
height="1" alt=""></td>
<td>
<img
src="images/spacer.gif" width="1" height="1"
alt=""></td>
</tr>
...
</table>
si pensi che ne abbiamo riportato solo un minimo
estratto!
I PROBLEMI DI TABLE
Da quanto abbiamo visto risulta evidente che
l'utilizzo delle tabelle per l'impaginazione era diven-
tato pressoch insostenibile. I problemi che si evi-
denziano in questa tecnica sono:
1. Leggendo la pagina con un browser testuale il
testo contenuto negli elementi grafici si perde ed
il menu si trova mischiato al testo
Questo fatto rende difficile l'accessibilit al sito ai
disabili che utilizzano strumenti diversi dai nor-
mali browser.
2. Lo spezzettamento delle immagini e il riassembla-
mento utilizzando una tabella porta a produrre
un codice HTML pressoch illeggibile, con molte
piccole immagini da scaricare e quindi a proble-
mi notevoli per la manutenzione e le prestazioni
del sito.
Ma allora come evitare tutto questo? Naturalmente
con i CSS!
LA SOLUZIONE DEI CSS
Sempre prendendo a modello il layout che abbiamo
visto, potremmo ottenere un effetto analogo con il
seguente markup HTML:
<div id="main">
<img src="images/testo.png" id="testo"
width="260" height="100" alt="Sito Web" />
<ul class="menu">
<li><a
href="#">l'azienda</a></li>
<li><a href="#">chi
siamo</a></li>
Fig. 3: Il layout grafico ottenuto da immagini suddivi-
se e da tabelle
063-067:032-035 1-04-2008 16:54 Pagina 64
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web
Maggio 2008/
65
G
Progettare una pagina web
<li><a
href="#">prodotti</a></li>
<li><a
href="#">contatti</a></li>
</ul> <div class="content"> <!--testo-->
</div> </div>
collegato al foglio di stile che definisce queste regole:
body {background-color: #C9D3E2; }
DIV#main {
width: 695px; height: 447px;
margin: 30px auto; position: relative;
background: url(images/ovale.jpg) no-repeat left top;
}
IMG#testo{
position: absolute; top: -40px; left: 35px;
}
UL.menu {
margin: 0; padding: 0; list-style: none;
position: absolute; left: 30px; top: 70px;
}
UL.menu LI {
width: 176px; height: 35px;display: block; margin: 0;
background: url(images/button.png) no-repeat left top;
padding: 15px 0 0 20px;
font: bold 12px Arial, Helvetica, sans-serif;
}
UL.menu A {
text-decoration: none; color: #FFF;
}
DIV.content{
position: absolute; top:76px; left: 250px;
width:269px; height:300px;
font: normal 12px 'Lucida Sans Unicode','Lucida
Grande', Arial, Helvetica, sans-serif;
}
Il risultato identico a quello ottenuto con la tabel-
la (sempre orribile, ma questo non colpa dei CSS).
I vantaggi sono evidenti:
1. HTML comprensibile e leggero (27 kb contro i 38
kb della versione precedente, il 30% in meno).
2. Separazione tra grafica e struttura. Che vuol dire
anche riusabilit sia della veste grafica (applica-
bile ad altre pagine simili) che della struttura
(alla quale possono essere applicate altre vesti
grafiche)
3. Accessibilit anche da parte di browser testuali o
vocali.
Abbiamo visto quindi che, con l'aiuto dei CSS, possi-
bile ottenere risultati analoghi, e anche superiori, a
quanto possiamo realizzare usando le tabelle.
Vediamo adesso, in pratica, quali sono gli attributi CSS
maggiormente coinvolti nella realizzazione dei layout.
TECNICHE CSS PER LAYOUT
Per controllare il layout sono utilizzati alcuni attribu-
ti CSS, di alcuni ne abbiamo gi parlato nell'articolo
precedente, ma comunque opportuno ricordarli :
G border disegna un bordo intorno all'elemento.
border dispone a sua volta di tre sotto-attributi:
border-width lo spessore del bordo espres-
so in px o con una delle costanti : thin, medium
e thick.
border-color il colore del bordo
border-style lo stile del bordo : solid (conti-
nuo), dotted (tratteggiato), dashed (tratteggiato
pi ampio), double (doppia linea), groove (corni-
ce 3D), inset (incassato 3D), outset (in rilievo 3D).
Quindi, ad esempio:
border:1px solid #CCCCCC;
oppure:
border-width:1px;
border-style:solid;
border-color: #CCCCCC;
border tuttavia consente anche una maggiore flessi-
bilit, ovvero l'impostazione di un bordo diverso
per ognuno dei quattro lati dell'elemento attraverso
gli attributi:
border-top lato superiore
border-right lato destro
border-bottom lato inferiore
border- left lato sinistro
ognuno di questi attributi ha poi, a sua volta, dei
sotto-attributi corrispondenti a spessore, colore e
stile, quindi possiamo avere:
border-top:1px solid #CCCCCC;
o anche:
border-top-width:1px;
border-top-style:solid;
border-top-color: #CCCCCC;
e cos via anche per gli altri tipi di bordo.
G margin imposta il margine esterno dell'elemen-
to rispetto all'elemento contenitore.
Il valore espresso nelle unit di misura valide.
Come valore possibile anche usare auto oppure
0 (il numero zero senza unit di misura).
Margin una propriet composta, nel senso che
NOTA
MIMARE IL
COMPORTA-
MENTO DELLE
TABELLE
Nella versione 2 dei
CSS possibile
riprodurre
esattamente il
comportamento dei
tag table, tr, td ecc.
attraverso i valori
dell'attributo display
(table, table-row,
table-cell ecc.). Se
siamo costretti a
ricorrere ad altri
stratagemmi perch
Internet Explorer,
nemmeno nella
versione 7, supporta
queste propriet (lo
far solo dalla
versione 8).
063-067:032-035 1-04-2008 16:54 Pagina 65
ht t p: / / www. i opr ogr ammo. i t
ioProgrammo Web
M
G
66
/Maggio 2008
Progettare una pagina web
accetta fino a quattro valori separati da spazi (per
indicare, rispettivamente, il margine superiore,
destro, inferiore e sinistro) con una sintassi del tipo:
margin:<top> <right> <bottom> <left>;
ad esempio:
margin:0 auto 12px 30%;
se viene indicato un solo valore il margine si
applica a tutte le direzioni, ad esempio:
margin:4px;
Anche per margin poi possiamo esprimere valori
per uno dei quattro lati:
margin-top
margin-right
margin-bottom
margin-left
G padding imposta il margine interno dell'elmen-
to, riferito cio rispetto agli elementi contenuti in
esso. Il valore espresso nelle unit di misura
valide che abbiamo visto per margin.
Anche qui possiamo usare padding sia come pro-
priet composta:
padding:0 auto 12px 30%;
che come propriet singole:
padding-top:0;
padding-right:auto;
padding-bottom:12px;
padding-left:30%;
oppure riferendosi a tutte le direzioni:
padding:4px;
G left , top, bottom e right impostano la distanza
(sinistra, superiore, inferiore e destra) dell'ele-
mento dall'intera pagina se position absolute.
G min-width, min-height, max-width, max-height
impostano larghezza e altezza minima e massi-
ma dell'elemento. In Internet Explorer queste
propriet sono supportate solo dalla versione 7 in
standard mode (cio, come abbiamo detto nel-
l'articolo precedente quando viene dichiarato un
DOCTYPE), la versione 6 supporta solo min-
height per gli elementi TD,TH e TR.
Per gli attributi position, float, display, visibility fac-
ciamo riferimento a quanto illustrato nell'articolo
precedente.
LA STRUTTURA
GENERALE DELLA PAGINA
La prima cosa da impostare la disposizione gene-
rale della pagina, ovvero le "macro aree" in cui si
presenta la pagina Web. Gli elementi principali
sono schematizzati nella figura 5:
container elemento che contiene tutti gli altri, a
rigor di logica potrebbe sembrare logico che sia il
tag HTML body. Tuttavia pi spesso di ricorre a un
div che ci consente una maggiore flessibilit come
impostare i margini, centrare il contenuto rispetto
alla pagina, dargli una larghezza fissa ecc.
header la testata della pagina, in genere conte-
nente il logo e le informazioni o i link di carattere
generale.
menu il menu del sito, posizionato di norma a
destra o sinistra del contenuto e contenente i link
alle altre pagine.
content il contenuto vero proprio della pagina
footer il pi di pagina, contenente di solito le infor-
mazioni come indirizzo, contatti ecc.
Ovviamente in una struttura possono anche non
essere presenti tutti questi elementi o esservene
anche altri, ma di norma questi sono i pi utilizzati.
Come buona pratica in genere si tende a contrasse-
gnare nel codice HTML questi elementi con un ID
corrispondente piuttosto che usare una classe CSS,
questo perch si tratta comunque di elementi che
non si ripetono (unici) e usare un selector di tipo #ID,
nel foglio di stile, ci aiuta a rintracciare subito gli ele-
menti. Basiamoci su una struttura come questa:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-
transitional.dtd">
<html><head>[...]</head>
<body>
<div id="container"><div id="header">[...]</div>
<div id="main"><div id="menu">[...]</div>
<div id="content">[...]</div>
</div>
<div id="footer">[...]</div>
</div>
</body>
</html>
vediamo come impostare il layout. Cominciamo col
Fig. 4: Lo stesso layout, ma creato con i CSS
063-067:032-035 1-04-2008 16:54 Pagina 66
ht t p: / / www. i opr ogr ammo. i t
M
ioProgrammo Web Progettare una pagina web
preparare un foglio di stile dove definiremo:
G il container fisso al centro con larghezza di 780
pixel
G il menu a sinistra di 180px
G il footer fisso a fondo pagina
Per prima cosa definiamo quindi le regole per gli ele-
menti di insieme HTML e BODY:
html,body {
margin:0;
padding:0;
height:100%; /* necessario per calcolare
min-height di container*/
background-color: #CCC;
font-family:Arial, Helvetica, sans-serif;
font-size:small;}
da notare come abbiamo impostato height al 100%
ci consentir il rendering corretto della propriet
min-height nel container. Quindi passiamo ad
impostare le regole per il DIV contenitore che abbia-
mo contrassegnato con l'ID "container":
DIV#container {position:relative; /* necessario per il
posizionamento del footer*/
margin: 0 auto;width:780px;
background-color: #FFF;
height:auto !important;
height:100%; /* IE6: lo interpreta come
min-height*/
min-height:100%;}
qui importante sottolineare che :
G abbiamo centrato l'elemento attribuendogli una
width di 780px e un margindestro settato ad auto
(il margine destro ad auto centra orizzontalmente
l'elemento).
G abbiamo dapprima definito height come auto
(contrassegnandolo con !important per evitare
ogni possibile ridefinizione) in modo da consenti-
re al DIV di ereditare il 100% di height degli ele-
menti padri.
G per evitare problemi con IE6 abbiamo poi ridefi-
nito height al 100% (gli altri browser avevano gi
ricevuto questa impostazione da auto).
G abbiamo impostato anche min-height al 100%
Definiamo poi l'header e il blocco main (che contie-
ne a sua volta menu e content):
DIV#header {border-bottom: 1px solid #999;
background-color: #FFF;}
DIV#main {position: relative;
padding-left: 200px;
padding-right: 10px; }
da notare padding-left di main a 200px che crea un
margine interno per ospitare il menu posizionato in
modo assoluto. Passiamo quindi al menu che viene
appunto definito come assoluto e allineato in alto a
sinistra di larghezza 180px:
DIV#menu {position: absolute;
top: 0; left: 0; width: 180px;}
Impostiamo anche alcune regole per il content e per
i paragrafi in esso contenuti:
div#content {padding:2px 2px 40px 2px; /* bottom
padding per footer */}
div#content p {margin: 0;
text-align:justify;
padding:10px;}
da notare qui il margine inferiore per il content in
modo da evitare che vi si sovrapponga il footer che
viene posizionato in modo assoluto. Ed infine pas-
siamo al footer che viene ancorato in fondo al con-
tainer e posizionato in modo assoluto:
DIV#footer {border-top: 1px solid #999;
background-color: #FFF;
text-align: center;
color:#999;
font-weight: bold;
position:absolute;
width:100%;
bottom:0; /* attaccato al bottom */}
CONCLUSIONI
In questo terzo appuntamento abbiamo cominciato
a vedere l'applicazione delle regole CSS che ci con-
sentono di superare il layout ottenuto con <TABLE>,
partendo dalla definizione della struttura della
pagina. Nel prossimo appuntamento vedremo, altri
due elementi molto utilizzati nel web : i menu, le
colonne e i box.
Francesco Smelzo
Fig. 5: Elementi strutturali della pagina web
Maggio 2008/
67
G
063-067:032-035 1-04-2008 16:54 Pagina 67
ht t p: / / www. i opr ogr ammo. i t
SISTEMA M
G
72
/Maggio 2008
Usare Crystal Report
M
icrosoft fornisce, allinterno di Visual Studio.NET,
un tool di grande qualit per la reportistica. Si trat-
ta di Crystal Reports che, come viene illustrato nel-
larticolo, perfettamente integrato in Visual Basic.NET, con-
sentendo di gestire con facilit le stampe allinterno delle ap-
plicazioni gestionali che sviluppate.
Una degli aspetti pi interessanti di Visual Basic.NET
, infatti, la possibilit di costruire report con sempli-
cit, utilizzando uno strumento che dalla versione 6.0
fa parte dellambiente di sviluppo. Il Crystal Reports
un prodotto di facile utilizzo che consente di creare
report personalizzati, elenchi e prospetti di stampa di
vario tipo utilizzando le informazioni contenute al-
linterno di un database. Il funzionamento si basa sul-
la creazione di connessioni con uno o pi database e
sullutilizzo di questi link per ricavare valori dai cam-
pi dei database selezionati, che possono poi essere in-
seriti nei report.
Lobiettivo principale di questo articolo quello di il-
lustrare lutilizzo di Crystal Reports in ambiente Vi-
sual Basic. Esistono, infatti, degli appositi ActiveX che
consentono di attivare da unapplicazione VB uno o
pi report.
DESTINATARI
DEL REPORT
I report sono strumenti di supporto alle decisioni e
destinati a chiunque debba gestire qualcosa. Il loro
principale obiettivo consiste nel permettere agli uten-
ti di apprendere rapidamente gli elementi e le rela-
zioni fondamentali esistenti tra i dati, in modo che sia
possibile prendere decisioni appropriate. La validit del
report dipende dalla presentazione logica di dati cor-
retti, proprio perch un report che contiene informa-
zioni presentate in maniera non chiara o addirittura er-
rate non solo pu rallentare il processo decisionale,
ma pu condurre a conclusioni sbagliate. Se, ad esem-
pio, il direttore commerciale di unazienda desume,
da uno o pi report errati, che il volume delle vendite
ha un trend crescente pu ritenere necessaria una po-
litica dinvestimenti e di costi ben differente se avesse
ricevuto dati veritieri sullattuale realt aziendale.
Prima di creare un report consigliabile identificar-
ne brevemente per iscritto gli obiettivi, in maniera ta-
le da poter realizzare uno strumento che persegua
proprio quanto definito in fase di analisi. In questa fa-
se sar necessario spendere un po di tempo con chi ci
ha commissionato il lavoro per evitare di prendere
cantonate. Ad esempio lobiettivo del report pu essere:
1. La visualizzazione delle vendite mensili ed an-
nuali per agente di vendita, paragonare le cifre del-
lanno corrente con quelle dellanno precedente e con-
trassegnare gli agenti con valori delle vendite che
non corrispondono agli standard societari.
2. La visualizzazione delle attivit di vendita per ogni
voce dellinventario e la definizione del punto di
riordino delle quantit in base a tale attivit.
3. Il calcolo e la successiva visualizzazione delle am-
monizioni e delle espulsioni per ogni squadra che par-
tecipa al campionato di calcio di serie A e B.
Dopo la definizione dellobiettivo importante capi-
re chi sono gli effettivi destinatari del nostro lavoro.
Un singolo report viene solitamente utilizzato da pi
persone. Tornando al caso delle vendite, un report det-
tagliato sulle vendite potrebbe essere utile agli agen-
ti di vendita, ai responsabili di area e magari anche al
direttore generale, anche se ognuno potrebbe essere
interessato ad aspetti diversi.
KICK OFF
DEL PROGETTO
La prima operazione che dovete effettuare durante la
fase di creazione di un report quella di attivare VB.NET,
per poi fare clic sul menu File-New-Project, selezio-
nare Windows Application nella sezione Templates,
digitare il nome dellapplicazione in Name e, poi, fate
clic sul pulsante OK. Successivamente, facendo clic
destro nella finestra Solution Explorer sul nome del
progetto, scegliere Add, poi New Iteme nella finestra
Add New Itemscegliete Crystal Reports. A questo pun-
to compare automaticamente il wizard Crystal Reports
Gallery dove si possono scegliere le seguenti opzioni:
G Using the Report Wizard, per creare un report in ma-
CREARE REPORT CON
VISUAL BASIC.NET
GRAFICI E REPORTISTICA RAPPRESENTANO UNA PARTE IMPORTANTE DI OGNI APPLICAZIONE.
VISUAL STUDIO OFFRE STRUMENTI AVANZATI PER LA CREAZIONE DI REPORT PROFESSIONALI.
IN QUESTO ARTICOLO SPIEGHEREMO PASSO DOPO PASSO COME USARLI
Conoscenze richieste
Visual Studio e VB.NET
Software
Windows XP Service
Pack 2, Windows
Server 2003 o
Windows Vista e
Visual Studio 2005
versione Standard o
Professional
Impegno

Tempo di realizzazione
REQUISITI
072-078:072-080 1-04-2008 16:35 Pagina 72
ht t p: / / www. i opr ogr ammo. i t
M SISTEMA
Maggio 2008/
73
G
Usare Crystal Report
niera guidata ed ex-novo.
G As a Blank Report, per generare un report vuoto,
senza alcun campo, n connessioni a database.
G From an Existing Report, per effettuare una copia
di un report gi creato in precedenza.
In questa esemplificazione utilizzerete la prima op-
zione. Il Report Wizard permette di procedere in ma-
niera guidata partendo dalla conessione al database.
Nella sezione Data selezionate Create New Connec-
tion e fare clic su OLE DB (ADO) per connettervi im-
mediatamente ad un database server come Microsoft
SQL Server o Oracle, scegliendo, poi, nella finestra di
dialogo che appare Microsoft OLE DB Provider for SQL
Server. Quindi indicate il nome del computer su cui
risiede il database, se la macchina corrente basta di-
gitare localhost, utente e password ed infine il nome
della fonte dati, ossia del database. A questo punto
lorigine dei dati disponibile ed necessario indica-
re gli oggetti da inserire nel report, che possono esse-
re tabelle, viste o stored procedure.
La successiva sezione Link rappresenta graficamen-
te i collegamenti tra gli oggetti selezionati in base alle
varie chiavi primarie e straniere presenti sulle tabelle.
Qui necessario eliminare i link sbagliati o che non
sono necessari per la costruzione del report finale.
Inoltre anche possibile verificare quali indici sono
presenti grazie alla legenda attivabile con il pulsante
Index Legend.
Nella successiva sezione Fields dovete indicare i cam-
pi che includerete nel report, che solitamente sono
solo una parte di quelli presenti nelle tabelle selezio-
nate.
In seguito nella sezione Grouping dovete individuare
le cosiddette Group By per raggruppare i dati secon-
do determinati campi. Facendo clic sul pulsante Next
si passa alla sezione Summaries, dove vengono indi-
viduati i campi di riepilogo e cio quelli che vengono
sommati in base ai criteri di raggruppamento. Nella
sezione Group Sortingi gruppi sono ordinati in base ai
totali di riepilogo.
Avete, poi, la possibilit dinserire un grafico che pu
essere a barre verticali, a linee orizzontali o a torta.
Nella successiva schermata, Record Selection, potete fil-
trare le informazioni, selezionando un sottoinsieme
dei campi presenti nel database, grazie alla combo
box posta a sinistra in basso; l si pu, ad esempio, spe-
cificare che devono essere visualizzati solo i computer
con scadenza inferiore o uguale al 31 dicembre 2008
(data digitata sulla seconda combo box, che appare
in seguito). Infine la sezione conclusiva Report Style per-
mette di scegliere il modello da utilizzare per visua-
lizzare il report tra dieci differenti alternative. A destra
il wizard Crystal Reports visualizza ogni volta lanteprima
di ci che state scegliendo.
OGGETTI
DEL CRYSTAL REPORTS
La finestra di progettazione di ciascun report, de-
nominata per default CrystalReport1.rpt, simile
ad una form di Visual Basic, ed include una fine-
stra di progettazione nella quale viene creato il
layout del report. Essa, inoltre, composta dagli
oggetti riportati di seguito.
Section. Ciascuna sezione della finestra di progetta-
Figura 1: Aggiungete nel progetto il componente Crystal
Reports
Figura 2: Il wizard consente di selezionare il database
di riferimento.
Figura 3: Le relazioni tra le tabelle utili al vostro report
possono essere modificate.
NOTA
UNA VERA
E PROPRIA
JOINT
VENTURE
Crystal Reports un
prodotto con
copyright Crystal
Decisions ed dal
1992 che diventato
lo strumento per la
creazione di report
pi utilizzato su
sistemi operativi
Microsoft Windows.
Questa
collaborazione tra
Microsoft e Crystal
Decisions
continuata fino ai
nostri giorni, anche
dopo lacquisizione
da parte di Business
Objects di Crystal
Decisions.
072-078:072-080 1-04-2008 16:35 Pagina 73
ht t p: / / www. i opr ogr ammo. i t
SISTEMA M
G
74
/Maggio 2008
Usare Crystal Report
zione Crystal Reports rappresentata da un oggetto
Section. In fase di progettazione, ogni sezione rap-
presentata da unintestazione, su cui potete fare clic
per selezionare la sezione, e da un riquadro in cui
possibile inserire e posizionare controlli. Tramite que-
sto oggetto e le relative propriet possibile riconfi-
gurare un report in modo dinamico prima delleffet-
tiva creazione.
Controlli di Crystal Reports. Si tratta di controlli speciali
che funzionano soltanto nella finestra di progettazio-
ne Crystal Reports. In questultima finestra non pos-
sibile utilizzare i controlli intrinseci di Visual Basic o
anche controlli ActiveX. I controlli specifici di Crystal
Reports sono inclusi nella casella degli strumenti di
Visual Basic nella scheda Crystal Reports. In partico-
lare quando in un progetto si aggiunge una finestra di
progettazione di un report, nella nuova scheda Cry-
stal Reports della casella degli strumenti vengono ag-
giunti automaticamente i seguenti controlli:
G Text Object, che consente di formattare testo.
G Line Object. Consente di disegnare righe nel report
per contraddistinguere in modo pi chiaro le varie
sezioni.
G Box Object. Consente di inserire nel report rettan-
goli, cerchi e ovali.
I DATI DA INCLUDERE
Lintestazione non deve venire trascurata, in quanto con-
tiene le informazioni necessarie allidentificazione del
report stesso. In particolare dovreste sempre include-
re i seguenti elementi: nome dellente responsabile
del report, titolo ed eventualmente anche gli obietti-
vi del report.
Il numero di pagina, invece, dovrebbe sempre fare
parte del pi di pagina come anche il termine confi-
denziale se necessario e la data e lora del report.
I tipi di dati che si possono includere in un report pro-
dotto con Crystal Reports sono i seguenti:
1. Provenienti da campi di un oggetto (tabella, vista,
ecc) di un database e sono quelli pi diffusi.
2. Calcolati ricavandoli in parte da campi di databa-
se.
3. Digitati direttamente dallautore in caselle di te-
sto (intestazioni, etichette, note e cos via).
Un altro concetto da tenere presente il raggruppamento
delle informazioni. Non una novit, in quanto pre-
sente nel linguaggio SQL ed un modo molto poten-
te che potete utilizzare per creare dei gruppi di record
in base al cliente, alla data o a qualsiasi altro criterio.
A rottura del gruppo potrete inserire dati calcolati, ti-
picamente percentuali, totali parziali/generali o me-
die.
LE SEZIONI
DI CIASCUN REPORT
Osservando un report possibile distinguere almeno
sette sezioni che potete utilizzare in fase di progetta-
zione. Si tratta di aree di default che sono destinate a
contenere i dati e le intestazioni del report. Tutte le
aree possono contenere controlli personalizzati pre-
levati dalla toolbox e, quindi, descrizioni statiche, da-
ti estratti dai database collegati e immagini grafiche.
Report Header. E una sezione che pu contenere il ti-
tolo del report e magari unimmagine grafica che ren-
de pi piacevole il prospetto di stampa.
Page Header. Contiene le intestazioni che vengono ri-
petute ogni volta che avviene un salto pagina.
Group Header Section1. Qui si deve indicare il campo
(o i campi) che fa parte della tabella master.
Details. Nella sezione corrente vengono specificati i
campi che sono presenti nella tabella detail. Ad esem-
pio si possono considerare le due tabelle Publishers e
Titles, che sono relazionate tra loro tramite il campo Pu-
bID. Infatti le tabelle sono legate con una relazione
uno a molti. Ci significa che per ogni record della ta-
bella master Publishers sono presenti uno o pi re-
cord sulla tabella detail Titles.
Group Footer Section1. Qui vengono specificati even-
tuali campi che devono essere riportati alla fine della
visualizzazione degli elementi di ciascun gruppo.
Report Footer. il cosiddetto pi di pagina del report,
ossia lultima sezione del report che viene visualizza-
ta sullultima pagina dello stesso. In questa area pos-
sono venire riportati i totali generali del report. Se, ad
esempio, le tabelle master e detail fossero rispettiva-
mente banche e conti correnti, evidente che in que-
sta sezione sarebbe possibile indicare la formula che
effettua la sommatoria degli importi dei saldi relativi
a tutte le banche considerate.
Page Footer. Si tratta dellarea del report che viene
ripetuta nella parte inferiore di ogni pagina. Soli-
tamente qui si indica la data e il progressivo della
pagina corrente.
NOTA
REPORT NON
CORRELATI
Crystal Reports
consente anche di
stampare due o pi
report non correlati
tra loro, luno di
seguito allaltro. Per
ottenere ci
necessario creare il
report che sintende
stampare per primo
ed inserirlo nella
sezione Details.
Successivamente
importare un report
gi esistente o creare
un subreport e
posizionarlo nella
sezione Report
Footer. Gli altri,
eventuali subreport,
dovranno essere
inseriti in ulteriori
Report Footer creati
con il Section Expert
(tasto destro del
mouse, opzione di
menu Insert Section).
Figura 4: La finestra di progettazione di Crystal Reports.
072-078:072-080 1-04-2008 16:35 Pagina 74
ht t p: / / www. i opr ogr ammo. i t
M SISTEMA
Maggio 2008/
75
G
Usare Crystal Report
UN REPORT DI SINTESI
Nellesempio presentato con questo articolo viene in-
cluso il database Access che contiene i dati caricati dal
report. Prodotti.mdb composto da 5 tabelle: 1.Or-
dineProdotto, che la traduzione della relazione con
molteplicit N x M che mette in collegamento le entit
ordine e prodotto. Lunico campo non chiave la quan-
tit di prodotto venduta per ogni ordine. 2.Ordine, che
contiene tutti gli attributi propri (come data dellor-
dine e data di consegna) e le chiavi straniere (foreign
keys) che la collegano alle tabelle Cliente e Venditore.
3.Prodotto, che contiene la descrizione del prodotto
e il costo unitario. 4.Cliente, che contiene attributi co-
me nome di riferimento, fax, indirizzo, ed altri anco-
ra. 5.Venditore, che la tabella relativa alla forza ven-
dita.
Lobiettivo del report che si vuole creare quello di
mettere a confronto le vendite effettuate da ciascun
agente di vendita, evidenziando una serie di campi di
dettaglio tra cui i prodotti venduti, le quantit vendu-
te, il prezzo unitario e quello totale (prezzo per quan-
tit). Inoltre si vogliono evidenziare anche i seguenti cam-
pi calcolati: fatturato totale realizzato da ciascun agen-
te di vendita e totale fatturato realizzato da tutta la for-
za vendita.
I destinatari possono essere i responsabili di area, il
direttore commerciale e qualsiasi manager che si oc-
cupa della politica delle vendite aziendale, ma anche
della gestione del personale.
Prima di tutto si deve creare un nuovo progetto di ti-
po Windows Application ed inserire sulla form il con-
trollo CrystalReportViewer. Bisogna, poi, ricordarsi
dimpostare a Fill la propriet Dock per ancorare il
controllo a tutti i lati della form corrente e, successi-
vamente, in ReportSource necessario specificare per-
corso e nome del report da visualizzare.
Qualora vogliate utilizzare lo stesso CrystalReport-
Viewer per pi report dovrete impostare la propriet
ReportSource dinamicamente da menu o tramite un
pulsante di comando. Il codice che segue serve pro-
prio a fare lo switch tra 2 report:
Private Sub Cambia_Click(...) Handles Cambia.Click
Static flgCR As Boolean = False
flgCR = Not flgCR
If Not flgCR Then
CrystalReportViewer1.DisplayGroupTree = True
Me.Text = "Comparazione delle vendite per
agente"
CrystalReportViewer1.ReportSource =
myCrystalReport1
Else
CrystalReportViewer1.DisplayGroupTree = False
Me.Text = "Ordini evasi per ogni cliente"
CrystalReportViewer1.ReportSource = CRcliente
End If
End Sub
Al fine di evitare errori, si ricorda anche che deve essere
anche incluso il codice che segue (nellapplicazione
desempio presente nella sezione generata automa-
ticamente da Progettazione Windows Form):
Friend WithEvents myCrystalReport1 As
WindowsApplication2.CrystalReport1
Figura 5: Le sezioni di un report a design time consento-
no di definire la logica di elaborazione: intestazioni, rag-
gruppamenti, dati calcolati e non, ecc.
Figura 6: I vincoli relazionali presenti nel database
Microsoft Access Prodotti.mdb.
Figura 7: Loggetto CrystalReportViewer, una volta inseri-
to nel progetto, si fonde con la form corrente.
072-078:072-080 1-04-2008 16:35 Pagina 75
ht t p: / / www. i opr ogr ammo. i t
Friend WithEvents CRcliente As
WindowsApplication2.CRcliente
Me.myCrystalReport1 = New
WindowsApplication2.CrystalReport1
Me.CRcliente = New WindowsApplication2.CRcliente
Aggiungere un componente Crystal Report come spie-
gato in precedenza e procedete allutilizzo del wizard
individuando passo dopo passo tutte le opzioni che
interessano. In particolare si deve scegliere un report
standard e identificare il database Prodotti.mdb co-
me quello di riferimento dopo avere fatto clic su File di
database. In questo modo si rendono disponibili tut-
ti gli oggetti del file Access allapplicazione.
IL WIZARD EXPERT
Nella sezione Links sono ora disponibili i collega-
menti che evidenziano le tabelle master e di detta-
glio ed in generale i vincoli dintegrit referenziale im-
postati sul database. Se volete aggiungere o rimuo-
vere collegamenti questa la sede giusta per farlo.
In effetti in questo caso il Report Wizard potrebbe
aver definito un link tra il campo Region della ta-
bella Venditore e il campo Regiondella tabella Clien-
te che non interessando bene rimuovere. Aggiun-
gete, poi, manualmente un link tra il campo SalesI-
NI della tabella Venditore e il campo SalesINI della
tabella Ordine, necessario per collegare la forza ven-
dita alle altre tabelle del database.
Successivamente individuate i seguenti campi da vi-
sualizzare: Venditore.Lastname, Venditore.Region,
Ordine.Shipping Date, Cliente.Contact Name,
Cliente.City, Cliente.Contract Date, Prodotto.Product
Description, Prodotto.Unit Price e OrdineProdot-
to.Quantity. Seguendo il wizard potrete impostare rag-
gruppamenti, ad esempio in questo report nella se-
zione Group By scegliete Venditore.Lastname per
raggruppare le righe in base al cognome degli agen-
ti di vendita.
La sezione successiva consente di definire il grafico
da visualizzare nel report. Fate clic sullopzione Bar
Chart.
Nella sezione Details aggiungete un campo calcolato
ottenuto dalla moltiplicazione di Prodotto.Unit Price
per OrdineProdotto.Quantity, al fine di identificare il fat-
turato totale di ogni prodotto di una certa categoria
agente per agente. Per inserire campi calcolati fate clic
su Formula Fields nel Field Explorer, scegliete Newe do-
po avere inserito il nome Prezzo x QTA viene visua-
lizzata la finestra di dialogo Formula Editor. Qui ne-
cessario scegliere Prodotto.Unit Pricepoi tra gli operatori
aritmetici Multiplyed infine OrdineProdotto.Quantity.
Dopo avere salvato le modifiche il nuovo campo pu
essere inserito tra i campi da visualizzare nel report.
In seguito facendo clic destro sul grafico e scegliendo
Chart Expert potete personalizzare il grafico creato
con il wizard. In Type scegliete Horizontal mentre in
Dataimpostate Once per report nel campo Place Chart
e a destra lopzione Header. In On change of scegliete
Venditore.Lastnamee in Showimpostate Sum of @Prez-
zo x QTA. In questo modo il grafico in grado di vi-
sualizzare un confronto tra il fatturato realizzato da
ogni agente. Nella sezione Text digitate, Venditore nel
campo Group titlee Guadagno realizzatonel campo Da-
ta title.
Nella sezione Group Footer dovete fare clic con il pul-
sante destro del mouse e selezionare Insert-Summa-
ry. Nella finestra di dialogo che appare operate come
segue: nella prima casella selezionate Prezzo x QTA,
nella seconda Sume, poi, scegliete OK. In questo mo-
do il campo Prezzo x QTA verr sommato per dare il
fatturato totale dellagente di vendita. Fate la stessa
cosa nella sezione Report Footer per calcolare il fat-
turato globale della forza vendita.
A questo punto potete eseguire il report (ricordarsi
della propriet ReportSource) e visualizzare le infor-
mazioni selezionate e presenti nel database Prodot-
ti.mdb.
Probabilmente sar opportuno procedere ad alcune ri-
finiture, come dimensionare manualmente alcuni
campi che risultano troppo piccoli, o posizionarli me-
glio, inserire le intestazioni e i pi di pagina, ed altro an-
cora.
SISTEMA M
G
76
/Maggio 2008
Usare Crystal Report
Figura 8: I dati vengono raggruppati in base al campo
Lastname della tabella Venditore.
Figura 9: Creazione di un campo calcolato con lo stru-
mento Formula Editor.
SUL WEB
possibile reperire
utili informazioni,
consigli e
suggerimenti su
Crystal Reports
visitando i seguenti
siti:
www.developers.net
(esempi da scaricare
nella sezione Crystal
Reports in basso a
sinistra)
www.businessobjects.co
m/products/reporting/cr
ystalreports
www.crystalreports.com
www.codeguru.com
(cercare Crystal
Reports)
msdn.microsoft.com/libr
ary (sezione
Development Tools
and Languages)
msdn2.microsoft.com/e
n-us/vbasic
072-078:072-080 1-04-2008 16:35 Pagina 76
ht t p: / / www. i opr ogr ammo. i t
IL CONTRIBUTO DI OLE
Per rendere pi significativo il report possibile inse-
rire oggetti elaborati allinterno di altre applicazioni, qua-
li Microsoft Access o Microsoft Excel. In particolare la
tecnologia OLE consente di ottenere molto sempli-
cemente questo risultato.
La prima versione di Object Linking and Embedding
(OLE1) nata da una collaborazione tra Microsoft, Al-
dus, Lotus, WordPerfect ed altri produttori di softwa-
re, con lobiettivo di rendere disponibile un meccani-
smo standard per consentire la gestione di Documenti
Composti (Compound Documents) in ambiente Win-
dows; le prime realizzazioni di OLE1 sono apparse gi
agli inizi del 1991. Lidea base di questa tecnologia era
quella di consentire ad unapplicazione (applicazio-
ne Client) dincludere un oggetto generato da unal-
tra applicazione (applicazione Server) tramite un par-
ticolare riferimento alloggetto da gestire (Object
Linking) o incorporando loggetto nel formato richie-
sto dallapplicazione Server allinterno del documen-
to gestito dallapplicazione Client (Object Embed-
ding).
In questo modo , per esempio possibile, incorpora-
re (Embedding) in un prospetto di stampa di Crystal
Reports un foglio elettronico di Excel o connettersi
(Linking) ad unapplicazione Server, ad esempio rea-
lizzata con Access. Nel primo caso loggetto incorpo-
rato, essendo solo una copia delloriginale, non in-
fluenzato dalle modifiche che, dopo loperazione di
embedding, vengono effettuate nellapplicazione Ser-
ver, mentre nel secondo caso le modifiche apportate
allinterno del Server saranno comunque riflesse an-
che allinterno del Client. Con la successiva introdu-
zione di OLE versione 2 (OLE2) si raffinata la capa-
cit di gestire oggetti composti e si sono poste le pre-
messe per consentire la realizzazione di un Windows
Object Oriented Environment. Nel caso dellesempio
stato incorporato un grafico Excel che, affiancato a
quello ottenuto con il Wizard di Crystal Reports, d
una visione anche delle commissioni che ciascun for-
nitore ottiene sui prodotti venduti. Se in sede di stam-
pa non si pu assolutamente percepire la differenza tra
i due grafici, tuttavia dovrebbe essere chiaro che il se-
condo frutto dellelaborazione effettuata allinterno
di unapplicazione esterna a Crystal Reports, appun-
to Excel. Procedendo in questo modo ovviamente
possibile rendere sempre pi chiari i dati contenuti
nel report. Ovviamente un oggetto pu essere inseri-
to in Crystal Reports in due modi, ovvero incorpo-
randolo o collegandolo. In entrambi casi si crea un
documento composto secondo OLE. Se si utilizza
lincorporamento, nel report viene memorizzata una
copia delloggetto originale. Gli oggetti incorporati
non hanno alcun collegamento con i relativi oggetti
di origine e pertanto esistono solo nel documento con-
tenitore. Se sincorpora lo stesso oggetto in report di-
versi, loggetto in ogni report non ha alcuna relazio-
ne con gli altri oggetti. Le modifiche apportate ad un
oggetto incorporato non verranno applicate agli altri
oggetti. Le modifiche apportate ad un oggetto nel-
lapplicazione di origine non vengono applicate al-
loggetto nellapplicazione contenitore. Sar quindi
necessario aggiornare manualmente loggetto nel-
lapplicazione contenitore. Ricordate che tutte le vol-
te che ricorrete a OLE appesantite notevolmente il re-
port, perch un oggetto incorporato parte integran-
te del report e pertanto aumenta in modo considere-
M SISTEMA
Maggio 2008/
77
G
Usare Crystal Report
Figura 10: Il report a run time evidenzia il grafico a barre
e i dati cos come selezionati durante la fase di disegno.
Figura 11: Relazione tra oggetti client collegati, incorpo-
rati e server OLE.
NOTA
VERIFICARE
IL DATABASE
Eseguendo
lapplicazione
allinterno
dellambiente di
sviluppo pu
accadere che il report
non venga
visualizzato a causa
di una richiesta di
login. Per evitare ci
dovete effettuare la
verifica del database
su tutti i report,
facendo clic destro
sul report stesso e
scegliendo Database-
Verify database.
Nella finestra che
appare fate clic sul
piccolo pulsante
corrispondente al
campo Database
Name, selezionate il
database di
riferimento, fate clic
su Open ed, infine, su
Finish. Al termine
dovr comparire il
messaggio The
database is up to
date.
Figura 12: Il secondo grafico presente nel report un
oggetto OLE.
072-078:072-080 1-04-2008 16:35 Pagina 77
ht t p: / / www. i opr ogr ammo. i t
vole le dimensioni del filedi riferimento. Al contrario,
se si utilizza il collegamento, nel report viene memo-
rizzata unimmagine delloggetto con le informazioni
di riferimento, mentre loggetto vero e proprio rima-
ne memorizzato nel documento server.
I SUBREPORT
Un subreport un report inserito allinterno di un re-
port principale e per crearlo bisogna procedere come
nel caso di un normale report. Un subreport si differenzia
dal report principale in quanto inserito al suo inter-
no come oggetto e non esiste da solo; pu essere po-
sizionato in qualsiasi sezione del report e, allinterno
di tale sezione, viene stampato per intero; non pu
contenere a sua volta un subreport. Tipicamente un
subreport viene creato per combinare report non cor-
relati in un unico prospetto di stampa oppure per pre-
sentare diverse visualizzazioni degli stessi dati in un
unico report. Per inserire un subreport basta visualiz-
zare la form che ospita il report e fare clic destro con il
mouse scegliendo, poi, lopzione di menu Insert-Sub-
report. Dopo aver posizionato il subreport nella se-
zione opportuna del report principale, necessario
decidere se scegliere un report gi esistente oppure se
crearne uno nuovo con il Report Wizard.
I subreport possono essere collegati oppure no al re-
port principale. Quelli non collegati sono autonomi: i
dati non sono collegati ai dati del report primario in al-
cun modo. Tra laltro subreport di questo tipo posso-
no anche utilizzare origini di dati completamente di-
verse da quelle del report principale. Al contrario i su-
breport collegati son esattamente lopposto, in quan-
to ic dati sono coordinati tra loro e il programma fa
corrispondere i record del subreport a quelli del re-
port principale. Per esemplificare se si crea un report
principale con informazioni sui clienti e un subreport
con informazioni sugli ordini e li si collega, il pro-
gramma crea un subreport per ciascun cliente e in-
clude anche tutti gli ordini ad essi relativi. Nellesem-
pio che vi presentiamo stato creato un report prin-
cipale che contiene nome e dati relativi a ciascun ven-
ditore, per ciascuno dei quali, grazie ad un subreport,
vengono specificati i dati di vendita. Al fine di colle-
gare report principale e subreport dovete specificare
un campo in entrambi i report in maniera tale che
contengano dati comuni. Crystal Reports utilizza tali
campi per coordinare i dati e permette di definirli se-
lezionando Change Subreport Links nel menu che
compare facendo clic destro sul subreport stesso. A
questo punto necessario evidenziare il campo che
si desidera utilizzare come campo di collegamento
nel report principale che lo contiene; fate, poi, clic sul
pulsante con la freccia rivolta verso destra. Il campo verr
aggiunto alla casella di riepilogo Field(s) to link to e
selezionato come campo di collegamento. Successi-
vamente dovete fare la stessa cosa per il subreport in-
dividuando lo stesso campo scelto per il report prin-
cipale in Subreport parameter field to use e i dati da vi-
sualizzare nel subreport Select data in subreport based
on field. Queste operazioni devono essere eseguite per
ciascun collegamento aggiuntivo che si vuole creare.
Al temine scegliete OK.
UNOCCHIATA
AL REPORTVIEWER
Ai pi attenti utilizzatori di Visual Basic.NET non pu
essere sfuggito il controllo ReportViewer. Si tratta di
un ulteriore strumento che Microsoft fornisce agli svi-
luppatori VB per creare report che, tuttavia, non fa
parte del voluminoso pacchetto di Crystal Reports.
Per utilizzare il ReportViewer dovete creare, al solito,
un progetto di tipo Windows Application, inserire il
controllo di riferimento ed, infine, creare una fonte di
dati, aggiungendo un nuovo DataSet. Ricordatevi, poi,
di definire la query SQL che costituir il riferimento
sorgente per il report finale. Linterfaccia del ReportViewer
costituita da pi sezioni ed ha una struttura simile a
quella delle prime versioni di Crystal Reports.
Sebbene si tratti di uno strumento abbastanza flessi-
bile ed utile a creare report collegati a database, il mag-
giore punto debole la mancanza di un wizard per la
creazione veloce del prospetto di stampa e la conseguente
necessit di realizzare il report passo dopo passo in
maniera del tutto manuale.
Enrico Bottari
SISTEMA M
G
78
/Maggio 2008
Usare Crystal Report
Figura 13: Creazione di un report che contiene un subre-
port.
Figura 14: Il controllo ReportViewer fornisce uno stru-
mento alternativo a Crystal Reports.
LAUTORE
Enrico Bottari lavora
da 18 anni nel
mondo ICT. Ha avuto
esperienze
significative nel
campo dello sviluppo
software su
piattaforme
Microsoft,
dellamministrazione
di database Oracle e
della gestione di
sistemi UNIX Solaris
System V.
Attualmente
responsabile delle
attivit operazionali
(LAN, Office
Automation e servizi
Desktop) presso la
sede italiana di
unimportante
organizzazione
internazionale.
072-078:072-080 1-04-2008 16:35 Pagina 78
ht t p: / / www. i opr ogr ammo. i t
MULTIMEDIA M
G
80
/Maggio 2008
Player MP3 in una pagina Web con Flash
P
er prima cosa apriamo il nostro software
Flash 8, creiamo un nuovo documento e
impostiamo le sue dimensioni a 300 x 200
pixel (le dimensioni possono essere modificate a
piacimento). A questo punto iniziamo a creare i
livelli di cui abbiamo bisogno rinominandoli come
in figura
Questo importante in quanto sar pi facile
individuare e capire su quale parte stiamo lavo-
rando. Selezioniamo il primo fotogramma del
livello Sfondo e disegniamo un rettangolo che
sar lo sfondo del nostro lettore (volendo possia-
mo anche utilizzare unimmagine dopo averla
importata nella libreria), ovviamente il rettango-
lo (o limmagine) avr la stessa grandezza del
nostro documento.
Ora nel primo fotogramma del livello Azioni
andremo a scrivere il nostro codice stop(); per
bloccare la riproduzione del filmato flash su quel
fotogramma, clicchiamo quindi col tasto destro
del mouse sul primo fotogramma del suddetto
livello e selezioniamo la voce Azioni e nel pan-
nello che si aprir scriveremo il seguente codice:
stop();
REALIZZAZIONE
DEI PULSANTI
A questo punto iniziamo ad occuparci dellaspet-
to grafico del nostro lettore, che potremmo
modificare come pi ci aggrada. Posizioniamoci
sul livello player e cominciamo col creare i pul-
santi di cui abbiamo bisogno. Se non vogliamo
perdere troppo tempo a disegnarne di nostri o
non si molto ferrati con la grafica, possiamo
utilizzare i pulsanti gi pronti che si trovano in
libreria; quindi dal menu Finestra andiamo col
cursore sulla voce Librerie comuni e selezionia-
mo la voce pulsanti:
Ora scegliamo i pulsanti pi adatti allo stile che
DOTARE UNA PAGINA
WEB DI UN MP3 PLAYER
IN QUESTO ARTICOLO DESCRIVEREMO COME REALIZZARE UN LETTORE MP3 PER I NOSTRI SITI
WEB. UTILIZZEREMO LA TECNOLOGIA MESSA A DISPOSIZIONE DA MACROMEDIA FLASH E INTE-
GREREMO IL TUTTO CON UNA STRUTTURA XML DI SUPPORTO.
Conoscenze richieste
Principi di XML e
utilizzo base di Flash
Software
Macromedia Flash
Impegno
Tempo di realizzazione
REQUISITI
Fig.1: In figura possiamo vedere come sono strutturati
i livelli.
Fig.3: Accesso alla libreria dei pulsanti.
Fig.2: Lo sfondo utilizzato per il nostro player.
080-089:072-080 2-04-2008 12:04 Pagina 80
ht t p: / / www. i opr ogr ammo. i t
M
MULTIMEDIA
Maggio 2008/
81
G
Player MP3 in una pagina Web con Flash
abbiamo pensato per il nostro lettore guardando
tra le librerie denominate Playback. Dopo aver
scelto i nostri pulsanti e trascinati sullo stage
dovremo trovarci nella seguente situazione:
Dopo aver posizionato i pulsanti, selezioniamoli
uno ad uno tenendo premuto il tasto SHIFT dalla
tastiera, in modo da selezionarli tutti, e poi clic-
chiamo su un solo pulsante col tasto destro e
selezioniamo la voce converti in simbolo, conver-
tiremo cosi in clip filmato il gruppo di pulsanti e
gli daremo come nome player
Ora diamo al gruppo di pulsanti appena creato,
come nome distanza, comandi e poi saremo
pronti per il passo successivo.
A questo punto clicchiamo due volte sul clip fil-
mato comandi e ci ritroveremo nella seguente
situazione:
CREAZIONE DEL
CONTROLLO VOLUME
Prima di procedere alla realizzazione del coman-
do volume bene creare tutti i livelli di cui avre-
mo bisogno, quindi per prima cosa rinominiamo
il livello 1, che quello che contiene i nostri pul-
santi, e chiamiamolo pulsanti, poi assegniamo
i rispettivi nomi distanza: al pulsante play dare-
mo come nome distanza playbtn, a stop dare-
mo stopbtn, a next daremo nextbtn ed infine
a back daremo backbtn. Adesso possiamo crea-
re i livelli di cui abbiamo bisogno per realizzare
gli altri comandi del lettore. Disponiamo e rino-
miniamo i livelli come in figura:
Come possiamo notare dalla figura precedente
abbiamo il livello volume_mascherato a cui
stata applicata una maschera. Per ora limitiamo-
ci a dare ai livelli gli stessi nomi di quelli in figu-
ra e procedendo dal basso verso lalto, realizzia-
mo il contenuto dei nostri livelli. Quindi selezio-
niamo il primo fotogramma di livello_sound e
nello stage andremo a posizionare un movie clip
vuoto che sar il nostro livello dappoggio in cui
verr creata, grazie al codice che dopo vedremo,
listanza per il caricamento della canzone che
verr riprodotta dal nostro lettore. Per realizzare
un clip filmato vuoto premiamo ctrl+F8, oppu-
re dal menu Inserisci selezioniamo la voce
Nuovo Simbolo , e chiamiamolo livel-
lo_appoggio clicchiamo su ok e ci ritroveremo
allinterno del movie clip appena creato.
Rinominiamo il livello 1 del suddetto clip filma-
NOTA
UN PLAYER
MP3 PRONTO
ALLUSO
Se non si vuole creare il
player ex-novo per
mancanza di voglia o
tempo, esistono in Rete
molti player gratuiti
pronti alluso. Uno su
tutti XSPF Web Music
Player, scaricabile
allindirizzo
http://musicplayer.source
forge.net/ .
Il player altamente
personalizzabile grazie
ai numerosi parametri
di configurazione, ed
in grado di gestire le
playlist.
Fig.4: Linsieme dei pulsanti di controllo
Fig.7: Ora siamo allinterno del clip filmato
comandi
Fig.8: Disposizione dei livelli e rispettivi nomi.
Fig.5: Il menu che consente di convertire in clip filmato.
Fig.6: Il campo in cui indicare il nome distanza del
clip filmato player.
080-089:072-080 2-04-2008 12:18 Pagina 81
ht t p: / / www. i opr ogr ammo. i t
MULTIMEDIA
M
G
82
/Maggio 2008
Player MP3 in una pagina Web con Flash
to, e chiamiamolo sound_temp, possiamo
anche chiamarlo diversamente in quanto il
nome del livello serve semplicemente come
descrizione del suo contenuto o delle sue funzio-
ni. A questo punto torniamo indietro al livello
player e, dopo aver selezionato il primo foto-
gramma di livello_sound trasciniamo dalla
libreria il clip filmato appena creato, ossia livel-
lo_appoggio. Posizioniamolo dove ci pare,
anche fuori dal nostro stage, in quanto come ho
gi specificato solo un livello dappoggio per la
canzone in riproduzione, e infine assegniamogli
come nome distanza appoggio. Passiamo ora
alla parte delicata del nostro progetto: creare una
barra per il volume utilizzando le maschere.
Selezioniamo il primo fotogramma del livello
guida_volume e creiamo un nuovo clip filmato,
premendo ctrl+F8, in cui andremo a disegnare
e posizionare come in figura la nostra linea guida
per lo scorrimento della barra di volume:
Assicuriamoci di aver posizionato la nostra guida
volume a destra del crocino dorigine come
abbiamo visto in figura; questa azione ci torner
utile in seguito per la realizzazione del codice per
il controllo della barra del volume. Torniamo
indietro al livello player e trasciniamo sullo
stage il clip filmato contenente la nostra guida
volume. Infine, assicurandoci di aver selezionato
il primo fotogramma del livello guida_volume,
selezioniamo il clip filmato della nostra guida e
diamogli come nome distanza guida_vol. Ora
passiamo alla realizzazione della nostra barra di
volume che, dovr avere la stessa forma e dimen-
sione della nostra guida volume, quindi posizio-
niamoci sul primo fotogramma del livello vol-
ume_mascherato e ancora una volta premiamo
ctrl+F8 per realizzare il nostro clip filmato, che
chiameremo volume_masch. Disegniamo la
nostra barra di volume e posizioniamola come in
figura facendo sempre attenzione al crocino
dorigine, perch questa volta esso si dovr trova-
re a destra della barra di volume, mentre prima,
per la guida, si trovava a sinistra.
Ora prima di tornare indietro al livello player
avremo bisogno di realizzare il pulsante che ci
permetter di trascinare la barra di volume appe-
na creata. Selezioniamo quindi la nostra barra di
volume e cliccando col tasto destro la trasforme-
remo in un clip filmato (cos da avere due clip fil-
mato annidati un nellaltro) che chiameremo
volum:
Dopo aver convertito la nostra barra di volume,
aggiungiamo un livello alla linea temporale e
chiamiamolo pulsante, questo conterr il pul-
sante che ci permetter di trascinare la barra
Per realizzare ora il nostro pulsante premiamo
ancora ctrl+F8, ma stavolta, invece della spun-
ta sulla voce clip filmato la metteremo sulla voce
pulsante, diamo il nome di volume_btn e clic-
chiamo su ok. A questo punto ci ritroveremo
davanti ad una situazione come in figura seguen-
te:
Guardando la linea temporale noteremo le voci:
- Su
- Sopra
- Gi
- Premuto
Queste voci corrispondo agli stati di un pulsante
e quindi a come il pulsante dovr comportarsi ad
ogni evento. Per ora lasciamo stare tutti gli stati e
concentriamoci su quello di cui abbiamo biso-
Fig.9: Ecco la nostra linea guida su cui scorrer la
barra di volume.
Fig.10: La barra di volume si trova a sinistra del cro-
cino dorigine rispetto alla guida volume che si trova-
va a destra del crocino.
Fig.11: Convertiamo la barra di volume appena realiz-
zata in clip filmato.
Fig.12: I livelli allinterno del clip filmato
volume_masch
Fig.13: Allinterno del pulsante appena realizzato.
080-089:072-080 1-04-2008 18:38 Pagina 82
ht t p: / / www. i opr ogr ammo. i t
M
MULTIMEDIA
Maggio 2008/
83
G
Player MP3 in una pagina Web con Flash
gno e cio un pulsante invisibile che ci per-
metter di trascinare la barra del volume.
Posizioniamoci sul fotogramma corrisponden-
te alla voce Premuto e clicchiamo col tasto
destro selezionando dal menu a tendina la voce
inserisci fotogramma chiave. In questo foto-
gramma andremo a disegnare e posizionare
come in figura 13 il nostro pulsante che sar
semplicemente un quadrato di colore nero (o
qualsiasi altro colore). Se tutto andato a buon
fine la situazione sar la seguente:
Ora torniamo indietro al livello vol-
ume_mascherato e trasciniamo dalla libreria
allo stage il pulsante appena creato nel primo
fotogramma del livello pulsante, gli daremo
come nome distanza volume_btn ed andre-
mo a posizionarlo sulla nostra barra volume e
pi precisamente sullestremit destra della
nostra barra.
Torniamo ora ancora pi indietro al nostro
livello player per andare a realizzare lultima
parte del nostro controllo volume, ovvero la
maschera. Posizioniamoci sul primo fotogram-
ma del livello maschera e premiamo
ctrl+F8. Questa volta andremo a realizzare un
oggetto di tipo grafico, quindi spuntiamo
appunto la voce Grafico, diamo come nome
maschera e clicchiamo su ok. Ora disegnere-
mo la nostra maschera che avr la grandezza e
la forma dellarea che vogliamo sia visibile. Per
il nostro caso la maschera avr la stessa forma
della barra del volume e della guida, ma ho
deciso di farla un po pi grande per assicurar-
mi la visibilit della barra. Stavolta non dobbia-
mo preoccuparci del crocino di origine in
quanto questa solo una maschera che posi-
zioneremo noi manualmente sullarea da ren-
dere visibile. Dopo aver disegnato la nostra
maschera, torniamo indietro al livello player
e nel primo fotogramma del livello vol-
ume_mascherato andiamo a trascinare dalla
libreria il nostro clip filmato, contenente la
barra di volume e il pulsante, che abbiamo
chiamato volume_ma
scherato, gli daremo come nome distanza
volum e lo sovrapporremo precisamente alla
nostra barra della guida. Passiamo poi al primo
fotogramma del livello maschera e trascinia-
mo dalla libreria allo stage il nostro oggetto
grafico maschera, sovrapponendolo alla barra
del volume facendo combaciare precisamente
lestremit sinistra e il lato superiore della
maschera con la barra. Clicchiamo quindi con
il tasto destro sul nome del livello maschera
nella barra temporale e selezioniamo la voce
maschera cos da rendere una maschera il
nostro oggetto grafico e un oggetto mascherato
la nostra barra di volume.
Prima di proseguire con la realizzazione del
nostro lettore, possiamo assicurarci che il con-
trollo volume appena creato funzioni nel modo
corretto dal punto di vista grafico; andiamo
quindi a cliccare col tasto destro sul primo
fotogramma del livello azioni ed aggiungia-
mo questo codice che servir per il controllo
del volume:
volum.volume_btn.onPress = function() {
sinistra = guida_vol._x;
sopra = guida_vol._y;
destra =
guida_vol._x+guida_vol._width;
Fig.14: La struttura del pulsante appena realizzato.
Fig.15: Barra e pulsante invisibile
Fig.16: Il menu che permette di creare un livello
maschera
080-089:072-080 1-04-2008 18:38 Pagina 83
ht t p: / / www. i opr ogr ammo. i t
sotto = guida_vol._y;
volum.startDrag(false, sinistra,
sopra, destra, sotto);
};
volum.volume_btn.onRelease = function() {
volum.stopDrag();
};
volum.volume_btn.onReleaseOutside =
function() {
volum.stopDrag();
};
dopo aver aggiunto il codice premiamo
ctrl+Invio e facciamo partire il filmato. Se
abbiamo fatto tutto come si deve, andando a
cliccare e trascinando dallestremit destra la
barra del volume, la vedremo accorciarsi
verso sinistra. In realt la barra non si accorcia
realmente ma trasla soltanto verso sinistra.
Leffetto labbiamo dato grazie alla maschera
creata che nasconde la parte di barra che supe-
ra la grandezza della maschera stessa. Andiamo
ora ad analizzare il codice per traslare la barra;
abbiamo richiamato il pulsante volume_btn
allinterno di volum, che il nome distanza
che abbiamo assegnato alla nostra barra, ed
essendo un pulsante gli abbiamo assegnato il
gestore onPress(). Quindi abbiamo che al clic-
care del pulsante volum_btn si da il via ad una
serie di processi contenuti nella funzione asse-
gnata a quellazione sul pulsante; in questo
caso si da il via alla funzione start Drag(), che
rende trascinabile il clip filmato a cui stata
assegnata durante la riproduzione. possibile
trascinare solo un clip filmato alla volta. Dopo
l'esecuzione di un'operazione startDrag(), il
clip filmato rimane trascinabile finch non
viene esplicitamente arrestato da stop Drag()
oppure finch non viene chiamata un'azione
startDrag() per un altro clip filmato. I parametri
per la suddetta funzione saranno per noi un
Valore booleano che specifica che il clip filma-
to trascinabile bloccato al centro della posi-
zione del mouse (se assegniamo true) oppure
bloccato nel punto in cui l'utente aveva fatto
clic sul clip filmato la prima volta (se assegnia-
mo false), come abbiamo fatto nel nostro caso.
Gli altri parametri che abbiamo indicato deli-
mitano lo spazio entro il quale il clip filmato
pu muoversi. Il valore di guida_vol._x vale per
il lato sinistro, guida_vol._y per il lato superiore
e quello inferiore ed infine guida_vol._width
per il lato destro. Continuando ad analizzare il
codice troviamo altri due gestori sempre asse-
gnati al pulsante, ovvero, onRelease(); e
onReleaseOutside(); questi due gestori servono
rispettivamente a controllare il rilascio del pul-
sante. Il primo controlla il rilascio entro larea
del pulsante stesso, mentre il secondo viene
richiamato quando il pulsante viene rilasciato
mentre il puntatore si trova fuori dallarea del
pulsante stesso. Ad ognuno dei due gestori
assegnata la funzione stop Drag(); che termina
il trascinamento del clip filmato. Detto ci,
prima di passare allimplementazione del codi-
ce in actionscript avremo bisogno di creare un
file xml che sar la nostra playlist e lo salvere-
mo nella stessa cartella del nostro player dove
creeremo inoltre una directory che chiamere-
mo canzoni che ospiter tutti i nostri file mp3.
IL FILE XML, OVVERO
LA NOSTRA PLAYLIST
Apriamo il blocco note e scriviamo il seguente
codice per creare il nostro file xml:
<?xml version="1.0"?>
<ARCHIVE>
<SONG title="Titolo"
file="url/../canzoni/song1.mp3"
artist="Artista"></SONG>
<SONG title="Titolo"
file="url/../canzoni/song2.mp3"
artist="Artista"></SONG>
</ARCHIVE>
Ovviamente dovremmo aggiungere una riga di
codice per ogni canzone che vogliamo ascolta-
re col nostro player. Ora salviamo il nostro file
chiamandolo listaCanzoni.xml e chiudiamo
il blocco note per tornare cos a lavorare al
nostro file in flash.
TESTI DINAMICI PER
VISUALIZZARE LE
INFORMAZIONI
Tornati ora alla nostra area di lavoro, clicchiamo
su Scena 1 nella linea temporale per tornare
alla scena principale, quindi dopo aver selezio-
MULTIMEDIA
M
G
84
/Maggio 2008
Player MP3 in una pagina Web con Flash
Fig.17: Ecco i nuovi livelli.
NOTA
PROGRAMMARE
CON XML.
I PORTATILI
Dedicato sia a utenti
principianti che non,
questo libro insegna
come utilizzare il
linguaggio XML ormai
sempre pi diffuso e in
continua evoluzione.
Partendo dalle basi
dell'XML, il testo
approfondisce
argomenti come la
validazione tramite
XSD, con qualche
accenno a DTD, all'XSD,
all'XSLT, all'XSL-FO e a
XPath, oltre a
sviluppare applicazioni
concrete di XML con
Visual Basic 6.0, il .NET
Framework, SQLXML e
JSP.
Autore: Paolo Pialorsi
Prezzo: 8.56 euro
Editore: Mondadori
Informatica
080-089:072-080 1-04-2008 18:38 Pagina 84
ht t p: / / www. i opr ogr ammo. i t
nato il primo fotogramma del livello player
andremo a creare delle caselle di testo dinamiche
che visualizzeranno informazioni sulla canzone
in esecuzione. Prendiamo lo strumento di testo e
dal pannello propriet apriamo il menu a tendi-
na e selezioniamo la voce testo dinamico sce-
gliamo come colore del testo quello che voglia-
mo, clicchiamo poi sulla casella per il bordo
intorno al testo e andiamo a disegnare tre caselle
di testo come in figura:
Dopo aver disegnato le tre caselle di testo, asse-
gniamo ad ognuna un nome nella casella var;
la prima la chiameremo errore e questa ci
segnaler leventuale mancanza del file xml, la
seconda la chiameremo contatore questa inve-
ce conterr informazioni riguardo il tempo di
esecuzione, e lultima la chiameremo titolo
conterr il nome dellartista e il titolo del brano
in esecuzione. Ora facciamo doppio click sul clip
filmato contenente i pulsanti per rientrare nel
livello player dove andremo ad aggiungere altri
due livelli sopra al livello Azioni, questi altri due
livelli andranno a contenere il codice per il con-
trollo dei pulsanti e per le impostazioni iniziali
del lettore, quindi li chiameremo rispettivamen-
te Azioni pulsanti e Impostazioni come in
figura:
IMPLEMENTAZIONE
DEL CODICE
Iniziamo dal livello impostazioni, quindi clic-
chiamo col tasto destro sul primo fotogramma
e selezioniamo la voce Azioni per aprire il
nostro pannello dove inseriremo il seguente
codice:
traccia = 1; // settiamo il valore di traccia ad uno per
segnalare la prima traccia del file xml
autoplay = false; // inizializziamo a false una
variabile autoplay
newSong = false; /*newSong viene settata a true
durante la riproduzione fino a che non si raggiunge la
fine della playlist*/
musicaOn = true;//musicaOn viene settata a true
allinizio ma se autoplay false musicaOn=false
songList = new Array();
Lista = "listaCanzoni.xml";
playList = new XML();
playList.ignoreWhite = true;
playList.onLoad = function(success) {
if (!success) {
_root.errore = "Playlist non
trovata";
return;
}
nodi = playList.firstChild.childNodes;
for (var k = 0; k<nodi.length; ++k) {
songList[k] =
nodi[k].attributes.file;
}
if (autoplay) {
appoggio.music = new Sound();/*creiamo un nuovo
oggetto sound di nome music, nel clip filmato
appoggio*/
appoggio.music.loadSound(songList[traccia-1],
true);/*carichiamo la nostra traccia dallarray
songList e con true segnaliamo che laudio in
streaming*/
appoggio.music.onSoundComplete
= function() {
traccia = traccia+1;
if
(traccia>songList.length) {
traccia = 1;
}
newSong = true;
};
} else {
musicaOn = false;
}
}
Questa la prima parte di codice. Oltre ad alcu-
ne variabili per il controllo automatico della
riproduzione come autoplay, in questa parte di
codice carichiamo il file xml, che sar la nostra
playlist, e creiamo larray per contenerne i
nodi. Dichiariamo quindi un nuovo array col
nome songList e gli assegniamo listruzione
new Array(); per la creazione di uno spazio di
memoria per larray che poi andremo a riempi-
re con i valori dal file xml. Carichiamo il file
listaCanzoni.xml in una variabile che abbiamo
chiamato Lista in questo modo: Lista = lista
Canzoni.xml ovviamente il file deve trovarsi
nella stessa cartella del nostro lettore. Se
vogliamo che il file della lista risieda in un altro
posto dovremo specificarne il percorso tra le
Maggio 2008/
85
G
Player MP3 in una pagina Web con Flash M
MULTIMEDIA
Fig.18: La struttura dei nuovi livelli.
080-089:072-080 1-04-2008 18:38 Pagina 85
ht t p: / / www. i opr ogr ammo. i t
virgolette oltre al nome del file. Dopo ci creia-
mo un nuovo oggetto XML prima di chiamare i
metodi della classe, in questo modo playList =
new XML(); cos abbiamo creato il nostro
oggetto che avr il nome di playList ed a questo
andremo ad assegnare eventuali metodi della
classe; del suddetto oggetto. Allinizio richia-
miamo il metodo ignoreWhite e lo impostiamo
come true in modo da eliminare eventuali nodi
di testo contenenti solo spazi vuoti, poi richia-
miamo il gestore onLoad(); il cui parametro
success risulta true se il file viene caricato cor-
rettamente. Viceversa risulter false se il file
non venisse caricato; nel secondo caso abbia-
mo fatto si che lutente venga avvertito con un
messaggio che apparir nella casella di testo
dinamico che abbiamo creato precedentemen-
te per questo scopo. Assegniamo ora ad una
variabile nodi il valore delloggetto XML playlist
con i seguenti metodi: firstChild, che fa riferi-
mento al primo elemento secondario nell'elen-
co degli elementi secondari del nodo principa-
le, questa propriet null se il nodo non ha ele-
menti secondari ed undefined se il nodo un
nodo di testo. Assegniamo anche il metodo
childNodes, che un array degli elementi
secondari dell'oggetto XML specificato, e ogni
elemento dell'array un riferimento a un
oggetto XML che rappresenta un nodo secon-
dario. Cos facendo abbiamo accesso agli ele-
menti del file xml, quindi a questo punto utiliz-
zeremo un ciclo for() per scorrere un ad uno gli
elementi dellarray songList[]; ed assegneremo
al k-esimo elemento del nostro array il valore
nodi[k].attributes.file;attributes, esso si riferi-
sce ad un oggetto che contiene tutti gli attribu-
ti dell'istanza XML specificata, in questo caso
nodi[k].attributes, dove k il nostro indice che
incrementa ogni volta di k+1, contiene una
variabile per ciascun attributo dell'istanza
XML.
Dal momento che queste variabili vengono
definite come parte dell'oggetto, a esse si fa
generalmente riferimento come propriet del-
l'oggetto. Il valore di ogni attributo viene
memorizzato nella propriet corrispondente
sotto forma di stringa, quindi per prelevare il
valore di un attributo presente in nodi[k] biso-
gna richiamare il nome dellattributo come
propriet in questo modo: oggettoXML.
firstChild.attributes.propriet. Dopo aver crea-
to larray da cui preleveremo le tracce musicali
passiamo alla creazione di un nuovo oggetto
Sound di nome music allinterno del nostro clip
filmato appoggio e carichiamo la traccia dal-
larray songList con il gestore loadSound che
permette di caricare un file mp3 e richiede un
valore booleano per verificare se laudio in
streaming o interno al filmato. In questo caso il
parametro assegnato sar true, in quanto i
nostri file vengono caricati in streaming. Per
passare alla traccia successiva utilizziamo il
gestore onSoundComplete chiamato automati-
camente quando termina la riproduzione di un
suono. Passiamo quindi alla traccia successiva
se il valore di traccia minore della lunghezza
dellarray, altrimenti il valore viene resettato ad
1 e la riproduzione parte di nuovo dalla prima
traccia.
Finite le nostre impostazioni iniziali passiamo
al codice per le azioni dei pulsanti, quindi clic-
chiamo col tasto destro sul primo fotogramma
del livello Azioni pulsanti e selezioniamo
ancora una volta la voce azioni per aprire il
nostro panello in cui scriveremo il seguente
codice:
volum.onEnterFrame = function() {
vol_uno = volum._x-guida_vol._x;
vol_due = guida_vol._width/100;
vol =
Math.round(vol_uno/vol_due);
appoggio.music.setVolume(vol);
};
volum.volume_btn.onPress = function() {
sinistra = guida_vol._x;
sopra = guida_vol._y;
destra =
guida_vol._x+guida_vol._width;
sotto = guida_vol._y;
volum.startDrag(false, sinistra,
sopra, destra, sotto);
};
volum.volume_btn.onRelease = function() {
volum.stopDrag();
};
volum.volume_btn.onReleaseOutside =
function() {
volum.stopDrag();
};
nextbtn.onRelease = function() {
traccia = traccia+1;
if (traccia>songList.length) {
traccia = 1;
}
if (musicaOn) {
newSong = true;
}
};
nextbtn.onReleaseOutside = function() {
traccia = traccia+1;
if (traccia>songList.length) {
traccia = 1;
}
if (musicaOn) {
newSong = true;
MULTIMEDIA
M
G
86
/Maggio 2008
Player MP3 in una pagina Web con Flash
080-089:072-080 1-04-2008 18:38 Pagina 86
ht t p: / / www. i opr ogr ammo. i t
}
};
backbtn.onRelease = function() {
traccia = traccia-1;
if (traccia<1) {
traccia = songList.length;
}
if (musicaOn) {
newSong = true;
}
};
backbtn.onReleaseOutside = function() {
traccia = traccia-1;
if (traccia<1) {
traccia = songList.length;
}
if (musicaOn) {
newSong = true;
}
};
playbtn.onRelease = function() {
if (!musicaOn) {
appoggio.music = new Sound();
appoggio.music.loadSound(songList[traccia-1], true);
appoggio.music.onSoundComplete
= function() {
traccia = traccia+1;
if
(traccia>songList.length) {
traccia = 1;
}
newSong = true;
};
musicaOn = true;
}
};
playbtn.onReleaseOutside = function() {
if (!musicaOn) {
appoggio.music = new Sound();
appoggio.music.loadSound(songList[traccia-1], true);
appoggio.music.onSoundComplete
= function() {
traccia = traccia+1;
if
(traccia>songList.length) {
traccia = 1;
}
newSong = true;
};
musicaOn = true;
}
};
stopbtn.onRelease = function() {
if (musicaOn) {
appoggio.music.stop();
musicaOn = false;
}
};
stopbtn.onReleaseOutside = function() {
if (musicaOn) {
appoggio.music.stop();
musicaOn = false;
}
};
questa parte di codice la pi semplice in
quanto controlla le azioni sui pulsanti con due
semplici gestori, onRelease e onReleaseOutside.
Come abbiamo gi visto per il volume questi
due gestori si occupano del punto in cui viene
rilasciato il click del mouse per poi eseguire le
azioni associate ai rispettivi pulsanti.
Per quanto riguarda invece la parte di codice
dedicata al controllo del volume, noteremo
delle righe di codice che, quando abbiamo
provato il funzionamento della barra volume,
non abbiamo utilizzato perch questa parte si
occupa del volume vero e proprio utilizzando il
metodo setVolume e richiede come parametri
un valore da 0 a 100 che ricaviamo dal rappor-
to tra la differenza tra la posizione sullasse x
della barra di volume, e la posizione sullasse x
della guida, e il rapporto tra la larghezza del
pulsante espressa in pixel e il valore massimo
di volume 100.
Visto che il risultato di questa operazione non
sar un numero intero, prima di passarlo come
parametro al metodo setVolume utilizziamo la
funzione math con il metodo round che arro-
tonda il valore del parametro vol al numero
intero pi vicino per eccesso o per difetto e
restituisce il valore. Se il parametro vol equi-
distante dai due numeri interi pi vicini (ovve-
ro termina con ,5), il valore viene arrotondato
al numero intero pi alto. A questo punto se
abbiamo scritto anche questo codice ci avvia-
mo alla fine della nostra realizzazione. Infatti
non rimane che aggiungere il codice per cari-
care e visualizzare le informazioni sui file che
verranno riprodotti. Clicchiamo col tasto
destro sul primo fotogramma del livello
Azioni e come sempre apriamo il pannello
per il codice selezionando la voce Azioni, quin-
di cancelliamo il codice che prima abbiamo
provato per il volume e scriviamo il seguente:
playList.load(Lista);
appoggio.onEnterFrame = function() {
const_uno = 1000;
const_due = 60;
minuti_pos =
posizione/const_uno/const_due;
secondi_pos = posizione/const_uno;
minuti_dur = durata/const_uno/const_due;
M
MULTIMEDIA
Maggio 2008/
87
G
Player MP3 in una pagina Web con Flash
080-089:072-080 1-04-2008 18:38 Pagina 87
ht t p: / / www. i opr ogr ammo. i t
secondi_dur = durata/const_uno;
if (musicaOn) {
posizione =
Math.round(appoggio.music.position);
durata =
Math.round(appoggio.music.duration);
minuti_trascorsi =
Math.floor(minuti_pos);
secondi_trascorsi =
Math.round(secondi_pos)-
minuti_trascorsi*const_due;
minuti_tot =
Math.floor(minuti_dur);
secondi_tot =
Math.round(secondi_dur)-minuti_tot*const_due;
if (posizione != 0 && durata != 0)
{
if
(secondi_trascorsi>59) {
minuti_trascorsi = minuti_trascorsi+1;
}
if (secondi_tot>59) {
minuti_tot =
minuti_tot+1;
}
if (secondi_tot>59) {
secondi_tot =
0;
}
if
(secondi_trascorsi>59) {
secondi_trascorsi = 0;
}
if (secondi_tot<10) {
secondi_tot =
"0"+secondi_tot;
}
if
(secondi_trascorsi<10) {
secondi_trascorsi = "0"+secondi_trascorsi;
}
if (minuti_trascorsi<10)
{
minuti_trascorsi = "0"+minuti_trascorsi;
}
if (minuti_tot<10) {
minuti_tot =
"0"+minuti_tot;
}
_root.contatore =
"Trascorsi:
"+minuti_trascorsi+":"+secondi_trascorsi+" - Durata:
"+minuti_tot+":"+secondi_tot;
}
} else if (!musicaOn) {
_root.contatore = "Trascorsi:
00:00 - Durata: 00:00";
}
if (newSong) {
appoggio.music = new Sound();
appoggio.music.loadSound(songList[traccia-1], true);
appoggio.music.onSoundComplete
= function() {
traccia = traccia+1;
if
(traccia>songList.length) {
traccia = 1;
}
newSong = true;
};
newSong = false;
}
_root.titolo = "Artista:
"+playList.firstChild.childNodes[traccia-
1].attributes.artist+" Titolo:
"+playList.firstChild.childNodes[traccia-
1].attributes.title;
};
in questultima parte di codice ci occupiamo
della visualizzazione delle informazioni riguar-
do al file in esecuzione. Guardando il codice
possiamo notare come anche qui sia stata uti-
lizzata la funzione math con il metodo round,
ma inoltre vediamo anche lutilizzo di un altro
metodo, ossia, il metodo floor. Questo metodo
restituisce il primo intero inferiore o uguale al
numero o all'espressione specificata; nel
nostro caso restituir il valore dei minuti tra-
scorsi e quello dei minuti totali del file in ese-
cuzione.
Continuando a spulciare il codice, oltre a tutti i
controlli per le varie visualizzazioni che dovre-
mo avere, arriveremo alle ultime righe nelle
quali viene assegnato alla variabile titolo il
valore dellattributo contenente il nome del-
lartista e il titolo della canzone in esecuzione.
Qui vediamo un esempio pratico di quello che
abbiamo gi detto durante la spiegazione della
prima parte di codice, ossia la sintassi per pre-
levare il valore degli attributi allinterno del file
xml.
CONCLUSIONI
Ora potrete divertirvi ad abbellire come vole-
te il vostro bel lettore mp3 pronto e funziona-
le per dilettare i visitatori dei nostri websites e
blog personali. In futuro vedremo come rea-
lizzare un player video per la riproduzione dei
filmati .flv.
Giovanni Fiore
MULTIMEDIA
M
G
88
/Maggio 2008
Player MP3 in una pagina Web con Flash
SUL WEB
Per approfondire la
conoscenza di Flash:
http://www.actionscript.it
http://flash.html.it
http://www.v2online.it
http://www.flashzone.com
http://www.flashcomguru.
com/
http://www.kloonigames.
com/
FORMATI AUDIO
Per conoscere i pi
diffusi formati audio e
confrontarne la qualit:
http://tinyurl.com/2a8nc8
http://tinyurl.com/337qvp
http://tinyurl.com/2e2hq2
http://tinyurl.com/2fgvfg
080-089:072-080 1-04-2008 18:38 Pagina 88
ht t p: / / www. i opr ogr ammo. i t
GRAFICA M
G
90
/Maggio 2008
Realizzare un cattura schermo
N
el redigere una relazione, un manuale,
unofferta o qualsivoglia documento
quasi sempre richiesto laggiunta di una
qualche immagine del prodotto trattato, dellin-
terfaccia o di un dettaglio della medesima per
meglio chiarire il senso di quello che si vuole
comunicare. La situazione nella quale ci trovia-
mo spesso quella in cui non disponiamo di una
versione su file dellimmagine pronta alluso ma
viceversa disponiamo di una versione creata a
run time sullo schermo da parte di qualche
applicazione o strumento.
Il metodo classico per catturare limmagine e al
quale ci si orienta pi frequentemente quello di
premere sulla tastiera il pulsante Print Screen
(stampa schermata) o Alt-Print Screen per cat-
turare solo la finestra attiva aprire Paint o qual-
siasi altro programma di grafica, incollare
limmagine e ritagliare la porzione che ci interes-
sa per poi salvarla nel formato che preferiamo.
Infine, completata loperazione, possiamo alle-
garla o incollarla al documento corrente.
Diversi sono i software commerciali che permet-
tono di automatizzare tale procedura e, vista
lutilit di un tale strumento, nellultima versione
del sistema operativo di casa Microsoft, Windows
Vista, stata giustamente aggiunta come utility.
Fino a poco tempo fa realizzare da zero una tale
tipologia di applicazione era un'operazione
alquanto elaborata e lunga e implicava chiamate
di API e notevoli sforzi di programmazione. In
realt, oggi, creare un programma che permetta di
catturare lo schermo o porzioni dello stesso in
modo semplice e veloce unoperazione abba-
stanza rapida se fatta con il supporto tecnologico
offerto dal .Net Framework. Per renderlo evidente,
nel prosieguo dellarticolo vedremo come realiz-
zare un programma fatto in C# che permetta di
catturare lo schermo o porzioni dello stesso per
poi salvarlo in un formato a scelta: BMP, JPEG,
TIFF o GIF. Per impreziosire il tutto vedremo
anche come visualizzare larea catturata in forma
di preview mediante una thumbnail con una serie
di informazioni aggiuntive che ne indichino le
dimensioni e leventuale spazio su disco occupato
se salvato in uno dei vari formati supportato.
DEFINIZIONE
DELLINTERFACCIA
La prima fase nello sviluppo della nostra piccola
applicazione consiste nella definizione dellinter-
faccia utente. Creiamo un nuovo progetto di tipo
Windows Application e rinominiamolo in
ScreenCapture. Decidiamo che la nostra interfac-
cia sar composta da quattro pulsanti, quattro
radio button e unarea dedicata allanteprima del-
limmagine catturata. Due pulsanti li utilizzere-
mo per la gestione della cattura dello schermo ed
in particolare il primo per la cattura dellintera
area di lavoro mentre il secondo per la cattura
delle singole porzioni. Gli altri due pulsanti servi-
ranno rispettivamente per salvare limmagine
catturata e per la chiusura dellapplicazione. I
quattro radio button li impiegheremo invece per
definire il formato con cui salvare limmagine
medesima. Per dettagliare meglio le caratteristi-
che dellimmagine mostrata nellanteprima
aggiungiamo una serie di label per rappresentare:
La profondit di colore dellimmagine
La larghezza
Laltezza
ANDIAMO A CACCIA
PER IL DESKTOP
CREIAMO, IN MODO SEMPLICE E VELOCE, UN PROGETTO C# IN GRADO DI CATTURARE
E SALVARE, NEL FORMATO CHE PREFERIAMO, SINGOLE PORZIONI O TUTTA LAREA
DI LAVORO DEL NOSTRO DESKTOP.
Fig.1: Risultato finale del nostro Cattura Schermo
personalizzato.
Conoscenze richieste
C#
Software
Windows XP/Vista,
Microsoft Visual Studio
2005
Impegno

Tempo di realizzazione
REQUISITI
090-095:066-071 2-04-2008 12:06 Pagina 90
ht t p: / / www. i opr ogr ammo. i t
M GRAFICA
Maggio 2008/
91
G
Realizzare un cattura schermo
Aggiungiamo ancora unetichetta per ogni singo-
lo formato individuato che permetta di visualiz-
zare loccupazione su disco nel caso venga salva-
ta con quel formato specifico. Come prima evi-
denziato i formati supportati sono: BMP, JPEG,
TIFF e GIF. Tuttavia con pochissime modifiche al
codice sar possibile aggiungere e gestire anche
gli altri formati non trattati come EXIF, PNG ecc.
Trasciniamo quindi sulla form tutti gli oggetti
necessari, introduciamo qualche dettaglio esteti-
co di personalizzazione e il risultato dovrebbe
essere simile a quello mostrato in figura 1. Creata
linterfaccia entriamo nel dettaglio della gestione
grafica del nostro personal screen capture.
CATTURA
DELLO SCHERMO
Per la cattura dello schermo e la gestione della
visualizzazione della thumbnail utilizzeremo
GDI+ (Graphics Device Interface), la nuova ver-
sione della libreria grafica di Windows, wrappata
dal Microsoft .Net Framework. E possibile sfrut-
tare le funzionalit grafiche di GDI+ mediante un
insieme di classi esposte presenti nel namespace
System.Drawing. Di tale namespace fanno parte
le classi:
System.Drawing.Drawing2D
System.Drawing.Imaging
System.Drawing.Text
System.Drawing.Printing
Il namespace System.Drawing consente di acce-
dere alle funzioni grafiche di base GDI+. Lo spa-
zio dei nomi System.Drawing.Graphics fornisce i
metodi per il disegno di varie forme, quali cerchi,
triangoli, archi, nonch metodi per la visualizza-
zione di testo, caratteri, font e cos via. Funzioni
pi avanzate vengono fornite invece negli spazi
dei nomi System.Drawing.Drawing2D, System.
Drawing.Imaging, System.Drawing.Text e System.
Drawing.Printing.
La classe Graphics fra i tanti metodi che espone
presenta anche il metodo CopyFromScreen che,
come dal nome stesso si evince, il metodo che
andremo ad utilizzare per i nostri scopi. Tale
metodo, a fronte di un oggetto di tipo Bitmap
definito con dimensioni pari allarea da copiare,
trasferisce limmagine dallarea del desktop ad
unarea di memoria specifica individuata dalla
Bitmap.
Tale metodo richiede come parametri:
Il punto dellangolo superiore sinistro del ret-
tangolo di origine
Il punto dellangolo superiore sinistro del ret-
tangolo di destinazione
Le dimensioni dellarea da trasferire
Quindi, al metodo, sufficiente passare le coor-
dinate del punto di partenza e le dimensioni di
unarea specifica da trasferire. Il secondo para-
metro, il punto iniziale dellarea di destinazione,
lo impostiamo al punto di coordinate (0,0).
Adesso che abbiamo visto quale metodo utilizza-
re volendo copiare tutto il contenuto del desktop
dobbiamo semplicemente fornire al metodo un
rettangolo le cui dimensioni siano pari a quelle
dello schermo oltre che definire una Bitmap di
dimensioni pari alla risoluzione impostata.
Possiamo ricavare le stesse tramite le propriet
Width e Height della classe Screen mediante il
metodo GetBounds(Point.Empty).
Laccortezza di cui vogliamo tener conto che
non desideriamo che linterfaccia della nostra
applicazione appaia in primo piano sullarea cat-
turata. Per fare ci minimizziamo linterfaccia
con listruzione this. WindowState =
FormWindowState.Minimized, diamo un attimo
di tempo al metodo redraw per il completamen-
to delloperazione (attivando una sleep di 200
millisecondi), copiamo larea e alla fine ripristi-
niamo linterfaccia rimettendo il WindowState a
Normal.
Per finire, avendo adesso loggetto Bitmap cari-
cato con limmagine catturata, possiamo rende-
re la medesima disponibile alla Clipboard, al fine
di poter effettuare il copia e incolla su qualsiasi
documento aperto, semplicemente scrivendo
listruzione Clipboard.SetImage((Image)bitmap).
//Viene catturato l'intero schermo dopo aver
minimizzato l'applicazione
private void btnCatturaSchermo_Click(object sender,
EventArgs e)
{
try
Fig.2: Risultato del click sul pulsante Cattura Schermo.
NOTA
LE BITMAP
Il termine bitmap
significa letteralmente
mappa di bit. La
qualit dell'immagine
di una bitmap dipende
strettamente da due
fattori: la risoluzione e
la profondit di colore.
La risoluzione indica il
numero di pixel che la
compongono, mentre
la profondit di colore
indica il numero di bit
utilizzati per
descrivere il colore di
ogni singolo punto. Il
numero di colori che
possibile assegnare ad
ogni pixel
determinato dal
numero di bit
destinati al singolo
pixel. Se ad esempio
ogni pixel
rappresentato da 4 bit,
sar possibile
assegnare a un dato
pixel uno dei 16 colori
diversi disponibili (2^4
= 16). La profondit di
colore pu variare da 1
fino a 64 bit.
Naturalmente con
profondit 1 possiamo
rappresentare solo
immagini in bianco e
nero.
090-095:066-071 1-04-2008 17:21 Pagina 91
ht t p: / / www. i opr ogr ammo. i t
GRAFICA M
G
92
/Maggio 2008
Realizzare un cattura schermo
{
this.WindowState =
FormWindowState.Minimized;
System.Threading.Thread.Sleep(200);
copyFromScreen(new Point(0, 0), new
Rectangle(0, 0, Screen.GetBounds
(Point.Empty).Width, Screen.GetBounds
(Point.Empty).Height));
this.WindowState = FormWindowState.Normal;
}
catch { }
}
//Viene catturata l'area disegnata
private void copyFromScreen(Point topPoint,
Rectangle capturedArea)
{
try
{
bitmap = new Bitmap(capturedArea.Width,
capturedArea.Height);
Graphics g = Graphics.FromImage(bitmap);
g.CopyFromScreen(topPoint, Point.Empty,
capturedArea.Size);
Clipboard.Clear();
Clipboard.SetImage((Image)bitmap);
getImageInformation();
g.Dispose();
}
catch { }
}
CATTURA
DI UNAREA SPECIFICA
Risolto il problema della cattura di tutta larea del
desktop vediamo come fare se il nostro interesse
si concentra solo su unarea specifica.
Premesso che al metodo CopyFromScreen dob-
biamo fornire il punto di partenza e le dimensio-
ni di unarea ben definita la questione si sposta
su come individuare tale regione. Dobbiamo tro-
vare una strategia per lavorare sul desktop.
Banalmente se noi espandiamo tutta larea della
form impostando il WindowState a Maximized
siamo gi in grado di poter gestire quasi tutto lo
schermo, ed esattamente cos che faremo. Per
completare lopera eliminiamo i bordi della
form, rendiamo invisibili tutti gli oggetti visualiz-
zati e per finire rendiamo trasparente la form
mediante limpostazione del valore di opacit ad
un numero abbastanza basso. Avviando adesso
lapplicazione quello che vedremmo a video il
desktop leggermente opaco. Se ora facciamo
diventare la form massimizzata unarea di dise-
gno per il tracciamento di rettangoli vari, tramite
lausilio del mouse facilmente possiamo indivi-
duare unarea specifica, evidenziarla e infine
copiarla in memoria.
//Viene modificato il layout dell'applicazione per poter
catturare un'area specifica
private void btnCatturaArea_Click(object sender,
EventArgs e)
Per il salvataggio di bitmap
con il .Net Framework sono
disponibili diversi formati:
BMP un formato standard
utilizzato da Windows per
la memorizzazione di
immagini indipendenti da
periferiche e da
applicazioni. Il numero di
bit per pixel viene
specificato nell'intestazione
del file. I file BMP non sono
compressi ed per questo
che occupano una gran
quantit di spazio su disco.
GIF (Graphics Interchange
Format) il formato che in
genere si usa per le
immagini visualizzate nelle
pagine Web. Tale formato
risulta ottimale per disegni
costituiti da linee, per
immagini con blocchi di
colore a tinta unita e
immagini con colori ben
definiti e distinti
diversamente si riscontra
una notevole perdita di
definizione. Il formato GIF
compresso e da anche la
possibilit di impostare un
colore della tavolozza come
trasparente. E altres
possibile gestire GIF
animate salvando sullo
stesso file pi immagini.
JPEG (Joint Photographic
Experts Group) uno
schema di compressione
particolarmente adatto per
le immagini fotografiche. Il
livello di compressione
delle immagini JPEG
configurabile, ma ad alti
livelli di compressione
corrisponde una maggiore
perdita di informazioni
mentre a bassi livelli tale
perdita quasi sempre
impercettibile per l'occhio
umano. I file JPEG non
supportano la trasparenza o
le animazioni.
EXIF (Exchangeable Image
File) un formato utilizzato
per immagini acquisite con
fotocamere digitali. In un
file EXIF contenuta
un'immagine compressa in
base alle specifiche JPEG
con laggiunta di una serie
di informazioni relative alla
fotografia (data in cui
stata scattata, velocit
dell'otturatore, esposizione
ecc.) e alla fotocamera
(produttore, modello ecc.).
PNG (Portable Network
Graphics) consente di
usufruire di molti dei
vantaggi offerti dal
formato GIF, ma fornisce
anche ulteriori funzionalit
rispetto a tale formato.
Analogamente ai file GIF, i
file PNG vengono compressi
senza alcuna perdita di
informazioni. Il formato
PNG rappresenta un
miglioramento della
capacit del formato GIF di
visualizzare
progressivamente
un'immagine. In altre
parole permette di
visualizzare
approssimazioni sempre
migliori di un'immagine
mentre viene trasmessa
attraverso una connessione
di rete.
TIFF (Tag Image File Format)
un formato di file
flessibile ed adattabile,
supportato da una vasta
gamma di piattaforme e di
applicazioni per
l'elaborazione di immagini.
possibile memorizzare nei
file TIFF immagini con un
numero arbitrario di bit per
pixel ed consentito
l'utilizzo di svariati
algoritmi di compressione.
FORMATO DEI FILE GRAFICI
090-095:066-071 1-04-2008 17:21 Pagina 92
ht t p: / / www. i opr ogr ammo. i t
M GRAFICA
Maggio 2008/
93
G
Realizzare un cattura schermo
{
try
{
this.SuspendLayout();
this.Cursor = Cursors.Cross;
this.FormBorderStyle = FormBorderStyle.None;
this.Opacity = 0.01;
this.WindowState =
FormWindowState.Maximized;
this.ResumeLayout(false);
graphArea = this.CreateGraphics();
isCaptureActive = true;
setVisibleFalse();
}
catch { }
}
Per rendere un p pi professionale il nostro
Screen Capture facciamo si che venga disegnato
un rettangolo sullarea che viene man mano evi-
denziata per la cattura. Modifichiamo anche il
layout del cursore per rendere loperazione di
disegno pi precisa e puntuale.
Per la gestione del tracciamento dellarea dob-
biamo far ricorso a vari eventi. In particolare
avremo necessit di gestire gli eventi:
ScreenCapture_MouseDown
ScreenCapture_Up
ScreenCapture_Move
Nellevento ScreenCapture_MouseDown intercet-
tiamo il punto del click del mouse, che servir
come riferimento iniziale per tracciare larea del
rettangolo da evidenziare. Per individuare le
coordinate (x,y) del punto cliccato sfruttiamo la
classe Control.MousePosition.
Nellevento ScreenCapture_Move teniamo invece
traccia delle coordinate correnti del mouse. Ad
ogni movimento del mouse ridisegniamo il ret-
tangolo cancellando il precedente non pi attua-
le. Otteniamo lo scopo colorando lo stesso con il
colore di sfondo adottato.
Infine nellevento ScreenCapture_Up catturiamo
concretamente la porzione di schermo in base
alle coordinate ultime tracciate e ripristiniamo
linterfaccia utente.
//Viene attivato il tracciamento dell'area da catturare
private void ScreenCapture_MouseDown(object
sender, MouseEventArgs e)
{
try
{
if (isCaptureActive)
{
this.Opacity = 0.25;
graphArea.Clear(Color.DimGray);
isMouseClicked = true;
startPoint = new Point(Control.Mouse
Position.X, Control.MousePosition.Y);
}
}
catch { }
}
//Al rilascio del mouse viene ripristinato il layout
originale
private void ScreenCapture_Up(object sender,
MouseEventArgs e)
{
try
{
if (isCaptureActive)
{
System.Threading.Thread.Sleep(200);
this.WindowState =
FormWindowState.Minimized;
copyFromScreen(new Point(topRect.X,
topRect.Y), new Rectangle(topRect.X, topRect.Y,
bottomRect.X - topRect.X, bottomRect.Y -
topRect.Y));
setVisibleTrue();
this.SuspendLayout();
this.WindowState =
FormWindowState.Normal;
this.FormBorderStyle =
FormBorderStyle.FixedDialog;
this.Cursor = Cursors.Default;
this.Opacity = 1;
this.ResumeLayout(true);
isCaptureActive = false;
isMouseClicked = false;
}
}
catch { }
}
//Viene tracciato passo passo il rettangolo da
catturare
private void ScreenCapture _Move(object sender,
MouseEventArgs e)
{
try
NOTA
LA CLIPBOARD
La "Clipboard" il
termine utilizzato per
descrivere lo spazio in
memoria destinato al
copia e incolla.
Quando si copia,
loggetto copiato
trasferito nella
Clipboard. Viceversa,
quando si incolla
loggetto copiato
dalla Clipboard nella
sua destinazione
finale.
Fig.3: Cattura di una porzione ben definita dello
schermo.
090-095:066-071 1-04-2008 17:21 Pagina 93
ht t p: / / www. i opr ogr ammo. i t
GRAFICA M
G
94
/Maggio 2008
Realizzare un cattura schermo
{
if (isMouseClicked)
{
graphArea.DrawRectangle(new
Pen(Color.DimGray), topRect.X, topRect.Y,
bottomRect.X - topRect.X, bottomRect.Y - topRect.Y);
getBorderImage();
Pen pen = new Pen(Color.Black);
pen.DashStyle = DashStyle.Dash;
graphArea.DrawRectangle(pen, topRect.X,
topRect.Y, bottomRect.X - topRect.X, bottomRect.Y -
topRect.Y);
}
}
catch { }
}
GESTIONE
INFORMAZIONI
DI SINTESI
Unutility interessante che possiamo aggiungere
al nostro cattura schermo consiste nel visualizza-
re lanteprima dellimmagine catturata diretta-
mente sulla form con laggiunta di una serie di
informazioni di dettaglio che meglio individuano
le caratteristiche della stessa, come indicato alli-
nizio dellarticolo.
Al fine di visualizzare limmagine sempre della
stessa dimensione e nello spazio ad essa dedica-
to utilizziamo il metodo GetThumbnailImage
della classe Bitmap per estrarre dallimmagine
catturata la versione in miniatura o cosiddetta
thumbnail. Cosi facendo otteniamo
unimmagine rimpicciolita se la stessa molto
estesa e viceversa unimmagine ingrandita se la
stessa piccola. Per la visualizzazione a video
effettuiamo loverride del metodo OnPaint e
allinterno serviamoci del metodo DrawImage
per disegnarla.
Vediamo adesso come calcolare le informazioni
da allegare allimmagine. Per calcolare la lar-
ghezza e laltezza nonch la profondit di colore
sufficiente accedere alloggetto Bitmap in cui
limmagine stessa contenuta e leggerli. Invece il
calcolo delloccupazione dello spazio su disco
richiede qualche passaggio in pi. In particolare
il metodo che ho individuato consiste nel salvare
in un oggetto di tipo MemoryStream limmagine
impostando di volta in volta il parametro
ImageCodecInfo al formato che vogliamo (BMP,
JPEG, TIFF, GIF) e il parametro Encoder
Parameters, che rappresenta la qualit o fattore
di compressione con la quale si vuole salvare
limmagine (dove applicabile), al valore di
default che 75.
Trovato il sistema per salvare limmagine in
memoria la dimensione effettiva in Kilo Byte la
ricaviamo facilmente dividendo la propriet
Length delloggetto imageStreamper 1024.
//Gestione visualizzazione thumbnail
protected override void OnPaint(PaintEventArgs e)
{
try
{
base.OnPaint(e);
e.Graphics.DrawImage(thumbnailImage, new
Rectangle(15, 125, 381, 221), 0, 0, 380, 220,
GraphicsUnit.Pixel);
if (bitmap != null) btnSalva.Enabled = true;
}
catch { }
}
//Vengono visualizzate le informazioni associate
all'immagine
private void getImageInformation()
{
try
{
thumbnailImage = bitmap.GetThumbnailImage
(380, 220, null, IntPtr.Zero);
label2.Text = "Color Depth: " + Image.Get
PixelFormatSize(bitmap.PixelFormat) + " bit";
label3.Text = "Width: " + bitmap.Width + "
pixel";
label4.Text = "Height: " + bitmap.Height + "
pixel";
label5.Text = getSize("bmp");
label6.Text = getSize("jpeg");
label7.Text = getSize("tiff");
label8.Text = getSize("gif");
}
catch { }
}
//Viene calcolato lo spazio su disco richiesto
dall'immagine in funzione del tipo
private string getSize(string type)
{
try
{
ImageCodecInfo ici = GetEncoderInfo("image/"
+ type);
MemoryStream imageStream = new
MemoryStream();
EncoderParameters ep = new
EncoderParameters(1);
ep.Param[0] = new EncoderParameter
(Encoder.Quality, (long)75);
bitmap.Save(imageStream, ici, ep);
string value = (Math.Ceiling((double)image
Stream.Length / 1024) + " KB");
imageStream.Dispose();
return value;
}
NOTA
E possibile avere
qualche informazione
di dettaglio sul nuovo
strumento Cattura
Schermo introdotto in
Windows Vista
allindirizzo:
http://windowshelp.
microsoft.com/Windows/
it-IT/help/1337cdba-52a2-
4704-ad4d-2d7bace605b
41040.mspx
090-095:066-071 1-04-2008 17:21 Pagina 94
ht t p: / / www. i opr ogr ammo. i t
GGG GGG
M GRAFICA
Maggio 2008/
95
G
Realizzare un cattura schermo
catch
{
return string.Empty;
}
}
private ImageCodecInfo GetEncoderInfo(String
mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
GESTIONE SALVATAGGIO
IMMAGINE
Per concludere la nostra applicazione non rima-
ne che scrivere le poche righe di codice che ci
permettono di salvare limmagine nel formato
desiderato. In funzione del radio button selezio-
nato cliccando sul pulsante Salva viene imposta-
to il filtro delloggetto saveFileDialog che per-
mette di accedere al file system e scegliere il
nome con cui salvare o sovrascrivere limmagine
nella cartella individuata.
//L'immagine catturata viene salvata
private void btnSalva_Click(object sender, EventArgs e)
{
try
{
string savePath = getFileName();
if (savePath != string.Empty)
if (BMP.Checked)
bitmap.Save(savePath,
ImageFormat.Bmp);
else if (JPEG.Checked)
bitmap.Save(savePath,
ImageFormat.Jpeg);
else if (TIFF.Checked)
bitmap.Save(savePath,
ImageFormat.Tiff);
else
bitmap.Save(savePath,
ImageFormat.Gif);
}
catch { }
}
//Gestione finestra di dialogo per salvare l'immagine
su file
private string getFileName()
{
if (BMP.Checked)
{
saveFileDialog1.DefaultExt = "bmp";
saveFileDialog1.Filter = "bmp files
(*.bmp)|*.bmp";
}
else if (JPEG.Checked)
{
saveFileDialog1.DefaultExt = "jpeg";
saveFileDialog1.Filter = "jpeg files
(*.jpeg)|*.jpeg";
}
else if (TIFF.Checked)
{
saveFileDialog1.DefaultExt = "tiff";
saveFileDialog1.Filter = "tiff files (*.tiff)|*.tiff";
}
else
{
saveFileDialog1.DefaultExt = "gif";
saveFileDialog1.Filter = "gif files (*.gif)|*.gif";
}
saveFileDialog1.Title = "Save Image As ";
saveFileDialog1.ShowDialog();
return saveFileDialog1.FileName;
}
Volendo aggiungere ulteriori formati grafici per il
salvataggio su disco sufficiente aggiungere alla
form qualche ulteriore radio button indicante il
tipo di formato richiesto e qualche ramo in pi
alla serie di if precedenti per definire lestensione
e il filtro.
CONCLUSIONI
Il semplice programma esposto un elegante
strumento per la cattura e il salvataggio di imma-
gini. Abbiamo visto come con il .Net Framework
e C# sia facile la gestione delle librerie grafiche
esposte dal GDI+ per creare utility anche com-
plesse e che sul mercato hanno un certo costo,
con un impiego di tempo abbastanza ragionevo-
le. Sicuramente molto altro ancora si pu
aggiungere e migliorare per rendere il nostro cat-
tura schermo pi professionale ed efficiente.
Tuttavia il risultato raggiunto, anche se con un
numero limitato di funzionalit, sicuramente
permette di fare gran parte del lavoro che si
farebbe con lacquisto di uno strumento com-
merciale con lindubbio vantaggio di non dover
spendere nulla.
Carlo Lollo
LAUTORE
Lautore, consulente
informatico, si occupa
di progettazione e
sviluppo software in
Java e .NET, sia nel
campo industriale con
applicazioni in real
time sia nelloffice
automation con
applicazioni stand-
alone, distribuite e
Web. Le principali aree
di interesse sono
lanalisi dei requisiti,
la progettazione, lo
sviluppo di sistemi ad
oggetti, la qualit e
lusabilit del
software, il testing e
la progettazione di
base di dati e relativa
gestione. Per
commenti, critiche e
suggerimenti
contattabile
allindirizzo
carlo_lollo@libero.it.
090-095:066-071 1-04-2008 17:21 Pagina 95
ht t p: / / www. i opr ogr ammo. i t
SISTEMA M
G
96
/Maggio 2008
Un sistema di talk con Rails
I
l nostro progetto, l'applicazione web Soap-
box, un semplice network sociale con tre
funzionalit:
1) Un utente pu tenere un discorso, cio in-
serire la propria opinione.
2) Un utente pu lasciare un commento e un
voto, positivo o negativo, al discorso di qual-
cun altro.
3) Tutti i discorsi sono elencati sulla prima pa-
gina di Soapbox, con quelli pi votati elencati
pi in alto.
Il mese scorso abbiamo usato Ruby on Rails per
sviluppare la versione 0.1 di Soapbox (se avete
perso il numero scorso di ioProgrammo, leggete
il box Arnesi da lavoro). Soapbox 0.1 implemen-
ta la prima funzionalit: un utente pu scrivere,
modificare o cancellare uno speech, cio un di-
scorso. Oggi ci occuperemo della seconda fun-
zionalit: i voti e i commenti.
UN GIRO DI RAILS
Per rinfrescarci la memoria, e per chi ha perso
l'articolo del mese scorso, torniamo al modello
Model-View-Controller di Rails. Cosa succede se
lanciamo Soapbox e visitiamo, ad esempio,
l'indirizzo http://localhost:3000/speeches/show/1? La
prima parte dell'indirizzo, fino alla porta 3000 in-
clusa, serve solo a identificare il server. Una vol-
ta che la chiamata HTTP arriva sul server, Rails
legge il resto della URL e ne estrae il primo segmento,
in questo caso speeches. Questa stringa viene
convertita nel nome di un Controller, che per con-
venzione si chiamer SpeechesController. Il seg-
mento successivo, show, il nome di una action
in quel controller. Questo significa che nella directory
soapbox/app/controllers esiste un file speech-
es_controller.rb, che contiene una classe Speech-
esController, che contiene un metodo show(), e
questo il metodo che viene invocato dalla URL
/speeches/show/1. Ecco una parte di questa classe,
commenti esclusi:
class SpeechesController < ApplicationController
...
def show
@speech = Speech.find(params[:id])
respond_to do |format|
format.html
format.xml { render :xml => @speech }
end
end
...
Il metodo show() legge da un oggetto di nome
params. Questo oggetto un hash, che il ter-
mine Ruby per indicare una mappa, o un di-
zionario. Rails usa params per passare alle ac-
tion i parametri della chiamata HTTP. La chia-
mata http://localhost:3000/speeches/show/1 non con-
tiene parametri, ma per una convenzione di Rails
il numero 1 alla fine della URL stato assegnato
ad un parametro di nome id. Quindi la prima ri-
ga di show() equivale a:
@speech = Speech.find(1)
Apriamo la classe Speech per capire cosa fa que-
sta riga. Si tratta di una classe del modello, quin-
di la troveremo nella directory soapbox/app/models,
in un file di nome speech.rb:
class Speech < ActiveRecord::Base
end
La classe vuota, ma eredita da ActiveRecord::Base.
ActiveRecord la libreria di Rails che si occupa
di sincronizzare oggetti e database. La classe si
chiama Speech, quindi ActiveRecord la mappa
su una tabella speeches nel database. Le colonne
della tabella diventano automaticamente pro-
priet della classe. Ad esempio: la tabella ha una
colonna di nome title, quindi tutti gli Speechricevono
automaticamente una propriet di nome title.
RUBY ON RAILS:
OGGETTI E RELAZIONI
CONSERVARE DATI OBJECT-ORIENTED IN UN DATABASE RELAZIONALE SPESSO UN LAVORO
DIFFICILE E COMPLICATO. MA NON CON LA LIBRERIA ACTIVERECORD DI RAILS, CHE RENDE
QUESTO COMPITO GRAVOSO ADDIRITTURA DIVERTENTE
J CD J WEB
soapbox-0.1.zip, soapbox-0.2.zip
cdrom.ioprogrammo.it
Conoscenze richieste
Basi di programmazione
object-oriented,
database e sviluppo
web.
Software
Ruby, Rails, SQLite3.
Impegno

Tempo di realizzazione
REQUISITI
096-103:072-080 1-04-2008 17:23 Pagina 96
ht t p: / / www. i opr ogr ammo. i t
M SISTEMA
Maggio 2008/
97
G
Un sistema di talk con Rails
Tutti gli oggetti ActiveRecord ricevono, tra gli al-
tri metodi, un metodo di classe di nome find().
Ad esempio, Speech.find(1) significa: vai nel da-
tabase, trova un record nella tabella speeches il
cui campo idsia uguale a 1, e convertilo in un og-
getto di classe Speech. Nella riga successiva, il
Controller assegna lo Speechappena recuperato
ad una variabile di nome @speech:
@speech = Speech.new
In Ruby, le variabili che iniziano con una @ sono
variabili di istanza (cio campi) di un oggetto,
quindi questa riga fa nascere una nuova variabi-
le di istanza nel Controller. I campi del Control-
ler hanno un ruolo speciale, che vedremo tra po-
co. Finiamo prima di esplorare il codice di show():
respond_to do |format|
format.html
format.xml { render :xml => @speech }
end
Queste righe selezionano la View (la vista) che
deve essere restituita all'utente. Non entreremo nei
dettagli, ma cerchiamo di spiegarle in poche pa-
role. La riga che inizia con format.xml vuol dire:
se ti stato richiesto il formato XML, prendi lo
Speechche hai appena creato, convertilo in XML
e mandalo all'utente. Se volete vedere questa ri-
ga in azione, aprite la URL
http://localhost:3000/speeches/1.xml.
La URL http://localhost:3000/speeches, invece, non
specifica alcuna estensione quindi chiede im-
plicitamente una pagina HTML. Il codice qui so-
pra non dice cosa restituire all'utente nel caso
venga richiesto dell'HTML, quindi Rails si affida
ad una convenzione di default: seleziona la View
che ha lo stesso nome della action (in questo ca-
so show) e l'estensione di default .html.erb. Il suf-
fisso .erb sta per Embedded RuBy, che come ve-
dremo tra poco un sistema di template, e .html
indica che il template deve generare un file HTML.
Andiamo nella directory soapbox/app/views e cu-
riosiamo nel file show.html.erb:
<p>
<b>Author:</b>
<%=h @speech.author %>
</p>
<p>
<b>Title:</b>
<%=h @speech.title %>
</p>
<p>
<b>Text:</b>
<%=h @speech.text %>
</p>
<%= link_to 'Edit', edit_speech_path(@speech)
%> |
<%= link_to 'Back', speeches_path %>
Questo un template HTML: un pezzo di HTML
punteggiato da tag speciali che contengono codice
Ruby. I tag <% ... %> significano esegui questo
codice, e i tag <%= ... %> significano esegui que-
sto codice e infilane il risultato nell'HTML. <%=h
... %> significa che la stringa deve essere codificata
in HTML, per evitare di usare caratteri riservati
come le parentesi angolari.
Qui possiamo vedere come fa il Controller a co-
municare dati alla View. Semplicemente, tutte le
variabili di istanza nel Controller (quelle che ini-
ziano per @) sono accessibili anche nella View.
Ad esempio, questa vista accede ai campi author,
title e text della variabile @speech, che corri-
spondono ad altrettante colonne nella tabella
speeches.
Le ultime due righe della View usano istruzioni
come link_to() e speeches_path() per generare i
link ad altre pagine dell'applicazione. In realt
non si tratta di istruzioni, ma di semplici metodi
(in Ruby si possono omettere le parentesi tonde
quando si chiama un metodo). I metodi che si
usano nelle View, come questi, si chiamano hel-
per.
Potreste chiedervi come mai questo HTML non con-
tiene tag come <html> o <body>. Troverete i tag
scomparsi nel file soapbox/app/views/layouts
/speeches.html.erb. Per una delle sue tante con-
venzioni, Rails avvolge tutte le viste invocate dal-
lo SpeechesController in questo file (che in gergo
Rails si chiama un layout), in modo da non du-
plicare l'inizio e la fine della pagina in ciascuna vi-
sta.
Ora il giro completo. La URL stata interpreta-
ta e inviata alla action di un Controller. Il Con-
troller si rivolto al Model per calcolare un risul-
tato, l'ha infilato nelle sue variabili di istanza e
ha selezionato una View. La View ha letto i dati
preparati dal Controller, li ha formattati in HTML,
ed ha usato qualche helper per calcolare i link ad
altre pagine. L'HTML risultante stato rispedito
all'utente. Quasi tutte le chiamate ad una appli-
cazione Rails funzionano in questo modo.
Ma ora basta studiare: ora di metterci al lavoro
e sviluppare la versione 0.2 di Soapbox.
UN PROBLEMA
DI FILOSOFIA
Ecco la funzionalit che vogliamo sviluppare
oggi:
096-103:072-080 1-04-2008 17:23 Pagina 97
ht t p: / / www. i opr ogr ammo. i t
SISTEMA M
G
98
/Maggio 2008
Un sistema di talk con Rails
- Un utente pu inserire un voto (+1 oppure -1)
sull'opinione di qualcun altro, e lasciare un com-
mento.
Pensiamo prima al posto dove risiede la logica
del sistema: il Model. Un commento sar proba-
bilmente un oggetto di classe Comment, che in-
clude un testo (il commento vero e proprio), il
nome dell'autore e un voto. Per semplificare, an-
zich usare letteralmente i valori +1 e -1, possia-
mo dare al voto un valore booleano: true per so-
no d'accordo e false per non sono d'accordo.
Potremo sempre convertire questi valori in +1 e -
1 in seguito.
Tutti i commenti si riferiscono ad una opinione,
quindi dobbiamo fare in modo che ciascun Com-
ment abbia la propria Speech. Questa quello che
si chiama una relazione 1 a N, nel senso che cia-
scun commento si riferisce ad una opinione, e
ciascuna opinione pu avere pi commenti. Man-
tenere questa relazione pu suonare semplicissimo,
fin quando non ci ricordiamo che sia i commen-
ti che le opinioni vivono contemporaneamente in
due mondi diversi: in memoria sotto forma di og-
getti, e nel database sotto forma di record. Le re-
lazioni tra un commento e la sua opinione, e tra
un'opinione e i suoi commenti, devono essere
mantenute in entrambi i casi.
Uno dei problemi con cui ci si scontra spesso
quando si conservano gli oggetti in un database
che gli oggetti e le tabelle hanno idee comple-
tamente diverse di come si gestiscono le relazio-
ni. Tra oggetti, si usano semplici riferimenti. Se
un Comment deve avere una Speech corrispon-
dente, basta che ciascun Comment conservi un
riferimento ad una Speech, probabilmente in una
variabile di istanza. Se vogliamo navigare la rela-
zione in entrambe le direzioni, allora anche la
Speechdeve avere un riferimento ai propri Com-
ment. Ma dato che una Speechpu avere pi Com-
ment, dovr conservarli in qualche tipo di colle-
zione, come ad esempio un array.
Il database non ha nessun concetto di direzio-
ne o collezione, e nemmeno di riferimento.
Per dire che una tabella comments ha una rela-
zione 1 a N con una tabella speeches, basta che
una colonna di comments sia una foreign key
ai corrispondenti record di speeches. Per trovare
lo speech di un comment, o i comment di uno
speech, dobbiamo fare un join tra le tabelle.
E' difficile mettere d'accordo queste due filosofie,
ma Rails semplifica tutto nel suo solito modo:
con una serie di convenzioni.
CIASCUNO DICA LA SUA
Ricordate il generator? Il mese scorso l'abbiamo
usato per creare l'impalcatura completa degli
Speech. Questa volta non vogliamo un'impalca-
tura completa ad esempio, non vogliamo che i
commenti abbiano un Controller e delle View.
Tutto quello che ci serve il Model:
ruby script/generate model comment author:string
text:text vote:boolean speech_id:integer
Abbiamo detto che vogliamo un modello per qual-
cosa che si chiama un comment. Questo mo-
dello deve avere un autore (una stringa), un te-
sto (di tipo text), un voto (booleano) e una fo-
reign key ad un record della tabella speeches.
Quest'ultima un semplice intero, che secondo
le convenzioni di Rails si chiama con il nome al sin-
golare della destinazione seguita da _id - in que-
sto caso, speech_id.
Il generator ha scritto per noi quattro o cinque fi-
le, ma i due pi importanti sono la migrazione e
il modello ActiveRecord. La migrazione si chia-
ma 002_create_comments.rb, e contiene le istru-
zioni che preparano il database ad accogliere i
commenti. Lanciamo la migrazione con Rake:
rake db:migrate
Il risultato sar qualcosa come:
= 2 CreateComments: migrating
================================-
create_table(:comments)
-> 0.0052s
== 2 CreateComments: migrated (0.0054s)
================================
NOTA
IL TOCCO
DELL'ARTISTA
Se conoscete l'HTML,
giocate un po' con i
template della View
per migliorare la
grafica di Soapbox.
Ricordate che tutte le
viste sono avvolte
nel file
soapbox/app/views/la
youts
speeches.html.erb.
RAILS IN PILLOLE
- Ruby on Rails un framework
per sviluppare applicazioni
web basate su database. In
altre parole, serve per scrivere
quel genere di sito web che
spesso si scrive con PHP,
ASP.NET o Java EE. Molti
ritengono che Rails sia di gran
lunga pi produttivo di questi
suoi concorrenti.
- Rails usa un linguaggio di
programmazione chiamato
Ruby. Ruby un linguaggio
dinamico come Python o
Perl. E' anche rigorosamente
object-oriented e
straordinariamente sintetico
ed espressivo.
- Molti siti di successo sono
scritti in Rails. Alcuni, come
Twitter, generano un'enorme
quantit di traffico e dati.
- Rails corredato da una serie
di script, tra i quali un
generatore di codice che
permette di sviluppare
rapidamente un prototipo di
applicazione da rifinire in
seguito.
- Rails implementa il pattern
Model-View-Controller. In
un'applicazione Rails, il
controller, il modello e le
viste risiedono fisicamente
in directory separate.
- Rails ha una sua filosofia,
basata su concetti come le
convenzioni sono meglio della
configurazione, o non
ripetere la stessa informazione
in due punti diversi. Un
esempio di entrambe queste
idee il modo in cui Rails
mappa gli oggetti sul
database, di cui parliamo in
questo articolo.
096-103:072-080 1-04-2008 17:23 Pagina 98
ht t p: / / www. i opr ogr ammo. i t
M SISTEMA
Maggio 2008/
99
G
Un sistema di talk con Rails
Quindi ora abbiamo una tabella comments dove
conservare i commenti. Andiamo a verificarlo
aprendo il database con SQLite3:
sqlite3 db/development.sqlite3
Il comando .tables mostra che il database con-
tiene le tabelle speeches, comments e schema_info
(Rails usa quest'ultima tabella per gestire le mi-
grazioni). Con il comando .schema comments
possiamo vedere il DDL usato per creare la ta-
bella comments:
CREATE TABLE comments ("id" INTEGER PRIMARY
KEY AUTOINCREMENT NOT NULL, "author"
varchar(255) DEFAULT NULL, "text" text DEFAULT
NULL, "vote" boolean DEFAULT NULL, "speech_id"
integer DEFAULT NULL, "created_at" datetime
DEFAULT NULL, "updated_at" datetime DEFAULT
NULL);
Come al solito, Rails ha fatto un po' di lavoro ex-
tra per conformare la tabella alle proprie con-
venzioni: ha aggiunto una chiave primaria di no-
me id, ha convertito i tipi in quelli nativi di SQ-
Lite3 (ad esempio, la string diventata un var-
char), ha assegnato NULL come default a tutti i
campi e ha persino creato due nuovi campi che ge-
stir automaticamente: created_at e updated_at,
che contengono le date di creazione e di ultima mo-
difica di ciascun record.
Ora abbiamo una relazione nel database, ma il
Model non ne sa ancora niente. Apriamo i file
comment.rb e speech.rb e aggiungiamo una riga
di codice a ciascuna classe:
class Comment < ActiveRecord::Base
belongs_to :speech
end
class Speech < ActiveRecord::Base
has_many :comments
end
Abbiamo appena detto a Rails che un Comment
appartiene ad uno Speech (belongs_to), e che
uno Speechha molti Comment (has_many). Che
ci crediate o no, queste due righe di codice sono
magiche: creano nuovi metodi nelle classi Com-
ment e Speech. Vediamo quali.
VIAGGIO AL CENTRO
DELL'APPLICAZIONE
Cerchiamo di capire come funziona il nostro nuo-
vo modello. Per interagire con il modello dob-
biamo scrivere un Controller e una serie di viste...
Aspettate un momento. Esiste un modo molto
pi semplice per giocare col modello: uno script
di nome console, che possiamo lanciare come al
solito dalla directory soapbox.
ruby script/console
Il risultato sar qualcosa di simile a questo:
Loading development environment (Rails 2.0.2)
>>
Strano ma vero: siamo appena entrati nell'appli-
cazione Soapbox. Abbiamo davanti un interpre-
te Ruby interattivo che ci permette di accedere
al modello e al sottostante database, proprio co-
me se fossimo un Controller. Ogni volta che dia-
mo un comando, la console ne stampa il risulta-
to. Lo script console carica uno degli ambienti de-
finiti nel file soapbox/config/database.yml. Non
abbiamo specificato quale ambiente ci interes-
sa, quindi Rails ha caricato per default l'ambiente
di sviluppo, che usa il database soapbox/db/ de-
velopment.sqlite3. Giochiamo un po' con la clas-
se Command. Con il metodo find() e il parametro
:all possiamo leggere tutti i Comment che sono
gi nel database:
>> Comment.find :all
=> []
In Ruby gli array sono delimitati da parentesi qua-
drate, quindi quello che vediamo nel risultato un
array vuoto. Giusto: non abbiamo ancora creato
alcun commento. Ora recuperiamo il primo re-
cord dalla tabella speeches usando il parametro
:first:
>> s = Speech.find :first
=> #<Speech id: 1, author: "Paolo", title: "Non ci
sono pi le mezze stagioni", text: "Anche senessuno
ne parla mai, ho notato che le mez...", created_at:
"2008-02-03 17:09:16", updated_at: "2008-03-16
16:30:25">
ActiveRecord andato nel DB, ha recuperato il
primo record della tabella speeches e l'ha avvol-
to in un oggetto di classe Speech. Ma il meglio
deve ancora venire.
Quando abbiamo scritto che uno Speechha mol-
ti Comment e un Comment appartiene a uno
Speech, Rails ha creato automaticamente una se-
rie di nuovi metodi nel modello. In particolare
ora abbiamo un metodo Speech.comments(), che
restituisce un array di commenti, e un metodo
Comment.speech(), che restituisce un singolo
Speech (notate i singolari e i plurali). Vediamo
Speech.comments() in azione:
096-103:072-080 1-04-2008 17:23 Pagina 99
ht t p: / / www. i opr ogr ammo. i t
>> s.comments
=> []
Come ci potevamo aspettare, questo Speechnon
ha alcun Comment. Proviamo a creare un Comment
come se fosse un normale oggetto Ruby, con il
metodo new() della sua classe:
>> c = Comment.new
=> #<Comment id: nil, author: nil, text: nil, vote:
nil, speech_id: nil, created_at: nil, updated_at: nil>
Le propriet di questo commento sono ancora
vuote. Riempiamole:
>> c.author = "Gino"
>> c.text = "Finalmente un'opinione originale!"
>> c.vote = true
Ora che il nostro Comment ha un autore, un testo
e un voto, possiamo aggiungerlo ai commenti
dello Speech. Per aggiungere un elemento ad un
array possiamo usare l'operatore <<:
>> s.comments << c
=> [#<Comment id: 1, author: "Gino", text:
"Finalmente un'opinione originale!", vote: true,
speech_id: 1, created_at: "2008-03-16 17:06:31",
updated_at: "2008-03-16 17:06:31">]
Questa semplice riga di codice ha avuto molte
conseguenze. La console ci dice che la propriet
comments dello Speech ora un array che con-
tiene un Comment con id uguale a 1. Gli id sono
assegnati dal database, quindi Rails deve aver sal-
vato il commento nel database. Possiamo anche
chiedere al Comment a quale Speechappartiene:
>> c.speech
=> #<Speech id: 1, author: "Paolo", title: "Non ci
sono pi le mezze stagioni", text: "Anche se
nessuno
ne parla mai, ho notato che le mez...", created_at:
"2008-02-03 17:09:16", updated_at: "2008-03-16
16:36:51">
Il commento appartiene allo Speechcon idugua-
le a 1, lo stesso che abbiamo messo da parte nel-
la variabile s. Quindi, nel database, la tabella com-
ments contiene ora un singolo record, il cui id
uguale a 1 e il cui campo speech_id anch'esso
uguale a 1.
La sincronia tra oggetti e database pu sembra-
re quasi magica, ma non sempre cos traspa-
rente. Proviamo a creare un secondo commen-
to. Questa volta usiamo una sintassi pi sintetica
per valorizzare i suoi campi nel momento stesso
in cui lo creiamo:
c2 = Comment.new :author => "Il Polemico", :text
=> "Non sono d'accordo", :vote => false
Assegniamo il commento ad s. Questa volta usia-
mo per l'operazione inversa. Anzich assegna-
re il Comment allo Speech, assegniamo lo Speech
al Comment:
>> c2.speech = s
Sembrerebbe tutto a posto, ma se andiamo a con-
trollare la lunghezza dell'array s.comments tro-
veremo che contiene ancora un solo elemento:
>> s.comments.size
=> 1
Il problema che (per alcuni buoni motivi sui
quali non ci soffermeremo) Rails salva gli ogget-
ti automaticamente solo se vengono assegnati
SISTEMA M
G
100
/Maggio 2008
Un sistema di talk con Rails
ARNESI DA LAVORO
Se avete seguito lo sviluppo di
Soapbox sin dal mese scorso,
allora avete gi tutto quello che
vi occorre. Se iniziate da questo
mese, ecco cosa vi serve.
Installate Ruby e il package
manager RubyGems. Se usate
Windows, potete installarli
entrambi con il One-Click Ruby
Installer che trovate su
http://www.ruby-
lang.org/en/downloads. Poi
copiate da qualche parte nel
path la DLL e l'eseguibile del
database SQLite3. Nel momento
in cui scriviamo, i file sono
sqlitedll-3_5_6.zip e sqlite-
3_5_6.zip, e potete scaricarli da
http://www.sqlite.org/download.
html. Infine installate i pacchetti
RubyGems che ci servono (Rails,
il driver per SQLite3 e il web
server Mongrel) con questo
comando:
gem install rails sqlite3-ruby mongrel -y
Vediamo se quello che abbiamo
installato funziona. Scompattate
da qualche parte il file soapbox-
0.1.zip che trovate sul CD allegato
alla rivista, aprite il prompt dei
comandi, entrate nella directory
soapbox e scrivete:
ruby script\server
Questo comando lancia il web
server Mongrel. Aprite un browser
e andate all'indirizzo
http://locahost:3000/speeches.
Dovreste vedere la prima pagina
di Soapbox: una lista editabile di
discorsi come quella
dell'immagine: primapagina.
Figura 1: Un semplice esempio di come appare la pagina
096-103:072-080 1-04-2008 17:23 Pagina 100
ht t p: / / www. i opr ogr ammo. i t
dal lato della relazione che non contiene la fo-
reign key. Dato che i Comment contengono la
foreign key, Rails non li salva fino a quando non
aggiorniamo il corrispondente Speech. Per evita-
re questo problema dobbiamo ricordarci di ge-
stire le relazioni dal lato has_many, non dal lato
belongs_to. In alternativa, possiamo salvare noi
stessi il nuovo Comment e rinfrescare lo Speech
con i dati del database:
>> c2.save
>> s.reload
>> s.comments.size
=> 2
Ora uno degli Speechnel nostro sistema ha due Com-
ment al seguito. Come ultima verifica, control-
liamo che questa relazione sia davvero bidire-
zionale. Lo Speechdi uno dei due Comment di s de-
ve essere proprio s:
>> s.comments[1].speech == s
=> true
Perfetto! Avete ancora il server di Soapbox atti-
vo? In caso contrario lanciatelo, perch il momento
di tornare sul web.
CAMERA CON VISTA
Aprite l'applicazione e cliccate sul link show ac-
canto a uno degli speech sulla prima pagina. Ve-
drete i dettagli dello speech che avete seleziona-
to, come nella figura
Vogliamo che i commenti degli utenti siano visi-
bili sul sito, quindi ciascuno Speechdovrebbe mo-
strare anche tutti i commenti relativi. Sappiamo
gi come viene costruita questa pagina: Rails
mappa una URL come http://localhost:3000/speeches/1
sulla action show() dello SpeechesController. Il
Controller recupera lo Speechcon l'id richiesto e
lo passa ad una View di nome show.html.rb nel-
la directory soapbox/app/views/speeches. Visto che
uno Speech si porta dietro tutti i suoi commenti,
possiamo gi accedere ai commenti dalla vista.
Dobbiamo solo visualizzarli. Apriamo il templa-
te show.html.erb e aggiungiamogli qualche riga:
<p>
<b>Author:</b>
<%=h @speech.author %>
</p>
<p>
<b>Title:</b>
<%=h @speech.title %>
</p>
<p>
<b>Text:</b>
<%=h @speech.text %>
</p>
<h3>Comments:</h3>
<% for comment in @speech.comments %>
<p>
<%= comment.vote ? "+1" : "-1" %><br/>
On <%=h comment.created_at.to_s(:short) %>,
<b><%=h comment.author %></b> says:<br/>
<%=h comment.text %>
</p>
<% end %>
<%= link_to 'Edit', edit_speech_path(@speech)
%> |
<%= link_to 'Back', speeches_path %>
Prima che tutti questi caratteri buffi ci facciano gi-
rare la testa, cerchiamo di distinguere subito tra
tag HTML e pezzi di codice Ruby. Abbiamo aper-
to l'elenco dei commenti con un normale titolo in
HTML. La riga successiva codice Ruby: un ci-
clo for su tutti i commenti contenuti nell'array
@speech.comments. Il ciclo termina con la paro-
la chiave end. Tutto quello che c' in mezzo fa
parte del ciclo, e ad ogni giro la variabile comment
assume il valore di un nuovo commento. (Se co-
noscete Ruby, sapete certo che esiste un modo
pi elegante per scrivere i cicli, ma in questo ar-
ticolo abbiamo preferito usare un pi tradizio-
nale for).
Vediamo cosa succede nel ciclo. Saltando la pri-
ma riga, sulla quale torneremo tra poco, il corpo
del ciclo :
M SISTEMA
Maggio 2008/
101
G
Un sistema di talk con Rails
Figura 2: Ed ecco i commenti!
NOTA
CENSURA!
Soapbox 0.2 non
permette di cancellare
i commenti attraverso
l'interfaccia web.
Provate ad aggiungere
un po' di commenti
inutili all'applicazione
(particolarmente
consigliati quelli che
pubblicizzano Viagra o
giochi d'azzardo). Poi
lanciate script/console
e cancellare i
commenti indesiderati
attraverso la riga di
comando. Potete
cancellare un oggetto
dal database
chiamando il suo
metodo destroy(), e
cancellare tutti gli
oggetti di una certa
classe con il metodo di
classe destroy_all().
096-103:072-080 1-04-2008 17:23 Pagina 101
ht t p: / / www. i opr ogr ammo. i t
On <%=h comment.created_at.to_s(:short) %>,
<b><%=h comment.author %></b> says:<br/>
<%=h comment.text %>
Questo HTML punteggiato da pezzi di Ruby che
leggono le propriet di comment. La propriet
comment.created_at una data, quindi l'abbiamo
convertita in una stringa breve e leggibile con il me-
todo to_s(), che sta per to string. Abbiamo anche
codificato in HTML i campi che contengono te-
sto.
La prima riga del ciclo contiene un pezzo di codice
un po' pi complicato:
comment.vote ? "+1" : "-1"
Se conoscete il C o qualcuno dei suoi derivati
avrete certo riconosciuto il famigerato operato-
re ternario. Questa riga dice: se comment.vote
true, stampa +1, altrimenti stampa -1. E' un
modo pi sintetico di scrivere if..else.
Salvate il file e fate un refresh della pagina nel
browser (non c' bisogno che riavviate il server).
Il risultato dovrebbe essere quello dell'immagi-
ne: comments:
lo Speech seguito dalla lista dei suoi commenti.
Proprio quello che volevamo.
UN PO'
DI REFACTORING
Il codice che abbiamo appena scritto funziona,
ma non del tutto pulito. Il problema in quel-
la brutta riga della View:
<%= comment.vote ? "+1" : "-1" %>
Se avete esperienza di applicazioni MVC, sapete
che le View dovrebbero essere stupide e conte-
nere solo la logica di presentazione. La logica di
business, cio il comportamento dell'applica-
zione, dovrebbe essere nel Model. Secondo voi,
questa riga logica di presentazione o logica di bu-
siness? Comunque la pensiate, questo genere di
codice rende il template pi difficile da leggere -
quindi per ora lasceremo da parte le discussioni
accademiche e ne approfitteremo per rimpolpa-
re il nostro Model anemico. Apriamo il file com-
ment.rb e aggiungiamo un metodo alla classe
Comment:
class Comment < ActiveRecord::Base
belongs_to :speech
def ranking
vote ? "+1" : "-1"
end
end
Il metodo ranking() restituisce +1 o -1 a se-
conda che la propriet vote del Comment sia ve-
ra o falsa. In un altro linguaggio avremmo usato
la parola chiave return, ma in Ruby non ce n' bi-
sogno: in assenza di return, un metodo restitui-
sce semplicemente il valore dell'ultima espres-
sione che ha calcolato. Ora possiamo semplifi-
care il codice della vista:
<% for comment in @speech.comments %>
<p>
<%= comment.ranking %><br/>
...
Abbiamo soddisfatto il nostro perfezionismo. Ora
ci resta solo un pezzo per completare questo puzz-
le.
QUESTIONE DI FORM
Finora gli utenti di Soapbox possono visualizza-
re i commenti, ma non inserirli. Per inserire un
commento ci serve una nuova action nel Con-
troller:
class SpeechesController < ApplicationController
def comment
s = Speech.find params[:id]
s.comments <<
Comment.new(params[:comment])
redirect_to :action => :show, :id => s
end
...
La action comment() inizia come la action show():
si aspetta che la chiamata HTTP contenga come
parametro l'id di uno Speech, e legge lo Speech
dal database. Inoltre si aspetta che la chiamata
contenga un parametro comment, che a sua vol-
ta contiene tutte le propriet necessarie per crea-
re un nuovo Comment (come vedremo tra poco,
Rails costruir questo parametro per noi). La ac-
tion usa questo parametro per creare un Com-
ment che poi aggiunge allo Speech. Se ricordae i
nostri esperimenti con la console di poco fa, sa-
pete che questa operazione salva automatica-
mente gli oggetti nel database.
Normalmente, al termine di un'azione viene vi-
sualizzata una View. Noi invece vogliamo che, do-
po aver inserito un Comment, l'utente veda la pa-
gina dello Speechcorrispondente. Quindi l'ultima
SISTEMA M
G
102
/Maggio 2008
Un sistema di talk con Rails
NOTA
PER I PI
AVVENTUROSI
Se ve la sentite,
provate a scrivere
una pagina di
amministrazione che
permette di
cancellare alcuni
Comment. Potete
scrivere tutto il
codice a mano,
oppure usare
script/generator per
costruire uno
scaffold per i
Comment, come
abbiamo fatto il
mese scorso per gli
Speech. In
quest'ultimo caso
potete modificare il
Controller e le viste
generate perch
rendano possibile
eliminare un
commento, ma non
aggiungerlo. Se ce la
fate, potete gi
considerarvi
programmatori Rails!
096-103:072-080 1-04-2008 17:23 Pagina 102
ht t p: / / www. i opr ogr ammo. i t
riga una redirezione alla action show(). Questa
action vuole un parametro id, quindi dobbiamo
assegnare a questo parametro il valore dell'iddel-
la Speech. Grazie ad una delle tante scorciatoie
di Rails, possiamo semplicemente assegnare al
parametro l'intero oggetto s, che verr converti-
to automaticamente nel suo id durante la tra-
sformazione in HTTP.
Ora ci manca solo l'interfaccia utente. Torniamo
alla vista show.html.erb e aggiungiamo queste ri-
ghe subito prima dei due link in fondo alla pagi-
na:
<h3>Add your comment:</h3>
<% form_for :comment, :url => { :action =>
:comment, :id => @speech } do |f| %>
<p>
By: <%= f.text_field :author %>
</p>
<p>
Vote: <%= f.check_box :vote %>
</p>
<p>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit "Add comment" %>
</p>
<% end %>
Questo codice pu sembrare complesso se non
conoscete ancora bene Ruby. In realt molto
semplice, ma il modo migliore per imparare co-
me funziona quello di scrivere due o tre form
per conto vostro - quindi per ora ci limiteremo a
scorrere velocemente queste righe senza con-
centrarci sui dettagli. L'helper form_for costrui-
sce un tag HTML <form>. Il codice all'interno del-
la form definisce tre campi: un campo di testo
breve di nome author, una checkbox di nome
vote (che indica un voto positivo se seleziona-
ta, negativo se non lo ), un'area di testo di no-
me text e un pulsante per inviare i dati. La chiamata
a form_for precisa che la form impacchetta i cam-
pi in un parametro di nome comment, e invia
questo parametro alla action comment().
Dato che non abbiamo specificato un Control-
ler, il Controller lo stesso che ha generato la pa-
gina. Attenzione a non confondervi: sia la action
che il parametro si chiamano si chiamano com-
ment, ma avremmo potuto anche usare due no-
mi diversi.
Oltre al parametro comment, la form infila nella
richiesta anche un parametro id, che contiene
l'id dello Speechattualmente visualizzato. Anco-
ra una volta, Rails converte automaticamente lo
Speechnel suo id ma nessuno ci avrebbe impe-
dito di scrivere esplicitamente @speech.id.
Ricapitoliamo il flusso della vita di un commen-
to. L'utente compila questa form, e il risultato una
chiamata HTTP POST alla action comment(). Que-
sta chiamata ha due parametri: id, che contiene
l'identificativo di uno Speech, e comment, un pa-
rametro che contiene i valori di author, text e
vote. La action comment() usa i dati nel parame-
tro comment per creare un nuovo Comment e as-
segnarlo allo Speech identificato dal parametro
id. Poi la action redirige l'utente alla action show()
dello stesso controller, che visualizza nuovamente
lo Speech, i suoi Comment aggiornati, e la form
per aggiungere un altro Comment. Il risultato do-
vrebbe essere quello dell'immagine: add_comments.
Fatto!
CONCLUSIONI
Soapbox 0.2 pronto. Certo, c' ancora tanto
lavoro da fare. La grafica ignobile, le funzio-
nalit sono pi o meno le stesse di un qualsia-
si blog, e comincia a farsi sentire l'esigenza di
un sistema di autenticazione degli utenti (non
bello che chiunque possa modificare o can-
cellare i discorsi di chiunque altro).
Ma noi siamo seguaci del motto: prima fallo
funzionare, poi fallo bene. Perch Soapbox fun-
zioni come dicono le specifiche, ci resta anco-
ra un'ultima caratteristica: dobbiamo ordina-
re le opinioni sulla prima pagina in base ai vo-
ti che hanno ricevuto.Ce ne occuperemo il me-
se venturo. Nel frattempo, buon divertimento
con Rails!
Paolo Perrotta
M SISTEMA
Maggio 2008/
103
G
Un sistema di talk con Rails
Figura 3: La form per limmissione
NOTA
ERRATA
CORRIGE
Nell'articolo del
mese scorso abbiamo
scritto che potete
installare il driver
SQLite3 per Ruby con
il comando:
gem install sqlite3
Questo comando
sbagliato. Quello
giusto :
gem install sqlite3-
ruby
Chiediamo scusa per
l'errore.
096-103:072-080 1-04-2008 17:23 Pagina 103
ht t p: / / www. i opr ogr ammo. i t
SOFTWARE SUL CD M
G
106
/Maggio 2008
Librerie e Tool di sviluppo
XAMPP 1.5.5
IL TUO SERVER PERSONALE!
Installando questo software avremo a
disposizione un completo ambiente
per lo sviluppo di applicazioni web ba-
sate su PHP e MySQL, ossia una delle
piattaforme pi usate del web. I pro-
grammi installati saranno: Apache 2.2.3
(server web), MySQL 5.0.27 (motore
SQL), PHP 5.20/4.4.4 (linguaggio di
scripting), phpMyAdmin 2.9.1.1 (tool
web per amministrare MySQL), File-
Zilla FTP Server 0.9.20 (server FTP),
OpenSSL 0.9.8.d (librerie per
limplementazione del protocollo SSL).
La presenza di un pannello di control-
lo, inoltre, semplificher lavvio e larresto
dei vari server.
Directory: XAMPP 1.5.5.zip
PYTHON 2.5
L'EX GIOVANE RAMPANTE
Python stato considerato per lungo
tempo il nuovo che avanza. Attual-
mente non lo si pu pi definire in que-
sto modo, Python ormai un linguag-
gio stabile e completo che trova appli-
cazione in un gran numero di proget-
ti. Se ne parla sempre di pi in campo
industriale come su Internet. Soprat-
tutto un gran numero di applicazioni an-
che in ambiente Windows girano or-
mai grazie a Python e presentano in-
terfacce grafiche ottimamente strut-
turate. Ci nonostante Python rimane
un grande linguaggio di scripting adat-
to a gestire in modo completamente
automatico buona parte di un sistema
operativo sia esso Linux o Windows
Directory: python-2.5.msi
ANKHSETUP 0.5.5
PER UTILIZZARE SUBVERSION
DI VISUAL STUDIO.NET
SubVersion uno strumento di con-
trollo della revisione che si sta affer-
mando rapidamente nel momento del-
la programmazione. Consente di te-
nere sotto controllo le modifiche ef-
fettuate al codice generando una serie
di log che consentono di capire come
quando e come determinate parti del-
l'applicazione siano state modificate.
Eventualmente possibile tornare a
versioni precedenti oppure generare il
changelog automaticamente. Questo
Add In consente ai programmatori .NET
di utilizzare subversion direttamente
dai propri progetti e dall'ambiente di
programmazione Visual Studio. Sub-
version sta lentamente soppiantando
il fratello maggiore CVS che nel tem-
po aveva conquistato larghe fette di
mercato. Alcuni progetti molto attivi
come ad esempio il kernel di Linux so-
no passati a subversion
Directory: AnkhSetup 0.5.5.zip
REGULATOR 20B
IL COSTRUTTORE DI REGEX
un tool ricco di funzioni e semplice
da usare, che permette di testare le
espressioni regolari. Le REGEX non
sempre sono facili da manipolare,
Regulator ci sa una mano semplifi-
candoci il lavoro consentendoci di
verificare il buon funzionamento di
un espressione regolare prima di in-
serirla nel nostro codice
Directory: Regulator 20B
BUGZILLA 2.23.3
PER TENERE SOTTO CONTROLLO
I BACHI DEL SOFTWARE
Un buon software evolve nel tempo-
sulla base delle indicazioni dei suoi
utenti. E tutti i software nascono con
qualche imperfezione che solitamen-
te viene fuori proprio in fase di utiliz-
zo intensivo dell'applicazione.Ma co-
me tener traccia delle segnalazioni ef-
fettuate dagli utenti?Bugzilla una Web
Application checonsente di memoriz-
zare i bug, ordinarli secondo precisi
ticket e cos garantisce al programma-
tore di poter intervenire in modo or-
ganico, sistemando i bachi, elaboran-
do patch, eventualmente segnalando
all'utente falsi bug.Un'applicazione
senza dubbio utile che risolve uno dei
maggiori problemidel ciclo di svilup-
po. Attualmente bugzilla lo strumento
pi diffuso per il controllo dei bug sui
progetti opensource e molto spesso
viene utilizzato anche in caso di pro-
getti commerciali
Directory: Bugzilla 2.23.3.zip
WIRESHARK 0.99
LO SPIONE DELLA RETE
Wireshark uno dei software pi di-
scussi dell'ultimo anno. Non perch in
se contenga qualcosa di realmente dan-
noso ma perch spesso viene utilizza-
to da malintenzionati per recuperare
dal traffico di rete informazioni non
criptate.Wireshark infatti un analiz-
zatore di traffico di rete. Intercetta tut-
ti i pacchetti che passano nella vostra
lan restituendo una serie di informa-
zioni completa, quantitativa e quali-
tativa del materiale che passa attra-
verso le schede di rete della Lan. Si trat-
ta di uno strumento utilissimo per ca-
pire come ottimizzare le vostre con-
nessioni, ma deve essere utilizzato con
cautela
Directory: wireshark 0.99
NUNIT 2.4.3
IL COSTRUTTORE DI TEST
Qualche volta, anzi molto spesso vi tro-
verete a costruire dei test per "stressa-
re" la vostra applicazione .NET e ve-
dere come reagisce. Nunit un tool
opensource che vi mette a disposizio-
ne un linguaggio per scrivere proce-
dure di test. Inoltre consente di visua-
SOFTWARE
SUL CD
106-109:106-108-software 1-04-2008 17:12 Pagina 106
ht t p: / / www. i opr ogr ammo. i t
M SOFTWARE SUL CD
Maggio 2008/
107
G
Librerie e Tool di sviluppo
lizzare i dati tramite un'interfaccia gra-
fica
Directory: Nunit 2.4.3
DAYPILOT 2.1. SP3
UN CONTROLLO ASP.NET PER LA
GESTIONE DEGLI APPUNTAMEN-
TI
Intelligente questo controllo! Consen-
te di creare un'applicazione ASP .NET
che offre funzionalit del tutto simili
a quelle utilizzate da Outlook nella sua
parte relativa alla gestione degli impe-
gni.Il controllo molto solido e ben
strutturato e offre una serie di funzio-
ni che risultano piuttosto comode per
un programmatore, molto pi evolute
di un normale calendario
Directory: Daypilot 2.1. SP3
NANT 0.86
IL COMPILATORE BATCH
Il vostro progetto in continua fase di
sviluppo. Avete deciso di rilasciare al
pubblico ogni sera ad una certa ora una
release binaria contenente gli ultimi
aggiornamenti. Come automatizzare
il processo di compilazione? Facile! ef-
fettuate uno scheduling indicando a
nant cosa e come volete compilare e
lui pensa al resto!
Directory: Nant 0.86
DPACK 2005-2008
UN PACCHETTO COMPLETO PER
VS 2008
Il DPack pi che un tool un Add-In
per le versioni di Visual Studio dal 2005
al 2008 e che si integra perfettamente
nell'ambiente. Aggiunge funzioni co-
me Code Browser, File Browser, Solution
Browser, Statistiche, Backup e molto
altro
Directory: Dpack 2005-2008
REFLECTOR 5.1.0
IL DECOMPILATORE PER .NET
forse il tool pi conosciuto tra gli svi-
luppatori .NET e non solo perch uti-
lissimo ma anche perch costante-
mente aggiornato e gratuito. Si tratta
di un software che sfrutta la reflection
di .NET per risalire al contenuto degli
assembly .NET. Questo consente di ri-
salire alla logica di funzionamento di
un codice anche quando non se ne han-
no a disposizione i sorgenti
Directory: Reflector 5.1.0
ASP.NET VERSION
SWITCHER 2008
MODIFICARE AL VOLO LA VER-
SIONE DI ASP.NET
Semplicissimo tool il cui unico scopo
quello di modificare la versione di
ASP.NET utilizzata da una particolare vir-
tual directory di IIS. Questa variazio-
ne in realt potrebbe essere fatta di-
rettamente dalla console di ammini-
strazione ma avere a disposizione una
piccola applicazione che lo fa per voi al
volo, potrebbe essere una comodit
non da poco
Directory: ASP.NET Version Switcher
2008
REFLECTOR 5.1.0
IL DECOMPILATORE PER .NET
forse il tool pi conosciuto tra gli svi-
luppatori .NET e non solo perch uti-
lissimo ma anche perch costante-
mente aggiornato e gratuito. Si tratta
di un software che sfrutta la reflection
di .NET per risalire al contenuto degli
assembly .NET. Questo consente di ri-
salire alla logica di funzionamento di
un codice anche quando non se ne han-
no a disposizione i sorgenti
Directory: Reflector 5.1.0
SNIPPET COMPI-
LER 2.0
PER COMPILARE UN PICCOLO
PEZZO DI CODICE
Un utility che consente di srivere, com-
pilare e fare girare piccoli spezzoni di co-
dice. Molto utile se si vuole provare il fun-
zionamento di una porzione di codi-
ce senza per questo volere creare un
completo progetto con Visual Studio
prima di eseguire il tutto
Directory: Snippet Compiler 2.0
DEV C++ 4.9.9.2
UN EDITOR C++ A BASSO CO-
STO
Dev C++ un editor distibuito su li-
cenza GPL, come tale non ha costi re-
lativi al diritto d'autore. Come tutto o
quasi il software GPL la sua economi-
cit non affatto sinonimo di scarsa
qualit. Al contrario DEV C++ uno
degli editor C++ pi amati ed utilizza-
ti da chi sviluppa in C++. Le caratteri-
stiche sono notevoli. Si va dal debugger
integrato, al project management, al
class browser, al code completion.
L'insieme di queste caratteristiche uni-
te all'eccezionale leggerezza dell'am-
biente lo rende particolarmente co-
modo da utilizzare per sviluppare pro-
getti C++ anche di grandi dimensioni
Directory: Dev C++ 4.9.9.2
WXWIDGETS 2.8.4
COMODE LIBRERIE PER LO SVI-
LUPPO DI INTERFACCE GRAFI-
CHE
Interessantissime queste librerie, pi
volte le abbiamo utilizzate all'interno
di ioProgrammo per realizzare degli
esempi. Si tratta di librerie che con-
sentono la creazione di interfacce gra-
fiche, possono essere utilizzate da C++
ma anche da altri linguaggi come ad
esempio Python. La cosa estremamente
interessante che consentono lo svi-
luppo di applicazioni completamente
multipiattaforma, sono disponibili in-
fatti sia in ambiente unix che in am-
biente Windows.
Directory: wxWidgets 2.8.4
ULTIMATE ++ 2008
IL NUOVO IDE PER C++
Completo e ben fatto questo IDE che
si affaccia alla programmazione ten-
tando di rubare la scena al ben pi no-
to DEV C++. Dotato di code comple-
tion e sintax highlighting, un ottimo
debugger e votato persino ad essere un
ambiente RAD programmabile a mez-
zo form come accade negli IDE pi bla-
sonati. Certo in questo senso ha anco-
ra molto da crescere, tuttavia si pone
come un ottimo IDE freeware e alter-
nativo a DEV C++
Directory: Ultimate ++ 2008
YUI - YAHOO
LIBRARY 2.4.1
IL FRAMEWORK FACILE PER JA-
VASCRIPT
Bottoni, Tabsheet, Menu a scomparsa,
effetti speciali, il Web 2.0 costellato
di interfacce simili a quelle lato desk-
top. Come possibile tutto ci? la ri-
sposta semplice: JavaScript. YUI un
framework JavaScript sponsorizzato
da Yahoo e che rende semplice la pro-
grammazione di interfacce per il web in
linguaggio JavaScript. Il framework
veramente ben fatto e contiene una se-
rie di funzionalit che coprono quasi
tutto lo specchio possibile dei compo-
106-109:106-108-software 1-04-2008 17:12 Pagina 107
ht t p: / / www. i opr ogr ammo. i t
SOFTWARE SUL CD M
G
108
/Maggio 2008
Librerie e Tool di sviluppo
nenti utili nella progettazione grafica
di un'applicazione. Si tratta di una di
quelle librerie che realmente accelera il
lavoro di qualunque programmatore
Web.
Directory: YUI - Yahoo Library 2.4.1
RICO 1.1.2
DRAG & DROP CON AJAX
Un altro interessante framework Java-
Script orientato ovviamente al Web 2.0.
Offre alcune particolarit interessanti co-
me il drag & drop ed effetti particolar-
mente spettacolari per arricchire
l'interfaccia. Lo stile quello dei beha-
viour gi utilizzati in Flex e Openlaszlo.
E' sufficiente inserire in qualche div al-
cune righe di JavaScript et voil il gio-
co fatto!
Directory: Rico 1.1.2
TOMCAT 6.0.9
IL SERVLET CONTAINER PER JA-
VA E JSP
L'idea molto semplice. Sviluppare im
Java pagine Web. Ad un primo sguardo,
Tomcat potrebbe sembrare un norma-
le Web Server.
Ed in effetti un normale Web Server! In
grado di soddisfare le richieste per qua-
lunque pagina HTML. In realt per
Tomcat anche qualcosa in pi, ovve-
ro la capacit di soddisfare le richieste
per applicazioni Java. Potrebbe sem-
brare complesso, in realt lo meno di
quanto sembri. Immaginate Tomcat co-
me un grande contenitore al cui inter-
no ci sono altri contenitori ciascuno
dei quali rappresenta un'applicazione
Java, che una volta richiamata costrui-
sce una pagina Web interpretabile da
un browser. Questo consente di svi-
luppare pagine Web utilizzando tutta
la potenza della normale gerarchia del-
le classi Java e la sintassi e il linguaggio
che qualunque programmatore Java co-
nosce bene.
Directory: Tomcat 6.0.9
ZKOSS 3.0.0
IL FRAMEWORK AJAX IN TECNO-
LOGIA MOZILLA
ZK un Ajax web framework che facili-
ta lo sviluppo di Rich Internet Applica-
tion aderenti alle indicazioni del Web
2.0. Il progetto Open Source ed pos-
sibile scegliere tra due diverse tipolo-
gie di licenza (stessa politica adottata
da MySQL): GPL o commerciale. La co-
struzione dellinterfaccia grafica rea-
lizzata tramite il linguaggio di markup
ZUL, un diretto discendente del pi
famoso XUL utilizzato nella costruzio-
ne di applicazioni basate su Mozilla.
Directory: ZKOss 3.0.0
ANIMADEAD 2.0
PER CREARE ANIMAZIONI PAR-
TENDO DA UNO SCHELETRO
Una libreria che sfrutta il concetto di
skeletal animation. Si inizia disegnan-
do con un qualunque ambiente 3D lo
scheletro di un soggetto, su questo sche-
letro si costruiscono i movimenti che
saranno pilotati dalla libreria. Si tratta
di un progetto per alcuni versi ancora em-
brionale, ma che lascia intravedere un
approccio piuttosto innovativo all'ani-
mazione di modelli tridimensionali
Directory: Animadead 2.0
PIRCBOT 1.4.4
UN BOT IRC PROGRAMMABILE
IN JAVA
Interessante questa idea di fornire agli
amanti di IRC una serie di API che con-
sentono di programmare un bot utiliz-
zando Java.Normalmente chi si dedica
a questo tipo di applicazioni utilizza
Eggdrop e programma in TCL, in tutti e
due i casi non si tratta di tecniche di
larga diffusione, viceversa Java un lin-
guaggio che gode di un'immensa po-
polarit, per cui il poter programmare
dei bot attraverso la flessibilt di Java
rappresenta senza dubbio un'oppor-
tunit interessante
Directory: Pircbot 1.4.4
J2ME POLISH 2.0
IL COSTRUTTORE DI GUI PER DE-
VICE MOBILI
J2ME polish forse un precursore dei
tempi. Si tratta di un software il cui sco-
po supportare il programmatore nel-
la creazione di interfacce destinate a
dispositivi portatili quali ad esempio
cellulari o palmari. Ovviamente la ba-
se su cui si fonda J2ME ormai onni-
presente in qualsiasi applicazione per
dispositivi del genere, tuttavia invece
la definizione dell'interfaccia basa le
sue caratteristiche su semplici file HTML.
Interessante il fatto che J2MEpolish
sia distribuito sotto licenza GPL
Directory: J2me Polish 2.0
JAVA SE DEVELOP-
MENT KIT 6 6.0
IL COMPILATORE INDISPENSABI-
LE PER PROGRAMMARE IN JAVA
Se avete intenzione di iniziare a pro-
grammare in Java oppure siete gi dei
programmatori esperti avete bisogno
sicuramente del compilatore e delle li-
brerie indispensabili. Sotto il nome di Ja-
va SE Development Kit vanno appunto
tutti gli strumenti e le librerie nonch le
utility necessarie per programmare in
Java. L'attuale versione la 6.0 molto
pi legata al desktop di quanto non fos-
sero tutte le precedenti
Directory: Java SE Development Kit
6 6.0
ECLIPSE SDK 3.2.2
L'IDE TUTTOFARE
Eclipse un progetto completo porta-
to avanti da Eclipse Foundation con la
collaborazione di una miriade di azien-
de fra cui IBM, Adobe, Sun e che si
prefissata lo scopo di creare un IDE
estendibile per plugin adattabile a qua-
lunque tipo di linguaggio o tecnologia.
Di default Eclipse si propone come IDE
per Java ed qui che da il meglio di se.
Ma proprio grazie ai suoi plugin pos-
sibile utilizzarlo come ambiente di pro-
grammazione per PHP, per C++, per Flex
e per molti altri linguaggi ancora. Inol-
tre sempre grazie per ciascun linguag-
gio sono disponibili altri plugin ad esem-
pio per rendere l'ambiente RAD o per fa-
vorire lo sviluppo dei Web Services o
altro.
Insomma lo scopo stato raggiunto
completamente. Eclipse realmente
un IDE tuttofare, ormai maturo, e che ser-
ve una miriade di programmatori gra-
zie alle sue caratteristiche di affidabilit
e flessibilit. Unica nota negativa: una
certa pesantezza che lo rende idoneo
ad essere usato solo su PC con una do-
tazione hardware minima di tutto ri-
spetto
Directory: Eclipse SDK 3.2.2
PHP 5.2.1
IL LINGUAGGIO DI SCRIPTING
PI AMATO DEL WEB
Sono tre le colonne portanti di Inter-
net: PHP, APACHE e MySQL. Certo la
concorrenza forte. Asp.NET e SQL Ser-
ver avanzano con celerit, ma a tutt'og-
gi non si pu affermare che i siti svi-
106-109:106-108-software 1-04-2008 17:12 Pagina 108
ht t p: / / www. i opr ogr ammo. i t
M SOFTWARE SUL CD
Maggio 2008/
109
G
Librerie e Tool di sviluppo
luppati in PHP costituiscano la stra-
grande maggioranza di Internet. Qua-
li sono le ragioni del successo di co-
tanto linguaggio? Prima di tutto la com-
pletezza.
PHP ha di base tutto quello che serve
ad un buon programmatore, raramen-
te necessario ricorrere a librerie ester-
ne, e quando proprio indispensabile
farlo esistono comunque una serie di
repository che rendono tutto imme-
diatamente disponibile ed in forma gra-
tuita.
Il secondo punto di forza del linguaggio
sta nella sua capacit di poter essere
utilizzato sia in modo procedurale che
nella sua forma ad oggetti certamente
pi potente e completa. Esiste un terzo
di punta di forza essenziale che quel-
lo riguardante la curva di apprendi-
mento.
PHP in assoluto uno dei linguaggi con
la curva di apprendimento pi bassa
nel panorama degli strumenti di pro-
grammazione. Si tratta perci di uno
strumento indispensabile per chi si avv-
vicina alla programmazione web, a me-
no che non intendiate scegliere strade
diverse quali possono essere ASP.NET o
JSP
Directory: PHP 5.2.1
SIMPLE MACHINE
FORUM 1.1.4
PER CREARE AGEVOLMENTE SE-
ZIONI FORUM
Per anni su Internet hanno dominato la
scena forum del calibro di PHPbb, VBul-
lettin, Invision, da qualche tempo a que-
sta parte a contendere lo scettro del mi-
gliore a questi mostri sacri arrivato
Simple Machine Forum, per gli amici:
SMF.Si tratta di un forum che ancora
non ha tutte le caratteristiche dei suoi
rivali ma che procede a ritmi serrati nel-
lo sviluppo e promette realmente bene.
La versione 1.1.4 che vi presentiamo
contiene gi un nutrito numero di fun-
zionalit ed un wizard realmente semplice
per l'installazione di addon. La 2.0 pros-
sima ventura annunciata con tutte le
caratteristiche degne dei suoi rivali e an-
che qualcosa in pi. Si tratta di un fo-
rum su cui scommettere se si vuole in-
stallare qualcosa di realmente innova-
tivo e con larghi orizzonti.
Directory: Simple Machine Forum
1.1.4
MYSQL 5.1.15
IL PRINCIPE DEI DATABASE
Indispensabile per programmare we-
bapplication in tecnologia PHP. Non-
che non sia possibile utilizzare altrida-
tabase, ma MySQL e PHP rappresenta-
no veramente un binomioinscindibi-
le. L'integrazione fra questo database
e il linguaggio di scripting pi usato sul-
la rete talmente alta da fare divenire
quasi un obbligo l'uso congiunto di
questi due strumenti
Directory: MySQL 5.1.15
DADABIK 4.2
UN CREATORE DI INTERFACCE
VERSO DATABASE
Si tratta di una web application scrit-
ta in PHP che consente di costruire
altre web application basate su data-
base. Ad esempio se volete costruire
un sito che esponga un catalogo mul-
timediale, non vi resta che informare
Dadabik di quali campi si compone il
catalogo in questione, di quali funzio-
nalit volete che il vostro sito sia
dotato, e lasciare a DadaBik il compi-
to di generare la vostra interfac-
cia.Non necessario avere compe-
tenze estese di programmazione,
l'uso di DadaBik piuttosto semplice.
Directory: Dadabik 4.2
POSTGRESSQL
8.2.5
IL DATABASE DELLE MERAVIGLIE
Postgres a pieno titolo una delle
meraviglie del mondo dei database.
Completo, performante, dotato di
tutte le funzioni principali che si
attribuiscono ad un database profes-
sionale. Stored Procedure, triggers,
gestione avanzata della sicurezza con
controllo fino al singolo campo, tutta
una serie di caratteristiche che lo
posizionano al top della categoria. In
pi Postgres realmente estendibile.
Contiene in se meccanismi per creare
funzioni e procedure che costituisco-
no il valore aggiunto di questo gi
dotatissimo database
Directory: Postgressql 8.2.5
MYSQL
WORKBENCH 5.0.12
BETA
IL PROGETTISTA DI DATABASE
Quante volte usando MySQL avete
rimpianto quella parte di Access che
vi consente di disegnare e collegare
graficamente le tabelle fra di loro?
Sicuramente tante. E non perch
Access sia minimamente comparabi-
le con MySQL ma solo e soltanto per-
ch realmente progettare un database
un'operazione che prende molto
meno tempo se possibile disegnare
un grafico di correlazione delle tabel-
le. MySQL Workbench assolve proprio
a questa funzione, si tratta di un uti-
lissimo programma che rende pi
comoda la progettazione di un DB,
mettendo a disposizione del progetti-
sta una sorta di lavagna in cui dise-
gnare graficamente le tabelle e le loro
relazioni, oltre alle viste e alle altre
molte cose che MySQL consente di
fare
Directory: MySQL Workbench 5.0.12
beta
MYSQL GUI 5.0
IL GESTORE DI MYSQL
Gestire MySQL un problema? Creare
nuovi database? Creare nuovi uten-
ti?In soccorso vi viene questa ottima
Gui attraverso la quale potete gestire
in modo realmente semplice tutte le
funzionalit del vostro database pre-
ferito.Si tratta di una Gui realizzata
proprio da MySQL AB per cui decisa-
mente affidabile e completa
Directory: MySQL GUI 5.0
PGADMIN III
3.1.8.2.2
L'INTERFACCIA DI GESTIONE DI
POSTGRES
PostgreSQL un database eccezional-
mente potente, forse il pi completo
oggi disponibile. Il suo tallone
d'achille risiede probabilmente nella
difficolt del linguaggio che ne la
base. Per evitare lo scontro con una
sintassi non sempre chiara c'
pgAdmin, una comoda interfaccia
grafica attraverso la quale si possono
gestire tutte le funzionalit di un ser-
ver Postgres in modo semplice ed
ottimale. Postgres rimane un databa-
se incredibilmente evoluto, che fa
dell'estendibilit uno dei dei suoi
punti di forza grazie al suo linguaggio
interno
Nome Programma: PGadmin III
3.1.8.2.
106-109:106-108-software 1-04-2008 17:12 Pagina 109
ht t p: / / www. i opr ogr ammo. i t
M
Soluzioni
Maggio 2008/
111
G
Analisi dei log e simulazione dellazione
A
scopo di intrattenimento sono sempre pi
diffusi sul web animazioni che simulano
uno sport, come una partita di calcio, una
corsa di cavalli, un incontro di tennis o quantaltro.
Non solo. Spesso si incontrano giochi e applicazioni
che consentono di indicare dei parametri per il
gioco o sport che si intende rappresentare, come
labilit dei singoli atleti per compiti specifici, ed in
funzione di routine che usano componenti random.
Si pu assistere cos ad una partita dove non vi
alcuna interazione con lutente ma che fornisce un
risultato. In altre parole come una procedura
batch in cui si stabiliscono inizialmente alcuni
aspetti generali e in un secondo momento si avvia la
simulazione. Ad esempio se parliamo di calcio, si
possono a priori stabilire le abilit dei singoli calcia-
tori, come la forza di gioco, ma anche secondo
aspetti particolari come: lagilit, la precisione, il tiro
e cos via. Inoltre, si possono impostare alcuni
aspetti generali come la condizione del campo.
Stabilito ci, si avvia la simulazione che avr il com-
pito di produrre un file di log. Questo file descriver
lintero incontro, azione per azione. A questo punto
affinch un opportuno client di un programma di
animazione come flash possa interpretare il risulta-
to ottenuto necessario trasformare il file di log
prodotto in un opportuno file, utile ad essere inter-
pretato. In questo articolo affronteremo le prime
parti riferite ad uno sport relativamente semplice
per essere trattato, come il tennis, e per esso vedre-
mo come si possano stabilire e strutturare dei para-
metri che descrivono le condizioni iniziali del gioco.
Infine, daremo indicazioni su come costruire il
codice che simula lincontro producendo un file di
log. Tale file potr facilmente essere tradotto in un
altro file secondo la sintassi del client di animazione
che si sta usando.
UN ESEMPIO
CONCRETO: IL TENNIS
La scelta del tennis individuale come sport per effet-
tuare un concreto esempio, stata fatta per la rela-
tiva semplicit che esso esprime, dovuta principal-
mente al fatto che non si tratta di uno sport di squa-
dra. In realt come vedremo, nonostante considere-
voli semplificazioni al fine di rendere pi chiaro e
comprensibile il percorso di costruzione della simu-
lazione, la struttura del programma tuttaltro che
semplice. Ad ogni modo compresa la filosofia che
sottende il ragionamento sar facile per il lettore
ampliare lapplicazione con ulteriori aspetti tecnici.
A tale proposito anticipo che non sono un esperto
di tale sport e quindi inevitabilmente mi capiter di
tralasciare alcuni aspetti tecnici sicuramente signi-
ficativi. Ogni riga del file di log, uno file di testo stan-
dard, contiene unazione completa. Ogni azione
consiste di due semi azioni, associate alle attivit dei
due tennisti. Entreremo successivamente sugli
aspetti squisitamente tecnici della questione, per
adesso utile ricordare che ogni giocatore pu tro-
varsi ad effettuare una tra diverse attivit come la
battuta, la corsa o spostamento, il rovescio, il dritto,
la schiacciata e cosi via. Ed ognuna di queste attivit
accompagnata da parametri come la forza e la
precisione per la battuta, il dritto, la schiacciata ed il
rovescio; e come la velocit per altri come la corsa o
spostamento. Risulta evidente che nel caso del ten-
nis i parametri che vanno settati inizialmente
riguardano le caratteristiche di abilit del singolo
giocatore che possono esprimersi con
unopportuna scala numerica. Come nella realt il
giocatore pi forte ha pi chance di vincere, ma
analogamente alla realt vedremo come giocher
un ruolo importante anche la variabile aleatoria.
STRUTTURA DEI DATI
In questo paragrafo individueremo le informazioni
per descrivere una incontro completo, una scelta
del tutto personale, ovviamente modificabile ed
ampliabile. Inoltre, stabiliremo oltre alle attivit
possibili quelle previste, ed in che scala possono
essere descritte. Le prime informazioni riguardano
SIMULAZIONE
RANDOM DI GIOCHI
COME COMANDARE DEI CLIENT DI ANIMAZIONE COME FLASH SIMULANDO GIOCHI O SPORT. LA
SOLUZIONE PRODURRE FILE DI LOG COSTRUITI INTORNO A DEI PARAMETRI DI GIOCO E CON
UNA FORTE COMPONENTE CASUALE
Conoscenze richieste
Basi di
programmazione sul
web
Software
nessuno
Impegno
Tempo di realizzazione
REQUISITI
110-114:032-035 1-04-2008 17:18 Pagina 111
ht t p: / / www. i opr ogr ammo. i t
Soluzioni
M
G
112
/Maggio 2008
Analisi dei log e simulazione dellazione
il contendenti. Come per le altre che esamineremo
le descriveremo in forma tabulare, sapendo che
questi dati possono essere memorizzati in modo
permanente su un file o meglio in una tabella di un
db. I dati salienti rispetto ai giocatori sono:
la prima riga che indica il tracciato record relativo
al tennista. Da notare che la lista di giocatori pu
essere corposa. Nel momento in cui si dovr dispu-
tare un incontro bisogner scegliere due tennisti.
Sar lindice (identificativo numerico del tennista -
IDGT) lelemento a cui fare riferimento successiva-
mente per distinguere un tennista. Un altro fonda-
mentale nucleo informativo riguarda lattivit che
un singolo tennista pu effettuare. Quelle previste
per una basilare simulazione sono:
Esisteranno informazioni che mettono in relazione
il singolo giocatore con le attivit da svolgere, si trat-
ta delle abilit. Come detto per ogni giocatore biso-
gna prestabilire le skills che verranno indicate
rispetto ad una scala di valori. Una scala particolar-
mente adatta e intuitiva si sviluppa su 101 valori da
0, che indica assenza di abilit a 100 che invece spe-
cifica il massimo delle capacit. Cosicch ogni gio-
catore avr la sua scheda informativa, che esiste
ovviamente anche nella realt, dove si desume dai
risultati medi rispetto a quella attivit. Nella scheda
per ogni attivit e rispettivo parametro si indicher
un valore. Ecco un esempio per il giocatore 2.
facile intuire come leggere tale tabella. Il giocato-
re con identificativo 2, che nel nostro esempio
Walter Beltrame ha come abilit media per
lattivit 1, ossia la battuta: 70 di forza e 50 di preci-
sione; e cos via. Da notare che per lo spostamento
i parametri indicano altri aspetti che non sono le
solite forza, e precisione, bens come si nota dalla
tabella attivit direzione e velocit. Di questi due il
secondo parametro pu essere espresso come
unabilit del tennista, il primo no cosicch contie-
ne il valore -1, il che indica appunto che non si trat-
ta di unabilit. Stessa cosa per lattesa. Questa
tabella sar il punto di partenza quando bisogner
produrre unazione, vedremo che si applicher una
funzione casuale a partire per dalle abilit posse-
dute. Quindi se ad esempio la forza con cui un ten-
nista tira il rovescio mediamente 80 (ricordo che
riferita in una scala da 0 a 100), allora ci saranno
buone possibilit che la forza effettiva della perfor-
mance sia 80 o un valore vicino ad esso, non si
esclude per, anche se con probabilit minore, che
si producano valori sensibilmente diversi da 80.
Inoltre, va considerato che non sempre valori alti
indicano ottimi risultati. Per la volet ad esempio, il
tocco leggero sotto rete, la forza deve essere bassa,
altrimenti il tiro risulta sbagliato, mentre la precisio-
ne deve essere alta. Le informazioni fino ad ora esa-
minate riguardano i giocatori e le loro caratteristi-
che, ma non entrano nel merito di una sfida, una
reale partita. Per esprimere una partita bisogner
sequenziare delle azioni, viste come un insieme di
semi azioni, svolte cio da un tennista e dal suo
avversario. Se ad esempio uno dei due giocatori
risponde ad un tiro di rovescio, laltro verosimil-
mente si sposter per riconquistare una posizione
ottimale. Unazione che sar lelemento centrale di
cui tenere traccia per descrivere una partita pu
essere espressa da un tracciato record. Come al soli-
to lo accompagniamo ad un esempio in cui si istan-
ziano valori.
Come si legge? La prima colonna scandisce i tempi
delle azioni che potrebbero essere espressi in deci-
mi di secondo. Le successive quattro colonne fanno
riferimento ad informazioni per un tennista, in par-
ticolare il codice del tennista, il codice dellazione
20
42
39
1
2
3
70
80
70
90
80
90
2
1
2
8
6
7
0
40
45
0
20
50
1
2
1
Tempo IDNT IDNA Par_1 Par_2 IDNT IDNA Par_1 Par_2
Tabella 4 - Azioni Alcune azioni di un incontro
1
2
3
Gianni Potente
Walter Beltrame
Gaspare Soffritti
Gpot.jpg
Walterb.jpg
Gasparr.ipg
IDNT Nominativo Pic
Tabella 1 - Tennisti - Elenco dei tennisti
1
2
3
4
5
6
7
8
Forza
Forza
Forza
Forza
Forza
Forza
Direzione
Battuta
Rovescio
Diritto
Schiacciata
Volet
Seconda Battuta
Spostamento
Attesa
Precisione
Precisione
Precisione
Precisione
Precisione
Precisione
Velocit
IDNA Nome_at Par 1 Par 2
Tabella 2 - Attivit - Elenco delle possibili attivit
1
2
3
4
5
6
7
8
70
80
60
70
20
50
-1
-1
50
90
60
50
70
30
60
-1
IDNA Par 1 Par 2
Tabella 3 - Abilit- Parametri riferiti ad uno specifico giocatore
110-114:032-035 1-04-2008 17:18 Pagina 112
ht t p: / / www. i opr ogr ammo. i t
che ha eseguito, i parametri riferiti allazione espres-
si secondo la scala citata, come la forza e la precisio-
ne. Analogamente le altre quattro colonne sono rife-
rite allazione dellavversario. Di questo e di come
tenerne traccia tratteremo pi approfonditamente
avanti. Per la direzione il numero indicato specifica
in quale parte del campo muoversi. Si pu pensare
di partizionare il campo in 101 parti e numerarle.
Unaltra importante nozione riguarda il punteggio. Il
risultato corrente di un incontro si pu mantenere
in un tabellone fatto semplicemente come segue:
Dal tabellone oltre al punteggio al momento acqui-
sito dai due tennisti si riesce a dedurre in quale fase
della partita ci si trova, ossia in quale: set, gioco e
punto. Nellesempio riportato ci troviamo al set 2
(secondo), gioco 8 (ottavo) e punto 4 (quarto).
Questi ultimi dati servono ad esempio a stabilire chi
deve battere. Le informazioni di cui tener conto
sono tante, nonostante come detto si voluto espli-
citamente mantenere il problema ad un livello di
astrazione tale da renderlo semplice. Si capisce ad
esempio facendo un paragone rispetto al calcio, che
nel tennis sebbene possa essere relativamente pi
semplice la gestione delle azioni di gioco, le cose si
complicano leggermente quando si deve gestire il
punteggio.
LA PRODUZIONE DI FILE
Il programma che si intende costruire deve produr-
re dei file. Un file tiene traccia di tutte le azioni svol-
te nel campo da tennis. Abbiamo visto con la tabella
4 come descrivere unazione, ossia con linsieme di
due semi azioni ottenute come attivit dei due con-
tendenti. Il file principale di log conterr quindi una
sequenza di righe che rappresentano azioni cos
come descritte nella tabella citata. Nel file ci sar
una prima riga di intestazione che contiene gli iden-
tificativi dei due giocatori, il luogo, la data, lora e il
turno. Il nome assegnato al file sar incontro seguito
da informazioni che lo contraddistinguono da altri
incontri, come un numero progressivo o insiemi di
altre informazioni legate allevento ma che comun-
que indichino in modo univoco la partita. Il file
dovr essere di testo per il suo carattere universale,
facile da essere trattato da terze parti. Un esempio di
questo file riportato di seguito (figura 1), si tratta di
una sequenza cos come riportata in tabella 2.
Bisogner per memorizzare in modo permanente
anche altre informazioni generali, come la lista dei
giocatori a disposizione, seguendo le indicazioni di
tabella 1; la lista delle azioni e dei significati, tabella
2 e un file di abilit in cui sono riportate in sequenza
una serie di righe che indicano le abilit dei singoli
tennisti, come una serie di tabelle 3, una per ogni
giocatore.
Un altro file che bisogna associare ad un singolo
incontro il punteggio, in modo da tenere traccia di
tutte le variazioni. necessario poich il tabellone
fotografa la sola situazione attuale e non rappresen-
ta come si arrivati a tale punteggio. Il file punteggio
pu essere espresso come mostrato in figura 2.
Individuata unopportuna struttura dati da realizza-
re sia per luso run-time, quindi come una serie di
vettori di record; che per la memorizzazione perma-
nente, appunto come files, ma si potrebbe pensare
anche ad un database, bisogna passare allimple-
mentazione.
IMPLEMENTAZIONE
Il programma principale sar scandito da una serie
di cicli innestati, riferiti ai quattro diversi livelli di
punteggio che si possono ottenere: partita, set, gio-
chi e punti. Nel ciclo pi interno si produrr una
nuova azione. Ecco come si pu costruire in C++ il
programma principale.
void partita ()
{ int ris;
tennista1=caricatennista();
tennista2=caricatennista();
M Soluzioni
Maggio 2008/
113
G
Analisi dei log e simulazione dellazione
1
2
1
1
3
5
3
5
IDNT Set Gioco Punto
Tabella 5 - Tabellone Punteggio attuale
Figura 1: Il file che rappresenta lincontro con le sue
azioni.
Figura 2: Il file che rappresenta il punteggio e la sua
evoluzione.
110-114:032-035 1-04-2008 17:18 Pagina 113
ht t p: / / www. i opr ogr ammo. i t
int set=1;
int azio=0;
bool fineset=false;
bool finepartita=false;
do // ripete fin quando non finisce la partita
{ int gioco=1;
bool finegioco=false;
do // ripete fin quando non finisce il set
{ int punto=0;
do // ripete fin quando non finisce il gioco
{ do // ripete fin quando non si
fa un punto
{ ris=fai_azione(++azio,
set, gioco, punto);
} while (ris!=0) ;
aggiorna_punteggio(ris, set,
finepartita, gioco, finegioco, punto);
} while (!finegioco)
} while (!fineset)
} while (!finepartita) }
Con le tre variabili: set, gioco e punto si riesce a sta-
bilire in che fase del gioco ci si trova, ossia in quale
set, gioco e punto. Le tre variabili booleane: finepar-
tita, finegioco e finepunto invece permettono di
indicare la fine delle rispettive cadenze di gioco.
Tutto ruota intorno al risultato della funzione
fai_azione(..) che produce un risultato. Il risultato
non necessariamente coincider con lassegnazione
di un punto. In altre parole unazione non altro che
linsieme di due semiazioni svolte dai due antagoni-
sti. Cos al termine di essa pu accadere che si pro-
dotto un punto oppure no. Per convenzione diremo
che se il valore restituito zero allora non si pro-
dotto un punto, quindi continueranno gli scambi tra
i tennisti. Se il valore 1 si intende punto per il
primo giocatore, se il valore 2 allora punto per il
secondo giocatore. Si rimane nel ciclo pi interno
fino a quando lazione non produce un punto. Qui si
aggiorna il punteggio con lomonima funzione.
utile ricordare che lassegnazione di un punto pu
modificare la situazione dei giochi, dei set e della
partita. La variabile azio conteggia tutte le azioni
giocate. Ritorniamo sulla funzione pi importante.
Analizziamo in sintesi cosa deve fare fai_azione:
- Produrre unazione come insieme di due semi
azioni;
- Gestire la produzione di un risultato conclusivo,
che non necessariamente si verifica;
- Registrare nel file di log, chiamato incontroxxx
(figura 1) tutti i particolari dellazione secondo la
sintassi stabilita;
Ecco come implementare:
int fai_azione(int pazio, int pset, int pgioco, int
ppunto)
{ int pris=0;
rec1=fai_semiazio(pazio,ppunto);
rec2=fai_semiazio(pazio,ppunto, rec1);
ris=risultato(rec1,rec2);
registra(rec1,rec2);
return pris;
}
Due funzioni con overloading con due e tre parame-
tri producono sulla base delle caratteristiche dei gio-
catori due semi azioni. La seconda dipende anche
dalla semiazione prodotta dal primo giocatore. I
risultati saranno due record chiamati rec1 e rec2 che
contengono tutte le informazioni necessarie per la
produzione del risultato (funzione risultato) e per la
registrazione nel file di log (funzione registra).
Merita un approfondimento la funzione
fai_semiazio nella fase in cui deve produrre
unattivit con le relative caratteristiche.
Supponiamo che il tennista debba fare un tiro dirit-
to, la funzione deve produrre in output la forza e la
precisione del tiro. Per farlo si pu usare una funzio-
ne random gaussiana, ossia una funzione che abbia
maggiori probabilit di produrre un valore prestabi-
lito che nel caso specifico labilit media, mentre
con meno probabilit valori lontano dalla media, sia
che si tratti di un colpo sbagliato (lontano a sinistra
della media) sia che si tratti di un colpo ottimo (lon-
tano a destra della media).
CONCLUSIONI
Lultimo anello della catena prevede la traduzione
dei file prodotti dallapplicazione in file comprensi-
bili dai client di animazione. A tale proposito biso-
gna studiare la sintassi dei vari client e produrre
delle animazioni adeguate per essere interpretate. Si
devono tradurre in animazione tutte le attivit pre-
viste e parametrizzarle come spiegato. Ad esempio
bisogna sviluppare un animazione di un tennista
che fa la battuta, che sar precisa e forte come indi-
cata nel file di log.
Fabio Grimaldi
Soluzioni M
G
114
/Maggio 2008
Analisi dei log e simulazione dellazione
DISTRIBUZIONE GAUSSIANA
Molti fenomeni della natura
vengono descritti dalla
distribuzione di Gauss. Nel caso
specifico, attraverso la
distribuzione, si possono
rendere pi probabili i valori
intorno alla media, nel grafico
indicati dalla banda blu, e
meno probabili gli altri valori.
110-114:032-035 2-04-2008 12:09 Pagina 114

Potrebbero piacerti anche