Qt 示例学习--2. calendar quick controls

时间:2022-07-01 15:58:42

简介

参看程序运行截图
Qt 示例学习--2. calendar quick controls

分解介绍

同样是一个quick为主的程序:

1 查看qml

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Private 1.0
import QtQuick.Controls.Styles 1.1
import org.qtproject.examples.calendar 1.0

ApplicationWindow {
visible: true
width: 640
height: 400
minimumWidth: 400
minimumHeight: 300
color: "#f4f4f4"

title: "Calendar Example"

SystemPalette { // 系统调色板,用于后门选择颜色的
id: systemPalette
}

SqlEventModel { // 左侧展示的list对应的model,这个model是从c++导入的,后面会看到如何进行导入
id: eventModel
}

Flow { // 这里可以用Row代替,若用Row代替,必须注释layoutDirection: Qt.RightToLeft
id: row
anchors.fill: parent
anchors.margins: 20
spacing: 10
layoutDirection: Qt.RightToLeft

Calendar { // 日历部件
id: calendar
width: (parent.width > parent.height ? parent.width * 0.6 - parent.spacing : parent.width)
height: (parent.height > parent.width ? parent.height * 0.6 - parent.spacing : parent.height)
frameVisible: true
weekNumbersVisible: true
selectedDate: new Date(2014, 0, 1)
focus: true

style: CalendarStyle {
dayDelegate: Item {
readonly property color sameMonthDateTextColor: "#444" // 定义的一些属性值,后面会使用到,相当于私有变量
readonly property color selectedDateColor: Qt.platform.os === "osx" ? "#3778d0" : systemPalette.highlight
readonly property color selectedDateTextColor: "white"
readonly property color differentMonthDateTextColor: "#bbb"
readonly property color invalidDatecolor: "#dddddd"

Rectangle {
anchors.fill: parent
border.color: "transparent"
color: styleData.date !== undefined && styleData.selected ? selectedDateColor : "transparent"
anchors.margins: styleData.selected ? -1 : 0
}

Image { // 三角形上标
visible: eventModel.eventsForDate(styleData.date).length > 0
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: -1
width: 12
height: width
source: "qrc:/images/eventindicator.png"
}

Label {
id: dayDelegateText
text: styleData.date.getDate()
anchors.centerIn: parent
color: {
var color = invalidDatecolor;
if (styleData.valid) {
// Date is within the valid range.
color = styleData.visibleMonth ? sameMonthDateTextColor : differentMonthDateTextColor;
if (styleData.selected) {
color = selectedDateTextColor;
}
}
color;
}
}
}
}
}

Component {
id: eventListHeader

Row {
id: eventDateRow
width: parent.width
height: eventDayLabel.height
spacing: 10

Label {
id: eventDayLabel
text: calendar.selectedDate.getDate()
font.pointSize: 35
}

Column {
height: eventDayLabel.height

Label {
readonly property var options: { weekday: "long" }
text: Qt.locale().standaloneDayName(calendar.selectedDate.getDay(), Locale.LongFormat)
font.pointSize: 18
}
Label {
text: Qt.locale().standaloneMonthName(calendar.selectedDate.getMonth())
+ calendar.selectedDate.toLocaleDateString(Qt.locale(), " yyyy")
font.pointSize: 12
}
}
}
}

Rectangle {
width: (parent.width > parent.height ? parent.width * 0.4 - parent.spacing : parent.width)
height: (parent.height > parent.width ? parent.height * 0.4 - parent.spacing : parent.height)
border.color: Qt.darker(color, 1.2)

ListView {
id: eventsListView
spacing: 4
clip: true
header: eventListHeader // 通过这句话了解到,可以在list中设置任意控件为表头
anchors.fill: parent
anchors.margins: 10
model: eventModel.eventsForDate(calendar.selectedDate) // 根据选择的日期返回对应的model,应该是selectedDate变化后,该model会自动变化(因为未看到其他触发器,具体未验证)

delegate: Rectangle { // 直接定义list各行如何绘制
width: eventsListView.width
height: eventItemColumn.height
anchors.horizontalCenter: parent.horizontalCenter

Image {
anchors.top: parent.top
anchors.topMargin: 4
width: 12
height: width
source: "qrc:/images/eventindicator.png"
}

Rectangle {
width: parent.width
height: 1
color: "#eee"
}

Column {
id: eventItemColumn
anchors.left: parent.left
anchors.leftMargin: 20
anchors.right: parent.right
height: timeLabel.height + nameLabel.height + 8

Label {
id: nameLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.name
}
Label {
id: timeLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.startDate.toLocaleTimeString(calendar.locale, Locale.ShortFormat)
color: "#aaa"
}
}
}
}
}
}
}

2 查看cpp文件

前面qml文件虽然比较长,但均是基础模块叠加,整体比较简单,在代码中均给出注释。

2.1 查看main

int main(int argc, char *argv[])
{
QtQuickControlsApplication app(argc, argv);
qmlRegisterType<SqlEventModel>("org.qtproject.examples.calendar", 1, 0, "SqlEventModel");
QQmlApplicationEngine engine(QUrl("qrc:/qml/main.qml"));
return app.exec();
}

注意到qmlRegisterType(“org.qtproject.examples.calendar”, 1, 0, “SqlEventModel”);即注册了SqlEventModel类型,可以看到main.qml导入该类型:import org.qtproject.examples.calendar 1.0

2.2 查看SqlEventModel源文件

SqlEventModel::SqlEventModel() :
QSqlQueryModel()
{
createConnection();
}

QList<QObject*> SqlEventModel::eventsForDate(const QDate &date)
{
const QString queryStr = QString::fromLatin1("SELECT * FROM Event WHERE '%1' >= startDate AND '%1' <= endDate").arg(date.toString("yyyy-MM-dd"));
QSqlQuery query(queryStr);
if (!query.exec())
qFatal("Query failed");

QList<QObject*> events;
while (query.next()) {
Event *event = new Event(this);
event->setName(query.value("name").toString());

QDateTime startDate;
startDate.setDate(query.value("startDate").toDate());
startDate.setTime(QTime(0, 0).addSecs(query.value("startTime").toInt()));
event->setStartDate(startDate);

QDateTime endDate;
endDate.setDate(query.value("endDate").toDate());
endDate.setTime(QTime(0, 0).addSecs(query.value("endTime").toInt()));
event->setEndDate(endDate);

events.append(event);
}

return events;// QList<QObject*> events,返回的为产找数据库后找到的事件的list
}

/*
Defines a helper function to open a connection to an
in-memory SQLITE database and to create a test table.
*/

void SqlEventModel::createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:"); // 数据存储未QSQLITE方式,此句含义应该是讲数据库存放在内存中
if (!db.open()) {
qFatal("Cannot open database");
return;
}

QSqlQuery query;
// We store the time as seconds because it's easier to query.
query.exec("create table Event (name TEXT, startDate DATE, startTime INT, endDate DATE, endTime INT)");
query.exec("insert into Event values('Grocery shopping', '2014-01-01', 36000, '2014-01-01', 39600)");
query.exec("insert into Event values('Ice skating', '2014-01-01', 57600, '2014-01-01', 61200)");
query.exec("insert into Event values('Doctor''s appointment', '2014-01-15', 57600, '2014-01-15', 63000)");
query.exec("insert into Event values('Conference', '2014-01-24', 32400, '2014-01-28', 61200)");

return;
}

2.3查看event.h

class Event : public QObject
{
Q_OBJECT

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QDateTime startDate READ startDate WRITE setStartDate NOTIFY startDateChanged)
Q_PROPERTY(QDateTime endDate READ endDate WRITE setEndDate NOTIFY endDateChanged)
public:
explicit Event(QObject *parent = 0);

QString name() const;
void setName(const QString &name);

QDateTime startDate() const;
void setStartDate(const QDateTime &startDate);

QDateTime endDate() const;
void setEndDate(const QDateTime &endDate);
signals:
void nameChanged(const QString &name);
void startDateChanged(const QDateTime &startDate);
void endDateChanged(const QDateTime &endDate);
private:
QString mName;
QDateTime mStartDate;
QDateTime mEndDate;
};

这个只需要查看头文件即可:

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QDateTime startDate READ startDate WRITE setStartDate NOTIFY startDateChanged)
Q_PROPERTY(QDateTime endDate READ endDate WRITE setEndDate NOTIFY endDateChanged)

看到头文件中定义了Event的一些属性,对照qml文件中的内容

delegate: Rectangle {
...
Column {
...
Label {
id: nameLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.name
}
Label {
id: timeLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.startDate.toLocaleTimeString(calendar.locale, Locale.ShortFormat)
color: "#aaa"
}
}
}

略去些不重要的行,关注这句:

Label {
id: nameLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.name
}

text的值直接设置的是modelData.name,刚好是Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)设置进去的,于此c++,qml,属性等均和谐地统一到了一起~