Issue
I want to create a window which height should be equal to the height of the child QLabel, the QLabel can be set to any size text and setWrap is True. Here is my current code:
class TextWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(230)
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QHBoxLayout(self.centralwidget)
self.horizontalLayout.setSizeConstraint(QLayout.SizeConstraint.SetMinimumSize)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QLabel(self.centralwidget)
self.label.setWordWrap(True)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.setCentralWidget(self.centralwidget)
self.label.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non urna nisl. Integer venenatis aliquet faucibus. Nam tristique massa a vestibulum congue. Vivamus nisi felis, volutpat vitae neque quis, pharetra tristique massa. Duis tincidunt et nulla a hendrerit. Vestibulum in molestie lectus.")
Actual behavior:
The text is cut off if there is a lot of it and if there is not enough of it, then there are huge margins between the edge of the window and the text, I want the window height to wrap the text, that is, the height of the window needs to be equal to the size of the text. How can this be done?
Solution
This is explained in the Layout Issues section of 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".
Note that, as a rule of thumb, you shall never rely on the size hint of a label that uses word-wrapped text. This is related to the many problems text laying out has, like unexpected font behavior, system font scaling, high DPI settings. In reality, it's a good thing that the default behavior doesn't consider the possible size hint of a word-wrapped label, otherwise there could be serious performance issues, especially while resizing.
Truth is, word-wrapped text should always be displayed in a scroll area (using a QTextEdit or with a QLabel that is placed inside a QScrollArea); the default API cannot know the infinite possibilities in which some text could be shown, and should always aim for the best result with optimal performance.
The problem is caused by the fact that there's no way to know the "best" size hint of a label that can wrap its contents, and layout managers should always try to be as fast as possible in their response, otherwise you'd risk recursion or unnecessary overhead, even for a simple label.
IF you are completely sure about the fixed width of the label, you should explicitly set it:
self.label.setFixedWidth(230)
If the width cannot be known beforehand, due to the presence of other widgets in the layout that might change the available width for the label, then you can rely on the QLabel heightForWidth()
, set a minimum height for it based on the current width, and finally make a delayed call to the adjustSize()
of the main window (the delay is required to allow the whole layout management to update the size hints).
from random import randrange
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
def randomText():
return ' '.join(['Lorem ipsum'] * randrange(10, 50)) + '\n\nThe end.'
class TextWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(230)
central = QWidget()
layout = QGridLayout(central)
layout.addWidget(QToolButton())
self.label = QLabel(randomText())
self.label.setWordWrap(True)
layout.addWidget(self.label, 0, 1)
layout.addWidget(QPushButton('Hello'), 1, 0, 1, 2)
self.setCentralWidget(central)
def setMessage(self, message=''):
self.label.setText(message or randomText())
self.updateSize()
def updateSize(self):
self.centralWidget().layout().activate()
self.label.setMinimumHeight(0)
self.label.setMinimumHeight(
self.label.heightForWidth(self.label.width()))
QTimer.singleShot(0, self.adjustSize)
def resizeEvent(self, event):
super().resizeEvent(event)
self.updateSize()
app = QApplication([])
w = TextWindow()
QTimer.singleShot(1000, w.setMessage)
w.show()
app.exec()
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.