上一次关注Qt Lighthouse是在6月初,可是现在都8月底了。时间真快...

Lighthouse 是 QPA(Qt Platform Abstraction) 项目的名字,它使得将Qt移植到新的平台变得比较简单。尽管现在它已经完全融入到了Qt主干代码中,lighthouse作为独立项目已经不复存在了,但本文中,我们继续使用这个名字(虽然已不太恰当)。

QPA 抽象了什么?

不妨看看QPA前后,有何不同:

之前

考虑一下,传统的Qt是如何实现图形界面的夸平台:

  • 针对不同的窗口系统(WS)定义相应的宏: Q_WS_*

Q_WS_X11
Q_WS_MAC
Q_WS_QWS
Q_WS_WIN
Q_WS_S60
  • 代码中夹杂大量的编译预处理指令 (处理小段)
#if defined(Q_WS_X11)
...
#elif defined(Q_WS_MAC)
...
#elif defined(Q_WS_WIN)
...
#endif
  • 各个窗口系统相关的代码文件 (处理大段)
qapplication_x11.cpp
qapplication_win.cpp
qapplication_s60.cpp
qapplication_mac.mm
qapplication_qws.cpp
...
qwidget_win.cpp
qwidget_qws.cpp
qwidget_mac.cpp
qwidget_x11.cpp
...
  • src/gui/kernel.pri 等工程文件内,控制哪些文件参与编译
win32 {
...
}
symbian {
...
}
unix:x11 {
...
}

这一切这意味这什么??

如果我们想在这个基础上支持一个新的窗口系统,比如wayland,需要

  • 添加平台相关的宏,代码中针对该窗口再扩充 #if #elif #endif

  • 添加平台相关的文件,扩充 **.pri 文件使其融入Qt
  • ...

总之,需要对Qt的代码进行大量的修改。这一切使得将Qt移植到新的窗口系统中,变得不是那么容易。

之后

QPA 定义了一套接口,而后,将窗口系统相关的代码放到插件中:

  • src/plugins/platforms/xlib/*
  • src/plugins/platforms/wayland/*
  • src/plugins/platforms/cocoa/*

这时,如果我们想支持一个新的窗口系统,怎么办?只需要编写一个新的插件,而Qt自身的代码则不需要任何改变。

(当然,编写插件本身还是很有难度的,哈...)

QPA源码结构

为了使插件能供工作,Qt中需要提供有相应的加载接口,在Qt源码中搜索*_qpa.h*_qpa.cpp *_qpa_p.h 即可找到所有(fixme)和 qpa有关的代码:

  • QTDIR/src/opengl

    • qgl_qpa.cpp
  • QTDIR/src/gui
    • painting

      • qcolormap_qpa.cpp
      • qpaintdevice_qpa.cpp
    • image
      • qpixmap_qpa.cpp
    • egl
      • qegl_qpa.cpp
    • kernel
      • qplatformintegrationplugin_qpa.cpp
      • qplatformcursor_qpa.cpp
      • qwidget_qpa.cpp
      • ...
    • text
      • qfontengine_qpa.cpp
      • qfontengine_qpa_p.h
      • ...

可以看到代码集中在 gui/kernel 部分;除此外,和字体相关gui/text,和绘图相关gui/painting、gui/image、gui/egl,和opengl相关

QPA结构

QPlatformIntegration

这个应该算是 QPA 的核心了,

  • 它是QApplication(准确地说是QApplicationPrivate)的成员
class Q_GUI_EXPORT QApplicationPrivate : public QCoreApplicationPrivate
{
...
static QPlatformIntegration *platform_integration;
...
  • 在初始化QAppliction时它会被创建
QApplication::QApplication()
QApplicationPrivate::construct()
qt_init()
init_platform()
QPlatfromIntegrationFactory::create()
  • 它是所有窗口系统相关函数的入口点
class Q_GUI_EXPORT QPlatformIntegration
{
public:

GraphicsSystem functions

 

virtual QPixmapData *createPixmapData()

 

virtual QPlatformWindow *createPlatformWindow()

 

virtual QWindowSurface *createWindowSurface()

Window System functions

 

virtual QList<QPlatformScreen *> screens()

 

virtual void moveToScreen()

 

virtual bool isVirtualDesktop()

 

virtual QPixmap grabWindow()

Deeper window system integrations

 

virtual QPlatformFontDatabase *fontDatabase()

 

virtual QPlatformClipboard *clipboard()

...

这样一来:

当你在程序中

它会向QPlatformIntegration请求

使用QWidget时

给我一个窗口(QPlatformWindow)及绘图区域(QWindowSurface)

使用QPixmap时

给我一个位图的后端(QPixmapData)

使用QFont时

给我字体数据信息(QPlatformFontDatabase)

使用QGLWidget时

给我一个窗口

...

...

QPlatformWindow 与 QWindowSurface

QPlatformWindow

窗口
负责窗口的几何尺寸
可以是另一个窗口的子窗口

QWindowSurface

窗口绘图区域(drawing area of a window)
它来决定使用哪一个paintEngine
将像素Push到屏幕上

相对而言,QPlatformWindow 出现的比较晚一点(见Say hello to QPlatformWindow一文)之所以。之所以分离开来,原因见Remodelling the Lighthouse

QPlatformScreen

  • 代表屏幕(显示器)
  • 它提供的api对应用程序来说是只读的
  • 用来计算分辨率 dpi
class Q_GUI_EXPORT QPlatformScreen : public QObject
{
...
virtual QRect geometry() const = 0;
virtual QRect availableGeometry() const {return geometry();}
virtual int depth() const = 0;
virtual QImage::Format format() const = 0;
virtual QSize physicalSize() const;

QPixmapData

为什么要有这个东西?

通常我们似乎都不怎么区分QImage和QPixmap,尽管在Manual中很大的篇幅在描述这二者的区别。

设计目的和用途(一个是IO和像素操作,一个是屏幕显示):

  • QImage is designed and optimized for I/O, and for direct pixel access and manipulation
  • while QPixmap is designed and optimized for showing images on screen.

典型的用途:

  • Typically, the QImage class is used to load an image file, optionally manipulating the image data, before the QImage object is converted into a QPixmap to be shown on screen.
  • Alternatively, if no manipulation is desired, the image file can be loaded directly into a QPixmap.

与QImage不同,QPixmap 是平台相关的

  • Note that the pixel data in a pixmap is internal and is managed by the underlying window system.

于是它的后端需要由各个窗口系统来提供也就不足为奇了。

QPlatformFontDatabase

提供字体信息

详见Fonts in Lighthouse一文。

其他

  • QPlatformClipboard
  • QPlatformCursor
  • ...

同前面几个一样,从名字上容易看出是做什么的。

参考

http://www.cppblog.com/lauer3912/archive/2011/09/15/155888.html

Qt Lighthouse学习(二),就是QPA(Qt Platform Abstraction) 项目的名字的更多相关文章

  1. QT入门学习笔记2:QT例程

    转至:http://blog.51cto.com/9291927/2138876 Qt开发学习教程 一.Qt开发基础学习教程 本部分博客主要根据狄泰学院唐老师的<QT实验分析教程>创作,同 ...

  2. SpringCloud学习(二):微服务入门实战项目搭建

    一.开始使用Spring Cloud实战微服务 1.SpringCloud是什么? 云计算的解决方案?不是 SpringCloud是一个在SpringBoot的基础上构建的一个快速构建分布式系统的工具 ...

  3. Qt介绍1---QPA(Qt Platform Abstraction)

    Qt是一个夸平台的库(一直宣称“Qt everywhere”),但是Qt底层不是夸平台的.比如:Qt中Gui部件的核心类QWidget,该类除了qwidget.h 和 qwidget.cpp两个原文件 ...

  4. Qt Model/View学习(二)

    Model和View的搭配使用 DEMO pro文件 #------------------------------------------------- # # Project created by ...

  5. 第15.27节 PyQt(Python+Qt)入门学习:Model/View架构中的便利类QTreeWidget详解

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 树部件(Tree Widget)是Qt Designer中 Item Widgets(It ...

  6. Qt 插件学习(一)

    插件是什么 注意:这儿暂时不考虑静态插件(潜意识中总觉得它根本就不算插件). 插件是一个动态库(共享库).动态库是一个独立的文件中的独立模块,可被多个程序访问. 先看动态库的两种用法 1. 程序链接时 ...

  7. PyQt(Python+Qt)学习随笔:QDial刻度盘部件功能简介

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 Designer中的Dial刻度盘输入部 ...

  8. PyQt(Python+Qt)学习随笔:QSlider滑动条部件功能简介

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 Designer输入部件中的Horizo ...

  9. PyQt(Python+Qt)学习随笔:纯文本编辑器QPlainTextEdit功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 QPlainTextEdit是用于纯文本的一个高级文档编辑器 ...

随机推荐

  1. 【LG3240】[HNOI2015]实验比较

    题面 洛谷 题解 30pts 爆搜即可. 100pts 题意描述里有一句:"对每张图片\(i\),小\(D\)都最多只记住了某一张质量不比\(i\)差的另一张图片\(K_i\)." ...

  2. Kubernetes学习之路(五)之Flannel网络二进制部署和测试

    一.K8S的ip地址 Node IP:节点设备的IP,如物理机,虚拟机等容器宿主的实际IP. Pod IP:Pod的IP地址,是根据docker0网络IP段进行分配的. Cluster IP:Serv ...

  3. 把模块有关联的放在一个文件夹中 在python2中调用文件夹名会直接失败 在python3中调用会成功,但是调用不能成功的解决方案

    把模块有关联的放在一个文件夹中 在python2中调用文件夹名会直接失败在python3中调用会成功,但是调用不能成功 解决办法是: 在该文件夹下加入空文件__init__.py python2会把该 ...

  4. 测试模型---V模型

    软件测试&软件工程 软件测试是软件工程不可缺少的一部分. 一.V模型简介 需求分析 验收测试 概要设计 系统测试 详细设计 集成测试 编码 单元测试   (1)单元测试: 又称模块测试,针对软 ...

  5. 通俗理解BFS和DFS,附基本模板

    1.BFS(宽度优先搜索):使用队列来保存未被检测的节点,按照宽度优先的顺序被访问和进出队列 打个比方:(1)类似于树的按层次遍历 (2)你的眼镜掉在了地上,你趴在地上,你总是先摸离你最近的地方,如果 ...

  6. Oracle中解析XMLType格式字段

    背景:项目从某数据交换平台获取XML数据,以Oracle的XMLType格式保存在数据库字段中,需要建立触发器.存储过程,在保存数据时解析XML字段,将数据写入其他业务表中. 参考资料:Oracle的 ...

  7. Python机器学习库SKLearn:数据集转换之管道和特征

    转载自:https://blog.csdn.net/cheng9981/article/details/61918129 4.1 管道和特征:组合估计量 4.1.1 管道:链接估计 管道可以用于将多个 ...

  8. Netty源码分析第6章(解码器)---->第4节: 分隔符解码器

    Netty源码分析第六章: 解码器 第四节: 分隔符解码器 基于分隔符解码器DelimiterBasedFrameDecoder, 是按照指定分隔符进行解码的解码器, 通过分隔符, 可以将二进制流拆分 ...

  9. Tesseract 4 自行构建支持双引擎的tessdata 文件

    Tesseract 4 版本具备两种识别引擎:新的基于LSTM(神经网络)引擎与传统引擎.通过在初始化时设定不同的EngineMode启动. OCR Engine modes: 0 Legacy en ...

  10. to_char

    to_date(to_char(to_date(#{conds.currentTime,jdbcType=VARCHAR},'YYYY-MM-DD hh24:mi:ss'),'hh24:mi:ss') ...