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

时间: 2024-08-08 12:39:19

Qt自定义控件之日志控件的相关文章

自定义控件VS用户控件

1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Controls控件 自定义控件(Custom Control):继承自 Control,主要用于开发windows控件的最基本的类,比如 Text,Button 控件 2 要开发自己的控件的几种方法[1] 复合控件(Composite Controls):将现有的各种控件组合起来,形成一个新的控件,来满

winform 自定义控件:半透明Loading控件

winform  自定义控件:半透明Loading控件 by wgscd date:2015-05-05 效果: using System;using System.Drawing;using System.Windows.Forms;using System.ComponentModel;using System.Threading; namespace wgscd{ /// <summary> /// 自定义控件:半透明控件 /// </summary> [ToolboxBit

Android自定义控件之日历控件

Android自定义控件之日历控件 2015-10-23 Android开发中文站 三月份学习android,至今也有半年有余,中间也做过两个项目,但是依然感觉自己做的应用不是很有新意,比不上应用市场上那些应用如此绚丽.所以自己仍需继续努力.学习至今,仍感觉自定义控件是一块硬骨头,还没修炼到身后的内功,下面就切入正题,以一次项目的需求,来实现一个自定义的日历控件.效果图先来一发. 我们分析下效果图,然后确定我们的需求. (1).绘制星期的自定义View,用于标识日期的礼拜. (2).绘制日期的自

在Qt中使用ActiveX控件

Qt的windows商业版本提供了ActiveQt这个framework,使用这个组件我们可以在Qt中使用ActiveX控件,并且也开发基于Qt的ActiveX控件.ActiveQt包含了两个组件QAxContainer和QAxServer. l         QAxContainer允许我们使用COM对象,并且可以将将ActiveX控件嵌入到Qt程序中去. l         QAxServer可以将我们写的Qt控件导出为COM对象或者是ActiveX控件. 第一个例子我们来演示一下在Qt中

C# 自定义控件VS用户控件

1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Controls控件 自定义控件(Custom Control):继承自 Control,主要用于开发windows控件的最基本的类,比如 Text,Button 控件 2 要开发自己的控件的几种方法[1] 复合控件(Composite Controls):将现有的各种控件组合起来,形成一个新的控件,来满

Qt Gui中父控件监听子控件的IO事件

父对象重新定义自己继承自QObject的函数bool eventFilter(QObject* watched, QEvent* event). 子控件安装父对象的eventFilter: 例如, QTableView * itsView = new QTableView; itsView->viewport()->installEventFilter(this); Qt Gui中父控件监听子控件的IO事件

Qt编写云台仪表盘控件

做过安防视频监控的同学都清楚,在视频监控系统软件上都可以看到一个云台控制区域,可以对球机进行下下左右等八个方位的运动控制,还可以进行复位,一般都是美工作图好,然后贴图的形式加入到软件中,好处是程序简单,界面美工,主要取决于美工的美图能力,缺点是对于各种分辨率的适应性稍微差点,需要不同的图片切图贴图,除非默认做好的是大图自适应看不出差别,可能大部分人所在的公司都是小公司,一般美工人员比较少甚至没有,都需要程序员一人负责,甚至一开始就要考虑到各种分辨率的应用场景以及后期可能的换肤换色等.之前做过很多

【自定义控件】组合控件

组合控件是自定义控件的一种,只不过它是由其他几个原生控件组合而成,故名组合控件. 在实际项目中,GUI会遇到一些可以提取出来做成自定义控件情况. 一个自定义控件的好处就是把一些需要模块化的UI和逻辑放在一起,做到了高内聚,向其他模块提供接口并很少 依赖外界,这样就是低耦合.一个自定义控件就是一个封闭的王国,这里由你掌控. 上述是我自己的一个体会,想必大家也会常做自定义控件吧,就像逻辑部分的模块化一样. 下面我要做一个例子,请看完成图. 下面一排图片加文字就是组合控件了,我是怎么做的呢? 其实这里

我写的一个 Qt 显示图片的控件

Qt 中没有专门显示图片的控件,通常我们会使用QLabel来显示图片.但是QLabel 显示图片的能力还是有点弱.比如不支持图像的缩放一类的功能,使用起来不是很方便.因此我就自己写了个简单的类. 我这个类支持三种图像显示模式,我分别称之为:FIXED_SIZE, CENTRED,AUTO_ZOOM, AUTO_SIZE. FIXED_SIZE 模式下,显示的图像大小等于图像尺寸乘以缩放因子,如果控件的尺寸小于这个大小则多出的部分被裁切掉. FIX_SIZE_CENTRED模式与FIXED_SIZ