QListView/QListWidget с пользовательскими элементами и виджетами пользовательских элементов
Я пишу приложение PyQt и у меня возникли проблемы с созданием пользовательского представления списка. Я хотел бы, чтобы список содержал произвольные виджеты (в частности, один пользовательский виджет). Как бы я пошел по этому поводу?
Похоже, что альтернативой было бы создать представление таблицы или сетки, завернутое в полосу прокрутки. Тем не менее, я хотел бы иметь возможность воспользоваться преимуществами подхода модель / представление, а также вложенности (древовидного представления) поддержки встроенного дескриптора.
Чтобы уточнить, пользовательские виджеты являются интерактивными (содержат кнопки), поэтому решение требует больше, чем рисование виджета.
5 ответов
Я думаю, что вам нужно создать подкласс 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 вы можете использовать свой собственный виджет.
редактировать: не забудьте настроить делегата вашего элемента с вашим QListView, используя setItemDelegate.
Разбирая ваш вопрос, я наткнулся на эту тему, в которой рассказывается, как рисовать пользовательский виджет с помощью QItemDelegate, я считаю, что он содержит всю необходимую вам информацию.
Если я правильно понимаю ваш вопрос, вы хотите что-то вроде этого:
где каждая строка содержит собственный набор виджетов.
Для этого нужно сделать два шага.
Реализуйте строку с помощью собственного виджета
Во-первых, реализуйте пользовательский виджет, который содержит все виджеты, необходимые для каждой строки списка.
Здесь я использую метку и две кнопки в строке, с горизонтальным расположением.
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)
Ответ @ Идана работает хорошо, но я опубликую более простой пример, который придумал. Этот делегат элемента просто рисует черный прямоугольник для каждого элемента.
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));
Ассист говорит, что:
void QTableWidget::setCellWidget (int row, int column, QWidget * widget)
Устанавливает отображение указанного виджета в ячейке в заданной строке и столбце, передавая владение виджетом таблице. Если виджет ячейки A заменяется на виджет ячейки B, виджет ячейки A будет удален.
И есть аналоги этого метода в большинстве потомков QAbstractItemView.
Вы должны создать подкласс Q***Delegate, только когда вы хотите, чтобы виджет редактора появлялся в View только тогда, когда вы нажимаете EditTrigger, затем исчезаете и позволяете делегату каким-то образом визуализировать элемент представления.
Если я исправляю, вы хотите видеть элемент управления в представлении элемента все время и иметь возможность нажимать элементы управления без необходимости входить в режим редактирования и ждать, пока делегат создаст редактор и установить его состояние, поэтому вам не нужно создавать определенный делегат, просто установить виджет в элемент представления.
Другим способом вы можете добавить пользовательские элементы в listWidget. Для этого вам нужно добавить новый класс. Назовите его так, как вы хотите. Я просто даю ему "myList", надеюсь, вы знаете, как добавлять новые элементы в проект.:)
затем в этом новом кадре добавьте свой контроль столько, сколько хотите. как QLabels,QlineEdit и т. д.
Затем в главном классе вы должны добавить список имен 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);
последний вы также можете изменить свойства элементов, используя сигналы / слоты.
надеюсь, это поможет вам..!