QLabel "break" word if too long

Viewed 1054

are there ways to allow QLabel breaks words if those words are too long? I've seen

q_label->setWordWrap(true)

but it works with spaces, but if a single word is too long, then it will overflow...
I would like something like word-break: break-all for web development

I've also seen QTextDocument but it does not allow to have a fixed width and a not-fixed height

5 Answers

Just put Zero-width space between each char

from PySide2 import QtWidgets

app = QtWidgets.QApplication()
label = QtWidgets.QLabel()
text = "TheBrownFoxJumpedOverTheLazyDog"
label.setWordWrap(True)
label.setText("\u200b".join(text))  # The magic is here.
label.show()
app.exec_()

Or you can write your own QLabel

from PySide2 import QtWidgets


class HumanLabel(QtWidgets.QLabel):
    def __init__(self, text: str = "", parent: QtWidgets.QWidget = None):
        super().__init__("\u200b".join(text), parent)
        self.setWordWrap(True)

    def setText(self, arg__1: str) -> None:
        super().setText("\u200b".join(arg__1))

    def text(self) -> str:
        return super().text().replace("\u200b", "")


app = QtWidgets.QApplication()
text = "TheBrownFoxJumpedOverTheLazyDog"
label = HumanLabel(text)
assert label.text() == text
label.show()
app.exec_()

Wikipedia: Zero-width space

As far as I know, there is no out-of-the-box way to automatically break words into several line for QLabel.

You may code to or manually insert line break or space in your text at a fixed length, so QLabel::setWordWrap() could work properly.

QLabel *pLabel = new QLabel(this);
pLabel->setText("first line\nsecond line\nthird line\n");
pLabel->setWordWrap(true);

You could also use QTextDocument. Its setDefaultTextOption method allows you to set a QTextOption. And QTextOption::setWrapMode(QTextOption::WrapAnywhere) allows to wrap text at any point on a line.

You could have a function that adds a space every time a word is larger than the maximum size of the label. If you want to limit the word length in character count, this should work:

void wrapLabelByCharCount(QLabel *label, int characterCount)
{
    QString text = label->text();
    int wordLength = 0;
    bool insideWord = false;
    QFontMetrics fontMetrics(label->font());
    for (int i = 0; i < text.length(); i++)
    {
        if (text[i] == ' ' || text[i] == '\t' || text[i] == '\n')
            insideWord = false;
        else
        {
            if (!insideWord)
            {
                insideWord = true;
                wordLength = 0;
            }
            ++wordLength;
        }
        if (wordLength > characterCount)
        {
            text = text.left(i) + "\n" + text.right(text.length() - i);
            label->setFixedHeight(label->height() + fontMetrics.height());
            insideWord = false;
        }
    }
    label->setText(text);
}

And you should use this if you want to wrap the word based on a fixed pixel width:

void wrapLabelByTextSize(QLabel *label, int widthInPixels)
{
    QString text = label->text();
    QString word = "";
    bool insideWord = false;
    QFontMetrics fontMetrics(label->font());
    for (int i = 0; i < text.length(); i++)
    {
        if (text[i] == ' ' || text[i] == '\t' || text[i] == '\n')
            insideWord = false;
        else
        {
            if (!insideWord)
            {
                insideWord = true;
                word = "";
            }
            word += text[i];
        }
        if (fontMetrics.horizontalAdvance(word) > widthInPixels)
        {
            text = text.left(i) + "\n" + text.right(text.length() - i);
            label->setFixedHeight(label->height() + fontMetrics.height());
            insideWord = false;
        }
    }
    label->setText(text);
}

Here are some examples of how to use these:

q_label->setWordWrap(true); //required for this to work
wrapLabelByCharCount(q_label, 15); // wraps all words that have more than 15 characters
wrapLabelByTextSize(q_label, q_label->width()); // wraps words that exceed the width of your label (this is probably the one you want)
wrapLabelByTextSize(q_label, 25); // wraps words that exceed 25 pixels

EDIT: It is important to note that these functions will not resize the label for text wrapped by QLabel's default word wrapper (which would also require reimplementing it in order to count the number of wraps). You should make sure the label is big enough to fit all the text.

TextWrapAnywhere QLabel

Subclass QLabel and and implement the paintEvent, where you can set the text alignment to TextWrapAnywhere when you drawItemText.

see this question for an example in pyqt5.

Qt only supports a subset of HTML which does not contain word-break. Or the solution will be extremely simple.

But there is also a workaround with QTextBrowser. It inherits from QTextEdit, and in read-only mode. The QTextDocument in the QTextBrowser does the trick.

QTextBrowser tb = new QTextBrowser(parent);
QTextOption opt;
opt.setWrapMode(QTextOption::WrapAnywhere); // like word-break: break-all
tb->document()->setDefaultTextOption(opt);
tb->setStyleSheet("border: none;"); // no border
tb->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); // no vertical scroller bar
tb->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); // no horizontal scroller bar

Related