캘린더 위젯 예제

캘린더 위젯 예시에서는 QCalendarWidget.

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

캘린더 위젯 예시에서는 QCalendarWidget 을 표시하고 사용자가 QComboBoxes, QCheckBoxes 및 QDateEdits를 사용하여 모양과 동작을 구성할 수 있으며, 개별 날짜 및 헤더의 서식에 영향을 줄 수 있습니다.

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

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

이 예는 QCalendarWidget 을 생성하고 배치하는 Window 클래스와 사용자가 QCalendarWidget 을 구성할 수 있는 다른 위젯으로 구성되어 있습니다.

창 클래스 정의

다음은 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는 비공개입니다. 비공개 멤버는 구현 과정에서 우연히 발견되는 대로 검토하겠습니다.

창 클래스 구현

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

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

먼저 아래에 설명된 4개의 비공개 create...GroupBox() 함수를 사용하여 4개의 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 콤보박스 설정부터 시작하겠습니다. 이 콤보박스는 어떤 요일을 요일로 표시할지 제어합니다.

QComboBox 클래스를 사용하면 각 항목에 QVariant 으로 사용자 데이터를 첨부할 수 있습니다. 이 데이터는 나중에 QComboBoxitemData() 함수로 검색할 수 있습니다. QVariantQt::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);
    ...
}

currentDateEditdateChanged() 신호를 캘린더의 setSelectedDate() 슬롯에 직접 연결합니다. 사용자 작업의 결과 또는 프로그래밍 방식으로 캘린더에서 선택한 날짜가 변경되면 selectedDateChanged() 슬롯이 Current Date 편집기를 업데이트합니다. 또한 사용자가 Minimum DateMaximum 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);

QComboBox 을 인스턴스화하고 색상("빨강", "파랑" 등)으로 채우는 createColorCombo() 을 사용하여 Weekday ColorWeekend Color 콤보박스를 설정했습니다.

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

사용자가 최소 날짜를 변경하면 QCalenderWidget에 알립니다. 새 최소 날짜가 현재 최대 날짜보다 늦으면 QCalendarWidget 이 모순되는 상태를 피하기 위해 자동으로 최대 날짜를 조정하므로 Maximum Date 에디터도 업데이트합니다.

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 ()를 사용하여 개별 날짜의 텍스트 형식을 설정할 수 있습니다. 캘린더 페이지가 변경될 때, 즉 새 달이 표시될 때와 평일/주말 형식이 변경될 때 날짜 형식을 설정하기로 선택했습니다. mayFirstCheckBoxfirstDayCheckBox 중 어느 것이 체크되어 있는지 확인하고 그에 따라 텍스트 형식을 설정합니다.

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