qt - QListView/QListWidget con elementos personalizados y widgets de elementos personalizados
pyqt qitemdelegate (5)
Estoy escribiendo una aplicación PyQt y estoy teniendo problemas para crear una vista de lista personalizada. Me gustaría que la lista contenga widgets arbitrarios (un widget personalizado en particular). ¿Cómo voy a hacer esto?
Parece que la alternativa sería crear una tabla o vista de cuadrícula envuelta en una barra de desplazamiento. Sin embargo, me gustaría poder aprovechar el enfoque de modelo / vista, así como la compatibilidad de anidamiento (vista de árbol) con el control incorporado.
Para aclarar, los widgets personalizados son interactivos (contienen botones), por lo que la solución requiere más que pintar un widget.
Creo que debes subclasificar QItemDelegate .
QItemDelegate se puede usar para proporcionar funciones de visualización personalizadas y widgets de editor para vistas de elementos basadas en las subclases QAbstractItemView. El uso de un delegado para este fin permite que los mecanismos de visualización y edición se personalicen y desarrollen independientemente del modelo y la vista.
Este código está tomado de los ejemplos de Qt, la aplicación de torrents.
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);
}
};
Básicamente, como puede ver, verifica si la columna que se va a pintar es de un índice específico, si es así, pinta una barra de progreso. Creo que podría modificarlo un poco y en lugar de usar QStyleOption podría usar su propio widget.
editar: no se olvide de configurar su delegado de elementos con su QListView utilizando setItemDelegate .
Mientras investigaba su pregunta me encontré con this hilo, que explica cómo pintar un widget personalizado usando un QItemDelegate, creo que tiene toda la información que pueda necesitar.
De otra manera, puede agregar elementos personalizados en listWidget. para este propósito, necesitas agregar una nueva clase. asígnele el nombre que quiera, simplemente le doy "myList", espero que sepa cómo agregar nuevos elementos en el proyecto. :)
luego, en este nuevo marco, agregue su control tantas como desee. como QLabels, QlineEdit, etc.
luego, en la clase principal, tienes que agregar una lista de nombres de widget de lista o como quieras y escribir el siguiente código
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);
este último también puede cambiar las propiedades de los elementos usando señales / ranuras.
espero que te ayude ...!
La ayuda dice que:
void QTableWidget::setCellWidget (int row, int column, QWidget * widget)
Establece el widget dado para mostrarse en la celda en la fila y columna dadas, pasando la propiedad del widget a la tabla. Si el widget de celda A se reemplaza con el widget de celda B, se eliminará el widget de celda A.
Y hay análogos a este método en la mayoría de los descendientes QAbstractItemView.
Tienes que subclase Q *** Delegar solo cuando quieras que el widget del editor aparezca en Ver solo cuando toques EditTrigger, luego desaparecer y dejar que delegar represente el elemento view de alguna manera.
Si corrijo, quería ver el control en la vista de elementos todo el tiempo y poder presionar los controles sin la necesidad de ingresar al modo de edición y esperar mientras el delegado crea el editor y establecer su estado, por lo que no necesita hacer un delegado específico, solo establecer widget en el elemento de la vista.
La respuesta de @Idan funciona bien, pero publicaré un ejemplo más simple que se me ocurrió. Este delegado de elementos simplemente dibuja un rectángulo negro para cada elemento.
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);
}
};
Y luego solo tiene que configurarlo para el widget de la lista:
ui->listWidget->setItemDelegate(new ItemDelegate(ui->listWidget));
Si entiendo tu pregunta correctamente, quieres algo como esto:
donde cada fila contiene un conjunto personalizado de widgets.
Para lograr esto, dos pasos.
Implementa la fila con un widget personalizado
Primero, implemente un widget personalizado que contenga todos los widgets necesarios por fila de la lista.
Aquí estoy usando una etiqueta y dos botones por fila, con un diseño horizontal.
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)
Agregar filas a la lista
Instanciar múltiples filas es simplemente una cuestión de crear un elemento de widget y asociar el widget personalizado a la fila del elemento.
# 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)