Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 动态更改QLabel的字体大小以适应可用空间_C++_Qt_Qtstylesheets - Fatal编程技术网

C++ 动态更改QLabel的字体大小以适应可用空间

C++ 动态更改QLabel的字体大小以适应可用空间,c++,qt,qtstylesheets,C++,Qt,Qtstylesheets,我试图用3QLabelscale制作一个水平布局,并使用其所有可用空间。更具体地说,这就是我所拥有的 这就是我的目标 目前,第二个图像是通过使用滑块更改QLabel的样式表来实现的。此外,由于我在groupbox内的布局中有三个标签,groupbox会调整大小以适应其内容,酷 现在我想放弃滑块方法,而是在移动拆分器时自动调整可用空间。有问题的是,OP重新实现了resizeEvent,我看到其他帖子也提出了同样的建议,在(!doesFit)或类似的情况下,用这个一点一点地改变 我尝试在resi

我试图用3
QLabel
scale制作一个水平布局,并使用其所有可用空间。更具体地说,这就是我所拥有的

这就是我的目标

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

现在我想放弃滑块方法,而是在移动拆分器时自动调整可用空间。有问题的是,OP重新实现了
resizeEvent
,我看到其他帖子也提出了同样的建议,在(!doesFit)或类似的情况下,用这个
一点一点地改变

我尝试在resize事件和splitterMoved事件上使用这种方法。然而,这种方法很容易导致反馈回路和其他显示错误。在另一个问题中,他们建议启用ignoreSizePolicy以防止大小策略重新触发sizeevent,但我喜欢qt如何处理布局的大小,如何保持最小大小,然后在用户坚持的情况下折叠小部件。如果
HLayout
忽略由
QLabels
触发的调整大小事件,那么它可能会起作用,这仍然是一个不干净的想法

我想知道这是否是实现这一点的推荐方法,是否存在不太稳定的解决方案,可能使用样式表。我也可以放弃一些行为,即最小大小限制(因此用户可能会隐藏groupbox)

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

这听起来不像是
,而(!fit)
方法将解决这一问题。还是这样

---关于重复问题的编辑


创建一个事件筛选器,如果对其进行重新处理以处理具有3个标签的布局,则该筛选器也可以工作。最后,我使用了第一篇文章的一个版本,并对评论中提到的文章进行了修改。如果问题被重新打开,我将发布答案。

可以应用牛顿方法来处理给定布局中的所有小部件。它将在任何具有可设置字体的小部件上工作,而不仅仅是在
QLabel

当给定一个良好的起点时,牛顿算法收敛得相当快,例如交互调整大小时。循环只执行一次并不是非典型的。另一方面,
QWidget::sizeHint
是整数值,并且widget可能会舍入分数字体大小,因此有时迭代比预期的要慢一些。迭代次数被限制,以确保良好的性能

标签的自定义替换提供了
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"
//https://github.com/KubaO/stackoverflown/tree/master/questions/label-text-size-vert-40861305
#包括
类LabelStretcher:公共QObject{
Q_对象
静态constexpr const char kMinimumsAcquired[]=“ls_minimumsaquired”;
静态constexpr const char kStretcherManaged[]=“ls_stretcherManaged”;
公众:
LabelStretcher(QObject*parent=0):QObject(parent){
应用(qobject_cast(父项));
}
无效应用(QWidget*小部件){
如果(!widget)返回;
setManaged(widget);
setMinimumSize(小部件);
小部件->安装事件过滤器(此);
}
void setManaged(QWidget*w,bool managed=true){
w->setProperty(kstretcherNamed,托管);
}
受保护的:
布尔事件过滤器(QObject*obj、QEvent*ev)覆盖{
自动小部件=qobject_cast(obj);
if(小部件&&ev->type()==QEvent::Resize)
调整大小(小部件);
返回false;
}
私人:
void onLayout(QLayout*布局,const std::function和onWidget){
如果(!布局)返回;
自动N=布局->计数();
对于(int i=0;i项目(i);
onWidget(item->widget());
onLayout(项->布局(),onWidget);
}
}
void setFont(QLayout*布局、const QFont和font){
onLayout(布局,[&](QWidget*widget){setFont(widget,font);});
}
void setFont(QWidget*widget,const QFont&font){
如果(!widget | |!widget->property(kstretcherNamed).toBool())返回;
小部件->设置字体(字体);
setFont(小部件->布局(),字体);
}
void setMinimumSize(QWidget*widget){
如果(widget->layout())返回;
widget->setMinimumSize(widget->minimumSizeHint());
}
静态int dSize(常量QSizeF和内部、常量QSizeF和外部){
auto dy=内部.height()-外部.height();
auto dx=内部.width()-外部.width();
返回标准::最大值(dx,dy);
}
qreal f(qreal fontSize,QWidget*widget){
自动字体=小部件->字体();
font.setPointSizeF(fontSize);
setFont(小部件,字体);
自动d=dSize(widget->sizeHint(),widget->size());

我认为KubaOber的答案更好,我会把这个贴出来,以帮助那些想在文章中提到的答案中找到答案的人。

请注意,sampletext也可以从标签中检索,字体也可以从样式表中检索,代码可能被放置在groupbox或布局的
resizeEvent
上。它不适用于标签的
resizeEvent
,因为它们会争夺空间

这就是为什么KubaOber的答案更好的原因之一。我能想到的其他原因是稳定性,因为3个标签的空间与样本文本不同,因此字体大小不那么准确
static void fitGroupBoxLabels(QGroupBox* groupbox, const QFont &samplefont, const QLayout* const samplelayout)
{

    groupbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

    QString sampletext = "V 1000.0 kts";
    QRect availablerect = samplelayout->contentsRect();

    if(samplefont.pointSizeF() <= 0) return; //not initalized yet, return
    QRect textrect   = QFontMetrics(samplefont).boundingRect(sampletext);
    if(!textrect.isValid() || !availablerect.isValid()) return; //not initalized yet, return

    float factorh = availablerect.width() / (float)textrect.width();
    float factorw = availablerect.height() / (float)textrect.height();
    float factor = std::min(factorh, factorw);

    if (factor < 0.95 || factor > 1.05)
    {
      float fontSize = samplefont.pointSizeF()*factor;
      QString groupBoxStyle = QString("QGroupBox{font-size:8pt} QLabel{font-size:%1pt}").arg(fontSize);
      groupbox->setStyleSheet(groupBoxStyle);
    }