1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
<html>
<head>
<title>Scripteur : scripts d'extension</title>
</head>
<body>
</head>
<body>
<h2>Scripteur : scripts d'extension</h2>
<p>Auteur : Craig Ringer</p>
<p>L'extension Python de Scribus offre des caractristiques additionnelles permettant de doter l'application de nouvelles fonctionnalits,plutôt que d'automatiser des tches. En particulier, il est possible d'utiliser des 'scripts d'extension' pour crer de nouvelles palettes et des fentres encastrables qui peuvent tre utilises comme si elles faisaient partie de Scribus.</p>
<h3>Scripts d'extension</h3>
<p>Les scripts d'extension ressemblent beaucoup aux scripts Python normaux de Scribus.
Ils comportent quelques variantes pour pouvoir tre
lancs avec la caractristique "script d'extension", qui leur donne
accs au support PyQt et d'autres caractristiques spciales du
scripteur. Les diffrences les plus importantes entre les scripts normaux et les scripts d'extensions sont les suiantes :
</p>
<ul>
<li>Les scripts d'extension peuvent crer des objets Python qui continuent d'exister aprs la fin de l'excution du script. Les objets continueront d'exister seulement s'ils sont rfrencs, la plupart du temps parce qu'ils sont associs une entre dans l'espace de noms global. Cela signifie que les fonctions Python peuvent tre appeles par Scribus; par exemple : insertion PyQt ou encore fonction de rappel sur vnement.</li>
<li>Les scripts d'extension peuvent crer du code qui fonctionne sans bloquer l'excution de Scribus, vous pouvez donc crer des palettes flottantes qui sont prsentes pendant que l'utilisateur travaille normalement avec Scribus (c'est--dire des palettes non modales).</li>
<li>PyQt fonctionne correctement dans les scripts d'extension, contrairement son comportement avec les scripts normaux.</li>
<li>Les scripts d'extension peuvent effectuer des changements l'environnement Python, lesquels affecteront les scripts conscutifs. Les modules imports par un script peuvent tre vus par un autre script, les paramtres changs par l'un restent changs, etc. Conclusion : vous devez crire vos scripts d'extension avec vigilance. En particulier, les noms globaux lis un script d'extension peuvent tre modifis par un autre script, de telle sorte que l'objet associ ces noms risque d'tre libr par l'interprteur. En d'autes mots, avec les scripts d'extension, vous pouvez rencontrer des conflits et des interactions qui n'existent pas dans les scripts normaux.</li>
</ul>
<h4>Le volet technique</h4>
<p>Les scripts normaux sont lancs dans un nouveau sous-interprteur Python qui est utilis exclusivement pour ce script et se trouve ensuite libr. Cela signifie que, quels que soient les objets Python qu'ils crent ou les paramtres qu'ils modifient, ces changements sont automatiquement annuls lorsque le script se termine. Parce que Scribus prend soin de librer votre script, vous n'avez pas vous proccuper de la mmoire ni
des conflits avec d'autres scripts, etc., et vous pouvez vous concentrer sur l'criture des instructions.</p>
<p>Les scripts d'extension, par contre, s'excutent dans un seul interprteur Python qui dmarre au chargement du module de gestion des extensions. Cet
interprteur continue tourner jusqu' ce que le script qui gre les extensions soit dsactiv la fermeture de Scribus. Quand Scribus excute un script d'extension, il le charge dans l'interprteur courant - un peu comme <code>execfile</code> charge un script Python dans un autre script Python. Ainsi, les scripts d'extension peuvent crer de nouveaux objets au cours de leur excution puis terminer et redonner le contrôle Scribus sans que objets qu'ils ont crs ne soient dtruits. Si un autre script s'excute alors, il peut voir les objets crs par le premier script.</p>
<p>Il y a plusieurs situations où il est utile de crer des objets Python qui subsistent aprs le script. Le cas le plus pertinent rside dans la programmation graphique avec PyQt, où les objets PyQt sont crs au dmarrage du script et ne deviennent oprationnels que lorsque le script termine, retournant le contrôle la boucle vnementielle de Scribus. Autres cas de figure : les macros, les vnements de rappel et les temporisateurs, où Scribus doit pouvoir appeler le code Python. Vous pouvez raliser ces fonctions ds maintenant avec PyQt, mais il n'existe pas encore de support direct pour les temporisateurs et les rappels dans Scribus.</p>
<p>Voici quelques inconvnients des objets persistants aprs la fin du script.
Les scripts interagissent parfois d'une manire imprvue par l'auteur, ce qui donne des rsultats souvent intressants mais cause aussi des bogues inattendus et tonnants. Les auteurs de scripts doivent par ailleurs considrer l'effet de leur code sur la consommation de la mmoire de Scribus.<p>
<h4>Construire des ajouts graphiques dans Python </h4>
<p>Construire de nouvelles palettes et dialogues dans PyQt constitue un moyen simple d'enrichir l'interface utilisateur de Scribus et de fournir des fonctionnalits supplmentaires pour les scripts avancs. Python
est bien adapt aux entres et sorties partir de bases de donnes, de systmes de gestion de contenu et d'autres rfrentiels externes; la capacit de btir des interfaces personnalises cette fin peut s'avrer trs utile.</p>
<p>Dans la plupart des cas, PyQt fonctionne de la mme manire l'intrieur de Scribus ou dans un interprteur Python autonome. Il y a cependant des diffrences, et il est important de les comprendre.</p>
<ul>
<li>Une instance de <code>QApplication</code> existe dj, et le fait d'en crer une autre aura des consquences indsirables. Au besoin, vous pouvez
accder l'instance de <code>QApplication</code> en tant que <code>qt.qApp</code>. </li>
<li>Scribus excute la boucle d'vnements Qt. Le chargement de la boucle d'vnements Qt dans PyQt empchera probablement l'excution de Scribus jusqu' ce que votre code finisse de s'excuter et peut provoquer d'autres comportements tranges. Les explications suivantes dcrivent l'approche approprie pour intgrer votre code la boucle d'vnements. En bref, il suffit de crer toutes vos instances, d'afficher vos fentres et de laisser votre script se terminer. Qt
intgrera automatiquement vos fentres dans la boucle d'vnements
et tout "fonctionnera", mme les insertions et les widgets Python. En gnral, tout ce que vous voulez conserver doit tre mis dans l'espace de noms global (comme expliqu ci-dessus). </li>
</ul>
<h4>Les bases - Convertir Hello World</h4>
<p>Le premier tutoriel est l'application classique Hello World. Pour montrer les diffrences entre PyQt et Scribus, nous convertirons le programme pour qu'il s'excute dans Scribus. Voici l'original :</p>
<pre>
#!/usr/bin/env python
import sys
import qt
a = qt.QApplication(sys.argv)
hello = qt.QPushButton("Hello world!", None)
hello.resize(100, 30)
a.setMainWidget(hello)
hello.show()
sys.exit(a.exec_loop())
</pre>
<p>Premirement, nous avons besoin de dsactiver la cration de <code>QApplication</code> puisque, dans Scribus, on trouve une instance de <code>QApplication</code> dj active; rappelez-vous qu'une seule instance est permise par application. PyQt nous fournit l'accs <code>QApplication</code>, cr pralablement par Scribus au dmarrage en tant que <code>qt.qApp</code>. Donc, il suffit de remplacer :</p>
<pre>
a = qt.QApplication(sys.argv)
</pre>
<p>par</p>
<pre>
a = qt.qApp
</pre>
<p>et nous avons termin la modification.</p>
<p>Ensuite, nous devons empcher le script d'essayer d'excuter sa propre boucle d'vnements. Comme Scribus possde une boucle d'vnements, si le script dmarre la sienne, l'application sera perturbe jusqu' sa fermeture. Qt est assez fut pour associer toute fentre que vous crez la boucle d'vnements exsitante; il n'y a donc pas grand chose faire. Pendant l'excution du script, Scribus est sous le contrôle de Python, de sorte qu'il nous suffit de raliser notre installation (dans ce cas, il s'agit de crer une fentre simple et de l'afficher), pour ensuite <i>laisser notre script se terminer</i> plutôt que de dclencher la boucle d'vnements. Tous les scripts
d'extension s'excutent dans le mme interprteur Python, ce qui implique que les objets crs par vos soins ne sont pas dtruits la fin de l'excution. C'est un peu comme charger un module. Quand votre script se termine, Scribus prend le contrôle et reprend l'excution de la boucle d'vnements de Qt. Comme
vos fentres sont des widgets Qt, la boucle d'vnements de Scribus les prend en charge, et elles deviennent une partie intgrante normale de Scribus. Quand une insertion Python est dclenche ou qu'une fonction Python est appele, PyQt se charge automatiquement de l'excution de la fonction Python et passe ensuite la main Scribus.</p>
<p>Le seul hic de cette mthode est qu' la fin de votre script, tous les objets crs dans une fonction ou un domaine local seront librs par Python lorsque le domaine est abandonn (par exemple la sortie de main()). Vous devez conserver une rfrence au niveau global pour viter que ces lments ne soient librs. Le support pour PyQt dans Scribus est trs rcent et il n'y a pas encore de mthode clairement dfinie comme "correcte" d'accomplir cela. Les options incluent :</p>
<ul>
<li>La cration de tout ce que vous voulez conserver dans l'espace de noms global. Des prcautions sont de mise si votre script s'excute plusieurs fois.</li>
<li>Le stockage d'objets que vous voulez conserver dans un dictionnaire ou une classe dans l'espace de noms global. La plupart des problmes sont identiques ceux poss par le stockage d'objets directement en tant que noms globaux.</li>
<li>Insertion de votre script dans un module, pour que le script lanc par l'utilisateur importe simplement le module et excute la fonction incluse. C'est l'approche que nous privilgions. Notez que le corps du module n'est pas recharg chaque importation;
vous devez donc placer chaque fois le code excuter dans une fonction du module plutôt que dans le niveau principal du module. Ou encore, vous pouvez vrifier si le module est dj charg, pour utiliser reload() au lieu de l'importer de nouveau.</li>
</ul>
<p>Pour l'instant, parce que ce script cre dj tous les lments au niveau global, nous allons procder comme cela. Les scripts volumineux devraient tre crits comme des modules.</p>
<p>Étant donn que les
objets dont nous avons besoin seront dj prsents lorsque le script se terminera, il nous suffit d'empcher l'entre dans la boucle d'vnements. C'est facile - mettez simplement en commentaire la dernire ligne :</p>
<pre>
# sys.exit(a.exec_loop())
</pre>
<p>et nous avons presque termin. Le script s'excutera maintenant correctement, mais, la fermeture, il aura un effet non dsir -l'interruption de Scribus. Ce n'est probablement pas ce que vous voulez. Voil l'explication : normalement, une application Qt se termine lorsque son widget principal (fentre principale) se ferme. Nous
appelons <code>qt.setMainWidget(...)</code> pour transformer notre nouvelle fentre en fentre principale; donc, la fermeture, Scribus s'interrompt aussi. Pour empcher cela, mettez simplement en commentaire <code>qt.setMainWidget</code>.</p>
<p>Le nouveau script ressemble ceci :</p>
<pre>
#!/usr/bin/env python
import sys
import qt
a = qt.qApp
hello = qt.QPushButton("Hello world!", None)
hello.resize(100, 30)
#a.setMainWidget(hello)
hello.show()
#sys.exit(a.exec_loop())
</pre>
<p>Vous trouverez le script dj enregistr sous le nom <code>pyqt_tut1.py</code> dans le rpertoire 'examples' du scripteur. Essayez de l'excuter comme un script d'extension. Vous devriez obtenir un bouton 'hello world'. Notez que vous pouvez continuer travailler dans Scribus comme l'accoutume; lorsque vous fermez la fentre 'hello world', elle disparaît lgamment, sans incidence sur Scribus.</p>
<p>Si vous jetez un coup d'oeil l'exemple de ce script tutoriel, vous remarquerez quelques ajouts. Ils sont accompagns de commentaires explicatifs et ne seront donc pas explors plus avant ici.</p>
<h4>Amusons-nous avec les noms globaux et les interprteurs partags </h4>
<p>Vous vous rappelez que j'ai mentionn plus tôt certains 'problmes' concernant le stockage d'objets conserver au niveauglobal ? Évidemment, j'ai pass sous silence quelque chose que je ne voulais pas expliquer ce moment. </p>
<p>Le stockage d'objets en tant que noms globaux fonctionne bien... jusqu' ce que l'utilisateur excute votre script nouveau, ou qu'il excute un autre script qui reprend les mmes noms.
Python utilise le comptage de rfrences : un objet continue d'exister tant qu'un ou plusieurs noms y font rfrence. Lorsqu'un nom global cr antrieurement est remplac par un autre script ou par une autre excution de votre script, il n'y a plus de rfrence cet objet (peut-tre une fentre que l'utilisateur continue d'utiliser). Python fait son travail scrupuleusement et supprime l'objet pour vous, sans savoir s'il est encore affich ou s'il s'agit d'un composant de votre fentre. Dans beaucoup de cas, une fentre disparaît tout simplement, mais il peut y avoir des consquences plus ennuyeuses. </p>
<p>Essayez ceci. Excutez le script 'hello world' (en utilisant "Load Extension Script..."). Puis, sans fermer la fentre "Hello world", excutez le script nouveau. La fentre originale devrait disparaître et tre remplace par la nouvelle.</p>
<p>Aucune solution idale n'est prvue pour ce problme, et tout dpend de ce que vous voulez faire exactement. J'aimerais donner des recommandations plus claires, mais chaque cas est diffrent. Si vous recontrez ce problme, entrez une description de votre projet sur la liste de diffusion de Scribus, et mes collgues ou moi-mme vous fourniront quelques suggestions.</p>
<p>La meilleure solution jusqu' prsent consiste utiliser un script enveloppe pour excuter votre script et de placer votre script rel dans un module. Le script enveloppe importe votre module et excute une fonction du module pour afficher les fentres. Puisque le module est excut uniquement la premire fois qu'il est import, la(les) fentre(s) seront affiches si elles ne sont pas dj visibles, mais ne seront pas perturbes si elles sont dj affiches. Vous pouvez appeler reload() pour recharger le module si vous voulez vraiment le relancer, peut-tre aprs l'excution de code de nettoyage.</p>
<p>Les suggestions appropries sont bienvenues. N'hsitez pas entrer vos questions et ides sur la liste de diffusion.</p>
<h4>Autres astuces</h4>
<p>Mme si vous ne btissez pas une interface graphique personnalise, il est possible d'utiliser les scripts d'extension. Par exemple, vous pouvez utiliser PyQt pour excuter une fonction temporise. Un autre usage pourrait tre de vrifier l'existence de mises jour d'un article dans une base de donnes et d'inviter l'utilisateur actualiser son document avec le nouveau texte (ou constater les diffrences). Vous
trouverez un exemple trs simple de mise en place d'un temporisateur
avec PyQt dans le rpertoire d'exemples, appel <code>pyqt_timer.py</code>.</p>
<p>Une autre ide, suggre par un membre de la liste de
diffusion, tait d'crire un serveur XML-RPC pour exposer le
scripteur API des programmes externes. Cette approche pourrait tre ralise l'aide
des classes PyQt pour la mise en rseau et la gestion des
vnements.</p>
<h4>Autres sources d'information</h4>
<p>Le prsent document n'est pas un tutoriel PyQt ou Qt. Voici quelques
sources d'information fiables sur Qt et PyQt :
</p><ul>
<li>Le tutoriel et les exemples PyQt partir de la documentation PyQt </li>
<li><a href="http://www.opendocs.org/pyqt/">Programmation graphique avec Python - Édition Qt</a></li>
<li><a href="http://doc.trolltech.com/">Documentation Qt de TrollTech (C++)</a></li>
<li>Le
<a href="http://www.digitalfanatics.org/projects/qt_tutorial/"> tutoriel Qt indpendant</a></li>
<li><a href="http://www.qtforum.org/">QtForum.org</a></li>
</ul>
<h3>Grer correctement l'excution hors Scribus </h3>
<pre>
Essayer ceci:
import scribus
except ImportError:
print "Ce script peut seulement s'excuter comme un script d'extension partir de Scribus."
sys.exit(1)
</pre>
<p>Cette squence essaie de charger l'interface de script de Scribus et, en cas
d'chec, suppose que celle-ci ne peut s'excuter sous Scribus. Veillez placer ce message dans tous vos scripts pour ne pas
drouter les utilisateurs qui essaient de les excuter avec
l'interprteur Python autonome. Essayez d'excuter le script avec
<code>python pyqt_tut1.py</code>, et notez comment il signale son chec avant de fermer. C'est
beaucoup plus prcis qu'une erreur d'importation ou qu'un comportement bizarre.</p>
<h3>Questions sans rponse et caractristiques manquantes </h3>
<p>Le support pour tendre Scribus partir de Python est
encore en chantier. Plusieurs composants fonctionnent
bien, mais il reste beaucoup explorer.
Les ractions, suggestions, requtes, ides et offres d'aide
seront grandement apprcies et peuvent tre diriges vers la
liste de diffusion ou vers les auteurs du prsent document. </p>
<p>Notamment, il n'existe aucun support pour :
</p><ul>
<li>L'utilisation de PyQt partir de scripts normaux (par opposition aux scripts d'extension)</li>
<li>L'utilisation de PyGtk ou de wxPython</li>
<li>L'utilisation de threads (les threads PyQt peuvent
fonctionner dans les limites du support des threads de Qt)</li>
<li>L'accrochage dans le menu activ par un clic droit (pas encore !)</li>
<li>L'appel de scripts par certains vnements (dveloppement envisag) </li>
<li>La connexion facile et fiable dans les menus </li>
<li>L'extension des dialogues de Scribus </li>
<li>L'utilisation de widgets et de classes personnaliss </li>
<li>Toute approche consistant passer le contrôle une boucle d'vnements sans retour de donnes (fonctionne mais bloque Scribus).</li>
</ul>
<p>Certains de ces lments ne sont pas encore implments, d'autres sont extrmement difficiles grer; dans d'autres cas, nous sommes tout simplement dpourvus d'ides ou ne prvoyons pas d'essayer.</p>
</body>
</html>
|