QT5.14.2 官方例子 - Widget Examples 3: calendar(日历)

系列总链接:

QT5.14.2 官方例子 - 学习系列

https://blog.csdn.net/qq_22122811/article/details/108007519

 

日历小部件示例展示了QCalendarWidget的使用。(Calendar =>   英 /ˈkælɪndə(r)/)

QT5.14.2 官方例子 - Widget Examples 3: calendar(日历)_第1张图片

QCalendarWidget每次显示一个日历月,并让用户选择一个日期。日历由四个组件组成:一个导航栏,允许用户更改所显示的月份;一个网格,其中每个单元格表示该月中的一天;以及两个标题,显示工作日名称和周号。

日历小部件示例显示了一个QCalendarWidget,并允许用户使用qcombobox、qcheckbox和QDateEdits配置它的外观和行为。此外,用户可以影响单个日期和标题的格式。

 

详细介绍链接:

https://doc.qt.io/qt-5/qtwidgets-widgets-calendarwidget-example.html

 

大概思路介绍:

Window::Window(QWidget *parent)
      : QWidget(parent)
  {
      createPreviewGroupBox();
      createGeneralOptionsGroupBox();
      createDatesGroupBox();
      createTextFormatsGroupBox();

      QGridLayout *layout = new QGridLayout;
      layout->addWidget(previewGroupBox, 0, 0);
      layout->addWidget(generalOptionsGroupBox, 0, 1);
      layout->addWidget(datesGroupBox, 1, 0);
      layout->addWidget(textFormatsGroupBox, 1, 1);
      layout->setSizeConstraint(QLayout::SetFixedSize);
      setLayout(layout);

      previewLayout->setRowMinimumHeight(0, calendar->sizeHint().height());
      previewLayout->setColumnMinimumWidth(0, calendar->sizeHint().width());

      setWindowTitle(tr("Calendar Widget"));
  }

我们首先使用下面描述的四个私有create…GroupBox()函数创建四个qgroupbox及其子小部件(包括QCalendarWidget)。然后在QGridLayout中排列组框。

我们将网格布局的调整策略设置为QLayout::SetFixedSize,以防止用户调整窗口的大小。在这种模式下,窗口的大小由QGridLayout根据其内容小部件的大小提示自动设置。

确保窗口没有自动调整大小QCalendarWidget的每次改变一个属性(例如,隐藏导航栏,垂直标题栏,或网格),我们设置了最低身高的行和列的最小宽度0 QCalendarWidget的初始大小。

.......

.......

QT5.14.2 官方例子 - Widget Examples 3: calendar(日历)_第2张图片

createGeneralOptionsGroupBox()函数有点大,几个小部件以相同的方式设置。我们将在这里看到它的实现部分,跳过其他部分:

void Window::createGeneralOptionsGroupBox()
  {
      generalOptionsGroupBox = new QGroupBox(tr("General Options"));

      localeCombo = new QComboBox;
      int curLocaleIndex = -1;
      int index = 0;
      for (int _lang = QLocale::C; _lang <= QLocale::LastLanguage; ++_lang) {
          QLocale::Language lang = static_cast(_lang);
          QList countries = QLocale::countriesForLanguage(lang);
          for (int i = 0; i < countries.count(); ++i) {
              QLocale::Country country = countries.at(i);
              QString label = QLocale::languageToString(lang);
              label += QLatin1Char('/');
              label += QLocale::countryToString(country);
              QLocale locale(lang, country);
              if (this->locale().language() == lang && this->locale().country() == country)
                  curLocaleIndex = index;
              localeCombo->addItem(label, locale);
              ++index;
          }
      }
      if (curLocaleIndex != -1)
          localeCombo->setCurrentIndex(curLocaleIndex);
      localeLabel = new QLabel(tr("&Locale"));
      localeLabel->setBuddy(localeCombo);

      firstDayCombo = new QComboBox;
      firstDayCombo->addItem(tr("Sunday"), Qt::Sunday);
      firstDayCombo->addItem(tr("Monday"), Qt::Monday);
      firstDayCombo->addItem(tr("Tuesday"), Qt::Tuesday);
      firstDayCombo->addItem(tr("Wednesday"), Qt::Wednesday);
      firstDayCombo->addItem(tr("Thursday"), Qt::Thursday);
      firstDayCombo->addItem(tr("Friday"), Qt::Friday);
      firstDayCombo->addItem(tr("Saturday"), Qt::Saturday);

      firstDayLabel = new QLabel(tr("Wee&k starts on:"));
      firstDayLabel->setBuddy(firstDayCombo);
      ...

补充:

qt 字符串中"&"的用法:

https://segmentfault.com/q/1010000004987218

我们从combobox上的设置开始。这个组合框控制哪一天应该显示为一周的第一天。

QComboBox类允许我们将用户数据作为一个QVariant附加到每个项上。稍后可以使用QComboBox的itemData()函数检索数据。QVariant不直接支持Qt::DayOfWeek数据类型,但它支持int,而c++很乐意将任何枚举值转换为int。

...
      connect(localeCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::localeChanged);
      connect(firstDayCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::firstDayChanged);
      connect(selectionModeCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::selectionModeChanged);
      connect(gridCheckBox, &QCheckBox::toggled,
              calendar, &QCalendarWidget::setGridVisible);
      connect(navigationCheckBox, &QCheckBox::toggled,
              calendar, &QCalendarWidget::setNavigationBarVisible);
      connect(horizontalHeaderCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::horizontalHeaderChanged);
      connect(verticalHeaderCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::verticalHeaderChanged);
      ...

创建小部件之后,我们将信号和插槽连接起来。我们将组合盒连接到窗口的私有插槽或QComboBox提供的公共插槽。

...
      firstDayChanged(firstDayCombo->currentIndex());
      selectionModeChanged(selectionModeCombo->currentIndex());
      horizontalHeaderChanged(horizontalHeaderCombo->currentIndex());
      verticalHeaderChanged(verticalHeaderCombo->currentIndex());
  }

在函数的最后,我们调用更新日历的插槽,以确保QCalendarWidget在启动时与其他小部件同步。

现在让我们看看createDatesGroupBox()私有函数:

void Window::createDatesGroupBox()
  {
      datesGroupBox = new QGroupBox(tr("Dates"));

      minimumDateEdit = new QDateEdit;
      minimumDateEdit->setDisplayFormat("MMM d yyyy");
      minimumDateEdit->setDateRange(calendar->minimumDate(),
                                    calendar->maximumDate());
      minimumDateEdit->setDate(calendar->minimumDate());

      minimumDateLabel = new QLabel(tr("&Minimum Date:"));
      minimumDateLabel->setBuddy(minimumDateEdit);

      currentDateEdit = new QDateEdit;
      currentDateEdit->setDisplayFormat("MMM d yyyy");
      currentDateEdit->setDate(calendar->selectedDate());
      currentDateEdit->setDateRange(calendar->minimumDate(),
                                    calendar->maximumDate());

      currentDateLabel = new QLabel(tr("&Current Date:"));
      currentDateLabel->setBuddy(currentDateEdit);

      maximumDateEdit = new QDateEdit;
      maximumDateEdit->setDisplayFormat("MMM d yyyy");
      maximumDateEdit->setDateRange(calendar->minimumDate(),
                                    calendar->maximumDate());
      maximumDateEdit->setDate(calendar->maximumDate());

      maximumDateLabel = new QLabel(tr("Ma&ximum Date:"));
      maximumDateLabel->setBuddy(maximumDateEdit);

在此函数中,我们创建最小日期、最大日期和当前日期编辑器小部件,这些小部件控制日历的最小、最大和所选日期。日历的最小和最大日期已经在createPrivewGroupBox()中设置;然后,我们可以将小部件的默认值设置为日历值。

connect(currentDateEdit, &QDateEdit::dateChanged,
              calendar, &QCalendarWidget::setSelectedDate);
      connect(calendar, &QCalendarWidget::selectionChanged,
              this, &Window::selectedDateChanged);
      connect(minimumDateEdit, &QDateEdit::dateChanged,
              this, &Window::minimumDateChanged);
      connect(maximumDateEdit, &QDateEdit::dateChanged,
              this, &Window::maximumDateChanged);
      ...
  }

我们将currentDateEdit的dateChanged()信号直接连接到日历的setSelectedDate()插槽。当日历所选择的日期更改时(无论是由于用户操作还是通过编程方式更改),selectedDateChanged()插槽将更新当前的日期编辑器。我们还需要在用户更改最小日期和最大日期编辑器时做出反应。

Here is the createTextFormatsGroup() function:

void Window::createTextFormatsGroupBox()
  {
      textFormatsGroupBox = new QGroupBox(tr("Text Formats"));

      weekdayColorCombo = createColorComboBox();
      weekdayColorCombo->setCurrentIndex(
              weekdayColorCombo->findText(tr("Black")));

      weekdayColorLabel = new QLabel(tr("&Weekday color:"));
      weekdayColorLabel->setBuddy(weekdayColorCombo);

      weekendColorCombo = createColorComboBox();
      weekendColorCombo->setCurrentIndex(
              weekendColorCombo->findText(tr("Red")));

      weekendColorLabel = new QLabel(tr("Week&end color:"));
      weekendColorLabel->setBuddy(weekendColorCombo);

我们使用createColorCombo()设置工作日颜色和周末颜色组合框,它实例化一个QComboBox并用颜色填充它(“红色”、“蓝色”等)。

headerTextFormatCombo = new QComboBox;
      headerTextFormatCombo->addItem(tr("Bold"));
      headerTextFormatCombo->addItem(tr("Italic"));
      headerTextFormatCombo->addItem(tr("Plain"));

      headerTextFormatLabel = new QLabel(tr("&Header text:"));
      headerTextFormatLabel->setBuddy(headerTextFormatCombo);

      firstFridayCheckBox = new QCheckBox(tr("&First Friday in blue"));

      mayFirstCheckBox = new QCheckBox(tr("May &1 in red"));

标题文本格式组合框允许用户更改用于水平和垂直标题的文本格式(粗体、斜体或纯文本)。第一个蓝色的星期五和红色的5月1号复选框会影响特定日期的呈现。

connect(weekdayColorCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::weekdayFormatChanged);
      connect(weekdayColorCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::reformatCalendarPage);
      connect(weekendColorCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::weekendFormatChanged);
      connect(weekendColorCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::reformatCalendarPage);
      connect(headerTextFormatCombo, QOverload::of(&QComboBox::currentIndexChanged),
              this, &Window::reformatHeaders);
      connect(firstFridayCheckBox, &QCheckBox::toggled,
              this, &Window::reformatCalendarPage);
      connect(mayFirstCheckBox, &QCheckBox::toggled,
              this, &Window::reformatCalendarPage);

我们将复选框和组合框连接到各种私有插槽。蓝色复选框中的第一个星期五和红色复选框中的5月1日都连接到reformatCalendarPage(),当日历切换到月份时,也会调用该函数。

...
      reformatHeaders();
      reformatCalendarPage();
  }

在createTextFormatsGroupBox()的最后,我们调用私有槽来同步QCalendarWidget和其他小部件。

现在我们已经完成了四个create…GroupBox()函数的检查。现在让我们看看其他私有函数和槽。

QComboBox *Window::createColorComboBox()
  {
      QComboBox *comboBox = new QComboBox;
      comboBox->addItem(tr("Red"), QColor(Qt::red));
      comboBox->addItem(tr("Blue"), QColor(Qt::blue));
      comboBox->addItem(tr("Black"), QColor(Qt::black));
      comboBox->addItem(tr("Magenta"), QColor(Qt::magenta));
      return comboBox;
  }

在createColorCombo()中,我们创建了一个组合框,并用标准颜色填充它。QComboBox::addItem()的第二个参数是一个存储用户数据的QVariant(在本例中是QColor对象)。

该函数用于设置工作日颜色和周末颜色组合框。

 void Window::firstDayChanged(int index)
  {
      calendar->setFirstDayOfWeek(Qt::DayOfWeek(
                                  firstDayCombo->itemData(index).toInt()));
  }

当用户在combobox的值上更改一周时,使用combobox新值的索引调用firstDayChanged()。我们使用itemData()检索与新当前项关联的自定义数据项,并将其转换为Qt::DayOfWeek。

selectionModeChanged()、horizontalHeaderChanged()和verticalHeaderChanged()非常类似于firstDayChanged(),因此它们被省略。

void Window::selectedDateChanged()
  {
      currentDateEdit->setDate(calendar->selectedDate());
  }

selectedDateChanged()更新当前日期编辑器,以反映QCalendarWidget的当前状态。

void Window::minimumDateChanged(QDate date)
  {
      calendar->setMinimumDate(date);
      maximumDateEdit->setDate(calendar->maximumDate());
  }

当用户更改最小日期时,我们告诉QCalenderWidget。我们还更新了最大日期编辑器,因为如果新的最小日期晚于当前最大日期,QCalendarWidget将自动调整其最大日期,以避免出现矛盾状态。

void Window::maximumDateChanged(QDate date)
  {
      calendar->setMaximumDate(date);
      minimumDateEdit->setDate(calendar->minimumDate());
  }

maximumDateChanged()的实现类似于minimumDateChanged()。

void Window::weekdayFormatChanged()
  {
      QTextCharFormat format;

      format.setForeground(qvariant_cast(
          weekdayColorCombo->itemData(weekdayColorCombo->currentIndex())));
      calendar->setWeekdayTextFormat(Qt::Monday, format);
      calendar->setWeekdayTextFormat(Qt::Tuesday, format);
      calendar->setWeekdayTextFormat(Qt::Wednesday, format);
      calendar->setWeekdayTextFormat(Qt::Thursday, format);
      calendar->setWeekdayTextFormat(Qt::Friday, format);
  }

每个combobox项目都有一个QColor对象作为与项目文本对应的用户数据。从组合框中获取颜色后,我们设置每周每天的文本格式。

日历中列的文本格式是QTextCharFormat,除了前景色外,它还允许我们指定各种字符格式信息。在本例中,我们只展示了可能性的一个子集。

void Window::weekendFormatChanged()
  {
      QTextCharFormat format;

      format.setForeground(qvariant_cast(
          weekendColorCombo->itemData(weekendColorCombo->currentIndex())));
      calendar->setWeekdayTextFormat(Qt::Saturday, format);
      calendar->setWeekdayTextFormat(Qt::Sunday, format);
  }

weekendFormatChanged()与weekdayFormatChanged()相同,不同之处在于它影响的是周六和周日,而不是周一到周五。

void Window::reformatHeaders()
  {
      QString text = headerTextFormatCombo->currentText();
      QTextCharFormat format;

      if (text == tr("Bold"))
          format.setFontWeight(QFont::Bold);
      else if (text == tr("Italic"))
          format.setFontItalic(true);
      else if (text == tr("Green"))
          format.setForeground(Qt::green);
      calendar->setHeaderTextFormat(format);
  }

当用户更改标题的文本格式时,将调用reformatHeaders()插槽。我们比较标题文本格式组合框的当前文本以确定应用哪种格式。(另一种方法是将QTextCharFormat值存储在combobox项旁边。)

void Window::reformatCalendarPage()
  {
      QTextCharFormat mayFirstFormat;
      const QDate mayFirst(calendar->yearShown(), 5, 1);

      QTextCharFormat firstFridayFormat;
      QDate firstFriday(calendar->yearShown(), calendar->monthShown(), 1);
      while (firstFriday.dayOfWeek() != Qt::Friday)
          firstFriday = firstFriday.addDays(1);

      if (firstFridayCheckBox->isChecked()) {
          firstFridayFormat.setForeground(Qt::blue);
      } else { // Revert to regular colour for this day of the week.
          Qt::DayOfWeek dayOfWeek(static_cast(firstFriday.dayOfWeek()));
          firstFridayFormat.setForeground(calendar->weekdayTextFormat(dayOfWeek).foreground());
      }

      calendar->setDateTextFormat(firstFriday, firstFridayFormat);

      // When it is checked, "May First in Red" always takes precedence over "First Friday in Blue".
      if (mayFirstCheckBox->isChecked()) {
          mayFirstFormat.setForeground(Qt::red);
      } else if (!firstFridayCheckBox->isChecked() || firstFriday != mayFirst) {
          // We can now be certain we won't be resetting "May First in Red" when we restore
          // may 1st's regular colour for this day of the week.
          Qt::DayOfWeek dayOfWeek(static_cast(mayFirst.dayOfWeek()));
          calendar->setDateTextFormat(mayFirst, calendar->weekdayTextFormat(dayOfWeek));
      }

      calendar->setDateTextFormat(mayFirst, mayFirstFormat);
  }

在reformatCalendarPage()中,我们设置当月的第一个星期五和当前年份的5月1日的文本格式。实际使用的文本格式取决于选中的复选框和工作日/周末格式。

QCalendarWidget允许我们使用setDateTextFormat()设置单个日期的文本格式。我们选择在日历页面更改时设置日期格式——即显示一个新的月份——以及在工作日/周末格式更改时设置日期格式。我们检查mayFirstCheckBox和firstDayCheckBox的哪个(如果有的话)被选中,并相应地设置文本格式。

你可能感兴趣的:(QT,examples)