QListView/QListWidget avec des éléments personnalisés et des widgets d'éléments personnalisés
j'écris une application PyQt et j'ai de la difficulté à créer une vue de liste personnalisée. J'aimerais que la liste contienne des widgets arbitraires (un widget personnalisé en particulier). Comment pourrais-je aller à ce sujet?
il semble que l'alternative serait de créer une vue de table ou de grille enveloppée dans une barre de défilement. Cependant, j'aimerais pouvoir profiter de l'approche modèle/vue ainsi que du support de nichage (vue sur les arbres) de la poignée intégrée.
pour clarifier, la coutume les widgets sont interactifs (contiennent des boutons), la solution nécessite donc plus que de peindre un widget.
5 réponses
je pense que vous devez à la sous-classe QItemDelegate.
QItemDelegate peut être utilisé pour fournir fonctions d'affichage personnalisées et éditeur widgets pour les vues d'item basés sur Sous-classes qabstractemview. À l'aide d'un délégué à cette fin permet au mécanismes d'affichage et d'édition à être personnalisé et développé indépendamment à partir du modèle et la vue.
ce code est tiré des exemples de Qt, le torrent application.
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);
}
};
Fondamentalement, comme vous pouvez le voir, il vérifie si la colonne à peindre est d'un indice, si si il peint une barre de progression. Je pense que vous pourriez le modifier un peu et au lieu d'utiliser une option QStyleOption vous pourriez utiliser votre propre widget.
edit: n'oubliez pas de configurer votre délégué d'item avec votre QListView en utilisant setItemDelegate.
en enquêtant sur votre question, je suis tombé sur fil, qui élabore comment peindre un widget personnalisé en utilisant un QItemDelegate, je crois qu'il a toutes les informations dont vous pourriez avoir besoin.
la réponse de@Idan fonctionne bien, mais je vais poster un exemple plus simple que j'ai inventé. Ce délégué d'élément dessine juste un rectangle noir pour chaque élément.
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);
}
};
Et puis vous avez juste besoin de mettre pour la liste de widget:
ui->listWidget->setItemDelegate(new ItemDelegate(ui->listWidget));
Aider dit, que:
void QTableWidget::setCellWidget (int row, int column, QWidget * widget)
Définit le widget est affiché dans la cellule dans la ligne et de la colonne, en passant la propriété du widget à la table. Si le widget A est remplacé par le widget B, le widget A sera supprimé.
et il y a des analogues à cette méthode dans la plupart des descendants de Qabstractemview.
Vous devez Sous-classe Q***Delegate seulement quand vous voulez que le widget d'éditeur apparaisse dans la vue seulement quand vous appuyez sur EditTrigger, puis disparaître et laisser délégué rendre l'affichage élément d'une certaine façon.
si je corrige, vous vouliez voir le contrôle dans la vue d'item tout le temps et être capable de frapper les contrôles sans avoir besoin d'entrer en mode édition et d'attendre pendant que delegate crée editor et définit son état, donc vous n'avez pas besoin de faire delegate spécifique, il suffit de définir widget dans l'item de la vue.
si je comprends bien votre question, vous voulez quelque chose comme ceci:
où chaque ligne contient un ensemble de widgets.
pour y parvenir, deux étapes.
implémenter la ligne avec un Widget personnalisé
tout d'abord, implémenter un widget personnalisé qui contient tous les widgets nécessaires par ligne de liste.
ici j'utilise une étiquette et deux boutons par rangée, avec un horizontal disposition.
class MyCustomWidget(QWidget):
def __init__(self, name, parent=None):
super(MyCustomWidget, self).__init__(parent)
self.row = QHBoxLayout()
self.row.addWidget(QLabel(name))
self.row.addWidget(QPushButton("view"))
self.row.addWidget(QPushButton("select"))
self.setLayout(self.row)
Ajouter des lignes à la liste
Instanciating multiple rows est alors juste une question de créer un élément widget, et d'associer le widget personnalisé à la ligne de l'élément.
# Create the list
mylist = QListWidget()
# Add to list a new item (item is simply an entry in your list)
item = QListWidgetItem(mylist)
mylist.addItem(item)
# Instanciate a custom widget
row = MyCustomWidget()
item.setSizeHint(row.minimumSizeHint())
# Associate the custom widget to the list entry
mylist.setItemWidget(item, row)
une autre façon d'ajouter des éléments personnalisés dans listWidget. pour ce faire, vous devez ajouter une nouvelle classe. nommez-le comme vous voulez je lui donne juste "myList" j'espère que vous savez comment ajouter de nouveaux éléments dans le projet. :)
ensuite, dans ce nouveau cadre ajouter votre contrôle autant que tu veux. comme QLineEdit, QLineEdit etc
alors dans la classe principale u doivent ajouter une liste de noms listWidget ou comme vous voulez et l'écrire le code suivant
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);
ce dernier u peut aussi changer les propriétés des items à l'aide de signaux/slots ..
j'espère que sa vous aider ..!