姚冬中老年程序员

被邀请了很久了,一直在思考,今天终于下决心开始写回答。

这个问题的确是够大的,Qt的代码规模在整个开源世界里也是名列前茅的,这么大的项目其中的精华是非常多的,很难说得全面,实际上我对Qt也不是完全了解,里面还有很多我不熟悉的东西。

首先,我想谈的是 signal/slot,Qt算是发明了signal/slot,这个思想也被其他一些框架语言借鉴了。

谈signal/slot之前先来谈谈C++的缺欠,这个问题也被讨论很多了,这里只谈一点,C++的设计目标是面向对象语言,它不仅提供了对象的定义和构建的方式,也定义了对象间的关系,比如 继承 派生 聚合,但是它没有提供对象间通信和共享数据的方式,这个缺点在一般程序的开发上不算个大问题,我们可以自己简单实现,但是对于GUI开发,这个缺点就被放大了很多倍。GUI上的对象实在太多,窗口是对象,布局是对象,定时器是对象,而且对象间有错综复杂的关系,通信和数据交换非常频繁,比如按钮按下要通知父窗口或容器对象,滚动条变化了要通知列表对象。这种数量庞大的对象以及复杂的通信关系,可不是自己搞个简单的实现就能解决的。

说到通信和共享,其实他们是一回事,共享很多时候就是为了通信,而C++里要通信就必然要共享。
比如,一个类实例拥有另一个的指针,就可以访问对方的数据,调用对方的方法了,这实际就是共享了一个指针,这个类指针也是另一个对象的this。访问数据和调用方法其实都是通信,把对方的数据拿过来,把自己的数据送过去,交换数据就是通信。

在C++里,由于没有GC,管理大量原生指针是极其危险的,对象的生命周期不可控,野指针的出现概率会很高,大型C++ 的GUI项目参与开发的人数众多,很难保证都不犯错。
那么用观察者模式呢?其实也一样,还是共享了IObserverXXX指针。
那么发消息行不行呢?比如 MFC那样,可以,但是本质上还是共享了窗口句柄,否则消息发给谁呢?而且还带来另外的问题,就是类型安全,消息的参数是无法类型安全的。

Qt作为大型GUI项目的Framework,它必须解决这个问题,否则这个程序是写不大的,写大了就会问题层出不穷。
来看一段代码,看看Qt 的解决方案:

Window::Window()
{
QPushButton *b = new QPushButton(this);
connect(b, SIGNAL(clicked()), SLOT(on_button_clicked()));
} Window::on_button_clicked()
{
QPushButton *b = qobject_cast<QPushButton*>(sender());
b->setText("clicked!");
}

这段代码,通过Qt的signal slot机制,把QPushButton的点击事件连接到了Window的on_button_clicked响应函数上。
Window 和 QPushButton并没有互相保存对方指针,QPushButton的指针b 只是个局部变量,用过之后很快销毁,Window和QPushButton实现了通信,数据共享,事件响应,但是却没有共享指针,而且他们不受对方的生命周期影响,无论谁先销毁,这段代码都不会出错。
这种方式还是类型安全的,当signal和slot的类型不匹配的时候 connect是会报错的。

有人会说,我们用智能指针不就好了。好啊,智能指针你不会自己写吧,那么用boost?boost里能创建窗口吗?不能吧,还是要其他GUI库的,把两个异构的Framework撮合到一起也不是轻而易举的。再说了Qt出来的时候,别说Boost,STL都还没有呢。

signal/slot为对象间通信提供了非常灵活方便的实现,如果你只关心一个signal那就可以只connect一个,可以多个slot连接同一个signal,也可以一个slot连接到多个signal,Qt会负责管理连接关系和对象生命周期,对象销毁时会自动断开连接。

Qt为了实现signal/slot也是付出代价的,在无法改变C++语法的情况下,只能通过moc预编译器来扩展关键字。这大概是独一无二的实现方式了,后来的signal/slot实现要不用C++ template,或者发明种语言直接做到语法里,比如C# delegate。(读书笔记:委托和函数指针有点类似,但是具有更多的功能,详见:http://baike.baidu.com/subview/159798/8172828.htm)

最后总结下,Qt的signal/slot是为了解决对象间通信问题,同时避免共享指针造成的内存野指针和对象生命周期问题(读书笔记:一共解决了2个问题,因为野指针说到底也是因为对象生命周期不可控)。

下一个议题,等我想好了再说。。。。

---------------------------------------------------
这么大的命题,邀请我?太看的起我了、、、
我先占个坑,等大牛们解答、、

顺便先抛个砖:
Qt把C++的特性利用的很给力,你读Qt源码就能学习很多C++的技巧。
Qt的moc系统,让静态的C++模拟了动态语言的很多特性,例如反射、、
Qt的很多设计思想很给力,那几种设计模式在Qt中也有很多应用的,而且很优雅、、
Qt的跨平台封装、、
······
至于你说怎么学到:
一、先学习理解设计的思路。
二、读源码、、

---------------------------------------------------
Qt的库很庞大,并且使用本来特性就包罗万象的C++,不能贪多只能慢慢来。
Qt的signal/slot机制算是很重要的一个环节。
除此之外我讲一个signal/slot与QEventLoop结合的小技巧,直接贴代码:

QNetworkAccessManager m;
QNetworkRequest req(QUrl("http://www.google.com"));
QNetworkReply* rep = m.get(req);
QEventLoop l;
QObject::connect(rep, SIGNAL(finished()), &l, SLOT(quit()));
l.exec();

上面的代码可以实现使用get方法获取页面内容的同时又不阻塞界面UI。
是不是挺好玩儿的?

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

QT的精髓就两个:
1、QT的metaobject系统
2、QT API的设计,易用且很难错用

------------------------------------------------------------------- 
qt 最重要的一点, 就是它的MVC 开发模式, 这让很多人的入行变得更为简单,,
因为你只要写好你所要的类就行了, 其它的你管不了, 也不用管,

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

曾经看到一个做电路的家伙(会C语言),在不懂C++的情况下,用Qt写出了windows应用程序。
这就是精髓吧,想想怎么做到的?(天啊,这需要多么高超的类库设计才能做到这一点!与Delphi有一拼了)

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

qt 的精髓在于开源,Windows的标准控件不是开源的,无法知道gui控件具体是如何实现的,扩展不开源的gui就像带着僚拷跳舞,修改,解决bug也麻烦,所以大部分gui库只是封装而已,qt基本上是全是自己的一套,并且完全开源,提供了一个绝好机会窥视gui具体实现。

参考:http://www.zhihu.com/question/27040542

如何才能学到Qt的精髓——信号槽之间的无关性,提供了绝佳的对象间通讯方式,QT的GUI全是自己的一套,并且完全开源,提供了一个绝好机会窥视gui具体实现的更多相关文章

  1. Qt开发之信号槽机制

    一.信号槽机制原理 1.如何声明信号槽 Qt头文件中一段的简化版: class Example: public QObject { Q_OBJECT signals: void customSigna ...

  2. Qt::浅谈信号槽连接,参数在多线程中的使用

    Qt的信号槽有五种连接方式定义在enum Qt::ConnectionType,下面简单介绍 Qt::AutoConnection:自动判断连接方式,如果信号发送对象和执行槽对象在同一线程,那么等于Q ...

  3. QT中的信号槽

    只有继承了QObject类的类,才具有信号槽的能力.所以,为了使用信号槽,必须继承QObject. 凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT. 不管是 ...

  4. Qt 学习之路:深入 Qt5 信号槽新语法

    在前面的章节(信号槽和自定义信号槽)中,我们详细介绍了有关 Qt 5 的信号槽新语法.由于这次改动很大,许多以前看起来不是问题的问题接踵而来,因此,我们用单独的一章重新介绍一些 Qt 5 的信号槽新语 ...

  5. Qt 学习之路 2(16):深入 Qt5 信号槽新语法

    Qt 学习之路 2(16):深入 Qt5 信号槽新语法  豆子  2012年9月19日  Qt 学习之路 2  53条评论 在前面的章节(信号槽和自定义信号槽)中,我们详细介绍了有关 Qt 5 的信号 ...

  6. QT信号槽与Delphi事件的对比

    最近学QT,对信号槽机制感到有点新鲜: QObject::connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int))); 自己 ...

  7. Qt信号-槽原理剖析--(1)信号槽简介

    唯有创造才是快乐.只有创造的生灵才是生灵.--罗曼·罗兰 信号槽是观察者模式的一种实现,特性如下: A.一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知: B.一个槽就是一个观察者, ...

  8. Qt自定义信号槽的使用浅析+实例

    1. Qt中自定义信号槽的使用 Qt框架提供的信号槽在某些特定场景下是无法满足我们的项目需求的,因此我们还设计自己需要的的信号和槽,使用connect()对自定义的信号槽进行连接. 如果想要使用自定义 ...

  9. Qt 学习之路 :信号槽

    信号槽是 Qt 框架引以为豪的机制之一.熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力. 所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被 ...

随机推荐

  1. 如何覆盖aar的资源

    1.首先理解一下aar的构造 classes.jar ----代码 res---资源文件 2.替换 查看res里面的资源文件,这个资源文件事实上都是跟安卓的资源文件夹是一样的.你只需要理解xml和里面 ...

  2. C#break、continue、return、goto

    1.break break语句会使运行的程序立即退出包含在其中的最内层循环(结束此次循环且结束该循环控制体)或者switch语句 ; ; j < ; j++) { i++; )break; Co ...

  3. WPF设置窗口模式(Windowstyle=“None”)

    当WindowStyle="None"时,设置AllowsTransparency="True",则不会出现黑色Border,然后可以另外设置外边的Border ...

  4. mysql innodb 数据打捞(一)innodb 页面结构特征

    如果文件系统损坏或意外删除了数据库文件,只要磁盘空间没有被覆盖,其实数据都还在磁盘的扇区中,还是可以恢复出来的,有些通用的文件恢复工具好象也可以恢复文件 ,但这里要研究的是在通用文件 恢复工具失效的时 ...

  5. 生产者-消费者模型的3种Java实现:synchronized,signal/notifyAll及BlockingQueue

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3555111.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  6. 获取input标签的所有属性

    1.用jquery$("input[name='btnAdd']").attr("value") 获取value属性值,其它属性换attr的参数就OK 例1: ...

  7. Photoshop快捷键

    ctrl+del :铺后景色alt+del:铺前景色ctrl+d:取消选框ctrl+t:拉伸(挡住文字)TAB:显示(隐藏)工具栏ctrl+alt+i:反选ctrl+r:辅佐线ctrl+j:复制并添加 ...

  8. C# 创建XML文档

    有些时候我们需要生成一个xml文档作为数据交换的容器.当然我们用拼接字符串的方法来进行构建xml,但是这种方法虽然简单有效,但是如果xml文档结构过于复杂,拼接字符串会让人眼花缭乱.这时候就需要C#给 ...

  9. 【6】了解Bootstrap栅格系统基础案例(1)

    从上一张我们了解了栅格选项,那么我们就来了实战了解下吧(其实还是中文官网的案例) ps.我这里是电脑上用谷歌浏览器来观察的,毕竟电脑的分辨率高(1440*900px),谷歌浏览器最大化后,值比大屏幕设 ...

  10. 安装ARM调试器

    一.概述 1.调试ARM应用程序的软硬件组成 硬件JTAG/SWD仿真器 Eclipse调试插件 GDB调试客户端 GDB服务器端 JTAG/SWD需要的硬件驱动 2.GNU ARM Eclipse推 ...