En esta página

Ejemplo de widget de calendario

El ejemplo de widget de calendario muestra el uso de QCalendarWidget.

Widget de calendario con varios ajustes

QCalendarWidget muestra un mes del calendario cada vez y permite al usuario seleccionar una fecha. El calendario consta de cuatro componentes: una barra de navegación que permite al usuario cambiar el mes que se muestra, una cuadrícula en la que cada celda representa un día del mes y dos cabeceras que muestran los nombres de los días de la semana y los números de semana.

El ejemplo de widget de calendario muestra un QCalendarWidget y permite al usuario configurar su aspecto y comportamiento mediante QComboBoxes, QCheckBoxes y QDateEdits. Además, el usuario puede influir en el formato de fechas y cabeceras individuales.

Las propiedades de QCalendarWidget se resumen en la siguiente tabla.

PropiedadDescripción
selectedDateFecha seleccionada actualmente.
minimumDateLa fecha más antigua que puede seleccionarse.
maximumDateLa fecha más tardía que puede seleccionarse.
firstDayOfWeekEl día que se muestra como primer día de la semana (normalmente domingo o lunes).
gridVisibleSi debe mostrarse la cuadrícula.
selectionModeSi el usuario puede seleccionar una fecha o no.
horizontalHeaderFormatEl formato de los nombres de los días en la cabecera horizontal (por ejemplo, "M", "Lun" o "Lunes").
verticalHeaderFormatEl formato de la cabecera vertical.
navigationBarVisibleSi se muestra la barra de navegación en la parte superior del widget de calendario.

El ejemplo consta de una clase, Window, que crea y dispone el QCalendarWidget y los otros widgets que permiten al usuario configurar el QCalendarWidget.

Definición de la clase Window

A continuación se muestra la definición de la clase 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;
};

Como suele ocurrir con las clases que representan ventanas autónomas, la mayor parte de la API es privada. Revisaremos los miembros privados a medida que nos topemos con ellos en la implementación.

Implementación de la clase Window

Revisemos ahora la implementación de la clase, empezando por el constructor:

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

Empezamos creando los cuatro QGroupBoxes y sus widgets hijos (incluyendo el QCalendarWidget) usando cuatro funciones privadas create...GroupBox(), descritas a continuación. A continuación, organizamos los cuadros de grupo en un QGridLayout.

Establecemos la política de redimensionamiento de la cuadrícula en QLayout::SetFixedSize para evitar que el usuario redimensione la ventana. En ese modo, el tamaño de la ventana se establece automáticamente por QGridLayout basándose en las sugerencias de tamaño de sus widgets de contenido.

Para asegurarnos de que la ventana no se redimensiona automáticamente cada vez que cambiamos una propiedad de QCalendarWidget (por ejemplo, ocultando la barra de navegación, la cabecera vertical o la rejilla), establecemos la altura mínima de la fila 0 y la anchura mínima de la columna 0 al tamaño inicial de QCalendarWidget.

Pasemos a la función 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);
}

El cuadro de grupo Preview sólo contiene un widget: el QCalendarWidget. Lo configuramos, conectamos su señal currentPageChanged() a nuestra ranura reformatCalendarPage() para asegurarnos de que cada nueva página recibe el formato especificado por el usuario.

La función createGeneralOptionsGroupBox() es algo grande y varios widgets se configuran de la misma manera. Aquí veremos partes de su implementación y nos saltaremos el resto:

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

Comenzamos con la configuración del combobox Week starts on. Este combobox controla qué día debe mostrarse como primer día de la semana.

La clase QComboBox nos permite adjuntar datos de usuario como QVariant a cada elemento. Los datos pueden ser recuperados más tarde con la función itemData() de QComboBox. QVariant no soporta directamente el tipo de datos Qt::DayOfWeek, pero soporta int, y C++ convertirá cualquier valor enum a 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);
    ...

Después de haber creado los widgets, conectamos las señales y las ranuras. Conectamos los comboboxes a los slots privados de Window o a los slots públicos proporcionados por QComboBox.

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

Al final de la función, llamamos a las ranuras que actualizan el calendario para asegurarnos de que QCalendarWidget se sincroniza con los demás widgets al iniciarse.

Veamos ahora la función privada 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);

En esta función, creamos los widgets editores Minimum Date, Maximum Date, y Current Date, que controlan las fechas mínima, máxima y seleccionada del calendario. Las fechas mínimas y máximas del calendario ya han sido establecidas en createPrivewGroupBox(); podemos entonces establecer los valores por defecto de los widgets a los valores del calendario.

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

Conectamos la señal dateChanged() de currentDateEdit directamente a la ranura setSelectedDate() del calendario. Cuando la fecha seleccionada del calendario cambia, ya sea como resultado de una acción del usuario o programáticamente, nuestra ranura selectedDateChanged() actualiza el editor Current Date. También necesitamos reaccionar cuando el usuario cambia los editores Minimum Date y Maximum Date.

Esta es la función 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);

Los combobox Weekday Color y Weekend Color se configuran mediante createColorCombo(), que crea un QComboBox y lo rellena con colores ("Rojo", "Azul", 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"));

El combobox Header Text Format permite al usuario cambiar el formato del texto (negrita, cursiva o normal) utilizado para las cabeceras horizontales y verticales. Las casillas First Friday in blue y May 1 in red afectan a la representación de determinadas fechas.

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

Conectamos las casillas de verificación y los cuadros combinados a varios espacios privados. Las casillas First Friday in blue y May 1 in red están conectadas a reformatCalendarPage(), que también se activa cuando el calendario cambia de mes.

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

Al final de createTextFormatsGroupBox(), llamamos a ranuras privadas para sincronizar QCalendarWidget con los otros widgets.

Hemos terminado de revisar las cuatro funciones de create...GroupBox(). Veamos ahora las otras funciones privadas y los 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;
}

En createColorCombo(), creamos un combobox y lo rellenamos con colores estándar. El segundo argumento de QComboBox::addItem() es un QVariant que almacena datos de usuario (en este caso, objetos QColor ).

Esta función se utilizó para crear los combobox Weekday Color y Weekend Color.

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

Cuando el usuario cambia el valor del combobox Week starts on, se invoca a firstDayChanged() con el índice del nuevo valor del combobox. Recuperamos el elemento de datos personalizado asociado con el nuevo elemento actual utilizando itemData() y lo convertimos en un Qt::DayOfWeek.

selectionModeChanged() horizontalHeaderChanged(), y son muy similares a , por lo que se omiten. verticalHeaderChanged() firstDayChanged()

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

selectedDateChanged() actualiza el editor Current Date para reflejar el estado actual de QCalendarWidget.

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

Cuando el usuario cambia la fecha mínima, se lo decimos al QCalenderWidget. También actualizamos el editor Maximum Date, porque si la nueva fecha mínima es posterior a la fecha máxima actual, QCalendarWidget adaptará automáticamente su fecha máxima para evitar un estado contradictorio.

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

maximumDateChanged() se implementa de forma similar a 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);
}

Cada elemento combobox tiene un objeto QColor como dato de usuario correspondiente al texto del elemento. Tras obtener los colores de los comboboxes, establecemos el formato de texto de cada día de la semana.

El formato de texto de una columna en el calendario se da como QTextCharFormat, que además del color de primer plano nos permite especificar diversa información de formato de caracteres. En este ejemplo, sólo mostramos un subconjunto de las posibilidades.

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() es igual que weekdayFormatChanged(), salvo que afecta a sábado y domingo en lugar de lunes a viernes.

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

La ranura reformatHeaders() se llama cuando el usuario cambia el formato del texto de las cabeceras. Comparamos el texto actual del combobox Header Text Format para determinar qué formato aplicar. (Una alternativa habría sido almacenar los valores de QTextCharFormat junto a los elementos del 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<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);
}

En reformatCalendarPage(), establecemos el formato de texto del primer viernes del mes y del 1 de mayo del año en curso. Los formatos de texto que se utilizan realmente dependen de las casillas de verificación que estén marcadas y de los formatos de día de la semana y fin de semana.

QCalendarWidget nos permite establecer el formato de texto de fechas individuales con el setDateTextFormat(). Hemos elegido establecer los formatos de fecha cuando cambie la página del calendario, es decir, cuando se muestre un nuevo mes, y cuando cambie el formato de día de la semana/fin de semana. Comprobamos cuál de los mayFirstCheckBox y firstDayCheckBox, si hay alguno, está marcado y establecemos los formatos de texto en consecuencia.

Proyecto de ejemplo @ 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.