Results 1 to 14 of 14

Thread: QUiLoader flawed/not providing name for Layouts. Workaround?

  1. #1
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default QUiLoader flawed/not providing name for Layouts. Workaround?

    I have an interface built with the Designer in which I have a layout that contains some widgets. I need to programatically get a pointer to this layout so that I can insert a QScrollArea, because it is not available (forgotten?) in the Designer.

    When using the UIC tool I get both a name (even though the Designer does not write one in the .ui-output) and the convenient pointer needed, however I have switched to using the QUiLoader and this is where I run into problems, because it does not function in the same way the UIC tool does as you would expect; it will not provide pointer nor name.

    Calling findChild( ) with the name that the UIC otherwise will construct gives a null pointer, as does calling layout() on one of the widgets placed inside my layout (I was told this is a normal behaviour though I can not understand why). How do I work around this?

    Thanks

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Quote Originally Posted by ZB View Post
    I need to programatically get a pointer to this layout so that I can insert a QScrollArea, because it is not available (forgotten?) in the Designer.
    It's not forgotten. It's not there for a reason - QScrollArea is rarely used without subclassing. If you really need QScrollArea, make a simple plugin for Designer to make it available.

    Calling findChild( ) with the name that the UIC otherwise will construct gives a null pointer, as does calling layout() on one of the widgets placed inside my layout (I was told this is a normal behaviour though I can not understand why). How do I work around this?
    layout() returns pointer to a layout which manages children of a given widget, so you need to call layout() on the parent widget instead.

  3. The following user says thank you to wysota for this useful post:

    ZB (1st October 2006)

  4. #3
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Thanks, when doing this I get a pointer back rather than 0, however the application still crashes when trying to add my QScrollArea to the layout. Any hints?

    EDIT: First time I tried layout() on the central widget I got a valid pointer, but consecutive runs yield a 0 pointer like previously :S

    Main
    Qt Code:
    1. int main(int arg_count, char **arg_list)
    2. {
    3. QApplication juliet(arg_count, arg_list);
    4. QApplication::setStyle(new QPlastiqueStyle);
    5.  
    6. mainwindow ui;
    7. ui.show();
    8.  
    9. return juliet.exec();
    10. }
    To copy to clipboard, switch view to plain text mode 


    Class header
    Qt Code:
    1. class mainwindow:public QMainWindow
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6.  
    7. mainwindow();
    8.  
    9. QScrollArea *render_window;
    10. QLabel *label_render;
    11. QGridLayout *render_layout;
    12.  
    13. ...
    14.  
    15. };
    To copy to clipboard, switch view to plain text mode 


    Class implementation
    Qt Code:
    1. mainwindow::mainwindow()
    2. {
    3. QUiLoader loader;
    4. QFile file(":/interface/juliet.ui");
    5. file.open(QFile::ReadOnly);
    6. QWidget *central = loader.load(&file);
    7. setCentralWidget(central);
    8. file.close();
    9.  
    10. label_render = findChild<QLabel*>("label_render");
    11. render_layout = qobject_cast<QGridLayout*>(central->layout());
    12. render_window = new QScrollArea;
    13.  
    14. QPixmap pixmap(200, 200);
    15. pixmap.fill(Qt::black);
    16. label_render->setPixmap(pixmap);
    17. label_render->setAlignment(Qt::AlignCenter);
    18. render_window->setWidget(label_render);
    19. render_window->setWidgetResizable(true);
    20. render_window->setFocusPolicy(Qt::NoFocus);
    21. render_window->installEventFilter(this);
    22. render_layout->addWidget(render_window, 0, 0, 1, 4); // <-- Application crash
    23.  
    24. QMetaObject::connectSlotsByName(this);
    25. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by ZB; 30th September 2006 at 23:27.

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Qt Code:
    1. render_layout = qobject_cast<QGridLayout*>(central->layout());
    To copy to clipboard, switch view to plain text mode 
    Does this return a valid (!=0) pointer?

    Did you try running the code under debugger and checking the backtrace?

  6. #5
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Very sorry, I was not being clear; that pointer is indeed a null pointer (except in a single odd run where it was non-zero) and I am clearly aware this is the reason my code crashes since obviously I can not reference data outside bounds.

    The code was just an excerpt to shed some light of what I am doing, my real question is how to get around this problem QUiLoader introduces - how to obtain the layout-pointer. If there is no easy way then I will simply go back to using UIC output again.

    Thanks

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Quote Originally Posted by ZB View Post
    Very sorry, I was not being clear; that pointer is indeed a null pointer (except in a single odd run where it was non-zero) and I am clearly aware this is the reason my code crashes since obviously I can not reference data outside bounds.
    Maybe the layout is not a grid layout but some other kind of layout?

  8. #7
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Thanks for your help, Wysota. I have been working some more with this, and it seems the only way I can get hold of this QGridLayout in my case is with some dirty code:

    Qt Code:
    1. QList<QGridLayout*> grids = findChildren<QGridLayout*>();
    2. render_layout = grids[1]; // 0 = central widget layout, 1 = outer most layout which i need
    To copy to clipboard, switch view to plain text mode 

    Some observations:

    • It was not possible to retrieve the layout by any means of calling parent() or layout() on actual or parental widgets, Though there may be some workaround I have not found.
    • Calling findChild<QGridLayout*> with the standard name constructions for layouts in some cases yielded non-zero pointers, but they were all wild and caused program crashes. This appears to be a bug, but there might be some explanation to it.
    • GUiLoader does not provide the same functionality as the UIC tool as one would expect; the UIC will give layouts a standard name construction, the GUiLoader will not.
    • The Qt Designer does not expose QObject::objectName for layouts. It will set a name when dropping a layout widget, but not when dropping it on a group of selected widgets. Regardless, it will ignore objectName property when saving the form.

    Conclusion:

    • Solution: Qt Designer must expose objectName for layouts so users can programatically obtain and use the layout in a safe way. The Designer must also be changed so it outputs this property when saving forms.


    I will fiddle with this a bit more and probably send a bug-report/feature request.

  9. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Quote Originally Posted by ZB View Post
    Solution: Qt Designer must expose objectName for layouts so users can programatically obtain and use the layout in a safe way. The Designer must also be changed so it outputs this property when saving forms.
    Are you sure this is necessary? The layout can always be retrieved using QWidget::layout() on a proper widget, so it is enough to have the name of the widget itself and then fetch its layout. If a layout is working, it has to be set as a widget's layout or a sublayout of this layout. Layouts can't be standalone - that's why an additional widget is created by Designer for "floating" layouts, so that they can be accessed through the widget interface.

  10. #9
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Maybe you can solve this for me once and for all, and we can conclude if it is lack of knowledge or a syntactical error on my part, or a bug/flaw in either the QUiLoader or the Designer :-)

    My form is a QMainWindow, placed top-most in it I have a QGridLayout containing a few widgets, and I need a pointer to this grid layout. The following things are not working:

    (The form and other code is correct, because it will create, display and function properly when I obtain the pointer using previously pasted code)

    Qt Code:
    1. pointer = qobject_cast<QGridLayout*>( (qobject_cast<QLabel*>( topmost_label_inside_layout->parent() ))->layout() );
    2. pointer = qobject_cast<QGridLayout*>( central_widget->layout() );
    3. pointer = qobject_cast<QGridLayout*>( main_window->layout() ); // long shot
    To copy to clipboard, switch view to plain text mode 


    Putting my grid layout inside an additional dummy widget to solve this is not an acceptable overhead, sorry to say :S

  11. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    What do you mean by that the grid layout is "placed top most in it"? Did you do that in Designer? If, then how? You should apply the layout to the widget itself, not "place it in the widget". I mean you shouldn't have a red rectangle visible inside the central widget. Could you attach the ui file (if you have one) here so that we can check it? If my guesses are correct, then you have placed an additional widget in the window yourself and that's precisely why it is not working... I may be wrong though, so I'd like to see that ui file (or the code you used to generate that hierarchy, if you're not using Designer there).

  12. #11
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    I drew widgets right inside the central widget, selected some of them and applied a grid layout on them, and then applied a grid layout to the entire window itself. Is this wrong? This is how it was done in the demo video on trolltech.com, and sure enough the interface behaves perfectly.

    I have not seen any mentioning that you should place dummy widgets around every single layout that shares hierarchy level with other widgets. It seems superfluous and as far as I can see the only benefit would be that you can specify a unique name for every dummy widget so that you programatically can find the layout manager inside it, which in itself is alot of extra work aswell as contradictory to how some parts of Qt work. Simplest and most convenient way would still be to expose objectName in layouts so you can acquire the layout safely and with minimal amount of work.

    Simplified version of the interface file is attached.
    Attached Files Attached Files

  13. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Quote Originally Posted by ZB View Post
    and sure enough the interface behaves perfectly.
    It doesn't as you can't access the layout

    I have not seen any mentioning that you should place dummy widgets around every single layout that shares hierarchy level with other widgets.
    I didn't say you should. Designer places floating layouts into QWidgets to be able to save the file. There is a thread on this forum which mentions that.

    Simplified version of the interface file is attached.
    So which layout you want to access?
    Last edited by wysota; 1st October 2006 at 16:24.

  14. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    I guess this might be what you wanted. Seems to work fine for me...

    Qt Code:
    1. #include <QApplication>
    2. #include <QUiLoader>
    3. #include <QFile>
    4. #include <QLabel>
    5. #include <QLayout>
    6. #include <QGridLayout>
    7.  
    8. int main(int argc, char **argv){
    9. QApplication app(argc, argv);
    10. QUiLoader loader;
    11. QFile file("temp.ui");
    12. file.open(QFile::ReadOnly);
    13. QWidget *widget = loader.load(&file, 0);
    14. if(!widget) return 2;
    15. QWidget *l = widget->findChild<QWidget*>("centralwidget");
    16. if(!l){
    17. qDebug("widget not found");
    18. delete widget;
    19. return 2;
    20. }
    21. QLayout *lay = l->layout();
    22. if(!lay){ qDebug("widget has no layout"); return 2; }
    23. QGridLayout *grid = qobject_cast<QGridLayout*>(lay);
    24. if(!grid){ qDebug("Not a grid"); return 2; }
    25. grid->addWidget(new QLabel("TESTING"), 0, 0, 1, 4);
    26. widget->show();
    27. int r = app.exec();
    28. delete widget;
    29. return r;
    30. }
    To copy to clipboard, switch view to plain text mode 

  15. The following user says thank you to wysota for this useful post:

    ZB (1st October 2006)

  16. #14
    Join Date
    Sep 2006
    Posts
    19
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QUiLoader flawed/not providing name for Layouts. Workaround?

    Thanks alot for taking your time to write this code, I see now it is doable just like you said, as long as you have that central widget to start from. My two lines of dirty code is convenient even if they are not very appreciating of changes in the the UI-file, and in any case I hope you agree that the possibility to replace all of this with findChild("my_layout") is attractive, even more so considering that you would not need dummy widgets as "search words" when having multiple layouts in the same hierarchy level.

    The layout object inherits QObject and both the Designer and UIC tool set and provide names for layouts in certain cases - Qt just need to go all the way with this. I will ask Trolltech for this feature and hope they agree with me :-)

    Thanks alot again for your help, Wysota.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.