Визуализация QWidget в методе paint () QWidgetDelegate для QListView - PullRequest
12 голосов
/ 23 июня 2011

У меня возникли проблемы с реализацией пользовательского рендеринга виджетов в QListView.В настоящее время у меня есть QListView, отображающий мою пользовательскую модель с именем PlayQueue, основанную на QAbstractListModel.

. Это нормально работает с простым текстом, но теперь я хотел бы отобразить собственный виджет для каждого элемента.Поэтому я вложил в класс QStyledItemDelegate для реализации метода paint следующим образом:

void QueueableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
    if (option.state & QStyle::State_Selected)
        painter->fillRect(option.rect, option.palette.highlight());
    QWidget *widget = new QPushButton("bonjour");
    widget->render(painter);
}

Фон выделения правильно отображается, но виджет не отображается.Я попробовал с простыми QPainter командами, как в примерах Qt, и это работает нормально:

void QueueableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
    if (option.state & QStyle::State_Selected)
        painter->fillRect(option.rect, option.palette.highlight());
    if (option.state & QStyle::State_Selected)
        painter->setPen(option.palette.highlightedText().color());
    painter->setFont(QFont("Arial", 10));
    painter->drawText(option.rect, Qt::AlignCenter, "Custom drawing");
}

Так что я попробовал некоторые изменения, такие как:

  • Изменение QStyledItemDelegate на QItemDelegate
  • Добавление painter->save() и painter->restore() при рендеринге
  • Установка геометрии виджета на доступный размер

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

Я использую Qt 4.7.3 для GCC в Ubuntu 11.04.

Ответы [ 3 ]

15 голосов
/ 24 сентября 2013

Просто для завершения всей картины: далее можно найти код для управления QWidget как элемента QListView с использованием делегатов.

Я наконец-то узнал, как заставить его работать в подклассе QStyledItemDelegate, используя его метод paint (...).

Это кажется более эффективным для производительности, чем предыдущее решение, но это утверждение нужно проверить =) путем исследования того, что setIndexWidget () делает с созданным QWidget.

Итак, вот код:

class PackageListItemWidget: public QWidget

.....

class PackageListItemDelegate: public QStyledItemDelegate

.....

void PackageListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{

// here we have active painter provided by caller

// by the way - we can't use painter->save() and painter->restore()
// methods cause we have to call painter->end() method before painting
// the QWidget, and painter->end() method deletes
// the saved parameters of painter

// we have to save paint device of the provided painter to restore the painter
// after drawing QWidget
QPaintDevice* original_pdev_ptr = painter->device();

// example of simple drawing (selection) before widget
if (option.state & QStyle::State_Selected)
    painter->fillRect(option.rect, option.palette.highlight());

// creating local QWidget (that's why i think it should be fasted, cause we 
// don't touch the heap and don't deal with a QWidget except painting)
PackageListItemWidget item_widget;

// Setting some parameters for widget for example
    // spec. params
item_widget.SetPackageName(index.data(Qt::DisplayRole).toString());     
    // geometry
item_widget.setGeometry(option.rect);

// here we have to finish the painting of provided painter, cause
//     1) QWidget::render(QPainter *,...) doesn't work with provided external painter 
//          and we have to use QWidget::render(QPaintDevice *,...)
//          which creates its own painter
//     2) two painters can't work with the same QPaintDevice at the same time
painter->end(); 

// rendering of QWidget itself
item_widget.render(painter->device(), QPoint(option.rect.x(), option.rect.y()), QRegion(0, 0, option.rect.width(), option.rect.height()), QWidget::RenderFlag::DrawChildren);   

// starting (in fact just continuing) painting with external painter, provided
// by caller
painter->begin(original_pdev_ptr);  

// example of simple painting after widget
painter->drawEllipse(0,0, 10,10);   
};
3 голосов
/ 01 июля 2011

Хорошо, я наконец понял, как делать то, что хотел. Вот что я сделал:

  1. Отбросьте класс делегата
  2. Вызовите QListView::setIndexWidget() в методе data() моей модели, чтобы установить виджет
  3. Убедитесь, что виджет уже отсутствует при установке, отметив QListView::indexWidget()
  4. Обработка роли Qt::SizeHintRole для возврата подсказки о размере виджета
  5. Вернуть пустой QVariant для роли Qt::DisplayRole

Таким образом, мои пользовательские виджеты отображаются в QListView, и они загружаются должным образом (поэтому я использовал шаблон модель / представление). Но я не вижу, как я могу выгрузить их, когда не отображается, ну, это еще одна проблема.

0 голосов
/ 23 июня 2011

Здесь пример для вас. Кажется, вам нужно использовать QStylePainter, но это только для рисования, насколько я понимаю, это не действует как настоящая кнопка.

...