In the example code below, I have a CustomWidget consisting of a main label (red) on top, and sub label (yellow) on bottom – and I instantiate several of those in a scroll area:
When I click on the “Merge” button, I’d like consecutive pairs of sub-labels to be replaced with a single sublabel, having the text of the left sub-label, and covering the area of both sub-labels – something like this (edited in image processing software):
So I thought, I’ll just calculate the width of the “merged” sub-label, apply it to the left sub-label, and hide the right sub-label, to achieve this effect – unfortunately, this doesn’t work, as it messes up the other previously set layout relationships – so the actual result looks something like this:
How can I achieve the kind of pairwise visual merging of sub-labels that I want?
The code:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CustomWidget(QWidget):
def __init__(self, parent=None, maintext=""):
super().__init__(parent)
self.maintext = maintext
self.origwidth = 50
self.lbl_main = QLabel(self.maintext)
self.lbl_main.setAlignment(Qt.AlignCenter)
self.lbl_main.setMinimumWidth(self.origwidth)
self.lbl_main.setFixedWidth(self.origwidth)
self.lbl_main.setFixedHeight(100)
self.lbl_main.setStyleSheet("background: #3FFF0000;")
self.lbl_sub = QLabel("sub_{}".format(self.maintext))
self.lbl_sub.setAlignment(Qt.AlignCenter)
self.lbl_sub.setMinimumWidth(self.origwidth)
self.lbl_sub.setFixedWidth(self.origwidth)
self.lbl_sub.setFixedHeight(20)
self.lbl_sub.setStyleSheet("background: #3FFFFF00; border: 1px solid black;")
self.vspacer = QLabel()
self.layout = QVBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setSpacing(0)
self.layout.addWidget(self.lbl_main)
self.layout.addWidget(self.lbl_sub)
self.layout.addWidget(self.vspacer)
self.layout.setAlignment(self.lbl_main, Qt.AlignHCenter)
self.layout.setAlignment(self.lbl_sub, Qt.AlignHCenter)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
class MyMainWindow(QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
self.num_cws = 10
# Define the geometry of the main window
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle("my first window")
self.centralwidget = QWidget(self)
self.layout = QHBoxLayout(self.centralwidget)
#self.centralwidget.setLayout(self.layout)
self.setCentralWidget(self.centralwidget)
self.scroll_area = QScrollArea()
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll_central = QWidget()
self.scroll_layout = QHBoxLayout(self.scroll_central)
self.scroll_area.setWidget(self.scroll_central)
self.scroll_area.setWidgetResizable(True)
self.layout.addWidget(self.scroll_area)
self.btn = QPushButton(text = 'Merge')
self.layout.addWidget(self.btn)
self.btn.clicked.connect(self.onBtnClick)
self.customwidgets = []
for ix in range(self.num_cws):
cw = CustomWidget(None, "{0}{0}".format(chr(65+ix)))
self.scroll_layout.addWidget(cw)
self.customwidgets.append(cw)
self.show()
def onBtnClick(self):
if self.btn.text() == "Merge":
self.btn.setText("Unmerge")
for ix in range(0, self.num_cws, 2):
cw_left = self.customwidgets[ix]
cw_right = self.customwidgets[ix+1]
llblgeom = cw_left.lbl_sub.geometry().translated( cw_left.lbl_sub.mapTo(self.scroll_central, QPoint(0,0)) )
rlblgeom = cw_right.lbl_sub.geometry().translated( cw_right.lbl_sub.mapTo(self.scroll_central, QPoint(0,0)) )
lbl_dual_width = rlblgeom.right() - llblgeom.left()
cw_right.lbl_sub.hide()
cw_left.lbl_sub.setFixedWidth(lbl_dual_width)
else:
self.btn.setText("Merge")
for ix in range(0, self.num_cws, 2):
cw_left = self.customwidgets[ix]
cw_right = self.customwidgets[ix+1]
cw_left.lbl_sub.setFixedWidth(cw_left.origwidth)
cw_right.lbl_sub.show()
if __name__== '__main__':
app = QApplication(sys.argv)
myGUI = MyMainWindow()
sys.exit(app.exec_())