Sur cette page

Exemple de widget calendrier

L'exemple de widget Calendrier montre l'utilisation de QCalendarWidget.

Widget de calendrier affichant divers paramètres de calendrier

QCalendarWidget Le calendrier affiche un mois à la fois et permet à l'utilisateur de sélectionner une date. Le calendrier se compose de quatre éléments : une barre de navigation qui permet à l'utilisateur de changer le mois affiché, une grille où chaque cellule représente un jour du mois et deux en-têtes qui affichent les noms et les numéros des jours de la semaine.

L'exemple de widget de calendrier affiche une page QCalendarWidget et permet à l'utilisateur de configurer son apparence et son comportement à l'aide de QComboBoxes, QCheckBoxes et QDateEdits. En outre, l'utilisateur peut influencer le formatage des dates et des en-têtes individuels.

Les propriétés de QCalendarWidget sont résumées dans le tableau ci-dessous.

PropriétéDescription
selectedDateLa date actuellement sélectionnée.
minimumDateLa date la plus ancienne pouvant être sélectionnée.
maximumDateLa date la plus tardive pouvant être sélectionnée.
firstDayOfWeekLe jour affiché comme premier jour de la semaine (généralement le dimanche ou le lundi).
gridVisibleSi la grille doit être affichée.
selectionModeLa possibilité pour l'utilisateur de sélectionner une date ou non.
horizontalHeaderFormatLe format des noms de jours dans l'en-tête horizontal (par exemple, "M", "Mon" ou "Lundi").
verticalHeaderFormatLe format de l'en-tête vertical.
navigationBarVisibleL'affichage ou non de la barre de navigation en haut du widget calendrier.

L'exemple se compose d'une classe, Window, qui crée et présente le site QCalendarWidget, et d'autres widgets qui permettent à l'utilisateur de configurer le site QCalendarWidget.

Définition de la classe de fenêtre

Voici la définition de la classe Window:

class Window : public QWidget
{
    Q_OBJECT

public:
    Window(QWidget *parent = nullptr);

private slots:
    void localeChanged(int index);
    void firstDayChanged(int index);
    void selectionModeChanged(int index);
    void horizontalHeaderChanged(int index);
    void verticalHeaderChanged(int index);
    void selectedDateChanged();
    void minimumDateChanged(QDate date);
    void maximumDateChanged(QDate date);
    void weekdayFormatChanged();
    void weekendFormatChanged();
    void reformatHeaders();
    void reformatCalendarPage();

private:
    void createPreviewGroupBox();
    void createGeneralOptionsGroupBox();
    void createDatesGroupBox();
    void createTextFormatsGroupBox();
    QComboBox *createColorComboBox();

    QGroupBox *previewGroupBox;
    QGridLayout *previewLayout;
    QCalendarWidget *calendar;

    QGroupBox *generalOptionsGroupBox;
    QLabel *localeLabel;
    QLabel *firstDayLabel;
    ...
    QCheckBox *mayFirstCheckBox;
};

Comme c'est souvent le cas avec les classes qui représentent des fenêtres autonomes, la majeure partie de l'API est privée. Nous examinerons les membres privés au fur et à mesure que nous les rencontrerons dans l'implémentation.

Implémentation de la classe Window

Examinons maintenant l'implémentation de la classe, en commençant par le constructeur :

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"));
}

Nous commençons par créer les quatre QGroupBoxes et leurs widgets enfants (y compris le QCalendarWidget) à l'aide de quatre fonctions create...GroupBox() privées, décrites ci-dessous. Nous disposons ensuite les boîtes de groupe dans une grille QGridLayout.

Nous réglons la politique de redimensionnement de la grille sur QLayout::SetFixedSize pour empêcher l'utilisateur de redimensionner la fenêtre. Dans ce mode, la taille de la fenêtre est définie automatiquement par QGridLayout en fonction des indices de taille des widgets qu'elle contient.

Pour éviter que la fenêtre ne soit automatiquement redimensionnée chaque fois que nous modifions une propriété de QCalendarWidget (par exemple, en masquant la barre de navigation, l'en-tête vertical ou la grille), nous fixons la hauteur minimale de la ligne 0 et la largeur minimale de la colonne 0 à la taille initiale de QCalendarWidget.

Passons maintenant à la fonction createPreviewGroupBox():

void Window::createPreviewGroupBox()
{
    previewGroupBox = new QGroupBox(tr("Preview"));

    calendar = new QCalendarWidget;
    calendar->setMinimumDate(QDate(1900, 1, 1));
    calendar->setMaximumDate(QDate(3000, 1, 1));
    calendar->setGridVisible(true);

    connect(calendar, &QCalendarWidget::currentPageChanged,
            this, &Window::reformatCalendarPage);

    previewLayout = new QGridLayout;
    previewLayout->addWidget(calendar, 0, 0, Qt::AlignCenter);
    previewGroupBox->setLayout(previewLayout);
}

Le cadre Preview ne contient qu'un seul widget : le QCalendarWidget. Nous le configurons, connectons son signal currentPageChanged() à notre slot reformatCalendarPage() pour nous assurer que chaque nouvelle page reçoit le formatage spécifié par l'utilisateur.

La fonction createGeneralOptionsGroupBox() est assez volumineuse et plusieurs widgets sont configurés de la même manière. Nous examinerons ici une partie de son implémentation et sauterons le reste :

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<QLocale::Language>(_lang);
        const auto locales =
            QLocale::matchingLocales(lang, QLocale::AnyScript, QLocale::AnyTerritory);
        for (auto loc : locales) {
            QString label = QLocale::languageToString(lang);
            auto territory = loc.territory();
            label += QLatin1Char('/');
            label += QLocale::territoryToString(territory);
            if (locale().language() == lang && locale().territory() == territory)
                curLocaleIndex = index;
            localeCombo->addItem(label, loc);
            ++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);
    ...

Nous commençons par la configuration de la boîte combo Week starts on. Cette combobox contrôle le jour qui doit être affiché comme premier jour de la semaine.

La classe QComboBox nous permet d'attacher des données utilisateur sous forme de QVariant à chaque élément. Les données peuvent ensuite être récupérées à l'aide de la fonction itemData() de QComboBox. QVariant ne prend pas directement en charge le type de données Qt::DayOfWeek, mais il prend en charge int, et C++ convertira volontiers n'importe quelle valeur d'énumération en int.

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

Après avoir créé les widgets, nous connectons les signaux et les slots. Nous connectons les comboboxes aux slots privés de Window ou aux slots publics fournis par QComboBox.

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

À la fin de la fonction, nous appelons les slots qui mettent à jour le calendrier afin de nous assurer que QCalendarWidget est synchronisé avec les autres widgets au démarrage.

Examinons maintenant la fonction privée 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);

Dans cette fonction, nous créons les widgets d'édition Minimum Date, Maximum Date et Current Date, qui contrôlent les dates minimales, maximales et sélectionnées du calendrier. Les dates minimales et maximales du calendrier ont déjà été définies dans createPrivewGroupBox(); nous pouvons donc définir les valeurs par défaut des widgets en fonction des valeurs du calendrier.

    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);
    ...
}

Nous connectons le signal dateChanged() de currentDateEdit directement à l'emplacement setSelectedDate() du calendrier. Lorsque la date sélectionnée dans le calendrier change, que ce soit à la suite d'une action de l'utilisateur ou par programmation, notre slot selectedDateChanged() met à jour l'éditeur Current Date. Nous devons également réagir lorsque l'utilisateur modifie les éditeurs Minimum Date et Maximum Date.

Voici la fonction createTextFormatsGroup():

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);

Nous avons configuré les comboboxes Weekday Color et Weekend Color en utilisant createColorCombo(), qui instancie un QComboBox et le remplit avec des couleurs ("Rouge", "Bleu", etc.).

    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"));

La boîte combo Header Text Format permet à l'utilisateur de modifier le format du texte (gras, italique ou simple) utilisé pour les en-têtes horizontaux et verticaux. Les cases à cocher First Friday in blue et May 1 in red affectent le rendu de dates spécifiques.

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

Nous connectons les cases à cocher et les comboboxes à divers emplacements privés. Les cases à cocher First Friday in blue et May 1 in red sont toutes deux connectées à reformatCalendarPage(), qui est également appelé lorsque le calendrier change de mois.

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

À la fin de createTextFormatsGroupBox(), nous appelons des slots privés pour synchroniser QCalendarWidget avec les autres widgets.

Nous avons maintenant terminé l'examen des quatre fonctions create...GroupBox(). Jetons maintenant un coup d'œil aux autres fonctions et slots privés.

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;
}

Dans createColorCombo(), nous créons un combobox et le remplissons avec des couleurs standard. Le deuxième argument de QComboBox::addItem() est un QVariant qui stocke les données de l'utilisateur (dans ce cas, des objets QColor ).

Cette fonction a été utilisée pour configurer les comboboxes Weekday Color et Weekend Color.

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

Lorsque l'utilisateur modifie la valeur de la boîte combobox Week starts on, firstDayChanged() est appelé avec l'index de la nouvelle valeur de la boîte combobox. Nous récupérons l'élément de données personnalisé associé au nouvel élément courant à l'aide de itemData() et le transformons en Qt::DayOfWeek.

selectionModeChanged()Les exemples suivants, horizontalHeaderChanged() et verticalHeaderChanged(), sont très similaires à firstDayChanged() et sont donc omis.

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

Le site selectedDateChanged() met à jour l'éditeur Current Date pour refléter l'état actuel du site QCalendarWidget.

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

Lorsque l'utilisateur modifie la date minimale, nous en informons le QCalenderWidget. Nous mettons également à jour l'éditeur Maximum Date, car si la nouvelle date minimale est postérieure à la date maximale actuelle, QCalendarWidget adaptera automatiquement sa date maximale pour éviter un état contradictoire.

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

maximumDateChanged() est mis en œuvre de manière similaire à minimumDateChanged().

void Window::weekdayFormatChanged()
{
    QTextCharFormat format;

    format.setForeground(qvariant_cast<QColor>(
        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);
}

Chaque élément de combobox possède un objet QColor en tant que données utilisateur correspondant au texte de l'élément. Après avoir récupéré les couleurs des comboboxes, nous définissons le format de texte de chaque jour de la semaine.

Le format de texte d'une colonne du calendrier est donné sous la forme d'un objet QTextCharFormat, qui, outre la couleur d'avant-plan, nous permet de spécifier diverses informations de formatage des caractères. Dans cet exemple, nous ne montrons qu'un sous-ensemble des possibilités.

void Window::weekendFormatChanged()
{
    QTextCharFormat format;

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

weekendFormatChanged() est identique à weekdayFormatChanged(), sauf qu'elle concerne le samedi et le dimanche au lieu du lundi au vendredi.

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);
}

Le slot reformatHeaders() est appelé lorsque l'utilisateur modifie le format de texte des en-têtes. Nous comparons le texte actuel de la combobox Header Text Format pour déterminer le format à appliquer. (Une autre solution aurait consisté à stocker les valeurs de QTextCharFormat à côté des éléments de la boîte combinée).

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<Qt::DayOfWeek>(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<Qt::DayOfWeek>(mayFirst.dayOfWeek()));
        calendar->setDateTextFormat(mayFirst, calendar->weekdayTextFormat(dayOfWeek));
    }

    calendar->setDateTextFormat(mayFirst, mayFirstFormat);
}

Dans reformatCalendarPage(), nous définissons le format de texte du premier vendredi du mois et du 1er mai de l'année en cours. Les formats de texte réellement utilisés dépendent des cases cochées et des formats des jours de la semaine et des week-ends.

QCalendarWidget permet de définir le format de texte des dates individuelles à l'aide de setDateTextFormat(). Nous avons choisi de définir les formats de date lorsque la page du calendrier change - c'est-à-dire lorsqu'un nouveau mois est affiché - et lorsque le format des jours de la semaine et des week-ends est modifié. Nous vérifions les cases mayFirstCheckBox et firstDayCheckBox, le cas échéant, et définissons les formats de texte en conséquence.

Exemple de projet @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.