Проблема согласованного позиционирования элементов QListWidget

Aug 17 2020

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

На данный момент я не хочу играть с пользовательским рисунком и всем этим, потому что я считаю, что проще делать элементы, которые я хочу, с правильным виджетом / макетом, поэтому я решил использовать QListwidget и подклассы QAbstractItemModel (KeyframeModel) и QListWidgetItem (TileWidgetItem).

После некоторого кодирования это выглядит так, как я хотел, но странная вещь происходит с QListWidget (режим сетки), когда я добавляю некоторые элементы. В моем случае QListWidget может изменять размер (из-за того, что он встроен в основной макет), а количество столбцов должно зависеть от списка и ширины элементов. Предметы фиксированного размера (по крайней мере, пока). Но когда я изменяю размер списка, один из элементов на некоторой ширине списка смещен, и я не знаю, что происходит. Ниже приведены скриншоты из приложения:

Рис. 1 Список начального состояния (сразу после запуска)

Рис. 2 Список после изменения размера # 1

Рис. 3 Список после изменения размера # 2

Изменение размера №2 на несколько пикселей шире, чем изменение размера №1, а изменение размера №1 трудно получить (граница) - ширина на несколько пикселей меньше, и у меня есть 2 столбца (это нормально), но на несколько пикселей больше, и я получаю регистр №2. Во всех случаях количество столбцов приемлемое.

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

Я что-то упускаю? Должен ли я сделать некоторые части по-другому? Или это просто какие-то глюки в режиме отладки?

Ниже я публикую код:

Заявка:

// Source file 

QtGuiApplication1::QtGuiApplication1(QWidget *parent) 
    : QMainWindow(parent)
{
    ui.setupUi(this);

    //--------------------------------------------------------------------------------
    // Add elements to the list

    TileWidgetItem *item = new TileWidgetItem();
    item->setData(TileWidgetItem::TileRole::TitleRole, QVariant("Long title"));
    item->setData(TileWidgetItem::TileRole::DescriptionRole, QVariant("My long info"));
    item->setText("My super text");
    qDebug() << "Widget size hint: " << item->sizeHint();

    ui.listWidget_moves->addItem(item);
    item->updateView();

    TileWidgetItem *item1 = new TileWidgetItem();
    item1->setData(TileWidgetItem::TileRole::TitleRole, QVariant("Item #2"));
    item1->setText("Tile #2");
    ui.listWidget_moves->addItem(item1);
    item1->updateView();

    TileWidgetItem *item2 = new TileWidgetItem();
    ui.listWidget_moves->addItem(item2);
    item2->updateView();

    TileWidgetItem *item3 = new TileWidgetItem();
    ui.listWidget_moves->addItem(item3);
    item3->updateView();

    //--------------------------------------------------------------------------------
    // Adjust cell size

    QSize cellSize;

    for (uint i = 0; i < ui.listWidget_moves->count(); i++)
    {
        int dim = ui.listWidget_moves->item(i)->sizeHint().height();

        if (dim > cellSize.height())
            cellSize.setHeight(dim);

        dim = ui.listWidget_moves->item(i)->sizeHint().width();

        if (dim > cellSize.width())
            cellSize.setWidth(dim);
    }

    ui.listWidget_moves->setGridSize(cellSize);
}

Виджет товара:

// Source file

constexpr int MAX_THUMB_SIZE = 100;

TileWidgetItem::TileWidgetItem(QListWidget *listview)
    : QListWidgetItem(listview, ItemType::UserType)
{
    /* Prepare main widget */

    QWidget *view = new QWidget();
    view->setObjectName("tile");
    view->setStyleSheet(
        "QWidget#tile { margin: 4 8; background-color: #404040; border: 1 solid rgba(0,0,0,30%); border-radius: 4px }\n"
        "QWidget#tile::hover { border: 1 solid #EEE; background-color: #484848 }\n"
        "QWidget#tile[selected=true] { background-color: #00F }"
    );
    
    //-----------------------------------------------------------
    /* Prepare layout */

    QVBoxLayout *layout = new QVBoxLayout();
    layout->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize);

    //-----------------------------------------------------------
    /* Prepare title with icon */

    QHBoxLayout *titleLayout = new QHBoxLayout();

    QLabel *titleIcon = new QLabel();
    titleIcon->setObjectName("titleIcon");
    titleIcon->setStyleSheet("background-color: black");
    titleIcon->setFixedSize(QSize(16, 16));
    titleLayout->addWidget(titleIcon);

    QLabel *title = new QLabel("Title");
    title->setObjectName("title");
    title->setMinimumWidth(60);
    title->setStyleSheet("background-color: #800;");
    titleLayout->addWidget(title);
    
    QWidget *titleWidget = new QWidget();
    titleWidget->setStyleSheet("background-color: #080");
    titleWidget->setLayout(titleLayout);

    layout->addWidget(titleWidget);

    //-----------------------------------------------------------
    /* Prepare thumbnail */
    
    QLabel *thumbnail = new QLabel();
    thumbnail->setObjectName("thumbnail");
    thumbnail->setStyleSheet("background-color: black; border: 1 solid #F00");
    thumbnail->setFixedSize(QSize(MAX_THUMB_SIZE, MAX_THUMB_SIZE * 0.7f));
    thumbnail->setPixmap(QPixmap("Resources/moto.jpg").scaledToWidth(MAX_THUMB_SIZE));
    layout->addWidget(thumbnail);
    
    //-----------------------------------------------------------
    /* Preparing additional info */

    QLabel *description = new QLabel("Description");
    description->setObjectName("description");
    //description->setToolTip("Custom info tip");
    description->setContentsMargins(4, 2, 4, 2);
    layout->addWidget(description);

    //-----------------------------------------------------------

    view->setLayout(layout);

    _customView = view;
    _titleView = title;
    _descriptionView = description;

    setSizeHint(_customView->sizeHint());

    updateView();
}

TileWidgetItem::~TileWidgetItem()
{
}

void TileWidgetItem::setData(int role, const QVariant &value)
{
    QListWidgetItem::setData(role, value);

    if (value.type() == QVariant::Type::String)
    {
        if (role == TileRole::TitleRole)
        {
            this->_titleView->setText(value.toString());
        }
        else if (role == TileRole::DescriptionRole)
        {
            this->_descriptionView->setText(value.toString());
        }

        setSizeHint(_customView->sizeHint());
    }
}

void TileWidgetItem::updateView()
{
    if (listWidget() != nullptr)
    {
        listWidget()->setItemWidget(this, this->_customView);
    }
}
// Header file

class TileWidgetItem : public QListWidgetItem
{
public:
    enum TileRole
    {
        TitleRole = Qt::UserRole + 1,
        DescriptionRole,
        ThumbnailRole
    };

public:
    TileWidgetItem(QListWidget *listview = nullptr);
    ~TileWidgetItem();

    void setData(int role, const QVariant &value) override;
    void updateView();

    QWidget *customView() const { return _customView; };

    QString getTitle() const { return _titleView->text(); };

    QString getInfo() const { return _descriptionView->text(); };

private:
    QWidget *_customView;
    QLabel *_titleView;
    QLabel *_descriptionView;
};

Платформа: Windows 10
Версия Qt: 5.14.2
IDE: Visual Studio 2019 (с Qt VS Tools)

Ответы

KamilSzepietowski Sep 01 2020 at 18:23

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

Я хотел переборщить с системой и проиграл :)