Skip to content

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_H
c++
#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();

    }
}

学 习 记 录