如何使多行QLabel省略最后一行,限制最大高度,但如果文本没有填满最大高度,则也会缩小?

3

编辑:已更新为可工作的示例和当前行为和期望行为的示例截图。

描述

我想让一个多行QLabel具有以下行为:

  1. 它应该扩展以填充可用的宽度。
  2. 如果其文本超过了它能够显示的长度,它应该尽可能地显示所有内容(扩展到最大高度)并省略最后一行。
  3. 如果其文本不是它能够显示的最长长度,它应该显示所有文本,但缩小其高度以适合文本。

该标签位于布局中。也许我的思路不对,比如可能不应该是一个标签,而应该是包装在其他东西中的文本区域?

无论如何,我找到的解决方案只涵盖了其中的一两个行为,而没有覆盖所有三个行为。我尝试调整Qt的ElidedLabel,但我不能完全弄清楚如何调整它以实现这三个行为。

我考虑重写sizeHint(),但我不熟悉Qt,不知道这是否是正确的方法。我觉得也许在布局中的layoutSizeConstraint和ElidedLabel的大小策略之间找到正确的组合可能会实现这一点,但我不确定。

我稍微修改了Qt的ElidedLabel示例代码,使其不使用构造函数的内容。

示例代码

https://gist.github.com/jahabrewer/bd0c79ac2255953eeadf87c9767ce693

屏幕截图

当前行为

左列文本足够短,使ElidedLabel减少高度并将垂直空间让给其下方的QLabel。右列文本足够长,被省略,这是正确/期望的。

current behavior

期望行为

(明确一下,我希望有一个单一的配置,在文本较短时产生像左列一样的行为,在文本较长时产生像右列一样的行为)

desired behavior


最好创建一个MCVE(添加创建标签的主函数,或者更好的是包含所有内容的独立main.cpp),并且添加错误行为的截图也不会有坏处。 - hyde
一个具有WordWrap属性为真的QLabel不够吗? - Dimitry Ernot
@RomhaKorev 使用带有“WordWrap”的QLabel不会省略。 - Jay
好的,是我的问题... 你的标签中的文本会在运行时更改吗?因为调整布局会更棘手(标签将被重新调整大小,但布局项不会)。 - Dimitry Ernot
1个回答

3

您需要将标签的高度限制在绘制文本所需的最小值上。您可以使用QFontMetrics类和方法QFontMetrics::boundingRect来获取此高度:

QFontMetrics const fontMetrics(font());
QRect const r = fontMetrics.boundingRect(
            QRect(QPoint(0, 0), size()),
            Qt::TextWordWrap | Qt::ElideRight,
            content
            );
qDebug() << "Needed Height:" << r.height();

首先,定义方法QWidget::sizeHint来强制设置标签的尺寸:

virtual QSize sizeHint() const override
{
    QFontMetrics const fontMetrics(font());
    QRect const r = fontMetrics.boundingRect(
            QRect(QPoint(0, 0), size()),
            Qt::TextWordWrap | Qt::ElideRight,
            content
            );
    return QSize(width(), r.height());
}

我们只想要缩小高度。这就是为什么我们不会使用字体指标返回的宽度。

现在,我们将使用调整大小事件来检查是否可以缩小高度:

因此,我们可以覆盖QWidget::resizeEvent方法:

virtual void resizeEvent(QResizeEvent* event) override
{
    QFrame::resizeEvent(event); // Process the event. The label is now resized
    QSize const size = sizeHint();
    if (size.height() < height()) // Shrink the height if needed
        resize(QSize(width(), size.height()));
}

如果文本在运行时需要更改,我们必须重新调整大小:

void setText(const QString &newText)
{
   content = newText;
   update();
   adjustSize(); // Will resize the label
}

我用于测试的代码:

QWidget* w = new QWidget();
QVBoxLayout* l = new QVBoxLayout(w);

QString const lorem("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
ElidedLabel* label = new ElidedLabel(lorem);
label->setFrameShape(QFrame::Box); // To see its bounds

l->addWidget(label);
l->addWidget(new QLabel("Text Label"));

QTimer::singleShot(3000, [=]() { label->setText(lorem.left(100)); });

w->show();


我创建了一个新的Gist,其中包含这些更改。谢谢!https://gist.github.com/jahabrewer/79110fa93eb193c234fb2efcfeadeda0 - Jay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接