Пример "Calendar Widget"
Файлы: Пример "Calendar Widget" показывает, как использовать виджет QCalendarWidget. QCalendarWidget выводит на экран один календарный месяц и позволяет пользователю выбрать дату. Календарь состоит из четырёх компонентов: навигационной панели, которая позволяет пользователю менять выводимый на экран месяц, сетки, где каждая ячейка представляет собой один день месяца, и двух заголовков, в которых выводятся дни недели и номер недели. Пример "Calendar Widget" выводит на экран QCalendarWidget и позволяет пользователю настроить его внешний вид и поведение, используя выпадающий списки QComboBox, флажки QCheckBox и редакторов даты QDateEdit. Кроме того, пользователь может воздействовать на форматирование отдельных дат и заголовков. Свойства QCalendarWidget приведены в таблице ниже.
Пример состоит из одного класса, Window, который создаёт и размещает виджет QCalendarWidget и другие виджеты, что позволяет пользователю конфигурировать QCalendarWidget. Определение класса WindowВот определение класса Window: class Window : public QWidget { Q_OBJECT public: Window(); 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(const QDate &date); void maximumDateChanged(const 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::Window() { 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")); } Начнём с создания четырёх QGroupBox и их дочерних виджетов (включая QCalendarWidget) используя четыре закрытых функции create...GroupBox(), описанных ниже. Затем располагаем групповые рамки в 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, SIGNAL(currentPageChanged(int, int)), this, SLOT(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); QList<QLocale::Country> countries = QLocale::countriesForLanguage(lang); for (int i = 0; i < countries.count(); ++i) { QLocale::Country country = countries.at(i); QString label = QLocale::languageToString(lang); label += QLatin1Char('/'); label += QLocale::countryToString(country); QLocale locale(lang, country); if (this->locale().language() == lang && this->locale().country() == country) curLocaleIndex = index; localeCombo->addItem(label, locale); ++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 к каждому элементу. Позднее данные могут быть получены с помощью функции QComboBox - itemData(). QVariant непосредственно не поддерживает тип данных Qt::DayOfWeek, но поддерживает int, а C++ успешно преобразует любое перечислимое значение в int. ... connect(localeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(localeChanged(int))); connect(firstDayCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(firstDayChanged(int))); connect(selectionModeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(selectionModeChanged(int))); connect(gridCheckBox, SIGNAL(toggled(bool)), calendar, SLOT(setGridVisible(bool))); connect(navigationCheckBox, SIGNAL(toggled(bool)), calendar, SLOT(setNavigationBarVisible(bool))); connect(horizontalHeaderCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(horizontalHeaderChanged(int))); connect(verticalHeaderCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(verticalHeaderChanged(int))); ... После создания виджетов, соединяем сигналы со слотами. Соединяем выпадающие списки с закрытыми слотами 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, SIGNAL(dateChanged(const QDate &)), calendar, SLOT(setSelectedDate(const QDate &))); connect(calendar, SIGNAL(selectionChanged()), this, SLOT(selectedDateChanged())); connect(minimumDateEdit, SIGNAL(dateChanged(const QDate &)), this, SLOT(minimumDateChanged(const QDate &))); connect(maximumDateEdit, SIGNAL(dateChanged(const QDate &)), this, SLOT(maximumDateChanged(const QDate &))); ... } Мы соединяем сигнал currentDateEdit'а, dateChanged(), со слотом setSelectedDate() календаря. Затем изменяем выбранную дату календаря, либо в результате выбора пользователя, либо программно, слот selectedDateChanged() обновляет редактор Current Date. Также нам нужно реагировать, когда пользователь изменяет редакторы Minimum Date и Maximum Date. Here is the createTextFormatsGroup() function: 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); Мы настроили выпадающие списки Weekday Color и Weekend Color используя createColorCombo(), которая создаёт объект 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, SIGNAL(currentIndexChanged(int)), this, SLOT(weekdayFormatChanged())); connect(weekendColorCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(weekendFormatChanged())); connect(headerTextFormatCombo, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(reformatHeaders())); connect(firstFridayCheckBox, SIGNAL(toggled(bool)), this, SLOT(reformatCalendarPage())); connect(mayFirstCheckBox, SIGNAL(toggled(bool)), this, SLOT(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"), Qt::red); comboBox->addItem(tr("Blue"), Qt::blue); comboBox->addItem(tr("Black"), Qt::black); comboBox->addItem(tr("Magenta"), Qt::magenta); return comboBox; } В createColorCombo(), создаём выпадающий список и заполняем его стандартными цветами. Второй аргумент в QComboBox::addItem() - QVariant, сохраняющий пользовательские данные (в данном случае, объекты QColor). Эта функция использовалась для настройки выпадающих списков 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() обновляет редактор Current Date чтобы отразить текущее состояние QCalendarWidget. void Window::minimumDateChanged(const QDate &date) { calendar->setMinimumDate(date); maximumDateEdit->setDate(calendar->maximumDate()); } Когда пользователь изменяет минимальную дату, сообщаем её в QCalenderWidget. Также обновляем редактор Maximum Date, поскольку если новая минимальная дата позже, чем текущая максимальная дата, QCalendarWidget автоматически настроит максимальную дату, чтобы избежать противоречивого состояния. void Window::maximumDateChanged(const 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; if (mayFirstCheckBox->isChecked()) mayFirstFormat.setForeground(Qt::red); QTextCharFormat firstFridayFormat; if (firstFridayCheckBox->isChecked()) firstFridayFormat.setForeground(Qt::blue); QDate date(calendar->yearShown(), calendar->monthShown(), 1); calendar->setDateTextFormat(QDate(date.year(), 5, 1), mayFirstFormat); date.setDate(date.year(), date.month(), 1); while (date.dayOfWeek() != Qt::Friday) date = date.addDays(1); calendar->setDateTextFormat(date, firstFridayFormat); } В reformatCalendarPage() устанавливаем формат текста первой пятницы месяца и 1 мая в текущем году. Формы текста, которые реально используются, зависят от того, какой флажок отмечен. QCalendarWidget lets us set the text format of individual dates with the setDateTextFormat(). Мы выбираем установку дат, когда меняется страница календаря, т.е. на экран выводится новый месяц. We check which of the mayFirstCheckBox and firstDayCheckBox, if any, are checked and set the text formats accordingly.
|
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |