이 페이지에서

캘린더 위젯 예제

달력 위젯 예제는 QCalendarWidget 의 사용법을 보여줍니다.

다양한 달력 설정을 보여주는 달력 위젯

QCalendarWidget 한 번에 한 달의 달력을 표시하며, 사용자가 날짜를 선택할 수 있게 해줍니다. 이 달력은 네 가지 구성 요소로 이루어져 있습니다: 사용자가 표시되는 달을 변경할 수 있게 해주는 탐색 모음, 각 셀이 해당 달의 하루를 나타내는 격자, 그리고 요일 이름과 주 번호를 표시하는 두 개의 헤더입니다.

달력 위젯 예제는 QCalendarWidget 를 표시하며, 사용자가 QComboBox, QCheckBox및 QDateEdit를 사용하여 외관과 동작을 구성할 수 있게 합니다. 또한 사용자는 개별 날짜와 헤더의 서식을 조정할 수도 있습니다.

QCalendarWidget 의 속성은 아래 표에 요약되어 있습니다.

속성설명
selectedDate현재 선택된 날짜입니다.
minimumDate선택할 수 있는 가장 이른 날짜입니다.
maximumDate선택할 수 있는 가장 늦은 날짜.
firstDayOfWeek주 첫 번째 날로 표시되는 요일(일반적으로 일요일 또는 월요일).
gridVisible그리드를 표시할지 여부.
selectionMode사용자가 날짜를 선택할 수 있는지 여부.
horizontalHeaderFormat가로 헤더에 표시되는 요일 이름의 형식(예: "M", "Mon" 또는 "Monday").
verticalHeaderFormat세로 방향 헤더의 형식.
navigationBarVisible달력 위젯 상단의 탐색 모음이 표시될지 여부.

이 예제는 하나의 클래스( Window)로 구성되어 있으며, 이 클래스는 QCalendarWidget 및 사용자가 QCalendarWidget 를 구성할 수 있게 해주는 다른 위젯들을 생성하고 레이아웃을 지정합니다.

Window 클래스 정의

다음은 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;
};

자립형 창을 나타내는 클래스에서 흔히 볼 수 있듯이, API의 대부분은 private으로 선언되어 있습니다. 구현 과정에서 private 멤버들을 접하게 될 때마다 이에 대해 살펴보겠습니다.

Window 클래스 구현

이제 생성자부터 시작하여 클래스 구현을 살펴보겠습니다:

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의 최소 높이와 열 0의 최소 너비를 QCalendarWidget 의 초기 크기로 설정합니다.

이제 ` 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);
}

Preview 그룹 박스에는 QCalendarWidget 위젯 하나만 포함되어 있습니다. 이 위젯을 설정하고, currentPageChanged() 신호를 reformatCalendarPage() 슬롯에 연결하여 모든 새 페이지가 사용자가 지정한 서식을 적용받도록 합니다.

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

먼저 Week starts on 콤보박스의 설정부터 시작하겠습니다. 이 콤보박스는 주(week)의 첫 번째 날로 표시될 요일을 제어합니다.

QComboBox 클래스를 사용하면 각 항목에 사용자 데이터를 ` QVariant `로 연결할 수 있습니다. 이 데이터는 나중에 ` QComboBox`의 ` itemData()` 함수를 통해 가져올 수 있습니다. ` QVariant `는 ` Qt::DayOfWeek ` 데이터 유형을 직접 지원하지는 않지만, ` int`를 지원하며, C++은 모든 열거형 값을 ` 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);
    ...

위젯을 생성한 후, 신호와 슬롯을 연결합니다. 콤보박스를 Window 의 비공개 슬롯이나 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);

이 함수에서는 달력의 최소, 최대 및 선택된 날짜를 제어하는 Minimum Date, Maximum Date 및 Current Date 편집기 위젯을 생성합니다. 달력의 최소 및 최대 날짜는 이미 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() 슬롯이 Current Date 에디터를 업데이트합니다. 또한 사용자가 Minimum Date 및 Maximum Date 에디터를 변경할 때도 이에 대응해야 합니다.

다음은 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);

우리는 createColorCombo() 를 사용하여 Weekday Color 및 Weekend Color 콤보박스를 설정했는데, 이 코드는 QComboBox 객체를 인스턴스화하고 “Red”, “Blue” 등의 색상을 할당합니다.

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

Header Text Format 콤보박스를 통해 사용자는 가로 및 세로 헤더에 적용될 텍스트 서식(굵게, 기울임꼴 또는 일반)을 변경할 수 있습니다. First Friday in blue 및 May 1 in red 확인란은 특정 날짜의 표시 방식에 영향을 미칩니다.

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

체크박스와 콤보박스를 다양한 비공개 슬롯에 연결합니다. ' First Friday in blue ' 및 ' May 1 in red ' 체크박스는 모두 ' 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()의 두 번째 인수는 사용자 데이터(이 경우 QColor 객체)를 저장하는 QVariant 입니다.

이 함수는 Weekday Color 및 Weekend Color 콤보박스를 설정하는 데 사용되었습니다.

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

사용자가 Week starts on 콤보박스의 값을 변경하면, firstDayChanged() 가 콤보박스의 새 값에 해당하는 인덱스와 함께 호출됩니다. 우리는 itemData()를 사용하여 새로운 현재 항목과 연관된 사용자 정의 데이터 항목을 가져온 다음, 이를 Qt::DayOfWeek 로 형변환합니다.

selectionModeChanged(), horizontalHeaderChanged() 및 verticalHeaderChanged() 는 firstDayChanged() 와 매우 유사하므로 생략합니다.

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

selectedDateChanged() 은 QCalendarWidget 의 현재 상태를 반영하도록 Current Date 편집기를 업데이트합니다.

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

사용자가 최소 날짜를 변경하면 QCalendarWidget에 이를 알립니다. 또한 Maximum Date 편집기도 업데이트합니다. 새로운 최소 날짜가 현재 최대 날짜보다 늦은 경우, QCalendarWidget 는 모순된 상태를 방지하기 위해 최대 날짜를 자동으로 조정하기 때문입니다.

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

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

각 콤보박스 항목에는 해당 항목의 텍스트에 대응하는 사용자 데이터로 QColor 객체가 있습니다. 콤보박스에서 색상을 가져온 후, 각 요일의 텍스트 서식을 설정합니다.

달력 내 열의 텍스트 형식은 ` QTextCharFormat`로 지정되며, 이를 통해 전경색 외에도 다양한 문자 서식 정보를 지정할 수 있습니다. 이 예제에서는 가능한 기능 중 일부만 보여줍니다.

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() 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() 슬롯은 사용자가 헤더의 텍스트 서식을 변경할 때 호출됩니다. Header Text Format 콤보박스의 현재 텍스트를 비교하여 어떤 서식을 적용할지 결정합니다. (다른 방법으로는 콤보박스 항목과 함께 QTextCharFormat 값을 저장하는 것도 가능합니다.)

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

reformatCalendarPage() 에서는 해당 월의 첫 번째 금요일과 당해 연도의 5월 1일에 대한 텍스트 서식을 설정합니다. 실제로 사용되는 텍스트 서식은 어떤 확인란이 선택되었는지와 평일/주말 서식 설정에 따라 달라집니다.

QCalendarWidget setDateTextFormat()를 사용하면 개별 날짜의 텍스트 서식을 설정할 수 있습니다. 우리는 달력 페이지가 변경될 때(즉, 새로운 달이 표시될 때)와 평일/주말 서식이 변경될 때 날짜 서식을 설정하도록 했습니다. 와 중 어떤 항목이 선택되었는지 확인하고, 그에 따라 텍스트 서식을 설정합니다. mayFirstCheckBox firstDayCheckBox

예제 프로젝트 @ 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.