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

Subclassing QTableWidgetItem and QTabWidget to add QTabWidget in QTableWidget



  • The aim is in the subject. I want to be available to add multiple items at the same cell in my table and display this behaviour using a tab. I don't know much about subclassing but I eventually get this compilable solution which does not work though (nothing is displayed).

    Part of my header (the rest is the parent widget (window) class) :

    class CustomItem : public QTableWidgetItem, public QTabWidget
    {
    public:
        explicit CustomItem();
    };
    

    Concerned parts of my cpp

    CustomItem::CustomItem() : QTableWidgetItem(), QTabWidget()
    {
    }
    
    void PlanningWindow::changeDay()
    {
        // clear the QTableView contents
        view->clearContents();
    
        CustomItem* testCustom = new CustomItem();
        testCustom->addTab(new QLabel(), "Works !");
    
        view->setItem(15,0,testCustom); // does not display anything in the corresponding cell of my QTableView
    }
    

    Thank you for your help and/or suggestions.



  • @rand10cs said in Subclassing QTableWidgetItem and QTabWidget to add QTabWidget in QTableWidget:

    I don't know much about subclassing

    :)

    class CustomItem : public QTableWidgetItem, public QTabWidget

    You should keep sub-classes separate. You don't want/can't have a class which is somehow both a table widget item and a tab widget. At least in my opinion. If you need to sub-class both of these, I would do it in two separate sub-classes, one for each.

    I'm not sure how your whole idea is supposed to work. A QTableWidget has an inbuilt model, and each item/cell stores/displays what is one index into the model. I don't know how your individual cell in the model is going to hold data such that it maps to/from your multi-item tab widget.


  • Lifetime Qt Champion

    Hi

    • add multiple items at the same cell in my table and display this behavior using a tab.

    Im not really sure how this is supposed to work?

    So inside the cell, there would be 2 tabs and if you click one, it shows value one and if you click tab2 it shows value 2
    or what was the idea with this? It sounds a bit o.O and would take up way to much space in a cell. the cells would have to be huge for this.



  • @JonB By reading you, I understand in some way that I can't do what I want. I "merged" the inheritance because I want to pass a QTabWidget as item of my QTableWidget but QTableWidget only accepts QTableWidgetItem.

    I thought about another possibility. Is it possible to do something like that while keeping my QTableWidget ? If no, what should I use and how could I do it ?
    Screenshot 2021-05-30 at 14.14.20.png

    Actually, in my project, :

    • the whole blank rectangle in the picture refers to a QTableWidget
    • the hours on the left refer to the vertical header labels of my QTableWidget (along with half hours I added in between each time)
    • each half an hour is a row of my QTableWidget

    The problem is that if I want to do that straighforwardly, I span my cells from Row#1 (8h30) to Row#20 (18h00) and add the green event. But when I add the blue event at 15h00 and I span from Row#14 to Row#18, it is either hidden by the green event or downright not added at all.

    @mrjj Yeah that's the idea. My cells are large enough I think. In my example above, it would create a tab when two events start at the same time (each half hour being a row). The easiest solution would have been to use several columns instead but it is not possible since it could use too many columns when like 5 or 6 events starts at the same time.



  • Can someone kindly help me with that ?



  • @rand10cs
    Whether using a QTableWidget for this is the best or you would be better with something custom I don't know. Someone like @mrjj may see this and comment.

    The problem is that if I want to do that straighforwardly, I span my cells from Row#1 (8h30) to Row#20 (18h00) and add the green event. But when I add the blue event at 15h00 and I span from Row#14 to Row#18, it is either hidden by the green event or downright not added at all.

    I don't imagine QTableWidget spanning allows that. You have "overlapping" rows now from 14--18. I would have thought you would have to "split" the first event into two: 8:30--15:00 and 17:00--18:00. You seem to want something which allows multiple layers/overlaps. Hence why this may not be the best widget to use.



  • @rand10cs I think it's doable but not easy.
    Mind you, I never tried to design something that would work that way but...

    I'd drop TableWidget in favour of TableView/ListView and deploy a model. Can be simple one, doesn't matter. Now, sticking to your calendar example...
    I can see how this can work with a db (can be Sqlite - I work with dbs mostly so it is easier for me to think that way but how you implement the model is absolutely your thing).
    I'd create two tables - one with simple one row per hour design (more on that later) and second table holding just the events - columns id, description, colour and whatever else you need.

    Now, back to first table - I'd give a column for datetime (24 rows per day), id of the event (if any, can be null). If the future day doesn't have the event the day doesn't exist in the table, if future event is created all the days between the end of the table and the event (up to the end of the day on the event day) are created.

    This can probably be simplified somehow, I am writing as I think...

    Now the display can be held as a delegate on per row/hr basis - if the "event id" column has the data the field is painted in corresponding colour, if more events are present (comma separated list?) the display is responding painting over the colours with the shift to right by a few pixels and the newest/latest added on top.

    It's just an idea and with the db approach would probably require either internal sql query from the delegate to the event table (dirty, don't like it) or QSqlRelationalTable and delegate to work.

    Doable I think. (don't shoot if I made some grave errors, it's just a thought experiment)



  • Thanks for your deep reply ! The good thing is that I already have a model in which my events are stored (actually I started with a TableView alongside but there were displaying problems so I switch to a TableWidget displaying only few information about an event). I can then take this model as a basis for further displaying.

    @artwaw said in Subclassing QTableWidgetItem and QTabWidget to add QTabWidget in QTableWidget:

    Now the display can be held as a delegate on per row/hr basis - if the "event id" column has the data the field is painted in corresponding colour, if more events are present (comma separated list?) the display is responding painting over the colours with the shift to right by a few pixels and the newest/latest added on top.

    I think this quoted paragraph is very interesting and should do the work at first sight. However I can't get how you would implement it. I mean what would you exactly use to design it ?

    Thanks again for your time



  • @JonB said in Subclassing QTableWidgetItem and QTabWidget to add QTabWidget in QTableWidget:

    I would have thought you would have to "split" the first event into two: 8:30--15:00 and 17:00--18:00

    The only (big) drawback of that is that I can handle multiple events starting at different times but ending at the same time... Thanks for the suggestion though



  • @rand10cs said in Subclassing QTableWidgetItem and QTabWidget to add QTabWidget in QTableWidget:

    I mean what would you exactly use to design it ?

    Short answer would be "my brain, my keyboard and Qt Documentation" but I think I know what you mean.

    As I hope you are aware from here https://doc.qt.io/qt-5/model-view-programming.html model is responsible for holding the data, the delegate for rendering the single unit of data (let's say) and the view for displaying the rendered content to the user, if you allow me to simplify that much.

    My approach would be to create descendant of QStyledItemDelegate that would handle rendering of a single cell (in QTableView) or a row (in QListView). Creating custom delegates is well documented under the links in this post.

    The real problem is how to get the data for the delegate - as I said in my previous post all depends on how you store the data. But there is plenty of options readily available - for example data roles in model, we have Qt::BackgroundRole that can be set upon event creation (this way the single cell/row/hr will hold the latest colour only though)... That all depends on how you design it.



  • @artwaw Alright thank you I will have a try. I'll comeback to you when I succeed or if I'm eventually stuck.



  • I come back to give y'all what I finally succeed to do. I struggled a lot understanding and above all trying to apply something convenient with delegate. It is still very abstract to me.

    In order to design something answering my issue, I added a fixed number of narrow columns next to each initial column of my QTableWidget. This is somehow limiting the number of events that can happen in the same period but it should not impact the way I will use it though.

    Thanks to that, I have been able to manage something like this which is now perfectly functional (up to 4 events in the same period but I could have added more narrow columns to manage more parallel events).

    Screenshot 2021-06-10 at 12.59.26.png

    Thanks you all for your help again and hope this can help someone else in the future !


Log in to reply