【项目实战】-壹点壹口·任务规划器-主要模块实现

291 阅读10分钟

这是我参与更文挑战的第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());
}

}