QListWidgetItem - adjust width and height to content
Asked Answered
H

1

6

I have got a QListWidgetItem, which has a QWidget and some QLabels. The height of the labels (imageLabel, titleLabel and descriptionLabel) varies depending on the text length. So does the height of the QWidget, which leds to different sizes in QListWidgetItem. So far the parameters for setSizeHint are static:

QListWidgetItem* listWidgetItem = new QListWidgetItem();
listWidgetItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
listWidgetItem->setSizeHint(200, 180));

QWidget* widget = new QWidget();

QVBoxLayout* rootLayout = new QVBoxLayout();
rootLayout->setAlignment(Qt::AlignTop);

QHBoxLayout* contentLayout = new QHBoxLayout();
contentLayout->setAlignment(Qt::AlignLeft);

QLabel* imageLabel = new QLabel();
imageLabel->setPixmap(pixmap);

contentLayout->addWidget(imageLabel, 0, Qt::AlignTop);

QVBoxLayout* informationLayout = new QVBoxLayout();
informationLayout->setAlignment(Qt::AlignTop);

QLabel* titleLabel = new QLabel("<b>" + title  + "</b>");
titleLabel->setWordWrap(true);
informationLayout->addWidget(titleLabel);

QLabel* descriptionLabel = new QLabel(description);
descriptionLabel->setWordWrap(true);
informationLayout->addWidget(descriptionLabel);

QLabel* dateLabel = new QLabel(date.toString());
informationLayout->addWidget(dateLabel);

contentLayout->addLayout(informationLayout);

rootLayout->addLayout(contentLayout);

QHBoxLayout* buttonLayout = new QHBoxLayout();
QPushButton* buttonOne = new QPushButton(tr("Button 1"));
QObject::connect(buttonOne, SIGNAL(clicked()), mButtonOneSignalMapper, SLOT(map()));
mButtonOneSignalMapper->setMapping(buttonOne, index);
buttonLayout->addWidget(buttonOne);

QPushButton* buttonTwo = new QPushButton(tr("Button 2"));
QObject::connect(buttonTwo, SIGNAL(clicked()), mButtonTwoSignalMapper, SLOT(map()));
mButtonTwoSignalMapper->setMapping(buttonTwo, index);
buttonLayout->addWidget(buttonTwo);

rootLayout->addLayout(buttonLayout);

widget->setLayout(rootLayout);

mListWidget->addItem(listWidgetItem);
mListWidget->setItemWidget(listWidgetItem, widget);

Is there any way to properly set the sizeHint regarding the width and height of the displayed content used in the QLabels of the QWidget?

For instance the first QListWidgetItem may have a descriptionLabel with a text length of 300 characters and the second QListWidgetItem may have a descriptionLabel with a text length of 1000 characters. So far both QListWidgetItems will have the same size (200px width and 180px height). While it may fit on the first QListWidgetItem, because it has only 300 characters, it may not fit on the second QListWidgetItem, because of the 1000 characters. Therefore I would like to somehow dynamically adjust the size of the QListWidgetItem regarding the needed space (first one will need less than the second one).

Hidalgo answered 6/8, 2014 at 10:33 Comment(5)
What is it exactly that you're trying to achieve? Are you aware that setting the sizeHint on a QListWidgetItem is a no-op until you configure the view's header to actually use said size hint? You'd need to post a self-contained example that demonstrates the problem, with an explanation of what you expect. So far I don't know what other code is missing, and what you really want to happen. Your question is worded as if you wished all the item sizes to be the same (you complain that they are different).Anvers
@KubaOber I have edited my question. I wish to have different sizes on the QListWidgetItems.Hidalgo
Try setting different size hints on a two or three items manually and see if that has any effect. Then you'll know whether you need to do other things first.Anvers
@KubaOber of course it does affect if I for instance use listWidgetItem->setSizeHint(200, index % 2 == 0 ? 180 : 360)); I just don't know how much height / width each QLabel need for displaying its content.Hidalgo
Good, because this doesn't happen by default :)Anvers
D
0

The way I see it, you won't be able to get a correct bounding rect for the label, unless you know it's future width, so that you can calculate the number of lines required to display the content. And you won't get the width before the layout with the other widgets is calculated.

An alternate approach might be to use an item delegate. Its sizeHint method has an option parameter with a preliminary rect, from which you can use the width and calculate the height with font metrics.

Concerning your other widgets, you could switch to a QTableWidget and put them in other columns..

The following code is not a working example .. just some clues to get you started..

class ItemDelegate : public QStyledItemDelegate
{
public:

    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
    {
        painter->save();

        QStyledItemDelegate::paint(painter,option,index);

        QString title = index.data(Qt::UserRole).toString();
        QFont f = option.font;
        painter->setFont(f);
        QFontMetrics fm(f);

        QRect r = option.rect;
        // r = r.adjusted(0, fm.lineSpacing(), 0, 0);
        painter->drawText(r.left(), r.top(), r.width(), r.height(), Qt::AlignTop|Qt::AlignLeft|Qt::TextWordWrap, title, &r);

        painter->restore();
    }

    QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
    {
        QFont f = option.font;
        QRect r = option.rect;
        QFontMetrics fm(f);
        QString title = index.data(Qt::UserRole).toString();
        QRect br = fm.boundingRect(r,Qt::AlignTop|Qt::AlignLeft | Qt::TextWordWrap,title);
        return QSize(option.rect.width(),br.height());
    }
};

Hope it helps,

Johannes

Disport answered 15/8, 2014 at 16:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.