title: PyQt / Qt Designer - Extra parameters for promoted widget without a plugin
body: <p>Let's say I have a custom PyQt widget that I want to use in Qt Designer, such as for a matplotlib canvas:</p>
  
  <p><strong>plot_widget.py:</strong></p>
  
  <pre><code>from PyQt5 import QtWidgets
  import matplotlib
  matplotlib.use('Qt5Agg')
  from matplotlib.backends.backend_qt5agg import (
      FigureCanvasQTAgg, NavigationToolbar2QT
  )
  
  class PlotWidget(QtWidgets.QWidget):
  
      def __init__(self, parent=None, toolbar=True, figsize=None, dpi=100):
          super(PlotWidget, self).__init__(parent)
          self.setupUi(toolbar, figsize, dpi)
  
      def setupUi(self, toolbar=True, figsize=None, dpi=100):
          layout = QtWidgets.QVBoxLayout(self)
          self.figure = Figure(figsize=figsize, dpi=dpi)
          self.canvas = FigureCanvasQTAgg(self.figure)
          if toolbar:
              self.toolbar = NavigationToolbar2QT(self.canvas, self)
              layout.addWidget(self.toolbar, 0)
          layout.addWidget(self.canvas, 1)
  </code></pre>
  
  <p>In the Qt Designer, I can easily promote a QWidget for this, with the header file set to "my_module/plot_widget.h" and its name set to PlotWidget. Then, I can construct a widget from my ui file by loading it dynamically such as this:</p>
  
  <p><strong>example.py:</strong></p>
  
  <pre><code>from PyQt5 import QtWidgets, uic
  
  class MyWidget(QtWidgets.QWidget):
  
      def __init__(self, parent=None):
          super(MyWidget, self).__init__(parent)
          uic.loadUi('example.ui', self)
          self.show()
  </code></pre>
  
  <p>This works fine, except for the fact that <strong>I don't see a straightforward way of modifying the default init parameters that I have</strong> (toolbar, figsize and dpi in this case).</p>
  
  <p>I know that there is the possibility of creating custom plugins for this, but I would like to avoid it, as I think it would be adding an unnecessary complexity to my simple needs. In addition, I want my code to be as compatible with PySide / PyQt4 / PyQt5 as possible (to that end, I am actually using QtPy instead of PyQt5 directly, although this is a bit off-topic), and I am not fully convinced I could achieve that if I start using plugins.</p>
  
  <p>Hence, I thought of the following two approaches:</p>
  
  <h1>Approach 1: Calling setupUi() programmatically</h1>
  
  <p>Basically, I can simplify my constructor so that setupUi() is not called there, and do that call after loading the ui file:</p>
  
  <p><strong>plot_widget.py:</strong></p>
  
  <pre><code>class PlotWidget(QtWidgets.QWidget):
  
      def __init__(self, parent=None):
          super(PlotWidget, self).__init__(parent)
  
      ...
  </code></pre>
  
  <p><strong>example.py:</strong></p>
  
  <pre><code>from PyQt5 import QtWidgets, uic
  
  class MyWidget(QtWidgets.QWidget):
  
      def __init__(self, parent=None):
          super(MyWidget, self).__init__(parent)
          uic.loadUi('example.ui', self)
          self.myPlotWidget.setupUi(figsize=(4, 4), dpi=200)
          self.show()
  </code></pre>
  
  <h1>Approach 2: Using dynamic properties</h1>
  
  <p>Instead of passing extra arguments to setupUi(), I can add any dynamic property that I need in the Qt Designer, and then use them such as this:</p>
  
  <pre><code>figsize = self.property('figsize')
  </code></pre>
  
  <p>If they are not defined, they will just be None. The problem is that the init constructor is called before those dynamic properties are added to the object (which seems logic), and hence figsize would always be None in this code:</p>
  
  <p><strong>plot_widget.py:</strong></p>
  
  <pre><code>class PlotWidget(QtWidgets.QWidget):
  
      def __init__(self, parent=None):
          super(PlotWidget, self).__init__(parent)
  
      def setupUi(self):
          layout = QtWidgets.QVBoxLayout(self)
          toolbar = self.property('toolbar')  # Always None
          figsize = self.property('figsize')  # Always None
          dpi = self.property('dpi')          # Always None
          self.figure = Figure(figsize=figsize, dpi=dpi)
          self.canvas = FigureCanvasQTAgg(self.figure)
          if toolbar:
              self.toolbar = NavigationToolbar2QT(self.canvas, self)
              layout.addWidget(self.toolbar, 0)
          layout.addWidget(self.canvas, 1)
  </code></pre>
  
  <p>Which means that I would still need an explicit call to setupUi() in my example.py file, unless I can figure out something else.</p>
  
  <h1>Conclusion</h1>
  
  <p>I like much more the idea of Approach 2, as it allows me to modify all the ui parameters directly from the Qt Designer. However, I would like to avoid that explicit call to setupUi(). Hence, <strong>is there any QWidget method that always gets called after the dynamic properties have been assigned to the object (and hence I could override this to make the call to setupUi() there)?</strong></p>
  
  <p>Also, do you see any other flaw in this approach or do you know of any other alternative method of achieving what I am trying to achieve? Note that I have used a matplotlib canvas as an example (for which there might be some specific approaches already), but I would like to use this for any custom widget that I might need.</p>