一、前言
日志功能,可以在任何想要记录操作的地方增加函数,之后会在日志信息列表中查询到。
二、环境
windows
qt5.7
三、正文
话不多说,直接一步一步复制粘贴即可。
1.main函数增加函数
//增加日志信息
void writejournal(QString note)
{
QDateTime time;
QString sqlnote;
QString date=time.currentDateTime().toString("yyyy-MM-dd");
QSqlQuery query(db);
QString sql=QString("select * from Sys_journal where date is '%1'").arg(date);
if(query.exec(sql)&&query.next()){
sqlnote=query.value(1).toString();
}
if(!sqlnote.isNull()){//有当天记录
sqlnote+="\r\n"+time.currentDateTime().toString("hh:mm:ss ")+note;
query.exec(QString("UPDATE Sys_journal set note='%1' where date ='%2';").arg(sqlnote).arg(date));
}
else{//无当天记录
sqlnote+=time.currentDateTime().toString("hh:mm:ss ")+note;
query.exec(QString("INSERT INTO Sys_journal(date,note) VALUES ('%1','%2');").arg(date).arg(sqlnote));
}
}
并在全局头文件中包含
extern void writejournal(QString note);
2.数据库建立日志表格
3.在使用的地方增加日志信息添加函数
writejournal(QString("导出%1使用日志信息").arg(searchdata[0].at(i)));
至此日志信息保存功能完毕,接下来就是日志管理和查询部分了
4.ui文件增加表格,查询按键,筛选日志条件信息控件
5.查询日志头文件
#ifndef USED_H
#define USED_H
#include "wurenjkgl_header.h"
namespace Ui {
class used;
}
class used : public QWidget
{
Q_OBJECT
public:
explicit used(QWidget *parent = 0);
~used();
protected:
//表格滑动刷新
bool eventFilter(QObject *obj, QEvent *event);
private slots:
//历史数据查询模块
void on_btn_datasearch_clicked();//数据查询
void tableWidget_journal_init(QTableWidget *tab,QVector<int> line,QStringList name,bool push);
void tableWidget_journal_refuse(QTableWidget *TableWidget);//更新历史数据信息
private:
Ui::used *ui;
QScrollBar *m_scrollBarV;//表格滚动实现
};
#endif // USED_H
6.查询日志源码
#include "used.h"
#include "ui_used.h"
#include "login.h"
used::used(QWidget *parent) :
QWidget(parent),
ui(new Ui::used)
{
ui->setupUi(this);
this->setWindowModality(Qt::ApplicationModal);//设置一直保持在顶端,不可切换其他界面,除非被新界面带此属性覆盖
this->setWindowFlags(Qt::FramelessWindowHint);//设置界面无边框
connect(ui->btn_exit,&QPushButton::clicked,[=](){this->close();});//退出健康管理界面
connect(ui->btn_exiticon,&QPushButton::clicked,[=](){this->close();});//退出健康管理界面
//日志初始化
QVector<int> historytable_line;
historytable_line.append({150,300,1000,200});//配置表格宽度6列
QStringList historytable_title;
historytable_title.append({"序号","日期","操作日志信息","功能"});//配置表格表头名称6列
m_scrollBarV = ui->tableWidget_used->verticalScrollBar();//绑定表格滑动效//在表格第一次初始化前必须初始化一次,否则程序崩溃
tableWidget_journal_init(ui->tableWidget_used,historytable_line,historytable_title,true);//初始化表格表头
tableWidget_journal_refuse(ui->tableWidget_used);//更新历史信息
connect(ui->tableWidget_used,&QTableWidget::cellPressed,[=](){//点击表格某行生效,当需要滑动时必定点击到表格某行。
m_scrollBarV = ui->tableWidget_used->verticalScrollBar();//绑定表格滑动效
});
}
used::~used()
{
delete ui;
}
//数据查询
void used::on_btn_datasearch_clicked()
{
tableWidget_journal_refuse(ui->tableWidget_used);//更新历史信息
}
//通用表格初始化函数,建立表格列,刷新表头和列宽
void used::tableWidget_journal_init(QTableWidget *tab,QVector<int> line,QStringList name,bool push)
{
tab->clearContents();//清空内容
tab->verticalHeader()->setVisible(false);//去掉行序号
tab->horizontalHeader()->setFixedHeight(80); //设置表头的高度
tab->horizontalHeader()->setStretchLastSection(true);//设置表格是否充满,即行末不留空
//tab->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); //禁止鼠标拖放列宽度
tab->horizontalHeader()->setFocusPolicy(Qt::NoFocus); //设置表头不可选
tab->horizontalHeader()->setHighlightSections(false); //设置表头不可选//QTableWidget表头塌陷问题解决
tab->setEditTriggers(QAbstractItemView::NoEditTriggers);//设置表格内容不可修改
tab->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选中就是一行选中
tab->setSelectionMode(QAbstractItemView::SingleSelection);//设置只能选中一行
tab->setFocusPolicy(Qt::NoFocus);//设置去掉选中虚线框
//tab->setAlternatingRowColors(true);//设置表格颜色交替
//表格滚动部分实现函数:初始化函数+以下俩函数+ (QObject *obj, QEvent *event)
if(push)tab->viewport()->installEventFilter(this);//对此对象安装事件过滤器
if(push)tab->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);//设置滚动模式按照像素滑动,做表格滑动时使用
tab->setColumnCount(line.size());//设置列数量
for(int i=0;i<line.size();i++)
tab->setColumnWidth(i,line.at(i));
tab->setHorizontalHeaderLabels(name);//设置table列表各项标题
tab->setRowCount(0);
}
//更新历史数据信息,默认包含日期筛选,人员筛选,编码筛选,如有不同功能更改相应部分
void used::tableWidget_journal_refuse(QTableWidget *TableWidget)
{
//更新页面控件操作员列表,每次都更新,以防人员管理改变
QString lastname=ui->comboBox_user->currentText();
ui->comboBox_user->clear();//清空操作员列表
ui->comboBox_user->addItems(Data_user.usernamelist);//放入最新操作员列表
ui->comboBox_user->setCurrentText(lastname);
//筛选搜索数据库数据
QStringList searchterm;//筛选条件,默认包含日期筛选,人员筛选,编码筛选,如有不同功能更改相应部分
if(ui->checkBox_starttime->isChecked())//判断起始日期是否包含
searchterm.append(QString("(date>'%1')").arg(ui->dateTimeEdit_start->dateTime().toString("yyyy-MM-dd")));//date是数据库表头
if(ui->checkBox_endtime->isChecked())//判断截止日期是否包含
searchterm.append(QString("(date<'%1')").arg(ui->dateTimeEdit_end->dateTime().toString("yyyy-MM-dd")));//date是数据库表头
if(ui->checkBox_user->isChecked())//判断操作员是否包含
searchterm.append(QString("note like '%%1%'").arg(ui->comboBox_user->currentText()));//note是数据库表头
if(ui->checkBox_car->isChecked())//判断车型是否包含
searchterm.append(QString("note like '%%1%'").arg(ui->comboBox_user_2->currentText()));//note是数据库表头
QSqlQuery qry(db);
QString sql=QString("select * from Sys_journal");
if(searchterm.size()>0){//判断是否有筛选条件
sql.append(" where ");
for(int i=0;i<searchterm.size();i++){
sql.append(searchterm.at(i));//添加筛选内容
if(i<(searchterm.size()-1))
sql.append(" and ");//添加连接符,最后一个不添加
}
}
// ui->btn_datasearch->setToolTip(sql);
qDebug()<<sql;
QStringList searchdata[2];//搜索数据,本程序数据库包含2列,如更换不同程序数据列不同更改相应部分
if(qry.exec(sql)){
for(int i=0;qry.next()&&i<10000;i++){
searchdata[0].append(qry.value(0).toString());//赋值日期
searchdata[1].append(qry.value(1).toString());//赋值日志信息
}
}
//更新表格显示
TableWidget->clearContents();//清空内容
TableWidget->setRowCount(searchdata[0].size());//设置表格行数
//删除上次表格的控件,这里必须先删除widget里面的控件,后删除widget,否则程序运行崩溃
QList<QPushButton*> btnList = TableWidget->findChildren<QPushButton*>();
for(int i=0;i<btnList.size();i++)delete btnList[i];//这里仍然要删除按键,没有因为按键在widget里先删除widget而被删除,还得先删除按键,否则崩溃
QList<QWidget*> widgetList = TableWidget->findChildren<QWidget*>();
for(int i=0;i<widgetList.size();i++){
if(widgetList.at(i)->objectName().contains("widget_journaltable_"))//判断是表格创建控件,才刷新
delete widgetList[i];//删除表格中新建的widget,根据object命名,避免错误删除其他widget
}
for(int i=0;i<searchdata[0].size();i++){ //刷新信号列表
TableWidget->setItem(i,0,new QTableWidgetItem(QString("%1").arg(i+1,2,10,QChar('0'))));//更新序号
TableWidget->item(i,0)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);//数据居中
TableWidget->setItem(i,1,new QTableWidgetItem(searchdata[0].at(i)));//更新日志时间
TableWidget->item(i,1)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);//数据居中
TableWidget->setItem(i,2,new QTableWidgetItem(searchdata[1].at(i)));//更新日志信息
TableWidget->item(i,2)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);//数据居中
//创建水平布局
QHBoxLayout *vLayout = new QHBoxLayout(this);//创建布局,布局不需要单独删除,会随着widget删除
vLayout->setContentsMargins(10, 2, 10, 2);// 设置外间距left,top,right,bottom
vLayout->setSpacing(10);//设置内间距
//创建widget放入单元格中,在widget里放入其他控件
QWidget *widget = new QWidget(this);
widget->setObjectName(tr("widget_journaltable_%1").arg(i+1));
widget->setStyleSheet("background-color:rgb(0,0,0,0)");
//创建按键1,根据需求更改创建的控件和数量
QPushButton *aaa=new QPushButton(this);//创建按键控件,按键控件需要单独删除,不会随着widget删除
aaa->setObjectName(tr("btn_table_look%1").arg(i+1));
aaa->setText("日志导出");//设置文本
aaa->setStyleSheet("font: 20pt ""黑体"";background-color:rgb(0,0,0,0);color: rgb(202, 234, 206);border-radius:10px;");//设置风格
aaa->setMinimumSize(140,45);//设置按键控件最小尺寸
aaa->setIcon(QIcon(":/icon/baogao.png"));//设置图标
aaa->setIconSize(QSize(40,40));//设置图标尺寸
//创建按键2,根据需求更改创建的控件和数量
QPushButton *bbb=new QPushButton(this);//创建按键控件,按键控件需要单独删除,不会随着widget删除
bbb->setObjectName(tr("btn_table_delete%1").arg(i+1));
bbb->setText("数据删除");//设置文本
bbb->setStyleSheet("font: 20pt ""黑体"";background-color:rgb(0,0,0,0);color: rgb(202, 234, 206);border-radius:10px;");//设置风格
bbb->setMinimumSize(140,45);//设置按键控件最小尺寸
bbb->setIcon(QIcon(":/icon/删除.png"));//设置图标
bbb->setIconSize(QSize(40,40));//设置图标尺寸
//将widget放入表格单元格中
vLayout->addWidget(aaa);//将按键放入布局中
vLayout->addWidget(bbb);//将按键放入布局中
widget->setLayout(vLayout);//将布局放入widget中
TableWidget->setCellWidget(i,3,widget);//插入widget到表格指定行列
widget->show();//显示widget
TableWidget->setRowHeight(i,60);//设置行高
//绑定自定义控件按键点击槽函数,根据需求更改创建的控件和数量
connect(aaa,&QPushButton::clicked,[=](){//绑定按键点击回调槽函数
QString dir = QFileDialog::getExistingDirectory(this, tr("选择信息导出文件目录"),"/home",QFileDialog::ShowDirsOnly|QFileDialog::DontResolveSymlinks);
if(dir.isEmpty())
QMessageBox::information(this,"提示","路径为空!设置保存报告路径失败!");
else{
bool exist;
QDir *folder = new QDir();
QString historydir="/journal";
exist = folder->exists(dir+historydir);//文件夹是否存在
if(!exist)folder->mkdir(dir+historydir);//不存在创建文件夹
//写入txt文件
QFile file(dir+"/journal/"+searchdata[0].at(i)+"日志信息.txt");
file.open(QIODevice::WriteOnly|QIODevice::Text);
QTextStream stream(&file);
stream<<searchdata[1].at(i);
file.close();
QMessageBox::information(this,"提示","保存日志信息成功!");
writejournal(QString("导出%1使用日志信息").arg(searchdata[0].at(i)));
}
});
connect(bbb,&QPushButton::clicked,[=](){//绑定按键点击回调槽函数
int res=massage_dialog(2,"提示",QString("是否确认删除序号%1数据?\r\n日期:%2")
.arg(QString("%1").arg(i+1,2,10,QChar('0')))
.arg(searchdata[0].at(i)),4);
if(res==0){//点击确认返回0,点击取消或关闭返回1
QSqlQuery qry(db);
qry.exec(QString("delete from Sys_journal where date = '%1'").arg(searchdata[0].at(i)));
qry.prepare("vacuum");//删除成功之后释放内存碎片
qry.exec();
tableWidget_journal_refuse(ui->tableWidget_used);//更新历史信息
massage_dialog(1,"提示","删除数据成功!",1);
}
});
}
TableWidget->resizeRowsToContents();//根据单元格内容自动换行
}
//滑动表格实现函数
bool used::eventFilter(QObject *obj, QEvent *event)
{
static signed int press_y = 0;
static signed int move_y = -1;
static signed int release_y = 0;
static QDateTime pressDateTime;
static QPropertyAnimation *animation = new QPropertyAnimation();
// qDebug()<<obj->objectName()<<event->type();
if("qt_scrollarea_viewport" != obj->objectName())
return false;
int scrollV_max = m_scrollBarV->maximum();//获取当前滚动控件的最大进度条值
int scrollV_min = m_scrollBarV->minimum();//获取当前滚动控件的最小进度条值,基本是0
#ifdef WINDOWS
int global_y=QCursor::pos().y();//相对于正屏幕的y坐标,window下此方法即可获取
#else
QMouseEvent *event1 = (QMouseEvent *)event;
int global_y=event1->globalPos().y();//相对于正屏幕的y坐标,linux下用此方法获取
#endif
//根据鼠标的动作——按下、放开、拖动,执行相应的操作
if(event->type() == QEvent::MouseButtonPress){//记录按下的时间、坐标
pressDateTime = QDateTime::currentDateTime();
move_y = global_y;
press_y = move_y;
animation->stop();
}
else if(event->type() == QEvent::MouseButtonRelease){//鼠标放开,根据鼠标拖动的垂直距离和持续时间,设置窗口滚动快慢程度和距离
if(animation->targetObject() != m_scrollBarV){
animation->setTargetObject(m_scrollBarV);
animation->setPropertyName("value");
}
move_y = -1;
release_y = global_y;
QObject *parent_obj = obj->parent();
if(parent_obj != 0 || parent_obj->inherits("QAbstractItemView"))
QTimer::singleShot(150, (QAbstractItemView *)parent_obj, SLOT(clearSelection()));
int endValue;
int pageStep;
if(release_y - press_y != 0 && qAbs(release_y - press_y) > 45){
int mseconds = pressDateTime.msecsTo(QDateTime::currentDateTime());
int limit = 440;
pageStep = 240;//scrollBarV->pageStep();
if(mseconds > limit)//滑动的时间大于某个值的时候,不再滚动(通过增加分母)
mseconds = mseconds + (mseconds - limit) * 20;
if(release_y - press_y > 0){
endValue = m_scrollBarV->value()- pageStep * (200.0 / mseconds);//.0避免避免强制转换为整形
if(scrollV_min > endValue)endValue = scrollV_min;
}
else if(release_y - press_y < 0){
endValue = m_scrollBarV->value() + pageStep * (200.0 / mseconds);
if(endValue > scrollV_max)
endValue = scrollV_max;
}
if(mseconds > limit)mseconds = 0;//滑动的时间大于某个值的时候,滚动距离变小,减小滑动的时间
animation->setDuration(mseconds+550);
animation->setEndValue(endValue);
animation->setEasingCurve(QEasingCurve::OutQuad);
animation->start();
return true;
}
}
else if(event->type() == QEvent::MouseMove && move_y >= 0){//窗口跟着鼠标移动
int move_distance = global_y - move_y;
int endValue = m_scrollBarV->value() - move_distance;
if(scrollV_min > endValue)endValue = scrollV_min;
if(endValue > scrollV_max)endValue = scrollV_max;
m_scrollBarV->setValue(endValue);
move_y = global_y;
}
return false;
}
有一个login的头文件,是用到了全局用户信息,可参照前面人员管理通用模板文章。
或者自定如下结构体,或者自己二次更改程序。
//用户管理结构体
typedef struct
{
QString now_username;//当前用户
QString now_password;//当前密码
bool now_root;//当前权限
QString now_noted;//当前备注
QStringList usernamelist;//用户列表
QStringList userpswdlist;//用户密码
QVector<bool> userroot;//用户权限
QStringList usernote;//用户备注
}UserList;
最后,效果演示:
四、结语
本文不放里程,全看正文即可。