Modifier dynamicment la taille de police de QLabel pour l’adapter à l’espace disponible

J’essaie de faire en sorte qu’une mise en page horizontale à l’échelle 3 QLabel utilise tout l’espace disponible. Plus précisément, voici ce que j’ai

Exemple

c’est ce que je vise

entrez la description de l'image ici

Pour le moment, la deuxième image est obtenue en changeant la feuille de style des qlabels avec un curseur. De plus, comme j’ai les trois étiquettes dans une disposition à l’intérieur d’une zone de groupe, la zone de groupe est redimensionnée pour s’adapter à son contenu, c’est cool.

Maintenant, je voulais abandonner l’approche par curseur et ajuster à la place l’espace disponible lors du déplacement des séparateurs. Dans cette question, OP réimplémente le resizeEvent , et j’ai vu d’autres publications suggérer la même chose, en changeant point par point avec while( !doesFit ) Ou quelque chose de similaire.

J’ai essayé d’utiliser cette approche, à la fois pour l’événement resize et pour l’événement splitterMoved. Cependant, cette approche est sujette aux boucles de rétroaction et aux autres erreurs d’affichage causées. Dans l’autre question, ils suggèrent d’activer ignoreSizePolicy pour empêcher la stratégie de taille de redéclencher le sizeevent, mais j’aime comment qt gère la taille de la mise en page, comment elle garde une taille minimale puis plie le widget si l’utilisateur le souhaite. Peut-être que cela fonctionnerait si HLayout ignorait les événements de redimensionnement déclenchés par les QLabels , toujours à QLabels avis.

Je me demandais si c’était le moyen recommandé pour y parvenir et s’il existait une solution moins instable, peut-être en utilisant des feuilles de style. Je peux également supprimer certains comportements, la taille minimale (pour que l’utilisateur puisse éventuellement masquer la zone de groupe).

Si c’est la méthode recommandée, comment utiliser les mésortingques de fonte si j’ai trois étiquettes distinctes, dont l’une (le nombre) modifie son texte de manière dynamic et rapide? Cela ne devrait pas avoir d’impact sur les performances, et cette boucle while me rend méfiant.

Cela ne sonne pas comme while(!fit) approche while(!fit) allait la réduire. Ou le fait-il?

— Modifier concernant la question en double

Une autre publication crée un filtre d’événements, qui pourrait également fonctionner si elle est retravaillée pour traiter une mise en page avec 3 étiquettes. J’ai finalement utilisé une version du premier article mentionné avec la variante de l’article mentionnée dans les commentaires. Je posterai la réponse si la question est rouverte.

On pourrait appliquer la méthode de Newton à partir de cette réponse pour travailler sur tous les widgets d’une présentation donnée. Cela fonctionnera sur n’importe quel widget avec une police paramétrable, pas seulement sur un QLabel .

L’algorithme de Newton converge assez rapidement lorsqu’un bon sharepoint départ est donné, par exemple lors d’un redimensionnement interactif. Il n’est pas inhabituel que la boucle ne s’exécute qu’une fois. D’autre part, QWidget::sizeHint valeur entière et les widgets peuvent arrondir les tailles de police fractionnaires. L’itération est donc parfois un peu plus lente que prévu. Le nombre d’itérations est limité pour assurer des performances décentes.

Un remplacement personnalisé pour l’étiquette, qui fournissait un QSizeF sizeHintF() , fonctionnerait mieux ici.

La taille minimale des widgets est un peu exagérée, car la taille n’est pas mise à jour car le contenu du widget change. Cela pourrait être facilement résolu, cependant.

  // https://github.com/KubaO/stackoverflown/tree/master/questions/label-text-size-vert-40861305 #include  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(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(obj); if (widget && ev->type() == QEvent::Resize) resized(widget); return false; } private: void onLayout(QLayout *layout, const std::function &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]; QSsortingng 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" 

Bien que je considère que la réponse de KubaOber est meilleure, je la posterai au cas où cela serait utile à quelqu’un qui souhaite une solution dans la lignée des réponses mentionnées dans le message.

Notez que le sampletext peut également être récupéré à partir des étiquettes, la police de la feuille de style et le code éventuellement placé sur un resizeEvent de la resizeEvent de groupe ou de la présentation. Cela ne fonctionnerait pas sur le resizeEvent des étiquettes car elles se disputeraient la place.

C’est l’une des raisons pour lesquelles la réponse de KubaOber est supérieure. Les autres raisons que je peux penser sont la stabilité étant donné que l’espace des 3 étiquettes diffère de celui de l’échantillon, ce qui fait que la taille de la police n’est pas aussi précise qu’elle pourrait être. Par conséquent, un événement de redimensionnement pourrait éventuellement être à nouveau déclenché par le changement de police.

 static void fitGroupBoxLabels(QGroupBox* groupbox, const QFont &samplefont, const QLayout* const samplelayout) { groupbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); QSsortingng 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; QSsortingng groupBoxStyle = QSsortingng("QGroupBox{font-size:8pt} QLabel{font-size:%1pt}").arg(fontSize); groupbox->setStyleSheet(groupBoxStyle); } 

}

Après avoir lutté avec ce problème, je crée les widgets DynamicFontSizeLabel et DynamicFontSizePushButton. J’espère que ça aide.

https://github.com/jonaias/DynamicFontSizeWidgets/