Qt自定义控件之日志控件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt自定义控件之日志控件相关的知识,希望对你有一定的参考价值。

摘要

一般的应用程序都需要在界面上显示日志信息, glog是google的轻量级日志库,本文结合glog,实现了一个简单的线程安全的日志控件。

正文

关于glog的使用,网上有好多介绍的资料,本文参考里面列出了一些,这里就不介绍了。下面列出日志控件的实现要点:

1、日志控件继承自google::LogSink,重新实现其virtual send()函数,自定义日志处理逻辑。

2、调用google::AddLogSink(this),将日志控件添加到glog的转发容器中;

3、日志控件使用QplainTextEdit来显示日志信息;

4、日志控件维护一个线程安全的日志的vector,使用定时器定时从vector中取出日志,并在QplainTextEdit中显示;

 本文代码在vs2015和qt5.7.1的64位编译下进行测试。

下载地址:https://github.com/binbinneu/qt_practice

 实现代码如下:

class LogWidget : public QWidget, public google::LogSink
{
    Q_OBJECT;

public:
    LogWidget(QWidget *parent = 0);
    virtual ~LogWidget();

public:
    virtual void send(google::LogSeverity severity, const char* full_filename, 
        const char* base_filename, int line, const struct ::tm* tm_time, const char* message, size_t message_len);

public Q_SLOTS:
    void refresh();

private:
    QPlainTextEdit *log_widget_;
    QTimer timer_;
    std::mutex mutex_;

    typedef std::pair<std::string, google::LogSeverity> MessageType;
    std::vector<MessageType> message_vec_;

    const int MAXIMUM_BLOCK_COUNT;
    const int REFESH_TIME;
};
LogWidget::LogWidget(QWidget *parent /*= 0*/) : QWidget(parent), 
    MAXIMUM_BLOCK_COUNT(10000), REFESH_TIME(100)
{
    QHBoxLayout *layout = new QHBoxLayout();
    layout->setMargin(0);
    setLayout(layout);

    //采用QPlainTextEdit显示日志信息
    log_widget_ = new QPlainTextEdit(this);
    log_widget_->setMaximumBlockCount(MAXIMUM_BLOCK_COUNT);
    log_widget_->setReadOnly(true);
    layout->addWidget(log_widget_);

    //定时器,定时刷新日志
    QObject::connect(&timer_, SIGNAL(timeout()), this, SLOT(refresh()));
    timer_.start(REFESH_TIME);

    //添加到glog的转发容器中
    google::AddLogSink(this);
}

LogWidget::~LogWidget()
{
    timer_.stop();
    QObject::disconnect(&timer_, SIGNAL(timeout()), this, SLOT(refresh()));

    google::RemoveLogSink(this);
}

void LogWidget::refresh()
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (!message_vec_.empty())
    {
        for (const auto &message : message_vec_)
        {
            log_widget_->appendPlainText(QString::fromLocal8Bit(message.first.c_str()));
        }
    }
    message_vec_.clear();
}

void LogWidget::send(google::LogSeverity severity, const char* full_filename,
    const char* base_filename, int line, const struct ::tm* tm_time, const char* message, size_t message_len)
{
    std::ostringstream message_stream;
    message_stream.fill(0);

    message_stream << "[" << google::LogSeverityNames[severity][0]
        << std::setw(2) << 1 + tm_time->tm_mon
        << std::setw(2) << tm_time->tm_mday
        <<  
        << std::setw(2) << tm_time->tm_hour << :
        << std::setw(2) << tm_time->tm_min << :
        << std::setw(2) << tm_time->tm_sec
        <<  
        << full_filename << : << line << "] ";

    message_stream << std::string(message, message_len);
    std::string message_str = message_stream.str();

    std::lock_guard<std::mutex> lock(mutex_);
    message_vec_.push_back(MessageType(message_str, severity));
}

测试代码:

void thread_fun()
{
    for (int i=0; i<1000000; ++i)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        LOG(INFO) << "INFO";
        LOG(WARNING) << "WARNING";
        LOG(ERROR) << "ERROR";
    }
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    LogWidget w;
    w.show();

    QString log_path = QCoreApplication::applicationDirPath() + "/";

    google::InitGoogleLogging(argv[0]);
    google::SetLogDestination(google::INFO, log_path.toStdString().c_str());
    google::SetLogDestination(google::WARNING, log_path.toStdString().c_str());
    google::SetLogDestination(google::ERROR, log_path.toStdString().c_str());
    google::SetLogDestination(google::FATAL, log_path.toStdString().c_str());

    for (int i=0; i<10; ++i)
    {
        std::thread t(thread_fun);
        t.detach();
    }

    int b = a.exec();

    google::ShutdownGoogleLogging();

    return b;
}

 输出结果:

技术分享

参考

1、http://blog.csdn.net/breaksoftware/article/details/51363353

2、http://www.cnblogs.com/davidyang2415/p/3861109.html

 

以上是关于Qt自定义控件之日志控件的主要内容,如果未能解决你的问题,请参考以下文章

Qt自定义控件之可伸缩组合框(GroupBox)控件

Qt自定义控件之仪表盘的完整实现

Qt编写自定义控件插件开放动态库dll使用(永久免费)

Qt学习笔记11.自定义控件 Customize the Widget

Qt编写自定义控件:左上角圆形菜单控件

Qt编写自定义控件55-手机通讯录