qt源码阅读准备

qt源码阅读准备

阅读qt源码前先了解以下知识,对阅读qt源码有极大的好处。

D-pointer介绍

D-pointer介绍

d-pointer它可以把一个类库的实施细节对使用的用户隐藏, 而且对实施的更改不会打破二进制兼容。其基本贯穿qt所有类。

Qt类的的结构

我们以QObject举例:
QObject对象叫行为类,QObjectPrivate叫数据类。
QT中大多数类的组织结构:
行为类中包含一个私有的指向数据类的指针d_ptr(就是所谓的d-pointer),
数据类中包含一个指向行为类指针q_ptr,
并且数据类对外不可见一般声明在行为类的cpp文件中。
我将QObject结构简化如下:

QObject.h文件:
class QObjectPrivate;//因为数据类对外应该不可见,所以这里仅声明
class QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QObject)
public:
    QObject(QObject *parent=nullptr);
protected:
    QObject(QObjectPrivate &dd, QObject *parent = nullptr);
protected:
    //QScopedPointer定义智能指针
    QScopedPointer<QObjectData> d_ptr;//这就是传说中的d-pointer,
};

QObject.cpp文件:
//数据类声明在行为类的cpp文件中或单独声明在一个文件中时,仅在行为类的cpp中引用其头文件

class QObjectData {
public:
    QObject *q_ptr;//包含一个行为类成员q_ptr  
};

class QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)
public:
    QObjectPrivate(int version = QObjectPrivateVersion);
} 

行为类和数据类关联实现如下:

//数据对象初始化q_ptr为空
QObjectPrivate::QObjectPrivate(int version)
{
    q_ptr = nullptr;  
}

//public构造函数调用protected构造函数时会new一个数据类对象
QObject::QObject(QObject *parent) : QObject(*new QObjectPrivate, parent)
{
}

//将数据类对象传给d_ptr
QObject::QObject(QObjectPrivate &dd, QObject *parent) : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;//将数据类的q_ptr指向行为类对象,即自己
}
//构造完成后行为类和数据类都相互保存对方的指针
//后面在行为类函数中就可以通过Q_D获取数据类对象
//在数据类函数中就可以通过Q_Q获取行为类对象

Q_DECLARE_PRIVATE

此宏定义在行为类中,定义了获取数据对象d_ptr的函数d_func
主要是为了后面的宏Q_D使用。
简化其定义如下:

宏定义中的##表示连接字符串
#define Q_DECLARE_PRIVATE(Class) \
    Class##Private* d_func() \
    {
         return d_ptr; \
    } \
     const Class##Private* d_func() const \
    {\ 
        return d_ptr; \
    } \
    friend class Class##Private;

Q_DECLARE_PRIVATE(QObject)转换后如下:
    QObjectPrivate* d_func() 
    {
         return d_ptr; 
    } 
     const QObjectPrivate* d_func() const 
    {
        return d_ptr; 
    }
    friend class QObjectPrivate;

Q_DECLARE_PUBLIC

此宏定义在数据类中,定义了获取行为对象的函数q_func
主要是为了后面的宏Q_Q使用。
简化其定义如下:

#define Q_DECLARE_PUBLIC(Class)  \
    Class* q_func() \
    { \
         return q_ptr; \ 
         } \
    const Class* q_func() const\
    { \
         return q_ptr; \
    } \
    friend class Class;

Q_DECLARE_PUBLIC(QObject)转换后如下:
    QObject* q_func()
    { 
        return q_ptr; 
    } 
    const QObject* q_func() const
    {
        return q_ptr;
    }
    friend class QObject;

Q_D

此宏在行为类函数中使用,用来定义一个指向数据对象d_ptr的指针d,
以供函数后面直接使用d
其定义如下:

#define Q_D(Class) Class##Private * const d = d_func()

Q_D(QObject);转换后:QObjectPrivate * const d = d_func();
由Q_DECLARE_PRIVATE(QObject)可知d_func返回的是d_ptr

void QObject::setParent(QObject *parent)
{
    Q_D(QObject);//转换后为QObjectPrivate * const d = d_ptr;
    d->setParent_helper(parent);//可以直接使用d指针操作数据类对象
}

Q_Q

此宏在数据类函数中使用,用来定义一个指向行为类对象q_ptr的指针q,
以供函数后面直接使用q
其定义如下:

#define Q_Q(Class) Class * const q = q_func()

Q_Q(QObject);转换后QObject * const q = q_func();
由Q_DECLARE_PUBLIC(QObject)可知q_func返回的是q_ptr

void QObjectPrivate::moveToThread_helper()
{
    Q_Q(QObject);//QObject * const q = q_ptr;
    QEvent e(QEvent::ThreadChange);
    QCoreApplication::sendEvent(q, &e);
    ...
}

Q_OBJECT

此宏用于定义元对象,需要使用QObject的信号关联必须定义此宏,并且需要在类定义最前面定义此宏

简化定义如下:
#define Q_OBJECT \
public: \
    static const QMetaObject staticMetaObject; \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
private: \
    static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    struct QPrivateSignal {}; \

QMetaObject元对象保存了类的基本信息是对类的描述,记录了类名称,槽、信号、函数数量偏移等。QMetaObject对象的初始化是通过qt元对象编译器moc编译后自动生成的。

继承QObject的类结构

继承QObject的类都有自己的特有数据类,其继承了QObject数据对象类。
在构造过程中是将自己的数据对象类,最终传给父亲类QObject的d_ptr,
也保证了每个对象仅有一个数据对象类指针,而不是每层级都有自己的d_ptr
在这里插入图片描述

1、
class QFtpPrivate : public QObjectPrivate
{};
//直接调用QObject的protected构造函数传入QObjectPrivate指针
QFtp::QFtp(QObject *parent) : QObject(*new QFtpPrivate, parent)
{
}

2、
class QActionGroupPrivate : public QObjectPrivate
{};
QActionGroup::QActionGroup(QObject* parent) : QObject(*new QActionGroupPrivate, parent)
{
}

3、
class  QWidgetPrivate : public QObjectPrivate
{};

class  QWidget : public QObject, public QPaintDevice
{
public:
 explicit QWidget(QWidget* parent = nullptr, Qt::WindowFlags);
protected:
    QWidget(QWidgetPrivate &d, QWidget* parent, Qt::WindowFlags f);
};

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, nullptr), QPaintDevice()
{
}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, nullptr), QPaintDevice()
{
}

get(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, nullptr), QPaintDevice()
{
}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, nullptr), QPaintDevice()
{
}
  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是保存HDMI视频数据录像的Qt代码示例: ```C++ #include <QCoreApplication> #include <QThread> #include <QDateTime> #include <QFile> #include <QDataStream> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavdevice/avdevice.h> } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 初始化ffmpeg库 av_register_all(); avdevice_register_all(); AVInputFormat *inputFormat = av_find_input_format("dshow"); AVDictionary *options = NULL; av_dict_set(&options, "video_size", "1920x1080", 0); av_dict_set(&options, "pixel_format", "uyvy422", 0); av_dict_set(&options, "framerate", "30", 0); av_dict_set(&options, "buffer_size", "1048576", 0); AVFormatContext *formatContext = NULL; int ret = avformat_open_input(&formatContext, "video=HD Webcam:audio=麦克风 (HD Webcam)", inputFormat, &options); if (ret != 0) { qDebug() << "avformat_open_input error" << av_err2str(ret); return 1; } // 查找视频流 int videoStreamIndex = -1; for (int i = 0; i < formatContext->nb_streams; i++) { if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; break; } } if (videoStreamIndex == -1) { qDebug() << "can't find video stream"; return 1; } // 打开视频解码器 AVCodecParameters *videoCodecpar = formatContext->streams[videoStreamIndex]->codecpar; AVCodec *videoCodec = avcodec_find_decoder(videoCodecpar->codec_id); AVCodecContext *videoCodecContext = avcodec_alloc_context3(videoCodec); ret = avcodec_parameters_to_context(videoCodecContext, videoCodecpar); if (ret != 0) { qDebug() << "avcodec_parameters_to_context error" << av_err2str(ret); return 1; } ret = avcodec_open2(videoCodecContext, videoCodec, NULL); if (ret != 0) { qDebug() << "avcodec_open2 error" << av_err2str(ret); return 1; } // 准备视频帧 AVFrame *videoFrame = av_frame_alloc(); if (videoFrame == NULL) { qDebug() << "av_frame_alloc error"; return 1; } // 打开输出文件 QDateTime currentDateTime = QDateTime::currentDateTime(); QString fileName = currentDateTime.toString("yyyyMMdd_hhmmss") + ".avi"; QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "open file error" << fileName; return 1; } // 写入文件头 AVOutputFormat *outputFormat = av_guess_format("avi", NULL, NULL); AVFormatContext *outFormatContext = NULL; ret = avformat_alloc_output_context2(&outFormatContext, outputFormat, NULL, fileName.toUtf8().data()); if (ret != 0) { qDebug() << "avformat_alloc_output_context2 error"

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值