Vincent A
Vincent A

Reputation: 77

How to dynamically resize the height of my CustomQWidget

I am creating a QList with a custom QWidget as QList item.

This CustomQWidget has a QButton to show or hide a QLabel at its bottom part.

If I can show/hide the QLabel, my CustomQwidget doesn't resize to fit the new configuration.

enter image description here

class CustomQWidget (QWidget):
    """Custom Qt Widget to be transformed to an item 
    for a QListWidget"""
    def __init__ (self, parent = None):
        super(CustomQWidget, self).__init__(parent)
        self.textQVBoxLayout = QVBoxLayout()
        self.txtNameQLabel = QLabel()
        self.subTextQHBoxLayoutUp = QHBoxLayout()
        self.subTextQHBoxLayoutBot = QHBoxLayout()
        self.txtAuthorQLabel = QLabel()
        self.txtDateQLabel = QLabel()
        self.txtContextQLabel = QLabel()
        self.txtTypeQLabel = QLabel()
        self.txtClassQLabel = QLabel()
        self.codeQVBoxLayout = QVBoxLayout()
        self.codeQVBoxLayout.addStretch()
        self.txtCodeQLabel = QLabel()#QLabel to show/hide
        self.txtCodeQLabel.setVisible(False)

        self.codeQVBoxLayout.addWidget(self.txtCodeQLabel)
        self.subTextQHBoxLayoutUp.addWidget(self.txtNameQLabel)
        self.subTextQHBoxLayoutUp.addWidget(self.txtAuthorQLabel)
        self.subTextQHBoxLayoutUp.addWidget(self.txtDateQLabel)
        self.subTextQHBoxLayoutBot.addWidget(self.txtContextQLabel)
        self.subTextQHBoxLayoutBot.addWidget(self.txtTypeQLabel)
        self.subTextQHBoxLayoutBot.addWidget(self.txtClassQLabel)

        self.textQVBoxLayout.addLayout(self.subTextQHBoxLayoutUp)
        self.textQVBoxLayout.addLayout(self.subTextQHBoxLayoutBot)

        self.upQHBoxLayout  = QHBoxLayout()
        self.copyButton = QPushButton('Copy')
        self.codeViewbutton = QPushButton('View code')#Trigger button to show/hide txtCodeQLabel
        self.codeViewbutton.clicked.connect(functools.partial(self.showHideCode, self.txtCodeQLabel))
        self.upQHBoxLayout.addWidget(self.copyButton)
        self.upQHBoxLayout.addWidget(self.codeViewbutton)
        self.upQHBoxLayout.addLayout(self.textQVBoxLayout, 1)

        self.globalLayout = QVBoxLayout()
        self.globalLayout.addLayout(self.upQHBoxLayout)
        self.globalLayout.addLayout(self.codeQVBoxLayout)
        self.globalLayout.addStretch()
        self.setLayout(self.globalLayout)

        # setStyleSheet
        self.txtNameQLabel.setStyleSheet('''color: rgb(255, 128, 64);''')
        self.txtAuthorQLabel.setStyleSheet('''color: rgb(128, 128, 128);''')

    def setTxtName (self, text):
        self.txtNameQLabel.setText(text)

    def setTxtAuthor (self, text):
        self.txtAuthorQLabel.setText(text)

    def setTxtDate (self, text):
        self.txtDateQLabel.setText(text)

    def setTxtContext (self, text):
        self.txtContextQLabel.setText(text)

    def setTxtType (self, text):
        self.txtTypeQLabel.setText(text)

    def setTxtClass (self, text):
        self.txtClassQLabel.setText(text)

    def setTxtCode (self, text):
        self.txtCodeQLabel.setText(text)

    def showHideCode(self, label):
        if label.isVisible():
            label.setVisible(False)        
        else:
            label.setVisible(True)

I tried to add self.adjustSize() to the showHideCode() method but if the QLabel appears entirely,it's in the background of the others QList iems which doesn't move. Plus, the others QLabels of my customwidget are moved. I tried to use this : Stack thread

with the same result

enter image description here

OK - I guess the problem lies within the QListWidget where I put my CustomWidget

    def populateMainLayout(self,json_disk_file):
        """Populate QListWidget with configured 
        CustomQWidget from json entry"""
        listing = QListWidget()
        current_data = self.openJson(json_disk_file)
        for entry in current_data:
            myQCustomQWidget = CustomQWidget()
            myQCustomQWidget.setTxtName(str(entry['name']))
            myQCustomQWidget.setTxtDate(str(entry['date']))
            myQCustomQWidget.setTxtAuthor(str(entry['author']))
            myQCustomQWidget.setTxtContext(str(entry['context']))
            myQCustomQWidget.setTxtType(str(entry['type']))
            myQCustomQWidget.setTxtClass(str(entry['class']))
            myQCustomQWidget.setTxtCode(str(entry['snip']))
            q_widgetitem = QListWidgetItem(listing)
            q_widgetitem.setSizeHint(myQCustomQWidget.sizeHint())
            listing.addItem(q_widgetitem)
            listing.setItemWidget(q_widgetitem, myQCustomQWidget)
        return listing

How I can reexecute

q_widgetitem.setSizeHint(myQCustomQWidget.sizeHint())

when one of the 'View Code' buttons is pushed ?

I attempt to get the corresponding QListWidgetItem in the CustomWidget instance.

Now when I push the 'View Code' button the code appear and the size QListWidgetItem is refresh but when I click again on the button the text of the QLabel is hidden but the QListWidgetItem doesn't refresh its size correctly, the same way as the code provided by @musicamante.

   ...
        for entry in current_data:
            ...
            q_widgetitem.setSizeHint(myCustomQWidget.sizeHint())
            myCustomQWidget.getListItem(q_widgetitem)#get the QListWidgetItem receiveing the CustomQWidget instance
class CustomQWidget (QWidget):
    ...
    def getListItem (self, item):
        self.item = item

    def showHideCode(self, label):
        if label.isVisible():
            label.setVisible(False)
            self.item.setSizeHint(self.sizeHint())
        else:
            label.setVisible(True)
            self.item.setSizeHint(self.sizeHint())

Upvotes: 0

Views: 56

Answers (2)

Vincent A
Vincent A

Reputation: 77

Dirty ... but it works

def showHideCode(self, label):
    if label.isVisible():
        label.setVisible(False)
        self.item.setSizeHint(QtCore.QSize(100,60))
    else:
        label.setVisible(True)
        self.item.setSizeHint(self.sizeHint())

Upvotes: 0

musicamante
musicamante

Reputation: 48335

If you use setSizeHint() you are statically setting the size hint of the item based on the current hint of the widget.

Obviously, if the contents of the widget change, the item will know absolutely nothing about it.

Qt doesn't have a direct way to notify when the size hint of a widget changes, but we can assume that your widget may need a different size whenever some of its contents are explicitly changed (for instance, when updating a label, or changing the visibility of a child).

A possible solution is to add a custom signal that emits the new size hint whenever required, and then connect that signal to the setSizeHint() of the item.

class CustomQWidget(QWidget):
    sizeHintChanged = pyqtSignal(QSize)
    ...
    # for any function that may change the hint, call this
    def emitSizeHintChanged(self):
        self.sizeHintChanged.emit(self.sizeHint())

    # for example:
    def showHideCode(self, label):
        label.setVisible(not label.isVisible())
        self.emitSizeHintChanged()

Then connect the signal to the item's setSizeHint whenever it's created and set on the list view:

def populateMainLayout(self, json_disk_file):
    ...
    for entry in current_data:
        ...
        q_widgetitem.setSizeHint(myQCustomQWidget.sizeHint())
        myQCustomQWidget.sizeHintChanged.connect(q_widgetitem.setSizeHint)

Upvotes: 0

Related Questions