基于 QT 实现 Task Timer,高效利用时间

一、开发环境

Ubuntu 20.04
QT6.0

二、新建 Qt Wigets Application 

这里的基类选择 Wigets,

基于 QT 实现 Task Timer,高效利用时间_第1张图片

基于 QT 实现 Task Timer,高效利用时间_第2张图片

pro 配置文件添加 sql 模块,需要用到 sqlite,

QT += sql

基于 QT 实现 Task Timer,高效利用时间_第3张图片

三、添加数据库连接头文件

基于 QT 实现 Task Timer,高效利用时间_第4张图片

// connection.h
#ifndef CONNECTION_H
#define CONNECTION_H

#include 
#include 
#include 
#include 
#include 

static bool createConnection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    //db.setDatabaseName("ikun.db");

    bool res = db.open();
    if (res)
    {
        qDebug() << "open ikun.db ok !";
    }
    else
    {
        qDebug() << "open ikun.db fail: " << db.lastError().text();
    }

    QSqlQuery query;
    if(!query.exec("create table task_history(id INTEGER PRIMARY KEY AUTOINCREMENT,task_name varchar(200) not null, cost_time varchar(20) not null, create_time varchar(25) not null)"))
    {
        qDebug() << "create table task_history  error: " << query.lastError().text();
    }

    return true;
}
#endif // CONNECTION_H

初始化连接到 sqlite 数据库,这里使用的内存数据库,没有持久化到磁盘,连接数据库之后创建了一个表 task_history  ,主键为 id 自增,任务事项 task_name 以及消耗时间 cost_time,

四、布局设计

一个 QLineEdit 用于输入任务事项,一个 QLCDNumber 用于计时,一个 QPlainTextEdit 用于输出日志,两个 QPushButton 用于操作开始计时和终止计时,

基于 QT 实现 Task Timer,高效利用时间_第5张图片

基于 QT 实现 Task Timer,高效利用时间_第6张图片

除了组件的布局调整,还需要在主窗体新增一个槽函数 on_Widget_customContextMenuRequested ,在添加右键菜单功能时需要用到,

五、修改 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *);
protected:
    QPoint pos;
    QTimer * timer;
    QTime * timeRecord;
    bool isStart;
private slots:
    void update_time();
    void on_start_btn_clicked();
    void get_todo_summary();
    void on_end_btn_clicked();

    void on_Widget_customContextMenuRequested(const QPoint &pos);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

头文件中主要定义了计时器的成员属性与成员方法、鼠标事件、绘画事件以及对应的槽方法,

六、修改 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowFlag(Qt::FramelessWindowHint);
    this->setAttribute(Qt::WA_TranslucentBackground);
    this->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
    // init
    this->isStart = false;
    this->timer = new QTimer;
    this->timeRecord = new QTime(0, 0, 0);
    // connect timer and SLOT function
    connect(this->timer,SIGNAL(timeout()),this,SLOT(update_time()));
    //  menu
    this->setContextMenuPolicy(Qt::CustomContextMenu);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::mousePressEvent(QMouseEvent* ev)
{
    if(ev->button()==Qt::LeftButton)
    {
        pos=ev->pos();
    }
}

void Widget::mouseMoveEvent(QMouseEvent*ev)
{


    if(ev->buttons()==Qt::LeftButton)
    {
        int x,y;
        x=ev->pos().x()-pos.x();
        y=ev->pos().y()-pos.y();
        this->move(this->x()+x,this->y()+y);
    }
}

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    QPixmap pixmap;

    pixmap.load(QString("../MyPet/image/pikakun.png"));

    painter.drawPixmap(0, 0, 128, 128, pixmap);
}

void Widget::on_start_btn_clicked()
{

    if(this->ui->todo_line->text().trimmed().length()  == 0 )
    {
        QMessageBox::warning(this, tr("warning"), tr("please input todo first!"), QMessageBox::Yes);
        this->ui->todo_line->setFocus();
        return;
    }

    this->ui->todo_line->setEnabled(false);
    this->ui->last_log->setPlainText(QString("Mission " +  this->ui->todo_line->text().trimmed() + " is timing..."));

    if(!this->isStart)
    {
        this->timer->start(128);
        this->ui->start_btn->setText(QString("Pause"));
    }
    else
    {
        this->timer->stop();
        this->ui->start_btn->setText(QString("Continue"));
    }
    this->isStart = !this->isStart;
}

void Widget::update_time()
{
    // timer add 1 secs, and then display
    *this->timeRecord = this->timeRecord->addMSecs(128);
    this->ui->timer->display(this->timeRecord->toString(QString("hh:mm:ss.zzz")));
}


void Widget::on_end_btn_clicked()
{
    // stop timer
    this->timer->stop();

    // show log
    this->ui->last_log->setPlainText(
        QString(
            this->ui->todo_line->text() +
                " Cost Time "  +
                this->timeRecord->toString(QString("hh:mm:ss.zzz"))
                )
        );

    // save db

    QSqlDatabase::database().transaction();
    QSqlQuery query;

    query.prepare(QString("insert into task_history(task_name, cost_time, create_time ) "
                          "values(:task_name, :cost_time,:create_time)"));

    query.bindValue(":task_name", this->ui->todo_line->text());
    query.bindValue(":cost_time", this->timeRecord->toString(QString("hh:mm:ss.zzz")));

    QDateTime dt =QDateTime::currentDateTime();
    // format yyyy//MM/dd hh:mm:s.zzz
    QString create_time = dt.toString("yyyy-MM-dd hh:mm:ss.zzz");

    query.bindValue(":create_time", create_time);

    if(!query.exec())
    {
        qDebug() << "insert into task_history error: " <<  query.lastError().text();
    }

    QSqlDatabase::database().commit();


    // reset display
    this->timeRecord->setHMS(0,0,0);
    this->ui->timer->display(this->timeRecord->toString(QString("hh:mm:ss.zzz")));

    this->isStart = false;
    this->ui->start_btn->setText(QString("Start"));

    // reset todo_line
    this->ui->todo_line->clear();
    this->ui->todo_line->setEnabled(true);
    this->ui->todo_line->setFocus();
}

void Widget::get_todo_summary()
{
    QSqlQueryModel *model = new QSqlQueryModel(this);

    model->setQuery("select * from task_history");

    model->setHeaderData(0, Qt::Horizontal, tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, tr("Task"));
    model->setHeaderData(2, Qt::Horizontal, tr("Time"));
    model->setHeaderData(3, Qt::Horizontal, tr("LogTime"));

    QTableView *view = new QTableView;
    view->setWindowTitle(QString("summary"));
    view->setModel(model);
    // must after setModel
    view->setColumnWidth(1,250);
    view->setColumnWidth(3,150);
    QSize *min_size = new QSize;
    min_size->setWidth(620);
    min_size->setHeight(400);
    view->setMinimumSize(*min_size);

    QScreen *screen = QApplication::primaryScreen();
    QSize screenSize = screen->size();
    view->move(( screenSize.width() - min_size->width() ) / 2 , ( screenSize.height() - view->height() ) / 2 );

    view->show();

    // free mem
    delete min_size;
}

void Widget::on_Widget_customContextMenuRequested(const QPoint &pos)
{
    QMenu *menu = new QMenu(this);
    QAction *summary = new QAction( QIcon(QString("../MyPet/image/pikakun.png")),tr("summary"), this);
    menu->addAction(summary);

    connect(summary, SIGNAL(triggered()), this, SLOT(get_todo_summary()));

    menu->exec(cursor().pos());
}

七、修改 main.cpp

初始化数据库连接,并将窗口移动至屏幕的中间位置,

#include "widget.h"
#include "connection.h"
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    if (!createConnection())
    {
        return 1;
    }

    QTranslator translator;
    const QStringList uiLanguages = QLocale::system().uiLanguages();
    for (const QString &locale : uiLanguages) {
        const QString baseName = "MyPet_" + QLocale(locale).name();
        if (translator.load(":/i18n/" + baseName)) {
            a.installTranslator(&translator);
            break;
        }
    }
    Widget w;
    QScreen *screen = QApplication::primaryScreen();
    QSize screenSize = screen->size();
    w.move(( screenSize.width() - w.width() ) / 2 , ( screenSize.height() - w.height() ) / 2 );
    w.show();
    return a.exec();
}

八、效果演示

基于 QT 实现 Task Timer,高效利用时间_第7张图片

1、输入需要计时的事项后,点击“Start”按钮开始计时

2、开始计时后,“Start”按钮会变成“Pause”按钮,点击该按钮会暂停计时

3、暂停后,“Pause”按钮会变成“Continue”按钮,点击该按钮会继续计时

4、点击“End”按钮后,停止计时,并记录事项耗时到 sqlite 数据库中

5、右键有“Summary”菜单,点击后可以看到事项汇总

特别注意,如果需要将数据从内存中持久化到硬盘,则修改 connection.h,

# 保存在内存,注释这行
// db.setDatabaseName(":memory:");

# 保存在 ikun.db,添加这行
db.setDatabaseName("ikun.db");

你可能感兴趣的:(禅与编程,禅与QT,qt,开发语言)