2009-06-04 3 views
28

Sto scrivendo un'applicazione PyQt e sto avendo qualche problema nella creazione di una visualizzazione elenco personalizzata. Mi piacerebbe che l'elenco contenga widget arbitrari (in particolare un widget personalizzato). Come andrei su questo?QListView/QListWidget con elementi personalizzati e widget articoli personalizzati

Sembra che l'alternativa sarebbe quella di creare una vista tabella o griglia avvolta in una barra di scorrimento. Tuttavia, mi piacerebbe essere in grado di sfruttare l'approccio modello/vista e il supporto di nidificazione (visualizzazione ad albero) per l'handle integrato.

Per chiarire, i widget personalizzati sono interattivi (contengono pulsanti), quindi la soluzione richiede più della pittura di un widget.

risposta

28

Penso che sia necessario sottoclasse QItemDelegate.

QItemDelegate può essere utilizzato per fornire funzioni di visualizzazione personalizzato e redattore widget per le viste elemento basato su sottoclassi QAbstractItemView. L'utilizzo di un delegato per questo scopo consente ai meccanismi di visualizzazione e modifica di essere personalizzati e sviluppati indipendentemente da dal modello e dalla vista.

Questo codice è preso dagli esempi di Qt, l'applicazione torrent.

class TorrentViewDelegate : public QItemDelegate 
{ 
    Q_OBJECT 
public: 
    inline TorrentViewDelegate(MainWindow *mainWindow) : QItemDelegate(mainWindow) {} 

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option, 
         const QModelIndex &index) const 
    { 
     if (index.column() != 2) { 
      QItemDelegate::paint(painter, option, index); 
      return; 
     } 

     // Set up a QStyleOptionProgressBar to precisely mimic the 
     // environment of a progress bar. 
     QStyleOptionProgressBar progressBarOption; 
     progressBarOption.state = QStyle::State_Enabled; 
     progressBarOption.direction = QApplication::layoutDirection(); 
     progressBarOption.rect = option.rect; 
     progressBarOption.fontMetrics = QApplication::fontMetrics(); 
     progressBarOption.minimum = 0; 
     progressBarOption.maximum = 100; 
     progressBarOption.textAlignment = Qt::AlignCenter; 
     progressBarOption.textVisible = true; 

     // Set the progress and text values of the style option. 
     int progress = qobject_cast<MainWindow *>(parent())->clientForRow(index.row())->progress(); 
     progressBarOption.progress = progress < 0 ? 0 : progress; 
     progressBarOption.text = QString().sprintf("%d%%", progressBarOption.progress); 

     // Draw the progress bar onto the view. 
     QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); 
    } 
}; 

In sostanza, come si può vedere controlla se la colonna da verniciare è di un indice specifico, se così dipinge una barra di avanzamento. Penso che potresti modificarlo un po 'e invece di usare QStyleOption puoi usare il tuo widget.

modifica: non dimenticare di configurare l'elemento delegato con QListView utilizzando setItemDelegate.

Mentre analizzo la tua domanda, mi sono imbattuto nel thread this, che elabora come dipingere un widget personalizzato utilizzando un QItemDelegate, credo che abbia tutte le informazioni che potrebbero essere necessarie.

+0

Grazie per il post, mi guarderò in esso più domani. Potresti approfondire come andrei a sostituire il disegno QStyleOption con un widget personalizzato? –

+0

beh, è ​​solo questione di dipingere il tuo widget con QPainter fornito nel metodo di pittura di QItemDelegate. Ho modificato il mio post per includere un link utile. –

+0

Bene, posso ottenere qualcosa di grezzo lavorando con questa tecnica. Ma il problema è rappresentato dall'aspetto "widget arbitrari": ho un widget composto che contiene pulsanti, ecc., Che sono interattivi, quindi devono essere collocati fisicamente nella lista o l'utente non è in grado di fare clic su di essi. correggimi se sbaglio, ma questo disegnerà solo un widget inattivo. –

2

Assist dice che:

void QTableWidget::setCellWidget (int row, int column, QWidget * widget) 

Imposta il dato widget da visualizzare nella cella della riga e la colonna data, passando la proprietà del widget al tavolo. Se il widget cella A viene sostituito con il widget cella B, il widget cella A verrà cancellato.

E ci sono analoghi a questo metodo nella maggior parte dei discendenti di QAbstractItemView.

Devi sottoclasse Q *** Delega solo quando vuoi che il widget dell'editor appaia in Visualizza solo quando premi EditTrigger, quindi svanisci e consenti al delegato di rendere l'elemento della vista in qualche modo.

Se correggo, si voleva vedere il controllo in vista elementi tutto il tempo e in grado di colpire i controlli senza la necessità di accedere alla modalità di modifica e attendi che il delegato crea editore e impostare il suo stato, quindi non è necessario fare delegato specifico, basta impostare il widget nell'elemento della vista.

+0

Sfortunatamente tali funzioni sono disponibili solo per 'QTableWidget',' QTreeWidget' e 'QListWidget'. Non sono disponibili quando si utilizza una vista con un modello personalizzato. –

+1

Da [docs] (http://doc.qt.io/qt-5/qlistwidget.html#setItemWidget) "Questa funzione deve essere utilizzata solo per visualizzare il contenuto statico al posto di un elemento del widget di elenco. per visualizzare il contenuto dinamico personalizzato o implementare un widget di editor personalizzato, utilizzare invece QListView e sottoclasse QItemDelegate. " – Trilarion

1

un altro modo per aggiungere articoli personalizzati in listWidget. per questo scopo è necessario aggiungere una nuova classe. chiamalo come vuoi io gli do semplicemente "myList" spero tu sappia come aggiungere nuovi elementi nel progetto. :)

quindi in questo nuovo frame aggiungi il tuo controllo quanti ne vuoi.come QLabel, QlineEdit ecc

poi nella classe principale u deve aggiungere un elenco di nomi listWidget o come si desidera e il scrivere il codice seguente

MyList *myList = new MyList(); 
QListWidgetItem *item = new QListWidgetItem(); 
ui->list->insertItem(ui->list->size().height(),item); 
item->setSizeHint(QSize(50,30)); 
ui->list->setItemWidget(item,myList); 

quest'ultimo u può anche cambiare articoli proprietà utilizzando segnali/slot.

spero che ti aiuti ..!

+0

Chi cancella myList sull'oggetto destroy? Non riesco a vedere alcun codice relativo alla proprietà in questo esempio. – Allex

+0

Beh, io sono sviluppatore Java e Java prendono cure di garbage collection :) che è stata la mia poca conoscenza di C++ –

3

@ La risposta di Idan funziona bene, ma pubblicherò un esempio più semplice che ho trovato. Questo elemento delegato disegna semplicemente un rettangolo nero per ogni oggetto.

class ItemDelegate : public QItemDelegate 
{ 
public: 
    explicit ItemDelegate(QObject *parent = 0) : QItemDelegate(parent) {} 
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 
    { 
     painter->fillRect(option.rect.adjusted(1, 1, -1, -1), Qt::SolidPattern); 
    } 
}; 

E poi solo bisogno di impostarlo per il widget lista:

ui->listWidget->setItemDelegate(new ItemDelegate(ui->listWidget));