Issue
My code has two files. One is the "main" file that uses a fixed size QFrame
instead of the standard window frame. The second is also a subclassed QWidget
for adding to the QScrollArea
in the main widget.
I want the QFrame
of the subwidget to be fixed and the label to actually use the wordwrap property instead of just making it longer to fit and screwing up the whole QScrollArea
scrolling area. I have tried using QSizePolicy
for the container_widget
and QFrame
of the subwidget. A minimal reproducible example is as follows.
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())
and 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) # https://stackoverflow.com/questions/49838817/how-to-resize-qlabels-to-fit-contents-in-qscrollarea
# Widget -> Layout
self.main_frame_layout.addWidget(self.name_lbl, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
This is a visual of the resulting window/frame.
Solution
A Wrapable Anywhere QLabel
My way to achieve this to subclass QLabel
and and implement the paintEvent
, where you can set the text alignment to TextWrapAnywhere
when you drawItemText
.
Here is a sample code.
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_())
The result.
Note: this work is tested with pyqt5, pyside2, pyside6 and should work in qt5 as well (in c++).
Answered By - Ted
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.