Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-137268

Additional signal caused by QCalendarWidget and sent by QDateTimeEdit for 1 date change

    XMLWordPrintable

Details

    Description

      Consider such use case:

      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
      
          QDateTimeEdit edit;
          edit.setCalendarPopup(true);
          QObject::connect(&edit, &QDateTimeEdit::dateChanged, [&]() {
              qDebug() << "Changing date, blocking";
              QSignalBlocker blocker = QSignalBlocker{&edit};
              QDate date = edit.date().addDays(1);
              edit.setDate(date);
          });
      
          edit.show();
      
          return app.exec();
      }
      

      User wants to change date one more time upon it was just changed. And a signal blocker is there for not causing infinite loop.

      The expected workflow is:
      Open calendar widget -> Pick a different date -> Lambda is triggered -> Date is changed again but that is it since no more signals

      But the actual outcome is:
      Lambda is triggered twice. Not once (the expected), not arbitrarily many times either (signal blocker works, so to speak).

      Some observations:
      1. Comment out "edit.setCalendarPopup(true);", get rid of QCalendarWidget, change date with only up/down arrows and problem is gone. So the cause is QCalendarWidget. But it is not QCalendarWidget that sends the additional signal. See #2.
      2. Add another blocker for edit.calendarWidget(); but problem is not solved.
      3. Change signal blocker to a pointer so that it does not go out of scope and problem is solved.
      4. To avoid permanent blocking due to #3, we can choose a proper timing of deleting signal blocker pointer. This actually works:

      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
      
          QSignalBlocker *blocker;
      
          QDateTimeEdit edit;
          edit.setCalendarPopup(true);
          QObject::connect(&edit, &QDateTimeEdit::dateChanged, [&]() {
              qDebug() << "Changing date, blocking";
              blocker = new QSignalBlocker{&edit};
              QDate date = edit.date().addDays(1);
              edit.setDate(date);
          });
          QObject::connect(edit.calendarWidget(), &QCalendarWidget::clicked, [&]() {
              qDebug() << "Date changed, unblocking";
              delete blocker;
              blocker = nullptr;
          });
          edit.show();
      
          return app.exec();
      }
      

      So my conclusion is that QCalendarWidget somehow causes QDateTimeEdit to send another signal at an unknown timing. It is later than "right after QDateTimeEdit::dateChanged" but earlier than "QCalendarWidget::clicked".

      We may want to change the behavior so that there won't be any duplicated signals. Or at least document the behavior so that users are not caught in surprise.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            axelspoerl Axel Spoerl
            luqiaochen Luqiao Chen
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes