QListView показывает только один элемент в представлении

Я использую каркас Model View Delegate, используемый Qt для отображения списков объектов с пользовательскими «представлениями» или макетами.

Фон:

Мне нужно, чтобы в списке был выбран флаг страны, название страны, название города и дополнительная звездочка рейтинга «премиум», которую может выбрать пользователь.

Для этого я использую следующие компоненты:

  • Модель — это QStandardItemModel, увидеть доктор страница, которая содержит все данные QListView и проблемы взаимодействия, страница документа

  • Делегат — для рисования / отображения данных в пользовательском стиле я использую QStyledItemDelegate, увидеть доктор стр.

  • Представление — Для представления, простой QListView будет достаточно, так как это список из одного столбца, содержащий коллекцию объектов с пользовательским макетом.

Учебники и справка:

Используя следующий учебник (ы),
1. а messageviewer приложение, показывающее, как реализовать подробный model-delegate-view концепция в соответствии с,
2. основы простого меню сообщений Система для смартфонов Nokia, я смог с относительной легкостью создать желаемый макет для моего QListView,

Проблема:

Я обязан добавить QStandardItem товары для моей модели, которые будут добавлены на мой взгляд. Я делаю это, и делегат подтверждает, что каждый пункт paint переопределить метод.

Однако во время выполнения QListView отображает только 1 элемент. Но я могу использовать клавиши со стрелками вверх / вниз, чтобы выбрать другие элементы в списке.

Пожалуйста, смотрите код ниже:

Настройка MVC (делегат):

mainwindow.h

//...
QStandardItemModel *modelServers;
ServerDelegate* serverDelegate;
//...

mainwindow.cpp

modelServers = new QStandardItemModel(0);
serverDelegate = new ServerDelegate(0);

ui->listServers->setModel(modelServers);
ui->listServers->setItemDelegate(serverDelegate);

и добавление предметов (QStandardItems) перечислить:

for (int i = 0; i < someList->length(); ++i) {
Server server = someList->value(i);
QStandardItem *item = new QStandardItem();
item->setData(server.getCountryName,         item->setData(QPixmap("", "PNG"), ServerDelegate::DataRole::CountryFlag);
item->setData(server.getCountry(), ServerDelegate::DataRole::CountryText);
item->setData(server.getCity(), ServerDelegate::DataRole::CityText);
item->setData(i, ServerDelegate::ListIndex);
//...
modelServer->appendRow(item)
}

Наконец, список отображает данные, однако список заполнен только элементами, но только первый содержит видимый текст и изображения.

примечание: при прокрутке вниз виден только верхний элемент, например, см. изображения ниже.

например

Начальный загруженный список:

введите описание изображения здесь

Одна прокрутка вниз

введите описание изображения здесь

Выбор элемента без текста / изображений:

введите описание изображения здесь

Дополнительный код ниже:

ServerDelegate класс, обрабатывающий пользовательский макет

ServerDelegate.h

#ifndef SERVERDELEGATE_H
#define SERVERDELEGATE_H

#include <QApplication>
#include <QtGui>
#include <QStyledItemDelegate>
#include <QtWidgets>
#include <qglobal.h>

#include "global.h"
class ServerDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
ServerDelegate(QStyledItemDelegate* parent = 0);
virtual ~ServerDelegate();

enum DataRole{
CountryText = Qt::UserRole + 100,
CityText = Qt::UserRole+101,
CountryFlag = Qt::UserRole+102,
SideIconFlag = Qt::UserRole+103,
ListIndex = Qt::UserRole+105
};

void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;

private:
QFont fontCountry, fontCity;
};

#endif // SERVERDELEGATE_H

ServerDelegate.cpp

#include "serverdelegate.h"
ServerDelegate::ServerDelegate(QStyledItemDelegate *parent)
: QStyledItemDelegate(parent)
{
fontCountry = QApplication::font();
fontCountry.setBold(true);
fontCountry.setPointSize(QApplication::font().pointSize() + 3);

fontCity = QApplication::font();
fontCity.setItalic(true);
fontCity.setPointSize(QApplication::font().pointSize() - 1);
}

ServerDelegate::~ServerDelegate(){
}

QSize ServerDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const{
Q_UNUSED(index)
QSize totalCountrySize = QPixmap("","").size();
QSize totalSideIcon = QPixmap(":/res/images/premium", "PNG").size();

QFontMetrics fmCountry(fontCountry);
QFontMetrics fmCity(fontCity);

int fontHeight = (2 * 2) + (2 * 5) + fmCountry.height() + fmCity.height();
int iconHeight = (2 * 2) + (totalCountrySize.height() > totalSideIcon.height() ? totalCountrySize.height() : totalSideIcon.height());
int height = (fontHeight > iconHeight) ? fontHeight : iconHeight;

int width = option.rect.width();
QSize size = QSize(width, height);

return size;
}

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

QRect rec = option.rect;

painter->save();
painter->setClipRect(rec);

QString countryText = index.data(DataRole::CountryText).toString();
QString cityText = index.data(DataRole::CityText).toString();
QPixmap countryFlag = QPixmap(qvariant_cast<QPixmap>(index.data(DataRole::CountryFlag)));
QPixmap sideIcon = qvariant_cast<QPixmap>(index.data(DataRole::SideIconFlag));

// Get a rectangle by size x, y.
// With cooridinates [0,0]; [x,0]; [x,y]; [0,y]
QRect topLine = option.rect,
bottomLine = option.rect;

// create top 'seperator' of X px's width, green in color;
topLine.setTop(0);
topLine.setLeft(0);
topLine.setRight(option.rect.width());
topLine.setBottom(2); // 1px down

painter->setPen(QColor(116, 183, 151));
painter->fillRect(topLine, QColor(116, 183, 151));
painter->drawRect(topLine);

// create bottom 'seperator' of X px's width, green in color;
bottomLine.setTop(option.rect.height() - 2);
bottomLine.setLeft(0);
bottomLine.setRight(option.rect.width());
bottomLine.setBottom(option.rect.height()); // 1px down

painter->setPen(QColor(116, 183, 151));
painter->fillRect(bottomLine, QColor(116, 183, 151));
painter->drawRect(bottomLine);

// create background rectangle
QRect content(0, topLine.bottom(), option.rect.width(), bottomLine.top());

painter->setPen(QColor(116, 183, 151));
painter->fillRect(content, QColor(116, 183, 151));
painter->drawRect(content);

// create content rectangles from content container.

QRect rectCountryFlag = content,
rectSideIcon = content;

//    create country icon rectangle
QSize countryFlagSize = countryFlag.size();
int cFPos = (rectCountryFlag.height() / 2) - (countryFlagSize.height() / 2) - 8;
rectCountryFlag.setTop(cFPos);
rectCountryFlag.setBottom(content.height() - cFPos);
rectCountryFlag.setLeft(20 - 8);
rectCountryFlag.setRight(20 + 16 + countryFlagSize.width());

painter->drawPixmap(rectCountryFlag, countryFlag);

//    create side icon rectangle
QSize sideIconSize = sideIcon.size();
int siPos = (rectSideIcon.height() / 2) - (sideIconSize.height() / 2) - 4;
rectSideIcon.setTop(siPos);
rectSideIcon.setBottom(content.height() - siPos);
rectSideIcon.setLeft(rec.width() - (10 + 8 + sideIconSize.width()));
rectSideIcon.setRight(rec.width() - 10);

painter->drawPixmap(rectSideIcon, sideIcon);

const QRect textContent(rectCountryFlag.right() + 5 + 20, content.top() + 5,
rectSideIcon.left() - 5, content.bottom() - 5);

// create country text rectangle

QRect rectCountryText = content,
rectCityText = content;

rectCountryText.setLeft(textContent.left());
rectCountryText.setTop(textContent.top());
rectCountryText.setRight(textContent.right());
rectCountryText.setBottom(qRound(textContent.height() * 0.6) - 5);

painter->setPen(QColor(26, 26, 26));
painter->setFont(fontCountry);
painter->drawText(rectCountryText, countryText);

// create city text rectangle

rectCityText.setLeft(textContent.left() + ( 2 * 5));
rectCityText.setTop(rectCountryText.bottom() + 5);
rectCityText.setRight(textContent.right());
rectCityText.setBottom(textContent.height());

painter->setPen(QColor(77, 77, 77));
painter->setFont(fontCity);
painter->drawText(rectCityText, cityText);

// restore painter
painter->restore();
}

1

Решение

Прежде чем я отправлю свой ответ, большой привет scopchanov за его помощь и предоставленный пример, также намекающий на тот факт, что смещение происходит при каждом обращении к paintчто-то, о чем я блаженно не подозревал.

Объясненная проблема:

Значения смещения предоставлены option.rect та же QSize который возвращается sizeHint метод. В моем случае мое беспокойство было связано с y offset который имел значение 56,

Мое понимание

Используя концепцию итеративного значения смещения, я изменил свой код (который ранее имел желаемый результат), где я предположил, что paint Метод был взят из происхождения [0,0]где в действительности я должен был учесть смещение, то есть мне не было предоставлено контейнер который был размещен на следующем QListView местоположение элемента, вместо этого мне дали местоположение следующего QListViewНачальная точка предмета, и мне нужно построить предмет оттуда.

Решение:

В моем случае, у меня был желаемый макет элемента, но элементы были нарисованы друг над другом, из-за происхождения [0,0], в результате чего single item эффект. После изменения нескольких значений и построения иерархия зависимости В некотором роде мне был представлен список предметов, имеющих желаемое расположение.

Код

Обновлен ServerDelegate.cpp

#include "serverdelegate.h"
ServerDelegate::ServerDelegate(QStyledItemDelegate *parent)
: QStyledItemDelegate(parent)
{
fontCountry = QApplication::font();
fontCountry.setBold(true);
fontCountry.setPointSize(QApplication::font().pointSize() + 3);

fontCity = QApplication::font();
fontCity.setItalic(true);
fontCity.setPointSize(QApplication::font().pointSize() - 1);
}

ServerDelegate::~ServerDelegate(){
}

QSize ServerDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const{
Q_UNUSED(index)
QSize totalCountrySize = Global::getCountryFlagFromCache(index.data(DataRole::CountryText).toString()).size();
QSize totalSideIcon = QPixmap(":/res/images/premium", "PNG").size();

QFontMetrics fmCountry(fontCountry);
QFontMetrics fmCity(fontCity);

int fontHeight = (2 * AppGlobal::Style_List_Seperator_Width) + (2 * AppGlobal::Style_List_Text_Item_Margin) + fmCountry.height() + fmCity.height();
int iconHeight = (2 * AppGlobal::Style_List_Seperator_Width) + (totalCountrySize.height() > totalSideIcon.height() ? totalCountrySize.height() : totalSideIcon.height());
int height = (fontHeight > iconHeight) ? fontHeight : iconHeight;

int width = option.rect.width();
QSize size = QSize(width, height);

return size;
}

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

QFontMetrics fmCountry(fontCountry);
QFontMetrics fmCity(fontCity);

QRect rec = option.rect;

painter->save();
painter->setClipRect(rec);

QString countryText = index.data(DataRole::CountryText).toString();
QString cityText = index.data(DataRole::CityText).toString();
QPixmap countryFlag = QPixmap(qvariant_cast<QPixmap>(index.data(DataRole::CountryFlag)));
QPixmap sideIcon = qvariant_cast<QPixmap>(index.data(DataRole::SideIconFlag));

// Get a rectangle by size x, y.
// With cooridinates [0,0]; [x,0]; [x,y]; [0,y]
QRect topLine = option.rect,
bottomLine = option.rect;

// create top 'seperator' of X px's width, green in color;
topLine.setTop(rec.top());
topLine.setLeft(rec.left());
topLine.setRight(rec.right());
topLine.setBottom(rec.top() + AppGlobal::Style_List_Seperator_Width); // 1px down

painter->setPen(AppGlobal::Style_List_Seperator_Color);
painter->fillRect(topLine, AppGlobal::Style_List_Seperator_Color);
painter->drawRect(topLine);

// create bottom 'seperator' of X px's width, green in color;
bottomLine.setTop(rec.bottom() - AppGlobal::Style_List_Seperator_Width);
bottomLine.setLeft(rec.left());
bottomLine.setRight(rec.right());
bottomLine.setBottom(rec.bottom()); // 1px down

painter->setPen(AppGlobal::Style_List_Seperator_Color);
painter->fillRect(bottomLine, AppGlobal::Style_List_Seperator_Color);
painter->drawRect(bottomLine);

// create background rectangle
QRect content(rec.left(), topLine.bottom(), (rec.right() - rec.left()), (bottomLine.top() - topLine.bottom()));

painter->setPen(AppGlobal::Style_List_Background_Color);
painter->fillRect(content, ((option.state & QStyle::State_MouseOver) ? AppGlobal::Style_List_Hover_Color : AppGlobal::Style_List_Background_Color ));
painter->drawRect(content);

// create content rectangles from content container.

QRect rectCountryFlag = content,
rectSideIcon = content;

//    create country icon rectangle
QSize countryFlagSize = countryFlag.size();
int cFPos = ((rectCountryFlag.bottom() - rectCountryFlag.top()) / 2) - (countryFlagSize.height() / 2) - 8;
rectCountryFlag.setTop(rectCountryFlag.top() + cFPos);
rectCountryFlag.setBottom(content.bottom() - cFPos);
rectCountryFlag.setLeft(AppGlobal::Style_List_Left_Item_Margin - 8);
rectCountryFlag.setRight(AppGlobal::Style_List_Left_Item_Margin + 16 + countryFlagSize.width());

painter->drawPixmap(rectCountryFlag, countryFlag);

//    create side icon rectangle
QSize sideIconSize = sideIcon.size();
int siPos = ((rectSideIcon.bottom() - rectSideIcon.top()) / 2) - (sideIconSize.height() / 2) - 4;
rectSideIcon.setTop(rectSideIcon.top() + siPos);
rectSideIcon.setBottom(content.bottom() - siPos);
rectSideIcon.setLeft(rec.width() - (AppGlobal::Style_List_Right_Item_Margin + 8 + sideIconSize.width()));
rectSideIcon.setRight(rec.width() - AppGlobal::Style_List_Right_Item_Margin);

painter->drawPixmap(rectSideIcon, sideIcon);

int textContentLeft = rectCountryFlag.right() + AppGlobal::Style_List_Text_Item_Margin + AppGlobal::Style_List_Left_Item_Margin,
textContentTop = content.top() + AppGlobal::Style_List_Text_Item_Margin;

const QRect textContent( textContentLeft , textContentTop,
(rectSideIcon.left() - AppGlobal::Style_List_Text_Item_Margin) - textContentLeft, (content.bottom() - AppGlobal::Style_List_Text_Item_Margin) - textContentTop);

// create country text rectangle

QRect rectCountryText = content,
rectCityText = content;

rectCountryText.setLeft(textContent.left());
rectCountryText.setTop(textContent.top());
rectCountryText.setRight(textContent.right());
rectCountryText.setBottom(textContent.top() + fmCountry.height());

painter->setPen(AppGlobal::Style_Heading_Color);
painter->setFont(fontCountry);
painter->drawText(rectCountryText, countryText);

// create city text rectangle

rectCityText.setLeft(textContent.left() + ( 2 * AppGlobal::Style_List_Text_Item_Margin));
rectCityText.setTop(rectCountryText.bottom());
rectCityText.setRight(textContent.right());
rectCityText.setBottom(textContent.bottom() + fmCity.height());

painter->setPen(AppGlobal::Style_SubText_Color);
painter->setFont(fontCity);
painter->drawText(rectCityText, cityText);

// restore painter
painter->restore();
}
1

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

Проблема, которую вы описываете, вызвана ошибкой в ​​повторной реализации paint метод в обычае QStyledItemDelegate. Вы берете (0, 0) в качестве источника и рисуете все относительно этой точки. Однако каждый элемент имеет вертикальное смещение, которое необходимо учитывать, используя геометрию QStyleOption :: Прямоугольник вместо.

Вот пример необычного делегата с пользовательскими рисунками и анимацией, которые помогут вам в дальнейшем.

1

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