PySide Intermediate Examples/fr

Introduction
Cette page couvre des exemples de niveau moyen du gestionnaire d'interface graphique PySide (les pages d'accompagnement couvrent des aspects à la fois moins ou plus avancés, Exemples PySide pour débutants et Exemples PySide pour confirmés). Dans cette page, un exemple de programme est utilisé pour couvrir les différents sujets PySide. L'intention est de présenter du code PySide fonctionnel afin que toute personne ayant besoin d'utiliser PySide puisse copier la section correspondante, la modifier et l'adapter à ses propres fins.

Remarques

 * Cette page n'est pas destinée à couvrir le langage Python ou à servir d'instructions en Python.
 * Les noms des variables ne sont pas descriptifs mais ont été conservés dans l'ordre pour mieux organiser les explications
 * Il existe de nombreuses conventions de dénomination pour les composants de l'interface graphique, dont aucune n'est «bonne» ou «mauvaise»
 * Il existe une variété de séquences différentes des déclarations pour les widgets, les signaux, les méthodes, encore une fois, aucune n'est "bonne" ou "mauvaise"
 * Il convient de garder à l'esprit que PySide fonctionne avec des chaînes lorsqu'il s'agit de la saisie de l'utilisateur, ce qui apparaît à l'écran sous forme de nombre est en fait une représentation textuelle d'un nombre

Discussion basée sur le code - Partie déclarative
Le "programme d'exemple" est en fait une grande définition de classe, la définition d'une classe PySide GUI et a plus de 150 lignes de code (y compris les commentaires). Il n'y a pas de but fonctionnel pour la classe ou son comportement, le seul but est de démontrer les actions possibles de l'interface graphique et de présenter du code qui, espérons-le, peut être utilisé par d'autres utilisateurs de FreeCAD.

La définition de classe et le petit nombre de lignes de code qui invoquent sont décrits dans l'ordre d'apparition dans le fichier. Cet ordre est basé sur la disposition de l'écran qui est plutôt arbitraire et uniquement destinée à démontrer les fonctionnalités. Voici l'écran GUI modal généré par la classe PySide:



La majeure partie du reste de cette section décrira le contenu de la définition de classe qui apparaît à la fin de cette section. Nous couvrirons d'abord les éléments déclaratifs qui définissent comment les choses fonctionnent et comment l'interface graphique est assemblée, puis nous couvrirons les sections opérationnelles (c'est-à-dire le code qui s'exécutera lorsque les interactions de l'utilisateur se produiront). Cette fenêtre est basée sur la classe QDialog et est donc modale - ce qui signifie qu'aucune activité ne peut être effectuée en dehors de la fenêtre lorsqu'elle est ouverte.

Déclaration d'importation
La déclaration d'importation obligatoire

Il est préférable de le placer en haut du fichier Python.

Définition de classe
Ce code est mieux copié textuellement et modifié. L'essentiel du code est que nous sous-classons la classe QDialog de PySide. En adaptant ce code, vous voudrez changer le nom de la classe "ExampleModalGuiClass" - assurez-vous de le changer dans les deux endroits (par exemple les lignes 1 et 4).

État de retour de la fenêtre
Ce n'est pas obligatoire mais plutôt une bonne pratique de programmation, cela définit un statut de retour par défaut pour la fenêtre qui sera là indépendamment de ce que fait l'utilisateur. Plus tard dans le code, cela peut être modifié par le code Python pour indiquer les différentes options que l'utilisateur peut avoir sélectionnées.

Création de fenêtres
En vous rappelant que les dimensions de l'écran sont mesurées à partir du coin supérieur gauche, sur la 3ème ligne, les valeurs se réfèrent à: Le titre de la fenêtre est défini et la dernière ligne signifie simplement que cette fenêtre ne sera jamais obscurcie par une autre fenêtre - si cela n'est pas souhaité, placez simplement un caractère de commentaire Python ('#') comme premier caractère de la ligne.
 * le nombre de pixels dans le coin supérieur gauche sera à droite du bord gauche de l'écran (250)
 * le nombre de pixels dans le coin supérieur gauche sera sous le bord supérieur de l'écran (250)
 * la largeur de l'écran en pixels (400)
 * la hauteur de l'écran en pixels (350)

Création d'étiquettes
Dans PySide, les étiquettes ont deux objectifs: les étiquettes statiques (comme leur nom l'indique) et les champs de texte en lecture seule (c'est-à-dire en affichage uniquement). Ainsi, des instructions inchangées à l'utilisateur telles que "Don't push the red button" ainsi que des résultats de calcul dynamiques tels que "42" peuvent être communiquées à l'utilisateur. La 2ème ligne déclare une étiquette et définit sa valeur initiale (qui est vide dans ce cas). La troisième ligne spécifie la police, n'importe quelle police (sur le système) peut être spécifiée, si elle n'est pas spécifiée, la police par défaut est utilisée. Dans ce cas, la police est spécifiée comme non proportionnelle. L'étiquette est déplacée vers son emplacement dans la fenêtre - ses coordonnées spécifient sa position par rapport à la fenêtre (pas à l'écran).

Création de cases à cocher
Les cases à cocher peuvent être désactivées et activées dans n'importe quelle combinaison (contrairement aux boutons radio). La ligne 2 en déclare un et définit sa valeur initiale. La ligne 3 spécifie quelle méthode sera exécutée lorsque la case à cocher est cliquée (dans ce cas, la méthode 'onCheckBox1'). Si la 4ème ligne n'avait pas le caractère de commentaire Python ('#') comme premier caractère, alors elle serait exécutée et il marquerait la case comme cochée. Enfin, la 5ème ligne place la case à cocher en position.

Création de boutons radio
La création des boutons radio est très similaire aux cases à cocher. La seule différence est vraiment le comportement des boutons radio en ce qu'un seul d'entre eux peut être 'activé' à la fois.

Création d'un menu contextuel
À la ligne 2, une liste est constituée de ce que seront les choix de l'utilisateur. Une alternative consiste à créer un dictionnaire mais à n'utiliser les touches que pour la liste des choix de menu. La ligne 4 crée le menu contextuel (appelé ComboBox vers PySide), les options utilisateur sont ajoutées à la ligne 5.

Si le Dictionnaire était utilisé, les lignes apparaîtraient comme suit :

Revenant à l'exemple de code principal de cette section, la ligne 6 définit le choix par défaut, cette ligne peut être omise, la valeur du choix par défaut peut également être chargée dans l'étiquette correspondante (encore une fois si nécessaire). Et enfin le passage en position à la ligne 8.

Création de bouton, partie 1
Le bouton est créé à la ligne 2 avec son nom, le gestionnaire de son signal lorsque l'utilisateur clique est spécifié à la ligne 3. La ligne 4 est là pour empêcher le bouton de devenir le 'bouton par défaut' - le bouton sur lequel l'utilisateur clique simplement si l'utilisateur appuie sur la touche. Et un passage à la position a terminé le segment de code.

Création d'une entrée de texte
Le widget QLineEdit est probablement le plus courant pour la saisie textuelle de l'utilisateur, dans cet exemple, la section de code après celle-ci mettra en place un menu contextuel pour l'utiliser. Cette section de code crée (ligne 2), définit une valeur initiale (ligne 3), définit une largeur pour le champ (ligne 4) et met le widget en place (ligne 5).

Création du menu contextuel
Ce code a de nombreuses répétitions car la même action est effectuée avec des valeurs différentes - cela fait partie de ce qui rend le code GUI si long (quel que soit le système). Tout d'abord, une QAction est créée - c'est un appariement (ou un lien) du texte que l'utilisateur verra comme son option sélectionnable avec la méthode qui s'exécutera s'il sélectionne cette option. Il s'agit essentiellement d'un couplage d'un choix d'utilisateur avec un morceau de code. La ligne 3 le crée, la ligne 4 définit l'option utilisateur (comme ils le verront) et la ligne 5 spécifie quel morceau de code Python sera exécuté.

En sautant à la ligne 19 (la ligne avec "self.textInput.setContextMenuPolicy"), un ActionsContextMenu est créé, qui contient tous les liens QAction séparés entre le choix de l'utilisateur et le code à exécuter. Chaque widget ne peut avoir qu'un seul menu contextuel (c'est-à-dire le menu associé au clic droit) donc la ligne 19 définit ce menu. Les 4 lignes suivantes ajoutent les liens créés au début de cette section de code. L'ordre est important ici, l'utilisateur verra les options du menu dans l'ordre dans lequel elles sont ajoutées. Notez que la 3ème option de menu est vraiment un peu rien, son code est nul mais il sert à séparer 2 groupes d'options sur le menu contextuel.

Création d'une entrée numérique
La création du champ pour la saisie numérique suit vraiment celle de la saisie de texte plus tôt. En fait le code est identique à l'exception des 3ème et 4ème lignes. La troisième ligne définit le masque tel que défini par PySide, qui dans ce cas spécifie jusqu'à 3 chiffres (qui peuvent inclure 0). Une liste complète des codes InputMask peut être trouvée sur QLineEdit InputMask

Création de bouton, partie 2
Les deux boutons sont créés avec un nom (qui apparaîtra comme leur étiquette), associé à une méthode qui s'exécutera quand ils seront cliqués et déplacés en position. La seule exception est la ligne 4 qui spécifie le bouton 'Annuler' comme bouton par défaut - cela signifie qu'il sera "cliqué" si l'utilisateur appuie sur la touche.

Window Display
There is only one line and it causes the GUI to be displayed after the setup.

Code Based Discussion - Operative Portion
We now move onto the operative portion of the GUI definition which is the code that executes in response to user interactions with the GUI. The order of statement groups is not very relevant - with the caveat that something must be declared before it can be referenced. Some people put all the handlers of a certain type (e.g. handlers for buttons) in one group, others list the handlers alphabetically. For specific application there may be a problem related reason that all handlers relating to a specific aspect be gathered together

There is a high degree of similarity between the handlers. Most do not receive a parameter, the fact they are executing is realy the only parameter (or signal) they get. Others like "onPopup1" and "mousePressEvent" accept a parameter.

There must be a one to one correspondance between the handlers specified in the declarative section and the handler declared in this, the operative section. There may be extra handlers declared which are never invoked but there may not be any missing.

Generic Handler
In this code example, generic handlers handle the following events:


 * onCheckbox1
 * onCheckbox2
 * onRadioButton1
 * onRadioButton2
 * onPushButton1
 * onPopMenuAction1
 * onPopMenuAction2
 * onPopMenuDivider
 * onPopMenuAction3
 * onCancel
 * onOk

The general form for the handlers is:

The first line has the keyword "def" followed by the handler name. The handler name must match the name from the earlier declarative section exactly. The parameter "self" is part of the standard syntax as are the enclosing parenthesis and the final colon character. Once the first line is finished then there are no requirements of the following code, it is purely application specific.

Pop-Up Menu Handler
The Pop-Up menu handler is the same as the generic handler with exception that a second parameter, the text selected by the user, is passed in. Remember that everything is text coming from the Pop-Up menu and even if the user has selected the number 3, it will be passed in as the string "3".

Mouse Event Handler
The Mouse Event handler is the same as the generic handler with exception that a second parameter, the mouse event (e.g. left-click, right-click) from the user is passed in. The name of the handler, "mousePressEvent", is reserved and if it is changed then the handler will no longer receive the event from the mouse presses.

The X and Y coordinates of the mouse press are given by the reference "event.pos.x" and "event.pos.y". The constants "QtCore.Qt.LeftButton" and "QtCore.Qt.RightButton" are used to determine which mouse button was pressed.

A reference to a widget can be made of the form "self.widgetName.underMouse" which will return or  as to whether the mouse cursor is over the widget "widgetName". Although presented in the same code excerpt the "underMouse" handler is not tied to the "mousePressEvent" handler and can be used at any time.

Code Based Discussion - Main Routine
Most of the volume of code is in the GUI Class definition, there is not much in the main procedure.

Lines 2,3 & 4 deal with coordinating the status of the user interaction with the GUI - e.g. Cancelled, OK, or any other application defined status. The handler routines On Cancel and OnOk earlier also set these statuses.

Lines 1 and 2 show the method for invoking the GUI. There may be multiple GUI definitions for a program and also the GUI need not be invoked as the first thing in the Python file, it may be invoked at any point. The Name of the GUI Class is specified in line 1 ("ExampleGuiClass" in this case) but the rest of the 2 lines are to be copied verbatim.

Lines 4 and 6 use the result field to determine the appropriate action. The last 4 lines simply show the copying of the data in the GUI object to variables local to the executing main procedure.

Complete Modal Code Example
This is the complete code example (developed on FreeCAD v0.14):

The best way to use this code is to copy it into an editor or FreeCAD macro file and play around with it.

Code Based Discussion - Nonmodal Code Example
All of the widget specific from the previous modal example transfer to use in a nonmodal window. The main difference is that the nonmodal window does not restrict the user from interacting with other windows. Basically, a nonmodal window is one that can be opened and left open for as long as needed without it placing any restrictions on other application windows. There are a small number of code differences between the two which will be highlighted, consequently this code example is quite brief. Anything that is the same as the previous modal example will be left out in the interests of keeping this overview brief. This is the nonmodal GUI screen the PySide Class generates:



Import Statement
The mandatory Import statement

This is best placed at the top of the Python file.

Class Definition
This code is best copied out verbatim and altered. The gist of the code is that we are sub-classing the QMainWindow Class of PySide. In adapting this code you will want to change the class name "ExampleNonmodalGuiClass" - make sure to change it in both locations (e.g. lines 1 & 4).

Window Creation
Obviously our window dimensions and title are different. The main point to note is the last line which lets PySide know that it is to send out mouse position events as they happen. Note that these events will not be sent out when the mouse is over a widget like a button as the widget will capture the events.

Mouse Move Event Handler
This handler receives the event of a Mouse Move and displays the formatted form of it. Test what happens when it is over widgets or outside of the window.

Invoking the Window
Invoking the window is another area of difference from the previous example. This time only 1 line is needed for invoking the GUI.

Misc Additional Topics
There are 3 concepts to the screen real estate in a GUI environment: Within the software all are measured in pixels. PySide has function to measure in real world units but these are undependable as the manufacturers have no standard for pixel size or aspect ratio.
 * physical space on the screen
 * frame
 * geometry

The Frame is the size of a window including it's side bars, top bar (possibly with a menu in it) and bottom bar. The Geometry is the space lying within the Frame and so is always less than or equal to the Frame. In turn the Frame is always less than or equal to the available screen size.

Available Screen Size
Generally the "availableHeight" should be less than the "screenHeight" by the height of the menu bar. These 4 values are based on the hardware environment and will change from computer to computer. They are not dependent on any application window size.

Frame Size and Geometry
These same commands can be executed on a user generated window, the syntax does not change.