Home > PyQt5, python > PyQt5: QListWidget

PyQt5: QListWidget

3 Aprile 2019

Torna all’indice degli appunti

QListWidget

Il ListWidget permette di visualizzare una lista di elementi.
Questi elementi possono essere semplici stringhe di testo o oggetti QListWidgetItem, che permettono ad esempio di avere associata un’icona.

I metodi principali sono:

addItem(item):
aggiunge l’elemento al listwidget. Questo elemento può essere anche un QListWidgetItem!

>>> from PyQt5.QtWidgets import (QMainWindow, QApplication, QGridLayout, QWidget,
...                              QListWidget)
>>> from PyQt5.QtWidgets import QListWidgetItem
>>> from PyQt5.QtGui import QIcon
>>> app = QApplication([])
>>> lw = QListWidget()
>>> lw.addItem("Simple string 1")
>>> item = QListWidgetItem(QIcon("Italy.png"), "Italy")
>>> lw.addItem(item)
>>> lw.count()
2

insertItem(row, item):
aggiunge l’elemento alla riga specificata row.

>>> lw.insertItem(1, "Simple string 2")
>>> for index in range(lw.count()):
...     print("[%s]" % index, lw.item(index).text())
...     
[0] Simple string 1
[1] Simple string 2
[2] Italy

count:
conta gli elementi del list-widget

current Item:
per settare il current item, si utilizza il metodo setCurrentItem(item) dove item è l’elemento
sul quale vogliamo spostare il focus.
Per sapere quale è attualmente il current item, si utilizza il metodo currentItem:

>>> item
<PyQt5.QtWidgets.QListWidgetItem object at 0x0398D260>
>>> lw.setCurrentItem(item)
>>> lw.currentItem()
<PyQt5.QtWidgets.QListWidgetItem object at 0x0398D260>

current Row:

Stessi concetti del metodo precedente, ma si sposta il focus sull’elemento desiderato, tramite row.
Il metodo è appunto setCurrentRow(row). Per ottenere invece la current row, si utilizza il metodo currentRow:

>>> lw.currentRow()
2
>>> lw.setCurrentRow(1)
>>> lw.currentRow()
1

Sorting:

E’ possibile impostare l’ordinamento degli elementi tramite il metodo sortItems(order).
Il parametro order può avere i seguenti due valori:
Qt.AscendingOrder: ordine ascendente;
Qt.DescendingOrder: ordine discendente;

>>> from PyQt5.QtCore import Qt
>>> for index in range(lw.count()):
...     print("[%s]" % index, lw.item(index).text())
...     
[0] Simple string 1
[1] Simple string 2
[2] Italy
>>> lw.sortItems(Qt.DescendingOrder)
>>> for index in range(lw.count()):
...     print("[%s]" % index, lw.item(index).text())
...     
[0] Simple string 2
[1] Simple string 1
[2] Italy

L’ordinamento degli elementi del list-widget può essere attivato/disattivato con il metodo setSortingEnabled(bool)
e per conoscere lo stato di questo flag, si utilizza il metodo isSortingEnabled(bool).

remove item:
Per Rimuovere l’item dalla list-widget si usa il metodo removeItemWidget(item). Questo metodo rimuove l’item dal list-widget, ma non lo cancella di fatto. Per rimuoverlo definitivamente bisogna usare takeItem(row) che ritorna l’elemento eliminato.

>>> item_to_remove = lw.item(2)
>>> lw.removeItemWidget(item_to_remove)
>>> for index in range(lw.count()):
...     print("[%s]" % index, lw.item(index).text())
...     
[0] Simple string 2
[1] Simple string 1
[2] Italy
>>> lw.takeItem(2)
<PyQt5.QtWidgets.QListWidgetItem object at 0x0398D260>
>>> for index in range(lw.count()):
...     print("[%s]" % index, lw.item(index).text())
...     
[0] Simple string 2
[1] Simple string 1

SEGNALI:

i segnali del list-widget sono i seguenti:

currentItemChanged: emesso quando cambia il current item;
currentRowChanged(int): emesso quando cambia la current row;
currentTextChanged: currentText è il text-data del current item, di conseguenza questo segnale viene emesso
ogni qualvolta cambia il current item;
itemActivated: segnale emesso quando un item viene attivato tramite doppio-click o premendo ;
itemChanged: segnale emesso quando l’item cambia i propri dati, più avanti faremo un accenno all’editing dell’item;
itemClicked: segnale emesso al click sull’item;
itemDoubleClicked: segnale emesso al doppio-click su un item;
itemEntered: segnale emesso quando il mouse passa sull’item, è necessario attivare il mouseTracking
per il list-widget con il metodo setMouseTracking;
itemPressed: segnale emesso quando sull’item viene premuto un botton del mouse;
itemSelectionChanged: segnale emesso quando cambia la selezione;

Ecco un esempio con tutti i segnali; decommentare il segnale da monitorare:

import sys
from PyQt5.QtWidgets import (QMainWindow, QApplication, QVBoxLayout, QWidget,
                             QListWidget, QListWidgetItem, QPushButton, QLabel)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("QListWidget Example")
        self.central_widget = FrameWidget(self)
        self.setCentralWidget(self.central_widget)
        self.resize(200, 200)


class FrameWidget(QWidget):
    def __init__(self, parent=None):
        super(FrameWidget, self).__init__(parent)
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.text_label = QLabel()
        self.list_widget = QListWidget()
        self.list_widget.setMouseTracking(True)
        for index, name in enumerate(["Italy", "France", "Spain"]):
            item = QListWidgetItem(QIcon("%s.png" % name), name)
            self.list_widget.insertItem(index, item)
        button_asc = QPushButton("Ascend")
        button_desc = QPushButton("Descend")
        layout.addWidget(self.text_label)
        layout.addWidget(self.list_widget)
        layout.addWidget(button_asc)
        layout.addWidget(button_desc)

        button_asc.clicked.connect(self.on_sorted)
        button_desc.clicked.connect(self.on_sorted)
        # self.list_widget.clicked.connect(self.on_list_widget)
        # self.list_widget.currentItemChanged.connect(self.on_current_i_changed)
        # self.list_widget.currentRowChanged[int].connect(self.on_row_changed)
        # self.list_widget.currentTextChanged.connect(self.on_text_changed)
        # self.list_widget.itemActivated.connect(self.on_item_activated)
        # self.list_widget.itemChanged.connect(self.on_item_changed)
        # self.list_widget.itemClicked.connect(self.on_item_clicked)
        # self.list_widget.itemDoubleClicked.connect(self.on_item_double_clicked)
        # self.list_widget.itemEntered.connect(self.on_item_entered)
        # self.list_widget.itemPressed.connect(self.on_item_pressed)
        # self.list_widget.itemSelectionChanged.connect(self.on_sel_changed)

    def on_current_i_changed(self):
        item = self.list_widget.currentItem()
        print("[SIG] Current item changed to <%s>" % item.text())

    def on_row_changed(self, row):
        item = self.list_widget.item(row)
        print("[SIG] Current item changed to <{}[{}]>".format(item.text(), row))

    def on_text_changed(self):
        item = self.list_widget.currentItem()
        print("[SIG] Current text-data changed to <%s>" % item.text())

    def on_item_activated(self):
        item = self.list_widget.currentItem()
        print("[SIG] Activated item <%s>" % item.text())

    def on_item_changed(self):
        item = self.list_widget.currentItem()
        print("[SIG] item changed to <%s>" % item.text())

    def on_item_clicked(self):
        item = self.list_widget.currentItem()
        print("[SIG] item <%s> clicked" % item.text())

    def on_item_double_clicked(self):
        item = self.list_widget.currentItem()
        print("[SIG] item <%s> double-clicked" % item.text())

    def on_item_entered(self):
        item = self.list_widget.currentItem()
        print("[SIG] Mouse on ListWidget: current item is <%s>" % item.text())

    def on_item_pressed(self):
        item = self.list_widget.currentItem()
        print("[SIG] item <%s> pressed" % item.text())

    def on_sel_changed(self):
        item = self.list_widget.currentItem()
        print("[SIG] item <%s> selected" % item.text())

    def on_sorted(self):
        button = self.sender()
        if button.text().lower() == "ascend":
            self.list_widget.sortItems(Qt.AscendingOrder)
        else:
            self.list_widget.sortItems(Qt.DescendingOrder)

    def on_list_widget(self):
        item = self.list_widget.currentItem()
        row = self.list_widget.currentRow()
        self.text_label.setText("{} selected (row {})".format(item.text(), row))


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

Editing Item

Merita un approfondimento l’editing di un item.
Per poter editare i dati di un item e modificarli (causando l’emissione del segnale itemChanged, dobbiamo
utilizzare i metodi openPersistentEditor(item) e closePersistentEditor(item), del list-widget.
Ad esempio possiamo fare in modo che al doppio click su un item, si apra l’editor; per questo possiamo utilizzare il
segnale itamActivated, mentre a dati modificati, possiamo chiudere l’editor sfruttando il segnale
itemChanged:

...

class FrameWidget(QWidget):
    def __init__(self, parent=None):
        ...
        self.list_widget.itemActivated.connect(self.on_item_activated)
        self.list_widget.itemChanged.connect(self.on_item_changed)
        ...

    def on_item_activated(self):
        item = self.list_widget.currentItem()
        print("[SIG] Activated item <%s>" % item.text())
        self.list_widget.openPersistentEditor(item) # qui apriamo l'editor

    def on_item_changed(self):
        item = self.list_widget.currentItem()
        print("[SIG] item changed to <%s>" % item.text())
        self.list_widget.closePersistentEditor(item) # qui chiudiamo l'editor
    ...

Nota:
Cosa succede se edito un item ma premo invio senza modificarne i dati?
L’editor rimane attivo sull’item, poichè lo chiudiamo solo in caso di modifica dei dati.

Per chiuderlo anche in caso di NON-modifica, possiamo ad esempio intercettare l’evento KeyPress e sovrascriverlo in modo che,
alla pressione del tasto , l’editor venga chiuso:

...

class FrameWidget(QWidget):
    def __init__(self, parent=None):
        ...
        self.list_widget.itemActivated.connect(self.on_item_activated)
        self.list_widget.itemChanged.connect(self.on_item_changed)
        ...

    def on_item_activated(self):
        item = self.list_widget.currentItem()
        print("[SIG] Activated item <%s>" % item.text())
        self.list_widget.openPersistentEditor(item) # qui apriamo l'editor

    def on_item_changed(self):
        item = self.list_widget.currentItem()
        print("[SIG] item changed to <%s>" % item.text())
        self.list_widget.closePersistentEditor(item) # qui chiudiamo l'editor

    def keyPressEvent(self, event):  # sovrascrivo l'evento KeyPressEvent
        print("[EVENT] Key Return pressed")
        if event.key() == Qt.Key_Return:
            item = self.list_widget.currentItem()
            self.list_widget.closePersistentEditor(item)
    ...

Ora, anche non modificando i deti dell’item, il persistent editor si chiuderà.

Torna all’indice degli appunti

Categorie:PyQt5, python Tag: ,
I commenti sono chiusi.