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

Calendar Week and Day views, need advises



  • Hi,

    I'm new in QT dev and start to develop an application where I need to manage events and display them to Week and Day calendar view.
    As calendar widget support only month view I want to develop custom widget for each view.

    My problem is I do not know what is the best solution or even a working solution to create for instance a view for a day, where I can add, remove, drag and drop .... events.

    I was thinking that maybe that a list view to manage the day view and table view to manage week view could do the job.

    I will really appreciate any hints from you if you have good enough (and surely better than me) in QT dev to have a better overview of a good solution.

    Just for information, the events are coming from an API REST and events created and modified will be save to this API, I think it will not do any difference but I prefere mention it.

    Thank's a lot for any advise.



  • While QCalendarWidget uses the model/view concept and you could use the same using a tree model, a custom view and a custom delegate, I think the easiest way to implement something similar to Google Calendar is using the QGraphicsScene framework instead



  • Thank you for your reply. I come back a long time after your response but I needed to learn more Qt to go further with my application.

    So now my App has growing up with a lot a functionality but I'm still stuck with my Calendar views.

    I finally managed the Day and Week view by using QTableView with a custom model from QAbstractTableModel. This model manage the layout of the QTableView with the needed rows and column, and also manage the headers and background color for working hours.
    Next to I created a a delegate from QItemDelegate where I'm able to manage the split cell lines. It looks nice and exactly with what I want

    So here is the result for week:
    week view
    for day:
    day view

    Now I need to add Events on this view and it where I'm stuck. I tried to add a simple QWidget with a label and set a background color, then finally add them to the table (and not the model...) like this.

             QWidget *eventWidget = new QWidget(ui->dayTable);
             eventWidget->setStyleSheet("background-color:rgb(145, 37, 5);"); 
    
            QLabel *label = new QLabel(eventWidget);
            label->setStyleSheet("QLabel { font-size : 11px; }");
            label->setText("John Doe");
    
            QVBoxLayout *eventLayout = new QVBoxLayout(eventWidget);
            eventLayout->addWidget(label);
            eventLayout->setMargin(2);
            eventWidget->setLayout(eventLayout);
    
            ui->dayTable->setIndexWidget(ui->dayTable->model()->index(hours * 3 + minutes / 20, 0), eventWidget);
    

    Then I get my Widgets render inside the table. Great! But I need for instance to change the size of some of event according to start and end date (maybe an event must cover 3 cells and not only one), so how I should manage the events inside the table ?
    I also want to have actions from right click on events and show a popup menu, and also want to be able to drag and drop the event.
    I'm also not able to delete the widgets on the table. Finally I also need to manage placement with more than one event in the same place. A lot of questions :'(

    Any idea from your side ?

    Here is a final result:
    day view events

    In the example we see that the Event call Vasseur Astrid should start at 10:00 and finish at 11:00 (take 3 cells) but I do not know how to manage that.

    Thank you in advance to taking time for an answer which would be really helpful.



  • @Gulivert

    Vasseur Astrid should start at 10:00 and finish at 11:00 (take 3 cells) but I do not know how to manage that

    It looks like you want that item to span more than 1 row downward. Just as you can make item span multiple columns you can do that for rows too. See https://doc.qt.io/qt-5/qtableview.html#setSpan

    If that does not work well for what you want (and it may not), you may have to look into creating multiple elements for one event at different times. There are pros & cons to doing it each way, design what you will need first.



  • @JonB
    Thank you for your quick answer.

    setSpan is to merge cells together, am I right ?
    If I have correctly understand this will not help me in case I have to show two events in same cell. Or did I miss something?



  • @Gulivert
    I think of setSpan() as allowing a single cell to span multiple columns, or in this case multiple rows. The idea being to get a single cell to occupy the 10:00, 10:20 & 10:40 cell rows (or something like that), which I believe is what you were asking for? I don't think it matters whether you think of it as "spanning" or "merging" cells.

    in case I have to show two events in same cell

    Well, you're going to have problems with your simple representation if you need that, depending on exactly what you want. Since it allows you to span your rows by column, if you do have multiple events you could place them in separate columns, one with multi-row span and the other with single row, and that should still work for what you have in mind?



  • OK I finally managed my view to be ok. I finally will never have any double events for the same hours then it is now a bit more easy to manage events placement and span the cells correctly by event.

    But I still have one last problem. When I delete an event on the table the application crash if my Calendar view is updated (Like changing the current date, then the table is updated to show the new date).

    Here is what I do to create the event and to delete it :

    foreach (const QJsonValue &value, appointmentsArr) {
            QJsonObject appointmentObj = value.toObject();
    
            // Create event model
            Event *event = new Event(appointmentObj); // create a new event from model
            event->setPosCol(QDate::fromString(appointmentObj["start_date"].toString(), Qt::ISODate).dayOfWeek() - 1);
    
            // Create event EventLabels for calendar table views
            EventLabel *eventLabel = new EventLabel();
            eventLabel->setEvent(event);
    
            // Add event labels to eventLabels list
            this->eventLabels.append(eventLabel);
    
            // Connect labels for mouse events
            connect(eventLabel, &EventLabel::doubleClicked, this, &CalendarView::onEventDoubleClicked);
            connect(eventLabel, &EventLabel::modifyActionClicked, this, &CalendarView::onModifyActionClicked);
            connect(eventLabel, &EventLabel::deleteActionClicked, this, &CalendarView::onDeleteActionClicked);
    
            // Span table cells for event label if needed
            if (eventLabel->getEvent()->getSpanRow() != 1) {
                ui->calendarWeekTable->setSpan(eventLabel->getEvent()->getPosRow(), eventLabel->getEvent()->getPosCol(), eventLabel->getEvent()->getSpanRow(), 1);
            }
    
            // Add event label to the table view
            ui->calendarWeekTable->setIndexWidget(ui->calendarWeekTable->model()->index(eventLabel->getEvent()->getPosRow(), eventLabel->getEvent()->getPosCol()), eventLabel);
        }
    

    Then later to delete an event :

    void CalendarView::onDeleteActionClicked(EventLabel *eventLabel)
    {
        this->apiClient->deleteAppointment(eventLabel->getEvent()->getId());
    
        // Hide the label
        eventLabel->setHidden(true);
        eventLabel->setParent(NULL); // Detach eventLabel to table
        // Remove label to the list
        eventLabels.removeOne(eventLabel);
    
        // Remove span cell to table if needed
        if (eventLabel->getEvent()->getSpanRow() != 1) {
            ui->calendarWeekTable->setSpan(eventLabel->getEvent()->getPosRow(), eventLabel->getEvent()->getPosCol(), 1, 1);
        }
    
        // Delete event widget
        eventLabel->deleteLater();
    }
    

    It is like the eventLabel object is still inside the table. Should I do something special to remove a widget from a QTableView ?


  • Lifetime Qt Champion

    @Gulivert said in Calendar Week and Day views, need advises:

    eventLabel

    Hi
    you used
    https://doc.qt.io/qt-5/qabstractitemview.html#setIndexWidget
    which states the viewport takes ownership.

    You can try setting a nullptr to same index instead of
    eventLabel->deleteLater();
    setIndexWidget is not really meant for dynamic content so
    there seems to be no API for removing it again, howver doc
    says calling setIndexWidget will delete any existing.
    So try give it a nullptr and see.



  • @mrjj
    Haaaa thank you soooo muchhhhh :) It works !


Log in to reply