Log界面
c++
#ifndef LOG_H
#define LOG_H
#include <QApplication>
#include <QStandardItemModel>
#include <QTableView>
#include <QStyledItemDelegate>
#include <QTextDocument>
#include <QPainter>
#include <QResizeEvent>
#include <QHeaderView>
#include <QDebug>
#include <QSortFilterProxyModel>
#include <qpushbutton.h>
#include <qboxlayout.h>
#include <QLineEdit>
#include <QTime>
#include <QDir>
#include "logthread.h"
// new的时候 传文件路径 然后起子线程,先解析这个日志文件,记录当前日志文件的大小,
// 然后在子线程里起个定时器 定时轮询日志文件的大小, 如果日志文件大小发生变化, 子线程重新从上次结束的位置解析日志
class Log : public QTableView
{
Q_OBJECT
public:
Log(QString dir_path);
~Log();
//设置默认按第col列查找
void SetFilterKeyColumn(int col);
//设置查找关键词是否对大小写敏感
void SetFilterCaseSensitivity(bool flag);
signals:
//添加日志
void AddItem(QString date,QString level, QString msg);
//按关键词查找
void Search(QString keyword);
//按多关键字查找
void MutiWordSearch(QString words,bool flag);
//按条件查找
void ConditionSearch(int col,bool case_sensitive, QString keyword);
//删除行
void RemoveRow(int row);
//清空所有数据
void ClearAllItem();
//排序接口 flag true是升序 false是降序
void SortByCol(int col,bool flag);
//关闭
void Close();
private:
//初始化
void Init();
//绑定信号槽
void BindSingnals();
//字自适应单元格
void WordSelfAdaption();
//关键字List转rex
QString KeyListToRex(QStringList key_words);
private:
QStandardItemModel* standardItemModel_;
QSortFilterProxyModel* sortFilterProxyModel_;
QStringList key_words_;//当前的关键字搜索列表
QString file_path_;
QString dir_path_;
LogThread* logThread_;
};
#endif // LOG_Hc++
#include "log.h"
#include <QScrollBar>
Log::Log(QString dir_path)
{
dir_path_ = dir_path;
standardItemModel_ = new QStandardItemModel();
sortFilterProxyModel_ = new QSortFilterProxyModel();
sortFilterProxyModel_->setSourceModel(standardItemModel_);
setModel(sortFilterProxyModel_);
SetFilterCaseSensitivity(true);
key_words_ <<"DEBUG" <<"WARN" <<"INFO" <<"ERROR";
Init();
BindSingnals();
//查找dir下最新的日志文件
QDir dir(dir_path);
QDate date;// = QDate::currentDate();
for(auto file_name:dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)){
QFileInfo file_info(file_name);
QDate file_cur_date = QDate::fromString(file_info.fileName().split(".log")[0],"yyyy_MM_dd");
if(QDate::currentDate() == file_cur_date){
date = QDate::currentDate();
file_path_ = file_info.filePath();
break;
}
}
//没有被赋值 说明当前路径下没有当天日志文件
if(!date.isNull()){
logThread_ = new LogThread(file_path_,this);
logThread_->start();
}
}
Log::~Log()
{
qDebug()<<"Log exit";
}
void Log::SetFilterKeyColumn(int col)
{
sortFilterProxyModel_->setFilterKeyColumn(col);
}
void Log::SetFilterCaseSensitivity(bool flag)
{
sortFilterProxyModel_->setFilterCaseSensitivity(flag?Qt::CaseSensitive:Qt::CaseInsensitive); // 设置过滤是否区分大小写
}
void Log::Init()
{
//设置平滑滚动 像素滚动
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
//是否显示网格线
setShowGrid(true);
//是否显示自带的表格行号
verticalHeader()->setVisible(false);
//点击一个item的选择模式(设置为选择一行)
setSelectionBehavior(QAbstractItemView::SelectRows);
//添加标题
QStringList title = {"日期","等级","消息"};
standardItemModel_->setColumnCount(title.size());//设置列数
standardItemModel_->setHorizontalHeaderLabels(title);
//字体自动换行
setWordWrap(true);
//设置小标题大小
horizontalHeader()->resizeSection(0, 250);
// 将列标题设置为自动调整大小,铺满控件
horizontalHeader()->setSectionResizeMode(title.size() - 1,QHeaderView::Stretch);
//表头排序
setSortingEnabled(true);
}
void Log::BindSingnals()
{
//绑定添加接口
QObject::connect(this,&Log::AddItem,this,[=](QString date, QString level, QString msg){
QList<QStandardItem*> items ;
items.append(new QStandardItem(date));
items.append(new QStandardItem(level));
//trimmed去掉换行符或者空格 这是因为表格在默认情况下可能不会在空格或换行符处进行换行。
items.append(new QStandardItem(msg.trimmed()));
items[0]->setTextAlignment(Qt::AlignCenter);
items[1]->setTextAlignment(Qt::AlignCenter);
standardItemModel_->appendRow(items);
//当数据量少时自适应
if(standardItemModel_->rowCount() < 20){
resizeRowsToContents();
}
});
QObject::connect(this,&Log::Close,this,[=](){
standardItemModel_->clear();
sortFilterProxyModel_->clear();
logThread_->quit();
logThread_->exit();
logThread_->wait();
if(logThread_->isFinished()){
delete logThread_;
}
delete standardItemModel_;
delete sortFilterProxyModel_;
close();
});
//改变标题的行宽时自适应
QHeaderView* headerView = horizontalHeader();
QObject::connect(headerView,&QHeaderView::sectionResized,this,[=](int logicalIndex, int oldSize, int newSize){
WordSelfAdaption();
});
//拖动时自适应
QScrollBar* scroll_bar = verticalScrollBar();
QObject::connect(scroll_bar,&QScrollBar::valueChanged,this,[=](int value){
WordSelfAdaption();
});
QObject::connect(this,&Log::RemoveRow,this,[=](int row){
standardItemModel_->removeRow(row);
});
//清空所有项
QObject::connect(this,&Log::ClearAllItem,this,[=](){
//清空数据
standardItemModel_->clear();
sortFilterProxyModel_->clear();
//清空视图
reset();
});
//绑定排序接口
QObject::connect(this,&Log::SortByCol,this,[=](int col,bool flag){
sortFilterProxyModel_->sort(col,flag?Qt::SortOrder::AscendingOrder:Qt::SortOrder::DescendingOrder);
});
//绑定搜索接口
QObject::connect(this,&Log::Search,this,[=](QString keyword){
SetFilterKeyColumn(2);
// QString regexPattern = QString(".*(%1|%2).*%3.*").arg("select", "where", keyword);
// QRegExp regex(regexPattern, Qt::CaseInsensitive);
// qDebug()<<regex;
// sortFilterProxyModel_->setFilterRegExp(regex);
sortFilterProxyModel_->setFilterRegExp(keyword);
//搜出来以后自适应一下
WordSelfAdaption();
});
//按多关键字查找
QObject::connect(this,&Log::MutiWordSearch,this,[=](QString word,bool flag){
SetFilterKeyColumn(1);
//表示以word为关键字搜索
if(flag && word != ""){
key_words_.append(word);
}else{//表示不以word为关键字进行搜索 会从关键字列表里面尝试删除word
key_words_.removeOne(word);
}
if(key_words_.size() == 0){
sortFilterProxyModel_->setFilterRegExp("No_Match");
}else{
sortFilterProxyModel_->setFilterRegExp(KeyListToRex(key_words_));
// qDebug()<< key_words_;
}
WordSelfAdaption();
});
}
void Log::WordSelfAdaption()
{
int row = rowAt(0);
int row_height = rowAt(viewport()->height())+5;
for (; row <= row_height; ++row) {
resizeRowToContents(row);
}
}
QString Log::KeyListToRex(QStringList key_words)
{
QString rex;
for(auto& word:key_words){
rex += word;
rex += "|";
}
rex.remove(rex.size()-1,1);
return rex;
}LogThread
c++
extern class Log;
class LogThread:public QThread
{
Q_OBJECT
public:
LogThread(QString file_path, Log* log);
~LogThread();
protected:
void run() override;
private:
void ReadFile();
private:
Log* log_;
QFile file_;
QString file_path_;
qint64 file_size_;
qint64 lastReadPosition;
};c++
#include "logthread.h"
#include "log.h"
LogThread::LogThread(QString file_path,Log* log)
{
log_ = log;
file_path_ = file_path;
lastReadPosition = 0;
//打开file_path
file_.setFileName(file_path_);
file_size_ = 0;
if (file_.open(QFile::ReadOnly | QFile::Text)) {
ReadFile();
}
}
LogThread::~LogThread()
{
qDebug()<<"LogThread exit";
}
void LogThread::run()
{
QTimer timer_;
timer_.setInterval(1000);
QObject::connect(&timer_,&QTimer::timeout,&timer_,[=](){
ReadFile();
});
timer_.start();
exec(); //当调用子线程的exit后 退出事件循环
}
void LogThread::ReadFile()
{
file_.seek(lastReadPosition);
if(file_size_ < file_.size()){
while (!file_.atEnd()) {
QByteArray line = file_.readLine();
if(line == "\n"){
break;
}
// 处理读取到的一行数据
int level_right = 21;
for(;line[level_right] != ']' && level_right < line.size();level_right++){}
emit log_->AddItem(line.mid(0,19),line.mid(21,level_right-20),line.mid(level_right+2,-1));
}
file_size_ = file_.size();
lastReadPosition = file_.pos();
}
}