其他分享
首页 > 其他分享> > c – 动态更改QLabel的字体大小以适合可用空间

c – 动态更改QLabel的字体大小以适合可用空间

作者:互联网

我正在尝试使用3 QLabel刻度使用所有可用空间进行水平布局.更具体地说,这就是我所拥有的

Example

这就是我的目标

enter image description here

目前,通过使用滑块更改qlabels的样式表来实现第二个图像.此外,由于我在组框内的布局中有三个标签,因此组框会调整大小以适应其内容,很酷.

现在我想放下滑块方法,而是在移动分割器时自动调整可用空间.在this问题中,OP重新实现了resizeEvent,并且我已经看到其他帖子暗示相同的,同时逐点改变(!doesFit)或类似的东西.

我尝试在resize事件和splitterMoved事件上使用这种方法.但是,这种方法很容易引起反馈循环和其他显示错误.在另一个问题中,他们建议启用ignoreSizePolicy以防止大小策略重新触发sizeevent,但我喜欢qt如何处理布局的大小,如何保持最小大小,然后如果用户坚持则折叠小部件.也许如果HLayout会忽略QLabels触发的调整大小事件,这仍然有效,恕我直言恕不通.

我想知道这是否是推荐的实现方法,并且存在不太不稳定的解决方案,可能使用样式表.我还可以删除一些行为,最小大小限制(因此用户可能隐藏组框).

如果这是推荐的方式,如果我有三个单独的标签,我应该如何使用fontmetrics,其中一个(数字)动态和快速地更改其文本?它不应该对性能产生影响,而且循环让我很谨慎.

听起来并不像while(!fit)方法会削减它.或者是吗?

—编辑重复的问题

Another post创建一个事件过滤器,如果重新处理具有3个标签的布局,它也可能有效.我最后使用了第一篇上述帖子的版本以及评论中提到的帖子的变体.如果问题重新开启,我会发布答案.

解决方法:

可以从this answer应用牛顿方法方法来处理给定布局中的所有小部件.它适用于任何具有可设置字体的小部件,而不仅仅适用于QLabel.

当给出一个好的起点时,牛顿算法会合理地快速收敛,例如:在交互式调整大小时.让循环只执行一次并不是非典型的.另一方面,QWidget :: sizeHint是整数值,并且小部件可以舍入小数字体大小,因此有时迭代比预期慢一点.迭代次数的上限是为了确保良好的性能.

提供QSizeF sizeHintF()的标签的自定义替换将在这里更好地工作.

窗口小部件的最小大小是一个延伸,因为窗口小部件内容更改时不会更新大小.不过,这可以很容易地解决.

 // https://github.com/KubaO/stackoverflown/tree/master/questions/label-text-size-vert-40861305
#include <QtWidgets>

class LabelStretcher : public QObject {
   Q_OBJECT
   static constexpr const char kMinimumsAcquired[] = "ls_minimumsAcquired";
   static constexpr const char kStretcherManaged[] = "ls_stretcherManaged";
public:
   LabelStretcher(QObject *parent = 0) : QObject(parent) {
      apply(qobject_cast<QWidget*>(parent));
   }
   void apply(QWidget *widget) {
      if (!widget) return;
      setManaged(widget);
      setMinimumSize(widget);
      widget->installEventFilter(this);
   }
   void setManaged(QWidget *w, bool managed = true) {
      w->setProperty(kStretcherManaged, managed);
   }
protected:
   bool eventFilter(QObject * obj, QEvent * ev) override {
      auto widget = qobject_cast<QWidget*>(obj);
      if (widget && ev->type() == QEvent::Resize)
         resized(widget);
      return false;
   }
private:
   void onLayout(QLayout *layout, const std::function<void(QWidget*)> &onWidget) {
      if (!layout) return;
      auto N = layout->count();
      for (int i = 0; i < N; ++i) {
         auto item = layout->itemAt(i);
         onWidget(item->widget());
         onLayout(item->layout(), onWidget);
      }
   }
   void setFont(QLayout *layout, const QFont &font) {
      onLayout(layout, [&](QWidget *widget){ setFont(widget, font); });
   }
   void setFont(QWidget *widget, const QFont &font) {
      if (!widget || !widget->property(kStretcherManaged).toBool()) return;
      widget->setFont(font);
      setFont(widget->layout(), font);
   }
   void setMinimumSize(QWidget *widget) {
      if (widget->layout()) return;
      widget->setMinimumSize(widget->minimumSizeHint());
   }
   static int dSize(const QSizeF & inner, const QSizeF & outer) {
      auto dy = inner.height() - outer.height();
      auto dx = inner.width() - outer.width();
      return std::max(dx, dy);
   }
   qreal f(qreal fontSize, QWidget *widget) {
      auto font = widget->font();
      font.setPointSizeF(fontSize);
      setFont(widget, font);
      auto d = dSize(widget->sizeHint(), widget->size());
      qDebug() << "f:" << fontSize << "d" << d;
      return d;
   }
   qreal df(qreal fontSize, qreal dStep, QWidget *widget) {
      fontSize = std::max(dStep + 1.0, fontSize);
      return (f(fontSize + dStep, widget) - f(fontSize - dStep, widget)) / dStep;
   }
   void resized(QWidget *widget) {
      qDebug() << "pre: " << widget->minimumSizeHint() << widget->sizeHint() << widget->size();
      if (!widget->property(kMinimumsAcquired).toBool()) {
         onLayout(widget->layout(), [=](QWidget *widget){ setMinimumSize(widget); });
         widget->setProperty(kMinimumsAcquired, true);
      }

       // Newton's method
      auto font = widget->font();
      auto fontSize = font.pointSizeF();
      qreal dStep = 1.0;
      int i;
      for (i = 0; i < 10; ++i) {
         auto prevFontSize = fontSize;
         auto d = df(fontSize, dStep, widget);
         if (d == 0) {
            dStep *= 2.0;
            continue;
         }
         fontSize -= f(fontSize, widget)/d;
         fontSize = std::max(dStep + 1.0, fontSize);
         auto change = fabs(prevFontSize - fontSize)/fontSize;
         qDebug() << "d:" << d << " delta" << change;
         if (change < 0.01) break; // we're within 1% of target
      }
      font.setPointSizeF(fontSize);
      setFont(widget, font);
      qDebug() << "post:" << i << widget->minimumSizeHint() << widget->sizeHint() << widget->size();
   }
};
constexpr const char LabelStretcher::kMinimumsAcquired[];
constexpr const char LabelStretcher::kStretcherManaged[];

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   QWidget w;
   QGridLayout layout{&w};
   LabelStretcher stretch{&w};
   QLabel labels[6];
   QString texts[6] = {"V", "30.0", "kts", "H", "400.0", "ft"};
   int i = 0, j = 0, k = 0;
   for (auto & label : labels) {
      stretch.setManaged(&label);
      label.setFrameStyle(QFrame::Box);
      label.setText(texts[k++]);
      if (j == 0) label.setAlignment(Qt::AlignRight | Qt::AlignVCenter);
      else if (j == 1) label.setAlignment(Qt::AlignCenter);
      layout.addWidget(&label, i, j++);
      if (j >= 3) { i++; j=0; }
   }
   w.show();
   return app.exec();
}
#include "main.moc"

标签:qtstylesheets,c,qt
来源: https://codeday.me/bug/20191008/1873569.html