如何自定义QLabel的换行模式

18

我有一个标签,有时包含没有空格的长文本(计算机中的路径)。

因此,自动换行会非常奇怪。

是否有一种方法可以使标签的自动换行在单词中间断开,而不仅仅是在空格处?

5个回答

8
这不是优雅的做法,但是可以有效解决问题...
假设header类有一个Private属性:
QLabel *thisLabel;
QString *pathName;
QString *pathNameClean;

当然,还需要在某个地方定义这个标签。 如果能简单点就更好了....

thisLabel->setWordWrap(true);

只有当单词有断点时,才能这样做(应避免哪些路径)。

因此,如果您以后需要用它进行QFile操作,请将实际路径保留在单独的字符串中。 然后手动为每行号定义一个字符,并将空格插入字符串中... 所以我们说50个字符是一个好的宽度...

    pathNameClean = new QString(pathName);

    int c = pathName->length();

    if( c > 50)
    {
        for(int i = 1; i <= c/50; i++)
        {
            int n = i * 50;
            pathName->insert(n, " ");
        }
    }
    thisLabel->setText(pathName);

Shazam……没有原始空格的模拟WordWrap……

请记住,pathName字符串现在仅用于漂亮的QLabel显示目的,而pathNameClean字符串是实际路径。如果您尝试使用空格注入路径打开文件,则Qt程序将崩溃。

(如果没有简单的类方法,可能只需要几行代码即可解决问题......这就是问题解决是程序员最好的工具的原因!)


1
最好使用Unicode字符ZWSPU+200A)-零宽度空格。如果您使用该字符,则文本将在插入它的位置换行,但当它适合时仍将显示为无空格。 - MarSoft
或者,如果您使用 软连字符 (U+00AD),则单词换行的位置将有连字符,但对于未换行的文本部分没有视觉效果。 - MarSoft
1
这将只能与等宽字体正确工作。 - asd

6

3
由于QTextEdit / QTextBrowser不适合内容,所以这是不可接受的。 - chacham15
适应内容?我在问题中没有看到这样的请求。 - Luca Carlon
你说得没错,但这是QLabel的默认行为,而不是QTextEdit的。此外,让QTextEdit具有该行为并不容易。 - chacham15
3
因此,这个答案似乎符合要求,我想这是完全可以接受的。如果你有更好的解决方案,就回答一下吧。这可能对未来的观众有用。 - Luca Carlon

2

具有其他换行模式的QLabel

我在2021年也遇到了同样的问题,所以在这里我将与您分享到目前为止我发现的一些最佳答案。

TextWrapAnywhere QLabel

子类化QLabel并实现paintEvent,在此处您可以设置文本对齐方式为TextWrapAnywhere,当您使用drawItemText时。

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QStyleOption, QVBoxLayout, QWidget, QStyle

class SuperQLabel(QLabel):
    def __init__(self, *args, **kwargs):
        super(SuperQLabel, self).__init__(*args, **kwargs)

        self.textalignment = Qt.AlignLeft | Qt.TextWrapAnywhere
        self.isTextLabel = True
        self.align = None

    def paintEvent(self, event):

        opt = QStyleOption()
        opt.initFrom(self)
        painter = QPainter(self)

        self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)

        self.style().drawItemText(painter, self.rect(),
                                  self.textalignment, self.palette(), True, self.text())


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setFixedSize(100, 200)

        self.label = QLabel()
        self.label.setWordWrap(True)
        self.label.setText("1111111111111111111111111111")

        self.slabel = SuperQLabel()
        self.slabel.setText("111111111111111111111111111")

        self.centralwidget = QWidget()
        self.setCentralWidget(self.centralwidget)

        self.mainlayout = QVBoxLayout()
        self.mainlayout.addWidget(self.label)
        self.mainlayout.addWidget(self.slabel)

        self.centralwidget.setLayout(self.mainlayout)


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

enter image description here

将文本包装在字符而不是空格处

根据 @ekhumoro 提供的 这个答案(在 op 的评论中),如果您想要基于逗号换行,可以在要换行的字符后插入零宽度空格并使用内置的换行函数。

以下是一个示例:

from PyQt5.QtCore import QRect, Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QStyleOption, QStylePainter, QVBoxLayout, QWidget, QStyle


class CommaWrapableQLabel(QLabel):
    def __init__(self, *args, **kwargs):
        super(CommaWrapableQLabel, self).__init__(*args, **kwargs)

    def setWordWrapAtAnychar(self, char):
        newtext = self.text().replace(char, f"{char}\u200b")
        self.setText(newtext)
        self.setWordWrap(True)


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setFixedSize(100, 200)

        self.label = QLabel()
        self.label.setWordWrap(True)
        self.label.setText(
            'Dog,Rabbit,Train,Car,Plane,Cheese,Meat,Door,Window')

        self.slabel = CommaWrapableQLabel()
        self.slabel.setText(
            'Dog,Rabbit,Train,Car,Plane,Cheese,Meat,Door,Window')
        self.slabel.setWordWrapAtAnychar(",")

        self.centralwidget = QWidget()
        self.setCentralWidget(self.centralwidget)

        self.mainlayout = QVBoxLayout()
        self.mainlayout.addWidget(self.label)
        self.mainlayout.addWidget(self.slabel)

        self.centralwidget.setLayout(self.mainlayout)


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

enter image description here


-2

黑魔法解决方案

正如其他答案所述,您可以重新实现 paintEvent() 以传递 Qt::TextWrapAnywhere 标志给 QLabel

但是,覆盖 paintEvent() 可能会导致意外的副作用,因为 paintEvent() 的默认实现除了绘制文本之外还包含很多额外的功能。

事实上,传递到 QStyle :: drawItemText 的对齐标志存储在私有成员 QLabelPrivate :: align 中。我想到了强制重写它的值并将其设置为 Qt::TextWrapAnywhere 标志,这有效。这种解决方法需要一些 C ++ 黑魔法。

class WorkaroundLabel: public QLabel {
    Q_OBJECT
public:
    WorkaroundLabel(QString text, QWidget* parent): QLabel(text, parent) {
        setWordWrap(true);
        ushort* p;
        if (FindAlignAddr(&p)) {
            *p = (*p | Qt::TextWrapAnywhere);
        } else {
            // workaround failed
        }
    }
    virtual ~WorkaroundLabel() {}
protected:
    // "ushort align;" in qtbase/src/widgets/widgets/qlabel_p.h
    bool FindAlignAddr(ushort** out) {
        Qt::Alignment align = alignment();
        void* d_raw = (void*) d_ptr.data();
        ushort* p = reinterpret_cast<ushort*>(d_raw);
        for (int i = 0; i < 1024; i += 1) {
            setAlignment(Qt::AlignLeft);
            ushort a = *p;
            setAlignment(Qt::AlignRight);
            ushort b = *p;
            if (a != b) {
                *out = p;
                setAlignment(align);
                return true;
            }
            p++;
        }
        setAlignment(align);
        return false;
    }
};

请不要那样做。这有很大可能会出现严重问题。 - Vincent Fourmond

-5

在2020年,PySide2就是这样的:

 tmp = QLabel()
 tmp.setWordWrap(True)    

5
无法解决没有空格的文本情况,阅读问题:“有没有办法使标签的自动换行在单词中间或仅在空格处打断?” - matthieu
你可能是对的。我不记得了,我只用过Qt一小段时间。无论如何,你可以提供正确的解决方案,因为你读得更好。祝你好运。 - Nicola Mingotti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接