1

I'm trying to get this custom frame be usable as a widget in qt-designer. I'm following this example in pyqt5 documentation. I've implemented subclasses of QPyDesignerContainerExtension, CollapsibleBoxExtensionFactory and QPyDesignerCustomWidgetPlugin. The only difference is that the example involves pages, and mine is just a custom frame. It is the only example demonstrating a container plugin, and therefore, using the class QPyDesignerContainerExtension.

All function of the widget work when used in python, it appears in qt-designer, but I'm unable to drop a widget in it. Except if I force getCurrentIndex to be 0 instead of -1 when the frame is empty. But this obviously create a segmentation fault error in qt designer as it tries to access a non existing widget.

After a bit of reverse ingeneering on how qt designer interact with multipagewidgetplugin, I have the impression that the QPyDesignerContainerExtension is more for multipage containers that for basic frames.

Is QPyDesignerContainerExtension supposed to work with basic containers, as a frame ? Or should I be looking for a bug in my code...

Thanks for any help

edit: To refocus the question on the primary problem, here is a simple version of the widget I want to use in qt-designer

The widget:

from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QWidget, QScrollArea, QSizePolicy, QVBoxLayout, QLabel

class CustomFrame(QWidget):
    def __init__(self, parent=None, title='title'):
        super().__init__(parent)
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        self.title = QLabel(text=title)
        layout.addWidget(self.title)

        self.content_area = QScrollArea()
        # self.content_area.setMinimumHeight(0)
        # self.content_area.setMaximumHeight(0)
        self.content_area.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Fixed
        )
        layout.addWidget(self.content_area)

        self.content_layout = QVBoxLayout(self.content_area)
        self.content_area.setLayout(self.content_layout)

    def _update_animation(self):
        # need to be called each time a widget is added
        pass

    def getTitle(self):
        return self.toggle_button.text()
    @pyqtSlot(str)
    def setTitle(self, value):
        self.toggle_button.setText(value)
    def resetTitle(self):
        self.toggle_button.setText("Title")
    titleString = pyqtProperty(str, getTitle, setTitle, resetTitle)
        

A plugin:

from PyQt5.QtDesigner import QPyDesignerCustomWidgetPlugin


class MultiPageWidgetPlugin(QPyDesignerCustomWidgetPlugin):

    def __init__(self, parent=None):    
        super(MultiPageWidgetPlugin, self).__init__(parent)
        self.initialized = False
    def initialize(self, formEditor):
        if self.initialized:
            return
        self.initialized = True
    def isInitialized(self):
        return self.initialized
    def createWidget(self, parent):
        widget = CustomFrame(parent)
        return widget
    def name(self):
        return "CustomFrame"
    def group(self):
        return "PyQt Examples"
    def icon(self):
        return QIcon()
    def toolTip(self):
        return ""
    def whatsThis(self):
        return ""
    def isContainer(self):
        return True
    def domXml(self):
        return ('<widget class="CustomFrame" name="customframe">'
                '  <widget class="QWidget" name="page" />'
                '</widget>')
    def includeFile(self):
        return "customframe"

The goal is, in qt-designer, that a widget dropped to the CustomFrame is added to content_area. By setting isContainer() to true, the widget accept dropped widgets, but they are added the widget itself, not to content_area. So unless there is a way to change this behaviour, It seems to be requiered to use a QPyDesignerContainerExtension with a single page...

beesleep
  • 1,322
  • 8
  • 18
  • 1
    As explained in the [QDesignerContainerExtension docs](https://doc.qt.io/qt-5/qdesignercontainerextension.html), it "allows you to add pages to a custom multi-page container in Qt Designer's workspace". All custom widget plugins allow adding children widgets (and layouts), as long as the interface returns True to `isContainer`, so you theoretically should not implement the container extension. OTOH, the problem is that in designer you can only see (and add children to) one container [page] at once, which makes the development of such a plugin very difficult, as you might need to change its -> – musicamante Jul 29 '20 at 15:31
  • please provide a [mre] – eyllanesc Jul 29 '20 at 15:31
  • -> behavior depending on the fact that the custom widget is loaded within designer or not (you can set a special variable to the new widget within the `createWidget()`). Consider that it won't be easy, and you might ask yourself if it's worth it (also note that some portions of the designer plugin framework are not completely implemented in PyQt). Anyway, I suggest you to make the code as minimal as possible and edit your question to share it with us. – musicamante Jul 29 '20 at 15:38
  • Creating container widget plugins for PyQt is not an easy task, mostly because the documentation is poor or outdated, pyuic has some erratic behavior depending on whether you use it from command line or from the `uic` module, and it also has no good support for multi-page containers that don't subclass from the existing classes. While it *could* be possible to implement that (using some hacks and workarounds), have you considered to just use a simple QScrollArea and create a plugin for the collapsible boxes only? – musicamante Aug 16 '20 at 14:58

0 Answers0