PySide Intermediate Examples/it

Introduzione
Questa pagina contiene degli esempi di livello medio di gestione della GUI con PySide. Gli Esempi di base di PySide e gli Esempi di livello avanzato di PySide sono contenuti nelle rispettive pagine. In questa pagina gli argomenti di PySide sono descritti utilizzando un programma come esempio. L'intenzione è quella di presentare dei codici PySide funzionanti, e consentire a chi ha bisogno di usare PySide di copiare la sezione utile, di modificarla e adattarla ai propri scopi.

Note

 * Questa pagina non è destinata a trattare il linguaggio Python o a fornire istruzioni su Python.
 * I nomi delle variabili non sono descrittivi, ma sono stati tenuti in sequenza per organizzare al meglio le spiegazioni.
 * Ci sono numerose convenzioni per i nomi dei componenti GUI, nessuno dei quali è mai "right" o "wrong"
 * C'è una serie di diverse sequenze di dichiarazioni per i widget, i segnali, i metodi, e ancora una volta nessuna è mai "right" o "wrong"
 * Vale la pena di ricordare che PySide opera con le stringhe quando tratta gli input dell'utente, e quello che appare sullo schermo come un numero è in realtà una rappresentazione testuale di un numero

Code Based Discussion - Declarative Portion
Questo "programma di esempio" è in realtà una grande definizione di classe, la definizione di una classe PySide GUI, e ha più di 150 righe di codice (inclusi i commenti). La classe e il suo comportamento non sono finalizzati a nulla, l'unico scopo è quello di dimostrare le azioni GUI possibili e di presentare un codice che si spera possa essere utilizzato da altri utenti di FreeCAD.

La definizione di classe e le poche righe di codice richiamate sono descritti nell'ordine in cui si presentano nel file. Questo ordine si basa sulla disposizione degli elementi nella schermata ed è piuttosto arbitrario e destinato unicamente a dimostrare le caratteristiche. Questa è la schermata GUI modale generata dalla Classe PySide:



La maggior parte del resto di questa sezione descrive il contenuto della Class definition che compare alla fine di questa sezione. Prima si descrivono gli elementi dichiarativi che definiscono il funzionamento delle cose e come viene assemblata la GUI, poi si descrivono le sezioni operative (cioè il codice che viene eseguito quando si verificano le interazioni degli utenti). Questa finestra è basata sulla classe QDialog e quindi è modale, questo significa che non si può fare nessuna attività al di fuori della finestra mentre essa è aperta.

La dichiarazione Import
La dichiarazione di importazione obbligatoria

Questa è meglio posizionarla all'inizio del file Python.

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

Ripristinare lo stato della finestra
Questo non è obbligatorio, ma è piuttosto una buona pratica di programmazione, questo imposta lo stato di default di ripristino per la finestra che sarà disponibile indipendentemente dalle azioni dell'utente. Più avanti nel codice questo può essere modificato dal codice Python per indicare le diverse opzioni che l'utente può aver selezionato.

Creare la finestra
Ricordando che le dimensioni dello schermo sono misurate partendo dall'angolo in alto a sinistra, i valori della terza riga si riferiscono a: Dopo viene impostato il titolo della finestra e la riga finale significa semplicemente che questa finestra non sarà mai oscurata da un'altra finestra, se non si desidera questo, basta semplicemente inserire il carattere di commento Python ('#') come primo carattere della riga.
 * numero di pixel dell'angolo in alto a sinistra, a destra del bordo sinistro dello schermo (250)
 * numero di pixel dell'angolo in alto a sinistra, sotto al bordo superiore dello schermo (250)
 * larghezza in pixel della finestra (400)
 * altezza in pixel della finestra (350)

Creare le etichette
In PySide le etichette (label) servono a due scopi, per le etichette statiche (come suggerisce il nome), e per quelle di sola lettura (cioè di sola visualizzazione) dei campi di testo. Così possono essere comunicati all'utente sia le istruzioni immutabili come "Non premere il pulsante rosso", sia i risultati dei calcoli dinamici come "42". La riga 2 dichiara un'etichetta e imposta il suo valore iniziale (che in questo caso è vuoto). La riga 3 specifica il tipo di carattere. Si può specificare qualsiasi tipo di carattere disponibile nel sistema, se il font non è specificato viene utilizzato quello di default. In questo caso il carattere viene specificato come non proporzionale. Infine l'etichetta viene spostata nella sua posizione della finestra - le sue coordinate specificano la sua posizione rispetto alla finestra, non allo schermo.

Creare una casella di controllo
Le caselle di controllo (Checkbox) possono essere selezionate o deselezionate in qualsiasi combinazione (a differenza dei pulsanti di opzione). La riga 2 ne dichiara una e imposta il suo valore iniziale. La riga 3 specifica quale metodo viene eseguito quando si clicca sulla casella di controllo (in questo caso il metodo 'onCheckBox1'). Se la riga 4 non non è stata commentata mettendo il carattere di commento Python ('#') come primo carattere, essa viene eseguita e segna la casella di controllo come selezionata. Infine la riga 5 sposta la casella di controllo nella sua posizione.

Creare i pulsanti di opzione
La creazione dei pulsanti di opzione (radioButton) è molto simile alla creazione delle caselle di controllo. L'unica differenza è data dal comportamento dei pulsanti di opzione in quanto non possono essere selezionati contemporaneamente

Creare i menu a scomparsa
Nella riga 2 è costruita la lista di quelle che saranno le scelte consentite agli utenti. Un'alternativa è quella di costruire un dizionario, ma di utilizzare solo i tasti per l'elenco del menu delle scelte. La riga 4 crea il menu pop-up (noto come un ComboBox in PySide), le opzioni utente sono aggiunte nella riga 5.

Come nota a margine, se è stato utilizzato il dizionario le righe appaiono come queste:

Tornando al codice principale dell'esempio per questa sezione, la riga 6 imposta la scelta predefinita, questa riga può essere omessa, il valore della scelta di default può anche essere caricato nell'etichetta corrispondente. Infine la riga 8 stabilisce il posizionamento.

Creare i pulsanti - Parte 1
Il pulsante (button) e il suo nome sono creati nella riga 2. Il gestore del segnale per sapere quando questo pulsante viene cliccato è specificato nella riga 3. La riga 4 impedisce che il pulsante diventi il 'pulsante di default' - il pulsante che viene cliccato se l'utente preme semplicemente il tasto. Lo spostamento nella sua posizione conclude questo segmento di codice.

Creare un campo per inserire dei testi
Il QLineEdit è probabilmente il widget più comune per consentire all'utente di inserire dei testi. Questa sezione di codice crea il campo (riga 2), imposta un valore iniziale (riga 3), imposta la lunghezza del campo (riga 4) e posiziona l'oggetto (riga 5). In questo esempio, la sezione di codice successiva crea un menù contestuale per operare su di esso.

Creare un menu contestuale
Siccome la stessa azione viene eseguita con diversi valori, questo codice ha numerose ripetizioni, ed è una parte di ciò che rende il codice GUI così lungo (non importa quale sistema). Prima viene creata una QAction - si tratta di un abbinamento (o collegamento) del testo che l'utente vede come opzione selezionabile con il metodo che viene eseguito quando l'opzione viene selezionata. Si tratta sostanzialmente di un abbinamento tra la scelta utente e una parte di codice. La riga 3 crea, la riga 4 definisce l'opzione dell'utente (come vedremo) e la riga 5 specifica quale pezzo di codice Python viene eseguito.

Saltando alla riga 19 (la riga con "self.textInput.setContextMenuPolicy") viene creato un ActionsContextMenu, che è il titolare di tutti i singoli collegamenti di QAction tra la scelta dell'utente e il codice da eseguire. Ogni widget può avere un solo menu contestuale (ovvero il menu associato al tasto destro del mouse), perciò la riga 19 definisce tale menu. Le 4 righe successive aggiungono i collegamenti creati all'inizio di questa sezione di codice. L'ordine è significativo, l'utente vede le opzioni del menu nell'ordine in cui vengono aggiunte. Notare che l'opzione del menu 3 non è niente, il suo codice è nullo, ma nel menu contestuale serve a separare due gruppi di opzioni.

Creare un campo di input numerico
La creazione del campo di input numerico è simile a quella per l'inserimento di testi vista in precedenza. Infatti il codice è identico ad eccezione delle righe 3 e 4. La riga 3 imposta la Mask (maschera) come definita da PySide, che in questo caso specifica fino a 3 cifre (che possono includere 0). Un elenco completo dei codici InputMask si trova in QLineEdit InputMask

Button Creation Part 2
Both buttons are created with a name (which will appear as their label), associated with a method which will execute when they are clicked, and moved into position. The one exception is line 4 which specifies the 'Cancel' button as the default button - that means it will be "clicked" if the user preses the key.

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
Tutti i singoli widget dell'esempio di finestra modale precedente possono essere trasferiti e utilizzati in una finestra non modale. La differenza principale è che la finestra non modale non impedisce all'utente di interagire con altre finestre. Fondamentalmente, una finestra non modale è una finestra che può essere aperta e lasciata aperta per tutto il tempo necessario senza che essa ponga delle restrizioni sulle altre finestre dell'applicazione. Tra i due tipi di finestre ci sono poche differenze di codice, che saranno evidenziate, quindi questo esempio di codice è abbastanza breve. Tutto ciò che è uguale al precedente esempio modale sarà omesso per mantenere breve questa panoramica. Questa è la schermata GUI non modale che la Classe PySide genera:



La dichiarazione Import
La dichiarazione di importazione obbligatoria

Questa è meglio posizionarla all'inizio del file Python.

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.

Argomenti aggiuntivi vari
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.