如何使 QScrollArea 内的 QLabel 子部件使用 wordwrap 而不是扩展容器部件?
How to make QLabel subwidgets inside a QScrollArea use wordwrap instead of expanding the container widget?
我的代码有两个文件。一个是使用固定大小 QFrame
而不是标准 window 框架的“主”文件。第二个也是 QWidget
的子类,用于添加到主小部件中的 QScrollArea
。
我希望子部件的 QFrame
得到修复,标签实际使用 wordwrap 属性 而不是让它更长以适合并搞砸整个 QScrollArea
滚动区域。我已尝试将 QSizePolicy
用于子小部件的 container_widget
和 QFrame
。一个最小的可重现示例如下。
main_window.py
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from subwidget import SubWidget
class Window(qtw.QWidget):
def __init__(self):
super().__init__()
# Configure Window
self.setWindowFlags(qtc.Qt.FramelessWindowHint)
self.setAttribute(qtc.Qt.WA_TranslucentBackground)
self.setFixedSize(350, 450)
# Init Methods
self.setupUI()
self.refresh_entries()
self.show()
def setupUI(self):
# Main Layout/Frame
self.main_layout = qtw.QHBoxLayout()
self.main_frame = qtw.QFrame()
self.main_frame_layout = qtw.QVBoxLayout()
# Set Layouts
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.main_frame)
self.main_frame.setLayout(self.main_frame_layout)
# Configure QFrame
self.main_frame.setContentsMargins(10, 10, 10, 10)
self.main_frame.setObjectName("main_frame")
self.main_frame.setStyleSheet("""
border: None;
border-radius: 10px;
background: #1E1E1E;
""")
# Secondary Layout/Widget
self.main_scroll_area = qtw.QScrollArea()
self.container_widget = qtw.QWidget()
self.container_layout = qtw.QVBoxLayout()
self.main_scroll_area.setObjectName("main_scroll_area")
self.main_scroll_area.setWidgetResizable(True)
self.main_scroll_area.setVerticalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.main_scroll_area.setHorizontalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.main_scroll_area.setWidget(self.container_widget)
self.container_widget.setLayout(self.container_layout)
self.container_widget.setObjectName("container_widget")
# Widget -> Layout
self.main_frame_layout.addWidget(self.main_scroll_area, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
def refresh_entries(self):
self.clear_entries()
for i in range(5):
self.container_layout.addWidget(SubWidget(i ** i ** i, i))
def clear_entries(self):
for i in reversed(range(self.container_layout.count())):
try:
widget = self.container_layout.itemAt(i).widget()
widget.setParent(None)
except Exception:
pass
if __name__ == "__main__":
app = qtw.QApplication(sys.argv)
win = Window()
sys.exit(app.exec())
和subwidget.py
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
class SubWidget(qtw.QWidget):
def __init__(self, name, index):
super().__init__()
# Variables
self.name = str(name)
self.index = index
# Init Methods
self.setupUI()
self.show()
def setupUI(self):
# Main Layout/Frame
self.main_layout = qtw.QHBoxLayout()
self.main_frame = qtw.QFrame()
self.main_frame_layout = qtw.QVBoxLayout()
# Set Layouts
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.main_frame)
self.main_frame.setLayout(self.main_frame_layout)
# Configure QFrame
self.main_frame.setContentsMargins(5, 5, 5, 5)
self.main_frame.setStyleSheet("""
border: None;
border-radius: 5px;
background: #000000;
""")
# Secondary Layout/Widget
self.name_lbl = qtw.QLabel()
# Configure Seondary Widgets
self.name_lbl.setText(self.name)
self.name_lbl.setStyleSheet("""
color: #FFFFFF;
""")
self.name_lbl.setWordWrap(True) #
# Widget -> Layout
self.main_frame_layout.addWidget(self.name_lbl, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
这是结果的视觉效果 window/frame。
可随处包装的 QLabel
我实现此目的的方法是子类化 QLabel
并实现 paintEvent
,您可以在 drawItemText
时将文本对齐方式设置为 TextWrapAnywhere
。
这是示例代码。
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_())
结果。
注意:这项工作是用 pyqt5、pyside2、pyside6 测试的,应该也能在 qt5 中工作(在 c++ 中)。
我的代码有两个文件。一个是使用固定大小 QFrame
而不是标准 window 框架的“主”文件。第二个也是 QWidget
的子类,用于添加到主小部件中的 QScrollArea
。
我希望子部件的 QFrame
得到修复,标签实际使用 wordwrap 属性 而不是让它更长以适合并搞砸整个 QScrollArea
滚动区域。我已尝试将 QSizePolicy
用于子小部件的 container_widget
和 QFrame
。一个最小的可重现示例如下。
main_window.py
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from subwidget import SubWidget
class Window(qtw.QWidget):
def __init__(self):
super().__init__()
# Configure Window
self.setWindowFlags(qtc.Qt.FramelessWindowHint)
self.setAttribute(qtc.Qt.WA_TranslucentBackground)
self.setFixedSize(350, 450)
# Init Methods
self.setupUI()
self.refresh_entries()
self.show()
def setupUI(self):
# Main Layout/Frame
self.main_layout = qtw.QHBoxLayout()
self.main_frame = qtw.QFrame()
self.main_frame_layout = qtw.QVBoxLayout()
# Set Layouts
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.main_frame)
self.main_frame.setLayout(self.main_frame_layout)
# Configure QFrame
self.main_frame.setContentsMargins(10, 10, 10, 10)
self.main_frame.setObjectName("main_frame")
self.main_frame.setStyleSheet("""
border: None;
border-radius: 10px;
background: #1E1E1E;
""")
# Secondary Layout/Widget
self.main_scroll_area = qtw.QScrollArea()
self.container_widget = qtw.QWidget()
self.container_layout = qtw.QVBoxLayout()
self.main_scroll_area.setObjectName("main_scroll_area")
self.main_scroll_area.setWidgetResizable(True)
self.main_scroll_area.setVerticalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.main_scroll_area.setHorizontalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.main_scroll_area.setWidget(self.container_widget)
self.container_widget.setLayout(self.container_layout)
self.container_widget.setObjectName("container_widget")
# Widget -> Layout
self.main_frame_layout.addWidget(self.main_scroll_area, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
def refresh_entries(self):
self.clear_entries()
for i in range(5):
self.container_layout.addWidget(SubWidget(i ** i ** i, i))
def clear_entries(self):
for i in reversed(range(self.container_layout.count())):
try:
widget = self.container_layout.itemAt(i).widget()
widget.setParent(None)
except Exception:
pass
if __name__ == "__main__":
app = qtw.QApplication(sys.argv)
win = Window()
sys.exit(app.exec())
和subwidget.py
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
class SubWidget(qtw.QWidget):
def __init__(self, name, index):
super().__init__()
# Variables
self.name = str(name)
self.index = index
# Init Methods
self.setupUI()
self.show()
def setupUI(self):
# Main Layout/Frame
self.main_layout = qtw.QHBoxLayout()
self.main_frame = qtw.QFrame()
self.main_frame_layout = qtw.QVBoxLayout()
# Set Layouts
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.main_frame)
self.main_frame.setLayout(self.main_frame_layout)
# Configure QFrame
self.main_frame.setContentsMargins(5, 5, 5, 5)
self.main_frame.setStyleSheet("""
border: None;
border-radius: 5px;
background: #000000;
""")
# Secondary Layout/Widget
self.name_lbl = qtw.QLabel()
# Configure Seondary Widgets
self.name_lbl.setText(self.name)
self.name_lbl.setStyleSheet("""
color: #FFFFFF;
""")
self.name_lbl.setWordWrap(True) #
# Widget -> Layout
self.main_frame_layout.addWidget(self.name_lbl, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
这是结果的视觉效果 window/frame。
可随处包装的 QLabel
我实现此目的的方法是子类化 QLabel
并实现 paintEvent
,您可以在 drawItemText
时将文本对齐方式设置为 TextWrapAnywhere
。
这是示例代码。
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_())
结果。
注意:这项工作是用 pyqt5、pyside2、pyside6 测试的,应该也能在 qt5 中工作(在 c++ 中)。