最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

qt - Pyside6-designer: export Python code of custom (promoted) widget - Stack Overflow

programmeradmin0浏览0评论

I've created the design for a widget in PySide6 GUI.
This MyCustomWidget is defined in my main UI, which contains many other things.
Please consider that this custom widget can be quite complex and have many sub-widgets, and I find it much more convenient to design it in the UI.

I would like to isolate and export the code of this widget alone, so I can import/programmatically generate copies of it from the main UI code.

However, normally, the UI export can only export the entire code for my main UI (with the custom widget code embedded in it). I tried promoting the widget, which I would expect to also take and isolate the code for the promoted widget in a class or separate module. If I promote the widget, and then I export the code for my main UI, I get something like:

################################################################################
## Form generated from reading UI file 'main_window_uiERYisl.ui'
##
## Created by: Qt User Interface Compiler version 6.8.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)

# More imports [...]

from myCustomWidget import MyCustomWidget

Where myCustomWidget is the expected module containing the widget, once it was promoted it. However, this is not exported as part of the main UI code conversion process -- only the main_window.ui content is exported in a single file.

Is there a way to isolate and export the code of a custom widget, promoted or not?

I've created the design for a widget in PySide6 GUI.
This MyCustomWidget is defined in my main UI, which contains many other things.
Please consider that this custom widget can be quite complex and have many sub-widgets, and I find it much more convenient to design it in the UI.

I would like to isolate and export the code of this widget alone, so I can import/programmatically generate copies of it from the main UI code.

However, normally, the UI export can only export the entire code for my main UI (with the custom widget code embedded in it). I tried promoting the widget, which I would expect to also take and isolate the code for the promoted widget in a class or separate module. If I promote the widget, and then I export the code for my main UI, I get something like:

################################################################################
## Form generated from reading UI file 'main_window_uiERYisl.ui'
##
## Created by: Qt User Interface Compiler version 6.8.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)

# More imports [...]

from myCustomWidget import MyCustomWidget

Where myCustomWidget is the expected module containing the widget, once it was promoted it. However, this is not exported as part of the main UI code conversion process -- only the main_window.ui content is exported in a single file.

Is there a way to isolate and export the code of a custom widget, promoted or not?

Share Improve this question edited Mar 14 at 17:41 alelom asked Mar 11 at 14:59 alelomalelom 3,0453 gold badges35 silver badges49 bronze badges 4
  • I don't understand the problem, can't you just import that class when you import the ui module? – musicamante Commented Mar 11 at 17:38
  • 1 A promoted widget is just a name - there's no code as such. That's really the whole point of it. The normal Qt name (e.g. QTextEdit) is simply replaced with a user-defined name (e.g, MetadataRenameEditWidget). The code for the promoted widget is in metadatarenameeditwidget.py. This will be a custom subclass of e.g. QTextEdit, which you must write yourself. If you want to use that subclass elsewhere, you can simply import it like any other Python module. – ekhumoro Commented Mar 11 at 20:30
  • If the only thing you actually did was really to promote the widget in Designer and generate the python file with the uic command, then you're making an invalid assumption, as ekhumoro explained above. Promoting a widget does not create anything, you must. metadatarenameeditwidget is not simply "the module containing the widget", it's the module you must write, containing the code of the widget subclass: if, for example, you promoted a QLineEdit, that module must contain a class MetadataRenameEditWidget(QLineEdit): ..., and Qt will be able to create its instances when used in the UI. – musicamante Commented Mar 13 at 1:00
  • I recommend you to do more research about widget promotion in Qt so that you can understand how it actually works. There are some relevant posts even here on SO, and you may start with this. – musicamante Commented Mar 13 at 1:03
Add a comment  | 

2 Answers 2

Reset to default 0

There is no direct way to only export a "part" of the UI, but there is a relatively simple work around.

First, create a new widget using the same type as the one you intend to use in the main UI: you want to "export" a group of widgets, so you probably have a container like the basic QWidget, QFrame or QGroupBox; ensure you select the correct type in the "New form" dialog.

Then, select all direct children of the widget in the original UI; it's probably easier to use the "Object inspector" for that: go to your widget and Ctrl+Click only the nodes that are its direct children.

Now keep pressed Ctrl and drag those widgets into the new form created before, so that they will be copied there. Note that the main layout of the original widget is not copied as well, so you need to set one for it.

All the above can be also achieved by using the clipboard: just do Ctrl+C on the original UI and Ctrl+V on the new form (or any key sequence used for copy/paste on your OS).

Keep in mind, though, that if you intend to use the newly created "custom widget" in your original UI, then you cannot use the original widget with its own children: the original widget will have to become a promoted one (based on the new custom widget), and shall have absolutely no contents in it, because they will be created by the actual promoted class of the custom widget.

This means that you need to remove all its children and unset its layout. This will leave you with a blank placeholder for the custom widget, but this will only happen in Designer: once you actually run your code with the proper widget promotion and classes, the UI will contain the custom widget where it's expected to be.

If you're asking if there is a way to also use (therefore see and edit) the custom promoted widget in the UI, you can't: that's not how widget promotion is intended to work.

As explained in the comments, the main purpose of widget promotion is to extend an existing class. When promoting a standard class (eg: a QTableWidget), you can obviously see it in the UI because that class has predefined contents, but since you're promoting a container widget, which by default has no contents at all, there is no way to see its contents in the main UI, as those contents will only be created by the final class used for the promotion at runtime.

The only way to have a custom container widget that also shows its contents and is somehow editable, is through Designer plugins, but creating them is a difficult task, and almost always unnecessary.

Finally, keep in mind that following the above procedure is suggested only if the custom widget has a relatively complex layout of children.
Considering the example in your original answer, there's little point to do all that: a simple widget like that can be written as a QWidget subclass with its layout and children added by code, and it will probably need less than 30 lines of code. If you don't know how to do that, just open the uic generated code and learn from there how it's done.

No matter what, it's really important that you take your time to understand the purpose and behavior of promoted widgets, because from your question (and self-answer) it seems that you have some important misunderstandings about all that.

The issue is that PySide6-designer does not export the code of the promoted widget. This is because promoted widgets are not designed to work this way, but to reference external code. This however disallows the design and packaging of custom (promoted or not) widgets with their UI code from the designer itself.

However, there's a fairly simple workaround that I found in order to design and export the code for a custom widget directly from the PySide6-designer.

1. Design your widget in the Designer GUI

Create your widget in PySide6-designer as you would normally do from within your main dialogue form. For example, the following is a widget designed with sub-widgets in it.
Please consider that this custom widget can be quite complex and have many sub-widgets, and it can be very convenient to design it in the UI.

2. Promote the widget.

Select the widget and right click -> promote to. Set the class name to something like MyCustomWidget and the header file to a name like my_custom_widget (this will be the expected Python module name; i.e. the file containing the widget will need to be named my_custom_widget.py).

Now, when the main dialogue form code is exported (e.g. by doing pyside6-uic your_file.ui -o ui_your_file.py or Form -> View Python code -> Save), it will reference the promoted widget code by including a line at the top of the file:

from my_custom_widget import MyCustomWidget

Unfortunately, the export does not include the code of the promoted widget in a separate metadatarenamewidget.py file, as it only exports 1 file containing the main ui and none of the promoted widget code, which is merely expected as a import from a separate file.

Therefore, we will need the next step in order to get the promoted widget code.

3. Export the code of the promoted widget

This involves the following steps:

  • Create a new empty dialog form
  • Copy the promoted widget in the new empty dialog form, by selecting the widget and dragging-dropping it, or copy-pasting it.
  • Demote the copied widget by right click -> Demote to QWidget.
  • Export the code for the entire new dialog, which now contains the demoted widget: Form menu -> View Python code -> Save...
  • Save the code in a file named like my_custom_widget.py

The exported code will have a form like:


from PySide6.QtCore import ...

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        if not Dialog.objectName():
            Dialog.setObjectName(u"Dialog")
        Dialog.resize(1138, 300)

        # [...code of your promoted-demoted widget...]

Now, replace the class signature to go from Dialog class to QWidget class, matching the expected class name as per when we promoted the widget (MyCustomWidget), and deleting the Dialog-specific code which we don't need:

from PySide6.QtCore import ...

class MyCustomWidget(QWidget):
    def __init__(self, parent: QWidget | None=None):
        super().__init__(parent)

        # [...code of your promoted-demoted widget...]

Et voilà! Designed and exported the code of the widget directly from PySide6-designer.

This widget code will be correctly referenced by the main form dialog code.

I couldn't find any simpler way, which seems weird, but at least this works. Happy to get comments if there's any simpler solution.

发布评论

评论列表(0)

  1. 暂无评论