天天看點

界面開發架構Qt新手入門指南 - 使用Calendar元件建立月曆(一)

作者:慧都科技

Qt 是目前最先進、最完整的跨平台C++開發工具。它不僅完全實作了一次編寫,所有平台無差别運作,更提供了幾乎所有開發過程中需要用到的工具。如今,Qt已被運用于超過70個行業、數千家企業,支援數百萬裝置及應用。

本文中的CalendarWidget示例展示了QCalendarWidget的用法。

界面開發架構Qt新手入門指南 - 使用Calendar元件建立月曆(一)

QCalendarWidget一次顯示一個月曆月,并允許使用者選擇一個日期。月曆由四個元件組成:一個允許使用者更改顯示月份的導航欄、一個網格,其中每個單元格表示一個月中的一天,以及兩個顯示星期名稱和星期數字的标題。

Calendar Widget示例顯示一個QCalendarWidget,并允許使用者使用QComboBoxes、QCheckBoxes和QDateEdits配置其外觀和操作,此外,使用者可以影響單個日期和标題的格式。

QCalendarWidget的屬性總結如下:

  • selectedDate:目前選擇的日期。
  • minimumDate:可以選擇的最早日期。
  • maximumDate:可以選擇的最晚日期。
  • firstDayOfWeek:顯示為一周的第一天的日期(通常是星期日或星期一)。
  • gridVisible:是否顯示網格。
  • selectionMode:使用者是否可以選擇日期。
  • horizontalHeaderFormat:水準标題中日期名稱的格式(例如,"M", "Mon"或"Monday")。
  • verticalHeaderFormat:垂直頁眉的格式。
  • navigationBarVisible:是否顯示月曆小部件頂部的導航欄。

本示例包含一個類Window,它建立并布局QCalendarWidget和其他讓使用者配置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"));
}           

我們首先使用四個私有的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);
...           

我們從組合框上的周開始設定開始,此組合框控制哪一天應顯示為一周的第一天。

QComboBox類允許我們将使用者資料作為QVariant附加到每個項目,稍後可以使用QComboBox的itemData()函數檢索資料。QVariant不直接支援Qt::DayOfWeek資料類型,但它支援int, c++會很樂意将任何enum值轉換為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在啟動時與其他小部件同步。

在下文中,我們将繼續介紹更多實作視窗類的函數,歡迎持續關注哦~

Qt Widget元件推薦

  • QtitanRibbon - Ribbon UI元件:是一款遵循Microsoft Ribbon UI Paradigm for Qt技術的Ribbon UI元件,QtitanRibbon緻力于為Windows、Linux和Mac OS X提供功能完整的Ribbon元件。
  • QtitanChart - Qt類圖表元件:是一個C ++庫,代表一組控件,這些控件使您可以快速地為應用程式提供漂亮而豐富的圖表。
  • QtitanDataGrid - Qt網格元件:提供了一套完整的标準 QTableView 函數和傳統元件無法實作的獨特功能。使您能夠将不同來源的各類資料加載到一個快速、靈活且功能強大的可編輯網格中,支援排序、分組、報告、建立帶狀列、拖放按鈕和許多其他友善的功能。
  • QtitanDocking:允許您像 Visual Studio 一樣為您的偉大應用程式配備可停靠面闆和可停靠工具欄。黑色、白色、藍色調色闆完全支援 Visual Studio 2019 主題!

繼續閱讀