Size of verticalLayout is different in Qt Designer and PyQt program

后端 未结 2 678
挽巷
挽巷 2020-12-07 04:33

In Qt Designer 5.9 the verticalLayout in test.ui had a certain distance to the edge of the window, but after loading test.ui with PyQt

相关标签:
2条回答
  • 2020-12-07 05:11

    If you check the code of uic.loadUi() you will find the following code:

    uiparser.py

    class UIParser(object):  
        # ...
        def createLayout(self, elem):
            # ...
            margin = -1 if self.stack.topIsLayout() else self.defaults['margin']
            margin = self.wprops.getProperty(elem, 'margin', margin)
            left = self.wprops.getProperty(elem, 'leftMargin', margin)
            top = self.wprops.getProperty(elem, 'topMargin', margin)
            right = self.wprops.getProperty(elem, 'rightMargin', margin)
            bottom = self.wprops.getProperty(elem, 'bottomMargin', margin)
            # A layout widget should, by default, have no margins.
            if self.stack.topIsLayoutWidget():
                if left < 0: left = 0
                if top < 0: top = 0
                if right < 0: right = 0
                if bottom < 0: bottom = 0
    
        def topIsLayoutWidget(self):
            # A plain QWidget is a layout widget unless it's parent is a
            # QMainWindow or a container widget.  Note that the corresponding uic
            # test is a little more complicated as it involves features not
            # supported by pyuic.
    
            if type(self[-1]) is not QtWidgets.QWidget:
                return False
    
            if len(self) < 2:
                return False
    
            parent = self[-2]
    
            return isinstance(parent, QtWidgets.QWidget) and type(parent) not in (
                    QtWidgets.QMainWindow,
                    QtWidgets.QStackedWidget,
                    QtWidgets.QToolBox,
                    QtWidgets.QTabWidget,
                    QtWidgets.QScrollArea,
                    QtWidgets.QMdiArea,
                    QtWidgets.QWizard,
                    QtWidgets.QDockWidget)
    

    The problem is caused by the topIsLayoutWidget() function since the parent will refer to the widget that is used as a base, in this case MainWindow complies with isinstance(parent, QtWidgets.QWidget) and type (parent) not in (QtWidgets.QMainWindow, ...) so topIsLayoutWidget() will return True, so to be left, top, right, bottom be -1 since those properties do not exist will be updated to 0 so the apply to contentsMargins will be established by eliminating the default value (9, 9, 9, 9), but in the case of Qt Designer the contentsMargins have not been updated maintaining their default value.

    So in conclusion is a pyqt bug that also points in the comments:

    # ... Note that the corresponding uic
    # test is a little more complicated as it involves features not
    # supported by pyuic.*
    

    So there are several solutions:

    • Remove:

      if self.stack.topIsLayoutWidget():
          if left < 0: left = 0
          if top < 0: top = 0
          if right < 0: right = 0
          if bottom < 0: bottom = 0
      
    • Use uic.loadUiType():

      #!/usr/bin/python3
      import sys
      from PyQt5 import QtCore, QtWidgets, uic
      
      Ui_Interface, _ = uic.loadUiType('test.ui')
      
      class MainWindow(QtWidgets.QMainWindow, Ui_Interface):
          def __init__(self, parent=None):
              super().__init__(parent)
              self.setupUi(self)
      
      def main():
          app = QtWidgets.QApplication(sys.argv)
          main_window = MainWindow()
          main_window.show()
          sys.exit(app.exec_())
      
      if __name__ == "__main__":
          main()
      

    I prefer the second solution since the source code should not be modified.

    0 讨论(0)
  • 2020-12-07 05:12

    Based off @eyllanesc's answer, here's a monkey patch that fixed the issue for me.

    This solution works because the only code inside PyQt5 that cares about the WidgetStack.topIsLayoutWidget attribute is the UIParser.createLayout() method, and it only uses that attribute to decide whether to set the default margins to zero.

    from PyQt5.uic import uiparser
    
    uiparser.WidgetStack.topIsLayoutWidget = lambda self: False
    
    0 讨论(0)
提交回复
热议问题