这是我参与更文挑战的第18天,活动详情查看:更文挑战
壹点壹口·任务规划器 互联网上有非常丰富的音乐资源任务管理器,做得好的如Ticktick、Todo等大型软件,当使用高级功能时需要付费,且功能臃肿,会员还不能买断,只能订月子,根本用不起,不符合个人使用习惯,于是决定设计一个个人任务管理器:壹点壹口。
一个任务的信息包括任务内容、开始时间 、截止时间、完成情况、具体描述、任务编号等信息。设计任务管理系统统,系统仿照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)详细设计
主要完成的功能:
任务信息的录入功能,任务状态的设置,任务信息不同方式浏览功能,单独浏览整个任务的信息,日历视图浏览任务信息:GUI模式浏览任务、任务信息删除、修改功能。(表格模式下,多用户登录,分别建立不同的数据库表单)
主要使用的技术:
结构体,指针,链表的应用,switch语句等。
1、主界面
sqlite数据库的连接和建立
#ifndef SQLCONECTION_H
#define SQLCONECTION_H
//使用静态函数把数据库的连接和主界面实现函数分离
#include <QtSql>
#include <QMessageBox>
#include <QProgressDialog>
#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<string>
#include<vector>
#include"QrCode.hpp"
using namespace qrcodegen;
QRcretor::QRcretor()
{
Show_QRcode_Picture();
}
QImage QRcretor::Show_QRcode_Picture(QString message)
{
std::vector<QrSegment> 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());
}
}