Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

PyQt5 - How to create widgets on a thread then move it to the GUI thread?



  • I'm working on an application and there is a long operation that I moved to a thread, but it stills get stuck because of when creating widgets based on the result of that long operation, so I moved the widgets creation to that thread so when it finishes I can grab that widget and display onto the main window.
    But I get:

    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QApplication(0x1f5e760), parent's thread is QThread(0x1cc7df0), current thread is QThread(0x2267a10)
    QObject::setParent: Cannot set parent, new parent is in a different thread
    

    So my question is: can I create somehow widgets that have NO parent so I can whenever I want set to them a parent on a different thread? There is another way of doing what I need? Or i CAN'T do it?



  • @Patitotective
    You cannot and should not either create or re-parent or use or whatever any widgets in any thread other than the main UI one. That's a general requirement in Qt. Whenever this is brought up the answer is always: you cannot do anything widget-wise in a sub-thread, all you can do is send signals to the main UI thread to get it to do what you would like. Even if there is some limited, contorted way to do it, I think others will ask for your use-case and advise an alternative sticking to the non-UI-widgets-in-thread principle.



  • @Patitotective
    You cannot and should not either create or re-parent or use or whatever any widgets in any thread other than the main UI one. That's a general requirement in Qt. Whenever this is brought up the answer is always: you cannot do anything widget-wise in a sub-thread, all you can do is send signals to the main UI thread to get it to do what you would like. Even if there is some limited, contorted way to do it, I think others will ask for your use-case and advise an alternative sticking to the non-UI-widgets-in-thread principle.



  • @JonB Thanks for the answer. I guess app users will have to wait some time.



  • @Patitotective said in PyQt5 - How to create widgets on a thread then move it to the GUI thread?:

    I guess app users will have to wait some time.

    Not sure what you mean. If you use the standard technique of sending a signal from a processing thread to the UI thread, and have that do whatever in the way of creating & showing a widget, it should be perfectly responsive.



  • @Patitotective said in PyQt5 - How to create widgets on a thread then move it to the GUI thread?:

    creating widgets based on the result of that long operation

    Couldn't you create most of the widgets in advance?
    And then when long operation is done just pick the required ones and maybe update labels/values on them?
    What that "pre-factory" approach save you some time when displaying "all the widgets"?
    But as @JonB mentioned, you may want to use signals from "long operation" back to GUI thread to keep it responsive as the background process moves on



  • @Pablo-J-Rogina The widgets to create are not on my control, they can be 10 or hundreds.



  • @Patitotective said in PyQt5 - How to create widgets on a thread then move it to the GUI thread?:

    they can be 10 or hundreds

    And you really think it's a good UX to have hundreds of widgets in the same screen?



  • @Pablo-J-Rogina How can avoid displaying hundreds of widgets?
    What I'm doing it's an API Reference creator (for Python modules) so I need to inspect a Python module that can have "infinite" members.
    Any optimization recommendation is very welcomed.


  • Lifetime Qt Champion

    Hi,

    Are you trying to implement a tool that generate diagrams like graphviz ?



  • @SGaist PyAPIReference creates a tree of collapsible widgets that you can convert to a markdown file and edit it.
    e.g.:
    If you load this module:

    version = "v1.0"
    def say_hi(name: str, last_name: str) -> str:
        print(f"Hi {name} {last_name}")
    

    You will get:
    Screenshot from 2021-09-25 14-17-10.png

    Then you can convert it to a markdown file and edit it to create your API Reference.



  • @JonB I think the part where my application get stuck is when creating widgets because in a thread I calculate some stuff, then using that stuff I create some widgets. So I don't see how it will get better if I send signals to create the widgets, I mean, I'm not doing anything else rather than creating widgets because I did already calculate the data.
    Or are the Python for loops it selves freezing the app? And I should try to send signals to create the widgets?


  • Lifetime Qt Champion

    @Patitotective As already said: do not create widgets in other threads than main/UI thread! This is simply not supported! Proper way to handle this is to emit signals from the other thread which are connected to slots in main thread. In these slots you can create the widgets.
    "Or are the Python for loops it selves freezing the app?" - if those loops are in main thread and take long then yes, they block the Qt event loop. But with signals/slots you do not need such loops in main thread...



  • @Patitotective said in PyQt5 - How to create widgets on a thread then move it to the GUI thread?:

    a tree of collapsible widgets

    If I may suggest, why don't you create a list or table of all the function/methods for a particular module, and then if the user is interested in one row in particular, by double clicking it a dialog is displayed with all the information related to such method in the selected row.

    This way "all the widgets" to create are reduce to just 10, maye 20 widgets, the ones needed to show information for "say_hi" in your example.

    So the whole process is reduced to two parts: parsing the Python code and storing information for it (maybe a JSON model or a SQLite DB) and then displaying such information (using Model/View programming perhaps?)



  • @Pablo-J-Rogina I will try to only generate the first three layers of collapsible widgets, then if you click on a collapsible widget that is in depth 3 it generates its childen till the third layer again.


Log in to reply