Kalender-Widget Beispiel

Das Kalender-Widget-Beispiel zeigt die Verwendung von QCalendarWidget.

QCalendarWidget zeigt jeweils einen Kalendermonat an und lässt den Benutzer ein Datum auswählen. Der Kalender besteht aus vier Komponenten: einer Navigationsleiste, mit der der Benutzer den angezeigten Monat ändern kann, einem Raster, in dem jede Zelle einen Tag im Monat darstellt, und zwei Kopfzeilen, die Wochentagsnamen und Wochennummern anzeigen.

Das Kalender-Widget-Beispiel zeigt ein QCalendarWidget an und ermöglicht dem Benutzer die Konfiguration seines Aussehens und Verhaltens mit QComboBoxes, QCheckBoxes und QDateEdits. Darüber hinaus kann der Benutzer die Formatierung einzelner Daten und Kopfzeilen beeinflussen.

Die Eigenschaften des QCalendarWidget sind in der folgenden Tabelle zusammengefasst.

EigenschaftBeschreibung
selectedDateDas aktuell ausgewählte Datum.
minimumDateDas früheste Datum, das ausgewählt werden kann.
maximumDateDas späteste Datum, das ausgewählt werden kann.
firstDayOfWeekDer Tag, der als erster Tag der Woche angezeigt wird (normalerweise Sonntag oder Montag).
gridVisibleOb das Gitter angezeigt werden soll.
selectionModeOb der Benutzer ein Datum auswählen kann oder nicht.
horizontalHeaderFormatDas Format der Tagesnamen in der horizontalen Kopfzeile (z. B. "M", "Mo" oder "Montag").
verticalHeaderFormatDas Format der vertikalen Kopfzeile.
navigationBarVisibleOb die Navigationsleiste am oberen Rand des Kalender-Widgets angezeigt wird.

Das Beispiel besteht aus einer Klasse, Window, die das QCalendarWidget erstellt und anordnet, und den anderen Widgets, mit denen der Benutzer das QCalendarWidget konfigurieren kann.

Definition der Fensterklasse

Hier ist die Definition der Klasse 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;
};

Wie häufig bei Klassen, die eigenständige Fenster darstellen, ist der größte Teil der API privat. Wir werden die privaten Mitglieder überprüfen, wenn wir in der Implementierung auf sie stoßen.

Implementierung der Fensterklasse

Schauen wir uns nun die Implementierung der Klasse an, beginnend mit dem Konstruktor:

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

Wir beginnen mit der Erstellung der vier QGroupBoxes und ihrer untergeordneten Widgets (einschließlich QCalendarWidget) unter Verwendung von vier privaten create...GroupBox() Funktionen, die unten beschrieben werden. Dann ordnen wir die Gruppenrahmen in einem QGridLayout an.

Wir setzen die Größenänderungsrichtlinie des Grid-Layouts auf QLayout::SetFixedSize, um zu verhindern, dass der Benutzer die Größe des Fensters ändert. In diesem Modus wird die Größe des Fensters automatisch von QGridLayout auf der Grundlage der Größenhinweise seiner Inhaltswidgets festgelegt.

Um sicherzustellen, dass die Größe des Fensters nicht jedes Mal automatisch angepasst wird, wenn wir eine Eigenschaft von QCalendarWidget ändern (z. B. Ausblenden der Navigationsleiste, der vertikalen Kopfzeile oder des Gitters), setzen wir die Mindesthöhe von Zeile 0 und die Mindestbreite von Spalte 0 auf die Anfangsgröße von QCalendarWidget.

Kommen wir nun zur Funktion 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);
}

Der Gruppenrahmen Preview enthält nur ein Widget: das QCalendarWidget. Wir richten es ein und verbinden sein Signal currentPageChanged() mit unserem reformatCalendarPage() -Slot, um sicherzustellen, dass jede neue Seite die vom Benutzer angegebene Formatierung erhält.

Die Funktion createGeneralOptionsGroupBox() ist recht umfangreich und mehrere Widgets werden auf die gleiche Weise eingerichtet. Wir werden uns hier nur Teile der Implementierung ansehen und den Rest auslassen:

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

Wir beginnen mit der Einrichtung der Week starts on Combobox. Diese Combobox steuert, welcher Tag als erster Tag der Woche angezeigt werden soll.

Mit der Klasse QComboBox können wir jedem Element Benutzerdaten als QVariant zuordnen. Die Daten können später mit der Funktion itemData() von QComboBox abgerufen werden. QVariant unterstützt den Datentyp Qt::DayOfWeek nicht direkt, wohl aber int, und C++ konvertiert jeden Enum-Wert problemlos in 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);
    ...

Nachdem wir die Widgets erstellt haben, verbinden wir die Signale und Slots. Wir verbinden die Comboboxen mit privaten Slots von Window oder mit öffentlichen Slots, die von QComboBox bereitgestellt werden.

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

Am Ende der Funktion rufen wir die Slots auf, die den Kalender aktualisieren, um sicherzustellen, dass QCalendarWidget beim Start mit den anderen Widgets synchronisiert wird.

Werfen wir nun einen Blick auf die private Funktion 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);

In dieser Funktion erstellen wir die Editor-Widgets Minimum Date, Maximum Date und Current Date, die das minimale, maximale und ausgewählte Datum des Kalenders steuern. Die Mindest- und Höchstdaten des Kalenders wurden bereits in createPrivewGroupBox() festgelegt; wir können dann die Standardwerte der Widgets auf die Werte des Kalenders setzen.

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

Wir verbinden das Signal dateChanged() von currentDateEdit direkt mit dem Slot setSelectedDate() des Kalenders. Wenn sich das ausgewählte Datum des Kalenders ändert, entweder als Ergebnis einer Benutzeraktion oder programmgesteuert, aktualisiert unser selectedDateChanged() Slot den Current Date Editor. Wir müssen auch reagieren, wenn der Benutzer die Editoren Minimum Date und Maximum Date ändert.

Hier ist die Funktion 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);

Wir richten die Kombinationsfelder Weekday Color und Weekend Color ein, indem wir createColorCombo() verwenden, das ein QComboBox instanziiert und es mit Farben ("Rot", "Blau", usw.) füllt.

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

Mit dem Kombinationsfeld Header Text Format kann der Benutzer das für horizontale und vertikale Überschriften verwendete Textformat (fett, kursiv oder einfach) ändern. Die Kontrollkästchen First Friday in blue und May 1 in red beeinflussen die Darstellung bestimmter Daten.

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

Die Kontrollkästchen und Comboboxen werden mit verschiedenen privaten Slots verbunden. Die Kontrollkästchen First Friday in blue und May 1 in red sind beide mit reformatCalendarPage() verbunden, das auch aufgerufen wird, wenn der Kalender den Monat wechselt.

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

Am Ende von createTextFormatsGroupBox() rufen wir private Slots auf, um QCalendarWidget mit den anderen Widgets zu synchronisieren.

Wir haben nun die vier Funktionen von create...GroupBox() durchgesehen. Werfen wir nun einen Blick auf die anderen privaten Funktionen und Slots.

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

In createColorCombo() erstellen wir eine Combobox und füllen sie mit Standardfarben. Das zweite Argument von QComboBox::addItem() ist eine QVariant, die Benutzerdaten (in diesem Fall QColor Objekte) speichert.

Diese Funktion wurde verwendet, um die Kombinationsfelder Weekday Color und Weekend Color einzurichten.

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

Wenn der Benutzer den Wert der Combobox Week starts on ändert, wird firstDayChanged() mit dem Index des neuen Wertes der Combobox aufgerufen. Wir rufen das benutzerdefinierte Datenelement ab, das mit dem neuen aktuellen Element verbunden ist, indem wir itemData() verwenden und es in ein Qt::DayOfWeek umwandeln.

selectionModeChanged()Da horizontalHeaderChanged() und verticalHeaderChanged() firstDayChanged() sehr ähnlich sind, werden sie weggelassen.

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

selectedDateChanged() aktualisiert den Current Date -Editor, um den aktuellen Zustand von QCalendarWidget wiederzugeben.

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

Wenn der Benutzer das Mindestdatum ändert, teilen wir dies dem QCalenderWidget mit. Wir aktualisieren auch den Maximum Date -Editor, denn wenn das neue Mindestdatum später liegt als das aktuelle Höchstdatum, passt QCalendarWidget automatisch sein Höchstdatum an, um einen widersprüchlichen Zustand zu vermeiden.

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

maximumDateChanged() ist ähnlich wie minimumDateChanged() implementiert.

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

Jedes Combobox-Element hat ein QColor Objekt als Benutzerdaten, das dem Text des Elements entspricht. Nachdem die Farben aus den Comboboxen geholt wurden, wird das Textformat für jeden Wochentag festgelegt.

Das Textformat einer Spalte im Kalender wird als QTextCharFormat angegeben, das uns neben der Vordergrundfarbe die Möglichkeit gibt, verschiedene Informationen zur Zeichenformatierung anzugeben. In diesem Beispiel zeigen wir nur eine Teilmenge der Möglichkeiten.

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() Der Slot weekdayFormatChanged() ist derselbe wie , nur dass er sich auf Samstag und Sonntag statt auf Montag bis Freitag bezieht.

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

Der Slot reformatHeaders() wird aufgerufen, wenn der Benutzer das Textformat der Kopfzeilen ändert. Wir vergleichen den aktuellen Text der Header Text Format Combobox, um zu bestimmen, welches Format angewendet werden soll. (Eine Alternative wäre gewesen, die Werte von QTextCharFormat neben den Elementen der Combobox zu speichern).

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

In reformatCalendarPage() legen wir das Textformat des ersten Freitags im Monat und des 1. Mai im laufenden Jahr fest. Welche Textformate tatsächlich verwendet werden, hängt davon ab, welche Kästchen angekreuzt sind und wie die Wochentags-/Wochenendformate lauten.

QCalendarWidget können wir das Textformat einzelner Datumsangaben mit setDateTextFormat() einstellen. Wir haben uns dafür entschieden, die Datumsformate bei einem Wechsel des Kalenderblattes - d. h. wenn ein neuer Monat angezeigt wird - und bei einer Änderung des Wochentags-/Wochenendformats einzustellen. Wir prüfen, welche der Optionen mayFirstCheckBox und firstDayCheckBox aktiviert sind, und setzen die Textformate entsprechend.

Beispielprojekt @ code.qt.io

© 2025 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.