From bcc95cd92ca12c1783464b8ada6816d430dc0e98 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 18 Dec 2011 03:08:08 -0600 Subject: Initial import of libqt-perl (not yet TQt compatible) --- doc/css/pod.css | 132 ++++++ doc/en/Makefile | 7 + doc/en/PerlQt.pod | 1147 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/en/index.html | 1081 +++++++++++++++++++++++++++++++++++++++++++++ doc/fr/Makefile | 7 + doc/fr/PerlQt.pod | 1189 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc/fr/index.html | 1120 +++++++++++++++++++++++++++++++++++++++++++++++ doc/images/ex1.png | Bin 0 -> 2569 bytes doc/images/ex2.png | Bin 0 -> 3578 bytes doc/images/pqtsh.png | Bin 0 -> 55385 bytes 10 files changed, 4683 insertions(+) create mode 100644 doc/css/pod.css create mode 100644 doc/en/Makefile create mode 100644 doc/en/PerlQt.pod create mode 100644 doc/en/index.html create mode 100644 doc/fr/Makefile create mode 100644 doc/fr/PerlQt.pod create mode 100644 doc/fr/index.html create mode 100644 doc/images/ex1.png create mode 100644 doc/images/ex2.png create mode 100644 doc/images/pqtsh.png (limited to 'doc') diff --git a/doc/css/pod.css b/doc/css/pod.css new file mode 100644 index 0000000..6f7bd52 --- /dev/null +++ b/doc/css/pod.css @@ -0,0 +1,132 @@ +/* standard elements */ +body + { + background: #FFFFFF; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + } +p + { + color: #000000; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + } +blockquote + { + color: #000000; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + } +ul + { + color: #000000; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + list-style-type: disc; + } +ol + { + color: #000000; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + } +h1 + { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 18px; + font-weight: bold; + color: #2660C9; + } +h2 + { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + font-weight: bold; + color: #2660C9; + background-color: #EAE2BB; + } +h3 + { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + font-weight: bold; + color: #000000; + } +h4 + { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; + font-weight: bold; + color: #2660C9; + } + +pre + { + font-size: 120%; + padding-bottom: 5px; + } +tt + { + font-size: 120%; + } +code + { + font-size: 120%; + } +kbd + { + font-size: 120%; + } + +/* documentation link formatting */ +a:link + { + color: #2660C9; + text-decoration: underline; + } +a:visited + { + color: #2660C9; + text-decoration: underline; + } +a:hover + { + color: #000000; + text-decoration: underline; + } +a:active + { + color: #2660C9; + text-decoration: underline; + } +.docsubheading + { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + font-weight: bold; + color: #B82619; + background-color: #EAE2BB; + } +.docsubheadinggrey + { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + font-weight: bold; + color: #B82619; + background-color: #cccccc; + } +.error + { + color: #B82619; + } +.err + { + color: #B82619; + } + +/* unordered list without bullets */ +ul.sans + { + list-style-type: none; + } + diff --git a/doc/en/Makefile b/doc/en/Makefile new file mode 100644 index 0000000..1d300c0 --- /dev/null +++ b/doc/en/Makefile @@ -0,0 +1,7 @@ + +index.html: PerlQt.pod + pod2html --css ../css/pod.css PerlQt.pod > index.html + perl -pi -e 's/cgibin/cgi-bin/' index.html + perl -pi -e 's/#http/http/g' index.html + rm -f pod2*~~ + diff --git a/doc/en/PerlQt.pod b/doc/en/PerlQt.pod new file mode 100644 index 0000000..b05a0a9 --- /dev/null +++ b/doc/en/PerlQt.pod @@ -0,0 +1,1147 @@ + +=head1 Programming PerlQt + +B + +This document describes a set of Perl bindings for the Qt toolkit. Contact +the author at + +=head1 Introduction + +PerlQt-3 is Ashley Winters' full featured object oriented interface to +L's C++ Qt toolkit v3.0. + +It is based on the +L +library, a language independent low-level wrapper generated from Qt headers by +Richard Dale's +L +thanks to David Faure's module. + +This document describes the principles of PerlQt programming. +It assumes you have some basic Perl Object Oriented programming knowledge. + +Some C++ knowledge is recommended but not required. +It would mostly help you to find your way through L which is our +ultimate and only reference. +If Qt is installed on your system, then you most probably +also have its documentation. Try the C<$QTDIR/bin/assistant> program. + + +=head1 Installation + +=head2 Requirements + +To compile and use PerlQt, you'll need : + +=over 4 + +=item * + +a POSIX system + +=item * + +GNU tools : automake(>=1.5), autoconf (>=2.13), aclocal... + +=item * + +L= v5.6.0|"http://www.perl.org"> + +=item * + +L= +v3.0|"http://www.trolltech.com/developer/download/qt-x11.html"> + +=item * + +L +The SMOKE library (Scripting Meta Object Kompiler) is part of L's B module. +You may want to check if a precompiled version of this module exists for your +system. +PerlQt is packaged with its own copy, so you don't need to check it out. + +=back + +Perl and Qt's installation is out of the scope of this document. Please refer +to those projects' documentation. + +=head2 Compilation + +PerlQt uses GNU's Autoconf framework. However, the standard ./configure script is preferably driven +by the Makefile.PL wrapper. All options are forwarded to ./configure : + + perl Makefile.PL + +If SMOKE is missing, C will generate its sources. +Then : + + make + + make install + +This will install PerlQt, Puic and Smoke (if needed), as well as the pqtsh and pqtapi utilities. + +The preferred install location for SMOKE and Puic is in the KDE3 file system. +If you don't have KDE3 installed, specify a location with C's +C<--prefix> option. e.g: + + perl Makefile.PL --prefix=/usr + +=head2 Troubleshooting and Configure Options + +If Smoke's linking fails or your Qt library was built with very specific +options, run Makefile.PL again with: + + perl Makefile.PL --with-threshold=0 + +When building smoke, configure will check for OpenGL and try to compile +support for it if it is properly installed and supported by Qt. + +You may disable this checking with: + + --disable-GL + +Also, default behaviour is to prefer the Mesa GL library over a proprietary +implementation. +If your system features a proprietary OpenGL library, and you'd like to use +it, specify: + + --without-Mesa + +=head2 How to install PerlQt with user rights + +To install PerlQt without super-user rights, simply follow this procedure: + +=over 4 + +=item * + +Perform a normal configuration, specifying as prefix a directory where you have write permissions : + + perl Makefile.PL --prefix=~ + +The above would install the Smoke library in ~/lib and the puic binary in ~/bin + +=item * + +Reconfigure the Perl module so that it doesn't target the standard perl hierarchy: + + cd PerlQt + perl Makefile.PL PREFIX=~ + cd .. + +Beware : this is not the same Makefile.PL as above, but the one located in the ./PerlQt +subdirectory + +=item * + +Compile and Install + + make && make install + +In order to use such an installation, you must tell to Perl where to find this extern hierarchy. +This can be done either on the command line: + + perl -Mlib="~/local/lib/perl/5.x.x" program.pl + +or at the top of your program: + + use lib qw( ~/local/lib/perl/5.x.x ); + +"5.x.x" should be changed to whatever Perl version your system is running. + +=back + +=head1 Anatomy of PerlQt + +A typical Qt program using GUI components is based on an event loop. + +This basically means that such a program is no more envisioned as a straight +flow where you would need to handle yourself every single events (such as a +mouse click or a key press). + +Instead, you just create an B object, create the GUI components it +uses, +define what objects methods need to be called when an event occurs, +and then start the main event loop. + +That's all! +Qt will handle all events and dispatch them to the correct subroutine. + +Lets see how this process is implemented in a minimal PerlQt program. + +=head2 Hello World + + 1: use Qt; + 2: my $a = Qt::Application(\@ARGV); + 3: my $hello = Qt::PushButton("Hello World!", undef); + 4: $hello->resize(160, 25); + 5: $a->setMainWidget($hello); + 6: $hello->show; + 7: exit $a->exec; + +=for html +
+
+ +This program first loads the Qt interface [line 1] and creates the application +object, passing it a reference to the command line arguments array C<@ARGV> +[l.2]. +This application object is unique, and may later be accessed from +anywhere through the B pointer. + +At line 3, we create a PushButton, which has no parent (i.e : it won't be +contained nor owned by another widget). +Therefore, we pass to the constructor an B value for the parent argument, +which is PerlQt's way of passing a Null pointer. + +After some layouting at [l.4], we tell the application object that our main +widget is this PushButton [l.5]... that way, it will know that closing the +window associated with this widget means : I. + +Now the last steps are to make this widget visible (as opposed to +hidden, which is the default) by calling the B method on it [l.6] and +to start the application loop [l.7]. + +B + +=over 4 + +=item 1 + +All Qt classes are accessed through the prefix B, which replaces the +initial B of Qt classes. +When browsing the L, you simply need to change the +name of classes so that B reads B. + +=item 2 + +An object is created by calling the B of the class. It has the +same name as the class itself. + +You don't need to say C or Cnew()> as most Perl +programmers would have expected. + +Instead, you just say : + + my $object = Qt::(arg_1, ..., arg_n); + + +If you don't need to pass any argument to the constructor, simply say : + + my $object = Qt::; + + +=item 3 + +Whenever you need to pass a Null pointer as an argument, use Perl's B +keyword. Do not pass zero. + Beware: this is by far the most common error in PerlQt programs. + +Pointers are arguments preceded by an B<*> +character in Qt's documentation (e.g: "C"). + +=back + +=head2 Inheritance and Objects + +Before we can discuss how Perl subroutines can be called back from Qt, we need +to introduce PerlQt's inheritance mechanism. + +PerlQt was designed to couple as tightly as possible Qt's simplicity and Perl's +power and flexibility. + +In order to achieve that goal, the classical Object Oriented Perl paradigm had +to be extended, much in the same way than Qt itself +had to extend C++'s paradigm with B. + +=head3 A Custom Widget + +Lets rewrite the "Hello World!" program, this time using a custom version +of PushButton: + + 1: use strict; + 2: + 3: package Button; + 4: use Qt; + 5: use Qt::isa qw(Qt::PushButton); + 6: + 7: sub NEW + 8: { + 9: shift->SUPER::NEW(@_[0..2]); + 10: resize(130, 40); + 11: } + 12: + 13: 1; + 14: + 15: package main; + 16: + 17: use Qt; + 18: use Button; + 19: + 20: my $a = Qt::Application(\@ARGV); + 21: my $w = Button("Hello World!", undef); + 22: $a->setMainWidget($w); + 23: $w->show; + 24: exit $a->exec; + +Here, we want to create our own version of the PushButton widget. +Therefore, we create a new package for it [l.3] and import Qt [l.4]. + +We now want to declare our widget as subclassing PushButton. +This is done through the use of the C pragma [l.5], which accepts a +list of one or more parent Qt classes. + +It is now time to create a B for our new widget. +This is done by creating a subroutine called B I<(note the capitalized +form, which differentate it from the usual "new" constructor. PerlQt's NEW +constructor is called >BI< as can be seen on line 21)>. + +Since we want our widget to call its parent's constructor first, we call the +B (here: Qt::PushButton) on line 9, passing it all +arguments we received. + +At this time, a class instance has been created and stored into a special +object holder named B (not C<$this> but really just C). + +Each time you invoke a method from within your package, you may now +indifferently say C or Cmethod()>; + +=head3 Using Attributes + +When building a new composite widget, you may just create its different +parts inside B variables, since widgets are only deleted by their parents +and not necessarily when their container goes out of scope. + +In other words, PerlQt performs clever reference counting to prevent +indesirable deletion of objects. + +Now, you'll often want to keep an access to those parts from anywhere inside +your package. +For this purpose, you may use the B object's blessed hash, as is usual in Perl, +but that isn't really convenient and you don't have any compile time +checking... + +Here come B. Attributes are data holders where you can +store any kind of properties for your object. + +Declaring new attributes is done through the C pragma, as is +demonstrated in the following package implementation : + + 1: use strict; + 2: + 3: package Button; + 4: use Qt; + 5: use Qt::isa qw(Qt::PushButton); + 6: use Qt::attributes qw( + 7: itsTime + 8: pData + 9: ); + 10: + 11: sub NEW + 12: { + 13: shift->SUPER::NEW(@_[0..2]); + 14: itsTime = Qt::Time; + 15: itsTime->start; + 16: pData = " Foo "; + 17: } + 18: + 19: sub resizeEvent + 20: { + 21: setText( "w: ". width() ." h: ". height() . + 22: "\nt: ". itsTime->elapsed . pData ); + 23: } + 24: + 25: 1; + +=for html +
+
+ + +An attribute itsTime is declared at line 7, and loaded with a C object +at line 14. + +Since we reimplement the virtual function "resizeEvent" [l.19]. +each time the main widget is resized, this function will be triggered and +our Button's text updated with values coming from the object [l.21] and from the +attributes we defined [l.22]. + +B + +=over 4 + +=item * + +In order to inherit a Qt class, a package must contain a +C pragma. +e.g: + + use Qt::isa "Qt::widget"; + +=item * + +The object constructor is named B and is implicitly called. +Thus you should not say : + + my $o = MyButton->NEW("Hello"); + +But say : + + my $o = MyButton("Hello"); + +=item * + +Within a package, the current instance can be accessed through the B +variable. + +When a member function is called, arguments are loaded as usual in the B<@_> +array, but B the object pointer itself. + +Hence, you shouldn't say : + + sub myMember + { + my $self = shift; + my $arg = shift; + $arg->doThat($self); + $self->doIt; + } + +But : + + sub myMember + { + my $arg = shift; + $arg->doThat(this); + doIt; + } + +Furthermore, if you want to call a base class method from a derived class, +you'd use the specal attribute SUPER : + + sub example + { + print "Now calling the base class\n"; + SUPER->example(@_) + } + +Note that the : + + this->SUPER::Example(@_); + +construct is also available, but will pass the object as first argument. + + +=item * + +Whenever you need to store a contained object in your package, you may define it +as an B : + + use Qt::attributes qw( + firstAttribute + ... + lastAttribute); + +and then use it as a convenient accessor : + + firstAttribute = myContainedWidget( this ); + firstAttribute->resize( 100, 100 ); + +=item * + +To reimplement a B, simply create a B with the +same name in your object. + +Existing virtual functions are marked as such in Qt's documentation +(they are prefixed with the "virtual" keyword). + +You can inspect what virtual function names are being called by Qt at runtime by +putting a C statement at the top of your program. + +=back + +=head2 Signals and Slots + +We'll now learn how Qt objects can communicate with each other, +allowing an event occuring, for instance, in a given widget to trigger the +execution of one or several subroutines anywhere inside your program. + +Most other toolkits use callbacks for that purpose, but Qt has a much more +powerful and flexible mechanism called B. + +Signals and slots are used for communication between objects. + +This can be thought off as something similar to the wiring between several Hi-fI +components : an amplificator, for instance, has a set of output signals, wich are +emitted wether a listening device is connected to them or not. Also, a tape +recorder deck can start to record when it receives a signal wired to it's input +slot, and it doesn't need to know that this signal is also received by a CD +recorder device, or listened through headphones. + +A Qt component behaves just like that. It has several output B and +several input B - and each signal can be connected to an unlimited number +of listening slots of the same type, wether they are inside or outside the +component. + +The general syntax of this connection process is either : + +Qt::Object::connect( sender, SIGNAL 'mysignal(arg_type)', +receiver, SLOT 'myslot(arg_type)'); + +or + +myObject->connect( sender, SIGNAL 'mysignal(arg_type)', SLOT +'myslot(arg_type)'); + +This mechanism can be extended at will by the declaration of custom Signals and +Slots, through the C and C pragma +(see also the other syntax, later on). + +Each declared slot will call the corresponding subroutine in your object, +each declared signal can be raised through the B keyword. + +B + + 1: use strict; + 2: + 3: package Button; + 4: use Qt; + 5: use Qt::isa qw(Qt::PushButton); + 6: use Qt::attributes qw(itsTime); + 7: use Qt::slots + 8: wasClicked => [], + 9: change => ['int', 'int']; + 10: use Qt::signals + 11: changeIt => ['int', 'int']; + 12: + 13: sub NEW + 14: { + 15: shift->SUPER::NEW(@_[0..2]); + 16: itsTime = Qt::Time; + 17: itsTime->start; + 18: this->connect(this, SIGNAL 'clicked()', SLOT 'wasClicked()'); + 19: this->connect(this, SIGNAL 'changeIt(int,int)', SLOT 'change(int,int)'); + 20: } + 21: + 22: sub wasClicked + 23: { + 24: my $w = width(); + 25: my $h = height(); + 26: setText( "w: $w h: $h\nt: ". itsTime->elapsed ); + 27: emit changeIt($w, $h); + 28: } + 29: + 30: sub change + 31: { + 32: my ($w, $h) = @_; + 33: print STDERR "w: $w h: $h \n"; + 34: } + 35: + 36: 1; + +In this package, we define two extra slots and one extra signal. + +We know from the Qt Documentation that a clicked PushButton emits a C +signal, so we connect it to our new slot at line 18. + +We also connect our signal C to our own C slot- which is +quite stupid, but as an example. + +Now, whenever our Button is clicked, the C signal is raised and +triggers the C slot. C then proceeds to emit +the C signal [l.27], hence triggering the C +slot with two arguments. + +Finally, since PerlQt-3.008, an alternative syntax can be used to declare Signals and Slots: + + sub a_slot : SLOT(int, QString) + { + $int = shift; + $string = shift; + # do something + } + +and + + sub a_signal : SIGNAL(QString); + +This syntax is perfectly compatible with the traditional +C and C declarations. + +Eventually, it can prove good programming practice to mix both syntaxes, by first declaring +Signals/Slots with C, then repeat this declaration +in the actual implementation with the second syntax. + +Declarations will be checked for consistency at compile time, and any mismatch +in arguments would trigger a warning. + +=head1 RAD prototyping with Qt Designer and Puic + +=head2 Introduction + +=over 4 + +=item * Note: + +As of PerlQt-3.008, a separate PerlQt plugin for Qt Designer is available, +bringing full integration, syntax highlighting, code completion and allowing to run/debug your PerlQt project +entirely from the Designer GUI. +Nevertheless, the below is still accurate with regard to puic command line interaction +and with regard to using Qt Designer I the specific plugin. + +=back + +As efficient and intuitive as Qt can be, building a complete GUI from scratch +is often a tedious task. + +Hopefully, Qt comes with a very sophisticated GUI Builder named Qt +Designer, which is close to a complete integrated development environment. +It features Project management, drag'n drop GUI building, a complete object +browser, graphical interconnection of signals and slots, and much much more. + +Qt Designer's output is XML which can be parsed by several command line tools, +among whose is B (the PerlQt User Interface Compiler). + +Assuming you have already built an interface file with the Designer, +translating it to a PerlQt program is simply a matter of issuing +one command : + + puic -x -o program.pl program.ui + +This will generate the package defined in your ui file and a basic main package +for testing purposes. + +You may prefer : + + puic -o package.pm program.ui + +This will only generate the package, which can then be used by a separate +program. + +=head2 Embedding Images + +If you need to B, it can be done in two ways +: + +=over 4 + +=item * Inline embedding + +For this, you need to check the "Edit->Form Settings->Pixmaps->Save inline" +checkbox inside Qt Designer. +Then : puic -x -o F F + +=item * Image Collection + +This option is more complex but also far more powerful and clean. + +puic -o F -embed F F ... F + +Then add a C statement to your program's main package. + +If you've created a project file in Qt Designer, and added all images +you want to group (through "Project->Image Collection"), you'll find all those +images inside the directory where your project file (*.pro) is stored, under +/images. +You can then generate the corresponding image collection by issuing : + +puic -o F -embed F ../images/* + +You can use as many image collections as you want in a program. Simply add a +B statement for each collection. + +=back + +=head2 Working With B<.ui> Files + +It will often happen that you need to regenerate your user interface -either +because you changed your initial design, or you want to extend it. +Thus writing your program's code straight in the auto-generated Perl file is +quite a bad idea. +You'd run constantly the risk of overwriting your handcrafted code, or end +up doing lot of copy-paste. + +Instead, you may : + +=over 4 + +=item * Write slots implementation in the Designer + +In Qt Designer, select the I tab of the B. +There you can see a tree-like representation of your classes. +Now if you double-click on the I entry, +you are prompted with a dialog where you can create a new custom slot for +your module. +Once this is done, the new slot appear inside the B tree and +clicking on it will bring you to a BYour ClassE.ui.h> file where you can write +the actual implementation of your slot. + +Keeping all the defaults, it should look like this : + + void Form1::newSlot() + { + + } + +The slot declaration is actually C++ code, but simply ignore it and write +your Perl code straight between the two braces, paying special attention to +indent it at least by one space. + + void Form1::newSlot() + { + print STDERR "Hello world from Form1::newSlot(); + if(this->foo()) + { + # do something + } + } + +All Perl code written this way will be saved to the ui.h file, and B will take care of +placing it back in the final program. + +Here, after running B on the Form1.ui file, you'd have: + + sub newSlot + { + print STDERR "Hello world from Form1::newSlot(); + if(this->foo()) + { + # do something + } + } + +=item * Subclassing your GUI + +By using B's I<-subimpl> option, you may generate a derived module +inheriting your original user interface. + +You'd typically generate the derived module once, and write any handcrafted +code in this child. +Then, whenever you need to modify your GUI module, simply regenerate the +parent module, and your child will inherit those changes. + +To generate the base module : + + puic -o Form1.pm form1.ui + +(do this as often as needed, never edit by hand) + +To generate the child : + + puic -o Form2.pm -subimpl Form2 form1.ui + +or + + puic -o program.pl -x -subimpl Form2 form1.ui + +(do this once and work on the resulting file) + +=back + +=head1 More development tools + +PerlQt comes bundled with two simple programs that can help you to find your way through +the Qt API: + +=head2 pqtapi + +pqtapi is a commandline driven introspection tool. + + usage: pqtapi [-r ] [] + + options: + -r : find all functions matching regular expression/keyword + -i : together with -r, performs a case insensitive search + -v : print PerlQt and Qt versions + -h : print this help message + +e.g: + + $>pqtapi -ir 'setpoint.* int' + void QCanvasLine::setPoints(int, int, int, int) + void QPointArray::setPoint(uint, int, int) + +=head2 pqtsh + +B is a graphical shell that can be used to test the API interactively. +It is fairly self explanatory and includes an interactive example (CExample>) + +=for html +
+
+ +=head1 Known Limitations + +Templated classes aren't available yet (classes derived from templated classes are). + +=head1 Credits + +PerlQt-3 is (c) 2002 Ashley Winters (and (c) 2003 Germain Garand) + +Kalyptus and the Smoke generation engine are (c) David Faure and Richard Dale + +Puic is (c) TrollTech AS., Phil Thompson and Germain Garand, + +The mentioned software is released under the GNU Public Licence v.2 or later. + + +=head1 Appendix 1 : C++ conventions and their Perl counterpart + +Whenever you want to use a class/method described in Qt's +L (see also the 'assistant' program bundled with Qt) +from PerlQt, you need to follow some simple translation rules. + +=over 4 + +=item Classnames + +=over 4 + +=item * + +All classnames are changed from a B prefix in Qt to a B prefix +in Perl. +e.g: QComboBox is named Qt::ComboBox within PerlQt. + +=back + +=item Functions + +=over 4 + +=item * + +Functions referenced as B are accessed directly, and not through +an object. Thus the static function Foo in class QBar would be accessed from +PerlQt as + + Qt::Bar::Foo( arg-1,...,arg-n); + +The only notable exceptions are : + + qApp() will map to Qt::app() + qVersion() will map to Qt::version() # not really needed anymore: we have qVersion(). See Global Functions below. + +=item * + +Functions referenced as B or B are accessed through an object +with the B<-E> operator. +e.g: + + $widget->show; + +There are no fundamental differences between methods and signals, however PerlQt +provides the B keyword as a convenient mnemonic, so that it is clear you +are emitting a signal : + + emit $button->clicked; + +=back + +=item Arguments + +=over 4 + +=item * By value + +When an argument isn't preceded by the B<&> or B<*> character, it is passed by +value. For all basic types such as int, char, float and double, PerlQt will +automatically convert litteral and scalar values to the corresponding C++ type. + +Thus for a constructor prototype written as follow in the documentation : + + QSize ( int w, int h ) + + +You'd say : + + Qt::Size(8, 12); + + +=item * By reference + +When an argument is preceded by the B<&> character, it means a reference to an +object or to a type is expected. You may either provide a variable name or a +temporary object : + + $keyseq = Qt::keySequence( &Qt::CTRL + &Qt::F3 ); + $widget->setAccel( $keyseq ); + +or + + $widget->setAccel(Qt::keySequence( &Qt::CTRL + &Qt::F3 ); + +If the argument isn't qualified as B (constant), it means the passed +object may be altered during the process - you must then provide a variable. + +=item * By pointer + +When an argument is preceded by the B<*> character, it means a +pointer to an object or to a type is expected. You may provide a variable +name or the Perl B keyword for a Null pointer. + +Similarly, if the argument isn't B, the passed object may be altered by +the method call. + +=back + +=item Enumerations + +Enumerations are sort of named aliases for numeric values that would be hard to +remember otherwise. + +A C++ example would be : + + enum Strange { Apple, Orange, Lemon } + +where C is the generic enumeration name, and C, C, +C its possible values, which are only aliases for numbers (here 0, 1 +and 2). + +Access to enumerations values in Perl Qt is very similar to a static function +call. In fact, it B a static function call. + +Therefore, since you probably want to avoid some readability problems, we +recommend the use of the alternate function call syntax : C<&function>. + +Lets now go back to our C example. + +If its definition was encountered in the class C, you'd write from +PerlQt : + + $apple_plus_orange = &Qt::Fruit::Apple + &Qt::Fruit::Orange; + +=item Operators + +Within PerlQt, B works transparently. +If a given operator is overloaded in a Qt class (which means using it triggers a custom method) +it will behave identically in PerlQt. +Beware though that due to limitations of the Smoke binding library, not all overloaded operators are +available in PerlQt. +You can check the availability of a given operator by using the pqtapi program. +Also, due to outstanding differences between C++'s and Perl's object paradigm, the copy constructor operator (a.k.a '=') +has been disabled. + +e.g-1: '+=' overload + + $p1 = Qt::Point(10, 10) + $p2 = Qt::Point(30,40) + $p2 += $p1; # $p2 becomes (40,50) + +e.g-2: '<<' overload + + $f = Qt::File("example"); + $f->open( IO_WriteOnly ); # see 'Constants' below + $s = Qt::TextStream( $f ); + $s << "What can I do with " << 12 << " apples?"; + +=item Constants + +Qt doesn't use many constants, but there is at least one place where they are used : for setting +Input/Output flags on files. +In order to avoid the namespace pollution induced by global constants, PerlQt group them in the B module. +For instance, requesting the importation of all IO constants into the current namespace would be done with: + + use Qt::constants; + +You may also import specific symbols: + + use Qt::constants qw( IO_ReadOnly IO_WriteOnly ); + +=item Global Functions + + +Qt has also some utilitarian functions such as bitBlt, qCompress, etc. + +Those were global scope functions and have been grouped in a common namespace: +C. + +Hence, you shall access this namespace either with a fully qualified call: + + Qt::GlobalSpace::qUncompress( $buffer ) + +Or directly, after importation in the current namespace: + + use Qt::GlobalSpace; + qUncompress( $buffer ) + +Of course, you may selectively import a few functions: + + use Qt::GlobalSpace qw( qUncompress bitBlt ) + +B GlobalSpace has also operators, such has the one performing an addition on two +Qt::Point(). Those operators are called automatically. + +e.g: + + $p1 = Qt::Point(10, 10) + Qt::Point(20, 20) + +=back + + +=head1 Appendix 2 : Internationalization + +PerlQt handles internationalization by always converting B back to B in Perl. + +Conversions from Perl strings to QStrings are made according to context : + +=over 4 + +=item * If the Perl string is already utf8-encoded + +then the string will be converted straight to QString. + +This is the most convenient and seemless way of internationalizing your application. Typically, one would just enable +the use of utf8 in source code with the C pragma and write its application with an utf8 aware editor. + +=item * If the string isn't tagged as utf8, and the B pragma is not set + +then the string will be converted to QString's utf8 from B. + +=item * If the string isn't tagged as utf8 and the B pragma is set + +then the string will be converted to QString's utf8 according to the currently set B. + +=back + +Once a string contains utf8, you can convert it back to any locale by setting up B : + + $tr1=Qt::TextCodec::codecForLocale(); # this one will use current locale + $tr2=Qt::TextCodec::codecForName("KOI8-R"); # that one forces a specific locale (Russian) + + print $tr1->fromUnicode(Qt::DateTime::currentDateTime()->toString)."\n\n"; + print $tr2->fromUnicode($my_utf8_string); + +Or, with Perl >= 5.8.0, you may use Perl's B modules (see C). + +=head3 disabling utf-8 + +Developers who don't want to use UTF-8 or want to temporarily disable UTF-8 marshalling +for handling legacy programs may use the B pragma (and the corresponding B). + +Within the scope of this pragma, QStrings are marshalled back to ISO-Latin1 (default) or to your locale +(if B has been set). + +Frivole use of this pragma is strongly discouraged as it ruins worldwide standardization efforts. + +=head1 Appendix 3 : Debugging Channels + +The B module offers various debugging channels/features. + + use Qt::debug; + + use Qt::debug qw|calls autoload verbose|; + +With the simple C statement, the B and B channels are activated. +If you specify a list of channels within the use statement, then only the specified channels will be enabled. + +B + +=over 4 + +=item * ambiguous + +Check if method and function calls are ambiguous, and tell which of the alternatives +was finally elected. + +=item * verbose + +Enable more verbose debugging. + +Together with B, tell you the nearest matches in case +a method or function call fails. +e.g: + + use Qt; + use Qt::debug; + $a= Qt::Application(\@ARGV); + $a->libraryPath("foo"); + + --- No method to call for : + QApplication::libraryPath('foo') + Closer candidates are : + static void QApplication::addLibraryPath(const QString&) + static QStringList QApplication::libraryPaths() + static void QApplication::removeLibraryPath(const QString&) + static void QApplication::setLibraryPaths(const QStringList&) + +=item * calls + +For every call, tell what corresponding Qt method is called +(detailing the arguments if B is on). + +=item * autoload + +Track the intermediate code between a method invocation in Perl +and its resolution to either a Qt or Perl call. + +=item * gc + +Give informations about garbage collection +whenever a Qt object is deleted and/or a Perl object is destroyed + +=item * virtual + +Report whenever a virtual function tries to access its Perl +reimplementation (wether it exists or not). + +=item * all + +Enable all channels + +=back + + +=head1 Appendix 4 : Marshallers + +A marshaller is a piece of "glue code" translating a given datatype to another. + +Within PerlQt, most Qt objects keep their object nature, so that one may invoke methods on them. +However, some classes and datatypes map so naturally to some Perl types that keeping their object nature would +would feel unnatural and clumsy. + +For instance, instead of returning a Qt::StringList object, which would require an iterator to retrieve its content, +PerlQt will translate it to an array reference containing all the object's strings. + +In the other way, instead of providing a Qt::StringList object as an argument of a method, one would simply +provide the reference to an array of Perl strings. + +Here is the list of Marshallers as of PerlQt-3.008 : + + ----------------------------------------------------------------- + float, double <=> Perl real (NV) + char, uchar, int, uint, enum + long, ulong, short, ushort <=> Perl integer (IV) + QString, -&, -* => Perl string (utf8) + QString, -&, -* <= Perl string (utf8 or iso-latin1 or locale) + QCString, -&, -* <=> Perl string (utf8 or bytes, according to content or "bytes" pragma) + QByteArray, -&, -* <=> Perl string (bytes) + QStringList, -&, -* => Reference to an array of Perl strings (utf8) + QString, -&, -* => Perl string (utf8 or iso-latin1 or locale) + int&, -* <=> Perl integer (IV) + bool&, -* <=> Perl boolean + char* <=> Perl string (bytes) + char** <= Reference to an array of Perl strings (bytes) + uchar* <= Perl string (bytes) + QRgb* <= Reference to an array of Perl integers (IV) + QCOORD* <= Reference to an array of Perl integers (IV) + void* <=> Reference to a Perl integer (IV) + QValueList, - *, - & <=> Reference to an array of Perl integers (IV) + QCanvasItemList, - *, - & => Reference to an array of Qt::CanvasItem + QWidgetList, - *, - & <=> Reference to an array of Qt::Widget + QObjectList, - *, - & <=> Reference to an array of Qt::Object + QFileInfoList, - *, - & <=> Reference to an array of Qt::FileInfo + QPtrList, - *, - & <=> Reference to an array of Qt::Tab + QPtrList, - *, - & <=> Reference to an array of Qt::ToolBar + QPtrList, - *, - & <=> Reference to an array of Qt::NetworkOperation + QPtrList, - *, - & <=> Reference to an array of Qt::DockWindow + (QUObject*) + + + + + diff --git a/doc/en/index.html b/doc/en/index.html new file mode 100644 index 0000000..6a4cc7b --- /dev/null +++ b/doc/en/index.html @@ -0,0 +1,1081 @@ + + + +Programming PerlQt + + + + + + +

+ + + + + +
+

+

+

Programming PerlQt

+

Germain Garand

+

This document describes a set of Perl bindings for the Qt toolkit. Contact +the author at <germain@ebooksfrance.com>

+

+

+
+

Introduction

+

PerlQt-3 is Ashley Winters' full featured object oriented interface to +Trolltech's C++ Qt toolkit v3.0.

+

It is based on the +SMOKE +library, a language independent low-level wrapper generated from Qt headers by +Richard Dale's +kalyptus +thanks to David Faure's module.

+

This document describes the principles of PerlQt programming. +It assumes you have some basic Perl Object Oriented programming knowledge.

+

Some C++ knowledge is recommended but not required. +It would mostly help you to find your way through Qt's excellent documentation which is our +ultimate and only reference. +If Qt is installed on your system, then you most probably +also have its documentation. Try the $QTDIR/bin/assistant program.

+

+

+
+

Installation

+

+

+

Requirements

+

To compile and use PerlQt, you'll need :

+
    +
  • +a POSIX system +

    +
  • +GNU tools : automake(>=1.5), autoconf (>=2.13), aclocal... +

    +
  • +Perl >= v5.6.0 +

    +
  • +Qt >= v3.0 +

    +
  • +SmokeQt 1.2.1 +The SMOKE library (Scripting Meta Object Kompiler) is part of KDE's kdebindings module. +You may want to check if a precompiled version of this module exists for your +system. +PerlQt is packaged with its own copy, so you don't need to check it out. +

+

Perl and Qt's installation is out of the scope of this document. Please refer +to those projects' documentation.

+

+

+

Compilation

+

PerlQt uses GNU's Autoconf framework. However, the standard ./configure script is preferably driven +by the Makefile.PL wrapper. All options are forwarded to ./configure :

+
+ perl Makefile.PL
+

If SMOKE is missing, configure will generate its sources. +Then :

+
+ make
+
+ make install
+

This will install PerlQt, Puic and Smoke (if needed), as well as the pqtsh and pqtapi utilities.

+

The preferred install location for SMOKE and Puic is in the KDE3 file system. +If you don't have KDE3 installed, specify a location with configure's +--prefix option. e.g:

+
+ perl Makefile.PL --prefix=/usr
+

+

+

Troubleshooting and Configure Options

+

If Smoke's linking fails or your Qt library was built with very specific +options, run Makefile.PL again with:

+
+ perl Makefile.PL --with-threshold=0
+

When building smoke, configure will check for OpenGL and try to compile +support for it if it is properly installed and supported by Qt.

+

You may disable this checking with:

+
+ --disable-GL
+

Also, default behaviour is to prefer the Mesa GL library over a proprietary +implementation. +If your system features a proprietary OpenGL library, and you'd like to use +it, specify:

+
+ --without-Mesa
+

+

+

How to install PerlQt with user rights

+

To install PerlQt without super-user rights, simply follow this procedure:

+
    +
  • +Perform a normal configuration, specifying as prefix a directory where you have write permissions : +
    + perl Makefile.PL --prefix=~
    +

    The above would install the Smoke library in ~/lib and the puic binary in ~/bin

    +

    +
  • +Reconfigure the Perl module so that it doesn't target the standard perl hierarchy: +
    + cd PerlQt
    + perl Makefile.PL PREFIX=~
    + cd ..
    +

    Beware : this is not the same Makefile.PL as above, but the one located in the ./PerlQt +subdirectory

    +

    +
  • +Compile and Install +
    + make && make install
    +

    In order to use such an installation, you must tell to Perl where to find this extern hierarchy. +This can be done either on the command line:

    +
    + perl -Mlib="~/local/lib/perl/5.x.x" program.pl
    +

    or at the top of your program:

    +
    + use lib qw( ~/local/lib/perl/5.x.x );
    +

    ``5.x.x'' should be changed to whatever Perl version your system is running.

    +

+

+

+
+

Anatomy of PerlQt

+

A typical Qt program using GUI components is based on an event loop.

+

This basically means that such a program is no more envisioned as a straight +flow where you would need to handle yourself every single events (such as a +mouse click or a key press).

+

Instead, you just create an Application object, create the GUI components it +uses, +define what objects methods need to be called when an event occurs, +and then start the main event loop.

+

That's all! +Qt will handle all events and dispatch them to the correct subroutine.

+

Lets see how this process is implemented in a minimal PerlQt program.

+

+

+

Hello World

+
+ 1: use Qt;
+ 2: my $a = Qt::Application(\@ARGV);
+ 3: my $hello = Qt::PushButton("Hello World!", undef);
+ 4: $hello->resize(160, 25);
+ 5: $a->setMainWidget($hello);
+ 6: $hello->show;
+ 7: exit $a->exec;
+
+

This program first loads the Qt interface [line 1] and creates the application +object, passing it a reference to the command line arguments array @ARGV +[l.2]. +This application object is unique, and may later be accessed from +anywhere through the Qt::app() pointer.

+

At line 3, we create a PushButton, which has no parent (i.e : it won't be +contained nor owned by another widget). +Therefore, we pass to the constructor an undef value for the parent argument, +which is PerlQt's way of passing a Null pointer.

+

After some layouting at [l.4], we tell the application object that our main +widget is this PushButton [l.5]... that way, it will know that closing the +window associated with this widget means : quit the application.

+

Now the last steps are to make this widget visible (as opposed to +hidden, which is the default) by calling the show method on it [l.6] and +to start the application loop [l.7].

+

Syntax elements summary :

+
    +
  1. +All Qt classes are accessed through the prefix Qt::, which replaces the +initial Q of Qt classes. +When browsing the Qt documentation, you simply need to change the +name of classes so that QFoo reads Qt::Foo. +

    +
  2. +An object is created by calling the constructor of the class. It has the +same name as the class itself. +

    You don't need to say new Qt::Foo or Qt::Foo->new() as most Perl +programmers would have expected.

    +

    Instead, you just say :

    +
    + my $object = Qt::<classname>(arg_1, ..., arg_n);
    +

    If you don't need to pass any argument to the constructor, simply say :

    +
    + my $object = Qt::<classname>;
    +

    +
  3. +Whenever you need to pass a Null pointer as an argument, use Perl's undef +keyword. Do not pass zero. + Beware: this is by far the most common error in PerlQt programs. +

    Pointers are arguments preceded by an * +character in Qt's documentation (e.g: ``QWidget * widget'').

    +

+

+

+

Inheritance and Objects

+

Before we can discuss how Perl subroutines can be called back from Qt, we need +to introduce PerlQt's inheritance mechanism.

+

PerlQt was designed to couple as tightly as possible Qt's simplicity and Perl's +power and flexibility.

+

In order to achieve that goal, the classical Object Oriented Perl paradigm had +to be extended, much in the same way than Qt itself +had to extend C++'s paradigm with metaobjects.

+

+

+

A Custom Widget

+

Lets rewrite the ``Hello World!'' program, this time using a custom version +of PushButton:

+
+  1: use strict;
+  2: 
+  3: package Button;
+  4: use Qt;
+  5: use Qt::isa qw(Qt::PushButton);
+  6: 
+  7: sub NEW
+  8: {
+  9:   shift->SUPER::NEW(@_[0..2]);
+ 10:   resize(130, 40);
+ 11: }
+ 12: 
+ 13: 1;
+ 14: 
+ 15: package main;
+ 16: 
+ 17: use Qt;
+ 18: use Button;
+ 19: 
+ 20: my $a = Qt::Application(\@ARGV);
+ 21: my $w = Button("Hello World!", undef);
+ 22: $a->setMainWidget($w);
+ 23: $w->show;
+ 24: exit $a->exec;
+

Here, we want to create our own version of the PushButton widget. +Therefore, we create a new package for it [l.3] and import Qt [l.4].

+

We now want to declare our widget as subclassing PushButton. +This is done through the use of the Qt::isa pragma [l.5], which accepts a +list of one or more parent Qt classes.

+

It is now time to create a constructor for our new widget. +This is done by creating a subroutine called NEW (note the capitalized +form, which differentate it from the usual ``new'' constructor. PerlQt's NEW +constructor is called implicitly as can be seen on line 21).

+

Since we want our widget to call its parent's constructor first, we call the +superclass's constructor (here: Qt::PushButton) on line 9, passing it all +arguments we received.

+

At this time, a class instance has been created and stored into a special +object holder named this (not $this but really just this).

+

Each time you invoke a method from within your package, you may now +indifferently say method() or this->method();

+

+

+

Using Attributes

+

When building a new composite widget, you may just create its different +parts inside my variables, since widgets are only deleted by their parents +and not necessarily when their container goes out of scope.

+

In other words, PerlQt performs clever reference counting to prevent +indesirable deletion of objects.

+

Now, you'll often want to keep an access to those parts from anywhere inside +your package. +For this purpose, you may use the this object's blessed hash, as is usual in Perl, +but that isn't really convenient and you don't have any compile time +checking...

+

Here come Attributes. Attributes are data holders where you can +store any kind of properties for your object.

+

Declaring new attributes is done through the use Qt::attributes pragma, as is +demonstrated in the following package implementation :

+
+  1: use strict;
+  2:
+  3: package Button;
+  4: use Qt;
+  5: use Qt::isa qw(Qt::PushButton);
+  6: use Qt::attributes qw(
+  7:     itsTime
+  8:     pData
+  9: );
+ 10:
+ 11: sub NEW
+ 12: {
+ 13:   shift->SUPER::NEW(@_[0..2]);
+ 14:   itsTime = Qt::Time;
+ 15:   itsTime->start;   
+ 16:   pData = " Foo ";
+ 17: }
+ 18: 
+ 19: sub resizeEvent
+ 20: {
+ 21:    setText( "w: ". width() ." h: ". height() .
+ 22:             "\nt: ". itsTime->elapsed . pData );
+ 23: }
+ 24:
+ 25: 1;
+
+

An attribute itsTime is declared at line 7, and loaded with a Qt::Time object +at line 14.

+

Since we reimplement the virtual function ``resizeEvent'' [l.19]. +each time the main widget is resized, this function will be triggered and +our Button's text updated with values coming from the object [l.21] and from the +attributes we defined [l.22].

+

Recapitulation

+
    +
  • +In order to inherit a Qt class, a package must contain a +use Qt::isa pragma. +e.g: + +
    +
    + use Qt::isa "Qt::widget";
    +

    +
  • +The object constructor is named NEW and is implicitly called. +Thus you should not say : +
    + my $o = MyButton->NEW("Hello");
    +

    But say :

    +
    + my $o = MyButton("Hello");
    +

    +
  • +Within a package, the current instance can be accessed through the this +variable. +

    When a member function is called, arguments are loaded as usual in the @_ +array, but without the object pointer itself.

    +

    Hence, you shouldn't say :

    +
    + sub myMember
    + {
    +   my $self = shift;
    +   my $arg = shift;
    +   $arg->doThat($self); 
    +   $self->doIt;
    + }
    +    
    +But :
    +
    + sub myMember
    + {
    +   my $arg = shift;
    +   $arg->doThat(this);
    +   doIt;
    + }
    +

    Furthermore, if you want to call a base class method from a derived class, +you'd use the specal attribute SUPER :

    +
    + sub example
    + {
    +   print "Now calling the base class\n";
    +   SUPER->example(@_)
    + }
    +

    Note that the :

    +
    + this->SUPER::Example(@_);
    +

    construct is also available, but will pass the object as first argument.

    +

    +
  • +Whenever you need to store a contained object in your package, you may define it +as an Attribute : +
    + use Qt::attributes qw(
    +        firstAttribute
    +        ...
    +        lastAttribute);
    +

    and then use it as a convenient accessor :

    +
    + firstAttribute = myContainedWidget( this );
    + firstAttribute->resize( 100, 100 );
    +

    +
  • +To reimplement a virtual function, simply create a sub with the +same name in your object. +

    Existing virtual functions are marked as such in Qt's documentation +(they are prefixed with the ``virtual'' keyword).

    +

    You can inspect what virtual function names are being called by Qt at runtime by +putting a use Qt::debug qw( virtual ) statement at the top of your program.

    +

+

+

+

Signals and Slots

+

We'll now learn how Qt objects can communicate with each other, +allowing an event occuring, for instance, in a given widget to trigger the +execution of one or several subroutines anywhere inside your program.

+

Most other toolkits use callbacks for that purpose, but Qt has a much more +powerful and flexible mechanism called Signals and Slots.

+

Signals and slots are used for communication between objects.

+

This can be thought off as something similar to the wiring between several Hi-fI +components : an amplificator, for instance, has a set of output signals, wich are +emitted wether a listening device is connected to them or not. Also, a tape +recorder deck can start to record when it receives a signal wired to it's input +slot, and it doesn't need to know that this signal is also received by a CD +recorder device, or listened through headphones.

+

A Qt component behaves just like that. It has several output Signals and +several input Slots - and each signal can be connected to an unlimited number +of listening slots of the same type, wether they are inside or outside the +component.

+

The general syntax of this connection process is either :

+

Qt::Object::connect( sender, SIGNAL 'mysignal(arg_type)', +receiver, SLOT 'myslot(arg_type)');

+

or

+

myObject->connect( sender, SIGNAL 'mysignal(arg_type)', SLOT +'myslot(arg_type)');

+

This mechanism can be extended at will by the declaration of custom Signals and +Slots, through the use Qt::signals and use Qt::slots pragma +(see also the other syntax, later on).

+

Each declared slot will call the corresponding subroutine in your object, +each declared signal can be raised through the emit keyword.

+

As an example, lets rewrite again our Button package :

+
+  1: use strict;
+  2:
+  3: package Button;
+  4: use Qt;
+  5: use Qt::isa qw(Qt::PushButton);
+  6: use Qt::attributes qw(itsTime);
+  7: use Qt::slots 
+  8:     wasClicked => [],
+  9:     change     => ['int', 'int'];
+ 10: use Qt::signals
+ 11:     changeIt   => ['int', 'int'];
+ 12:
+ 13: sub NEW
+ 14: {
+ 15:   shift->SUPER::NEW(@_[0..2]);
+ 16:   itsTime = Qt::Time;
+ 17:   itsTime->start;   
+ 18:   this->connect(this, SIGNAL 'clicked()', SLOT 'wasClicked()');
+ 19:   this->connect(this, SIGNAL 'changeIt(int,int)', SLOT 'change(int,int)');
+ 20: }
+ 21: 
+ 22: sub wasClicked
+ 23: {
+ 24:    my $w = width();
+ 25:    my $h = height();
+ 26:    setText( "w: $w h: $h\nt: ". itsTime->elapsed );
+ 27:    emit changeIt($w, $h);          
+ 28: }
+ 29:
+ 30: sub change
+ 31: {
+ 32:    my ($w, $h) = @_;
+ 33:    print STDERR "w: $w h: $h \n";
+ 34: }
+ 35:
+ 36: 1;
+

In this package, we define two extra slots and one extra signal.

+

We know from the Qt Documentation that a clicked PushButton emits a clicked() +signal, so we connect it to our new slot at line 18.

+

We also connect our signal changeIt to our own change slot- which is +quite stupid, but as an example.

+

Now, whenever our Button is clicked, the clicked() signal is raised and +triggers the wasClicked() slot. wasClicked then proceeds to emit +the changeIt(int,int) signal [l.27], hence triggering the change(int,int) +slot with two arguments.

+

Finally, since PerlQt-3.008, an alternative syntax can be used to declare Signals and Slots:

+
+ sub a_slot : SLOT(int, QString)
+ { 
+        $int = shift;
+        $string = shift;
+        # do something
+ }
+

and

+
+ sub a_signal : SIGNAL(QString);
+

This syntax is perfectly compatible with the traditional +use Qt::signals and use Qt::slots declarations.

+

Eventually, it can prove good programming practice to mix both syntaxes, by first declaring +Signals/Slots with use Qt::slots/signals, then repeat this declaration +in the actual implementation with the second syntax.

+

Declarations will be checked for consistency at compile time, and any mismatch +in arguments would trigger a warning.

+

+

+
+

RAD prototyping with Qt Designer and Puic

+

+

+

Introduction

+
    +
  • Note:
    +
  • +As of PerlQt-3.008, a separate PerlQt plugin for Qt Designer is available, +bringing full integration, syntax highlighting, code completion and allowing to run/debug your PerlQt project +entirely from the Designer GUI. +Nevertheless, the below is still accurate with regard to puic command line interaction +and with regard to using Qt Designer without the specific plugin. +

+

As efficient and intuitive as Qt can be, building a complete GUI from scratch +is often a tedious task.

+

Hopefully, Qt comes with a very sophisticated GUI Builder named Qt +Designer, which is close to a complete integrated development environment. +It features Project management, drag'n drop GUI building, a complete object +browser, graphical interconnection of signals and slots, and much much more.

+

Qt Designer's output is XML which can be parsed by several command line tools, +among whose is puic (the PerlQt User Interface Compiler).

+

Assuming you have already built an interface file with the Designer, +translating it to a PerlQt program is simply a matter of issuing +one command :

+
+ puic -x -o program.pl program.ui
+

This will generate the package defined in your ui file and a basic main package +for testing purposes.

+

You may prefer :

+
+ puic -o package.pm program.ui
+

This will only generate the package, which can then be used by a separate +program.

+

+

+

Embedding Images

+

If you need to embed images or icons, it can be done in two ways +:

+
    +
  • Inline embedding
    +
  • +For this, you need to check the ``Edit->Form Settings->Pixmaps->Save inline'' +checkbox inside Qt Designer. +Then : puic -x -o program.pl program.ui +

    +
  • Image Collection
    +
  • +This option is more complex but also far more powerful and clean. +

    puic -o Collection.pm -embed unique_identifier image-1 ... image-n

    +

    Then add a use Collection.pm statement to your program's main package.

    +

    If you've created a project file in Qt Designer, and added all images +you want to group (through ``Project->Image Collection''), you'll find all those +images inside the directory where your project file (*.pro) is stored, under +/images. +You can then generate the corresponding image collection by issuing :

    +

    puic -o Collection.pm -embed identifier ../images/*

    +

    You can use as many image collections as you want in a program. Simply add a +use statement for each collection.

    +

+

+

+

Working With .ui Files

+

It will often happen that you need to regenerate your user interface -either +because you changed your initial design, or you want to extend it. +Thus writing your program's code straight in the auto-generated Perl file is +quite a bad idea. +You'd run constantly the risk of overwriting your handcrafted code, or end +up doing lot of copy-paste.

+

Instead, you may :

+
    +
  • Write slots implementation in the Designer
    +
  • +In Qt Designer, select the Source tab of the Object Explorer. +There you can see a tree-like representation of your classes. +Now if you double-click on the Slots/public entry, +you are prompted with a dialog where you can create a new custom slot for +your module. +Once this is done, the new slot appear inside the Object Explorer tree and +clicking on it will bring you to a <Your Class>.ui.h file where you can write +the actual implementation of your slot. +

    Keeping all the defaults, it should look like this :

    +
    + void Form1::newSlot()
    + {
    + 
    + }
    +

    The slot declaration is actually C++ code, but simply ignore it and write +your Perl code straight between the two braces, paying special attention to +indent it at least by one space.

    +
    + void Form1::newSlot()
    + {
    +     print STDERR "Hello world from Form1::newSlot();
    +     if(this->foo())
    +     {
    +         # do something
    +     }
    + }
    +

    All Perl code written this way will be saved to the ui.h file, and puic will take care of +placing it back in the final program.

    +

    Here, after running puic on the Form1.ui file, you'd have:

    +
    + sub newSlot
    + {
    +     print STDERR "Hello world from Form1::newSlot();
    +     if(this->foo())
    +     {
    +         # do something
    +     }
    + }
    +

    +
  • Subclassing your GUI
    +
  • +By using puic's -subimpl option, you may generate a derived module +inheriting your original user interface. +

    You'd typically generate the derived module once, and write any handcrafted +code in this child. +Then, whenever you need to modify your GUI module, simply regenerate the +parent module, and your child will inherit those changes.

    +

    To generate the base module :

    +
    + puic -o Form1.pm form1.ui
    +

    (do this as often as needed, never edit by hand)

    +

    To generate the child :

    +
    + puic -o Form2.pm -subimpl Form2 form1.ui
    +

    or

    +
    + puic -o program.pl -x -subimpl Form2 form1.ui
    +

    (do this once and work on the resulting file)

    +

+

+

+
+

More development tools

+

PerlQt comes bundled with two simple programs that can help you to find your way through +the Qt API:

+

+

+

pqtapi

+

pqtapi is a commandline driven introspection tool.

+
+ usage: pqtapi [-r <re>] [<class>]
+
+ options:
+        -r <re> : find all functions matching regular expression/keyword <re>
+        -i : together with -r, performs a case insensitive search
+        -v : print PerlQt and Qt versions
+        -h : print this help message
+

e.g:

+
+ $>pqtapi -ir 'setpoint.* int'
+        void QCanvasLine::setPoints(int, int, int, int)
+        void QPointArray::setPoint(uint, int, int)
+

+

+

pqtsh

+

pqtsh is a graphical shell that can be used to test the API interactively. +It is fairly self explanatory and includes an interactive example (Help->Example)

+
+

+

+
+

Known Limitations

+

Templated classes aren't available yet (classes derived from templated classes are).

+

+

+
+

Credits

+

PerlQt-3 is (c) 2002 Ashley Winters (and (c) 2003 Germain Garand)

+

Kalyptus and the Smoke generation engine are (c) David Faure and Richard Dale

+

Puic is (c) TrollTech AS., Phil Thompson and Germain Garand,

+

The mentioned software is released under the GNU Public Licence v.2 or later.

+

+

+
+

Appendix 1 : C++ conventions and their Perl counterpart

+

Whenever you want to use a class/method described in Qt's +documentation (see also the 'assistant' program bundled with Qt) +from PerlQt, you need to follow some simple translation rules.

+
+
Classnames
+
+
    +
  • +All classnames are changed from a Q prefix in Qt to a Qt:: prefix +in Perl. +e.g: QComboBox is named Qt::ComboBox within PerlQt. +

+
Functions
+
+
    +
  • +Functions referenced as static are accessed directly, and not through +an object. Thus the static function Foo in class QBar would be accessed from +PerlQt as +
    + Qt::Bar::Foo( arg-1,...,arg-n);
    +

    The only notable exceptions are :

    +
    + qApp()     will map to Qt::app()
    + qVersion() will map to Qt::version() # not really needed anymore: we have qVersion(). See Global Functions below.
    +

    +
  • +Functions referenced as members or Signals are accessed through an object +with the -> operator. +e.g: +
    + $widget->show;
    +

    There are no fundamental differences between methods and signals, however PerlQt +provides the emit keyword as a convenient mnemonic, so that it is clear you +are emitting a signal :

    +
    + emit $button->clicked;
    +

+
Arguments
+
+
    +
  • By value
    +
  • +When an argument isn't preceded by the & or * character, it is passed by +value. For all basic types such as int, char, float and double, PerlQt will +automatically convert litteral and scalar values to the corresponding C++ type. +

    Thus for a constructor prototype written as follow in the documentation :

    +
    + QSize ( int w, int h )
    +

    You'd say :

    +
    + Qt::Size(8, 12);
    +

    +
  • By reference
    +
  • +When an argument is preceded by the & character, it means a reference to an +object or to a type is expected. You may either provide a variable name or a +temporary object : +
    + $keyseq = Qt::keySequence( &Qt::CTRL + &Qt::F3 );
    + $widget->setAccel( $keyseq );
    + 
    +or
    +
    + $widget->setAccel(Qt::keySequence( &Qt::CTRL + &Qt::F3 );
    +

    If the argument isn't qualified as const (constant), it means the passed +object may be altered during the process - you must then provide a variable.

    +

    +
  • By pointer
    +
  • +When an argument is preceded by the * character, it means a +pointer to an object or to a type is expected. You may provide a variable +name or the Perl undef keyword for a Null pointer. +

    Similarly, if the argument isn't const, the passed object may be altered by +the method call.

    +

+
Enumerations
+
+
+Enumerations are sort of named aliases for numeric values that would be hard to +remember otherwise. +
+
+

A C++ example would be :

+
+
+
+ enum Strange { Apple, Orange, Lemon }
+
+
+

where Strange is the generic enumeration name, and Apple, Orange, +Lemon its possible values, which are only aliases for numbers (here 0, 1 +and 2).

+
+
+

Access to enumerations values in Perl Qt is very similar to a static function +call. In fact, it is a static function call.

+
+
+

Therefore, since you probably want to avoid some readability problems, we +recommend the use of the alternate function call syntax : &function.

+
+
+

Lets now go back to our Strange example.

+
+
+

If its definition was encountered in the class QFruits, you'd write from +PerlQt :

+
+
+
+ $apple_plus_orange = &Qt::Fruit::Apple + &Qt::Fruit::Orange;
+
+

+
Operators
+
+
+Within PerlQt, operators overloading works transparently. +If a given operator is overloaded in a Qt class (which means using it triggers a custom method) +it will behave identically in PerlQt. +Beware though that due to limitations of the Smoke binding library, not all overloaded operators are +available in PerlQt. +You can check the availability of a given operator by using the pqtapi program. +Also, due to outstanding differences between C++'s and Perl's object paradigm, the copy constructor operator (a.k.a '=') +has been disabled. +
+
+

e.g-1: '+=' overload

+
+
+
+ $p1 = Qt::Point(10, 10)
+ $p2 = Qt::Point(30,40)
+ $p2 += $p1; # $p2 becomes (40,50)
+ 
+e.g-2: '<<' overload
+
+
+
+ $f = Qt::File("example");
+ $f->open( IO_WriteOnly ); # see 'Constants' below
+ $s = Qt::TextStream( $f );
+ $s << "What can I do with " << 12 << " apples?";
+
+

+
Constants
+
+
+Qt doesn't use many constants, but there is at least one place where they are used : for setting +Input/Output flags on files. +In order to avoid the namespace pollution induced by global constants, PerlQt group them in the Qt::constants module. +For instance, requesting the importation of all IO constants into the current namespace would be done with: +
+
+
+ use Qt::constants;
+
+
+

You may also import specific symbols:

+
+
+
+ use Qt::constants qw( IO_ReadOnly IO_WriteOnly );
+
+

+
Global Functions
+
+
+Qt has also some utilitarian functions such as bitBlt, qCompress, etc. +
+
+

Those were global scope functions and have been grouped in a common namespace: +Qt::GlobalSpace.

+
+
+

Hence, you shall access this namespace either with a fully qualified call:

+
+
+
+ Qt::GlobalSpace::qUncompress( $buffer )
+
+
+

Or directly, after importation in the current namespace:

+
+
+
+ use Qt::GlobalSpace;
+ qUncompress( $buffer )
+
+
+

Of course, you may selectively import a few functions:

+
+
+
+ use Qt::GlobalSpace qw( qUncompress bitBlt )
+
+
+

Note: GlobalSpace has also operators, such has the one performing an addition on two +Qt::Point(). Those operators are called automatically.

+
+
+

e.g:

+
+
+
+ $p1 = Qt::Point(10, 10) + Qt::Point(20, 20)
+
+

+

+

+
+

Appendix 2 : Internationalization

+

PerlQt handles internationalization by always converting QString back to utf8 in Perl.

+

Conversions from Perl strings to QStrings are made according to context :

+ +

Once a string contains utf8, you can convert it back to any locale by setting up converters :

+
+ $tr1=Qt::TextCodec::codecForLocale(); # this one will use current locale
+ $tr2=Qt::TextCodec::codecForName("KOI8-R"); # that one forces a specific locale (Russian)
+
+ print $tr1->fromUnicode(Qt::DateTime::currentDateTime()->toString)."\n\n";
+ print $tr2->fromUnicode($my_utf8_string);
+

Or, with Perl >= 5.8.0, you may use Perl's Encode modules (see perldoc Encode).

+

+

+

disabling utf-8

+

Developers who don't want to use UTF-8 or want to temporarily disable UTF-8 marshalling +for handling legacy programs may use the use bytes pragma (and the corresponding no bytes).

+

Within the scope of this pragma, QStrings are marshalled back to ISO-Latin1 (default) or to your locale +(if use locale has been set).

+

Frivole use of this pragma is strongly discouraged as it ruins worldwide standardization efforts.

+

+

+
+

Appendix 3 : Debugging Channels

+

The Qt::debug module offers various debugging channels/features.

+
+ use Qt::debug;
+
+ use Qt::debug qw|calls autoload verbose|;
+

With the simple use Qt::debug statement, the verbose and ambiguous channels are activated. +If you specify a list of channels within the use statement, then only the specified channels will be enabled.

+

Available channels :

+
    +
  • ambiguous
    +
  • +Check if method and function calls are ambiguous, and tell which of the alternatives +was finally elected. +

    +
  • verbose
    +
  • +Enable more verbose debugging. +

    Together with ambiguous, tell you the nearest matches in case +a method or function call fails. +e.g:

    +
    + use Qt;
    + use Qt::debug;
    + $a= Qt::Application(\@ARGV);
    + $a->libraryPath("foo");
    +
    + --- No method to call for :
    +        QApplication::libraryPath('foo')
    + Closer candidates are :
    +        static void QApplication::addLibraryPath(const QString&)
    +        static QStringList QApplication::libraryPaths()
    +        static void QApplication::removeLibraryPath(const QString&)
    +        static void QApplication::setLibraryPaths(const QStringList&)
    +

    +
  • calls
    +
  • +For every call, tell what corresponding Qt method is called +(detailing the arguments if verbose is on). +

    +
  • autoload
    +
  • +Track the intermediate code between a method invocation in Perl +and its resolution to either a Qt or Perl call. +

    +
  • gc
    +
  • +Give informations about garbage collection +whenever a Qt object is deleted and/or a Perl object is destroyed +

    +
  • virtual
    +
  • +Report whenever a virtual function tries to access its Perl +reimplementation (wether it exists or not). +

    +
  • all
    +
  • +Enable all channels +

+

+

+
+

Appendix 4 : Marshallers

+

A marshaller is a piece of ``glue code'' translating a given datatype to another.

+

Within PerlQt, most Qt objects keep their object nature, so that one may invoke methods on them. +However, some classes and datatypes map so naturally to some Perl types that keeping their object nature would +would feel unnatural and clumsy.

+

For instance, instead of returning a Qt::StringList object, which would require an iterator to retrieve its content, +PerlQt will translate it to an array reference containing all the object's strings.

+

In the other way, instead of providing a Qt::StringList object as an argument of a method, one would simply +provide the reference to an array of Perl strings.

+

Here is the list of Marshallers as of PerlQt-3.008 :

+
+ -----------------------------------------------------------------
+ float, double                         <=>       Perl real (NV)
+ char, uchar, int, uint, enum
+ long, ulong, short, ushort            <=>       Perl integer (IV)
+ QString, -&, -*                        =>       Perl string (utf8)
+ QString, -&, -*                       <=        Perl string (utf8 or iso-latin1 or locale)
+ QCString, -&, -*                      <=>       Perl string (utf8 or bytes, according to content or "bytes" pragma)
+ QByteArray, -&, -*                    <=>       Perl string (bytes)
+ QStringList, -&, -*                    =>       Reference to an array of Perl strings (utf8)
+ QString, -&, -*                        =>       Perl string (utf8 or iso-latin1 or locale)
+ int&, -*                              <=>       Perl integer (IV)
+ bool&, -*                             <=>       Perl boolean
+ char*                                 <=>       Perl string (bytes)
+ char**                                <=        Reference to an array of Perl strings (bytes)
+ uchar*                                <=        Perl string (bytes)
+ QRgb*                                 <=        Reference to an array of Perl integers (IV)
+ QCOORD*                               <=        Reference to an array of Perl integers (IV)
+ void*                                 <=>       Reference to a Perl integer (IV)
+ QValueList<int>, - *, - &             <=>       Reference to an array of Perl integers (IV)
+ QCanvasItemList, - *, - &              =>       Reference to an array of Qt::CanvasItem
+ QWidgetList, - *, - &                 <=>       Reference to an array of Qt::Widget
+ QObjectList, - *, - &                 <=>       Reference to an array of Qt::Object
+ QFileInfoList, - *, - &               <=>       Reference to an array of Qt::FileInfo
+ QPtrList<QTab>, - *, - &              <=>       Reference to an array of Qt::Tab
+ QPtrList<QToolBar>, - *, - &          <=>       Reference to an array of Qt::ToolBar
+ QPtrList<QNetworkOperation>, - *, - & <=>       Reference to an array of Qt::NetworkOperation
+ QPtrList<QDockWindow>, - *, - &       <=>       Reference to an array of Qt::DockWindow
+ (QUObject*)
+
+
+ + + + diff --git a/doc/fr/Makefile b/doc/fr/Makefile new file mode 100644 index 0000000..1d300c0 --- /dev/null +++ b/doc/fr/Makefile @@ -0,0 +1,7 @@ + +index.html: PerlQt.pod + pod2html --css ../css/pod.css PerlQt.pod > index.html + perl -pi -e 's/cgibin/cgi-bin/' index.html + perl -pi -e 's/#http/http/g' index.html + rm -f pod2*~~ + diff --git a/doc/fr/PerlQt.pod b/doc/fr/PerlQt.pod new file mode 100644 index 0000000..5036239 --- /dev/null +++ b/doc/fr/PerlQt.pod @@ -0,0 +1,1189 @@ + +=head1 Programmer avec PerlQt + +B traduit par B, révisé et augmenté par l'auteur. + +Ce document décrit l'interface Perl au toolkit Qt 3.x. Contacter +l'auteur à ou le traducteur à +. Vous trouverez le document original sur le site +L + +=head1 Introduction + +PerlQt-3, crée par Ashley Winters, est une interface perl aux composants +graphiques (et non graphiques) fournis par Qt3. + +Le toolkit Qt 3.0 auquel PerlQt accède à été écrit en C++ par la société +Trolltech: L. + +PerlQt3 est fondé sur la librairie +L, +une surcouche fine indépendante du langage. Cette couche a été générée +à partir des fichiers d'en tête de Qt par le +L +de Richard Dale grâce au module de David Faure. + +Le présent document décrit les principes de la programmation PerlQt. +Vous devez avoir des notions de programmation orientée objet en Perl pour le +lire. Une connaissance de C++ est recommandée mais non requise. Avec +celle de l'anglais, elle vous facilitera la consultation des L. Ladite documentation est +la seule référence qui fasse autorité. + +Si Qt est installé sur votre système, sa documentation l'est +certainement aussi : voyez le programme $QTDIR/bin/assistant. + +=head1 Installation + +=head2 Conditions requises + +Pour compiler et utiliser PerlQt, vous devez avoir: + + +=over 4 + +=item * + +un système conforme à la norme POSIX. + +=item * + +L= v5.6.0|"http://www.perl.org"> + +=item * + +L= +v3.0|"http://www.trolltech.com/developer/download/qt-x11.html"> + +=item * + +L La +librarie SMOKE (Scripting Meta Object Kompiler) fait partie du module +L's B. Vous pouvez vérifier si +une version précompilée de ce module existe pour votre système. Mais +perlQt inclut une copie, donc la version précompilée n'est pas +nécessaire. + +=item * + +Les outils GNU : automake(>=1.5), autoconf (>=2.13), aclocal... + +=back + +L'installation de Perl et de Qt sont en dehors du sujet du présent +document. Se référer aux documentations respectives de ces logiciels. + +=head2 Compilation de PerlQt + +Les instructions de cette section présupposent que le répertoire courant est +le répertoire racine de l'arborescence des sources de PerlQt. + +PerlQt utilise le système GNU Autoconf, mais il est préférable de le lancer via +le script standard C : + + perl Makefile.PL + +B Si la variable d'environnement B n'est pas définie, vous devrez +peut-être spécifier manuellement l'emplacement de Qt à l'aide de l'option : + + --with-qtdir=/emplacement/de/Qt + +Si la bibliothèque SMOKE est manquante, C générera ses sources dans +un sous-répertoire. + + make + + make install + +Cela installera PerlQt, Puic et les utilitaires pqtsh et pqtapi. + +Le lieu d'installation privilégié de SMOKE et de PUIC est le système de +fichiers de KDE3. Si KDE3 n'est pas installé (ou que la variable KDEDIR n'est pas +définie), spécifier ce lieu avec l'option C<--prefix> de C's. Ainsi : + + perl Makefile.PL --prefix=/usr + +=head2 Installation avec les droits d'utilisateur + +Pour réaliser une installation locale, sans les droits de super-utilisateur, +suivez les instructions suivantes : + +=over 4 + +=item * + +Réalisez tout d'abord une configuration normale, en spécifiant le préfixe de la hiérarchie de fichier +dans laquelle la bibliothèque Smoke et l'exécutable 'puic' seront installés : + + perl Makefile.PL --prefix=~ + +Ceci installera Smoke dans ~/lib et puic dans ~/bin + +=item * + +Reconfigurez le module PerlQt pour qu'il ne s'installe pas dans la hiérarchie Perl ordinaire : + + cd PerlQt + perl Makefile.PL PREFIX=~ + cd .. + +Attention : il ne s'agit pas du Makefile.PL situé à la racine de l'arborescence mais bien de celui +situé dans le sous-répertoire PerlQt + +=item * + +Lancez la compilation et l'installation + + make && make install + +Pour exécuter des programmes PerlQt, il vous faudra désormais indiquer à Perl l'emplacement de cette hiérarchie externe, +à l'aide d'une ligne de la forme : + + perl -Mlib="~/local/lib/perl/5.x.x" programme.pl + +où 5.x.x représente la version de Perl utilisée, ligne qui peut également être placée en tête de programme : + + use lib qw( ~/local/lib/perl/5.x.x ); + +=back + +=head1 Anatomie de PerlQt + +Un programme Qt typique utilisant des composants GUI est fondé sur une +boucle événementielle. + +Il ne se comporte pas comme une suite séquentielle +d'instructions où vous devriez gérer vous-même chaque événement (tels +que le clic de la souris ou l'enfoncement d'une touche). + +Au lieu de cela, vous créez un objet B et les composants +du GUI qu'il utilise, puis vous définissez les méthodes d'objet à appeler +lors de l'occurrence d'un événement, puis démarrez la boucle événementielle. + +C'est tout. Qt gérera les événements et les dirigera vers les +routines appropriées. + +Voyons un programme PerlQt minimal. + +=head2 Hello World + + 1: use Qt; + 2: my $a = Qt::Application(\@ARGV); + 3: my $hello = Qt::PushButton("Hello World!", undef); + 4: $hello->resize(160, 25); + 5: $a->setMainWidget($hello); + 6: $hello->show; + 7: exit $a->exec; + +=for html +
+
+ +Ce programme charge d'abord le module Qt [line 1] puis crée l'objet +application B<$a> en lui passant une référence au tableau C<@ARGV> +contenant les arguments de la ligne de commande [l.2]. Cet objet +application est unique pour un interpréteur Perl donné et peut être +ensuite accédé par la fonction pure B. + +La ligne 3, crée un PushButton orphelin (c.à.d sans parent: non +contenu dans un autre widget) dont nous passons la valeur B +comme argument pour le parent. B est l'équivalent perlQt d'un +pointeur null en C++. + +Après les instructions de "mise en page" [l.4], nous indiquons à +l'objet application que le widget principal est ce +PushButton... Ainsi, il saura que fermer la fenêtre associée à ce +widget signifie: I. + +Pour rendre ce widget visible (qui est par défaut caché), on +appelle la méthode B [l.6] et lance la boucle +événementielle [l.7]. + +B + +=over 4 + +=item 1 + +Les classes PerlQt sont accessibles par le préfixe B au lieu du +B initial des classes Qt en C++. En consultant la L, vous devez donc mentalement changer le +nom d'une clasee B en B. + +=item 2 + +De manière similaire à C++, un objet est créé par l'appel d'un +B de même nom que la classe dont il est une méthode. + +Vous ne devez donc pas dire C ou Cnew()> +contrairement à l'usage commun en Perl. + +Dites simplement: + + my $object = Qt::(arg_1, ..., arg_n); + +Un constructeur sans argument s'énonce encore plus brièvement : + + my $object = Qt::; + + +=item 3 + +Comme il a déjà été dit, l'équivalent Perl d'un pointeur C++ est le mot-clé +Perl B. + +Les pointeurs sont les arguments précédés par le caractère B<*> dans la +documentation Qt (Par exemple: "C"). + +=back + +=head2 L'héritage et les objets + +Avant d'expliquer comment les routines Perl peuvent être appelées de Qt, +parlons du mécanisme d'héritage vu de PerlQt. + +PerlQt est conçu pour allier la simplicité de Qt à la puissance et à la +flexibilité de Perl. Pour ce faire, PerlQt étend le paradigme objet de +Perl pour mimer Qt et son mécanisme de B. + +=head3 Un Widget personnalisé + +Réécrivons le programme "Hello World!" avec une version personnalisée +de PushButton: + + 1: use strict; + 2: + 3: package Button; + 4: use Qt; + 5: use Qt::isa qw(Qt::PushButton); + 6: + 7: sub NEW + 8: { + 9: shift->SUPER::NEW(@_[0..2]); + 10: resize(130, 40); + 11: } + 12: + 13: 1; + 14: + 15: package main; + 16: + 17: use Qt; + 18: use Button; + 19: + 20: my $a = Qt::Application(\@ARGV); + 21: my $w = Button("Hello World!", undef); + 22: $a->setMainWidget($w); + 23: $w->show; + 24: exit $a->exec; + +Pour implanter notre propre version de PushButton, nous créons un nouveau +package [l.3] et importons Qt [l.4]. + +Nous utilisons le pragma C [l.5] pour déclarer notre widget +comme sous-classe de PushButton. Ce pragma accepte une liste de une ou +plusieurs classes dont dérive la classe à définir. + +Créons maintenant un constructeur pour notre nouveau widget +en écrivant une routine appelée B I<(notez les majuscules qui +marquent une méthode différente du constructeur "new" usuel)>. +Le constructeur PerlQt est appelé B I. + +Note widget doit d'abord appeler le constructeur de sa classe de base +(ici: Qt::PushButton) à la ligne 9, avec tous les arguments que nous +avons reçus. + +Nous créons ainsi un objet instance de notre classe. Cette objet est +accessible par la fonction B (Attention: ce n'est pas la +variable C<$this> mais simplement C). + +Chaque fois que nous invoquons une méthode à partir de notre package +nous pouvons écrire indifféremment C ou +Cmethod()>; + +=head3 L'utilisation d'attributs + +Lors de la construction d'un objet composite, vous pouvez simplement créer +ses différents composants à l'intérieur de variables de scope lexical +(c.à.d déclarées par B) puisque les widgets sont seulement détruits +par leur parent et non nécessairement quand leur conteneur disparaît +du scope. + +En d'autres termes, PerlQt utilise un système de comptage de +références pour gérer la destruction des objets. + +Souvent cependant, vous souhaiterez accéder aux composants de votre objet depuis +un tout autre endroit que celui où vous l'avez créé (par exemple pour modifier une +légende de bouton dynamiquement). Dans ce cas, la syntaxe traditionnelle de perl +propose de stocker une référence à ces composants dans la table associative (hash) de +l'objet lui-même. Mais cette syntaxe s'avère peu pratique à l'usage et beaucoup +trop libre - il n'y a pas de vérification à la compilation de sorte que vous pouvez +accéder à des clefs non existantes sans déclencher d'erreur. + +En lieu et place de cette syntaxe, PerlQt introduit le concept d'B. + +Les attributs sont de simples variables perl, écrites sans le signe dollar initial, et +pouvant contenir toute donnée qui est une propriété de votre objet. +Leur principal avantage est de fournir une syntaxe très rapide et vérifiable à la compilation. + +Pour définir et pouvoir utiliser de nouveaux attributs, il suffit d'utiliser +le pragma C, suivi d'une liste des noms d'attributs souhaités. +Ainsi: + + + 1: use strict; + 2: + 3: package Button; + 4: use Qt; + 5: use Qt::isa qw(Qt::PushButton); + 6: use Qt::attributes qw( + 7: itsTime + 8: pData + 9: ); + 10: + 11: sub NEW + 12: { + 13: shift->SUPER::NEW(@_[0..2]); + 14: itsTime = Qt::Time; + 15: itsTime->start; + 16: pData->{'key'} = " Foo "; + 17: } + 18: + 19: sub resizeEvent + 20: { + 21: setText( "w: ". width() ." h: ". height() . + 22: "\nt: ". itsTime->elapsed . pData->{'key'} ); + 23: } + 24: + 25: 1; + +=for html +
+
+ + +L'attribut itsTime est déclaré à la ligne 7 et initialisé par un objet C +à la ligne 14. + +Puisque nous réimplémentons la fonction virtuelle "resizeEvent" +[l.19], chaque fois que le widget principal est redimensionné, cette +fonction "resizeEvent" sera déclenchée et le texte de notre Button mis +à jour avec les valeurs venant de l'objet [1.21] et les attributs que +nous avons définis [1.22]. + +B + +=over 4 + +=item * + +Pour hériter d'une classe Qt, un package doit contenir un +pragma C. + +Ainsi: + + use Qt::isa "Qt::widget"; + +=item * + +Le constructeur d'objet est nommé B et est appelé implicitement. +Vous ne devez donc pas dire: + + my $o = MyButton->NEW("Hello"); + +Mais bien : + + my $o = MyButton("Hello"); + +=item * + +A l'intérieur d'un package, on accéde l'instance courante par la +fonction B. + +Quand une fonction membre est appelée, les arguments sont accessibles +par le tableau B<@_>, mais le premier élément de B<@_> n'est pas une +référence à l'objet contrairement à l'usage commun en Perl. + +Vous ne pouvez donc pas dire : + + sub myMember + { + my $moi = shift; + my $arg = shift; + $arg->doThat($moi); + $moi->doIt; + } + +Écrivez plutôt : + + sub myMember + { + my $arg = shift; + $arg->doThat(this); + doIt(); + } + +De plus, si vous voulez appeler une méthode dans une classe de base à +partir d'une classe dérivée, utilisez l'attribut spécial SUPER : + + sub exemple + { + print "Appel de la méthode 'exemple' dans la classe de base"; + SUPER->exemple(@_) + } + +Notez aussi que la construction : + + this->SUPER::Exemple(@_); + +est possible, mais qu'elle passe l'objet comme premier argument. + +=item * + +Lorsque vous devez stocker dans votre package un objet contenu, vous +devez le définir comme B : + + use Qt::attributes qw( + firstAttribute + ... + lastAttribute); + +Il sera alors disponible comme accesseur : + + firstAttribute = myContainedWidget( this ); + firstAttribute->resize( 100, 100 ); + +B Pour ceux qui souhaitent en savoir plus, les attributs sont implémentés +à l'aide de sub lvalue, c'est à dire de fonctions assignables. +En interne, elles ne font que pointer sur la clef de hachage correspondante dans +l'objet B, ce qui rend les tournures "unAttribut->fonction()" et +"this->{'unAttribut'}->fonction()" strictement équivalentes +(si ce n'est que la première est vérifiée au moment de la compilation). + +=item * + +Pour réimplémenter une B, créez simplement une +B de même nom que cette fonction. + +Les fonctions virtuelles existantes sont marquées comme telles dans +la documentation de Qt (ce sont les méthodes précédées du mot clef "virtual"). + +Vous pouvez visualiser les noms de méthodes virtuelles que Qt tentera d'appeler +dans votre classe en plaçant C en tête de +votre programme. + +=back + +=head2 Signaux et Slots + +Voyons maintenant comment les objets Qt peuvent communiquer entre eux +de manière à ce qu'un événement concernant un objet puisse déclencher +l'exécution d'une routine en un quelconque endroit de votre programme. + +Dans d'autres toolkits, les callbacks (appels en retour) sont généralement +utilisés à cet effet. Mais Qt dispose d'un mécanisme beaucoup plus puissant +et plus flexible : les B. + +On peut se le représenter comme le cablage entre les composants d'une +chaîne Hi-Fi. Un amplificateur, par exemple, émet des signaux de sortie +sans chercher à savoir si des enceintes lui sont connectées ou non. +Un magnétophone peut attendre un signal sur sa prise d'entrée +pour commencer à enregistrer, et il ne cherchera pas à savoir s'il est +l'unique destinataire de ce signal ou si ce dernier est aussi reçu par un graveur de CD +ou écouté au casque. + +Un composant Qt se comporte comme notre amplificateur ou notre +magnétophone. Il a des sorties ou B et des entrées ou +B. Chaque sortie (signal) est connectable à un nombre illimité +d'entrées (slots). La sortie d'un composant peut être potentiellement +branchée à toute entrée d'un composant (y compris lui-même), + + +La syntaxe de ce système de connexion est soit: + +Qt::Object::connect( envoyeur, SIGNAL 'mon_signal(types_d_arguments)', +recepteur, SLOT 'monslot(types_d_arguments)'); + +soit: + +unObjet->connect( envoyeur, SIGNAL 'mon_signal(types_d_arguments)', +SLOT 'monslot(types_d_arguments)'); + +Dans le second cas, le récepteur est omis car c'est l'objet lui-même, + +Ce mécanisme est extensible à volonté par la déclaration de nouveaux Signaux et +Slots par l'usage des pragma C et C +(voir aussi la deuxième syntaxe décrite plus bas). + +Chaque slot déclaré appellera la routine correspondante de votre +objet. Chaque signal déclaré peut être déclenché via le mot-clé B. + +B + + 1: use strict; + 2: + 3: package Button; + 4: use Qt; + 5: use Qt::isa qw(Qt::PushButton); + 6: use Qt::attributes qw(itsTime); + 7: use Qt::slots + 8: aEteClicke => [], + 9: changement => ['int', 'int']; + 10: use Qt::signals + 11: changeLe => ['int', 'int']; + 12: + 13: sub NEW + 14: { + 15: shift->SUPER::NEW(@_[0..2]); + 16: itsTime = Qt::Time; + 17: itsTime->start; + 18: this->connect(this, SIGNAL 'clicked()', SLOT 'aEteClicke()'); + 19: this->connect(this, SIGNAL 'changeLe(int,int)', SLOT 'changement(int,int)'); + 20: } + 21: + 22: sub aEteClicke + 23: { + 24: my $w = width(); + 25: my $h = height(); + 26: setText( "w: $w h: $h\nt: ". itsTime->elapsed ); + 27: emit changeLe($w, $h); + 28: } + 29: + 30: sub changement + 31: { + 32: my ($w, $h) = @_; + 33: print STDERR "w: $w h: $h \n"; + 34: } + 35: + 36: 1; + +Nous définissons dans ce package deux nouveaux slots et un nouveau signal. + + +La documentation Qt nous dit que tout PushButton clické émet un signal +C ; nous le connectons donc à notre nouveau slot [ligne 18]. + +Nous connectons aussi notre signal C à notre slot +C. + +Ainsi, quand on appuie (clique) sur notre Button , le signal +C est émit et déclenche le slot C. +C émet à son tour le signal C[l.27], +appelant de ce fait le slot C, avec deux arguments. + +Enfin, il existe une syntaxe alternative introduite dans PerlQt-3.008 : + + sub un_slot : SLOT(int, QString) + { + $int = shift; + $string = shift; + # faire quelque chose + } + +et + + sub un_signal : SIGNAL(QString); + +Cette syntaxe est parfaitement compatible avec la déclaration par le biais de +C et C. +Il peut d'ailleurs d'avérer très profitable pour la clarté du programme de déclarer tout d'abord +les signaux/slots au moyen de C, puis de rappeler cette déclaration au niveau de +l'implémentation à l'aide de la seconde syntaxe. +Les déclarations seront alors vérifiées à la compilation, et le moindre conflit +générera un avertissement. + +=head1 Développement rapide (RAD) avec Qt Designer et Puic + + +=head2 Introduction + +=over 4 + +=item * N.B: + +Depuis la version 3.008, il existe un plugin spécifique à PerlQt pour Qt Designer. +Ce plugin (disponible sur les pages internet du projet) apporte le confort d'une intégration poussée, +la coloration syntaxique Perl, la complétion automatique, et permet de lancer et déboguer un projet +sans quitter l'interface du Designer. +Ce qui suit reste néanmoins parfaitement valable pour ce qui est de l'utilisation de puic en ligne de commande, +et pour l'utilisation de Qt Designer I le plugin spécifique. + +=back + +Aussi puissant et intuitif que soit Qt, écrire une GUI complète reste un exercice +fastidieux. + +Heureusement, Qt est fourni avec un constructeur de GUI sophistiqué +appelé Qt Designer qui est quasiment un environnement de développement +intégré. Il comporte la gestion de Projets, la création d'un GUI par +des actions de "drag and drop", un butineur d'objet complet, +l'interconnexion graphique de signaux et de slots, et plus encore. + +L'information générée par Qt Designer's est en format XML et peut donc +être parsée par différentes commandes comme dont B (le +compilateur d'interface utilisateur PerlQt). + +Supposons que vous avez déja construit un fichier d'interface avec +Qt Designer, la transcription en un programme PerlQt se fait par +la simple exécution de la commande : + + puic -x -o program.pl program.ui + +Cela génèrera le package défini dans votre fichier ui et un package +principal à fins de test, + +Vous pouvez préférer : + + puic -o package.pm program.ui + +Cela ne générera que le package qui pourra être utilisé par un programme séparé. + +=head2 Inclure des Images + + +Il y a deux manières d'inclure des B: + +=over 4 + +=item * Inclusion Inline + +A cette fin, nous devons sélectionner "Edit->Form +Settings->Pixmaps->Save inline" dans Qt Designer et executer ensuite: + + puic -x -o F F + + +=item * Image Collection + +Cette stratégie est plus complexe, mais plus propre et plus puissante. + + puic -o F -embed F F ... F + +Ajoutez l'instruction C dans le package principal +de votre programme. + +Si vous avez créé un fichier projet dans Qt Designer et ajouté toutes +les images dans un groupe (par "Project->Image Collection"), vous +disposez ensuite de ces images dans le répertoire où votre fichier +projet (*.pro) est stocké, dans le sous-répertoire B. Vous pouvez +alors générer la collection d'images par: + + puic -o F -embed F images/* + +Vous pouvez utiliser autant de collections d'images que vous voulez +dans un programme en ajoutant simplement une instruction B +pour chaque collection. + +=back + +=head2 Travailler avec des fichiers B<.ui> + +Souvent, vous voudrez regénérez votre interface utilisateur à +à cause d'une modification ou extension de votre design initial. +C'est donc une mauvais idée d'écrire votre code dans le fichier Perl +autogénéré car vous risquerez d'écraser le code que vous avez écrit +manuellement ou vous devrez faire des copier-coller intensifs. + +Voici une meilleure méthode : + +=over 4 + +=item * Écrire l'implémentation de slots dans le Designer + +Dans Qt Designer, selectionnez l'onglet I dans l'explorateur +d'objets (B). Vous pouvez ainsi voir représentées +sous forme d'arbre les classes que vous avez générées. Maintenant, si +vous cliquez deux fois sur l'entrée I, +un dialogue vous demande si vous voulez créer un nouveau slot pour +votre module. Une fois cela fait, le nouveau slot apparait à +l'intérieur de l'arbre l'explorateur d'objet; cliquer dessus vous +amènera à votre fichier BVotre ClasseE.ui.h> où vous pouvez +écrire l'implémentation de votre slot. + +Par défaut, il devrait ressembler à ceci : + + void Form1::newSlot() + { + + } + + +La déclaration du slot est réellement du code C++, mais ignorons cela +et écrivons du code Perl entre les deux accolades en faisant bien +attention d'indenter notre code avec au moins un espace. + + void Form1::newSlot() + { + print STDERR "Hello world from Form1::newSlot(); + if(this->foo()) + { + # faire quelque chose + } + } + +Notre code Perl ainsi écrit sera sauvé dans le fichier ui.h et +B prendra soin de le placer dans notre programme final. + +Ici, après l'exécution de B sur le ficier Form1.ui, vous +devriez avoir: + + sub newSlot + { + print STDERR "Hello world from Form1::newSlot(); + if(this->foo()) + { + # faire quelque chose + } + } + +=item * Sous-classez votre GUI + +En utilisant l'option I<-subimpl> de B, vous pouvez générer un +module dérivé qui hérite l'interface utilisateur originelle. + +Typiquement, vous générez le module dérivé une fois, et écrivez votre +code dans ce module dérivé. Ainsi, quand vous devez modifier votre +module GUI, regénérez le module dont il dérive et il héritera les +changements. + +Pour générer le module de base : + + puic -o Form1.pm form1.ui + +(faîtes cela aussi souvent que nécessaire: n'éditez jamais +manuellement form1.ui puisqu'il serait écrasé) + + +Pour générer le GUI dérivé : + + puic -o Form2.pm -subimpl Form2 form1.ui + +ou + + puic -o program.pl -x -subimpl Form2 form1.ui + +(faites cela une fois et travaillez avec le fichier résultant) + +=back + +=head1 Autres outils de développement + +PerlQt comprend également deux programmes pouvant vous aider à maîtriser l'API de Qt : + +=head2 pqtapi + +pqtapi est un outil d'introspection en ligne de commande. + + utilisation: pqtapi [-r ] [] + + options: + -r : chercher les méthodes correspondant à l'expression régulière + -i : avec -r, effectue une recherche insensible à la casse + -v : afficher les versions de PerlQt et de Qt + -h : afficher ce message d'aide + +ex: + + $>pqtapi -ir 'setpoint.* int' + void QCanvasLine::setPoints(int, int, int, int) + void QPointArray::setPoint(uint, int, int) + +=head2 pqtsh + +B est un shell graphique permettant de tester l'API de manière interactive. +Un exemple dynamique est accessible dans l'entrée de menu CExample>. + +=for html +
+
+ +=head1 Limitations + +Les classes à modèle (templates) ne sont pas encore accessibles par PerlQt. +En revanche, les classes dérivées de classes à modèle sont disponibles. + +Vous pouvez reconnaître ce type de classe en ce que leurs arguments comprennent un type générique placé entre +les signes "<" et ">". + +ex: + QDictIterator ( const QDict & dict ) + + +=head1 Crédits + +PerlQt-3 est (c) 2002 Ashley Winters (et (c) 2003 Germain Garand) + +Kalyptus et l'engin de génération Smoke sont (c) David Faure and Richard Dale + +Puic is (c) TrollTech AS., Phil Thompson et Germain Garand, + +Ledit logiciel est délivré sous la GNU Public Licence v.2 or later. + + +=head1 Appendice: Les conventions de C++ et leur traduction en Perl + +Lorsque vous voulez utiliser depuis PerlQt une classe ou méthode décrite +dans la L Qt (voyez aussi le programme +$QTDIR/bin/assistant livré avec Qt), vous devez suivre des règles de translation simples. + +=over 4 + +=item Noms de classe + +=over 4 + +=item * + +Les noms de classes utilisent le préfixe B au lieu de B pour +être conforme à l'usage Perl. Ainsi: QComboBox est nommé Qt::ComboBox +dans PerlQt. + +=back + +=item Fonctions + +=over 4 + +=item * + +Les fonctions décrites comme B sont accédées directement et non +à travers un objet. Ainsi la fonction statique Foo de la classe B +peut être accédée de PerlQt par + + Qt::Bar::Foo( arg-1,...,arg-n); + +=item * + +Les fonctions décrites comme B ou B sont +accessibles à travers l'objet par l'opérateur + B<-E> . +Par exemple: + + $widget->show; + +Il n'y a pas de différence fondamentale entre les méthodes et les +signaux, néanmoins PerlQt fournit le mot-clé B comme une +mnémonique pratique pour rendre clair que vous émettez un signal : + + emit $button->clicked; + +=back + +=item Arguments + +=over 4 + +=item * Par valeur + +Lorsqu'un argument n'est pas précédé par un des caractères B<&> or +B<*>, il est passé par valeur. Pour tous les types basiques tels que +int, char, float and double, PerlQt convertira automatiquement les +valeurs litérales et scalaires dans le type correspondants C++. + +Ainsi pour le prototype d'un constructeur écrit dans la documentation +comme ceci: + QSize ( int w, int h ) + + +Vous écrirez : + + Qt::Size(8, 12); + +=item * Par référence + +Lorsqu'un argument est précédé par le caractère B<&>, Il est une +référence à un objet ou à un type. Vous pouvez alors fournir un nom de +variable ou un objet temporaire : + + $keyseq = Qt::keySequence( &Qt::CTRL + &Qt::F3 ); + $widget->setAccel( $keyseq ); + +ou + + $widget->setAccel(Qt::keySequence( &Qt::CTRL + &Qt::F3 ); + +Si l'argument n'est I qualifié par B (constante), l'argument +est un objet qui peut être altéré par la méthode, vous devez +donc passer une variable. + +=item * Par pointeur + +Lorsqu'un argument est précédé par le caractère B<*>, +un pointeur vers un objet ou un type est attendu. En PerlQt, vous +pouvez fournir un nom de variable ou le mot clé B à la place +du pointer Null. + +De plus, si l'argument est const, l'objet passé en argument est en +lecture seule: il ne peut pas être modifié. + +=back + +=item Énumérations + +Les Énumerations sont une forme d'alias pour des valeurs numériques +dont il serait autrement difficile de se souvenir: + +Exemple C++: + + enum Strange { Apple, Orange, Lemon } + +Ici, C est le type (au sens de C++) de l'énumération, et +C, C et +C ses valeurs possible , qui sont des aliases pour des +nombres (ici 0, 1 et 2) + +L'accès aux valeurs d'énumération en Perl Qt est un appel +de fonction statique. + +Donc, si vous voulez éviter des prblèmes de lisibilité, nous vous +recommandons l'usage d'une syntaxe alternative d'appel de fonction +pour marquer l'utilisation d'un alias d'énumération: C<&fonction>. + + +Revenons à notre exemple C. + +Si nous rencontrons sa définition dans la classe C, vous +écrirez en PerlQt : + + $pomme_plus_orange = &Qt::Fruit::Pomme + &Qt::Fruit::Orange; + +=item Opérateurs + +Dans PerlQt, la B fonctionne de manière transparente. +Si un opérateur est surchargé dans une classe Qt (ce qui signifie que son utilisation +déclenchera un appel de méthode, au lieu d'utiliser l'opérateur générique) +il sera également surchargé dans PerlQt. + +ex-1: surcharge de '+=' + + $p1 = Qt::Point(10, 10) + $p2 = Qt::Point(30,40) + $p2 += $p1; # $p2 devient (40,50) + +ex-2: surcharge de '<<' + + $f = Qt::File("example"); + $f->open( IO_WriteOnly ); # voir l'entrée 'Constantes' plus bas + $s = Qt::TextStream( $f ); + $s << "Que faire avec " << 12 << " pommes ?"; + + +B : le constructeur de copie (signe égal, '=') n'est jamais surchargé, +attendu qu'il ne pourrait fonctionner que partiellement et que le paradigme de +Perl est très différent de C++ en matière de copie d'objets. + +=item Constantes + +Qt n'utilise pas beaucoup de constantes, mais on en trouve cependant dans le module d'Entrées/Sorties, +où elles font office de drapeaux pour les modes d'ouverture de fichiers. + +Pour éviter de polluer inutilement l'espace de nom, nous avons regroupé les constantes dans le module +B, d'où elles seront chargées à la demande. + +Ainsi, pour importer l'ensemble des constantes d'E/S, on écrira : + + use Qt::constants; + +Et pour importer quelques symboles seulement : + + use Qt::constants qw( IO_ReadOnly IO_WriteOnly ); + +=item Fonctions globales + +Qt dispose de fonctions utilitaires, telles bitBlt, qCompress, etc. + +Ces fonctions ont été rassemblées dans un espace de nom commun: +C. + +Vous pourrez donc y accéder soit par un appel pleinement qualifié : + + Qt::GlobalSpace::qUncompress( $buffer ) + +Soit en important préalablement ces fonctions dans l'espace de nom courant : + + use Qt::GlobalSpace; + qUncompress( $buffer ) + +Bien entendu, vous pouvez aussi n'importer que les fonctions souhaitées : + + use Qt::GlobalSpace qw( qUncompress bitBlt ) + +B GlobalSpace renferme également des opérateurs de portée globale, tels +celui permettant d'aditionner deux Qt::Point(). Ces opérateurs seront appelés +automatiquement. + +ex: + + $p1 = Qt::Point(10, 10) + Qt::Point(20, 20) + +=back + +=head1 Annexe 2 : Internationalisation + +PerlQt résout les problèmes d'internationalisation en convertissant systématiquement les B +de Qt en B côté Perl. + +Les conversions en sens inverse, depuis Perl vers Qt sont traitées différemment suivant le contexte : + +=over 4 + +=item * Si la chaîne de caractère est déjà marquée comme étant utf8 + +alors elle sera convertie en QString directement. + +C'est la manière privilégiée d'opérer, et la plus simple : +Il vous suffit d'insérer un pragma B en tête de vos programmes, puis d'utiliser un éditeur de +texte supportant l'utf8 (quasiment tous de nos jours) pour élaborer votre code source. +Les chaînes seront marquées par Perl automatiquement. + +=item * Si la chaîne n'est pas marquée comme utf8, et le pragma 'use locale' n'est pas actif + +alors la conversion en QString se fera depuis l'B. + +=item * Si la chaîne n'est pas marquée comme utf8, et le pragma 'use locale' est actif + +alors la conversion en QString se fera depuis votre B. + +=back + +Lorsque des chaînes contiennent de l'utf8, Perl adapte automatiquement ses opérateurs pour que +leur gestion soit entièrement transparente (comprendre opaque, comme toujours...). +Cependant, vous pourrez avoir besoin à l'occasion de les transcrire en d'autres jeux d'encodage. +Ceci peut se faire soit avec Qt : + + $tr1=Qt::TextCodec::codecForLocale(); # ceci utilisera la locale en vigueur + $tr2=Qt::TextCodec::codecForName("KOI8-R"); # ceci force l'emploi d'une locale spécifique (Russe) + + print $tr1->fromUnicode(Qt::DateTime::currentDateTime()->toString)."\n\n"; + print $tr2->fromUnicode($une_chaine_utf8); + +Soit avec les outils de Perl (pour perl >= 5.8.0). +Se reporter à ce sujet à la documentation du module B (C). + +=head3 désactiver l'encodage utf8 + +Les programmeurs souhaitant désactiver temporairement l'encodage utf8 +(pour la gestion de programmes externes ou de modules anciens ne supportant pas cet encodage) +pourront utiliser le pragma B (et sa réciproque : B). + +Dans la portée de ce pragma, les conversions depuis QString vers les chaînes Perl se feront en ISO-Latin1 +(par défaut) ou suivant la locale en vigueur (si B est actif). + +Notez bien qu'il est préférable de I, en ce qu'il ruine totalement les +efforts de standardisations autour d'utf8 entrepris depuis plusieurs années déjà. +Il est très préférable de corriger les programmes fautifs. + +=head1 Annexe 3 : Canaux de déboguage + +Le module B offre divers canaux de déboguage permettant de filtrer +le flux conséquent d'informations disponibles pour l'adapter à vos besoins. + + use Qt::debug; + + use Qt::debug qw|calls autoload verbose|; + +Avec le pragma C, seuls les canaux B et B sont activés. +Si vous le faites suivre d'une liste précise de canaux, seuls ceux-ci seront affichés. + +B + +=over 4 + +=item * ambiguous + +Vérifier si les appels de méthodes sont ambigus, et dire quelle méthode, parmi le jeux +d'alternatives, à finalement été choisie. + +=item * verbose + +Donner davantage d'informations. + +Utilisé avec B, vous donnera les correspondances les plus proches lorsqu'un appel de méthode échoue. + +ex: + + use Qt; + use Qt::debug; + $a= Qt::Application(\@ARGV); + $a->libraryPath("chose"); + + --- No method to call for : + QApplication::libraryPath('chose') + Closer candidates are : + static void QApplication::addLibraryPath(const QString&) + static QStringList QApplication::libraryPaths() + static void QApplication::removeLibraryPath(const QString&) + static void QApplication::setLibraryPaths(const QStringList&) + +=item * calls + +Pour chaque appel de méthode, vous dira quelle méthode Qt est finalement appelée, +en précisant les arguments si B est actif. + +=item * autoload + +Détaille le passage dans le code intermédiaire faisant la jonction entre Perl et Qt. + +=item * gc + +Donne des informations sur la collection des déchets, c'est à dire sur la destruction des objets, +qu'ils soient détruits depuis Perl ou Qt. + +=item * virtual + +Vous averti chaque fois qu'une fonction virtuelle tente d'accéder à sa réimplémentation en Perl +(que cette réimplémentation existe ou non). + +=item * all + +Activer tous les canaux. + +=back + +=head1 Annexe 4 : Marshalleurs + +Un marshalleur est un convertisseur permettant de transcrire un type de données en un autre. + +Dans PerlQt, la plupart des objets Qt gardent leurs propriétés d'objet, ce qui permet d'invoquer leurs méthodes +et de changer leurs propriétés comme il se doit. +Cependant, il arrive que l'objet d'origine corresponde à ce point à un type natif de Perl qu'il serait malséant +d'utiliser l'interface C++ et beaucoup plus naturel de lui substituer son équivalent. + +Ici interviennent les marshalleurs. +Plutôt que de retourner un objet Qt::StringList, qui serait délicat à manipuler, +PerlQt le transformera en référence de liste Perl. +Dès lors, tous les opérateurs de manipulation de liste pourront lui être appliqué : +on gagne en densité, en cohérence et en simplicité. + +Cette transformation s'appliquera aussi en sens inverse, et n'importe quelle liste de chaînes Perl +pourra être donnée en argument à une méthode attendant une Qt::StringList. + + Liste des marshalleurs (PerlQt-3.008) + ----------------------------------------------------------------- + float, double <=> réel Perl (NV) + char, uchar, int, uint, enum + long, ulong, short, ushort <=> entier Perl (IV) + QString, -&, -* => chaîne Perl (utf8) + QString, -&, -* <= chaîne Perl (utf8 ou iso-latin1 ou locale) + QCString, -&, -* <=> chaîne Perl (utf8 ou octets, suivant contenu ou pragma "bytes") + QStringList, -&, -* => référence à une liste de chaînes Perl (utf8) + QByteArray, -&, -* <=> chaîne Perl (octets) + int&, -* <=> entier Perl (IV) + bool&, -* <=> booléen Perl + char* <=> chaîne Perl (octets) + char** <= référence à une liste de chaînes Perl (octets) + uchar* <= chaîne Perl(octets) + QRgb* <= référence à une liste d'entiers Perl (IV) + QCOORD* <= référence à une liste d'entiers Perl (IV) + void* <=> référence à un entier Perl (IV) + QValueList, - *, - & <=> référence à une liste d'entiers Perl (IV) + QCanvasItemList, - *, - & => réference à une liste de Qt::CanvasItem + QWidgetList, - *, - & <=> réference à une liste de Qt::Widget + QObjectList, - *, - & <=> réference à une liste de Qt::Object + QFileInfoList, - *, - & <=> réference à une liste de Qt::FileInfo + QPtrList, - *, - & <=> réference à une liste de Qt::Tab + QPtrList, - *, - & <=> réference à une liste de Qt::ToolBar + QPtrList, - *, - & <=> réference à une liste de Qt::NetworkOperation + QPtrList, - *, - & <=> réference à une liste de Qt::DockWindow + (QUObject*) + diff --git a/doc/fr/index.html b/doc/fr/index.html new file mode 100644 index 0000000..2f5e788 --- /dev/null +++ b/doc/fr/index.html @@ -0,0 +1,1120 @@ + + + +Programmer avec PerlQt + + + + + + +

+ + + + + +
+

+

+

Programmer avec PerlQt

+

Germain Garand traduit par Stéphane Payrard, révisé et augmenté par l'auteur.

+

Ce document décrit l'interface Perl au toolkit Qt 3.x. Contacter +l'auteur à <germain@ebooksfrance.com> ou le traducteur à +<stef@mongueurs.net>. Vous trouverez le document original sur le site +perlqt.sourceforge.net

+

+

+
+

Introduction

+

PerlQt-3, crée par Ashley Winters, est une interface perl aux composants +graphiques (et non graphiques) fournis par Qt3.

+

Le toolkit Qt 3.0 auquel PerlQt accède à été écrit en C++ par la société +Trolltech: Trolltech.

+

PerlQt3 est fondé sur la librairie +SMOKE, +une surcouche fine indépendante du langage. Cette couche a été générée +à partir des fichiers d'en tête de Qt par le +kalyptus +de Richard Dale grâce au module de David Faure.

+

Le présent document décrit les principes de la programmation PerlQt. +Vous devez avoir des notions de programmation orientée objet en Perl pour le +lire. Une connaissance de C++ est recommandée mais non requise. Avec +celle de l'anglais, elle vous facilitera la consultation des manuels en ligne de Qt. Ladite documentation est +la seule référence qui fasse autorité.

+

Si Qt est installé sur votre système, sa documentation l'est +certainement aussi : voyez le programme $QTDIR/bin/assistant.

+

+

+
+

Installation

+

+

+

Conditions requises

+

Pour compiler et utiliser PerlQt, vous devez avoir:

+
    +
  • +un système conforme à la norme POSIX. +

    +
  • +Perl >= v5.6.0 +

    +
  • +Qt >= v3.0 +

    +
  • +SmokeQt 1.2.1 La +librarie SMOKE (Scripting Meta Object Kompiler) fait partie du module +KDE's kdebindings. Vous pouvez vérifier si +une version précompilée de ce module existe pour votre système. Mais +perlQt inclut une copie, donc la version précompilée n'est pas +nécessaire. +

    +
  • +Les outils GNU : automake(>=1.5), autoconf (>=2.13), aclocal... +

+

L'installation de Perl et de Qt sont en dehors du sujet du présent +document. Se référer aux documentations respectives de ces logiciels.

+

+

+

Compilation de PerlQt

+

Les instructions de cette section présupposent que le répertoire courant est +le répertoire racine de l'arborescence des sources de PerlQt.

+

PerlQt utilise le système GNU Autoconf, mais il est préférable de le lancer via +le script standard Makefile.PL :

+
+ perl Makefile.PL
+

N.B : Si la variable d'environnement QTDIR n'est pas définie, vous devrez +peut-être spécifier manuellement l'emplacement de Qt à l'aide de l'option :

+
+ --with-qtdir=/emplacement/de/Qt
+

Si la bibliothèque SMOKE est manquante, configure générera ses sources dans +un sous-répertoire.

+
+ make
+
+ make install
+

Cela installera PerlQt, Puic et les utilitaires pqtsh et pqtapi.

+

Le lieu d'installation privilégié de SMOKE et de PUIC est le système de +fichiers de KDE3. Si KDE3 n'est pas installé (ou que la variable KDEDIR n'est pas +définie), spécifier ce lieu avec l'option --prefix de configure's. Ainsi :

+
+ perl Makefile.PL --prefix=/usr
+

+

+

Installation avec les droits d'utilisateur

+

Pour réaliser une installation locale, sans les droits de super-utilisateur, +suivez les instructions suivantes :

+
    +
  • +Réalisez tout d'abord une configuration normale, en spécifiant le préfixe de la hiérarchie de fichier +dans laquelle la bibliothèque Smoke et l'exécutable 'puic' seront installés : +
    + perl Makefile.PL --prefix=~
    +

    Ceci installera Smoke dans ~/lib et puic dans ~/bin

    +

    +
  • +Reconfigurez le module PerlQt pour qu'il ne s'installe pas dans la hiérarchie Perl ordinaire : +
    + cd PerlQt
    + perl Makefile.PL PREFIX=~
    + cd ..
    +

    Attention : il ne s'agit pas du Makefile.PL situé à la racine de l'arborescence mais bien de celui +situé dans le sous-répertoire PerlQt

    +

    +
  • +Lancez la compilation et l'installation +
    + make && make install
    +

    Pour exécuter des programmes PerlQt, il vous faudra désormais indiquer à Perl l'emplacement de cette hiérarchie externe, +à l'aide d'une ligne de la forme :

    +
    + perl -Mlib="~/local/lib/perl/5.x.x" programme.pl
    +

    où 5.x.x représente la version de Perl utilisée, ligne qui peut également être placée en tête de programme :

    +
    + use lib qw( ~/local/lib/perl/5.x.x );
    +

+

+

+
+

Anatomie de PerlQt

+

Un programme Qt typique utilisant des composants GUI est fondé sur une +boucle événementielle.

+

Il ne se comporte pas comme une suite séquentielle +d'instructions où vous devriez gérer vous-même chaque événement (tels +que le clic de la souris ou l'enfoncement d'une touche).

+

Au lieu de cela, vous créez un objet Qt::Application et les composants +du GUI qu'il utilise, puis vous définissez les méthodes d'objet à appeler +lors de l'occurrence d'un événement, puis démarrez la boucle événementielle.

+

C'est tout. Qt gérera les événements et les dirigera vers les +routines appropriées.

+

Voyons un programme PerlQt minimal.

+

+

+

Hello World

+
+ 1: use Qt;
+ 2: my $a = Qt::Application(\@ARGV);
+ 3: my $hello = Qt::PushButton("Hello World!", undef);
+ 4: $hello->resize(160, 25);
+ 5: $a->setMainWidget($hello);
+ 6: $hello->show;
+ 7: exit $a->exec;
+
+

Ce programme charge d'abord le module Qt [line 1] puis crée l'objet +application $a en lui passant une référence au tableau @ARGV +contenant les arguments de la ligne de commande [l.2]. Cet objet +application est unique pour un interpréteur Perl donné et peut être +ensuite accédé par la fonction pure Qt::app().

+

La ligne 3, crée un PushButton orphelin (c.à.d sans parent: non +contenu dans un autre widget) dont nous passons la valeur undef +comme argument pour le parent. undef est l'équivalent perlQt d'un +pointeur null en C++.

+

Après les instructions de ``mise en page'' [l.4], nous indiquons à +l'objet application que le widget principal est ce +PushButton... Ainsi, il saura que fermer la fenêtre associée à ce +widget signifie: sortir de l'application.

+

Pour rendre ce widget visible (qui est par défaut caché), on +appelle la méthode show [l.6] et lance la boucle +événementielle [l.7].

+

Sommaire de la syntaxe :

+
    +
  1. +Les classes PerlQt sont accessibles par le préfixe Qt:: au lieu du +Q initial des classes Qt en C++. En consultant la documentation Qt, vous devez donc mentalement changer le +nom d'une clasee QFoo en Qt::Foo. +

    +
  2. +De manière similaire à C++, un objet est créé par l'appel d'un +constructeur de même nom que la classe dont il est une méthode. +

    Vous ne devez donc pas dire new Qt::Foo ou Qt::Foo->new() +contrairement à l'usage commun en Perl.

    +

    Dites simplement:

    +
    + my $object = Qt::<classname>(arg_1, ..., arg_n);
    +

    Un constructeur sans argument s'énonce encore plus brièvement :

    +
    + my $object = Qt::<classname>;
    +

    +
  3. +Comme il a déjà été dit, l'équivalent Perl d'un pointeur C++ est le mot-clé +Perl undef. +

    Les pointeurs sont les arguments précédés par le caractère * dans la +documentation Qt (Par exemple: ``QWidget* widget'').

    +

+

+

+

L'héritage et les objets

+

Avant d'expliquer comment les routines Perl peuvent être appelées de Qt, +parlons du mécanisme d'héritage vu de PerlQt.

+

PerlQt est conçu pour allier la simplicité de Qt à la puissance et à la +flexibilité de Perl. Pour ce faire, PerlQt étend le paradigme objet de +Perl pour mimer Qt et son mécanisme de métaobjets.

+

+

+

Un Widget personnalisé

+

Réécrivons le programme ``Hello World!'' avec une version personnalisée +de PushButton:

+
+  1: use strict;
+  2:
+  3: package Button;
+  4: use Qt;
+  5: use Qt::isa qw(Qt::PushButton);
+  6:
+  7: sub NEW
+  8: {
+  9:   shift->SUPER::NEW(@_[0..2]);
+ 10:   resize(130, 40);
+ 11: }
+ 12:
+ 13: 1;
+ 14:
+ 15: package main;
+ 16:
+ 17: use Qt;
+ 18: use Button;
+ 19:
+ 20: my $a = Qt::Application(\@ARGV);
+ 21: my $w = Button("Hello World!", undef);
+ 22: $a->setMainWidget($w);
+ 23: $w->show;
+ 24: exit $a->exec;
+

Pour implanter notre propre version de PushButton, nous créons un nouveau +package [l.3] et importons Qt [l.4].

+

Nous utilisons le pragma Qt::isa [l.5] pour déclarer notre widget +comme sous-classe de PushButton. Ce pragma accepte une liste de une ou +plusieurs classes dont dérive la classe à définir.

+

Créons maintenant un constructeur pour notre nouveau widget +en écrivant une routine appelée NEW (notez les majuscules qui +marquent une méthode différente du constructeur ``new'' usuel). +Le constructeur PerlQt est appelé implicitement comme ligne 21.

+

Note widget doit d'abord appeler le constructeur de sa classe de base +(ici: Qt::PushButton) à la ligne 9, avec tous les arguments que nous +avons reçus.

+

Nous créons ainsi un objet instance de notre classe. Cette objet est +accessible par la fonction this (Attention: ce n'est pas la +variable $this mais simplement this).

+

Chaque fois que nous invoquons une méthode à partir de notre package +nous pouvons écrire indifféremment method() ou +this->method();

+

+

+

L'utilisation d'attributs

+

Lors de la construction d'un objet composite, vous pouvez simplement créer +ses différents composants à l'intérieur de variables de scope lexical +(c.à.d déclarées par my) puisque les widgets sont seulement détruits +par leur parent et non nécessairement quand leur conteneur disparaît +du scope.

+

En d'autres termes, PerlQt utilise un système de comptage de +références pour gérer la destruction des objets.

+

Souvent cependant, vous souhaiterez accéder aux composants de votre objet depuis +un tout autre endroit que celui où vous l'avez créé (par exemple pour modifier une +légende de bouton dynamiquement). Dans ce cas, la syntaxe traditionnelle de perl +propose de stocker une référence à ces composants dans la table associative (hash) de +l'objet lui-même. Mais cette syntaxe s'avère peu pratique à l'usage et beaucoup +trop libre - il n'y a pas de vérification à la compilation de sorte que vous pouvez +accéder à des clefs non existantes sans déclencher d'erreur.

+

En lieu et place de cette syntaxe, PerlQt introduit le concept d'attributs.

+

Les attributs sont de simples variables perl, écrites sans le signe dollar initial, et +pouvant contenir toute donnée qui est une propriété de votre objet. +Leur principal avantage est de fournir une syntaxe très rapide et vérifiable à la compilation.

+

Pour définir et pouvoir utiliser de nouveaux attributs, il suffit d'utiliser +le pragma use Qt::attributes, suivi d'une liste des noms d'attributs souhaités. +Ainsi:

+
+  1: use strict;
+  2:
+  3: package Button;
+  4: use Qt;
+  5: use Qt::isa qw(Qt::PushButton);
+  6: use Qt::attributes qw(
+  7:     itsTime
+  8:     pData
+  9: );
+ 10:
+ 11: sub NEW
+ 12: {
+ 13:   shift->SUPER::NEW(@_[0..2]);
+ 14:   itsTime = Qt::Time;
+ 15:   itsTime->start;
+ 16:   pData->{'key'} = " Foo ";
+ 17: }
+ 18:
+ 19: sub resizeEvent
+ 20: {
+ 21:    setText( "w: ". width() ." h: ". height() .
+ 22:             "\nt: ". itsTime->elapsed . pData->{'key'} );
+ 23: }
+ 24:
+ 25: 1;
+
+

L'attribut itsTime est déclaré à la ligne 7 et initialisé par un objet Qt::Time +à la ligne 14.

+

Puisque nous réimplémentons la fonction virtuelle ``resizeEvent'' +[l.19], chaque fois que le widget principal est redimensionné, cette +fonction ``resizeEvent'' sera déclenchée et le texte de notre Button mis +à jour avec les valeurs venant de l'objet [1.21] et les attributs que +nous avons définis [1.22].

+

Récapitulation

+
    +
  • +Pour hériter d'une classe Qt, un package doit contenir un +pragma use Qt::isa. +

    Ainsi:

    +
    + use Qt::isa "Qt::widget";
    +

    +
  • +Le constructeur d'objet est nommé NEW et est appelé implicitement. +Vous ne devez donc pas dire: +
    + my $o = MyButton->NEW("Hello");
    +

    Mais bien :

    +
    + my $o = MyButton("Hello");
    +

    +
  • +A l'intérieur d'un package, on accéde l'instance courante par la +fonction this. +

    Quand une fonction membre est appelée, les arguments sont accessibles +par le tableau @_, mais le premier élément de @_ n'est pas une +référence à l'objet contrairement à l'usage commun en Perl.

    +

    Vous ne pouvez donc pas dire :

    +
    + sub myMember
    + {
    +   my $moi = shift;
    +   my $arg = shift;
    +   $arg->doThat($moi);
    +   $moi->doIt;
    + }
    +

    Écrivez plutôt :

    +
    + sub myMember
    + {
    +   my $arg = shift;
    +   $arg->doThat(this);
    +   doIt();
    + }
    +

    De plus, si vous voulez appeler une méthode dans une classe de base à +partir d'une classe dérivée, utilisez l'attribut spécial SUPER :

    +
    + sub exemple
    + {
    +   print "Appel de la méthode 'exemple' dans la classe de base";
    +   SUPER->exemple(@_)
    + }
    +

    Notez aussi que la construction :

    +
    + this->SUPER::Exemple(@_);
    +

    est possible, mais qu'elle passe l'objet comme premier argument.

    +

    +
  • +Lorsque vous devez stocker dans votre package un objet contenu, vous +devez le définir comme attribut : +
    + use Qt::attributes qw(
    +        firstAttribute
    +        ...
    +        lastAttribute);
    +

    Il sera alors disponible comme accesseur :

    +
    + firstAttribute = myContainedWidget( this );
    + firstAttribute->resize( 100, 100 );
    +

    NB: Pour ceux qui souhaitent en savoir plus, les attributs sont implémentés +à l'aide de sub lvalue, c'est à dire de fonctions assignables. +En interne, elles ne font que pointer sur la clef de hachage correspondante dans +l'objet this, ce qui rend les tournures ``unAttribut->fonction()'' et +``this->{'unAttribut'}->fonction()'' strictement équivalentes +(si ce n'est que la première est vérifiée au moment de la compilation).

    +

    +
  • +Pour réimplémenter une fonction virtuelle, créez simplement une +sub de même nom que cette fonction. +

    Les fonctions virtuelles existantes sont marquées comme telles dans +la documentation de Qt (ce sont les méthodes précédées du mot clef ``virtual'').

    +

    Vous pouvez visualiser les noms de méthodes virtuelles que Qt tentera d'appeler +dans votre classe en plaçant use Qt::debug qw|virtual| en tête de +votre programme.

    +

+

+

+

Signaux et Slots

+

Voyons maintenant comment les objets Qt peuvent communiquer entre eux +de manière à ce qu'un événement concernant un objet puisse déclencher +l'exécution d'une routine en un quelconque endroit de votre programme.

+

Dans d'autres toolkits, les callbacks (appels en retour) sont généralement +utilisés à cet effet. Mais Qt dispose d'un mécanisme beaucoup plus puissant +et plus flexible : les Signaux et Slots.

+

On peut se le représenter comme le cablage entre les composants d'une +chaîne Hi-Fi. Un amplificateur, par exemple, émet des signaux de sortie +sans chercher à savoir si des enceintes lui sont connectées ou non. +Un magnétophone peut attendre un signal sur sa prise d'entrée +pour commencer à enregistrer, et il ne cherchera pas à savoir s'il est +l'unique destinataire de ce signal ou si ce dernier est aussi reçu par un graveur de CD +ou écouté au casque.

+

Un composant Qt se comporte comme notre amplificateur ou notre +magnétophone. Il a des sorties ou Signaux et des entrées ou +Slots. Chaque sortie (signal) est connectable à un nombre illimité +d'entrées (slots). La sortie d'un composant peut être potentiellement +branchée à toute entrée d'un composant (y compris lui-même),

+

La syntaxe de ce système de connexion est soit:

+

Qt::Object::connect( envoyeur, SIGNAL 'mon_signal(types_d_arguments)', +recepteur, SLOT 'monslot(types_d_arguments)');

+

soit:

+

unObjet->connect( envoyeur, SIGNAL 'mon_signal(types_d_arguments)', +SLOT 'monslot(types_d_arguments)');

+

Dans le second cas, le récepteur est omis car c'est l'objet lui-même,

+

Ce mécanisme est extensible à volonté par la déclaration de nouveaux Signaux et +Slots par l'usage des pragma use Qt::signals et use Qt::slots +(voir aussi la deuxième syntaxe décrite plus bas).

+

Chaque slot déclaré appellera la routine correspondante de votre +objet. Chaque signal déclaré peut être déclenché via le mot-clé emit.

+

Réécrivons encore notre exemple pour illustrer nos propos :

+
+  1: use strict;
+  2:
+  3: package Button;
+  4: use Qt;
+  5: use Qt::isa qw(Qt::PushButton);
+  6: use Qt::attributes qw(itsTime);
+  7: use Qt::slots
+  8:     aEteClicke => [],
+  9:     changement     => ['int', 'int'];
+ 10: use Qt::signals
+ 11:     changeLe   => ['int', 'int'];
+ 12:
+ 13: sub NEW
+ 14: {
+ 15:   shift->SUPER::NEW(@_[0..2]);
+ 16:   itsTime = Qt::Time;
+ 17:   itsTime->start;
+ 18:   this->connect(this, SIGNAL 'clicked()', SLOT 'aEteClicke()');
+ 19:   this->connect(this, SIGNAL 'changeLe(int,int)', SLOT 'changement(int,int)');
+ 20: }
+ 21:
+ 22: sub aEteClicke
+ 23: {
+ 24:    my $w = width();
+ 25:    my $h = height();
+ 26:    setText( "w: $w h: $h\nt: ". itsTime->elapsed );
+ 27:    emit changeLe($w, $h);
+ 28: }
+ 29:
+ 30: sub changement
+ 31: {
+ 32:    my ($w, $h) = @_;
+ 33:    print STDERR "w: $w h: $h \n";
+ 34: }
+ 35:
+ 36: 1;
+

Nous définissons dans ce package deux nouveaux slots et un nouveau signal.

+

La documentation Qt nous dit que tout PushButton clické émet un signal +clicked() ; nous le connectons donc à notre nouveau slot [ligne 18].

+

Nous connectons aussi notre signal ChangeLe à notre slot +changement.

+

Ainsi, quand on appuie (clique) sur notre Button , le signal +clicked() est émit et déclenche le slot aEteClicke(). +aEteClicke() émet à son tour le signal changeLe(int,int)[l.27], +appelant de ce fait le slot changement(int,int), avec deux arguments.

+

Enfin, il existe une syntaxe alternative introduite dans PerlQt-3.008 :

+
+ sub un_slot : SLOT(int, QString)
+ { 
+        $int = shift;
+        $string = shift;
+        # faire quelque chose
+ }
+

et

+
+ sub un_signal : SIGNAL(QString);
+

Cette syntaxe est parfaitement compatible avec la déclaration par le biais de +use Qt::signals et use Qt::slots. +Il peut d'ailleurs d'avérer très profitable pour la clarté du programme de déclarer tout d'abord +les signaux/slots au moyen de use Qt::slots/signals, puis de rappeler cette déclaration au niveau de +l'implémentation à l'aide de la seconde syntaxe. +Les déclarations seront alors vérifiées à la compilation, et le moindre conflit +générera un avertissement.

+

+

+
+

Développement rapide (RAD) avec Qt Designer et Puic

+

+

+

Introduction

+
    +
  • N.B:
    +
  • +Depuis la version 3.008, il existe un plugin spécifique à PerlQt pour Qt Designer. +Ce plugin (disponible sur les pages internet du projet) apporte le confort d'une intégration poussée, +la coloration syntaxique Perl, la complétion automatique, et permet de lancer et déboguer un projet +sans quitter l'interface du Designer. +Ce qui suit reste néanmoins parfaitement valable pour ce qui est de l'utilisation de puic en ligne de commande, +et pour l'utilisation de Qt Designer sans le plugin spécifique. +

+

Aussi puissant et intuitif que soit Qt, écrire une GUI complète reste un exercice +fastidieux.

+

Heureusement, Qt est fourni avec un constructeur de GUI sophistiqué +appelé Qt Designer qui est quasiment un environnement de développement +intégré. Il comporte la gestion de Projets, la création d'un GUI par +des actions de ``drag and drop'', un butineur d'objet complet, +l'interconnexion graphique de signaux et de slots, et plus encore.

+

L'information générée par Qt Designer's est en format XML et peut donc +être parsée par différentes commandes comme dont puic (le +compilateur d'interface utilisateur PerlQt).

+

Supposons que vous avez déja construit un fichier d'interface avec +Qt Designer, la transcription en un programme PerlQt se fait par +la simple exécution de la commande :

+
+ puic -x -o program.pl program.ui
+

Cela génèrera le package défini dans votre fichier ui et un package +principal à fins de test,

+

Vous pouvez préférer :

+
+ puic -o package.pm program.ui
+

Cela ne générera que le package qui pourra être utilisé par un programme séparé.

+

+

+

Inclure des Images

+

Il y a deux manières d'inclure des images ou icônes:

+
    +
  • Inclusion Inline
    +
  • +A cette fin, nous devons sélectionner ``Edit->Form +Settings->Pixmaps->Save inline'' dans Qt Designer et executer ensuite: +
    +  puic -x -o F<program.pl> F<program.ui>
    +

    +
  • Image Collection
    +
  • +Cette stratégie est plus complexe, mais plus propre et plus puissante. +
    + puic -o F<Collection.pm> -embed F<unique_identifier> F<image-1> ... F<image-n>
    +

    Ajoutez l'instruction use Collection.pm dans le package principal +de votre programme.

    +

    Si vous avez créé un fichier projet dans Qt Designer et ajouté toutes +les images dans un groupe (par ``Project->Image Collection''), vous +disposez ensuite de ces images dans le répertoire où votre fichier +projet (*.pro) est stocké, dans le sous-répertoire image. Vous pouvez +alors générer la collection d'images par:

    +
    + puic -o F<Collection.pm> -embed F<identifier> images/*
    +

    Vous pouvez utiliser autant de collections d'images que vous voulez +dans un programme en ajoutant simplement une instruction use +pour chaque collection.

    +

+

+

+

Travailler avec des fichiers .ui

+

Souvent, vous voudrez regénérez votre interface utilisateur à +à cause d'une modification ou extension de votre design initial. +C'est donc une mauvais idée d'écrire votre code dans le fichier Perl +autogénéré car vous risquerez d'écraser le code que vous avez écrit +manuellement ou vous devrez faire des copier-coller intensifs.

+

Voici une meilleure méthode :

+
    +
  • Écrire l'implémentation de slots dans le Designer
    +
  • +Dans Qt Designer, selectionnez l'onglet Source dans l'explorateur +d'objets (Object Explorer). Vous pouvez ainsi voir représentées +sous forme d'arbre les classes que vous avez générées. Maintenant, si +vous cliquez deux fois sur l'entrée Slots/public, +un dialogue vous demande si vous voulez créer un nouveau slot pour +votre module. Une fois cela fait, le nouveau slot apparait à +l'intérieur de l'arbre l'explorateur d'objet; cliquer dessus vous +amènera à votre fichier <Votre Classe>.ui.h où vous pouvez +écrire l'implémentation de votre slot. +

    Par défaut, il devrait ressembler à ceci :

    +
    + void Form1::newSlot()
    + {
    +
    + }
    +

    La déclaration du slot est réellement du code C++, mais ignorons cela +et écrivons du code Perl entre les deux accolades en faisant bien +attention d'indenter notre code avec au moins un espace.

    +
    + void Form1::newSlot()
    + {
    +     print STDERR "Hello world from Form1::newSlot();
    +     if(this->foo())
    +     {
    +         # faire quelque chose
    +     }
    + }
    +

    Notre code Perl ainsi écrit sera sauvé dans le fichier ui.h et +puic prendra soin de le placer dans notre programme final.

    +

    Ici, après l'exécution de puic sur le ficier Form1.ui, vous +devriez avoir:

    +
    + sub newSlot
    + {
    +     print STDERR "Hello world from Form1::newSlot();
    +     if(this->foo())
    +     {
    +         # faire quelque chose
    +     }
    + }
    +

    +
  • Sous-classez votre GUI
    +
  • +En utilisant l'option -subimpl de puic, vous pouvez générer un +module dérivé qui hérite l'interface utilisateur originelle. +

    Typiquement, vous générez le module dérivé une fois, et écrivez votre +code dans ce module dérivé. Ainsi, quand vous devez modifier votre +module GUI, regénérez le module dont il dérive et il héritera les +changements.

    +

    Pour générer le module de base :

    +
    + puic -o Form1.pm form1.ui
    +

    (faîtes cela aussi souvent que nécessaire: n'éditez jamais +manuellement form1.ui puisqu'il serait écrasé)

    +

    Pour générer le GUI dérivé :

    +
    + puic -o Form2.pm -subimpl Form2 form1.ui
    +

    ou

    +
    + puic -o program.pl -x -subimpl Form2 form1.ui
    +

    (faites cela une fois et travaillez avec le fichier résultant)

    +

+

+

+
+

Autres outils de développement

+

PerlQt comprend également deux programmes pouvant vous aider à maîtriser l'API de Qt :

+

+

+

pqtapi

+

pqtapi est un outil d'introspection en ligne de commande.

+
+ utilisation: pqtapi [-r <re>] [<class>]
+
+ options:
+        -r <re> : chercher les méthodes correspondant à l'expression régulière <re>
+        -i : avec -r, effectue une recherche insensible à la casse
+        -v : afficher les versions de PerlQt et de Qt
+        -h : afficher ce message d'aide
+

ex:

+
+ $>pqtapi -ir 'setpoint.* int'
+        void QCanvasLine::setPoints(int, int, int, int)
+        void QPointArray::setPoint(uint, int, int)
+

+

+

pqtsh

+

pqtsh est un shell graphique permettant de tester l'API de manière interactive. +Un exemple dynamique est accessible dans l'entrée de menu Help->Example.

+
+

+

+
+

Limitations

+

Les classes à modèle (templates) ne sont pas encore accessibles par PerlQt. +En revanche, les classes dérivées de classes à modèle sont disponibles.

+

Vous pouvez reconnaître ce type de classe en ce que leurs arguments comprennent un type générique placé entre +les signes ``<'' et ``>''.

+

ex: + QDictIterator ( const QDict<type> & dict )

+

+

+
+

Crédits

+

PerlQt-3 est (c) 2002 Ashley Winters (et (c) 2003 Germain Garand)

+

Kalyptus et l'engin de génération Smoke sont (c) David Faure and Richard Dale

+

Puic is (c) TrollTech AS., Phil Thompson et Germain Garand,

+

Ledit logiciel est délivré sous la GNU Public Licence v.2 or later.

+

+

+
+

Appendice: Les conventions de C++ et leur traduction en Perl

+

Lorsque vous voulez utiliser depuis PerlQt une classe ou méthode décrite +dans la documentation Qt (voyez aussi le programme +$QTDIR/bin/assistant livré avec Qt), vous devez suivre des règles de translation simples.

+
+
Noms de classe
+
+
    +
  • +Les noms de classes utilisent le préfixe Qt:: au lieu de Q pour +être conforme à l'usage Perl. Ainsi: QComboBox est nommé Qt::ComboBox +dans PerlQt. +

+
Fonctions
+
+
    +
  • +Les fonctions décrites comme static sont accédées directement et non +à travers un objet. Ainsi la fonction statique Foo de la classe QBar +peut être accédée de PerlQt par +
    + Qt::Bar::Foo( arg-1,...,arg-n);
    +

    +
  • +Les fonctions décrites comme members ou Signals sont +accessibles à travers l'objet par l'opérateur + -> . +Par exemple: +
    + $widget->show;
    +

    Il n'y a pas de différence fondamentale entre les méthodes et les +signaux, néanmoins PerlQt fournit le mot-clé emit comme une +mnémonique pratique pour rendre clair que vous émettez un signal :

    +
    + emit $button->clicked;
    +

+
Arguments
+
+
    +
  • Par valeur
    +
  • +Lorsqu'un argument n'est pas précédé par un des caractères & or +*, il est passé par valeur. Pour tous les types basiques tels que +int, char, float and double, PerlQt convertira automatiquement les +valeurs litérales et scalaires dans le type correspondants C++. +

    Ainsi pour le prototype d'un constructeur écrit dans la documentation +comme ceci: + QSize ( int w, int h )

    +

    Vous écrirez :

    +
    + Qt::Size(8, 12);
    +

    +
  • Par référence
    +
  • +Lorsqu'un argument est précédé par le caractère &, Il est une +référence à un objet ou à un type. Vous pouvez alors fournir un nom de +variable ou un objet temporaire : +
    + $keyseq = Qt::keySequence( &Qt::CTRL + &Qt::F3 );
    + $widget->setAccel( $keyseq );
    +

    ou

    +
    + $widget->setAccel(Qt::keySequence( &Qt::CTRL + &Qt::F3 );
    +

    Si l'argument n'est pas qualifié par const (constante), l'argument +est un objet qui peut être altéré par la méthode, vous devez +donc passer une variable.

    +

    +
  • Par pointeur
    +
  • +Lorsqu'un argument est précédé par le caractère *, +un pointeur vers un objet ou un type est attendu. En PerlQt, vous +pouvez fournir un nom de variable ou le mot clé undef à la place +du pointer Null. +

    De plus, si l'argument est const, l'objet passé en argument est en +lecture seule: il ne peut pas être modifié.

    +

+
Énumérations
+
+
+Les Énumerations sont une forme d'alias pour des valeurs numériques +dont il serait autrement difficile de se souvenir: +
+
+

Exemple C++:

+
+
+
+ enum Strange { Apple, Orange, Lemon }
+
+
+

Ici, Strange est le type (au sens de C++) de l'énumération, et +Apple, Orange et +Lemon ses valeurs possible , qui sont des aliases pour des +nombres (ici 0, 1 et 2)

+
+
+

L'accès aux valeurs d'énumération en Perl Qt est un appel +de fonction statique.

+
+
+

Donc, si vous voulez éviter des prblèmes de lisibilité, nous vous +recommandons l'usage d'une syntaxe alternative d'appel de fonction +pour marquer l'utilisation d'un alias d'énumération: &fonction.

+
+
+

Revenons à notre exemple Strange.

+
+
+

Si nous rencontrons sa définition dans la classe QFruits, vous +écrirez en PerlQt :

+
+
+
+ $pomme_plus_orange = &Qt::Fruit::Pomme + &Qt::Fruit::Orange;
+
+

+
Opérateurs
+
+
+Dans PerlQt, la surcharge d'opérateurs fonctionne de manière transparente. +Si un opérateur est surchargé dans une classe Qt (ce qui signifie que son utilisation +déclenchera un appel de méthode, au lieu d'utiliser l'opérateur générique) +il sera également surchargé dans PerlQt. +
+
+

ex-1: surcharge de '+='

+
+
+
+ $p1 = Qt::Point(10, 10)
+ $p2 = Qt::Point(30,40)
+ $p2 += $p1; # $p2 devient (40,50)
+
+
+

ex-2: surcharge de '<<'

+
+
+
+ $f = Qt::File("example");
+ $f->open( IO_WriteOnly ); # voir l'entrée 'Constantes' plus bas
+ $s = Qt::TextStream( $f );
+ $s << "Que faire avec " << 12 << " pommes ?";
+
+
+

Exception notable : le constructeur de copie (signe égal, '=') n'est jamais surchargé, +attendu qu'il ne pourrait fonctionner que partiellement et que le paradigme de +Perl est très différent de C++ en matière de copie d'objets.

+
+

+
Constantes
+
+
+Qt n'utilise pas beaucoup de constantes, mais on en trouve cependant dans le module d'Entrées/Sorties, +où elles font office de drapeaux pour les modes d'ouverture de fichiers. +
+
+

Pour éviter de polluer inutilement l'espace de nom, nous avons regroupé les constantes dans le module +Qt::constants, d'où elles seront chargées à la demande.

+
+
+

Ainsi, pour importer l'ensemble des constantes d'E/S, on écrira :

+
+
+
+ use Qt::constants;
+
+
+

Et pour importer quelques symboles seulement :

+
+
+
+ use Qt::constants qw( IO_ReadOnly IO_WriteOnly );
+
+

+
Fonctions globales
+
+
+Qt dispose de fonctions utilitaires, telles bitBlt, qCompress, etc. +
+
+

Ces fonctions ont été rassemblées dans un espace de nom commun: +Qt::GlobalSpace.

+
+
+

Vous pourrez donc y accéder soit par un appel pleinement qualifié :

+
+
+
+ Qt::GlobalSpace::qUncompress( $buffer )
+
+
+

Soit en important préalablement ces fonctions dans l'espace de nom courant :

+
+
+
+ use Qt::GlobalSpace;
+ qUncompress( $buffer )
+
+
+

Bien entendu, vous pouvez aussi n'importer que les fonctions souhaitées :

+
+
+
+ use Qt::GlobalSpace qw( qUncompress bitBlt )
+
+
+

N.B: GlobalSpace renferme également des opérateurs de portée globale, tels +celui permettant d'aditionner deux Qt::Point(). Ces opérateurs seront appelés +automatiquement.

+
+
+

ex:

+
+
+
+ $p1 = Qt::Point(10, 10) + Qt::Point(20, 20)
+
+

+

+

+
+

Annexe 2 : Internationalisation

+

PerlQt résout les problèmes d'internationalisation en convertissant systématiquement les QString +de Qt en utf8 côté Perl.

+

Les conversions en sens inverse, depuis Perl vers Qt sont traitées différemment suivant le contexte :

+ +

Lorsque des chaînes contiennent de l'utf8, Perl adapte automatiquement ses opérateurs pour que +leur gestion soit entièrement transparente (comprendre opaque, comme toujours...). +Cependant, vous pourrez avoir besoin à l'occasion de les transcrire en d'autres jeux d'encodage. +Ceci peut se faire soit avec Qt :

+
+ $tr1=Qt::TextCodec::codecForLocale(); # ceci utilisera la locale en vigueur
+ $tr2=Qt::TextCodec::codecForName("KOI8-R"); # ceci force l'emploi d'une locale spécifique (Russe)
+
+ print $tr1->fromUnicode(Qt::DateTime::currentDateTime()->toString)."\n\n";
+ print $tr2->fromUnicode($une_chaine_utf8);
+

Soit avec les outils de Perl (pour perl >= 5.8.0). +Se reporter à ce sujet à la documentation du module Encode (perldoc Encode).

+

+

+

désactiver l'encodage utf8

+

Les programmeurs souhaitant désactiver temporairement l'encodage utf8 +(pour la gestion de programmes externes ou de modules anciens ne supportant pas cet encodage) +pourront utiliser le pragma use bytes (et sa réciproque : no bytes).

+

Dans la portée de ce pragma, les conversions depuis QString vers les chaînes Perl se feront en ISO-Latin1 +(par défaut) ou suivant la locale en vigueur (si use locale est actif).

+

Notez bien qu'il est préférable de ne pas utiliser ce pragma à la légère, en ce qu'il ruine totalement les +efforts de standardisations autour d'utf8 entrepris depuis plusieurs années déjà. +Il est très préférable de corriger les programmes fautifs.

+

+

+
+

Annexe 3 : Canaux de déboguage

+

Le module Qt::debug offre divers canaux de déboguage permettant de filtrer +le flux conséquent d'informations disponibles pour l'adapter à vos besoins.

+
+ use Qt::debug;
+
+ use Qt::debug qw|calls autoload verbose|;
+

Avec le pragma use Qt::debug, seuls les canaux verbose et ambiguous sont activés. +Si vous le faites suivre d'une liste précise de canaux, seuls ceux-ci seront affichés.

+

Liste et descriptif des canaux :

+
    +
  • ambiguous
    +
  • +Vérifier si les appels de méthodes sont ambigus, et dire quelle méthode, parmi le jeux +d'alternatives, à finalement été choisie. +

    +
  • verbose
    +
  • +Donner davantage d'informations. +

    Utilisé avec ambiguous, vous donnera les correspondances les plus proches lorsqu'un appel de méthode échoue.

    +

    ex:

    +
    + use Qt;
    + use Qt::debug;
    + $a= Qt::Application(\@ARGV);
    + $a->libraryPath("chose");
    +
    + --- No method to call for :
    +        QApplication::libraryPath('chose')
    + Closer candidates are :
    +        static void QApplication::addLibraryPath(const QString&)
    +        static QStringList QApplication::libraryPaths()
    +        static void QApplication::removeLibraryPath(const QString&)
    +        static void QApplication::setLibraryPaths(const QStringList&)
    +

    +
  • calls
    +
  • +Pour chaque appel de méthode, vous dira quelle méthode Qt est finalement appelée, +en précisant les arguments si verbose est actif. +

    +
  • autoload
    +
  • +Détaille le passage dans le code intermédiaire faisant la jonction entre Perl et Qt. +

    +
  • gc
    +
  • +Donne des informations sur la collection des déchets, c'est à dire sur la destruction des objets, +qu'ils soient détruits depuis Perl ou Qt. +

    +
  • virtual
    +
  • +Vous averti chaque fois qu'une fonction virtuelle tente d'accéder à sa réimplémentation en Perl +(que cette réimplémentation existe ou non). +

    +
  • all
    +
  • +Activer tous les canaux. +

+

+

+
+

Annexe 4 : Marshalleurs

+

Un marshalleur est un convertisseur permettant de transcrire un type de données en un autre.

+

Dans PerlQt, la plupart des objets Qt gardent leurs propriétés d'objet, ce qui permet d'invoquer leurs méthodes +et de changer leurs propriétés comme il se doit. +Cependant, il arrive que l'objet d'origine corresponde à ce point à un type natif de Perl qu'il serait malséant +d'utiliser l'interface C++ et beaucoup plus naturel de lui substituer son équivalent.

+

Ici interviennent les marshalleurs. +Plutôt que de retourner un objet Qt::StringList, qui serait délicat à manipuler, +PerlQt le transformera en référence de liste Perl. +Dès lors, tous les opérateurs de manipulation de liste pourront lui être appliqué : +on gagne en densité, en cohérence et en simplicité.

+

Cette transformation s'appliquera aussi en sens inverse, et n'importe quelle liste de chaînes Perl +pourra être donnée en argument à une méthode attendant une Qt::StringList.

+
+ Liste des marshalleurs (PerlQt-3.008)
+ -----------------------------------------------------------------
+ float, double                         <=>       réel Perl (NV)
+ char, uchar, int, uint, enum
+ long, ulong, short, ushort            <=>       entier Perl (IV)
+ QString, -&, -*                        =>       chaîne Perl (utf8)
+ QString, -&, -*                       <=        chaîne Perl (utf8 ou iso-latin1 ou locale)
+ QCString, -&, -*                      <=>       chaîne Perl (utf8 ou octets, suivant contenu ou pragma "bytes")
+ QStringList, -&, -*                    =>       référence à une liste de chaînes Perl (utf8)
+ QByteArray, -&, -*                    <=>       chaîne Perl (octets)
+ int&, -*                              <=>       entier Perl (IV)
+ bool&, -*                             <=>       booléen Perl
+ char*                                 <=>       chaîne Perl (octets)
+ char**                                <=        référence à une liste de chaînes Perl (octets)
+ uchar*                                <=        chaîne Perl(octets)
+ QRgb*                                 <=        référence à une liste d'entiers Perl (IV)
+ QCOORD*                               <=        référence à une liste d'entiers Perl (IV)
+ void*                                 <=>       référence à un entier Perl (IV)
+ QValueList<int>, - *, - &             <=>       référence à une liste d'entiers Perl (IV)
+ QCanvasItemList, - *, - &              =>       réference à une liste de Qt::CanvasItem
+ QWidgetList, - *, - &                 <=>       réference à une liste de Qt::Widget
+ QObjectList, - *, - &                 <=>       réference à une liste de Qt::Object
+ QFileInfoList, - *, - &               <=>       réference à une liste de Qt::FileInfo
+ QPtrList<QTab>, - *, - &              <=>       réference à une liste de Qt::Tab
+ QPtrList<QToolBar>, - *, - &          <=>       réference à une liste de Qt::ToolBar
+ QPtrList<QNetworkOperation>, - *, - & <=>       réference à une liste de Qt::NetworkOperation
+ QPtrList<QDockWindow>, - *, - &       <=>       réference à une liste de Qt::DockWindow
+ (QUObject*)
+ + + + diff --git a/doc/images/ex1.png b/doc/images/ex1.png new file mode 100644 index 0000000..140b380 Binary files /dev/null and b/doc/images/ex1.png differ diff --git a/doc/images/ex2.png b/doc/images/ex2.png new file mode 100644 index 0000000..5e44a51 Binary files /dev/null and b/doc/images/ex2.png differ diff --git a/doc/images/pqtsh.png b/doc/images/pqtsh.png new file mode 100644 index 0000000..f5929b3 Binary files /dev/null and b/doc/images/pqtsh.png differ -- cgit v1.2.1