[Solved] Cannot access custom widgets loaded by uiloader



  • i've created a designer plugin with custom widgets. I can use them in the Designer.
    During run-time i want to load these widgets. But even though i can see my widgets in the created gui, i cant get access to them programmatically...
    @
    QUiLoader loader;
    loader.addPluginPath("."); //copied the designer lib to the path
    qDebug() << loader.availableWidgets(); //recognizes custom widgets

    QWidget* gui = loader.load(new QFile&#40;"form.ui"&#41;&#41;;
    //FlipButton is a customWidget derived from QToolButton
    QList<FlipButton*> flips = gui->findChildren<FlipButton*>(); 
    qDebug() << flips.size(); // prints zero
    qDebug() << flips;
    

    @

    Loading standard qt widgets, works fine.
    Printing them via
    @
    qDebug() << gui->findChildren<QWidget*>();
    @
    Shows ... FlipButton(0x8a8aa80, name = "flipButton") ...
    in the output, which suggests that the right custom class is created in memory.

    But how can i access them?
    Any help is greatly appreciated.



  • found a workaround.
    @
    QList<QWidget*> list = gui->findChildren<QWidget*>();
    foreach(QWidget* w, list)
    {
    customWidget* cw;
    if((cw=static_cast<customWidget*>(w)))
    //...
    }
    @

    alternatively use dynamic_cast or reinterpret_cast works
    aswell. Weird that qobject_cast always fails tho.
    Shrug


  • Lifetime Qt Champion

    Hi,

    If qobject_cast fails then there's something fishy going on. Can you provide a minimal compilable sample application that reproduce this behavior ?

    Also, which OS/Qt version are you running ?



  • Thank you for sharing a solution.
    Do you have Q_OBJECT define in your class?

    [EDIT]: Checked QObject source. qobject_cast has an assert if Q_OBJECT is not included. My questions is answered :-)



  • Im using Ubuntu 13.10 with Qt5.2.0 (32bit).
    I omitted the files mywidgetplugin.{h,cpp} mywidget.{h,cpp} for brevity. They were automatically created by wizard (new project->other project->qt custom designer widget)

    designer project file
    @
    CONFIG += plugin release
    TARGET = mywidgetplugin
    TEMPLATE = lib

    HEADERS = mywidgetplugin.h mywidget.h
    SOURCES = mywidgetplugin.cpp mywidget.cpp
    LIBS += -L.

    QT += designer

    target.path = /path/to/plugins/designer
    client.path = /path/to/client/
    client.files = libmywidgetplugin.so

    INSTALLS += target client
    @

    client project file
    @
    QT = core gui uitools widgets
    TARGET = untitled
    TEMPLATE = app

    INCLUDEPATH += /path/to/designerPluginProject
    VPATH += /path/to/designerPluginProject
    HEADERS += mywidget.h
    SOURCES += main.cpp
    @
    client main.cpp
    @
    #include <QApplication>
    #include <QDebug>
    #include <QUiLoader>
    #include <QFile>
    #include <QWidget>
    #include "mywidget.h"
    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    QUiLoader loader;
    loader.clearPluginPaths();
    loader.addPluginPath(".");
    if( !loader.availableWidgets().contains("myWidget") )
    qDebug() << "UiLoader did not read custom widgets library";

    QWidget* gui = loader.load(new QFile&#40;"form.ui"&#41;&#41;;
    gui->show();
    
    myWidget* mw = gui->findChild<myWidget*>();
    qDebug() << "Found a myWidget? " << (mw!=NULL);
    
    QList<myWidget*> mws = gui->findChildren<myWidget*>();
    qDebug() << "Found myWidgets? " << !mws.isEmpty();
    
    QWidget* qwidget = gui->findChild<QWidget*>();
    qDebug() << "Found qwidget? " << (qwidget!=NULL);
    qDebug() << "dynamic_cast to myWidget?" << (dynamic_cast<myWidget*>(qwidget)!=NULL);
    qDebug() << "qobject_cast to myWidget?" << (qobject_cast<myWidget*>(qwidget)!=NULL);
    
    qDebug() << "list childs : " << gui->findChildren<QWidget*>();
    return a.exec&#40;&#41;;
    

    }
    @

    form.ui
    @
    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
    <class>Form</class>
    <widget class="QWidget" name="Form">
    <property name="geometry">
    <rect>
    <x>0</x>
    <y>0</y>
    <width>402</width>
    <height>302</height>
    </rect>
    </property>
    <property name="windowTitle">
    <string>Form</string>
    </property>
    <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
    <widget class="myWidget" name="myWidget"/>
    </item>
    </layout>
    </widget>
    <customwidgets>
    <customwidget>
    <class>myWidget</class>
    <extends>QWidget</extends>
    <header>mywidget.h</header>
    </customwidget>
    </customwidgets>
    <resources/>
    <connections/>
    </ui>
    @

    When running client it prints:
    @
    main-Found a myWidget? false
    main-Found myWidgets? false
    main-Found qwidget? true
    main-dynamic_cast to myWidget? true
    main-qobject_cast to myWidget? false
    main-list childs : (myWidget(0x863f438, name = "myWidget") )
    @

    Im also not sure why i need to add VPath in client.pro
    Thanks for helping :)



  • Got it! Wasnt linking against the plugin. Thought Qt would do it automatically...

    client project file
    @
    //...
    INCLUDEPATH += /path/to/designerPluginProject
    LIBS += -L. -lmywidgetplugin
    @

    When running client it prints:
    @
    main-Found a myWidget? true
    main-Found myWidgets? true
    main-Found qwidget? true
    main-dynamic_cast to myWidget? true
    main-qobject_cast to myWidget? true
    main-list childs : (myWidget(0x94200f8, name = "myWidget") )
    @


  • Lifetime Qt Champion

    IIRC you should have two libraries, one containing your widget and the other that is the current designer plugin. So you link your project to the library and not the plugin and you can update the library without the need to recompile the plugin (unless e.g. you are adding new widgets)



  • Let my try rephrase for understanding:

    create designer plugin containing custom widgets

    create shared/static library which also contains the widgets

    link project against the second

    The advantage of this approach:
    I can change the implementation (.cpp) of my custom widgets in the second library as long as the interface (.h or public stuff + properties) does not change with having to touch the designer lib.
    Object if wrong!


  • Lifetime Qt Champion

    I object ! But you almost got it

    Here is the right order:

    Create library containing the widgets

    Create designer plugin linking to that lib

    Link project to the first

    So you have only one lib containing the widgets



  • Ah, that makes sense!
    Thank you :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.