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

一、开发环境

Ubuntu 20.04
QT6.0

二、新建 Qt Wigets Application 

这里的基类选择 Wigets,

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

QT += sql

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

// connection.h
#ifndef CONNECTION_H
#define CONNECTION_H#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>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 用于操作开始计时和终止计时,

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

五、修改 widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QDateTime>
#include <QTimer>
#include <QTime>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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 <qpainter.h>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QMessageBox>
#include <QMenu>
#include <QSqlQueryModel>
#include <QTableView>
#include <QDateTime>
#include <QScreen>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);// initthis->isStart = false;this->timer = new QTimer;this->timeRecord = new QTime(0, 0, 0);// connect timer and SLOT functionconnect(this->timer,SIGNAL(timeout()),this,SLOT(update_time()));//  menuthis->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 timerthis->timer->stop();// show logthis->ui->last_log->setPlainText(QString(this->ui->todo_line->text() +" Cost Time "  +this->timeRecord->toString(QString("hh:mm:ss.zzz"))));// save dbQSqlDatabase::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.zzzQString 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 displaythis->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_linethis->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 setModelview->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 memdelete 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 <QApplication>
#include <QLocale>
#include <QTranslator>
#include <QScreen>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();
}

八、效果演示

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

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

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/93226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Acwing 840. 模拟散列表

Acwing 840. 模拟散列表 题目描述思路讲解代码展示 题目描述 思路讲解 代码展示 拉链法&#xff1a; #include <cstring> #include <iostream>using namespace std;const int N 100003;int h[N], e[N], ne[N], idx;void insert(int x) {int k (x % N N) % N;e…

图神经网络GNN(一)GraphEmbedding

DeepWalk 使用随机游走采样得到每个结点x的上下文信息&#xff0c;记作Context(x)。 SkipGram优化的目标函数&#xff1a;P(Context(x)|x;θ) θ argmax P(Context(x)|x;θ) DeepWalk这种GraphEmbedding方法是一种无监督方法&#xff0c;个人理解有点类似生成模型的Encoder过程…

8.3Jmeter使用json提取器提取数组值并循环(循环控制器)遍历使用

Jmeter使用json提取器提取数组值并循环遍历使用 响应返回值例如&#xff1a; {"code":0,"data":{"totalCount":11,"pageSize":100,"totalPage":1,"currPage":1,"list":[{"structuredId":&q…

字符串,字符数组,类型转换,整数越界,浮点数,枚举

目录 自动类型转换 强制类型转换 数据类型 sizeof 数据类型所占字节数 整数越界 浮点数 字符型 字符串变量 ​编辑字符串的输入输出 main函数的参数 &#xff0c;argc,argv 单个字符输入输出 putchar getchar strlen,strcmp,strcat,strchr,strstr strlen 求字…

云安全之HTTP协议介绍补充

HTTP是一个基于TCP/IP通信协议来传递数据的协议&#xff0c;传输的数据类型为HTML文件、图片文件、查询结果等。HTTP协议一般用于B/S架构。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。 URI、URL、URN HTTP使用统一资源标识符(Uniform Resource ldentif…

【软件工程_UML—StartUML作图工具】startUML怎么画interface接口

StartUML作图工具怎么画interface接口 初试为圆形 &#xff0c;点击该接口在右下角的设置中->Format->Stereotype Display->Label&#xff0c;即可切换到想要的样式 其他方式 在class diagram下&#xff0c;左侧有interface图标&#xff0c;先鼠标左键选择&#xff0…

Google vs IBM vs Microsoft: 哪个在线数据分析师证书最好

Google vs IBM vs Microsoft: 哪个在线数据分析师证书最好&#xff1f; 对目前市场上前三个数据分析师证书进行审查和比较|Madison Hunter 似乎每个重要的公司都推出了自己版本的同一事物&#xff1a;专业数据分析师认证&#xff0c;旨在使您成为雇主的下一个热门商品。 随着…

侯捷 C++ STL标准库和泛型编程 —— 4 分配器 + 5 迭代器

4 分配器 4.1 测试 分配器都是与容器共同使用的&#xff0c;一般分配器参数用默认值即可 list<string, allocator<string>> c1;不建议直接用分配器分配空间&#xff0c;因为其需要在释放内存时也要指明大小 int* p; p allocator<int>().allocate(512,…

nodejs+vue交通违章查询及缴费elementui

第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性&#xff1a;技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性&#xff1a; 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…

【STM32】IAP升级03关闭总中断,检测栈顶指针

IAP升级方法 IAP升级时需要关闭总中断 TM32在使用时有时需要禁用全局中断&#xff0c;比如MCU在升级过程中需禁用外部中断&#xff0c;防止升级过程中外部中断触发导致升级失败。 ARM MDK中提供了如下两个接口来禁用和开启总中断&#xff1a; __disable_irq(); // 关闭总中…

8. 基于消影点进行相机内参(主点)的标定

目录 1. ocam模型2. 消影点3. 基于消影点进行相机主点标定3.1 基于ocam模型的主点标定 感谢大家的阅读。 1. ocam模型 可以参考我的另一篇博客ocam模型。 这里简单提一下ocam模型&#xff1a; 这个模型将中心折反射相机和鱼眼相机统一在一个通用模型下&#xff0c;也称为泰勒模…

如何解决版本不兼容Jar包冲突问题

如何解决版本不兼容Jar包冲突问题 引言 “老婆”和“妈妈”同时掉进水里&#xff0c;先救谁&#xff1f; 常言道&#xff1a;编码五分钟&#xff0c;解冲突两小时。作为Java开发来说&#xff0c;第一眼见到ClassNotFoundException、 NoSuchMethodException这些异常来说&…

VUE3照本宣科——应用实例API与setup

VUE3照本宣科——应用实例API与setup 前言一、应用实例API1.createApp()2.app.use()3.app.mount() 二、setup 前言 &#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f33e;&#x1f4dd;记录学习成果&#xff0c;以便温故而知新 “VUE3照本宣科”是指照着中文官网和菜鸟教…

Multiple CORS header ‘Access-Control-Allow-Origin‘ not allowed

今天在修改天天生鲜超市项目的时候&#xff0c;因为使用了前后端分离模式&#xff0c;前端通过网关统一转发请求到后端服务&#xff0c;但是第一次使用就遇到了问题&#xff0c;比如跨域问题&#xff1a; 但是&#xff0c;其实网关里是有配置跨域的&#xff0c;只是忘了把前端项…

JavaSE | 初识Java(七) | 数组 (下)

Java 中提供了 java.util.Arrays 包 , 其中包含了一些操作数组的常用方法 代码实例&#xff1a; import java.util.Arrays int[] arr {1,2,3,4,5,6}; String newArr Arrays.toString(arr); System.out.println(newArr); // 执行结果 [1, 2, 3, 4, 5, 6] 数组拷贝 代码实例…

VRRP配置案例(路由走向分析,端口切换)

以下配置图为例 PC1的配置 acsw下行为access口&#xff0c;上行为trunk口&#xff0c; 将g0/0/3划分到vlan100中 <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sysname acsw [acsw] Sep 11 2023 18:15:48-08:00 acsw DS/4/DATASYNC_CFGCHANGE:O…

Python 无废话-基础知识元组Tuple详讲

“元组 Tuple”是一个有序、不可变的序列集合&#xff0c;元组的元素可以包含任意类型的数据&#xff0c;如整数、浮点数、字符串等&#xff0c;用()表示&#xff0c;如下示例&#xff1a; 元组特征 1) 元组中的各个元素&#xff0c;可以具有不相同的数据类型&#xff0c;如 T…

python使用mitmproxy和mitmdump抓包在手机上抓包(三)

现在手机的使用率远超过电脑&#xff0c;所以这篇记录用mitmproxy抓手机包&#xff0c;实现手机流量监控。 环境&#xff1a;win10 64位&#xff0c;Python 3.10.4&#xff0c;雷电模拟器4.0.78&#xff0c;android版本7.1.2&#xff08;设置-拉至最底部-关于平板电脑&#xf…

Grander因果检验(格兰杰)原理+操作+解释

笔记来源&#xff1a; 1.【传送门】 2.【传送门】 前沿原理介绍 Grander因果检验是一种分析时间序列数据因果关系的方法。 基本思想在于&#xff0c;在控制Y的滞后项 (过去值) 的情况下&#xff0c;如果X的滞后项仍然有助于解释Y的当期值的变动&#xff0c;则认为 X对 Y产生…

IDEA2023 常用配置(JDK/系统设置等常用配置)

目录 一、JDK及编译目录设置 1 项目的JDK设置 2 out目录和编译版本 二、相关详细设置 1 打开详细配置界面 1、显示工具栏 2、默认启动项目配置 3、取消自动更新 2 设置整体主题 1、选择主题 2、设置菜单和窗口字体和大小 3、设置IDEA背景图 3 设置编辑器主题样式…