QListWidget 项目一致定位问题

Posted

技术标签:

【中文标题】QListWidget 项目一致定位问题【英文标题】:QListWidget items consistent positioning problem 【发布时间】:2020-08-17 12:47:47 【问题描述】:

我是 Qt 框架的新手。在新应用程序中,我想创建包含自定义项目的列表。这些项目非常简单,必须包含标题标签、缩略图和描述标签(picture here)

现在我不想玩自定义绘图和所有这些东西,因为我认为使用适当的小部件/布局更容易完成我想要的项目,所以我决定使用 QListwidget 和子类 QAbstractItemModel (KeyframeModel) 和 QListWidgetItem (TileWidgetItem )。

经过一些编码后,它看起来是我想要的,但是当我添加一些项目时,QListWidget(网格模式)发生了奇怪的事情。在我的情况下,QListWidget 是可调整大小的(由于它是如何嵌入到主布局中的),并且列数应该取决于列表和项目的宽度。项目是固定大小的(至少现在是这样)。 但是当我调整列表的大小时,某个列表宽度的项目之一是未对齐的,而不是我不知道发生了什么。以下是应用截图:

Pic. 1 List initial state (right after start)

Pic. 2 List after resizing #1

Pic. 3 List after resizing #2

调整 #2 的大小比调整 #1 的大小要宽几个像素,调整 #1 的大小很难获得(边界情况) - 宽度少了几个像素,我有 2 列(没关系),但多了一些像素,我就结束了与案例 #2 一样。 在所有情况下,列数都可以。

有时在程序立即启动后最后一项也未对齐,如here(就像在图 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 工具)

【问题讨论】:

欢迎来到***,请阅读***.com/help/how-to-ask 特别提供minimal reproducible example 我不会这样做:QWidget *view = new QWidget(); 没有QWidgetList,而是QListWidget。这意味着,没有列出小部件,但它是一个列出项目的小部件。这两者之间有根本的区别。小部件使用布局来自动调整大小和定位其子级,这很方便,但它们也参与事件循环并对其施加负载,这使得应用程序的性能迅速恶化。这就是物品的用途。它们是轻量级对象,与小部件相比,它们使用委托来显示其内容。它们不是用来加载小部件的,因为这会破坏它们的目的。 我必须坚持使用模型/视图方法并创建自定义委托我相信这是实现您想要的正确方法。 【参考方案1】:

最后我只是使用自定义委托解决了问题。

我想过度使用系统,结果我被打败了:)

【讨论】:

以上是关于QListWidget 项目一致定位问题的主要内容,如果未能解决你的问题,请参考以下文章

Python pyautogui分辨率不同造成的图片定位与鼠标位置不一致的解决方法

高德定位腾讯定位在APP上无法开启定位权限的解决方案

iPhone 定位按钮

当方向改变时重新定位控件

EasyPR源码剖析:车牌定位之偏斜扭转

QListWidget:项目点击事件