Automatically Scale Text in QLabels



  • If I have a set of QLabels in a widget, as I resize the widget I would like the QLabels not only to fill the space available (as any layout will handle), I also want the Label text to scale proportionately.

    How do you go about doing this?


  • Lifetime Qt Champion

    Hi,

    I would reimplement resizeEvent and update the font size based on the new widget size

    Hope it helps


  • Moderators

    to add up to SGaist:
    in the resizeEvent use QLabel::contentsRect() and QFontMetrics::boundingRect()



  • [quote author="raven-worx" date="1388647547"]to add up to SGaist:
    in the resizeEvent use QLabel::contentsRect() and QFontMetrics::boundingRect()[/quote]

    Thanks...could you possibly expand a bit on what you mean by this?


  • Moderators

    something like this:

    void MyLabel::resizeEvent(QResizeEvent* event)
    {
         QLabel::resizeEvent(event);
    
         QFont font = this->font();
         QRect cRect = this->contentsRect();
    
        if( this->text().isEmpty() )
                return;
    
         int fontSize = 1;
    
          while( true )
          {
                      QFont f(font);
                           f.setPixelSize( fontSize );
                      QRect r = QFontMetrics(f).boundingRect( this->text() );
                      if (r.height() <= cRect.height() && r.width() <= cRect.widht() )
                            fontSize++;
                      else
                            break;
          }
    
         font.setPixelSize(fontSize);
         this->setFont(font);
    }
    

    Not tested though, but it should give you an idea.



  • Thanks, I will give it a try.



  • @raven-worx This method is too slow...



  • @zed962 Yea I doubt he meant it for production level code without optimizations. It was meant to give the guy an idea on how to deal with it.

    If you wanted to use it in production you would need to limit the calling of the while loop during the resize event. I would call that only after the person had chosen a size, or maybe less often during the resizing. Or finally, use a member or static var and track sizes and only recalculate sizing as things don't fit.

    Don't forget most of us that answer questions on these forums pull the code right out of our heads as an example for people to base their fixes off. The code is rarely ready to be dropped into a project. But we all assume the developers asking the questions can figure out things like compiler errors (again code type from our heads) and optimizations themselves. :)



  • @ambershark sure thing and I appreciate the time everyone is taking to come up with solutions. Thanks for your solution ^^.



  • you should use something like:

    #include <QLabel>
    #include <QTimer>
    class ScaleTextlabel : public QLabel{
        Q_OBJECT
        Q_DISABLE_COPY(ScaleTextlabel)
    public:
        explicit ScaleTextlabel(QWidget* parent=Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags())
            :QLabel(parent,f)
        {
           initTimer();
        }
        explicit ScaleTextlabel(const QString &text, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags())
            :QLabel(text,parent,f)
        {
           initTimer();
        }
    
    protected:
        void resizeEvent(QResizeEvent* event) override{
            QLabel::resizeEvent(event);
            m_resizeTimer->start();
        }
    protected slots:
        void resizeFont(){
            QFont basefont = font();
            const QRect baseRect = contentsRect();
            const QString baseText = text();
            int fontSizeGuess = qMax(1,basefont.pixelSize());
            for(;;++fontSizeGuess){
                QFont testFont(basefont);
                testFont.setPixelSize(fontSizeGuess);
                const QRect fontRect=QFontMetrics(testFont).boundingRect(baseText);
                if(fontRect.height()>baseRect.height() || fontRect.width()>baseRect.width())
                    break;
            }
            for(;fontSizeGuess>1;--fontSizeGuess){
                QFont testFont(basefont);
                testFont.setPixelSize(fontSizeGuess);
                const QRect fontRect=QFontMetrics(testFont).boundingRect(baseText);
                if(fontRect.height()<=baseRect.height() && fontRect.width()<=baseRect.width())
                    break;
            }
            basefont.setPixelSize(fontSizeGuess);
            setFont(basefont);
        }
    
    private:
        void initTimer(){
            m_resizeTimer=new QTimer(this);
            m_resizeTimer->setInterval(100);
            m_resizeTimer->setSingleShot(true);
            connect(m_resizeTimer,&QTimer::timeout,this,&ScaleTextlabel::resizeFont);
        }
    
        QTimer* m_resizeTimer;
    };
    
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.