QListView / QListWidget с пользовательскими элементами и виджетами пользовательских элементов - PullRequest
29 голосов
/ 04 июня 2009

Я пишу приложение PyQt, и у меня возникли проблемы с созданием пользовательского представления списка. Я хотел бы, чтобы список содержал произвольные виджеты (в частности, один пользовательский виджет). Как бы я пошел по этому поводу?

Похоже, что альтернативой было бы создание представления таблицы или сетки, обернутого в полосу прокрутки. Тем не менее, я хотел бы иметь возможность воспользоваться преимуществами подхода модель / представление, а также того, что вложенность (древовидная структура) поддерживает встроенную ручку.

Чтобы уточнить, пользовательские виджеты являются интерактивными (содержат кнопки), поэтому для решения требуется нечто большее, чем рисование виджета.

Ответы [ 5 ]

28 голосов
/ 04 июня 2009

Я думаю, вам нужно создать подкласс 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, я считаю, что он содержит всю необходимую вам информацию.

4 голосов
/ 14 марта 2018

Если я правильно понимаю ваш вопрос, вы хотите что-то вроде этого:

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)
3 голосов
/ 12 марта 2014

@ Ответ Идана работает хорошо, но я опубликую более простой пример, который придумал. Этот делегат элемента просто рисует черный прямоугольник для каждого элемента.

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));
2 голосов
/ 19 марта 2010

Ассист говорит, что:

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

Устанавливает отображение указанного виджета в ячейке в заданной строке и столбце, передавая владение виджетом таблице. Если виджет ячейки A будет заменен на виджет ячейки B, виджет ячейки A будет удален.

И есть аналоги этого метода у большинства потомков QAbstractItemView.

Вы должны подкласс Q. Делегировать только тогда, когда вы хотите, чтобы виджет редактора появлялся в представлении, только когда вы нажимаете EditTrigger, затем исчезаете и позволяете делегату каким-то образом визуализировать элемент представления.

Если я исправлю, вы хотели бы видеть элемент управления в представлении элемента все время и иметь возможность нажимать элементы управления без необходимости входить в режим редактирования и ждать, пока делегат создаст редактор и установит его состояние, поэтому вам не нужно задавать конкретные параметры. делегат, просто установите виджет в элемент представления.

1 голос
/ 01 апреля 2013

еще один способ добавить пользовательские элементы в listWidget. Для этого вам нужно добавить новый класс. Назовите его так, как вы хотите. Я просто даю ему «myList», надеюсь, вы знаете, как добавлять новые элементы в проект :)

тогда в этом новом кадре добавьте свой контроль столько, сколько хотите. как QLabels, QlineEdit и т. д.

тогда в основном классе вы должны добавить список имен виджетов или, как вы хотите, и написать следующий код

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);

Последний вы также можете изменить свойства элементов, используя сигналы / слоты.

надеюсь, это поможет вам ..!

...