Как заставить текст в QLabel перепрыгивать на новую строку, если ему не хватает места?
Мой код содержит достаточно много контейнеров. Я попытаюсь рассказать о них. Хотел упростить конструкцию, но, как показывает практика, лучше объяснить ситуацию подробнее и оставить в примере больше деталей
- Главный контейнер -
main_box. Включает:color_box- цветной контейнер;scroll_box- контейнер, связанный с областью прокрутки. Включает:- Три цветных контейнера
little_box; box_h- горизонтальный контейнер. Включает:box_v1- вертикальный контейнер;box_v2- вертикальный контейнер.
- Три цветных контейнера
В box_v1 находится picture - изображение с закругленными краями. Его получаю с помощью класса RoundArt.
В box_v2 находятся две надписи - label1 и label2.
label2 нужна, чтобы сохранить форму макета, никак задействовать ее не нужно.
А вот label1 хотелось бы полностью переделать. Мне нужно, чтобы текст внутри label1 переходил на новую строку, если окно приложения становится слишком маленьким. Есть несколько условий:
- Если это возможно, текст располагается на одной строке.
- Если места становится слишком мало, текст частично переползает на вторую строку, пока ему это необходимо.
- Текст может располагаться
максимум на двух строках. На третью переходить он не должен. - Если двух строк становится мало, приложение должно обрезать текст тремя точками:
Было - looooong text >>> Стало - looo...
^^^ Текст стал непозволительно длинным, и приложение обрезало его
Честно говоря, сейчас я вообще не представляю, как такое можно организовать.
Для меня это очень сложно, но я не знаю, насколько это трудоемкая задача на самом деле. Может быть, это делается вручную на сотни строк кода, а может быть, для этого существует специальный виджет? Из-за этого я даже не знаю, насколько корректный задал вопрос. Возможно, я сейчас слишком много хочу.
Есть две причины, которые объясняют, почему мне это нужно.
Первая причина довольно очевидная - я хочу, чтобы текст было лучше видно.
Вторая причина заключается в том, что вместе с текстом становится не видно надписи в контейнерах little_box. Эти надписи я специально прижимаю к правому боку. Я думаю, что, когда для надписи label1 становится слишком мало места, перестает масштабироваться весь контейнер scroll_box, хотя контейнеры little_box еще могут уменьшаться.
Я немного потерялся и мог забыть что-нибудь очень важное. Пожалуйста, дайте знать, если что-то не объяснил или объяснил плохо
Пожалуйста, помогите мне.
from PyQt5 import QtCore, QtWidgets, QtGui
class RoundArt(QtWidgets.QLabel):
clicked = QtCore.pyqtSignal()
def __init__(self, picture, x, *args, **kwargs):
super(RoundArt, self).__init__(*args, **kwargs)
self.setFixedSize(x, x)
self.x = x
self.radius = 10
self.setPicture(picture)
def setPicture(self, picture):
target = QtGui.QPixmap(self.size())
target.fill(QtCore.Qt.transparent)
p = QtGui.QPixmap(picture).scaled(
self.x, self.x, QtCore.Qt.KeepAspectRatioByExpanding,
QtCore.Qt.SmoothTransformation
)
painter = QtGui.QPainter(target)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
path = QtGui.QPainterPath()
path.addRoundedRect(0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(target)
painter.end()
target = None
def mouseReleaseEvent(self, event):
self.clicked.emit()
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
self.resize(900, 600)
main_box = QtWidgets.QGridLayout(self)
scrollArea = QtWidgets.QScrollArea()
container = QtWidgets.QWidget()
scrollArea.setWidget(container)
scrollArea.setWidgetResizable(True)
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scroll_box = QtWidgets.QVBoxLayout(container)
main_box.addWidget(scrollArea, 0, 0)
container = QtWidgets.QWidget()
container.setFixedHeight(220)
scroll_box.addWidget(container)
box_h = QtWidgets.QHBoxLayout(container)
picture = RoundArt('Fc414959288ga866.png', 200)
box_v1 = QtWidgets.QVBoxLayout()
box_v1.addWidget(picture)
box_h.addLayout(box_v1)
box_h.addSpacing(10)
box_v2 = QtWidgets.QVBoxLayout()
box_v2.addSpacing(10)
label1 = QtWidgets.QLabel('very looooooooooooooong label')
label1.setStyleSheet(qss_lb)
label1.setFixedHeight(30)
box_v2.addWidget(label1)
box_v2.addSpacing(20)
label2 = QtWidgets.QLabel('label')
label2.setStyleSheet(qss_lb)
label2.setFixedHeight(30)
box_v2.addWidget(label2)
box_v2.addSpacing(10)
box_h.addLayout(box_v2)
container = QtWidgets.QWidget()
container.setStyleSheet('background: #3A4256;')
container.setFixedWidth(200)
main_box.addWidget(container, 0, 1)
color_box = QtWidgets.QVBoxLayout(container)
label = QtWidgets.QLabel('color box')
label.setStyleSheet(qss_lb)
color_box.addWidget(label, alignment = QtCore.Qt.AlignCenter)
for i in range(0, 3):
container = QtWidgets.QWidget()
container.setStyleSheet('background: #3A4256;')
container.setFixedHeight(50)
little_box = QtWidgets.QHBoxLayout(container)
label = QtWidgets.QLabel('label')
little_box.addWidget(label, alignment = QtCore.Qt.AlignRight)
scroll_box.addWidget(container)
qss_lb = '''QLabel {
font: bold 25px;
}'''
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())
Ответы (1 шт):
В общем, вам надо изучить:
QFontMetricsF Class -> https://doc.qt.io/qt-5/qfontmetricsf.html
from PyQt5 import QtCore, QtWidgets, QtGui
class RoundArt(QtWidgets.QLabel):
clicked = QtCore.pyqtSignal()
def __init__(self, picture, x, *args, **kwargs):
super(RoundArt, self).__init__(*args, **kwargs)
self.setFixedSize(x, x)
self.x = x
self.radius = 10
self.setPicture(picture)
def setPicture(self, picture):
target = QtGui.QPixmap(self.size())
target.fill(QtCore.Qt.transparent)
p = QtGui.QPixmap(picture).scaled(
self.x, self.x, QtCore.Qt.KeepAspectRatioByExpanding,
QtCore.Qt.SmoothTransformation
)
painter = QtGui.QPainter(target)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
path = QtGui.QPainterPath()
path.addRoundedRect(0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(target)
painter.end()
target = None
def mouseReleaseEvent(self, event):
self.clicked.emit()
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
self.resize(900, 600)
main_box = QtWidgets.QGridLayout(self)
scrollArea = QtWidgets.QScrollArea()
container = QtWidgets.QWidget()
scrollArea.setMinimumWidth(390) # +++
scrollArea.setMinimumHeight(235) # +++
scrollArea.setWidget(container)
scrollArea.setWidgetResizable(True)
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scroll_box = QtWidgets.QVBoxLayout(container)
main_box.addWidget(scrollArea, 0, 0)
container = QtWidgets.QWidget()
container.setFixedHeight(220)
scroll_box.addWidget(container)
box_h = QtWidgets.QHBoxLayout(container)
picture = RoundArt('head3.png', 200)
box_v1 = QtWidgets.QVBoxLayout()
box_v1.addWidget(picture)
box_h.addLayout(box_v1)
box_h.addSpacing(10)
box_v2 = QtWidgets.QVBoxLayout()
box_v2.addSpacing(10)
# +++ vvv
self.text = 'я не могу сказать про максимум, т.к. текст излекается из тегов MP3-файла, '\
'а в тегах может находится строка любой длины.'
self.label1 = QtWidgets.QLabel(self.text) # +++ text
self.label1.setWordWrap(True) # +++
# self.label1.setStyleSheet(qss_lb)
self.label1.resize(418, 55) # +++
self.label1.setFixedHeight(55) # 30 -> 55
self.label1.setMinimumWidth(130) # +++
self.label1.setFont(QtGui.QFont("Consolas", 20, QtGui.QFont.Bold)) # +++
# +++ ^^^
box_v2.addWidget(self.label1)
box_v2.addSpacing(20)
label2 = QtWidgets.QLabel('label')
label2.setStyleSheet(qss_lb)
label2.setFixedHeight(30)
box_v2.addWidget(label2)
box_v2.addSpacing(10)
box_h.addLayout(box_v2)
container = QtWidgets.QWidget()
container.setStyleSheet('background: #3A4256;')
container.setFixedWidth(200)
main_box.addWidget(container, 0, 1)
color_box = QtWidgets.QVBoxLayout(container)
label = QtWidgets.QLabel('color box')
label.setStyleSheet(qss_lb)
color_box.addWidget(label, alignment = QtCore.Qt.AlignCenter)
for i in range(0, 3):
container = QtWidgets.QWidget()
container.setStyleSheet('background: #3A4256;')
container.setFixedHeight(50)
little_box = QtWidgets.QHBoxLayout(container)
label = QtWidgets.QLabel('label')
little_box.addWidget(label, alignment = QtCore.Qt.AlignRight)
scroll_box.addWidget(container)
# ++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
def resizeEvent(self, event):
super(MyWindow, self).resizeEvent(event)
w = self.label1.size().width()
# https://doc.qt.io/qt-5/qfontmetricsf.html#averageCharWidth
# Возвращает среднюю ширину глифов в шрифте.
fw = self.label1.fontMetrics().averageCharWidth()
x = w * 2 // fw - 12 # 12 - какое-то корректирующее число
self.label1.setText(self.text[:x] + ' ...')
# ++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
qss_lb = '''QLabel {
font: bold 23px;
}'''
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())
Update
Есть одна деталь - три точки ... никуда не уходят, если тексту хватает места. Я забыл уточнить это в вопросе. Буду очень рад узнать, как это поправить, если вы знаете решение, и вам не трудно.
Замените:
self.label1.setText(self.text[:x] + ' ...')
на что-то такое:
if (w * 2 // fw) > (len(self.text) ):
self.label1.setText(self.text)
else:
self.label1.setText(self.text[:x] + ' ...')



