如何让文字填满所有QLabel的space?

How to make the text fill all the QLabel's space?

我正在从事 PyQt5 项目,但也很乐意阅读 C++/Qt 答案,因为 C++ 解决方案也可以在 Python 上工作。

我有一个水平布局的 MainWindow,里面有一个 QLabel。

我的 QLabel 的大小策略是 "Expanding",因此我所有的 window 都由 QLabel 填充。

但是,我的 QLabel 显示的文本并没有改变它的大小。我希望文本在 window 增长时增长,并且在 QLabel 大小的限制内尽可能大。

我听说过 QWidget::adjustSize() 但不知道如何使用它。 QtDesigner 上我的 QLabel 的选项 scaledContents 没有做任何事情,所以我想它只在使用 pixmap 时有用。

目前,我的解决方案是重新实现 window 的 resizeEvent() 方法,并使用 setFont() 更改标签的字体大小。但我认为必须有一个更简单的解决方案。而且,我的resizeEvent()方法不是很好,因为我在myWindowWidth* myWindowHeightmyTextFontSize之间建立了线性关系,因此当只有myWindowWidth增加时,myTextFontSize增加并强制myWindowHeight要增加,不好。

这是一个可能指向解决方案的快速草图。可以在任何标签上安装事件过滤器,而不是从标签派生,以使其文本填充可用 space。该过滤器使用现有的 scaledContents 属性,并将其适用性扩展到文本内容。

使用牛顿算法调整标签的字体大小以填充可用space。需要进行一些调整才能使其与启用自动换行的标签一起使用;字体大小永远不会超过适合的大小。

// https://github.com/KubaO/Whosebugn/tree/master/questions/label-text-size-36575192
#include <QtWidgets>

class LabelStretcher : public QObject {
   Q_OBJECT
public:
   LabelStretcher(QObject * parent = 0) : QObject(parent) {
      apply(qobject_cast<QLabel*>(parent));
   }
   void apply(QLabel * label) { if (label) label->installEventFilter(this); }
protected:
   bool eventFilter(QObject * obj, QEvent * ev) Q_DECL_OVERRIDE {
      if (ev->type() != QEvent::Resize) return false;
      auto label = qobject_cast<QLabel*>(obj);
      if (!label || label->text().isEmpty() || !label->hasScaledContents()) return false;
      qDebug() << "pre: " << label->minimumSizeHint() << label->sizeHint() << label->size();

      static auto dSize = [](const QSize & inner, const QSize & outer) -> int {
         auto dy = inner.height() - outer.height();
         auto dx = inner.width() - outer.width();
         return std::max(dx, dy);
      };
      static auto f = [](qreal fontSize, QLabel * label) -> qreal {
         auto font = label->font();
         font.setPointSizeF(fontSize);
         label->setFont(font);
         auto d = dSize(label->sizeHint(), label->size());
         qDebug() << "f:" << fontSize << "d" << d;
         return d;
      };
      static auto df = [](qreal fontSize, QLabel * label) -> qreal {
         if (fontSize < 1.0) fontSize = 1.0;
         return f(fontSize + 0.5, label) - f(fontSize - 0.5, label);
      };

      // Newton's method
      auto font = label->font();
      auto fontSize = font.pointSizeF();
      int i;
      for (i = 0; i < 5; ++i) {
         auto d = df(fontSize, label);
         qDebug() << "d:" << d;
         if (d < 0.1) break;
         fontSize -= f(fontSize, label)/d;
      }
      font.setPointSizeF(fontSize);
      label->setFont(font);
      qDebug() << "post:" << i << label->minimumSizeHint() << label->sizeHint() << label->size();
      return false;
   }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   QLabel label{"Hello There!"};
   label.setScaledContents(true);
   label.show();
   LabelStretcher stretch(&label);
   return app.exec();
}

#include "main.moc"