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.
-
-
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 wantSo here is the result for week:
for day:
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:
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.
-
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.
-
@Gulivert
I think ofsetSpan()
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 ?
-
@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.