Word Wrapped QLabel cutting off text early

人走茶凉 提交于 2021-02-11 12:40:44

问题


I'm essentially trying to just add a title to the top of a layout to give a brief description, but Qt has to get in the way already.

I have word wrap enabled, and the QLabel will grow it's height dynamically based on how long the content is... but it's always too short.

My code:

class Window(QMainWindow):

    def __init__(self, qtpy):
        super().__init__()
        self.qtpy = qtpy
        self.setMinimumSize(250, 150)
        self.resize(600, 450)

class ThemeTool(Window):

    def __init__(self, qtpy):
        super().__init__(qtpy)
        self.setWindowTitle("qtpy-rant Theme Tool")

        widget = QWidget()
        layout = QBoxLayout(QBoxLayout.LeftToRight)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        sidebar = QWidget()
        sidebar.setMaximumWidth(150)
        sidebar_layout = QBoxLayout(QBoxLayout.TopToBottom)
        sidebar_layout.setAlignment(Qt.AlignTop)
        sidebar.setLayout(sidebar_layout)
        layout.addWidget(sidebar)

        palette = sidebar.palette()
        sidebar.setAutoFillBackground(True)
        palette.setColor(sidebar.backgroundRole(), QColor("#e3e3e3"))
        sidebar.setPalette(palette)

        sidebar_label = QLabel()
        sidebar_label.setWordWrap(True)
        sidebar_label.setText("The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors The Theme Tool is used to preview a theme and detect errors")
        sidebar_label.adjustSize()
        sidebar_layout.addWidget(sidebar_label)

        palette = sidebar_label.palette()
        sidebar_label.setAutoFillBackground(True)
        palette.setColor(sidebar_label.backgroundRole(), QColor("#ff0000"))
        sidebar_label.setPalette(palette)

        theme_area = QWidget()
        theme_area_layout = QBoxLayout(QBoxLayout.TopToBottom)
        theme_area.setLayout(theme_area_layout)
        layout.addWidget(theme_area, 1)

qapplication = QApplication(sys.argv)
main_window = ThemeTool(None)
main_window.show()
qapplication.exec_()

回答1:


I'd like to add some insight about this specific issue.

There are various reasons for this behavior, with the most important being layout issues when using child widgets that have rich text (to clarify, even if you're not using rich text, enabling word wrapping on a QLabel makes its contents rich text internally). This is explained in the layout documentation:

The use of rich text in a label widget can introduce some problems to the layout of its parent widget. Problems occur due to the way rich text is handled by Qt's layout managers when the label is word wrapped.

Consider that the computation of a size hint for a rich text content is quite complex, and with QLabels it often results in multiple recursive calls between the layouts and the label. While all that happens quite immediately and transparently to the user, this is sometimes prone to unexpected behavior, and the result is that the QLabel is not able to correctly compute its size under certain conditions.

Note that in normal conditions one would add a label and set the alignment on the label, not on the layout.

Before explaining further, an important consideration: layout management under Qt works using an abstract item called QLayoutItem, which works as a "reference" for anything that can be managed by a layout. When you add a widget to a layout, Qt actually creates a new QLayoutItem for that widget, and it's that item that is added to the layout; the same happens when adding a layout. But, wait: all Qt layouts are subclasses of QLayout, which actually inherits QLayoutItem!

When you use the simple addWidget(someWidget), that widget will try to use the entire "cell" the layout provides, but when an alignment is specified (addWidget(someWidget, alignment=Qt.AlignmentFlag)) the widget will only expand to its size hint.

In your case, the problem is due to the fact that you have set the alignment on the layout "item" (the vertical box layout), which is the same as specifying an alignment when adding an item to a layout, as written above. In this case, the layout [item] will use its size hint, but due to the aforementioned issues with rich text, this doesn't work very well. Generally speaking, you should almost never set the alignment of the layout.

Normally one would simply add the label to the layout and specify the alignment on the label, but this clearly won't work in your case: the label will correctly align the text on top, but will also still try to occupy the whole available cell space, and since you're also setting a background you'll see the color for the whole available space.

While you can use addStretch() after adding the label, this might be a slight problem whenever you need to add other widgets: the new widget will be added after the stretch, leaving blank space between the label and the new widget. In that case, the only solution is to always use insertWidget with an index based on the item count:

        sidebar_layout.insertWidget(sidebar_layout.count() - 1, newWidget)

That works, but it's not very comfortable and makes the code less readable.

The simplest solution is to specify the alignment when adding the label and not on the layout:

        # remove the following
        # sidebar_layout.setAlignment(Qt.AlignTop)
        # ...
        sidebar_label = QLabel()
        sidebar_label.setWordWrap(True)
        sidebar_label.setText("")
        # this is also unnecessary
        # sidebar_label.adjustSize()
        sidebar_layout.addWidget(sidebar_label, alignment=Qt.AlignTop)

Finally, adjustSize() only works for widgets not added to a layout or top level widgets (windows); since you're going to add the widget to a layout, that call is useless.
Also, instead of using the QBoxLayout(orientation) constructor, it's usually better to use the direct classes QHBoxLayout and QVBoxLayout instead.



来源:https://stackoverflow.com/questions/64165018/word-wrapped-qlabel-cutting-off-text-early

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!