C++期末项目——壹点壹口任务管理器

、 课程设计目的及要求
1、 设计目的
计算机科学与技术专业所开设的C++课程设计是教学实践环节中的一项重要内容,进行此课程设计的旨在:
1、提高和加强学生的计算机应用与软件开发能力,使学生由初学者向专业的程序员过渡。
2、培养学生独立分析问题、解决问题、查阅资料以及自学能力,以适应计算机产业日新月异发展的形势。
3、学习和掌握C++程序设计方法以及上机调试技巧,为以后学习其它专业课程打好基础。
本次课程设计是以学生独立思考解决问题为主,教师指导为辅,结合上机操作,完成指定的任务,做出设计报告。
2、 设计具体内容及要求
(一) 基础设计题目
 建立图形拥护界面。
 有存储数据的能力。
 使用类的继承、虚基类。
 使用友元、函数重载。
 使用虚函数实现多态性。
 需求文档、整体功能图、类图、流程图等。

(二) 具体内容:壹点壹口·任务规划器
互联网上有非常丰富的音乐资源任务管理器,做得好的如Ticktick、Todo等大型软件,当使用高级功能时需要付费,且功能臃肿,会员还不能买断,只能订月子,根本用不起,不符合个人使用习惯,于是决定设计一个个人任务管理器:壹点壹口。(其实就是看不惯在用的TickTick只有windows用户要会员,凭什么?明明MAC用户更有钱好不好!!!)
一个任务的信息包括任务内容、开始时间 、截止时间、完成情况、具体描述、任务编号等信息。设计任务管理系统统,系统仿照TickTick软件制作,增添一系列功能。:
 轻松记录大小事务
 支持二维码导出信息查看任务
 为任务打上标签,用来标识“情境”、“状态”或其他,以便更加灵活的进行筛选。
 任务信息的删除、修改功能
 在日历视图中概览全局、查看时间轴,即刻掌握各天的日程。
 导出到excel的记录支持所有excel+wps等表格文件版本,不依赖excel等软件。
 使用FlatUi,界面仿照TickTick。
 支持用户权限管理,用户登录+用户退出,可以记住密码和自动登录。
 本地数据存储支持sqlite,可以随着创建账号,创建数据表。
 数据库自带默认信息,以便在新帐号的的时候测试数据。
 按道理来说支持windows操作系统+linux操作系统和其他操作系统。(未测试)

二、 课程设计具体实现
1、建立图形界面
(1)图形界面的总体设计
Qt 是一个基于C ++ 的跨平台图形用户界面( Graphical User Interface,GUI) 应用程序开发框架,它提供给应用程序开发者建立艺术级 GUI所需的所有功能,允许组件编程,且易扩展. 此外,Qt提供了较丰富的数据库接口、传输控制协议、文件传输协议等与平台无关的类,能够方便地进行开发. 本应用利用 Qt 的 GUI 框架和数据库,实现了一款纯净、高性能的任务管理器,其既具有任务管理器基本的常用功能,也实现了基于日历视图的任务管理器。
(2)图形界面的详细设计
主要完成的功能:
每个窗口都可以通过过标题栏来实现窗口拖动,主界面实现了透明美化,省略了标题栏。
使用QT美化界面。
主要使用技术:
运算符的重载,动态分配内存,字符串函数的使用。
关键代码:
 实现窗口的拖动
Windows 系统中,存在各种“消息”,如鼠标消息、按键消息等. Qt 已经把想要的“消息”封装成 3 个函数: mousePressEvent、mouseMoveEvent、mouseReleaseEvent. 通过重写这些函数,即可实现对鼠标行为的定制,
void mouseReleaseEvent( QMouseEvent* event)
{
isPress = false;
}
void mousePressEvent( QMouseEvent* event)
{
lastPos = event->globalPos( ) ; /* 记录鼠标的当前位置* /
isPress = true; /* 标记鼠标是否在主面板上按下* /
}
void mouseMoveEvent( QMouseEvent* event)
{
if ( isPress) /* 鼠标按下的时候才移动,防止从子控件移
动到主面板上时产生的“瞬移”* /
{
int dx = event - > globalX( ) - lastPos. x( ) ;
int dy = event - > globalY( ) - lastPos. y( ) ;
lastPos = event - > globalPos( ) ;
move( x( ) + dx,y( ) + dy) ; /* 通过鼠标上次出现的位
置与当前位置的差,求出窗口的移动方向和长度* /
}
}
其中,isPress 是自己设定的的一个内部变量,当等于0时,无法移动,当为1时,可以移动. Qt 提供了很多种无边框窗口移动的代码,但其几乎都没有 isPress 的存在.
}
 用QSS美化界面
QSS( Qt Style Sheets) 是一种类似于 WEB 设计中层叠样式表( Cascading Style Sheets,CSS) 技术的设计语言,它的目标和 CSS 相同,即实现表现与内容分离. 通过 QSS,可以很方便地实现界面的美化,而不需要编写大量用于控件自绘的代码. 比如,设置按钮的背景图片。
 public:
static QString setPushButtonQss(QPushButton *btn, //按钮对象
int radius = 5,
int padding = 8,
const QString &normalColor = “#34495E”,
const QString &normalTextColor = “#FFFFFF”,
const QString &hoverColor = “#4E6D8C”,
const QString &hoverTextColor = “#F0F0F0”,
const QString &pressedColor = “#2D3E50”,
const QString &pressedTextColor = “#B8C6D1”);

//设置文本框样式
static QString setLineEditQss(QLineEdit *txt,                                   //文本框
                              int radius = 3,                                   //圆角半径
                              int borderWidth = 2,                              //边框大小
                              const QString &normalColor = "#DCE4EC",           //正常颜色
                              const QString &focusColor = "#34495E");           //选中颜色

};
以上是程序中flatui.h中的部分代码,用于实现flatUI的风格。其中美化的代码使用了网页课程中学习的css2。
(3)背景颜色的解决
使用Qt自带的QPalette 函数(绘画函数)
QPalette bgpal = palette();
QLinearGradient linearGrad(QPointF(0, 0), QPointF(200, 200));
linearGrad.setColorAt(1, Qt::lightGray);
linearGrad.setColorAt(0, Qt::darkGray);
QBrush brush(linearGrad);
bgpal.setBrush(QPalette::Background,brush);
//bgpal.setColor (QPalette::Background, QColor (0, 0 , 0, 255));

//bgpal.setColor (QPalette::Background, Qt::transparent);

bgpal.setColor (QPalette::Foreground, QColor (255,255,255,255)); setPalette (bgpal);。

分别设置前景色和后景色,并使用渐变。

(后面觉得有点丑就把上面这段给注释掉了,留白还好看点)
2、存储数据的能力
(1)详细设计
是用了Qt内置的sqlite数据库,而且数据量能支持亿级别

主要使用的技术:
数据库的创建绑定、表单的创建和编辑,基本的SQL语句使用。
关键代码如下:
static bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase(“QSQLITE”);
db.setDatabaseName(“TaskDb.db”);
db.setUserName(QString(“ydyk”));
db.setPassword(QString(“123456”));
if(! db.open())
{
QMessageBox::critical(0,QString(“启动失败”)
,QString(“无法创建数据库\n原因:%1”).arg(db.lastError().text()),
QMessageBox::Ok);
return false;
}
return true;
}

3、 使用类的继承、虚基类。
类图:

AbstractEvent
//AbstractEvent是一个虚基类(因为使用了纯虚函数)
enum EventType { ContinuousEvent, RecurrentEvent };
//用来记录任务的状态

explicit AbstractEvent() {}
explicit AbstractEvent(const QDate& begin, const QDate& end);
virtual ~AbstractEvent();

QDate Begin() const { return begin; }
QDate End() const { return end; }
QString Title() const { return title; }
QString Place() const { return place; }
QString Detail() const { return detail; }
QColor LabelColor() const { return color; }
QString MagicString() const { return magic_string; }
int FileCount() const { return file_name_list.size(); }
QString FilePathAt(int i) const;

void ResetBeginEnd(const QDate& begin, const QDate& end)
{
    this->begin = begin;
    this->end = end;
}
void SetTitle(const QString& text) { title = text; }
void SetPlace(const QString& text) { place = text; }
void SetDetail(const QString& text) { detail = text; }
void SetLabelColor(const QColor& col) { color = col; }

bool AddFile(const QString& filePath, QWidget* parent);
void RemoveFile(const QString &fileName);
void RemoveAllFiles();
void Clone(AbstractEvent* event);

virtual EventType Type() const = 0;
virtual bool InList(const QDate& date) const = 0;

friend QDataStream& operator <<(QDataStream& dataStream, AbstractEvent* event);
friend QDataStream& operator >>(QDataStream& dataStream, AbstractEvent** event);

protected:
QDate begin, end;
QString title, place, detail, magic_string;
QColor color;
QStringList file_name_list;

virtual void save(QDataStream &dataStream) const = 0;
virtual void load(QDataStream &dataStream) = 0;

};

上面是抽象类,也就是基类。
后面建立一个ContinuousEvent和RecurrentEvent 分别继承AbstractEvent,分别代表两种任务类型:连续任务和重复任务。
关键代码如下:class RecurrentEvent : public AbstractEvent
class ContinuousEvent : public AbstractEvent
等等等,更多见下面管理器设计类图等模块。
虚基类:以上的AbstractEvent函数作为虚基类,其
virtual EventType Type() const = 0;
virtual bool InList(const QDate& date) const = 0;
用于在ContinuousEvent和RecurrentEvent类中分别表达。具体的实现见后面相关代码。
4、使用友元、函数重载、运算符重载。

Friend函数
friend class MainWindow;//在qrcretor里使用的,使得主窗口可以调用,创建二维码。
friend QDataStream& operator <<(QDataStream& dataStream, AbstractEvent* event);
friend QDataStream& operator >>(QDataStream& dataStream, AbstractEvent** event);//在抽象类中使用的两个运算符重载,用到了友元用于读取文件的时候判断是否有重复

函数重载
1.之前的纯虚函数在两个类中的不同表达。
virtual EventType Type() const override
{ return EventType::ContinuousEvent; }
EventType Type() const override { return EventType::RecurrentEvent; }
2.构造函数的函数重载
在abstractEvent头文件中,
explicit AbstractEvent() {}
explicit AbstractEvent(const QDate& begin, const QDate& end);
通过使用函数重载,展现了C++的多态性。

5、使用虚函数实现多态性。
虚函数
1.纯虚函数:
virtual EventType Type() const = 0;
virtual bool InList(const QDate& date) const = 0;
virtual void save(QDataStream &dataStream) const = 0;
virtual void load(QDataStream &dataStream) = 0;

2.虚函数:
virtual ~AbstractEvent();//基类的析构函数写成虚函数。

6、个人任务管理器(面向对象)
(1)总体设计
设计类图:
用户类:
userTb字段类型
1-username-varchar(15)
2-password-varchar(20)
3-lastLogTime-datetime
explicit loginDialog(QWidget *parent = nullptr);//构造函数
~loginDialog();//析构函数
QString getUserNmae() const;//获取用户名

private slots:
void on_loginBtn_clicked();//登录函数
void on_logupBtn_clicked();//注册函数
private:
Ui::loginDialog *ui;
QPoint startPoint;
bool isDrag;//拖动
void setting();//保存设置(是否自动登入、记住密码)
void getSetting();//获取设置
void accpept();

任务类(数据库版):
TaskTb(数据表)
1-taskId-int
2-taskName-varchar(200)
3-bgLine-datetime
4-ddLine-datatime
5-taskFlag-bool
6-PRI-INT
7-typeId-int
8-note-memo
//使用基本的SQL语句建立任务表:任务id、任务内容、任务标签、重要度、起始时间、终止时间、完成flag
query.exec(QString(“create table taskTb (taskId int primary key,taskName varchar(200) not null”
“,bgLine datetime not null,ddLine datatime”
“,taskFlag bool not null,PRI INT,typeId int,note memo”
“,foreign key(typeId) references taskTypeTb)”));
query.exec(QString(“insert into taskTb values(01,‘完成数据库与程序的分离’,‘2019-12-01 12:13:14’,‘2019-12-07 12:13:14’,false,1,00,‘faster’)”));

任务类(抽象类):
AbstractEvent
QDate begin, end;
QString title, place, detail, magic_string;
QColor color;
QStringList file_name_list;
explicit AbstractEvent() {}
explicit AbstractEvent(const QDate& begin, const QDate& end);
virtual ~AbstractEvent();

QDate Begin() const { return begin; }
QDate End() const { return end; }
QString Title() const { return title; }
QString Place() const { return place; }
QString Detail() const { return detail; }
QColor LabelColor() const { return color; }
QString MagicString() const { return magic_string; }
int FileCount() const { return file_name_list.size(); }
QString FilePathAt(int i) const;

void ResetBeginEnd(const QDate& begin, const QDate& end)
{
    this->begin = begin;
    this->end = end;
}
void SetTitle(const QString& text) { title = text; }
void SetPlace(const QString& text) { place = text; }
void SetDetail(const QString& text) { detail = text; }
void SetLabelColor(const QColor& col) { color = col; }

bool AddFile(const QString& filePath, QWidget* parent);
void RemoveFile(const QString &fileName);
void RemoveAllFiles();
void Clone(AbstractEvent* event);

virtual EventType Type() const = 0;
virtual bool InList(const QDate& date) const = 0;

friend QDataStream& operator <<(QDataStream& dataStream, AbstractEvent* event);
friend QDataStream& operator >>(QDataStream& dataStream, AbstractEvent** event);

连续任务类:
ContinuousEvent
继承任务类
ContinuousEvent::ContinuousEvent(const QDate& begin, const QDate& end) :
AbstractEvent(begin, end)(连续任务类继承了任务类的所有操作)

复发事件类
RecurrentEvent
继承任务类
RecurrentType type;
int interval, day_mark, end_times;
int month_day, month_weekday, month_weekday_num;
int year_month;
int end_type, repeat_times;
QDate repeat_end;
std::set skip_set;
class RecurrentEvent : public AbstractEvent(复发事件类继承了任务类的所有操作)
RecurrentType GetRecurrentType() const { return type; }
int Interval() const { return interval; }
int DayMark() const { return day_mark; }
int MonthDay() const { return month_day; }
int MonthWeekday() const { return month_weekday; }
int MonthWeekdayNum() const { return month_weekday_num; }
int YearMonth() const { return year_month; }
int EndType() const { return end_type; }
int RepeatTimes() const { return repeat_times; }

// Setter member functions
void SetRecurrentType(RecurrentType x) { type = x; }
void SetInterval(int x) { interval = x; }
void SetDayMark(int x) { day_mark = x; }
void SetMonthDay(int x) { month_day = x; }
void SetMonthWeekday(int x) { month_weekday = x; }
void SetMonthWeekdayNum(int x) { month_weekday_num = x; }
void SetYearMonth(int x) { year_month = x; }
void SetEndType(int x)
{
    end_type = x;
    if (end_type == 2) repeat_end = end; else repeat_end = Const::MAX_DATE;
}
void SetRepeatTimes(int x);

void AddSkip(const QDate& date) { skip_set.insert(date); }

private:
RecurrentType type;
int interval, day_mark, end_times;
int month_day, month_weekday, month_weekday_num;
int year_month;
int end_type, repeat_times;
QDate repeat_end;
std::set skip_set;

virtual void save(QDataStream &dataStream) const override;
virtual void load(QDataStream &dataStream) override;

(2)详细设计
主要完成的功能:
任务信息的录入功能,任务状态的设置,任务信息不同方式浏览功能,单独浏览整个任务的信息,日历视图浏览任务信息:GUI模式浏览任务、任务信息删除、修改功能。(表格模式下,多用户登录,分别建立不同的数据库表单)
主要使用的技术:
结构体,指针,链表的应用,switch语句等。
关键设计及界面截屏:(由于代码数量过多影响文档浏览,.cpp文件放在附录

1、主界面
(1)主函数:

Qt的界面由于可以使用设计模式直接编辑生成.ui文件,编辑结果如下图。

2、sqlite数据库的连接和建立
#ifndef SQLCONECTION_H
#define SQLCONECTION_H
//使用静态函数把数据库的连接和主界面实现函数分离

#include
#include
#include
#pragma execution_character_set(“utf-8”)

/*
建立数据库以及表
*/
static bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase(“QSQLITE”);
db.setDatabaseName(“TaskDb.db”);
db.setUserName(QString(“ydyk”));
db.setPassword(QString(“123456”));
if(! db.open())
{
QMessageBox::critical(0,QString(“启动失败”)
,QString(“无法创建数据库\n原因:%1”).arg(db.lastError().text()),
QMessageBox::Ok);
return false;
}
return true;
}

static void makeData(){
QProgressDialog sqldialog;
sqldialog.setWindowModality(Qt::WindowModal);
//将子窗口和主窗口独立
sqldialog.setWindowTitle(QObject::tr(“创建数据库”));
sqldialog.setLabelText(QObject::tr(“creating…”));
sqldialog.setMinimum(0);
sqldialog.setMaximum(100);
sqldialog.show();
qApp->processEvents();
QSqlQuery query;
query.exec(QString(“create table userTb (username varchar(15) primary key,”
“password varchar(20),”
“lastLogTime datetime not null)”));
query.exec(QString(“insert into userTb values(‘admin’,‘123456’,‘2019-11-12 02:13:14’)”));
query.exec(QString(“insert into userTb values(‘ydyk’,‘123456’,‘2019-10-16 10:16:00’)”));
//建立用户表
qApp->processEvents();
sqldialog.setValue(20);

//建立Basket:收集箱、垃圾箱、waitingBox
query.exec(QString("create table taskTypeTb (typeId int primary key,taskType varchar(20) not null)"));
query.exec(QString("insert into taskTypeTb values(00,'收集箱')"));
query.exec(QString("insert into taskTypeTb values(01,'垃圾箱')"));
query.exec(QString("insert into taskTypeTb values(02,'待办')"));
query.exec(QString("insert into taskTypeTb values(03,'日常任务')"));
qApp->processEvents();
sqldialog.setValue(50);
//建立任务表:任务id、任务内容、任务标签、重要度、起始时间、终止时间、完成flag
query.exec(QString("create table taskTb (taskId int primary key,taskName varchar(200) not null"
                   ",bgLine datetime not null,ddLine datatime"
                   ",taskFlag bool not null,PRI INT,typeId int,note memo"
                   ",foreign key(typeId) references taskTypeTb)"));
query.exec(QString("insert into taskTb values(01,'完成数据库与程序的分离','2019-12-01 12:13:14','2019-12-07 12:13:14',false,1,00,'faster')"));
query.exec(QString("insert into taskTb values(02,'登入页面的建立','2019-12-07 12:13:14','2019-12-07 12:13:14',true,1,00,'faster')"));
query.exec(QString("insert into taskTb values(03,'完善各种功能','2019-12-07 12:13:14','2019-12-08 12:13:14',0,1,00,'faster')"));
query.exec(QString("insert into taskTb values(04,'美化界面','2019-12-08 12:13:14','2019-12-08 12:13:14',1,1,00,'faster')"));
qApp->processEvents();
sqldialog.setValue(80);

qApp->processEvents();
sqldialog.setValue(100);

}

static bool addAccout(QString str){
QSqlQuery query;
query.exec(QString(“create table ‘%1’ (taskId int primary key,taskName varchar(200) not null”
“,bgLine datetime not null,ddLine datatime”
“,taskFlag bool not null,PRI INT,typeId int,note memo”
“,foreign key(typeId) references taskTypeTb)”).arg(str));
query.exec(QString(“insert into ‘%1’ values(01,‘完成数据库与程序的分离’,‘2019-12-01 12:13:14’,‘2019-12-07 12:13:14’,false,1,00,‘faster’)”).arg(str));
query.exec(QString(“insert into ‘%1’ values(02,‘登入页面的建立’,‘2019-12-07 12:13:14’,‘2019-12-07 12:13:14’,true,1,00,‘faster’)”).arg(str));
query.exec(QString(“insert into ‘%1’ values(03,‘完善各种功能’,‘2019-12-07 12:13:14’,‘2019-12-08 12:13:14’,0,1,00,‘faster’)”).arg(str));
query.exec(QString(“insert into ‘%1’ values(04,‘美化界面’,‘2019-12-08 12:13:14’,‘2019-12-08 12:13:14’,1,1,00,‘faster’)”).arg(str));

return true;

}

#endif // SQLCONECTION_H

3、表格模式浏览任务信息
void MainWindow::openTable(QString user)
{
//打开数据表
QSqlDatabase db = QSqlDatabase::addDatabase(“QSQLITE”);
db.setDatabaseName(“TaskDb.db”);
if(! db.open())
{
QMessageBox::critical(nullptr,QString(“启动失败”)
,QString(“无法创建数据库\n原因:%1”).arg(db.lastError().text()),
QMessageBox::Ok);
}

tabModel=new QSqlTableModel(this,db);//数据表
tabModel->setTable(QString("%1").arg(user)); //设置数据表
tabModel->setEditStrategy(QSqlTableModel::OnRowChange);//数据保存方式,OnRowChange:当离开正在编辑的这一行的时候,立刻保存到数据库中
tabModel->setSort(tabModel->fieldIndex("Taskid"),Qt::AscendingOrder); //排序
if (!(tabModel->select()))//查询数据
{
   QMessageBox::critical(this, "错误信息",
          "打开数据表错误,错误信息\n"+tabModel->lastError().text(),
             QMessageBox::Ok,QMessageBox::NoButton);
   return;
}

//字段显示名
tabModel->setHeaderData(tabModel->fieldIndex(“taskId”),Qt::Horizontal,QString(tr(“任务编号”)));
tabModel->setHeaderData(tabModel->fieldIndex(“taskName”),Qt::Horizontal,“任务”);
tabModel->setHeaderData(tabModel->fieldIndex(“bgLine”),Qt::Horizontal,“开始时间”);
tabModel->setHeaderData(tabModel->fieldIndex(“ddLine”),Qt::Horizontal,“截止时间”);
tabModel->setHeaderData(tabModel->fieldIndex(“taskFlag”),Qt::Horizontal,“状态”);
tabModel->setHeaderData(tabModel->fieldIndex(“PRI”),Qt::Horizontal,“优先级”);
tabModel->setHeaderData(tabModel->fieldIndex(“typeId”),Qt::Horizontal,“类型”);
tabModel->setHeaderData(tabModel->fieldIndex(“note”),Qt::Horizontal,“备注”);
theSelection=new QItemSelectionModel(tabModel);//关联选择模型
//theSelection当前项变化时触发currentChanged信号
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
//选择行变化时
connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));

ui->tableView->setModel(tabModel);//设置数据模型
ui->tableView->setSelectionModel(theSelection); //设置选择模型
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->tableView->setAlternatingRowColors(true);
ui->tableView->setColumnHidden(tabModel->fieldIndex("Taskid"),true);/ 
dataMapper= new QDataWidgetMapper();
dataMapper->setModel(tabModel);//设置数据模型
dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
dataMapper->addMapping(ui->calendarWidget, tabModel->fieldIndex("ddLine"));
dataMapper->addMapping(ui->lcdNumber, tabModel->fieldIndex("ddLine"));
dataMapper->setItemDelegate(new QSqlRelationalDelegate(this)); 

dataMapper->addMapping(ui->taskLineEdit,tabModel->fieldIndex(“taskName”)); dataMapper->addMapping(ui->ddTImeEdit,tabModel->fieldIndex(“ddLine”)) dataMapper->addMapping(ui->stateCheckBox,tabModel->fieldIndex(“taskFlag”)); dataMapper->addMapping(ui->taskMemo,tabModel->fieldIndex(“note”));
dataMapper->addMapping(ui->lineEdit,tabModel->fieldIndex(“typeId”));
dataMapper->toFirst();//移动到首记录

4、 排序与筛选任务信息

void MainWindow::on_allBtn_clicked()
{
tabModel->setFilter("");
tabModel->select();
}
void MainWindow::on_todayBtn_clicked()
{
QDateTime now =QDateTime::currentDateTime();
//now = now.addDays(1);
QString sqlStr = QString(“ddLine > convert(varchar(10),’%1’,120)”).arg(now.toString());
tabModel->setFilter(sqlStr);
tabModel->select();
}
void MainWindow::on_sevenBtn_clicked()
{
QDateTime now =QDateTime::currentDateTime();
QDateTime next = now.addDays(6);
QString sqlStr = QString(“ddLine < convert(varchar(10),’%1’,120)”).arg(next.toString());
tabModel->setFilter(sqlStr);
tabModel->select();
}

case 2: 排序

void MainWindow::on_radioButton_clicked()
{//正序排序
tabModel->setSort(1,Qt::AscendingOrder);
tabModel->select();
}

void MainWindow::on_radioButton_2_clicked()
{
//倒序排序
tabModel->setSort(1,Qt::DescendingOrder);
tabModel->select();
}

5、 任务详细情况实现
//创建界面组件与数据模型的字段之间的数据映射
dataMapper= new QDataWidgetMapper();
dataMapper->setModel(tabModel);//设置数据模型
dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);//

dataMapper->addMapping(ui->calendarWidget, tabModel->fieldIndex("ddLine"));
dataMapper->addMapping(ui->lcdNumber, tabModel->fieldIndex("ddLine"));
dataMapper->setItemDelegate(new QSqlRelationalDelegate(this)); //含有外键的

//界面组件与tabModel的具体字段之间的联系
dataMapper->addMapping(ui->taskLineEdit,tabModel->fieldIndex(“taskName”));
dataMapper->addMapping(ui->ddTImeEdit,tabModel->fieldIndex(“ddLine”));

dataMapper->addMapping(ui->stateCheckBox,tabModel->fieldIndex("taskFlag"));
dataMapper->addMapping(ui->taskMemo,tabModel->fieldIndex("note"));
dataMapper->addMapping(ui->lineEdit,tabModel->fieldIndex("typeId"));

dataMapper->toFirst();//移动到首记录	 }

6、 新建或删除任务信息
删除信息:
void MainWindow::on_pushButton_clicked()
{
QModelIndex curIndex = theSelection->currentIndex();
tabModel->removeRow(curIndex.row());

}
新建:
void MainWindow::on_pushButton_2_clicked()
{
tabModel->insertRow(tabModel->rowCount(),QModelIndex());
QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);
int currow = curIndex.row();

QDateTime now =QDateTime::currentDateTime();
tabModel->setData(tabModel->index(currow,0),1000+tabModel->rowCount());
tabModel->setData(tabModel->index(currow,1),"请输入你的任务");
tabModel->setData(tabModel->index(currow,2),now);
tabModel->setData(tabModel->index(currow,3),now);
tabModel->setData(tabModel->index(currow,4),false);
tabModel->setData(tabModel->index(currow,6),0);
tabModel->setData(tabModel->index(currow,7),0);

if(!(tabModel->submitAll()))
    QMessageBox::information(this, "消息", "数据保存错误,错误信息\n"+tabModel->lastError().text(),
                             QMessageBox::Ok,QMessageBox::NoButton);

}

5.5 二维码按功能的实现

这次二维码的实现的实现我直接使用了外国大神的库函数,只是直接建立以了一个接口类
#include “qrcretor.h”

#include
#include
#include"QrCode.hpp"
using namespace qrcodegen;

QRcretor::QRcretor()
{
Show_QRcode_Picture();
}

QImage QRcretor::Show_QRcode_Picture(QString message)
{
std::vector segs=
QrSegment::makeSegments(message.toUtf8());
QrCode qr1 = QrCode::encodeSegments(
segs,QrCode::Ecc::HIGH,5,10,2,false);
//创建二维码画布
QrCode_Image = QImage(qr1.getSize(),qr1.getSize(),QImage::Format_RGB888);

for (int y = 0;y < qr1.getSize();y++) {
    for (int x = 0;x<qr1.getSize();x++) {
        if(qr1.getModule(x,y)==0)
        QrCode_Image.setPixel(x,y,qRgb(255,255,255));
        else
        QrCode_Image.setPixel(x,y,qRgb(0,0,0));
    }
}
QrCode_Image = QrCode_Image.scaled(128,128,Qt::KeepAspectRatio);
return QrCode_Image;

}

7、 登录界面
人物界面通过创建和比对数据表中的数据表来判断是否这个账号。
界面仿照TIM制作:

(1)实现记住密码、自动登录
void loginDialog::setting()
{
QSettings settings(“Software Inc.”,“logindialog”);
QString userName;
QString passWord;
bool checked = false;
bool autoCheck = false;
if(ui->remeberCheckBox->isChecked())
{
userName = ui->userlineEdit->text().trimmed();
passWord = ui->passlineEdit_2->text().trimmed();
autoCheck = ui->autoCheckBox->isChecked();
checked = true;
}
else {
checked = false;
userName = QString("");
passWord = QString("");
autoCheck = false;
}

settings.setValue("UserName",userName);
settings.setValue("Password",passWord);
settings.setValue("AutoChecked",autoCheck);
settings.setValue("Checked",ui->remeberCheckBox->isChecked());

}

}
8、 日历视图的实现
(1)日历视图:

#pragma once
#ifndef CALENDAR_H
#define CALENDAR_H

#include “const.h”

#include “daywidget.h”
#include “abstractevent.h”

#include
#include
#include

namespace Ui {
class Calendar;
}

void AddEventDialog::reject()
{
if (!is_editing && tmp_event)
{
tmp_event->RemoveAllFiles();
tmp_event->deleteLater();
}
QDialog::reject();
}

void AddEventDialog::on_dateEdit_begin_dateChanged(const QDate &date)
{
begin = date;
if (begin > end) ui->dateEdit_end->setDate(date);
}

void AddEventDialog::on_dateEdit_end_dateChanged(const QDate &date)
{
end = date;
ui->comboBox_endType->setItemText(2, date.toString(“yyyy/M/d”));
if (begin > end) ui->dateEdit_begin->setDate(date);
}

void AddEventDialog::on_comboBox_repeatType_currentIndexChanged(int index)
{
ui->widget_empty->show();
switch (index)
{
case 0: // day
layout_repeat->setCurrentIndex(0);
ui->widget_empty->hide();
break;
case 1: // week
layout_repeat->setCurrentIndex(1);
break;
case 2: // month
layout_repeat->setCurrentIndex(2);
break;
case 3: // year
layout_repeat->setCurrentIndex(3);
break;
}
}

void AddEventDialog::on_comboBox_endType_currentIndexChanged(int index)
{
ui->dateEdit_end->setEnabled(index == 2);
if (index == 1)
{
ui->spinBox_repeatTimes->show();
ui->label_5->show();
}
else
{
ui->spinBox_repeatTimes->hide();
ui->label_5->hide();
}
}

void AddEventDialog::on_groupBox_clicked(bool checked)
{
if (checked)
{
on_comboBox_endType_currentIndexChanged(ui->comboBox_endType->currentIndex());
}
else
{
ui->dateEdit_begin->setEnabled(true);
ui->dateEdit_end->setEnabled(true);
}
}

void AddEventDialog::on_pushButton_addFile_clicked()
{
QString file = QFileDialog::getOpenFileName(this, tr(“Select Attachment”), QDir::homePath(), tr(“All Files (*)”));
if (!file.isEmpty())
{
if (!tmp_event)
{
tmp_event = new ContinuousEvent(begin, end);
connect(file_list_widget, &FileListWidget::fileRemoved, tmp_event, &AbstractEvent::RemoveFile);
}
if (tmp_event->AddFile(file, this))
file_list_widget->AddFile(tmp_event->FilePathAt(tmp_event->FileCount() - 1));
}
}
(3)实现数据的输入输出:
//导入数据
void Calendar::importData(const QString& fileName, bool showMessageBox)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
{
if (showMessageBox) QMessageBox::critical(0, tr(“失败”), QString(tr(“Cannot import data from “%1”!”)).arg(fileName));
return;
}

QDataStream in(&file);
int size;
in >> size;
for (int i = 0; i < size; i++)
{
    AbstractEvent* event;
    in >> &event;
    bool ok = true;
    for (auto j : event_list)
        if (j->MagicString() == event->MagicString()) ok = false;
    if (ok) event_list.push_back(event);
}
in >> size;
for (int i = 0; i < size; i++)
{
    QDate date; QColor color;
    in >> date >> color;
    day_color[date] = color;
}
file.close();

}
//导出数据
void Calendar::exportData(const QString& fileName, bool showMessageBox)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly))
{
if (showMessageBox) QMessageBox::critical(0, tr(“导出失败”), QString(tr(“Cannot export data to “%1”!”)).arg(fileName));
return;
}

QDataStream out(&file);
out << (int)event_list.size();
for (auto i : event_list) out << i;
out << (int)day_color.size();
for (auto i : day_color) out << i.first << i.second;
file.close();

}
(3)菜单内功能的实现
using namespace std;

static AbstractEvent* eventByAction;
static EventLabelButton* eventLabelByAction;
static QDate dateByAction;
static DayWidget* dayWidgetByAction;

Calendar::Calendar(QString username,QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Calendar),
current_date(QDate::currentDate()),
username(username)
{
ui->setupUi(this);
this->setAttribute(Qt::WA_TranslucentBackground);

corner_label = new QLabel(this);
corner_label->setFixedWidth(40);
corner_label->setStyleSheet("QLabel{background:white;}");
ui->layout_table->addWidget(corner_label, 0, 0, 1, 1);

for (int i = 0; i < Const::WEEK_DAYS; i++)
{
    horizontal_header[i] = new LabelButton(this);
    horizontal_header[i]->setAlignment(Qt::AlignCenter);
    horizontal_header[i]->setFixedHeight(30);
}
for (int i = 0; i < Const::MONTH_WEEKS; i++)
{
    vertical_header[i] = new LabelButton(this);
    vertical_header[i]->setFixedWidth(40);
    vertical_header[i]->setAlignment(Qt::AlignCenter);

    for (int j = 0; j < 4; j++)
    {
        QWidget* empty = new QWidget(this);
        if (!j) empty->setFixedHeight(25);
        ui->layout_table->addWidget(empty, i * 4 + j + 1, 0, 1, 1);
    }
}
for (int i = 0; i < Const::MONTH_WEEKS; i++)
    for (int j = 0; j < Const::WEEK_DAYS; j++)
    {
        day_table[i][j] = new DayWidget(this);
        connect(day_table[i][j], &DayWidget::clicked, this, &Calendar::onShowDayDetail);
        connect(day_table[i][j], &DayWidget::dropIn, this, &Calendar::onAddFile);
        connect(day_table[i][j], &QWidget::customContextMenuRequested, this, &Calendar::onDayWidgetContextMenu);
    }
createActions();
//importData(QDir::currentPath() + "/" + Setting::UserDirectory + Const::USER_DATA_FILE);
loadTable();

}

Calendar::~Calendar()
{
clearAll();
delete ui;
}

2、 2调试及问题解决
在做课设写代码的过程中遇到很多问题,
很多时候我们遇到问题首先想到的是将错误复制下来,然后粘贴到google搜索框中,漫无目的的去寻找答案,而不是仔细分析查看编译器给出的错误提示。跟我的经验,很多时候编译器给出的提示相当明显,认真仔细阅读大部分可以很快找出解决方案。
我还经常引起LINK,这个时候回到文档,把原来生成的Debug’等自动生成的文件,重新编译一遍就能运行了,我猜是因为缓存问题。
面向对象编程。万物皆是对象,需要对各个对象的属性和行为进行分析,进行抽象,归纳和分析。说实话,在实际编程的时候还是无法直接想到面向对象的思想,而总是走向模块话的老路。后面在参照别人代码和看了一点编程编译设计后好了一点,但还不能很快改正。
不过说真的,我也的确需要补充些这方面的知识。当然第一次做c++项目肯定还是有很多考虑不周全的,基础知识太薄弱了以后继续努力!
三、 结束语(包括感想、致谢、设计总结)

在本次的实训中,除了让我明白工作中需要能力,素质,知识之外,更重要的是学会了如何去完成一个任务,懂得了享受工作。当遇到问题,冷静,想办法一点一点的排除障碍,到最后获取成功,一种自信心由然而生,这就是工作的乐趣。有时候也需要虚心请教,从别人的身上真得能学习到不自己没有的东西,每一次的挫折只能使我更接近成功。除此以外,我还学会了如何更好地与别人沟通,如何更好地去陈述自己的观点,如何说服别人认同自己的观点。这次所学知识与实际的应用,理论与实际的相结合,让我大开眼界。也是对以前所学知识的一个初审吧!这次 实训对于我以后学习、找工作也真是受益菲浅,在短短的一个星期中让我初步从理性回到感性的重新认识,也让我初步的认识C++这门语言,对于以后前进所应把握的方向也有所启发!相信这些宝贵的经验会成为我今后成功的重要的基石。。
在这里,还要感谢刘老师的指导及同学们能和我一起讨论学习,共同进步,使我在学习过程中有了很大的提高,也提升了我对自己编程能力的自信。现在还只是初步学习了浅易的C++语言,未能体会c++程序设计中诸多更加强大的软件功能,所以c++的学习是没有结束的,在将来的大学生活乃至工作中,我还会更加勤奋努力,更好的学习运用这门计算机语言。

参考文献:
[1]Blanchette J,Summerfield M. C ++ GUI Qt 4 编程[M]. 闫
锋欣,曾泉人,张志强,译. 北京: 电子工业出版社,2013.
[2]焦正才,樊文侠. 基于 Qt /Embedded 的 MP3 音乐播放器的
设计与实现[J]. 电子设计工程,2012,20( 7) : 148 - 150.
[3]Gregoire M,Solter N A,Klerper S J. C ++ 高级编程[M]. 侯
普秀,郑思遥,译. 北京: 清华大学出版社,2014.
[4]蔡 志 明. 精 通 Qt 4 编 程[M]. 北 京: 电子工业出版社,
2011.
[5]Summerfield M. Qt 高级编程[M]. 白建平,王军锋,闫锋
欣,译. 北京: 电子工业出版社,

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页