Problème de positionnement cohérent des éléments QListWidget

Aug 17 2020

Je suis nouveau sur le framework Qt. Dans une nouvelle application, je souhaite créer une liste avec des éléments personnalisés. Ces éléments sont assez simples et doivent contenir une étiquette de titre, une vignette et une étiquette de description ( image ici )

Pour l'instant, je ne veux pas jouer avec le dessin personnalisé et tout ça parce que je pense qu'il est plus facile de faire les éléments que je veux avec le bon widget/mise en page, j'ai donc décidé d'utiliser QListwidget et de sous-classer QAbstractItemModel (KeyframeModel) et QListWidgetItem (TileWidgetItem).

Après un peu de codage, cela ressemble à ce que je voulais, mais une chose étrange se produit avec QListWidget (mode grille) lorsque j'ajoute des éléments. Dans mon cas, un QListWidget est redimensionnable (en raison de la façon dont il est intégré dans la mise en page principale) et le nombre de colonnes doit dépendre de la liste et de la largeur des éléments. Les articles sont de taille fixe (du moins pour l'instant). Mais lorsque je redimensionne la liste, l'un des éléments à la largeur d'une liste est mal aligné et je ne sais pas ce qui se passe. Vous trouverez ci-dessous des captures d'écran de l'application :

Photo. 1 Lister l'état initial (juste après le démarrage)

Photo. 2 Liste après redimensionnement #1

Photo. 3 Liste après redimensionnement #2

Le redimensionnement # 2 est plus large de quelques pixels que le redimensionnement # 1 et le redimensionnement # 1 est difficile à obtenir (cas de bordure) - quelques pixels de moins et j'ai 2 colonnes (ça va) mais quelques pixels de plus et je me retrouve avec cas #2. Dans tous les cas, le nombre de colonnes est correct.

Parfois aussi le dernier élément est mal aligné après le démarrage du programme tout de suite comme ici (juste après le démarrage comme sur la photo 1 mais comme vous pouvez voir un résultat différent malgré la même largeur de liste). Je me demande pourquoi c'est si incohérent après le démarrage.

Est-ce que je manque quelque chose? Dois-je faire certaines parties de manière différente ? Ou est-ce juste quelques problèmes en mode débogage ?

Ci-dessous, je poste un code:

Application:

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

Widget d'article :

// 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;
};

Plateforme : Windows 10
Version Qt : 5.14.2
IDE : Visual Studio 2019 (avec Qt VS Tools)

Réponses

KamilSzepietowski Sep 01 2020 at 18:23

En fin de compte, j'ai simplement utilisé des délégués personnalisés qui ont résolu des problèmes.

Je voulais abuser du système et j'ai été vaincu :)