Auf dieser Seite

Beispiel für ein Kalender-Widget

Das Beispiel für das Kalender-Widget veranschaulicht die Verwendung von QCalendarWidget.

Kalender-Widget mit verschiedenen Kalendereinstellungen

QCalendarWidget Es zeigt jeweils einen Kalendermonat an und ermöglicht es dem Benutzer, ein Datum auszuwählen. Der Kalender besteht aus vier Komponenten: einer Navigationsleiste, über die der Benutzer den angezeigten Monat ändern kann, einem Raster, in dem jede Zelle einen Tag des Monats darstellt, sowie zwei Kopfzeilen, die die Wochentagsnamen und die Wochennummern anzeigen.

Das Beispiel „Kalender-Widget“ zeigt ein „ QCalendarWidget “ an und ermöglicht es dem Benutzer, dessen Darstellung und Verhalten mithilfe von „ QComboBoxs“, „ QCheckBoxs“ und „ QDateEdits“ zu konfigurieren. Darüber hinaus kann der Benutzer die Formatierung einzelner Datumsangaben 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 (in der Regel Sonntag oder Montag).
gridVisibleOb das Raster angezeigt werden soll.
selectionModeOb der Benutzer ein Datum auswählen kann oder nicht.
horizontalHeaderFormatDas Format der Wochentagsbezeichnungen in der horizontalen Kopfzeile (z. B. „M“, „Mon“ 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 “ und die anderen Widgets erstellt und anordnet, 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 so oft bei Klassen, die eigenständige Fenster darstellen, ist der Großteil der API privat. Wir werden die privaten Mitglieder im Laufe der Implementierung näher betrachten, sobald wir auf sie stoßen.

Implementierung der Window-Klasse

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

Zunächst erstellen wir die vier „ QGroupBox“-Objekte und ihre untergeordneten Widgets (einschließlich des „ QCalendarWidget “) mithilfe von vier privaten „ create...GroupBox() “-Funktionen, die im Folgenden beschrieben werden. Anschließend ordnen wir die Gruppenfelder in einem „ QGridLayout “ an.

Wir legen die Größenanpassungsrichtlinie des Rasterlayouts auf „ QLayout::SetFixedSize “ fest, um zu verhindern, dass der Benutzer die Größe des Fensters ändert. In diesem Modus wird die Größe des Fensters automatisch von „ QGridLayout “ basierend auf den Größenhinweisen seiner Inhalts-Widgets festgelegt.

Um sicherzustellen, dass die Fenstergröße nicht jedes Mal automatisch angepasst wird, wenn wir eine Eigenschaft des „ QCalendarWidget “ ändern (beispielsweise das Ausblenden der Navigationsleiste, der vertikalen Kopfzeile oder des Rasters), legen wir die Mindesthöhe von Zeile 0 und die Mindestbreite von Spalte 0 auf die Anfangsgröße des „ QCalendarWidget “ fest.

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

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

Die Funktion ` createGeneralOptionsGroupBox() ` ist recht umfangreich, und mehrere Widgets werden auf dieselbe Weise eingerichtet. Wir werden uns hier Teile ihrer Implementierung ansehen und den Rest überspringen:

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 Combobox „ Week starts on “. Diese Combobox legt fest, welcher Tag als erster Tag der Woche angezeigt werden soll.

Die Klasse ` QComboBox ` ermöglicht es uns, jedem Element Benutzerdaten als „ QVariant “ zuzuweisen. Die Daten können später mit der Funktion ` itemData()` von ` QComboBox` abgerufen werden. ` QVariant ` unterstützt den Datentyp ` Qt::DayOfWeek ` zwar nicht direkt, aber es unterstützt ` 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 ist.

Werfen wir nun einen Blick auf die private Funktion von ` 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 Mindest-, Höchst- und ausgewähltes Datum des Kalenders steuern. Das Mindest- und Höchstdatum des Kalenders wurden bereits in „ createPrivewGroupBox() “ festgelegt; wir können die Standardwerte der Widgets dann 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()“ des „ currentDateEdit “ direkt mit dem Slot „ setSelectedDate()“ des Kalenders. Wenn sich das ausgewählte Datum des Kalenders ändert – sei es durch eine Benutzeraktion oder programmgesteuert –, aktualisiert unser Slot „ selectedDateChanged() “ den Editor „ Current Date “. Wir müssen außerdem 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 Comboboxen „ Weekday Color “ und „ Weekend Color “ mithilfe von ` createColorCombo()` ein, wodurch ein ` QComboBox ` instanziiert und mit Farben („Red“, „Blue“ usw.) gefüllt wird.

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

Über die Combobox „ Header Text Format “ kann der Benutzer das Textformat (fett, kursiv oder normal) für horizontale und vertikale Überschriften ändern. Die Kontrollkästchen „ First Friday in blue “ und „ May 1 in red “ beeinflussen die Darstellung bestimmter Datumsangaben.

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

Wir verbinden die Kontrollkästchen und Kombinationsfelder mit verschiedenen privaten Slots. 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.

Damit haben wir 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 ein ` QVariant `, der Benutzerdaten (in diesem Fall ` QColor `-Objekte) speichert.

Diese Funktion wurde verwendet, um die Comboboxen „ 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 Werts der Combobox aufgerufen. Wir rufen das benutzerdefinierte Datenelement ab, das dem neuen aktuellen Element zugeordnet ist, indem wir „ itemData()“ verwenden, und wandeln es in ein „ Qt::DayOfWeek “-Objekt um.

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

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

Die Methode „ selectedDateChanged() “ aktualisiert den Editor „ Current Date “, um den aktuellen Zustand von „ QCalendarWidget “ widerzuspiegeln.

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

Wenn der Benutzer das Mindestdatum ändert, teilen wir dies dem `QCalenderWidget` mit. Außerdem aktualisieren wir den ` Maximum Date `-Editor, denn falls das neue Mindestdatum nach dem aktuellen Höchstdatum liegt, passt ` QCalendarWidget ` sein Höchstdatum automatisch 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 verfügt über ein „ QColor “-Objekt als Benutzerdaten, das dem Text des Elements entspricht. Nachdem wir die Farben aus den Comboboxen abgerufen haben, legen wir das Textformat für jeden Wochentag fest.

Das Textformat einer Spalte im Kalender wird als ` QTextCharFormat` angegeben, wodurch wir neben der Vordergrundfarbe verschiedene Informationen zur Zeichenformatierung festlegen können. In diesem Beispiel zeigen wir nur einen Ausschnitt 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() entspricht „ weekdayFormatChanged() “, mit dem Unterschied, dass es 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 Überschriften ändert. Wir vergleichen den aktuellen Text der Combobox „ Header Text Format “, um zu bestimmen, welches Format angewendet werden soll. (Eine Alternative wäre gewesen, „ QTextCharFormat “-Werte zusammen mit den Combobox-Elementen 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 für den ersten Freitag im Monat und den 1. Mai des laufenden Jahres fest. Die tatsächlich verwendeten Textformate hängen davon ab, welche Kontrollkästchen aktiviert sind und wie die Formate für Wochentage und Wochenenden eingestellt sind.

QCalendarWidget Mit der Funktion „ setDateTextFormat()“ können wir das Textformat einzelner Datumsangaben festlegen. Wir haben uns dafür entschieden, die Datumsformate zu setzen, wenn die Kalenderseite wechselt – d. h. wenn ein neuer Monat angezeigt wird – und wenn das Wochentags-/Wochenendformat geändert wird. Wir prüfen, welche der Optionen „ mayFirstCheckBox “ und „ firstDayCheckBox “ gegebenenfalls aktiviert sind, und legen die Textformate entsprechend fest.

Beispielprojekt @ 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.