QListView/QListWidget с настраиваемыми элементами и пользовательскими виджетами элементов
Я пишу приложение PyQt, и у меня возникли проблемы с созданием пользовательского списка. Я хотел бы, чтобы список содержал произвольные виджеты (в частности, один пользовательский виджет). Как я могу это сделать?
Кажется, что альтернативой было бы создание таблицы или сетки, завернутых в полосу прокрутки. Тем не менее, я хотел бы иметь возможность использовать подход модели/представления, а также вложение (tree-view) поддержки встроенного дескриптора.
Чтобы уточнить, пользовательские виджеты являются интерактивными (содержат кнопки), поэтому для решения требуется больше, чем рисование виджета.
Ответы
Ответ 1
Я думаю, вам нужно подкласс QItemDelegate.
QItemDelegate может использоваться для предоставления пользовательские функции отображения и редактор виджеты для просмотра позиций на основе Подкласс QAbstractItemView. Используя делегат для этой цели позволяет отображения и редактирования индивидуально и независимо от модели и вида.
Этот код взят из примеров Qt, торрент-приложения.
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);
}
};
В основном, как вы можете видеть, он проверяет, является ли столбец для окрашивания конкретным индексом, если он рисует индикатор выполнения. Я думаю, вы могли бы немного подкорректировать его, и вместо использования QStyleOption вы могли бы использовать свой собственный виджет.
edit: не забудьте настроить делегат вашего объекта с помощью QListView, используя setItemDelegate.
При исследовании вашего вопроса я наткнулся на этот поток, в котором подробно описывается, как рисовать пользовательский виджет с помощью QItemDelegate, я считаю, имеет всю необходимую информацию.
Ответ 2
Ответ @Idan работает хорошо, но я опубликую более простой пример, который я придумал. Этот элемент делегата просто рисует черный прямоугольник для каждого элемента.
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);
}
};
И тогда вам просто нужно установить его для виджета списка:
ui->listWidget->setItemDelegate(new ItemDelegate(ui->listWidget));
Ответ 3
Если я правильно понимаю ваш вопрос, вы хотите что-то вроде этого:
![enter image description here]()
где каждая строка содержит собственный набор виджетов.
Для этого нужно сделать два шага.
Реализуйте строку с помощью собственного виджета
Во-первых, реализуйте пользовательский виджет, который содержит все виджеты, необходимые для каждой строки списка.
Здесь я использую метку и две кнопки в строке, с горизонтальным расположением.
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)
Добавить строки в список
Создание нескольких строк - это всего лишь вопрос создания элемента виджета и его привязки к строке элемента.
# 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)
Ответ 4
Помощник говорит, что:
void QTableWidget::setCellWidget (int row, int column, QWidget * widget)
Устанавливает данный виджет, который будет отображаться в ячейке в данной строке и столбце, передавая владение виджетам в таблицу. Если виджет ячейки A заменен виджлетом ячейки B, виджет ячейки A будет удален.
И есть аналоги этого метода у большинства потомков QAbstractItemView.
Вы должны подклассифицировать Q *** Делегировать только тогда, когда вы хотите, чтобы виджет редактора появлялся в режиме просмотра только при нажатии EditTrigger, затем исчезает и позволяет делегату каким-либо образом визуализировать элемент вида.
Если я исправлю, вы хотите постоянно контролировать элемент управления в элементе управления и иметь возможность удалять элементы управления без необходимости входа в режим редактирования и ждать, пока делегат создает редактор и устанавливает его состояние, поэтому вам не нужно указывать конкретные делегат, просто установите виджет в элемент представления.
Ответ 5
другой способ добавления пользовательских элементов в listWidget. для этого вам нужно добавить новый класс. назовите его так, как хотите, я просто дам его "myList". Надеюсь, вы знаете, как добавлять новые элементы в проект.:)
то в этом новом фрейме добавьте свой элемент управления столько, сколько хотите. как QLabels, QlineEdit и т.д.
то в основном классе u вам нужно добавить список имен listWidget или как хотите, и напишите следующий код
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);
last u также может изменять свойства элементов с помощью сигналов/слотов.
надеюсь, что это поможет вам..!