QLabel & Word Wrap:如何以逗号为基础换行(与空格)

Posted

技术标签:

【中文标题】QLabel & Word Wrap:如何以逗号为基础换行(与空格)【英文标题】:QLabel & Word Wrap : How to break line base on a comma (vs space) 【发布时间】:2021-05-20 18:38:09 【问题描述】:

我正在尝试使用没有空格但用逗号分隔的文本创建多行 QLabel。 例如:'猫、狗、兔子、火车、汽车、飞机、奶酪、肉、门、窗'

我发现setWordWrap 可以使用多行,但它会根据空格中断。

如何根据逗号换行?

这是一个代码示例:

from PySide2.QtWidgets import *


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setGeometry(500,100,50,100)

        line = QLabel()
        line.setMaximumWidth(150)
        line.setText('Cat,Dog,Rabbit,Train,Car,Plane,Cheese,Meat,Door,Window')
        line.setWordWrap(True)

        self.setCentralWidget(line)

        self.show()


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    app.exec_()

【问题讨论】:

您需要将单词全部放在不同的行上,或者像自动换行一样适合容器? 我希望拥有与自动换行相同的机制。在这个例子中,它应该在 Car 之后中断, @Pythmalion 一个快速而肮脏的解决方法是在每个逗号之后插入一个 zero-width-space (\u200b),因为在 any 类型的空格之后换行会中断。 @ekhumoro 谢谢,也许有点脏,但它使工作。在我看来,这是一个/解决方案! 【参考方案1】:

一种方法是根据QLabel 大小编辑文本。

在每个行大小事件上都会触发以下触发器,因此这是一个成本高昂的解决方案。

首先我们添加一个信号:

class MainWindow(QMainWindow):
    resized = QtCore.pyqtSignal()

然后我们用一个方法连接信号,将 wordwrap 设置为 False 并添加自定义调整大小事件,每次标签获得新大小时触发:

self.line.setWordWrap(False)
self.line.resizeEvent = self.on_resize_event
self.resized.connect(self.add_spaces)

on_resize_event 处理大小变化并触发add_spaces

def on_resize_event(self, event):
    if not self._flag:
        self._flag = True
        self.resized.emit()
        QtCore.QTimer.singleShot(100, lambda: setattr(self, "_flag", False))
    print(f"Resized line: self.line.size()")
    return super(MainWindow, self).resizeEvent(event)

最后我们有一个add_spaces 方法,它计算最大行长度并以逗号分隔。

def add_spaces(self):
    size = self.line.size()
    text = self.mystring
    result_string = ""
    temp_label = QLabel()
    temp_text = ""

    #Split the chunks by delimiter
    chunks = text.split(",")

    for i,chunk in enumerate(chunks):
        temp_text += chunk + ",";
        if len(chunks) > i+1:
            temp_label.setText(temp_text + chunks[i+1] + ",")
            width = temp_label.fontMetrics().boundingRect(temp_label.text()).width()
            if width >= size.width():
                result_string += temp_text + "\n"
                temp_text = ""
        else:
            result_string += temp_text

    self.line.setText(result_string)

完整代码:

from PyQt5 import QtCore
from PyQt5.QtWidgets import QMainWindow, QLabel, QApplication


class MainWindow(QMainWindow):
    resized = QtCore.pyqtSignal()
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self._flag = False

        self.line = QLabel()
        self.line.setStyleSheet("background-color: grey;color:white;")
        self.line.setMaximumWidth(300)
        self.line.setMinimumWidth(20)

        self.mystring = 'Cat,Dog,Rabbit,Train,Car,Plane,Cheese,Meat,Door,Window,very,long,list of words,list of words,word,word,word,list of word,word,list of word,list of word'

        self.line.setText(self.mystring)



        self.setCentralWidget(self.line)

        self.line.setWordWrap(False)
        self.line.resizeEvent = self.on_resize_event
        self.resized.connect(self.add_spaces)

        self.show()
        self.add_spaces()


    def on_resize_event(self, event):
        if not self._flag:
            self._flag = True
            self.resized.emit()
            QtCore.QTimer.singleShot(100, lambda: setattr(self, "_flag", False))
        print(f"Resized line: self.line.size()")
        return super(MainWindow, self).resizeEvent(event)

    def add_spaces(self):
        size = self.line.size()
        text = self.mystring
        result_string = ""
        temp_label = QLabel()
        temp_text = ""

        #Split the chunks by delimiter
        chunks = text.split(",")

        for i,chunk in enumerate(chunks):
            temp_text += chunk + ",";
            if len(chunks) > i+1:
                temp_label.setText(temp_text + chunks[i+1] + ",")
                width = temp_label.fontMetrics().boundingRect(temp_label.text()).width()
                if width >= size.width():
                    result_string += temp_text + "\n"
                    temp_text = ""
            else:
                result_string += temp_text

        self.line.setText(result_string)




if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    app.exec_()

【讨论】:

不建议在 resizeEvent 中更改几何图形,因为这很容易导致递归,特别是对于像 QLabel 这样具有自适应大小提示的小部件。 @musicamante 是的,这是真的。 resizeEvent 应该如何处理?目前我将其更改为有 100 毫秒的延迟以防止这种情况发生。 感谢您花时间回答问题。可能不是答案,但我学到了其他东西,它告诉我如何克服我的另一个问题:) @BlueGhost 它根本不应该调用调整大小,并且一个好的(但远非简单)实现需要适当的 QLabel 子类,至少覆盖 resizeEvent 到计算正确的自动换行,hasHeightForWidthheightForWidth 用于适当的“比率”提示,sizeHint 用于可能的“最终”提示,setText 用于最小尺寸甚至可能是paintEvent;如果保留一个内部 QTextDocument(这是 QLabel 实际所做的),所有这些显然会更好。

以上是关于QLabel & Word Wrap:如何以逗号为基础换行(与空格)的主要内容,如果未能解决你的问题,请参考以下文章

CSS 换行知多少: word-wrap && word-break && white-space && word-spacing

我可以将 word-wrap:break-word 设置为提交类型的输入吗?

如何使用 pixmap 和 Qlabel 使图像可选择?

如何在 QLabel 中查看未知的 HTML 标签?

word-wrap:break-word;和word-break:break-all;的区别

如何在 PyQt5 中将字节数组图像添加到 QLabel