Archivio

Posts Tagged ‘PyQt5’

Ubuntu 16.04: PyQt5

27 Marzo 2019 Commenti chiusi

Compilazione PyQt5 su Ubuntu 16.04 32 bit.

L’obbiettivo è l’installazione di PyQt5 su Ubuntu 16.04 32 bit

Qt è un set di librerie C++ per la costruzione di interfacce grafiche e non solo.
PyQt è un set di bindings di python a tali librerie.
Tali bindings (collegamenti) altro non sono che moduli python con più di mille classi disponibili.

Dal sito ufficiale di PyQt5 però notiamo con sgomento come non siano previste
le PyQt5 per dispositivi a 32 bit.

“Binary Packages
Wheels are provided for Python v3.5 and later for 64-bit Linux, macOS and 32-bit and 64-bit Windows.
These include copies of the corresponding Qt libraries.
Note that the minimum version of macOS supported is determined by the version of Qt included in the wheel.
So long as you are using a supported version of Python you can install PyQt5 from PyPi by running:
pip3 install PyQt5″

Non è quindi possibile installarle con pip e nemmeno sono reperibili dei deb package.

Per poter usufruire di tali librerie, senza ricorrere alle obsolete PyQt4, bisognerà compilare le versioni precedenti alla 5.12 attuali.

L’ordine logico sarà quindi quello di installare Qt, Sip, PyQt5

Cos’è Sip?

” One of the features of Python that makes it so powerful is the ability to take existing libraries, written in C or C++,
and make them available as Python extension modules.
SIP is a tool that makes it very easy to create Python bindings for C and C++ libraries.

In sostanza è proprio colui che permette di utilizzare le librerie Qt, come moduli di Python!

Installazione pacchetti per compilazione

Cominciamo con i pacchetti utili alle varie compilazioni:

sudo apt-get install build-essential
sudo apt-get install checkinstall
sudo apt-get install qt5-default qtdeclarative5-dev python-dev

Installazione Qt

Installiamo le Qt con l’installer online:
Scaricato il file, lo rendiamo eseguibile,

sudo chmod +x qt-unified-linux-x86-online.run

e lo eseguiamo:

./qt-unified-linux-x86-online.run

Proseguire e saltare la registrazione in modo da terminare l’installazione del toolkit Qt

Installazione SIP

Ora dobbiamo installare Sip, nel mio caso ho installato la 4.16.5, perchè la 4.19.15 mi dava dei problemi.
Si scarica l’archivio da qui:

ci portiamo nell dir dove lo abbiamo scaricato e lo scompattiamo

tar -xvzf sip-4.16.5.tar.gz
cd sip-4.16.5
python3 configure.py
make
sudo checkinstall

utilizzo checkinstall per agevolare eventuali rimozioni del pacchetto, ma andrebbe benissimo

sudo make install

Se tutto va bene Sip sarà alla versione desiderata

banco@banco-laptop:~/Scaricati$ sip -V
4.16.5

Installazione PyQt5

Installato Sip, passiamo a PyQt5. Nel mio caso sono riuscito con la 5.4 (la 5.6 richiede già sip 4.19.15 che mi dà problemi!)

Scarico PyQt-5.4 da qui.

tar -xvzf PyQt-gpl-5.4.tar.gz
cd PyQt-gpl-5.4

importante ora è dire al configure dove si trova sip:

python3 configure.py --sip-incdir ../sip-4.16.5/siplib
make
sudo checkinstall

Se tutto è filato lischio, ora abbiamo delle Qt per Python su architettura 32 bit:

banco@banco-laptop:~/Scaricati$ python3
>>> from PyQt5.QtWidgets import QMainWindow
>>> from PyQt5.QtWidgets import QWidget, QApplication
>>> class FormWidget(QWidget):
...     def __init__(self, parent):
...         super(FormWidget, self).__init__(parent)
... 
>>> class MainWindow(QMainWindow):
...     def __init__(self, parent=None):
...         super(MainWindow, self).__init__(parent)
...         self.central_widget = FormWidget(self) 
...         self.setCentralWidget(self.central_widget) 
... 
>>> app = QApplication([])
>>> mw = MainWindow()
>>> mw.show()
>>> app.exec_()

Non abbiamo errori e la finestra appare regolarmente.

Categorie:PyQt5, python Tag: ,

PyQt5: QTabWidget

22 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

QTabWidget

Il TabWidget mette a disposizione un contenitore con pagine multiple, selezionabili tramite tabs.
Ogni pagina può contenere un widget, o un ulteriore contenitore di widgets.
La testata del TabWidget altri non è che il TabBar, ottenibile
con il metodo tabBar di QTabWidget.

Per prima cosa si istanzia l’oggetto QTabWidget, poi è possibile aggiungere tab con i due seguenti metodi:
addTab(child, label): aggiunge un tab nell’ordine in cui viene inserito, uno dopo l’altro;
insertTab(index, child, label): aggiunge un tab all’indice predefinito, slittando tutti gli altri in avanti.

è possibile assegnare anche un oggetto QIcon al tab in fase di aggiunta, nella seguente modalità:

addTab(child, icon, label);
insertTab(index, child, icon, label);

Un esempio molto semplice di TabWidget può essere:

import sys
from PyQt5.QtWidgets import (QMainWindow, QApplication, QPushButton, QWidget,
                             QTabWidget, QVBoxLayout)
from PyQt5.QtGui import QIcon


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("QTabWidget Example")
        self.central_widget = TableWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(400, 100)


class TableWidget(QWidget):
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.layout = QVBoxLayout(self)

        # Inizializzo il TabWidget
        self.tab_widget = QTabWidget()
        self.tab1 = QWidget()  # Creo un primo widget generico
        self.tab2 = QWidget()  # Creo un secondo widget generico
        self.tab_widget.resize(300, 200)

        # Aggiungo i tabs al TabWidget
        self.tab_widget.addTab(self.tab1, QIcon("Italy.png"), "Ialy")
        self.tab_widget.addTab(self.tab2, QIcon("France.png"), "France")

        # Create first tab
        layout1 = QVBoxLayout(self)
        self.pushButton1 = QPushButton("button 1")
        layout1.addWidget(self.pushButton1)
        self.tab1.setLayout(layout1)  # aggiungo il layout al widget generico

        # Create second tab
        layout2 = QVBoxLayout(self)
        self.pushButton2 = QPushButton("button 2")
        layout2.addWidget(self.pushButton2)
        self.tab2.setLayout(layout2)  # aggiungo il layout al widget generico

        # Add tabs to widget
        self.layout.addWidget(self.tab_widget)
        self.setLayout(self.layout)

        self.pushButton1.clicked.connect(self.on_button)
        self.pushButton2.clicked.connect(self.on_button)

    def on_button(self):
        button = self.sender()
        print("Clicked on <%s>" % button.text())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Vediamo i metodi più importanti di QTabWidget:

Aggiunta e rimozione tabs

Come già anticipato possiamo aggiungere tab con il metodo addTab(child, label):

>>> from PyQt5.QtWidgets import *
>>> app = QApplication(sys.argv)
>>> tabwidget = QTabWidget()
>>> tab1 = QWidget()
>>> tabwidget.addTab(tab1, "tab1")
0
>>> tab0 = QWidget()
>>> tabwidget.insertTab(0, tab0, "tab0")
0

L’int ritornato è la posizione di inserimento del tab.

Per sapere quanti tab ci sono in un TabWidget si utilizza il metodo count

>>> tabwidget.count()
2

Nota:

Come anticipato, è possibile risalire al componente principale del tabwidget, il tabbar appunto:

>>> tabwidget.tabBar()
<PyQt5.QtWidgets.QTabBar object at 0x0396D5D0>
>>> tabbar = tabwidget.tabBar()
>>> tabbar.count()
2
>>> tabbar.currentIndex()
1

Per rimuovere un tab si utilizza il metodo removeTab(index), dove index è ovviamente l’indice della posizione del tab da rimuovere.

>>> tabwidget.removeTab(0)
>>> tabwidget.count()
1

Per rimuovere tutti i tabs in un colpo solo si utilizza il metodo clear

Testo, Icona e Tooltip

Il nome di un tab è modificabile anche dopo l’avvenuta aggiunta sul tabwidget; si utilizza il metodo setTabText(index, text).
Allo stesso modo è possibile aggiungere un’icona con il metodo setTabIcon(index, icon) e un tooltip con il metodo
setTabToolTip(index, tooltip_text)

>>> tabwidget.setTabText(0, "New tab 1")
>>> from PyQt5.QtGui import QIcon
>>> tabwidget.setTabIcon(0, QIcon("icon.png"))
>>> tabwidget.setTabToolTip(0, "Tab 1 tooltip text")

Tutte queste cose sono rintracciabili con i metodi tabIcon(index) per risalire all’Icona assegnata al tab di indice index,
tabToolTip(index) per risalire al tooltip del tab e tabText(index) per il testo:

>>> tabwidget.tabIcon(0)
<PyQt5.QtGui.QIcon object at 0x0396D3F0>
>>> tabwidget.tabToolTip(0)
'Tab 1 tooltip text'
>>> tabwidget.tabText(0)
'New tab 1'

Con il metodo widget è possibile risalire al widget appartenente a quel tab di indice index es:

>>> class MyQWidget(QWidget):
...     def __init__(self, name):
...         super(MyQWidget, self).__init__()
...         self.name = name
...         
>>> mytab = MyQWidget("MyTab 1")
>>> tabwidget.addTab(mytab, "my tab 1")
1
>>> tabwidget.widget(1).name
'MyTab 1'

Vediamo alcune cose di tipo Grafico

AutoHide

Se settiamo il metodo setAutoHide a True, qualora il tabwidget avesse meno di 2 tab, la tabbar scomparirebbe automaticamente.

...
        # Aggiungo i tabs al TabWidget
        self.tab_widget.addTab(self.tab1, QIcon("Italy.png"), "Ialy")
        # self.tab_widget.addTab(self.tab2, QIcon("France.png"), "France")
...

Se commentiamo l’aggiunta del secondo tab, il risultato sarà:

Tab chiudibili

Se vogliamo che i tab siano chiudibili, bisogna settare a True il metodo setTabsClosable.
Apparirà così un pulsante di chiusura nel tab.
Cliccando su tale pulsante verrà emesso un segnale tabCloseRequested da collegare all’apposito slot.

...
        # Aggiungo i tabs al TabWidget
        self.tab_widget.addTab(self.tab1, QIcon("Italy.png"), "Ialy")
        self.tab_widget.addTab(self.tab2, QIcon("France.png"), "France")
        self.tab_widget.setTabsClosable(True)
        self.tab_widget.tabCloseRequested[int].connect(self.on_tab_close)
...
    def on_tab_close(self, int):
        print("Tab <%s> Closed!" % int)
        self.tab_widget.removeTab(int)
...

Tab Disattivabili

E’ sufficiente utilizzare il metodo setTabEnabled(index, bool) ad es:

...
        self.tab_widget.setTabEnabled(0, False)
...

risulterà in:


L’informazione relativa al tab sarà ottenibile tramite il metodo isTabEnabled(index):

>>> tabwidget.setTabEnabled(0, False)
>>> tabwidget.isTabEnabled(0)
False

Shift dei Tab

Se vogliamo che i tab possano muoversi per scambiarsi ad esempio di posto, possiamo utilizzare il metodo setMovable(bool):

...
        # self.tab_widget.setTabEnabled(0, False)
        self.tab_widget.setMovable(True)
...

Ovviamente lo shift, aggiornerà anche gli indici nella tabbar.

Quando setMovable è attivo, possiamo anche spostare le tab in differenti posizioni. Di Default vengono posizionate in alto (QTabWidget.North), ma è possibile utilizzare anche altre modalità, usando i valori
QTabWidget.South, QTabWidget.East, QTabWidget.West:

...
        self.tab_widget.setMovable(True)
        self.tab_widget.setTabPosition(QTabWidget.West)
...


Segnali

Abbiamo già parlato del segnale tabCloseRequested, vediamo gli altri.

currentChanged(index): segnale emesso quando si cambia tab;
tabBarClicked(index): segnale emesso quando si clicca sulla tabbar;
tabBarDoubleClicked(index): segnale emesso quando si doppio-clicca sulla tabbar;

Non resta che connettere tali segnali agli slot dedicati:

...
        self.tab_widget.tabCloseRequested[int].connect(self.on_tab_close)
        self.tab_widget.currentChanged[int].connect(self.on_tab_change)
        self.tab_widget.tabBarClicked[int].connect(self.on_tab_click)
        self.tab_widget.tabBarDoubleClicked[int].connect(self.on_tab_2click)

    def on_tab_close(self, int):
        print("Tab <%s> Closed!" % int)
        self.tab_widget.removeTab(int)

    def on_tab_change(self, int):
        print("Now you are in Tab <%s>!" % int)

    def on_tab_click(self, int):
        print("You have clicked on Tab <%s>!" % int)

    def on_tab_2click(self, int):
        print("You have double-clicked on Tab <%s>!" % int)
...

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: QGroupBox

21 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

QCheckBox

Il GroupBox è un contenitore con titolo e bordo, che permette di raggruppare elementi.
Siccome il groupbox può ospitare un widget soltanto, volendo raggruppare più widget (es. dei radio button), è consigliabile utilizzare un BoxLayout. Il GroupBox conterrà quindi il BoxLayout,
che a sua volta conterrà i widget multipli.

Es.:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QRadioButton
from PyQt5.QtWidgets import QGroupBox, QVBoxLayout
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QGroupBox Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        groupbox = QGroupBox("Nations")
        external_box = QBoxLayout(QBoxLayout.TopToBottom)
        external_box.addWidget(groupbox, 0)
        internal_box = QVBoxLayout()
        radiobutton1 = QRadioButton("Italy", self)
        radiobutton1.setChecked(True)
        radiobutton2 = QRadioButton("France", self)
        internal_box.addWidget(radiobutton1, 0)
        internal_box.addWidget(radiobutton2, 0)
        groupbox.setLayout(internal_box)
        self.setLayout(external_box)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Un metodo interessante è setCheckable(bool) che setta la costante checkable a True o False.
Se settiamo checkable a True, al posto della label del groupbox, apparirà una checkbox, che ci permetterà di abilitare o disabilitare i widget del groupbox stesso:

...
        groupbox.setCheckable(True)
...

Per sapere se il groupbox è checkable, si utilizza il metodo isCheckable:

>>> from PyQt5.QtWidgets import QApplication, QGroupBox
>>> app = QApplication([])
>>> groupbox = QGroupBox("Nations")
>>> groupbox.setCheckable(True)
>>> groupbox.isCheckable()
True

Per settare lo stato di checkable al groupbox, si usa il metodo setChecked(bool).
Settandolo a False, il groupbox sarà disattivato fino a chè non clicchiamo la checkbox del titolo.

Per sapere in quale stato (checked: True/False) si trova il groupbox si usa il metodo isChecked.

>>> groupbox.setChecked(False)
>>> groupbox.isChecked()
False

Allineamento widget

L’allineamento del widget all’interno del groupbox è modificabile con il metodo setAlignment(alignment), dove alignment può assumere i seguenti valori: Qt.AlignLeft, Qt.AlignRight, Qt.AlignHCenter.
Avendo utilizzato un BoxLayout all’interno del GrouBox, è necessario specificarne l’allineamento:

...
from PyQt5.QtCore import Qt
...
        internal_box = QVBoxLayout()
        internal_box.setAlignment(Qt.AlignRight)
        ...
        groupbox.setLayout(internal_box)
        groupbox.setCheckable(True)
        groupbox.setChecked(False)
        groupbox.setAlignment(Qt.AlignRight)
        self.setLayout(external_box)
...

Segnali

Esclusi i segnali dei widget compresi nel group box, va evidenziato clicked.
Ogni volta che clicchiamo sulla checkbox del groupbox, viene emesso un segnale clicked, che possiamo connettere ad uno slot dedicato:

...

        groupbox.clicked.connect(self.on_groupbox)

    def on_groupbox(self):
        groupbox = self.sender()
        title = groupbox.title()
        if groupbox.isChecked():
            print("<%s> group box ENABLED!" % title)
        else:
            print("<%s> group box DISABLED!" % title)
...

Utilizzare sender permette di utilizzare un unico slot per il segnale clicked.

GroupBox multipli

E’ infatti possibile utilizzare più groupBox come nel sequente esempio:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QRadioButton
from PyQt5.QtWidgets import QGroupBox, QVBoxLayout
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QGroupBox Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        external_box = QBoxLayout(QBoxLayout.TopToBottom)
        groupbox = QGroupBox("Nations")
        external_box.addWidget(groupbox, 0)
        groupbox.setCheckable(True)
        groupbox.setChecked(False)
        internal_box = QVBoxLayout()
        groupbox.setLayout(internal_box)
        radiobutton1 = QRadioButton("Italy", self)
        radiobutton1.setChecked(True)
        radiobutton2 = QRadioButton("France", self)
        internal_box.addWidget(radiobutton1, 0)
        internal_box.addWidget(radiobutton2, 0)

        groupbox2 = QGroupBox("Cities")
        external_box.addWidget(groupbox2, 0)
        groupbox2.setCheckable(True)
        groupbox2.setChecked(False)
        internal_box2 = QVBoxLayout()
        groupbox2.setLayout(internal_box2)
        radiobutton3 = QRadioButton("Bologna", self)
        radiobutton3.setChecked(True)
        radiobutton4 = QRadioButton("Milano", self)
        internal_box2.addWidget(radiobutton3, 0)
        internal_box2.addWidget(radiobutton4, 0)

        self.setLayout(external_box)

        groupbox.clicked.connect(self.on_groupbox)
        groupbox2.clicked.connect(self.on_groupbox)

    def on_groupbox(self):
        groupbox = self.sender()
        title = groupbox.title()
        if groupbox.isChecked():
            print("<%s> group box ENABLED!" % title)
            print("Available options:")
            for radiobox in [w for w in groupbox.children()
                             if isinstance(w, QRadioButton)]:
                print(radiobox.text())
        else:
            print("<%s> group box DISABLED!" % title)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Quando le checkbox dei groupbox saranno selezionate, potremo ricavare l’oggetto QGroupBox di riferimento, tramite il metodo sender di QWidget e di conseguenza gli attributi necessari, come ad esempio i radiobutton utilizzati, utilizzando il metodo children

<Nations> group box ENABLED!
Available options:
Italy
France
<Nations> group box DISABLED!
<Cities> group box ENABLED!
Available options:
Bologna
Milano
<Cities> group box DISABLED!

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: QComboBox

21 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

QComboBox

Il combobox è un widget composto da un bottone e da una popup list.
Per creare un combobox si utilizza il costruttore QComboBox.
Per aggiungere elementi multipli al combobox si utilizza il metodo addItems(list), oppure addItem(str) per
aggiungere un solo elemento. Con il metodo count contiamo gli elementi della popup list:

>>> from PyQt5.QtWidgets import QApplication, QComboBox
>>> app = QApplication([])
>>> combobox = QComboBox()
>>> combobox.addItems(['Italy', 'France'])
>>> combobox.addItem('Spain')
>>> combobox.count()
3

Di default l’indice all’interno della popup list sarà settato a 0.
Per sapere quale indice è settato sulla popup list, si utilizza il metodo currentIndex.
Per modificare l’indice, si utilizza il metodo setCurrentIndex(int) e per leggere il testo dell’indice corrente,
si utilizza il metodo currentText:

>>> combobox.currentIndex()
0
>>> combobox.setCurrentIndex(1)
>>> combobox.currentIndex()
1
>>> combobox.currentText()
'France'
>>> combobox.setCurrentIndex(2)
>>> combobox.currentText()
'Spain'

Per ottenere il testo di un elemento della lista, si usa il metodo itemText(int), dove int è l’indice che ci interessa.

>>> combobox.itemText(0)
'Italy'

E’ possibile trovare un testo all’interno della popup list con il metodo findText(str).
Tale metodo ritorno l’indice del testo all’interno della lista, se lo trova, altrimenti ritorna -1.

>>> combobox.findText('Germany')
-1
>>> combobox.findText('Spain')
2

Per ottenere la lista di tutti gli elementi della popup list possiamo usare una list comprehension:

>>> items = [combobox.itemText(i) for i in range(combobox.count())]
>>> items
['Italy', 'France', 'Spain']

Per inserire un elemento in una determinata posizione, possiamo usare il metodo insertItem(int, str) dove,
int è l’indice dove verrà inserito il nuovo elemento e str è il nome del nuovo elemento che
apparirà nella popup list. Il nuovo elemento causerà lo slittamento dei successivi.
E’ possibile inserire anche una lista di nuovi elementi, con il metodo insertItems(int, list), con
list, la lista dei nuovi elementi:

>>> combobox.insertItems(1, ['San Marino', 'Andorra'])
>>> [combobox.itemText(i) for i in range(combobox.count())]
['Italy', 'San Marino', 'Andorra', 'France', 'Spain']

oppure

>>> combobox.insertItem(1, 'Germany')
>>> [combobox.itemText(i) for i in range(combobox.count())]
['Italy', 'Germany', 'France', 'Spain']

Per eliminare un elemento si utilizza il metodo removeItem(int), dove int è l’indice
dell’elemento che verrà eliminato

>>> combobox.removeItem(1)
>>> [combobox.itemText(i) for i in range(combobox.count())]
['Italy', 'France', 'Spain']

Visivamente il combobox si presenta così:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QComboBox
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QComboBox Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        nations = ['Italy', 'France', 'Spain']
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.combobox = QComboBox()
        self.combobox.addItems(nations)
        layout.addWidget(self.combobox, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Icone

Se volessimo aggiungere le icone nella popup list, è possibile aggiungere alla combobox, oggetti QIcon invece che semplici stringhe. Infatti i metodi addItem e addItems lo consentono:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QComboBox
import sys
from PyQt5.QtGui import QIcon


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QComboBox Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        nations = ['Italy', 'France', 'Spain']
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        italy_icon = QIcon("Italy.png")
        france_icon = QIcon("France.png")
        self.combobox = QComboBox()
        self.combobox.addItem(italy_icon, "Italy")  # aggiungo icona e stringa
        self.combobox.addItem(france_icon, "France")  # aggiungo icona e stringa
        layout.addWidget(self.combobox, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Segnali

Il segnale che connettiamo è activated(int).
Richiede, come da documentazione, l’id dell’elemento selezionato dalla popup list:

...

        self.combobox.activated[int].connect(self.on_combobox)

    def on_combobox(self, id):
        text = self.combobox.itemText(id)
        print("%s [%s] selected!" % (text, id))

...

Gli altri segnali ereditati sono: currentIndexChanged, currentTextChanged, editTextChanged, highlighted.

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: QCheckBox

20 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

QCheckBox

Per creare un checkbox si utilizza il costruttore QCheckBox(label).
Ci sono molte similitudini con gli altri tipi di button, ma a differenza dei radiobutton, in questo caso
la scelta di un checkbox, non esclude assolutamente gli altri.

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QCheckBox
from PyQt5.QtGui import QIcon, QColor, QFont
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QCheckBox Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.checkbox1 = QCheckBox("Italy", self)
        self.checkbox2 = QCheckBox("France", self)
        layout.addWidget(self.checkbox1, 0)
        layout.addWidget(self.checkbox2, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

E’ possibile settare di default a checked (selezionato) un radiobutton, con il metodo setChecked,
passando come argomento True:

...
        self.checkbox1.setChecked(True)
...

Come per gli altri button, se vogliamo fare il checkbox non sia selezionabile, possiamo utilizzare il metodo setCheckable passando come argomento False:

...
        self.checkbox2.setCheckable(False)
...

Icons

Vale lo stesso discorso fatto per gli altri bottoni: si utilizza un oggetto QIcon e lo si associa al checkbox:

...
from PyQt5.QtGui import QIcon
...
        self.checkbox1.setIcon(QIcon("Italy.png"))
        self.checkbox2.setIcon(QIcon("France.png"))
...

Colore

valgono le regole già viste per gli altri widget, ovvero si utilizzano QPalette e QColor sugli
elementi backgroundRole e foregroundRole del widget interessato:

...
from PyQt5.QtGui import QColor

...
        # background
        bg_color = QColor('Yellow')
        palette = self.radio_button1.palette()
        rb1_background = self.radio_button1.backgroundRole()
        palette.setColor(rb1_background, bg_color)
        fg_color = QColor('Red')
        # foreground
        rb1_foreground = self.radio_button1.foregroundRole()
        palette.setColor(rb1_foreground, fg_color)
        self.radio_button1.setPalette(palette)
        self.radio_button1.setAutoFillBackground(True)
...

Font

Anche la modifica del font non cambia, si utilizza cioè il costruttore QFont nella solita maniera:

...
        # Font
        font = QFont("Lucida", 14, QFont.Bold)
        self.checkbox1.setFont(font)
...


Testo

Il testo può essere settato con il metodo setText anche dopo aver istanziato l’oggetto.
E’ possibile anche utilizzare gli ampersand con il medesimo metodo.
Stesso discorso vale per settare un tooltip tramite metodo setToolTip:

...
        self.checkbox1 = QCheckBox()
        self.checkbox1.setText("&Italy")  # Ampersand
        self.checkbox1.setIcon(QIcon("Italy.png"))
        self.checkbox1.setToolTip("Select Italy")  # Tooltip
...

Stato del CheckBox

Come detto, lo stato del checkbox è settabile tramite metodo setChecked, mentre per ottenere lo
stato del checkbox si utilizza il metodo isChecked:

>>> from PyQt5.QtWidgets import QApplication, QCheckBox
>>> app = QApplication([])
>>> checkbox1 = QCheckBox("Italy")
>>> checkbox1.setChecked(True)
>>> checkbox1.isChecked()
True
>>> checkbox1.setChecked(False)
>>> checkbox1.isChecked()
False

il metodo isChecked funziona solo con il checkbox tradizionale, non in caso di tristate.

Tristate

Di default il checkbox può avere due stati, True quando è cliccato, False quando non lo è.
E’ possibile però settare un checkbox in Tristate con il metodo setTristate.
Per sapere se un checkbox è tristate, si usa il metodo isTristate

>>> checkbox1.setTristate(True)
>>> checkbox1.isTristate()
True
...
        self.checkbox1.setTristate(True)
        self.checkbox2.setTristate(True)
...

per controllare lo stato di un checkbox tristate, si usa il metodo checkState:

>>> checkbox1.setTristate(True)
>>> checkbox1.isTristate()
True

Per settare lo stato del tristate, si usa il metodo setCheckState:

>>> checkbox1.setCheckState(2)
>>> checkbox1.checkState()
2

I tre valori da passare a setCheckState sono:

0: checkbox non selezionato, corrisponde al valore Qt.Unchecked;
1: checkbox intermedio, corrisponde al valore Qt.PartiallyChecked;
2: checkbox selezionato, corrisponde al valore Qt.Checked;

...
from PyQt5.QtCore import Qt

...
        self.checkbox1.setCheckState(Qt.PartiallyChecked)        
        self.checkbox2.setCheckState(Qt.Checked)
...

Visivamente l’opzione intermedia (nè True, nè False), si traduce in :

Segnali

Oltre ai segnali ereditati dal QAbstractButton, ovvero:
clicked, pressed, released e toggled, abbiamo stateChanged.

Si connette tale segnale allo slot predisposto ed il gioco è fatto.
Possiamo creare slot ad hoc per ogni checkbox:

...
        self.checkbox1.stateChanged.connect(self.on_checkbox1)
        self.checkbox2.stateChanged.connect(self.on_checkbox2)

    def on_checkbox1(self):
        print("[CB1] State changed to %s!" % self.checkbox1.checkState())

    def on_checkbox2(self):
        print("[CB2] State changed to %s!" % self.checkbox2.checkState())
...

O ne creiamo uno condiviso, al quale passare come argomento il widget:

...
        self.checkbox1.stateChanged.connect(
            lambda: self.on_checkbox(self.checkbox1))
        self.checkbox2.stateChanged.connect(
            lambda: self.on_checkbox(self.checkbox2))

    @staticmethod
    def on_checkbox(checkbox):
        if checkbox.text().lower() == "italy":
            print("[CB1] State changed to %s!" % checkbox.checkState())
        else:
            print("[CB2] State changed to %s!" % checkbox.checkState())
...

BUTTONGROUP

Anche nel caso dei checkbox è possibile legare logicamente i bottoni a buttongroup, come già visto nei
radiobutton.
Ad esempio, associare i checkbox ad un buttongroup permette di attivare l’Exclusive mode grazie al metodo setExclusive.
In questo modo i checkbox si comporteranno come i radiobutton, ovvero la selezione di uno, esclude l’altro.

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QCheckBox
from PyQt5.QtWidgets import QButtonGroup
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QCheckBox Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.button_group = QButtonGroup()
        self.button_group.setExclusive(True)
        self.checkbox1 = QCheckBox("Italy", self)
        self.checkbox2 = QCheckBox("France", self)
        self.button_group.addButton(self.checkbox1, 1)
        self.button_group.addButton(self.checkbox2, 2)
        layout.addWidget(self.checkbox1, 0)
        layout.addWidget(self.checkbox2, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: QRadioButton

20 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

QRadioButton

Per creare i radiobutton si utilizza il costruttore QRadioButton(label).
Quando si hanno più opzioni con i radio button, la scelta di una opzione, escluderà automaticamente le altre.
L’esempio sequente mostra come creare i radio button.

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QRadioButton
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QRadioButton Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.radio_button1 = QRadioButton("Italy", self)
        self.radio_button2 = QRadioButton("France", self)
        self.radio_button3 = QRadioButton("Spain", self)
        layout.addWidget(self.radio_button1, 0)
        layout.addWidget(self.radio_button2, 0)
        layout.addWidget(self.radio_button3, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

E’ possibile settare di default a checked (selezionato) un radiobutton, con il metodo setChecked,
passando come argomento True:

...
        self.radio_button1 = QRadioButton("Italy", self)
        self.radio_button2 = QRadioButton("France", self)
        self.radio_button3 = QRadioButton("Spain", self)
        self.radio_button2.setChecked(True)
...

Se vogliamo fare in modo che una delle opzioni, non sia selezionabile, possiamo utilizzare il metodo setCheckable
passando come argomento False:

...
        self.radio_button1 = QRadioButton("Italy", self)
        self.radio_button2 = QRadioButton("France", self)
        self.radio_button3 = QRadioButton("Spain", self)
        self.radio_button2.setChecked(True)
        self.radio_button3.setCheckable(False)
...

Icons

Per inserire una icona a fianco del radio button, si utilizza lo stesso procedimento utilizzato per il QPushButton.
Si crea quindi un’oggetto QIcon e lo si associa al radio button:

...
from PyQt5.QtGui import QIcon
...
        self.radio_button1 = QRadioButton("Italy", self)
        self.radio_button1.setIcon(QIcon("Italy.png"))
        self.radio_button2 = QRadioButton("France", self)
        self.radio_button2.setIcon(QIcon("France.png"))
        self.radio_button3 = QRadioButton("Spain", self)
        self.radio_button3.setIcon(QIcon("Spain.png"))
...

Colore

valgono le regole già viste per gli altri widget, ovvero si utilizzano QPalette e QColor sugli
elementi backgroundRole e foregroundRole del widget interessato:

...
from PyQt5.QtGui import QColor

...
        # background
        bg_color = QColor('Yellow')
        palette = self.radio_button1.palette()
        rb1_background = self.radio_button1.backgroundRole()
        palette.setColor(rb1_background, bg_color)
        fg_color = QColor('Red')
        # foreground
        rb1_foreground = self.radio_button1.foregroundRole()
        palette.setColor(rb1_foreground, fg_color)
        self.radio_button1.setPalette(palette)
        self.radio_button1.setAutoFillBackground(True)
...

Font

Anche la modifica del font non cambia, si utilizza cioè il costruttore QFont nella solita maniera:

...
        # Font
        font = QFont("Lucida", 14, QFont.Bold)
        self.radio_button1.setFont(font)
...

Segnali

Quando si clicca su un radio button viene emesso il segnale toggled.
Una volta connesso tale segnale al proprio slot, possiamo controllare quale radio button sia stato selezionato utilizzando
il metodo isChecked.

O creiamo uno slot per ogni radio button:

...
        self.radio_button1.toggled.connect(self.on_radio_button_1)
        self.radio_button2.toggled.connect(self.on_radio_button_2)
        self.radio_button3.toggled.connect(self.on_radio_button_3)

    def on_radio_button_1(self):
        if self.radio_button1.isChecked():
            print("click on %s" % self.radio_button1.text())

    def on_radio_button_2(self):
        if self.radio_button2.isChecked():
            print("click on %s" % self.radio_button2.text())

    def on_radio_button_3(self):
        if self.radio_button3.isChecked():
            print("click on %s" % self.radio_button3.text())
...

O ne creiamo uno condiviso, al quale passare come argomento il widget:

...
        self.radio_button1.toggled.connect(
            lambda: self.on_radio_button(self.radio_button1))
        self.radio_button2.toggled.connect(
            lambda: self.on_radio_button(self.radio_button2))
        self.radio_button3.toggled.connect(
            lambda: self.on_radio_button(self.radio_button3))

    @staticmethod
    def on_radio_button(widget):
        if widget.isChecked():
            print("click on %s" % widget.text())
...

Testo

Il testo può essere settato con il metodo setText anche dopo aver istanziato l’oggetto.
E’ possibile anche utilizzare gli ampersand con il medesimo metodo.
Stesso discorso vale per settare un tooltip tramite metodo setToolTip:

...
        self.radio_button1 = QRadioButton()
        self.radio_button1.setText("&Italy")  # Ampersand
        self.radio_button1.setIcon(QIcon("Italy.png"))
        self.radio_button1.setToolTip("Select Italy")  # Tooltip
...

Per evitare effetti indesiderati tra radiobuttons, è possibile utilizzare i ButtonGroup, oggetti invisibili che
hanno il solo scopo di raggruppare bottoni isolandoli da altri con i quali non devono interagire.

BUTTONGROUP

Il costruttore è il QButtonGroup.
Per aggiungere un bottone al gruppo, si utilizza il metodo addButton(widget, id).
Widget è il bottone che vogliamo aggiungere a quel gruppo, id è l’indice che verrà assegnato al bottone e che utilizzeremo per riconoscerlo nel gruppo.

>> from PyQt5.QtWidgets import QApplication, QRadioButton, QButtonGroup
>>> app = QApplication([])
>>> radio_button1 = QRadioButton("Italy")
>>> radio_button2 = QRadioButton("France")
>>> radio_button3 = QRadioButton("Spain")
>>> buttongroup = QButtonGroup()
>>> buttongroup.addButton(radio_button1, 1)
>>> buttongroup.addButton(radio_button2, 2)
>>> buttongroup.addButton(radio_button3, 3)

Per conoscere quali bottoni fanno parte di un gruppo, si utilizza il metodo buttons:

>>> for button in buttongroup.buttons():
...     print(button.text(), button)
...     
Italy <PyQt5.QtWidgets.QRadioButton object at 0x0343E120>
France <PyQt5.QtWidgets.QRadioButton object at 0x0343E0D0>
Spain <PyQt5.QtWidgets.QRadioButton object at 0x0343E1C0>

Per rimuovere un bottone da un gruppo si utilizza il metodo removeButton:

>>> buttongroup.removeButton(radio_button3)
>>> for button in buttongroup.buttons():
...     print(button.text(), button)
...     
Italy <PyQt5.QtWidgets.QRadioButton object at 0x0343E120>
France <PyQt5.QtWidgets.QRadioButton object at 0x0343E0D0>

Gli id precedenti, ci consentono di recuperare un bottone tramite il metodo button(id):

>>> button = buttongroup.button(1)
>>> button
<PyQt5.QtWidgets.QRadioButton object at 0x0343E120>
>>> button.text()
'Italy'

Se invece abbiamo necessità di recuperare l’id di un bottone utilizziamo il metodo id(button):

>>> buttongroup.id(radio_button2)
2

Per cambiare l’id del bottone all’interno del gruppo, si utilizza il metodo setId(button, newid):

>>> buttongroup.setId(radio_button2, 200)
>>> buttongroup.id(radio_button2)
200
>>> button = buttongroup.button(200)
>>> button.text()
'France'

Se vogliamo recuperare il bottone settato a checked, utilizziamo il metodo checkedButton:

>>> buttongroup.checkedButton()  # Nessun bottone settato a checked
>>> radio_button1.setChecked(True)
>>> buttongroup.checkedButton()
<PyQt5.QtWidgets.QRadioButton object at 0x0343E120>

Signal

Quando un bottone appartenente ad un button-group viene cliccato, viene emesso un segnale buttonClicked.
Tale segnale emette anche l’id del bottone cliccato. E’ quindi possibile connettere tale segnale ad uno slot:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout
from PyQt5.QtWidgets import QRadioButton, QButtonGroup
from PyQt5.QtGui import QIcon
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QRadioButton Example")
        self.central_widget = FormWidget(self) 
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.button_group = QButtonGroup()

        self.radio_button1 = QRadioButton()
        self.radio_button1.setText("Italy")
        self.radio_button1.setIcon(QIcon("Italy.png"))
        self.radio_button1.setToolTip("Select Italy")
        self.button_group.addButton(self.radio_button1, 1)

        self.radio_button2 = QRadioButton("France", self)
        self.radio_button2.setIcon(QIcon("France.png"))
        self.button_group.addButton(self.radio_button2, 2)

        self.radio_button3 = QRadioButton("Spain", self)
        self.radio_button3.setIcon(QIcon("Spain.png"))
        self.button_group.addButton(self.radio_button3, 3)

        layout.addWidget(self.radio_button1, 0)
        layout.addWidget(self.radio_button2, 0)
        layout.addWidget(self.radio_button3, 0)
        self.setLayout(layout)

        self.button_group.buttonClicked[int].connect(self.on_radio_button)

    def on_radio_button(self, id):
        for button in self.button_group.buttons():
            if button is self.button_group.button(id):
                print("click on %s" % button.text())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Volendo forzare la scelta multipla sui radiobutton appartenenti allo stesso gruppo, si può utilizzare il metodo
setExclusive:

...
        self.button_group = QButtonGroup()
        self.button_group.setExclusive(False)
...

Nota:

Se escludessimo da gruppo uno dei tre radio button e il setExclusive sul gruppo fosse settato a True, questa caratteristica coinvolgerebbe solo i radio button apparrtenenti al gruppo stesso!
Ovvero sarà possibile cliccare anche il radio button escluso, che dovrà però essere collegato al proprio segnale:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout
from PyQt5.QtWidgets import QRadioButton, QButtonGroup
from PyQt5.QtGui import QIcon
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QRadioButton Example")
        self.central_widget = FormWidget(self) 
        self.setCentralWidget(self.central_widget)
        self.resize(300, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.button_group = QButtonGroup()
        self.button_group.setExclusive(True)

        radio_button1 = QRadioButton()
        radio_button1.setText("Italy")
        radio_button1.setIcon(QIcon("Italy.png"))
        radio_button1.setToolTip("Select Italy")
        self.button_group.addButton(radio_button1, 1)

        radio_button2 = QRadioButton("France", self)
        radio_button2.setIcon(QIcon("France.png"))
        self.button_group.addButton(radio_button2, 2)

        radio_button3 = QRadioButton("Spain", self)
        radio_button3.setIcon(QIcon("Spain.png"))
        # self.button_group.addButton(radio_button3, 3)  # Escluso dal gruppo

        layout.addWidget(radio_button1, 0)
        layout.addWidget(radio_button2, 0)
        layout.addWidget(radio_button3, 0)
        self.setLayout(layout)

        self.button_group.buttonClicked[int].connect(self.on_button_group)
        radio_button3.clicked.connect(
            lambda: self.on_radio_button_3(radio_button3))

    def on_button_group(self, id):
        for radio_button in self.button_group.buttons():
            if radio_button is self.button_group.button(id):
                print("[GROUP] click on %s" % radio_button.text())

    def on_radio_button_3(self, radio_button):
        print("[SINGLE] click on %s" % radio_button.text())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())
[GROUP] click on Italy
[GROUP] click on France
[SINGLE] click on Spain

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: QLineEdit

14 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

Le textbox sulle Qt sono le QLineEdit.
Il costruttore è quindi QLineEdit. Solitamente le textbox vengono create vuote, ma può essere utile prepopolarle con un testo.
I metodi per fare questo sono setText ed insert.
Il secondo metodo inserisce un testo in coda a quello esistente.
Per ottenere il testo contenuto nella textbox, come per la label, si usa il metodo text.

>>> from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QLineEdit
>>> app = QApplication([])
>>> label = QLineEdit()
>>> label.setText("first text")
>>> label.text()
'first text'
>>> label.insert(", second one")
>>> label.text()
'first text, second one'

Se vogliamo che la textbox in fase di creazione della UI, abbia già un testo predefinito, possiamo utilizzare il metodo
setPlaceholderText

Di default la textbox permette di scrivere 32767 caratteri. Se vogliamo limitare la quantità, possiamo utilizzare il metodo setMaxLenght

Se vogliamo che il contenuto della textbox non venga modificato, possiamo utilizzare il metodo setReadOnly

Vediamo un esempio pratico

from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QLineEdit
from PyQt5.QtWidgets import QMainWindow
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QButton Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(200, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)

        label = QLineEdit()
        label.setPlaceholderText("Write here your text")
        # label.setReadOnly(True)  # read-only
        layout.addWidget(label, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Completer

Il completer è un oggetto QCompleter che ci permette di utilizzare la funzione di auto-completamento in fase di scrittura all’interno di un widget come il QLineEdit.
Prende in ingresso una lista di stringhe che verranno proposte nel momento della scrittura all’interno della textbox:

...
from PyQt5.QtWidgets import QCompleter

...
        names = ['Andrea', 'Asia', 'Alessio', 'Sara']
        completer = QCompleter(names)
        label.setCompleter(completer)

...


Dimensioni e colore

Valgono tutti i metodi utilizzati negli esempi di QLabel

Selezione Testo

Ci sono alcuni metodi utili per selezionare ed estrapolare il testo presente nella textbox.
Con il metodo selectAll, seleziono tutto il testo e con il metodo selectedText ritorno il testo selezionato.
Per deselezionare il testo si utilizza il metodo deselect e per assicurarsi che ci sia o meno testo selezionato,
utilizziamo il metodo hasSelectedText:

>>> label.setText("first text")
>>> label.selectAll()
>>> label.hasSelectedText()
True
>>> label.deselect()
>>> label.hasSelectedText()
False

Per selezionare porzioni di testo, si utilizza il metodo setSelection, che prende in ingresso lo startindex della stringa e quanti caratteri selezionare:

>>> label.deselect()
>>> label.setSelection(6, 3)
>>> label.selectedText()
'tex'

Se vogliamo sapere quali sono gli indici della selezione, usiamo i metodi selectionStart e selectionEnd:

>>> label.selectionStart()
6
>>> label.selectionEnd()
9

Segnali

I Segnali pyqtSignal collegabili al widget QLineEdit sono:

selectionChanged: il segnale viene emesso quando il tipo di selezione effettuata sul testo, cambia:

>>> label.selectionChanged.connect(lambda : print("ALERT: Selection Changed!"))
<PyQt5.QtCore.QMetaObject.Connection object at 0x0373BE70>
>>> label.setSelection(6, 3)
>>> label.selectAll()
ALERT: Selection Changed!

cursorPositionChanged: il segnale viene emesso quando cambia la posizione del cursore all’interno della stringa:

>>> label1 = QLineEdit()
>>> label1.setText("a")
>>> label1.insert("b")
>>> label1.insert("c")
>>> label1.text()
'abc'
>>> label1.selectionChanged.connect(lambda : print("ALERT: Selection Changed!"))
<PyQt5.QtCore.QMetaObject.Connection object at 0x0373BDF0>
>>> label1.cursorPositionChanged.connect(lambda : print("ALERT: cursor position changed!"))
<PyQt5.QtCore.QMetaObject.Connection object at 0x0373BD70>
>>> label1.selectAll()
ALERT: Selection Changed!
>>> label1.setSelection(1, 1)
ALERT: Selection Changed!
ALERT: cursor position changed!
>>> label1.text()
'abc'
>>> label1.selectedText() #  position 1 length 1
'b'

textChanged: il segnale viene emesso quando il testo viene modificato.

Attenzione!
Se il cursore è stato modificato in precedenza, qualora si utilizzasse il metodo insert per aggiungere testo,
questi verrebbe aggiunto nell’ultima posizione del cursore (setSelection).

>>> label1.textChanged.connect(lambda : print("ALERT: text changed!"))
<PyQt5.QtCore.QMetaObject.Connection object at 0x0373BDB0>
>>> label1.insert("d")
ALERT: text changed!
ALERT: Selection Changed!
>>> label1.text()
'adc' 

Per spostare il cursore è possibile usare il metodo setCursorPosition:

>>> label1.setCursorPosition(0)
ALERT: Selection Changed!
ALERT: cursor position changed!
>>> label1.insert("1")
ALERT: text changed!
ALERT: cursor position changed!
>>> label1.setCursorPosition(len(label1.text()))
ALERT: cursor position changed!
>>> label1.insert("2")
ALERT: text changed!
ALERT: cursor position changed!
>>> label1.text()
'1adc2'

Gli altri segnali disponibili sono apprezzabili sulla UI

returnPressed: segnale emesso quando premiamo INVIO dopo avere editato il testo
editingFinished: simile a returnPressed, ma in questo caso incide anche la perdita del Focus sulla textbox.
inputRejected: segnale emesso quando si premono tasti non consentiti da eventuali validator,
o quando finiamo oltre il limite massimo consentito di caratteri
textEdited: segnale emesso quando il testo viene editato

...
        label = QLineEdit()
        label.setPlaceholderText("Write here your text")
        label.setMaxLength(10)

        label.returnPressed.connect(self.on_return_pressed)
        label.editingFinished.connect(self.on_editing_finished)
        label.inputRejected.connect(self.on_input_rejected)
        label.textEdited.connect(self.on_text_edited)
        layout.addWidget(label, 0)
        self.setLayout(layout)

    def on_return_pressed(self):
        print("INFO: You have pressed <Return Key>")

    def on_editing_finished(self):
        print("INFO: You have finished")

    def on_input_rejected(self):
        print("ERROR: Input rejected")

    def on_text_edited(self):
        print("INFO: You're editing text...")
...

Validation

La validazione può essere effettuata grazie agli oggetti QRegExp e QRegExpValidator.
Il primo costruttore prende come argomento il pattern regex da utilizzare.
Il secondo costruttore perende come argomenti l’oggetto QRegExp appena istanziato e il widget soggetto
a validazione.
Infine si setta tale oggetto QRegExpValidator al widget con il metodo setValidator.
Come si vede nell’esempio di seguito, quando verranno premuti i caratteri proibiti, non verrenno inseriti nella textbox:

...
from PyQt5.QtCore import QRegExp
from PyQt5.QtGui import QRegExpValidator
...

        label = QLineEdit()
        label.setPlaceholderText("Write here your text")
        label.setMaxLength(10)

        reg_ex = QRegExp("[a-z-A-Z_]+")
        label_validator = QRegExpValidator(reg_ex, label)
        label.setValidator(label_validator)

        label.inputRejected.connect(self.on_input_rejected)

        layout.addWidget(label, 0)
        self.setLayout(layout)

    def on_input_rejected(self):
        print("ERROR: Input rejected")
...

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: Signal e event

14 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

Signals and Slots

Le GUI applications sono event-driven, ovvero vengono continuamente generati eventi (ad esempio il click dello user su un pulsante) che vengono catturati dal mainloop dell’applicazione (metodo exec_()) e spediti agli oggetti di competenza.
In PyQt5 la comunicazione tra oggetti avviene tramite il meccanismo Signal/Slot.

Signal: viene emesso quando avviene un determinato evento;
Slot: è una qualsiasi callable Python che, collegata opportunamente ad un segnale, viene chiamata
ogni volta che tale segnale viene emesso;

Le caratteristiche del meccanismo Signal/Slot, sono le seguenti:

1. Un Signal può essere connesso a più Slot;
2. Un Signal può essere connesso ad un altro Signal;
3. Gli argomenti del Signal possono essere tutti i tipi di Python;
4. Uno Slot può essere connesso a più Signals;
5. La connessione può essere diretta (sincrona) o queued (Asincrona);
6. La connessione può essere effettuata tra threads differenti;
7. Il Signal può essere disconnesso

Per definire un nuovo segnale si utilizza il pyqtSignal factory che prende in ingresso i seguenti argomenti:

types: può essere ogni Python type o una stringa che sia una C++ type signature, ad es. “QString”;
name: il nome del segnale, se omesso si utilizza il nome dell’attributo di classe;
revision: la revisione del segnale che è esportata in QML;
arguments: la sequenza dei nomi degli argomenti del Signal, che vengono esportati in QML;

>>> from PyQt5.QtCore import QObject, pyqtSignal
>>> class MyQObject(QObject):
...     mysignal = pyqtSignal()
...     
>>> MyQObject.mysignal
<unbound PYQT_SIGNAL mysignal()>
>>> myobject = MyQObject()
>>> myobject.mysignal
<bound PYQT_SIGNAL mysignal of MyQObject object at 0x034D6990>

Nel momento in cui viene istanziato MyQobject, mysignal diventa un PYQT_SIGNAL bound mettendo a disposizione i tre metodi fondamentali: connect, disconnect, emit.

connect: connette il segnale allo slot;
disconnect: disconnette il segnale;
emit: emette il segnale;

Supponiamo di avere questa semplice classe:

from PyQt5.QtCore import QObject, pyqtSignal


class MyQObject(QObject):
    my_signal = pyqtSignal()

    def __init__(self):
        super(MyQObject, self).__init__()
        self.my_signal.connect(self.on_event)

    def my_event(self):
        print("Signal emitting...")
        self.my_signal.emit()

    def on_event(self):
        print("Signal received!")

Istanziamo l’oggetto e scateniamo l’evento:

>>> my_object = MyQObject()
>>> my_object.my_event()
Signal emitting...
Signal received!

Se disconnettiamo il segnale…

>>> my_object.my_signal.disconnect()
>>> my_object.my_event()
Signal emitting...

Non viene più ricevuto.

Signal con argomenti

Abbiamo detto che pyqtSignal prende come argomento type
Vediamo un paio di esempi con int e con una stringa

from PyQt5.QtCore import QObject, pyqtSignal


class MyQObject(QObject):
    my_signal = pyqtSignal(int)

    def __init__(self):
        super(MyQObject, self).__init__()
        self.my_signal.connect(self.on_event)

    def my_event(self):
        print("Signal emitting...")
        self.my_signal.emit(100)

    def on_event(self, value):
        print("Signal <%s> received!" % value)


if __name__ == "__main__":
    my_object = MyQObject()
    my_object.my_event()

Eseguendo questo codice otteniamo:

Signal emitting...
Signal <100> received!

Per utilizzare il type stringa, dobbiamo usare la C++ signature quindi:

from PyQt5.QtCore import QObject, pyqtSignal


class MyQObject(QObject):
    my_signal = pyqtSignal('QString')

    def __init__(self):
        super(MyQObject, self).__init__()
        self.my_signal.connect(self.on_event)

    def my_event(self):
        print("Signal emitting...")
        self.my_signal.emit("bancaldo")

    def on_event(self, value):
        print("Signal <%s> received!" % value)


if __name__ == "__main__":
    my_object = MyQObject()
    my_object.my_event()
Signal emitting...
Signal <bancaldo> received!

Metter in comunicazione due Oggetti differenti

Supponiamo di volere far giungere il segnale emesso da un primo oggetto, ad un secondo oggetto.
Il primo oggetto è già definito e, una volta emesso il segnale, lo riceve correttamente.
Creiamo quindi un secondo oggetto e, in esso, un metodo che prenda in ingresso il riferimento al primo oggetto, così da effettuare una seconda connessione al segnale emesso dal primo oggetto, ma su uno slot del secondo oggetto.
Per aggiungere un ulteriore slot al segnale, si utilizza il decoratore pyqtSlot come nel codice seguente:

from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot


class MyQObject(QObject):
    my_signal = pyqtSignal('QString')

    def __init__(self):
        super(MyQObject, self).__init__()
        self.my_signal.connect(self.on_event)

    def my_event(self):
        print("[FIRST OBJECT] Signal emitting...")
        self.my_signal.emit("bancaldo")

    def on_event(self, value):
        print("[FIRST OBJECT] Signal <%s> received!" % value)


class MySecondQObject(QObject):
    def __init__(self):
        super(MySecondQObject, self).__init__()

    def make_connection(self, external_object):
        external_object.my_signal.connect(self.get_external_value)

    @pyqtSlot('QString')
    def get_external_value(self, value):
        print("[SECOND OBJECT] Signal <%s> received!" % value)


if __name__ == "__main__":
    my_object = MyQObject()
    second_object = MySecondQObject()
    second_object.make_connection(my_object)
    my_object.my_event()

che una volta eseguito:

[FIRST OBJECT] Signal emitting...
[FIRST OBJECT] Signal <bancaldo> received!
[SECOND OBJECT] Signal <bancaldo> received!

In questo esempio, nel secondo oggetto, abbiamo utilizzato il decoratore pyqtSlot, per definire la callable
get_external_value. Il codice funzionerebbe anche senza l’uso del decoratore; le differenze tra usare o meno il
decoratore sono:

– che il metodo apparirà nella lista degli slot in caso di utilizzo di una interfaccia QML;
– uso di memoria ridotto;
– facilità di lettura del codice;

Sender

Qualora volessimo risalire a chi ha emesso il segnale, è possibile utilizzare il metodo sender di QObject sender() ritorna semplicemente l’oggetto originale che ha mandato il segnale.
Nel nostro codice basta modificare come segue:

...

class MyQObject(QObject):
    ...
    
    def __repr__(self):
        return "<%s>" % MyQObject.__name__


class MySecondQObject(QObject):
    ...

    @pyqtSlot('QString')
    def get_external_value(self, value):
        sender = self.sender()
        print("[SECOND OBJECT] Signal <%s> received from %s!" % (value, sender))
...

che si traduce in:

[FIRST OBJECT] Signal emitting...
[FIRST OBJECT] Signal <bancaldo> received!
[SECOND OBJECT] Signal <bancaldo> received from <MyQObject>!

Reimplementazione EventHandler predefiniti

E’ possibile sovrascrivere il comportamento degli EventHandler predefiniti in modo da personalizzarli.
Ad esempio vogliamo che nella nostra textbox venga rilevata la pressione del tasto ESC e si esca dall’applicazione.

Il codice è il seguente:

from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QLineEdit
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QLineEdit Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(200, 100)


class FormWidget(QWidget):

    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        self.main_win = parent
        layout = QBoxLayout(QBoxLayout.TopToBottom)

        label = QLineEdit()
        layout.addWidget(label, 0)
        self.setLayout(layout)

    def keyPressEvent(self, event):
        key = event.key()
        if key == Qt.Key_Escape:
            print("INFO: ESC-key pushed (%s). Exiting!" % key)
            self.main_win.close()
        else:
            print("INFO: KEY pushed (%s)" % key)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Quando premiamo il tasto ESC l’applicazione si chiude regolarmente.

Event object

Essendo Event un oggetto python, a seconda del tipo di evento ne possiamo sfruttare gli attributi.
Nel caso di reimplementazione dell’evento di movimento del mouse mouseMoveEvent, potremmo ad esempio mostrare in una label le coordinate del mouse.
Il codice è il seguente:

from PyQt5.QtWidgets import QWidget, QApplication, QGridLayout, QLabel, QFrame
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import Qt
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QLineEdit Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(200, 100)



class FormWidget(QWidget):

    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        self.main_win = parent
        grid = QGridLayout()

        self.label = QLabel("x: {0},  y: {1}".format(0, 0))
        grid.addWidget(self.label, 0, 0, Qt.AlignTop)
        self.setMouseTracking(True)
        self.setLayout(grid)

        self.label.setFrameShape(QFrame.Panel)
        self.label.setFrameShadow(QFrame.Sunken)
        self.label.setLineWidth(2)

    def mouseMoveEvent(self, event):
        x = event.x()
        y = event.y()
        text = "x: {0},  y: {1}".format(x, y)
        self.label.setText(text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Nota:
è fondamentale abilitare il setMouseTracking altrimenti non verrà tenuta traccia del mouse.


Esempio finale di segnale tra widget differenti

Niente di più che un piccolo esempio di comunicazione tra widgets:

import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QProgressBar
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QSlider, QDialog, QLabel, QGridLayout, QHBoxLayout
from PyQt5.QtCore import Qt, pyqtSignal


class Monitor(QDialog):
    def __init__(self):
        super(Monitor, self).__init__()
        left_label = QLabel('L channel', self)
        right_label = QLabel('R channel', self)

        self.l_bar = QProgressBar(self)
        self.l_bar.setMaximum(100)
        self.l_bar.setMinimum(0)

        self.r_bar = QProgressBar(self)
        self.r_bar.setMaximum(100)
        self.r_bar.setMinimum(0)

        layout = QGridLayout(self)

        # Adding the widgets
        layout.addWidget(left_label, 0, 0)
        layout.addWidget(right_label, 1, 0)
        layout.addWidget(self.l_bar, 0, 1)
        layout.addWidget(self.r_bar, 1, 1)

        self.setLayout(layout)
        self.setWindowTitle('Channel Monitor')
        self.show()

    def make_connection(self, channel_object):
        channel_object.changedValue.connect(self.get_channel_value)

    @pyqtSlot(int)
    def get_channel_value(self, value):
        sender = self.sender()
        if sender.name.lower() == "left":
            self.l_bar.setValue(value)
        else:
            self.r_bar.setValue(value)


class Channel(QDialog):

    changedValue = pyqtSignal(int)

    def __init__(self, name):
        super(Channel, self).__init__()
        self.name = name.lower()
        self.setWindowTitle("%s channel" % self.name)

        label = QLabel('volume', self)

        self.slider = QSlider(self)
        self.slider.setMinimum(0)
        self.slider.setMaximum(100)
        self.slider.setOrientation(Qt.Horizontal)

        layout = QHBoxLayout(self)

        layout.addWidget(label)
        layout.addWidget(self.slider)
        self.setLayout(layout)

        self.slider.valueChanged.connect(self.on_changed_value)
        self.show()

    def on_changed_value(self, value):
        self.changedValue.emit(value)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    monitor = Monitor()
    monitor.setGeometry(400, 300, 200, 100)
    left_channel = Channel("left")
    left_channel.setGeometry(400, 450, 200, 50)
    right_channel = Channel("right")
    right_channel.setGeometry(400, 550, 200, 50)
    monitor.make_connection(left_channel)
    monitor.make_connection(right_channel)
    sys.exit(app.exec_())

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: QLabel

13 Marzo 2019 Commenti chiusi

Torna all’indice degli appunti

Sulle Label non è che ci sia molto da dire.
Il costruttore è QLabel(text).
In fase di creazione il testo può anche essere omesso e poi aggiunto in seguito con il metodo setText.
Con il metodo text si ottiene il testo della label.

>>> from PyQt5.QtWidgets import QApplication, QLabel
>>> app = QApplication([])
>>> label = QLabel()
>>> label.setText("Some text")
>>> label.text()
'Some text'

I parametri da passare al costruttore sono: il testo da mostrare e il parent widget.

Dimensione widget

E’ possibile modificare la geometria della label (e di molti widgets) con il metodo setGeometry,
che prende in ingresso un oggetto QRect(left_point_x, left_point_y, right_point_x, right_point_y):

from PyQt5.QtWidgets import QWidget, QApplication, QLabel, QFrame
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QRect
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QButton Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(300, 200)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        label1 = QLabel("setFixedSize", self)
        label1.setGeometry(QRect(50, 100, 200, 20))
        self.set_border(label1)

    @staticmethod
    def set_border(label):
        label.setFrameShape(QFrame.Panel)
        label.setFrameShadow(QFrame.Sunken)
        label.setLineWidth(2)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Nota:

Le seguenti linee di codice servono semplicemente a dare un contorno alle label per distinguere più chiaramente le differenze negli assegnamenti.

    @staticmethod
    def set_border(label):
        label.setFrameShape(QFrame.Panel)
        label.setFrameShadow(QFrame.Sunken)
        label.setLineWidth(2)

Nota:

Quando si inserisce il widget all’interno di un QBoxLayout, questi segue le policy di quest’ultimo.

...
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        label1 = QLabel("setFixedSize", self)
        label1.setGeometry(QRect(50, 100, 200, 20))
        self.set_border(label1)
        layout.addWidget(label1)
        self.setLayout(layout)
...

E’ possibile definire delle dimensioni fisse con il metodosetFixedSize(size_x, size_y):

...
        label1 = QLabel("setFixedSize", self)
        label1.setFixedSize(70, 30)
        self.set_border(label1)  # Add border and shadow
        layout.addWidget(label1, 0)
        self.setLayout(layout)
...

E’ possibile anche definire le misure minime fisse in caso di ridimensionamento della finestra:

setMinimumSize: blocchiamo entrambe le dimensioni del widget in caso di riduzione della finestra che lo ospita;
setMinimumHeight: blocchiamo le dimensioni del widget in Y, in caso di riduzione della finestra;
setMinWidth: blocchiamo le dimensioni del widget in X, in caso di riduzione della finestra;

L’efficacia dei comandi la si può notare nel momento in cui si riduce la finestra principale, poichè le misure fissate dei
widget, diventano bloccanti!

...
        layout = QBoxLayout(QBoxLayout.TopToBottom)

        label1 = QLabel("setMinimumHeight", self)
        label1.setMinimumHeight(100)
        self.set_border(label1)
        layout.addWidget(label1, 0)

        label2 = QLabel("setMinimumWidth", self)
        label2.setMinimumWidth(150)
        self.set_border(label2)
        layout.addWidget(label2, 0)

        label3 = QLabel("setMinimumSize", self)
        label3.setMinimumSize(150, 150)
        self.set_border(label3)
        layout.addWidget(label3, 0)

        self.setLayout(layout)
...

I metodi per fissare le dimensioni dei widget nei valori massimi sono invece:

setMaximumSize: blocchiamo entrambe le dimensioni del widget in caso di ingrandimento del frame che lo ospita;
setMaximumHeight: blocchiamo le dimensioni del widget in Y, in caso di ingrandimento della finestra;
setMaxWidth: blocchiamo le dimensioni del widget in X, in caso di ingrandimento della finestra;

...
        label1 = QLabel("setMaximumHeight", self)
        label1.setMaximumHeight(100)
        self.set_border(label1)
        layout.addWidget(label1, 0)

        label2 = QLabel("setMaximumWidth", self)
        label2.setMaximumWidth(150)
        self.set_border(label2)
        layout.addWidget(label2, 0)

        label3 = QLabel("setMaximumSize", self)
        label3.setMaximumSize(150, 150)
        self.set_border(label3)
        layout.addWidget(label3, 0)

        self.setLayout(layout)
...

Allineamento testo orizzontale

E’ gestito dalle costanti:

Qt.AlignLeft: allineamento testo a sinistra
Qt.AlignHCenter: testo al centro della label
Qt.AlignRight: allineamento testo a destra
Qt.AlignJustify: testo giustificato

Allineamento testo verticale

E’ gestito dalle costanti:

Qt.AlignTop: allineamento testo in alto
Qt.AlignVCenter: testo al centro dell’asse verticale
Qt.AlignBottom: allineamento testo in basso
Qt.AlignBaseLine: testo giustificato

from PyQt5.QtWidgets import QWidget, QApplication, QBoxLayout, QLabel, QFrame
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import Qt
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("QButton Example")
        self.central_widget = FormWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(200, 100)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.setLayout(layout)

        for text, align in [
            ("Align Left", Qt.AlignLeft), ("Align H Center", Qt.AlignHCenter),
            ("Align Right", Qt.AlignRight), ("Align Justify", Qt.AlignJustify),
            ("Align Top", Qt.AlignTop), ("Align V Center", Qt.AlignVCenter),
            ("Align Bottom", Qt.AlignBottom), ("Align BaseLine", Qt.AlignBaseline),
             ]:
            label = QLabel(text, self)
            label.setMinimumHeight(50)
            label.setAlignment(align)

            label.setFrameShape(QFrame.Panel)
            label.setFrameShadow(QFrame.Sunken)
            label.setLineWidth(2)
            layout.addWidget(label, 0)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Vediamo visivamente le differenze

E’ ovviamente possibile unire più allineamenti tramite pipe, ad es. centrare il testo sia orizzontalmente che
verticalmente:

...
        label = QLabel("Align center H and V ", self)
        label.setMinimumHeight(50)
        label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        label.setFrameShape(QFrame.Panel)
        label.setFrameShadow(QFrame.Sunken)
        label.setLineWidth(2)
        layout.addWidget(label, 0)
...

Colore

Come per gli altri widget è ovviamente possibile dare una differente colorazione alla label utilizzando QColor e QPalette:

...
from PyQt5.QtGui import QColor
...
        label = QLabel("Some text", self)
        label.setMinimumHeight(50)
        # Color
        palette = label.palette()
        background = label.backgroundRole()
        foreground = label.foregroundRole()
        palette.setColor(background, QColor('Yellow'))
        palette.setColor(foreground, QColor('Red'))
        label.setPalette(palette)
        label.setAutoFillBackground(True)
        
        layout.addWidget(label, 0)
        self.setLayout(layout)
...

Modificare Font

Per modificare il font di una label utilizziamo QFont.
Questo costruttore prende in ingresso gli argomenti nome del font, dimensione, e tipo di font (grassetto, ecc..).
Una volta creato un oggetto font si associa alla label con il metodo setFont:

...
from PyQt5.QtGui import QFont
...
        label = QLabel("some text", self)
        font = QFont("Lucida", 14, QFont.Bold)
        label.setFont(font)

        layout.addWidget(label, 0)
        self.setLayout(layout)
...

Immagini

Per inserire un’immagine nella label, si utilizza il costruttore QMixMap.

...
from PyQt5.QtGui import QPixmap

...
        label = QLabel(self)
        pixmap = QPixmap('qt.jpg')
        label.setPixmap(pixmap)
        layout.addWidget(label, 0)
        self.setLayout(layout)
...

External Link

Vediamo come associare un link ad una label e connettere un segnale che apra tale link con il browser.
Il pyqtSignal da utilizzare è linkActivated:

...
import subprocess


...
        label = QLabel('<a href="www.google.com">Find something</a>')
        label.linkActivated.connect(self.on_activate)

        layout.addWidget(label, 0)
        self.setLayout(layout)

    def on_activate(self, link):
        print("INFO: link %s opening..." % link)
        subprocess.call(['C:\\Program Files\\Mozilla Firefox\\firefox.exe',
                         link])
...

Una volta cliccato sul testo, si aprirà il browser alla pagina desiderata.

Testo selezionabile

Si utilizza semplicemente il metodo setTextInteractionFlags(Qt.TextSelectableByMouse), che permette di selezionare con il mouse il testo della lable e copiarlo.

...
from PyQt5.QtCore import Qt

...
        label = QLabel('<a href="www.google.com">Find something</a>')
        label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        layout.addWidget(label, 0)
        self.setLayout(layout)
...

Testo su più righe

Se vogliamo che, durante la riduzione della finestra principale, il testo della label si disponga automaticamente su più righe, a seconda dell’esigenza, possiamo utilizzare il metodo setWordWrap(True).

...
        label = QLabel('This is a long long long text')
        label.setWordWrap(True)
...

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,

PyQt5: appunti

13 Marzo 2019 Commenti chiusi
Categorie:PyQt5, python Tag: ,