4
votes

I need to display text with a QLabel with following requirements:

  1. Word wrapping
  2. Expand from small width to full width according to the length of the text while the label takes a single line
  3. Always full width while the label takes multiple lines
  4. Background of the label is filled with some color

I tried putting QLabel with sizePolicy (Preferred, Preferred) and QSpacerItem with sizePolicy (Expanding, Minimum) into QHBoxLayout.

layout

And I expect that the text is not wrapped before reaches right side.

expect

But I got that the text is wrapped before reaches right side.

result

How to prevent this unnecessary word-wrapping?

Reproduction code

Note

  1. If I do not put the spacer in the HBox, then meets requirement 1 and 3, but 2 (The area that text not exists is filled with background color. In this time, I do not want this behavior).
  2. If I disable word-wrapping, then meets requirement 2, but 1.

enter image description here enter image description here

Relevant questions

This question is about the similar problem, but there is no layout.

2
Cant access the figures. Can you add it here? Also did you set the Minimum and maximum width for the QLabel?techneaz
Adding spacer is quite pointless in this example because you could just remove the spacer and get desired behavior. You should describe your actual use case. You can use QBoxLayout::setStretch to determine how much space is given to each expanding item (e.g. set stretch=4 for label and 1 for spacer will give label 4/5 of full width). If other items in the layout are fixed-size, expanding label will take all available space.Pavel Strakhov
@techneaz Thanks for finding the problem. I fixed the link.tetsurom
@techneaz I don't set the Minimum/Maximum size or I use default values for them but I think it is OK. Because I cannot give constant values.tetsurom
@PavelStrakhov Thanks. and sorry, the question may not be clear. I should fill background of the label with some color but a area that text dosn't exist should not be filled. So the spacer is not useless. If I remove the spacer, the label takes all spaces. Second, the Stretch is not suitable for me in this case. Because I don't want to fix how much space is given for the label. I want to give spaces according to the length of the text.tetsurom

2 Answers

2
votes
  1. This can be solved by setting the wordWrap of the label only when needed. To trigger the size change of the label you can make a custom label by replementing from QLabel. Below is an example.

When a text is added to the label. Initially with word wrap false, It will expand until it reaches the frame size. If it crosses the frame size, the word wrap is set to true.

  1. mylabel.h

    #ifndef MYLABEL_H
    #define MYLABEL_H
    
    #include <QLabel>
    
    class MyLabel : public QLabel
    {
         Q_OBJECT
    public:
       explicit MyLabel();
        ~MyLabel();
    
    signals:
        void labelSizeChange();
    protected slots:
        void resizeEvent(QResizeEvent *);
    
    };
    
    #endif // MYLABEL_H
    
  2. mylabel.cpp

    #include "mylabel.h"
    
    MyLabel::MyLabel():QLabel()
    {
    }
    
    MyLabel::~MyLabel()
    {
    }
    
    void MyLabel::resizeEvent(QResizeEvent *)
    {
        emit labelSizeChange();
    }
    
  3. mainwindow.h

        #ifndef MAINWINDOW_H
        #define MAINWINDOW_H
    
        #include <QMainWindow>
        #include <QtCore>
        #include <mylabel.h>
    
    
        namespace Ui {
        class MainWindow;
        }
    
        class MainWindow : public QMainWindow
        {
            Q_OBJECT
    
        public:
            explicit MainWindow(QWidget *parent = 0);
            ~MainWindow();
    
        private slots:
    
            void lableSettings();
            void on_pbShort_clicked();
            void on_pbMedium_clicked();
            void on_pbLong_clicked();
    
            void addTextToLabel(QString text);
        private:
            Ui::MainWindow *ui;
    
            MyLabel myLabel;
    
            QString lorem;
    
        };
    
         #endif // MAINWINDOW_H
    
  4. mainwindow.cpp

    #include "mainwindow.h"
        #include "ui_mainwindow.h"
    
    
        MainWindow::MainWindow(QWidget *parent) :
            QMainWindow(parent),
            ui(new Ui::MainWindow)
        {
            ui->setupUi(this);
    
            ui->horizontalLayout->addWidget(&myLabel);
            ui->horizontalLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding));
    
            myLabel.setStyleSheet("Background-color:black;color:white");
            myLabel.setWordWrap(false);
            myLabel.setMinimumWidth(0);
            myLabel.setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
    
            connect(&myLabel,SIGNAL(labelSizeChange()),this,SLOT(lableSettings()));
    
            lorem ="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
        }
    
        MainWindow::~MainWindow()
        {
            delete ui;
        }
    
    
        void MainWindow::addTextToLabel(QString text)
        {
            myLabel.setWordWrap(false);
            myLabel.setMinimumWidth(0);
            myLabel.setText(text);
    
        }
    
        void MainWindow::lableSettings()
        {
    
            if(myLabel.width()> ui->frame->width()-20)
            {
                myLabel.setWordWrap(true);
                myLabel.setMinimumWidth(ui->frame->width()-20);
             // Note the value 20 depends on the layout spacing 
             //between the Horizontal layout and the frame. 
             //If this value is less. The whole windo will start resizing.
            }
        }
    
        void MainWindow::on_pbShort_clicked()
        {
             addTextToLabel(lorem.left(15));
        }
    
        void MainWindow::on_pbMedium_clicked()
        {
            addTextToLabel(lorem.left(150));
        }
    
        void MainWindow::on_pbLong_clicked()
        {
            addTextToLabel(lorem);
        }
    
  5. GUI layout : HorizontalLayout inside a frame.

    enter image description here

1
votes

I've encountered same problem when making a chat app. Inspired by techneaz's answer, I found that using QFontMetrics is a cleaner way to compute the text width.

So if the computed text width plus some padding is less than the disired max width, set the label's fixed width to "the computed text width plus some padding", otherwise set it to the disired max width

Here's my code in pyqt:

class TextBubbleView(BubbleView):

    PADDING = 18
    MAX_WIDTH = 400

    def __init__(self, msg: Message):
        super().__init__(msg)
        self.setWordWrap(True)
        fm = QFontMetrics(self.font())
        width = fm.width(msg.content) + TextBubbleView.PADDING
        if width < TextBubbleView.MAX_WIDTH:
            self.setFixedWidth(width)
        else:
            self.setFixedWidth(TextBubbleView.MAX_WIDTH)
        self.setText(msg.content)

BubbleView is just a subclass of QLabel.

before

after

Sorry about my bad english.