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

Widget in a QListView



  • Hi! So, I have this problem: I have a QListView with QStyledItemDelegate. What I want to do is paint a widget for each item and it should be able to receive events (for example, if that widget is a button, it would be possible to click it).

    So far, in the paint method of the delegate, I initialize the widget and do

    widget.render(painter, targetOffset=option.rect.topLeft())
    

    This paints the widget, but there's no way to interact with it. I thought, is there another way? Maybe I could somehow redirect the events to the widget? But how? Need help on this.

    PS I need to use QListView with a delegate for speed (as there's no limit on the size of the model) and flexibility.

    PS2 If there are ways to do this without delegate, I guess I might sacrifice some flexibility after all (QListWidget won't let me set a custom model, so that one won't work).


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    This stack overflow answer and the answer linked there is likely what you are looking for.



  • @SGaist Thank you! That link's gonna turn up useful very soon for me for some specific tweaking.

    But what about widgets whose structure I don't know in advance? Is there a simple way to make it interactive? Is it maybe possible to set the editor of the item to be a widget? Like make it a full-blown widget on mouse-over and restore the state when the mouse leaves the item area?



  • @mrjj Also, found in this thread that

    You can also cheat and use render() if you have a lots of widgets in one cell. But that uses memory since each items then has an image to maintain.

    Why does that work that way? Why would each item (of the whole model?) have to maintain an image? Doesn't the delegate just repaint the widget every time based on the need and that's that?


  • Lifetime Qt Champion

    @coaxmetal
    Hi
    The delegate only uses real widgets when in edit mode. (as in one row at a time)
    The rest of the time, the Delegate must paint a look-alike of the Widget
    using QStyle/QPainter calls. So the cheat is let the widget render to an image and show that instead of painting it with paint calls.

    If it uses real QWidgets all the time, it would have the same bad performance as
    setCellWidget (that places a real Widget on top of the cell for all rows )

    So a Delegate is to avoid using setCellWidget as that is very heavy on large lists and/or small IOT boards.



  • @mrjj I see, thanks for the clarification, I just misunderstood you the first time around!

    By the way, I am wondering, say, if all I wanted to render is a bunch of labels in each item, is it going to be much faster if I draw them myself using QPen, fillRect etc versus putting them as QLabels in a widget with a custom layout? Widgets+QLabels would be more generic and easier, but speed is of major importance. I guess, one has to check, but maybe someone has tried that before...


  • Lifetime Qt Champion

    @coaxmetal
    Hi
    Why would you use Labels in the cells ?
    The normal CellDrawing can draw the text already ?
    For RichText Support or what is the use case ? (if i may ask)
    (ahh for multiple texts (non editable) in same cell ?)

    From my tests, yes QLabel is slower (due to more checks/options/code )
    than a few QPainter Calls. But it all depends.
    You can see its paint here
    https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qlabel.cpp.html
    line 999



  • @mrjj

    (ahh for multiple texts (non editable) in same cell ?)

    yes, this one : ) I have a flow of generic data, meaning QTable wouldn't work, so doing it this way.

    You can see its paint here
    https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qlabel.cpp.html
    line 999

    Yeah, I see, that's quite a function there, better paint it myself then.

    Thank you!

    PS Looks like the best way to display a widget without setItemWidget is to employ the editor in the delegate to display actual interactive widget on editing. For anyone finding this and doing the same, look at StarDelegate example, at the very minimum you will have to redefine flags() function in your view to indicate that an index is editable and also the createEditor to return the widget which will be drawn over the item (StarDelegate has this). So, marking as solved.


  • Lifetime Qt Champion

    @coaxmetal
    Hi
    Ok You might have other requirements making a Delegate the way to go.
    Yes, the Starelegate is the usual sample we refer to. And yes
    the design of the Delegate API is to use CreateEditor to use a real widget for editing and then draw the rest of the time. (fake it , one could say )

    Just a a note. It can display multiple lines of text ready. ( if it has newlines)

    int main(int argc, char **argv)
    {
        QApplication app(argc, argv);
        QTreeView view;
        QStandardItemModel *model = new QStandardItemModel;
        // Prepend 4 rows into the model
        model->insertRows(0, 4);
        // Prepend 4 columns into the model
        model->insertColumns(0, 4);
    
        for (int row = 0; row < 4; row++) {
            for (int col = 0; col < 4; col++) {
                // Return a model index for the given row and column.
                QModelIndex index = model->index(row, col);
                // Set the index's data to the specified value
                model->setData(index, QVariant("hello\nnextline"));
            }
        }
    
    
        view.setModel(model);
        view.show();
        return app.exec();
    }
    
    

    alt text



  • @mrjj Thanks for the newline example, but yeah, I am planning for some other requirements (coloring, custom arrangements, no-columns etc.)


Log in to reply