今天在看QT对象内存管理的一篇文章时:
http://blog.csdn.net/dbzhang800/article/details/6300025
想到了一个问题:就是QT类库体系结构与Delphi类库体系结构的对比问题。从它们都有parent属性,而且都可以管理子控件的内存释放,就可以猜测两者的体系结构十分相似。以下是我的过程,就把它当自己对Qobject和QWidget的一个熟悉过程吧。

---------------------------------------------------------------------------

先看它们的继承体系:

Delphi的TApplication->TComponent->TPersistent->TObject
QT的QApplication->QCoreApplication->QObject
注意,它直接继承自QObject,而省略了delphi的两个层次:TComponent和TPersistent
因此特意查看了一下,QObject已经包括了setParent,非常类似于TComponent的InsertComponent(owner)
QObject的setObjectName相当于TComponent的setName。这样一来,QObject即已经包括了TComponent的主要功能。

但是QObject貌似没有TPersistent的RTTI和流入流出的功能。不过不要紧,因为C++标准里就包括了RTTI和流入流出的功能,因此不需要在类库里体现这一点,而是随时随地可用的。而Delphi因为自成一体,语言和类库结合的过于紧密,不得不单独定义一层TPersistent来提供相应的功能(也就是说,不使用VCL的object pascal是没有RTTI和流入流出功能的)。

这么说来,一个QObject就已经包括了Delphi的TObject、TPersistent和TComponent这三个类层次的功能。并且QObject还多了对signal的管理,tr的功能。

而且还有一个最大的区别是从QObject开始就处理事件的方方面面,connect,过滤,阻塞,并且专门提供了一大堆相关的附加功能。Delphi虽然也可使用Dispatch把消息发给TObject,但事实上没有人这样使用。

此外,QObject还提供了deleteLater功能,即自删除。这可是没有父类控件的情况下提供的哦~

还有一个特点:QObject竟然是从属于某个线程的,而且专门提供了2个函数:thread()和moveToThread()。而其它语言包括Delphi的Object都没有这个特征。究其原因,是因为QT把信号槽机制放在QObject级了,换而言之每个Object都可接受和处理信号,而信号是从属于某个线程的,因此QObject也就只能从属于某个线程了。这只是我的粗浅理解,不知道对不对。而且我觉得能不能把QObject的最基本服务提炼出来作为更高一层呢?这样更易于理解,也便于与其它语言交互,还可少用内存和其它负担。目前QObject管的事情实在太多了,强迫QObject从属于某个线程感觉有点怪异。对象交互性是很重要,但从实际角度而言,主要是GUI对象交互管理比较麻烦,所以没有必要将信号槽机制放在根对象级。

QObject还可调用metaObject()返回QMetaObject,里面又包括很多东西(类名,超类名,属性,信号,槽等等,QObject提供的objectName()是实例的名称,不是类名)。每个使用Q_OBJECT宏的子类实例,都会包括一个metaObject。但是QMetaObject是通过宏关键字实现的,所以除非官方提供了相应方法,否则无法增加/修改其内容。但是偏偏官方还提供了Q_DECLARE_METATYPE(MyClass)。这样一来,QMetaObject所包含的东西几乎是无限制的,其功能可谓异常强大。

最后,QObject还包括了customEvent,childEvent和timerEvent三个事件,而TObject却没有事件,要等到TControl才有,因为到了TControl才开始真正处理GUI事件。顺便数了一下,QWidget有31个事件(都是些保护函数),其中包括了winEvent函数。

---------------------------------------------------------------------------

让我觉得最有趣的就是,QT也有一个Application,并且相当于也是继承自TComponent。

QCoreApplication 最重要的功能是用来管程序的事件过滤(包括non-GUI的程序),而且QApplication管的事情非常多:

1. main函数的参数都传给它(Delphi则使用ParamStr这个系统级的变量解决了问题)
2. 管理QInputContext,里面包括输入方法和状态
3. Session
4. 显示状况(字体,styleSheet,调色板,光标,文字左右方向)
5. threshold 自动最大化的门槛,警告窗口,焦点变化,关闭closeAllWindows,当前激活的窗口,记录最后关闭的窗口等等
6. 提交数据
7. 与session manager的交互
8. 与外部桌面,键盘,鼠标的交互,双击间隔等等

看了一下Delphi的TApplication,主要还是管程序的运行与终止,以及它所有的子窗口。总的来说,QApplication的功能比TApplication管的事情多的多,因为Delphi还有TScreen分担一小部分功能,既不需要跨平台,且有winapi助阵因而对其它功能不以为然,TApplication把它的子窗口都管理管理好就行啦!虽然程序员也可使用winapi帮助QApplication,但是那样代码就不跨平台啦!因此QApplication被迫设计成多管许多系统方面的闲事。最后还发现application.run与app.exec都是那么的一致,控制GUI线程的事件/消息循环,真是太逗了。

------------------------------------------------------------------------------

那么接下去呢?Delphi单独写了一个TControl,主要目的是给图形类也提供一些鼠标处理的功能和文字字体颜色对齐这些基本的显示功能(比如用户可点击TLabel),这是Delphi非常独特和强大的功能。而QT接下去就是QWidget,相当于把TControl和TWinControl的功能直接合并了,QLabel就是继承自它的,这样一来每个QWidget都有句柄(问题:为啥Spy++探测不到QT程序的每个子元素),有了句柄还不是可以随心所欲的做各种处理,这就和标准Windows控件没有什么区别了。

那么QT的图像显示类怎么处理?基本上是自成一体,查看一下QPaintDevice是原类(不继承自任何类),这时C++的多继承特性就可发挥作用了,QWidget直接继承自QObject和QPaintDevice,即把Delphi的TWinControl和TGraphicControl的功能强行融合在一起(因为多继承的原因,这种融合是轻而易举的),准确的说,是把Delphi的TCustomControl和TGraphic的功能强行融合在一起,并且对图像控件和非图像控件不做区分,即每个QWidget子类都可自绘,而不依赖于系统提供的原生控件的功能与界面。Delphi之所以提供TControl是为了在提供一些功能的同时还能节省系统资源,即图形控件不需要系统句柄。而QWidget看起来没有强行区分图像控件和句柄控件,但它在更底层的实现上,实现了所有控件都是自绘,因此不需要在更上层的类库划分里再次区分两者。这么说来,两者还真是异曲同工呢,只是实现层面不同而已。

再进一步说,无论QT还是Delphi,首先它的是一个GUI元素(有没有句柄则不一定),它才可以具备自绘功能。但是如何自绘,以及哪些功能是通用的,这就需要一个单独的类进行定义,而不可能直接放到QWidget和TGraphicControl里,此时QT的QPaintDevice和Delphi的TGraphic就扮演了这种功能。不同之处在于QPaintDevice是原类,而TGraphic却仍继承了TObject和TPersistent,前面说过了TPersistent的功能,QPaintDevice也有(尽管它是原类),但继承自TObject并获取它提供的功能感觉不是很必要,也许这是Delphi基于RAD的设计的原因——为了管理和使用上的方便,因此才这样规定所有类都必须继承TObject。TGraphic还必须实现TInterface, IStreamPersist两个接口,说明还提供了引用计数和随心所欲的流入流出(TPersistent是针对DFM文件格式的)。

TComponent.Name与QObject.objectName相似(注意,TObject没有Name属性)
TComponent.tag与QWidget::accessibleName和QWidget::accessibleDescription比较相似

最后一个问题,QT为什么没有Delphi里对应的TForm?目前的情况是QMainWindow对应Delphi的主TForm,它继承自QWidget,相当于把控件专门强化后专门用来做主界面。而QT的每一个QWidget,都可作为一个显示窗口(除了主Form以外的每一个TForm),因此不需要单独定义TForm对应的组件,换而言之QWidget提供的功能过于强大,每一个QWidget既可以自己作为窗口,也可作为窗口的一个子元素。

QWidget过于强大,看看这些函数就知道了,大概QT官方是想尽可能的提供最方便的全部界面功能:
setGraphicsEffect
setMask
setStyle
windowModality
setWindowRole
而Delphi尽管也异常强大,但也没有直接提供如此之多的功能,更多的还是要基于Winapi的特性来扩展相应的功能。其实QT这么做也是没有办法呀。Delphi控件在取得Windows句柄后可以有winapi随时来助阵,但QT一切都是自绘,如果它官方不提供这种基本的特殊功能(好像有点绕口),普通程序员是很难进行扩充的。

这里还要提一句,体系结构类的函数多不要紧,那个完全不占内存,只有类里的数据成员才会增加对象的内存大小。

还有QDialog,还有。。。以后再补充。

------------------------------------------------------------------------------

今天又发现,QDesktopWidget相当于TScreen,真是差点笑死:
QDesktopWidget* d = QApplication::desktop();
区别在于QDesktopWidget它没有提供一个全局实例,而是每次都要返回指针。但事实上也是一直存在于内存中。

但是Delphi没有提供QSessionManager,也许是它有winapi,所以不需要吧。

------------------------------------------------------------------------------

还有一个重大的区别,就是Delphi只使用了绝对坐标体系,而QT同时使用了Layout可变的相对坐标体系(其实Delphi最新的FMX体系也提供了类似的layout)和setGeometry绝对坐标体系,还有QSS也能控制一部分界面排版(又跟VCL Style对应上了),这三者可同时起作用,并且相互影响或屏蔽,因此导致我在开发的时候经常产生一些困惑。

------------------------------------------------------------------------------

总的来说,QT的体系结构与Delphi类库体系结构十分相似,没有什么本质区别,但是鉴于Delphi严格区分图像控件和非图像控件,说明管理的更精细一些,把TForm与普通控件区分开也是这个原因,节省系统资源。而Delphi强调TComponent,除了提供父子控件的内存管理功能以外,还方便对非可视的算法与系统功能也可制作控件,也算是它的一大特色。

QT类库与Delphi VCL类库的体系结构对比——两者十分类似!的更多相关文章

  1. QT类库与Delphi类库的体系结构对比——两者十分类似!

    今天在看QT对象内存管理的一篇文章时:http://blog.csdn.net/dbzhang800/article/details/6300025想到了一个问题:就是QT类库体系结构与Delphi类 ...

  2. Atitit 图像处理 常用8大滤镜效果 Jhlabs 图像处理类库 java常用图像处理类库

    Atitit 图像处理 常用8大滤镜效果 Jhlabs 图像处理类库 java常用图像处理类库1.1. 5种常用的Photoshop滤镜,分别针对照片的曝光.风格色调.黑白照片处理.锐利度.降噪这五大 ...

  3. linux gcc 编译动态类库(.so)和静态类库(.a)

    linux gcc 编译动态类库(.so)和静态类库(.a) 我的编译环境 ubuntu desktop 16.04 一:测试代码 测试有3个文件:AB.h,AB.c,test.c //AB.h vo ...

  4. Z Order of Controls in Delphi VCL

    Get and set the Z Order of controls at runtime in Delphi VCL. If you are looking for a FireMonkey so ...

  5. [JNA系列]Java调用Delphi编写的Dll之Delphi与JAVA基本数据类型对比

    Delphi与JAVA基本数据类型对比 类型 Delphi关键字 JAVA关键字 字节 备注 范围 整型 Shortint byte 1 有符号8位 -128..127 Byte 1 无符号8位 0 ...

  6. QT Creator引用win32 api类库方法(.lib)

    由于Qt Creator使用的是mingW进行程序编译,该编译方式无法识别#pragma comment(lib,"lib\\hvdailt.lib")引用. 所以需要在.Pro文 ...

  7. c#类库和可移值类库的区别

    所谓类库,只能指定一个类库的可运行平台. 而可移值类库,可以在无需修改代码的情况,同时可以在多平台上运行DLL文件.多平台如NET Framework.Silverlight.Windows Phon ...

  8. 打包jar类库与使用jar类库

    翻译人员: 铁锚 翻译时间: 2013年11月17日 原文链接:  Build a Java library by using jar file 代码复用是软件开发中很重要的一个原则.将常用的函数构建 ...

  9. 4.熟悉Java基本类库系列——Java 正则表达式类库

    正则表达式语法结构图: Java正则表达式类库结构图: Java典型例子 1.String类 matches()方法 判断字符串是否符合特定正则表达式 @Test public void testRe ...

随机推荐

  1. Java基础学习总结(40)——Java程序员最常用的8个Java日志框架

    作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...

  2. ANSI转UTF-8中文无乱码解决方案

    近期做的项目需要使用Doxygen生成文档,由于前期代码不是本人完成,他使用的是ANSI格式的文件,后来我用Notepad++写其他文件时,默认保存为UTF-8 无BOM编码格式,因此整个项目文件中既 ...

  3. VMWare中装Linux系统常见问题

    1.安装VMWare的时候,可能会提示vtx-m没开启 解决办法:重启笔记本电脑,按完开机键后,按住del或者F1或者F2,进入BIOS,在BIOS中找到intel-cietue开关,开启就 可以(如 ...

  4. 读文件头数据判断 PE 文件格式和类型

    namespace X.Reflection { using System; using System.IO; public static partial class ReflectionX { pu ...

  5. Mybatis的使用中的一些不太注意的技巧

    以下就总结一下Mybatis的使用中的一些不太注意的技巧,算是Mybatis的总结笔 1.插入时主键返回 我们向数据库插入一条记录是,使用Mybatis的<insert>是无法返回插入的主 ...

  6. 关于mybatis中,批量增删改查以及參数传递的问题

    1.參数传递的问题 大多数情况下,我们都是利用map作为參数,而且大部分情况下都是仅仅有一个參数. 可是,我们也能够利用@param注解,来传入多个參数,此时,mybatis会自己主动将參数封装成ma ...

  7. Redis学习笔记--Hash(五)

    Redis的数据是通过key-value的方式存储的,对于value的数据类型有字符串.Hash.list.set.sortedSet在redis命令语句中,语句是忽略大小写的,但是key是不可以忽略 ...

  8. Makefile中支持的函数大全

    一.描述 Makefile的函数调用,很像变量的使用,也是以"$"来标识的,其语法如下: $(<function> <arguments> ) 或是 ${& ...

  9. 高级Java工程师必备 ----- 深入分析 Java IO (三)

    概述 Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO( ...

  10. C++学习笔记(达内视频版)

    达内C++(陈宗权主讲) 第一天: 课程分为Core C++(标准C++.不依赖操作系统)和Unix C++. 1.配置bash,运行.sh文件. vi bash_profile 在"pat ...