使QLabel的宽度与文本无关

6
我需要一个QLabel,其宽度不应根据包含的文本自适应,但用户(或准确地说是布局)可以调整其大小。如果文本过长而超出QLabel的宽度,则应将其裁剪。
这个问题有点相反于如何使QLabel扩展宽度以适应文本。然而,那个问题的内容对我没有帮助。在布局中设置QLabel上的文本不会调整大小也没有帮助。
背景:
QLabel将显示来自另一个系统的标识符(单词)。有时这些标识符每秒钟变化很多次,这使整个布局闪烁。QLabel是垂直停靠窗口的一部分,因此停靠窗口的宽度会闪烁。
另一方面,用户应该决定能看到多少标识符。所以我想允许用户更改停靠栏的宽度,使 QLabel 的宽度适应此宽度。
解决尝试
为了实现这一点,我将水平大小策略设置为 QSizePolicy::Preferred 并从 QLabel 派生出自己的标签类,在其中覆盖了 sizeHint() 以返回固定大小。但是,这并没有改变行为。
我知道可以应用 QFontMetrics 来计算文本的宽度,然后将其截断以适应 QLabel 的宽度。但是这似乎不是正确的解决方案,特别是当最后一个字母本身无法完全适合时,我希望将其剪切以向用户提供指示,即标识符过长无法显示。
版本
Qt 5.5.1 GCC 5.4.0 所有来自当前 Ubuntu 16.04 存储库。

你尝试过调用 QLabel::setScaledContents(true) 吗?它对标签中的文本有影响吗? - vahancho
@vahancho:感谢您的建议。我之前不知道这个方法,刚刚尝试了一下。不幸的是,它并没有起到帮助作用。 - bjhend
好的,作为另一种选择,我建议将您的标签放在滚动区域中。 - vahancho
@vahancho:谢谢,我开始尝试在我的“QLabel”周围添加滚动区域,看起来很有前途。也许你可以把这个建议作为答案添加进去。 - bjhend
4个回答

4

将文本进行缩放并不是一个好主意,因为在长字符串和小标签的情况下,缩放后的文本将很难看到。作为替代方案,我会将标签放入滚动区域中,这样它就可以容纳任何大小的标签而不需要调整自身大小(并防止我的GUI闪烁)。以下是一个简单的示例:

QLabel *label = new QLabel;
label->setAlignment(Qt::AlignTop);

QScrollArea *scrollArea = new QScrollArea;
scrollArea->setWidgetResizable(true);
scrollArea->setWidget(label);

label->setText("ThisIsVeryLargeStringThatIWantToPutIntoALabel");
scrollArea->show();

这个滚动区域可以放置在可停靠的窗口中。


将我的“QLabel”放入“QScrollArea”中,并相应地设置其属性(主要是边距和关闭滚动条)即可实现我的目标。 - bjhend

3

我认为我找到了一个相当“不太好”的解决方案来解决你的问题,这可能会引起更多问题,但你可以尝试一下。它只是防止setText调整标签的大小,同时仍允许用户和布局进行调整。

void CustomLabel::setText(const QString text)
{
    max = maximumSize();
    min = minimumSize();
    setMinimumSize(size());
    setMaximumSize(size());
    settingText = true;

    QLabel::setText(text);
}


void CustomLabel::resizeEvent(QResizeEvent *event)
{
    QLabel::resizeEvent(event);
    if(settingText){
        setMinimumSize(min);
        setMaximumSize(max);
        settingText = false;
    }
}

有趣的想法。它确实使文本剪裁得像我喜欢的那样。然而,它也防止小部件被调整大小。将“QLabel::resizeEvent(event)”的调用移动到“if”块之后也没有帮助,也没有在“CustomLabel::resizeEvent”中将最小和最大尺寸设置为“event->size()”。 - bjhend

2

通过继承QWidget,您可以创建自己的标签类,如下所示:

#include <QWidget>

class DisplayWidget : public QWidget
{
    Q_OBJECT
    QString _text;
public:
    explicit DisplayWidget(QString text, QWidget *parent = nullptr);

    QString text() const;
    void setText(QString text);

protected:
    void paintEvent(QPaintEvent *event);
};

实现非常简单:
#include "displaywidget.h"

#include <QPainter>
#include <QFontMetrics>

bool DisplayWidget::ellipsis() const { return _ellipsis; }
void DisplayWidget::setEllipsis(bool ellipsis) { _ellipsis = ellipsis; }

DisplayWidget::DisplayWidget(QString text, QWidget *parent) : QWidget(parent), _text(text), _ellipsis(false) {}

QString DisplayWidget::text() const { return _text; }

void DisplayWidget::setText(QString text)
{
    _text = text;
    update();
}

void DisplayWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    QFontMetrics metrics(painter.font());

    int maxwidth = rect().width();
    QString text = _text;
    int length = _text.size();
    while(length > 0 && metrics.width(text, length) > maxwidth)
    {
        --length;
    }
    if(length < _text.size())
    {
        text = text.left(length);
        if(_ellipsis)
        {
            const QString ellipsis = " ...";
            maxwidth -= metrics.width(ellipsis);
            while(length > 0 && metrics.width(text, length) > maxwidth)
            {
                --length;
            }
            if(length > 0)
            {
                text = text.left(length);
            }
            else
            {
                text = "";
            }
            text.append(ellipsis);
        }
    }
    painter.drawText(rect(), Qt::AlignLeft, text);
}

正如您所看到的,大部分代码都在paintEvent重写方法中。这里重要的是要有字体度量,以便根据需要决定显示多少文本(我在部分显示的文本末尾添加了省略号),而不更改文本属性本身。只需将此类的实例添加到停靠窗口内的垂直布局中即可。我认为它可能会起作用。


谢谢您的代码。这是我在“解决方案尝试”中想到的解决方案,使用了QFontMetrics。然而,我希望有一个解决方案,在其中文本被裁剪到恰好适合当前宽度的最后一个像素。此外,我担心逐个字符缩短文本会影响性能,因为对于多个QLabel,文本更新有时每10毫秒就会出现一次,但这需要测试。 - bjhend
我编辑了代码以获得更好的性能,并设置省略号开启或关闭。 - p-a-o-l-o

0

我曾经遇到过完全相同的问题,并找到了一个优雅的解决方案:设置小部件的最小大小()

要理解为什么这个方法有效,您需要知道QLabel始终将其文本的完整宽度报告为最小大小。 QWidget文档中说:

QLayout永远不会将小部件调整为小于最小大小提示的大小,除非设置最小大小()或将大小策略设置为QSizePolicy :: Ignore。 如果设置了最小大小(), 将忽略最小大小提示。

如果将最小大小设置为合理值,例如40px,则布局将忽略提示并根据需要缩小QLabel

例子:

QLabel *label = new QLabel;
label->setMinimumSize(40, 0);
label->setText("VeryVeryLongTextThatShouldNeverFitInTheSmallWindow");

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