Как сделать так, чтобы многострочный QLabel убрал последнюю строку, был ограничен максимальной высотой, но также уменьшился, если текст не заполняется до максимальной высоты? - PullRequest
1 голос
/ 29 мая 2019

РЕДАКТИРОВАТЬ: Обновлено с рабочим примером и примерами скриншотов текущего и желаемого поведения.

Описание

Я пытаюсь получить многострочный QLabel для следующих действий:

  1. Это должно расшириться, чтобы заполнить доступную ширину.
  2. Если его текст длиннее, чем он может показать, он должен показать все, что может (расширяется до максимальной высоты) и удалить последнюю строку.
  3. Если его текст не самый длинный, который он может показать, он должен показать весь текст, но уменьшить его высоту, чтобы соответствовать тексту.

Метка находится в макете. Может быть, я думаю об этом неправильно, как, может быть, вместо метки должна быть текстовая область, завернутая во что-то еще?

Во всяком случае, я нашел решения, которые охватывают одно или два из этих поведений, но не все три. Я пытался настроить Qt's ElidedLabel , но я не могу понять, как настроить его для достижения всех трех.

Я подумал о переопределении sizeHint(), но я недостаточно разбираюсь в Qt, чтобы знать, правильно ли это делать. Я чувствую, что, возможно, правильная комбинация layoutSizeConstraint в политиках макета и размера в ElidedLabel может сделать это возможным, но я не уверен.

Я немного изменил пример кода Qt ElidedLabel, чтобы он не брал свое содержимое в своем конструкторе.

Пример кода

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

Скриншоты

Текущее поведение

В левом столбце текст достаточно короткий, чтобы ElidedLabel уменьшил его высоту и уступил вертикальное пространство QLabel под ним. Правый столбец имеет достаточно длинный текст, чтобы его исключить, что является правильным / желательным.

current behavior

Желаемое поведение

(для ясности, я хочу одну конфигурацию, которая будет вести себя как левый столбец, когда текст короткий, и как правый столбец, когда текст длинный)

desired behavior

1 Ответ

1 голос
/ 30 мая 2019

Вы должны ограничить высоту вашего ярлыка до минимума, необходимого для рисования текста. Вы можете получить эту высоту, используя класс 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();

...