As soon as python class receives QMessageBox.Information as argument, resizing by stylesheet won't work

50 Views Asked by At

In python, I created a class “ScrollMessageBoxShowRC“ , which receives three arguments (see below):

result = ScrollMessageBoxShowRC(QMessageBox.Information, '', '')

result.exec_()

Originally, I instantiated the class with solely "None" as argument. As long as it received only "None", I could resize the class as follows: self.setStyleSheet("QScrollArea{min-width:410 px; min-height: 600px}"), see below:

class ScrollMessageBoxShowRC(QMessageBox):  

   def __init__(self, *args, **kwargs):
       QMessageBox.__init__(self, *args, **kwargs)
       
       self.setWindowTitle("Contacts to view or to delete.")
       
       scroll = QScrollArea(self)
       scroll.setWidgetResizable(True)
       self.content = QWidget()
       scroll.setWidget(self.content)
       lay = QVBoxLayout(self.content)
       lay.setStyleSheet("min-width: 100px;");

       dlts = {} 
       self.x = {}
       
       for rc in dbaccess.allRC():
          dlt = QCheckBox('delete', self)
          dlt.stateChanged.connect(partial(self.btnstateDel, dlt, dlts))
          dlt.setObjectName(rc[9])
 
          qb = QPushButton(rc[9], self)
          qb.released.connect(partial(self.button_releasedRC, rc[9]))
          lay.addWidget(qb)
          lay.addWidget(dlt)
 
       self.buttonClicked.connect(self.msgButtonClickDel)   
       self.layout().addWidget(scroll, 0, 0, 1, self.layout().columnCount())
       self.setStyleSheet("QScrollArea{min-width:410 px; min-height: 600px}")

   def btnstateDel(self, dlt, dlts):
       
       dlts[dlt.objectName()] = False
       
       if dlt.isChecked:
           dlts[dlt.objectName()] = True
        
       self.x = dlts

   def msgButtonClickDel(self, i):
       if i.text() == "OK":
           dbaccess.deleteRCs(self.x)

   def button_releasedRC(self, nameshow):

       pass

Since I changed the arguments to QMessageBox.Information, '', '' the stylesheet setting the size of the Widget seems no longer to have been in vigour. I could not find out why this is the case. Could anybody give me a hint what I might have overlooked?

1

There are 1 best solutions below

0
musicamante On

QMessageBox is a special type of QDialog that creates its own layout on execution. When created without arguments, it behaves almost like a basic QDialog, but as soon as elements are added (most importantly, the icon), the internal layout takes precedence and in certain cases is also completely deleted a recreated.

Since QMessageBox is generally intended as a convenience simple class, and it seems that the only actual specific feature used here is the icon, there's no need to use it at all.

A basic QDialog can be used instead, and the icon can be loaded using the style, just like QMessageBox does. Then you can add buttons using QDialogButtonBox.

class ScrollMessageBoxShowRC(QDialog):
    def __init__(self, *args, **kwargs):
        QDialog.__init__(self, *args, **kwargs)
        layout = QGridLayout(self)

        icon = self.style().standardIcon(
            QStyle.SP_MessageBoxInformation, None, self)
        iconSize = self.style().pixelMetric(
            QStyle.PM_MessageBoxIconSize, None, self)
        self.iconLabel = QLabel(pixmap=icon.pixmap(iconSize, iconSize))

        layout.addWidget(self.iconLabel, 0, 0, 
            alignment=Qt.AlignLeft|Qt.AlignTop)

        self.scroll = QScrollArea()
        layout.addWidget(self.scroll, 0, 1)
        # ...

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
        layout.addWidget(self.buttonBox, 
            layout.rowCount(), 0, 1, layout.columnCount())
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

    def accept(self):
        dbaccess.deleteRCs(self.x)
        super().accept()

The icons of QMessageBox are listed in the StandardPixmap enum of QStyle.

Further important notes:

  • you should not use string matching for buttons, especially if the names are set by the library: "OK" can be a different string in other systems (for instance, on my computer the "k" is lowercase);
  • even if you're using the local dlts in partial, you're actually always updating self.x, which makes it pointless to have two dictionaries and also sending them to the connected function;
  • the released signal is emitted whenever a button is released, which can also happen when the user presses the mouse on the button and moves the mouse outside it while keeping the mouse pressed; use clicked instead;
  • isChecked is a function, you should use if dlt.isChecked():, or, better dlts[dlt.objectName()] = dlt.isChecked(), instead of setting it to False every time before actually checking;
  • stateChanged is used for three state check boxes that can be partially checked; if you only need a bool value, use toggled;
  • for basic signals that are directly (not queued, like in threads) connected to functions for which the behavior is known and specific for those signal senders, you can use self.sender() instead of partials; in this way, you can also directly use the signal arguments instead of querying the property; if you're not interested in the argument, ignore it in the function signature; always use sender() with care, though;
        # ...
        self.dlts = {} 
       
        for rc in dbaccess.allRC():
            dlt = QCheckBox('delete', self)
            dlt.toggled.connect(self.btnstateDel)
            dlt.setObjectName(rc[9])

            qb = QPushButton(rc[9], self)
            qb.clicked.connect(self.button_releasedRC)
            lay.addWidget(qb)
            lay.addWidget(dlt)

    def btnstateDel(self, checked):
        self.dlts[self.sender().objectName()] = checked

    def button_releasedRC(self):
        nameshow = self.sender()
        # ...