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

How to achieve Qt card based layout



  • How to create a card in qt like the image bellow dynamically? I tried using layouts and widgets, but it got messy. Widgets won't stay inside another widget in layout with it's alinment. I even used webEngine to design it in css and load the page. But I really I want it in ui. I'm afraid I will get suggestion on using QML, I'm not familiar with QML, but if someone thinks is the best choice with some instructions will be a good start. Thanks.
    b80c46d6-e4b6-4561-9410-a1c0885890aa-image.png



  • @mrjj Do you have any resource on how to start creating the custom widget? The listview you mentioned is it from Ui or QML? Thanks


  • Lifetime Qt Champion

    Hi
    If you create a custom widget with UI form you can easy just design it and then reuse from code.
    However, how many do you need to have ?
    Many of them say in a scroll view would get heavy on small boards etc but could handle 1000 on a
    Desktop class pc.

    The normal way would be to use a list view + a delegate to draw the card.



  • @mrjj Do you have any resource on how to start creating the custom widget? The listview you mentioned is it from Ui or QML? Thanks


  • Lifetime Qt Champion

    @Ucn_
    Its pure Widgets i was talking about but QML could also be used.

    I was bored so drinking some coffee and making sample. You can have it in a moment for reference.

    alt text


  • Lifetime Qt Champion

    Hi
    Here is custom Widget example.
    https://www.dropbox.com/s/pgf1mippucf36nb/cardTest.zip?dl=0
    Note its fast made so the like and comments are just labels with image.
    You need to use a button instead or
    https://wiki.qt.io/Clickable_QLabel

    Also, to the Card class, you should add access methods like
    setIcon
    SetText
    to be able to set the data from outside without touching the inner UI elements directly.
    Then its completely encapsulated and you can easily reuse it.

    Regarding the listview.
    Reading here will be a start.
    https://doc.qt.io/qt-5/model-view-programming.html
    You would then make a delegate to draw the Card and allow the needed editing, clicking.
    Its a system so some reading is required to understand it.


  • Lifetime Qt Champion

    Hi
    To Create a custom Widget is no more than selecting

    alt text
    (if you want with UI form so u can use designer)

    alt text

    Then you get a cpp , h and ui file with a Widget you can then customize.



  • @mrjj Thanks for the reference. I think my issue was that layouts were creating extra space when adding widgets. I'll stick with pure widgets, I'm not familiar with QML, but I'll have a look



  • Sorry, maybe a silly question, but where is ui->CardsLayout? I can't find it in the ui. Or no where except where you mentioned in the mainwindow.cpp


  • Lifetime Qt Champion

    @Ucn_
    well the scrollarea/layout will try to compress the widget etc so unless you set fixed size (a max height) on it - it will alter look a lot.

    Its in forms
    alt text


  • Lifetime Qt Champion

    @Ucn_

    sorry misread.
    The layout is in
    scrollAreaWidgetContents
    alt text



  • @mrjj I was looking for it. Thanks. I will play with it and try to implement based on what I want to achieve. I will not mark as the correct answer for now because I may have question regarding the example. So I can come back, I wouldn't like to create another post. I will mark after everything. Thanks for the help



  • @mrjj when creating Card instance "card":

        Card * card = new Card;
        ui->CardsLayout->addWidget(card);
    

    Is it possible to give different name each time it's clicked? maybe from a function parameter value or QString value. I'm asking this because later on I may want to removeWidget by name.

        ui->CardsLayout->removeWidget(card);
    

    It may remove all "card". So I would like to have different name for the instance every time is created. Thanks


  • Lifetime Qt Champion

    @Ucn_
    Hi
    You can call card->setObjectName("card1");
    Then have a std::map with names, and widget pointer.

    Is it just to be able to close it / delete it ?

    We could close it using only signals
    and slot but if you need other operations then using names might be easier.



  • @mrjj Yes I want to be able to replace the info or remove the widget by name if something changes. I will be giving the names dynamically. Also could you tell me how to make the widget appear on top when clicking add? It adds in the middle, I set the CardsLayout VerticalPolicy to fixed. It appears on top, but the height is not adjusting. It squeezes the picture. Thanks


  • Lifetime Qt Champion

    @Ucn_
    Ok, if it has to be by name, the objectname should work good.

    to have be at top.
    Add a vertical spacer to the ScroallArea widget
    alt text

    alt text

    and change addWidget to insertWidget
    ui->CardsLayout->insertWidget(0,card);

    to have it add to index zero so it comes before the spacer
    then it will push them up



  • @mrjj Thanks. It does the job. However, the card doesn't expand its height, it squeezes the rest if a new layout with widgets is added And ui->CardsLayout->removeWidget() won't take QString in the parameter. I came up with this solution, I created QVector-QWidget-cards*. And every time I add a widget to the layout I also append to cards. Then for deleting I do this:

    for (int i = 0; i < cards.size(); ++i) {
    if (cards.at(i)->objectName() == ui->lineEdit->text()){

            qDebug () << "widget found at " << i << cards.at(i) << cards.at(i)->objectName();
            delete cards.at(i);
            cards.removeAt(i);
        }
    }

  • Lifetime Qt Champion

    @Ucn_
    Hi
    The card has a fixed size set to prevent it from being compressed below the design size.
    You can just make it bigger if you need more room.

    The QVector is a fine idea, however, if you had many Cards to manage , i think i would have used
    std::map<QString, Card *> CardsMap;
    To avoid having to loop a list to find the one i want. std::map supports direct lookup
    but for a small set of Cards, it really dont matter.



  • @mrjj Thanks, I will give a try with map. About the size, I set the card sizePolicy to Expanding still squeezing.


  • Lifetime Qt Champion

    @Ucn_ said in How to achieve Qt card based layout:

    Expanding still squeezing.

    Yeah, it will be squeezed if many cards are added. You have to set a minimum Height to avoid that.
    On the Top Card in UI. So the laytout wont make it smaller if it can.
    Even when set to Expanding, its only when there are left over space , however, we add them next to each other so it tries to fit as many as possible and unless we say Not smaller than this, it might not look like we want to.



  • @mrjj This is what I'm trying to achieve:
    hover.gif


  • Lifetime Qt Champion

    @Ucn_
    Hi
    Well pictures help so much. :)
    You have to alter the Maximum Height to allow for the popup lineEdit.
    It seems its not allow to alter Card size so it will compress the other elements to
    make room.

    Ps. its looking good :)


Log in to reply