Рисовать виджет прямо в QListView с помощью QStyledItemDelegate :: paint ()

После нескольких часов работы я могу нарисовать виджет на QListView, Тем не менее, картина делается через QPixmap, Появляется виджет, и я вижу индикатор выполнения. Тем не менее, это немного «неровной» (из-за использования QPixmap). Можно ли рисовать напрямую как обычный виджет? Это мой вопрос.

Вот что я делаю:

void FileQueueItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QPaintDevice* original_pdev_ptr = painter->device();

FileQueueListItem* itemWidget = reinterpret_cast<FileQueueListItem*>(index.data(Qt::UserRole).value<void*>());

itemWidget->setGeometry(option.rect);
painter->end();

QPixmap pixmap(itemWidget->size());
if (option.state & QStyle::State_Selected)
pixmap.fill(option.palette.highlight().color());
else
pixmap.fill(option.palette.background().color());
itemWidget->render(&pixmap,QPoint(),QRegion(),QWidget::RenderFlag::DrawChildren);

painter->begin(original_pdev_ptr);
painter->drawPixmap(option.rect, pixmap);
}

Я узнал, как сделать то, что я сделал с подсказками Вот. Там картина делается прямо на QListViewЭто то, чего я хочу достичь. Что я делаю не так для следующей попытки не работать:

void FileQueueItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
std::cout<<"Painting..."<<std::endl;
QPaintDevice* original_pdev_ptr = painter->device();

FileQueueListItem* itemWidget = reinterpret_cast<FileQueueListItem*>(index.data(Qt::UserRole).value<void*>());

itemWidget->setGeometry(option.rect);
painter->end();

if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
else
painter->fillRect(option.rect, option.palette.background());

itemWidget->render(painter->device(),
QPoint(option.rect.x(), option.rect.y()),
QRegion(0, 0, option.rect.width(), option.rect.height()),
QWidget::RenderFlag::DrawChildren);
painter->begin(original_pdev_ptr);
}

Список просто остается пустым, и ничего не происходит. Хотя выбор можно увидеть, но виджет не отображается.

2

Решение

Давайте проясним несколько вещей:

  1. Вы не должны создавать виджеты и помещать их в модель. Для этого есть очень веская причина. Виджеты участвуют в Цикл событий Qt, Это означает, что слишком большое количество виджетов значительно замедлит вашу программу.

  2. Виджеты — это не просто набор элементов управления (кажется, как вы их видите). Они принимают участие в цикле событий, поэтому у вас не должно быть виджета, который является частью модели данных.

  3. Если вы используете многопоточную программу, и наша модель отделена от представления, управление памятью станет кошмаром. Qt никогда не потерпит попыток создать или удалить какие-либо виджеты из других потоков (что имеет смысл, поскольку отсоединение потоков от цикла обработки событий обычно не является потокобезопасным).

Учитывая эту информацию, как правильно делать то, что вы пытаетесь сделать? К сожалению, единственный правильный способ — нарисовать элементы управления самостоятельно. Если ваш виджет прост, это легко сделать. Если ваш виджет сложный, вам понадобится много математики для расчета позиций каждого виджета.

в Пример Qt Torrent, Вы увидите, как нарисован индикатор выполнения. Все, что вам нужно сделать, чтобы нарисовать свои элементы управления, это рассчитать положение и использовать rect Переменная-член в качестве содержащего прямоугольника элементов управления, а затем нарисовать их (конечно, после установки их значений). Функция paint() имеет option.rect параметр в нем, который является прямоугольником всего элемента. Все, что вам нужно сделать, это использовать некоторую математику, чтобы вычислить позиции внутри этого прямоугольника для каждого виджета.

PS: НИКОГДА НЕ ИСПОЛЬЗУЙТЕ АБСОЛЮТНЫЕ ЗНАЧЕНИЯ ДЛЯ ПОЗИЦИЙ. Вы никогда не поймете это правильно, особенно для разных точек на дюйм.

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]