QT-201410220947qt是什么软件

【图】- QT450-10是什么材料 - 东莞东坑其他物品 - 百姓网
更新提示:发现新版本浏览器,一样简单易用,速度提升30%不再显示&&关注百姓微信公众号,尽享快捷刷新、信息推送、抽奖活动等众多微信功能您只需要:1 &用微信“扫一扫”右边的二维码2 &在微信中“关注”我们&|&||||||QT450-10是什么材料&提示信息设置为“搞定了!”状态后,其他用户将无法查看您的联系方式。您确认搞定了这条信息吗?提示重新发布后可使用“刷新”将发布时间更新为最新时间,并将信息排到第一页。&&9月15日 8:22 &...次浏览 &信息编号: &价格:15元QQ号:地区:&-&东莞市东坑第一工业区&1502407****号码归属地:东莞&&百姓网号码保护功能介绍&&拨打百姓400转呼电话绝不收取您任何额外费用,该信息发布人仍能看到您的来电号码。联系时,请一定说明在百姓网看到的,谢谢!见面最安全,发现问题请举报。东莞球墨铸铁棒供应商,球墨铸铁材质,球墨铸铁板,球&&墨铸铁棒,铸铁型材,球墨铸铁价格,球墨铸铁厂家,球墨铸铁密度,球墨铸铁硬度,球墨铸铁多少钱一吨,球墨铸铁性能,灰铸铁,铸铁棒,灰铸铁板,灰铸铁棒,灰铸铁化学成分,灰铸铁密度,灰铸铁材质,灰铸铁多少钱一吨,高精密球墨铸铁棒,高密度球墨铸铁棒,耐热球墨铸铁棒,球墨铸铁板。耐高温球墨铸铁棒,合金球墨铸铁棒,高韧性球墨铸铁棒,铸铁型材。高强度球墨铸铁棒,高精密球墨铸铁棒,高韧性铸铁棒,高硬度球墨铸铁棒,铸造球墨铸铁,耐热球墨铸铁,高硅耐热球墨铸铁,中硅耐热球墨铸铁。球墨铸铁报价,球墨铸铁行情,球墨铸铁热处理硬度。
主要由铁、碳和硅组成的合金的总称。在这些合金中,含碳量超过在共晶温度时能保留在奥氏体固溶体中的量。铸铁主要由铁、碳和硅组成的合金的总称。在这些合金中,含碳量超过在共晶温度时能保留在奥氏体固溶体中的量。
含碳量在2%以上的铁碳合金。工业用铸铁一般含碳量为2%~4%。碳在铸铁中多以石墨形态存在,有时也以渗碳体形态存在。除碳外,铸铁中还含有1%~3%的硅,以及锰、磷、硫等元素。合金铸铁还含有镍、铬、钼、铝、铜、硼、钒等元素。碳、硅是影响铸铁显微组织和性能的主要元素。
铸铁可分为
①灰口铸铁。含碳量较高(2.7%~4.0%),碳主要以片状石墨形态存在,断口呈灰色,简称灰铁。熔点低(℃),凝固时收缩量小,抗压强度和硬度接近碳素钢,减震性好。用于制造机床床身、汽缸、箱体等结构件。
②白口铸铁。碳、硅含量较低,碳主要以渗碳体形态存在,断口呈银白色。凝固时收缩大,易产生缩孔、裂纹。硬度高,脆性大,不能承受冲击载荷。多用作可锻铸铁的坯件和制作耐磨损的零部件。
③可锻铸铁。由白口铸铁退火处理后获得,石墨呈团絮状分布,简称韧铁。其组织性能均匀,耐磨损,有良好的塑性和韧性。用于制造形状复杂、能承受强动载荷的零件。
④球墨铸铁。将灰口铸铁铁水经球化处理后获得,析出的石墨呈球状,简称球铁。比普通灰口铸铁有较高强度、较好韧性和塑性。用于制造内燃机、汽车零部件及农机具等。
⑤蠕墨铸铁。将灰口铸铁铁水经蠕化处理后获得,析出的石墨呈蠕虫状。力学性能与球墨铸铁相近,铸造性能介于灰口铸铁与球墨铸铁之间。用于制造汽车的零部件。
⑥合金铸铁。普通铸铁加入适量合金元素(如硅、锰、磷、镍、铬、钼、铜、铝、硼、钒、锡等)获得。合金元素使铸铁的基体组织发生变化,从而具有相应的耐热、耐磨、耐蚀、耐低温或无磁等特性。用于制造矿山、化工机械和仪器、仪表等的零部件。
铸铁的分类
分类方法分类名称说明
1.按断口颜色分
(1)灰铸铁这种铸铁中的碳大部分或全部以自由状态的片状石墨形式在,其断口呈暗灰色,有一定的力学性能和良好的被切削性能,普遍应用于工业中
(2)白口铸铁白口铸铁是组织中完全没有或几乎完全没有石墨的一种铁碳合金,其断口呈白亮色,硬而脆,不能进行切削加工,很少在工业上直接用来制作机械零件。于其具有很高的表面硬度和耐磨性,又称激冷铸铁或冷硬铸铁
(3)麻口铸铁麻口铸铁是介于白口铸铁和灰铸铁之间的一种铸铁,其断口呈灰白相间的麻点状,性能不好,极少应用
2.按化学成分分
(1)普通铸铁是指不含任何合金元素的铸铁,如灰铸铁、可锻铸铁、球墨铸铁等
(2)合金铸铁是在普通铸铁内加入一些合金元素,用以提高某些特殊性能而配制的一种高级铸铁。如各种耐蚀、耐热、耐磨的特殊性能铸铁
3.按生产方法和组织性能分
(1)普通灰铸铁参见&灰铸铁&
(2)孕育铸铁这是在灰铸铁基础上,采用&变质处理&而成,又称变质铸铁。其强度、塑性和韧性均比一般灰铸铁好得多,组织也较均匀。主要用于制造力学性能要求较高,而截面尺寸变化较大的大型铸件
(3)可锻铸铁可锻铸铁是由一定成分的白口铸铁经石墨化退火而成,比灰铸铁具有较高的韧性,又称韧性铸铁。它并不可以锻造,常用来制造承受冲击载荷的铸件
(4)球墨铸铁简称球铁。它是通过在浇铸前往铁液中加入一定量的球化剂和墨化剂,以促进呈球状石墨结晶而获得的。它和钢相比,除塑性、韧性稍低外,其他性能均近,是兼有钢和铸铁优点的优良材料,在机械工程上应用广泛
(5)特殊性能铸铁这是一种有某些特性的铸铁,根据用途的不同,可分为耐磨铸铁、耐热铸铁、耐蚀铸铁等。大都属于合金铸铁,在机械制造上应用较广泛
铸铁-热处理工艺
1.消除应力退火由于铸件壁厚不均匀,在加热,冷却及相变过程中,会产生效应力和组织应力。另外大型零件在机加工之后其内部也易残存应力,所有这些内应力都必须消除。去应力退火通常的加热温度为500~550℃保温时间为2~8h,然后炉冷(灰口铁)或空冷(球铁)。采用这种工艺可消除铸件内应力的90~95%,但铸铁组织不发生变化。若温度超过550℃或保温时间过长,反而会引起石墨化,使铸件强度和硬度降低。
2.消除铸铁白口的高温石墨化退火
铸件冷却时,表层及薄截面处,往往产生白口。白口组织硬而脆、加工性能差、易剥落。因此必须采用退火(或正火)的方法消除白口组织。退火工艺为:加热到550-950℃保温2~5 h,随后炉冷到500-550℃再出炉空冷。在高温保温期间,游高渗碳体和共晶渗碳体分解为石墨和A,在随后护冷过程中二次渗碳体和共析渗碳体也分解,发生石墨化过程。由于渗碳体的分解,导致硬度下降,从而提高了切削加工性。
3.球铁的正火
 球铁正火的目的是为了获得珠光体基体组织,并细化晶粒,均匀组织,以提高铸件的机械性能。有时正火也是球铁表面淬火在组织上的准备、正火分高温正火和低温正火。高温正火温度一般不超过950~980℃,低温正火一般加热到共折温度区间820~860℃。正火之后一般还需进行四人处理,以消除正火时产生的内应力。
4.球铁的淬火及回火
 为了提高球铁的机械性能,一般铸件加热到Afc1以上30~50℃(Afc1代表加热时A形成终了温度),保温后淬入油中,得到马氏体组织。为了适当降低淬火后的残余应力,一般淬火后应进行回火,低温回火组织为回火马氏作加残留贝氏体再加球状石墨。这种组织耐磨性好,用于要求高耐磨性,高强度的零件。中温回火温度为350-500℃回火后组织为回火屈氏体加球状石墨,适用于要求耐磨性好、具有一定效稳定性和弹性的厚件。博扬公司-相关人才较多集中在钢铁英才网。高温回火温度为500-60D℃,回火后组织为回火索氏作加球状石墨,具有韧性和强度结合良好的为500-60D℃,回火后组织为回火索氏作加球状石墨,具有韧性和强度结合良好的综合性能,因此在生产中广泛应用。
5.球铁的多温淬火
球铁经等温淬火后可以获得高强度,同时兼有较好的塑性和韧性。多温淬火加热温度的选择主要考虑使原始组织全部A化、不残留F,同时也避免A晶粒长大。加热温度一般采用Afc1以上30~50℃,等温处理温度为0~350℃以保证获得具有综合机械性能的下贝氏体组织。稀土镁铝球铁等温淬火后&b=MPa,&k=3~3.6J/cm2,HRC=47~51。但应注意等温淬火后再加一道回火工序。
6.表面淬火
为了提高某些铸件的表面硬度、耐磨性及疲劳强度,可采用表面淬火。灰铸铁及球铁铸件均可进行表面淬火。一般采用高(中)频感应加热表面淬火和电接触表面淬火。
7.化学热处理
对于要求表面耐磨或抗氧化、耐腐蚀的铸件,可以采用类似于钢的化学热处理工艺,如气体软氯化、氯化、渗硼、渗硫等处理。
KS韩国 GC100
AWS美国NO.20
UNS美国 F11401
GB中国 QT400-18
JIS日本 FCD350-22
KS韩国GCD370
AWS美国 60-40-18
UNS美国F32800
特 点:产品规格齐全,价格优惠,包装完好,铜质纯净,直线度好,库存量大,可提供材质证明和SGS报告。
规格可定做,诺西公司欢迎您的来电,我们将谒诚为您服务。
【销售热线赵丽丽】【2】【QQ:】
浙江球墨铸铁棒,苏州铸铁型材,耐热铸铁棒,上海球墨铸铁棒,上海灰铁棒,宁波铸铁型材,嘉兴球墨铸铁棒,杭州球墨铸铁棒,广东球墨铸铁棒,苏州球墨铸铁,无锡球墨铸铁,球墨铸铁棒,铸铁型材,上海球墨铸铁,安徽球墨铸铁,湖州球墨铸铁,台州球墨铸铁,珠海球墨铸铁棒,江门球墨铸铁棒,佛山球墨铸铁棒,汕头球墨铸铁棒,湛江球墨铸铁,肇庆球墨铸铁,茂名球墨铸铁,惠州球墨铸铁棒,梅州球墨铸铁棒,汕尾球墨铸铁棒,河源球墨铸铁棒,阳江球墨铸铁棒,清远球墨铸铁棒,东莞球墨铸铁棒,中山球墨铸铁棒,潮州球墨铸铁棒,揭阳球墨铸铁棒,云浮球墨铸铁棒,灰铸铁型材。15元左右 其他物品 信息15元14元15元12元14元14元14元14元15元13元12.00元12.00元12元12元12元14元15元14元15元14元该用户其他信息2月4日&东坑 - 东莞市东坑第一工业区35元2月4日&东坑 - 东莞市东坑第一工业区35元2月4日&东坑 - 东莞市东坑第一工业区35元
反馈建议描述:请填写描述手机号:请填写手机号请填写手机号qt-qml移动开发之在ios上开发和部署app流程简介 | qml | 稀泥蟹
& qt-qml移动开发之在ios上开发和部署app流程简介
qt-qml移动开发之在ios上开发和部署app流程简介
qt5.3已经全面支持移动开发,除了mac,windows,linux,还支持ios,android,wp,meego等移动平台,本教程是作者根据自己的经验,从头讲怎么样在ios上发布自己的app,由于目前国内相关文章还比较少,可能文章里有所疏漏,或者并非最优方法。
软件准备:qt5.3 , xcode 5.1.1
编译环境: Mac os
Qt5.3下载地址选择对应的Mac ox版本,支持iOS和android的版本,安装过程省略
Xcode在app store里直接下载
所有环境准备好后:
第一步:打开Qt creator,创建一个quick项目,如下:
然后输入项目名称和存盘位置,这里需要选择要部署的环境。
可以在这里选择,或者后面在项目里在重新选择部署也OK
开始编辑工程
第二步:在Qt creator中写好逻辑。
先在Mac上将逻辑调试完毕后,我这里用一个小游戏 “别踩白块儿”做为例子,工程代码如下:
UI逻辑主要在qml中实现,一些业务逻辑在C++代码中处理,这里业务逻辑也很简单,甚至可以不用在C++中处理,但是为了将整个流程走通,C++和qml通信流程,相互调用等。具体方法可以查看:
这里在C++中使用多线程的方法,来播放游戏音效,这部分的处理逻辑在PlayThread和PlayWork类中。
第三步:MAC下调试运行。
所有代码完成后,选择编译运行环境,然后运行mac版本结果如下图
第四步:在Xcode中编译qt代码
要在Xcode中编译QT代码,首先生成xcode的工程文件,qmake可以帮我们完成这项工作,在qt的安装目录下,找到如下目录下的qmake
/Users/seanyxie/qt5.3/5.3/ios/bin/qmake
然后切换到qt源码目录,在终端中执行改命令,就可以生成xcode工程文件,如下图:
然后打开xcode,打开改工程代码,结果如下图:
首先在Xcode中使用ios模拟器来运行改程序,如下图:
下面的步骤,可以用来设置app启动画面和图标。
首先在xcode中选择,添加文件到工程,分别用来做启动换面和图标,apple对这两个文件的格式有特殊要求,具体可以百度再查,很多文章讲的很清楚。
如下图设置
然后再次启动,就可以看到启动画面了
OK,到目前我们已经可以在ios模拟器上运行qt程序,下面就要移植真机调试了
第五步:移植iPhone真机调试。
再移植之前,需要有apple 开发者账号,这个需要在 上申请,688RMB一年。申请流程往上也有很详细的流程,需要使用visa支付,申请流程还可以随时致电苹果,她们的服务都很不错。 此处省略
假如已经有了开发者账号,然后就准备去创建调试流程了,这个过程还是比较麻烦的,尤其是对第一次做苹果开发的朋友,如下图,需要四个步骤:
Certificates 意思是让你的mac机器有权限去使用你的开发者账号去调试程序
Identifiers 需要根据不同的项目,创建不同的id,每个Identifiers有个对应buddle id,后面需要设置到xcode里面,和对应的程序buddle id设置一直才可以
Devices 用来添加目标真机,就是允许再哪些apple 设备上调试运行你的程序
Provisioning Profiles 是生成的profile证书,下载后导入到apple移动设备中,Xcode 会将连接到mac的移动设备里的证书读取出来,决定Xcode是否有权限对改机器调试。
好吧,这个确实很麻烦。。
然后设置XCODE,上面讲的,需要设置项目的buddle id ,还有另外一项,如下图
然后连接iphone到mac上,就可以调试运行了
同时可以再xcode的输出窗口,查看你使用qdebug() 或者console.log输出的日志
真机效果图:
源码已经共享 sourceforge &
点击下面的广告,感谢对本博客的支持。
Posted on 04月10日
Posted on 12月12日
Posted on 03月01日
Posted on 08月07日
半夜睡不着,爬起床来走到客厅抽支烟,发现一只蟑螂,于是跟它聊了很长时间,把我对人生的看法,对社会有些现象的不爽,生活的压力,调试遇到的bug,压榨似的发泄给它听,烟抽完了,于是我狠狠一脚踩死了它,没办法,它知道的太多了,压力会大。
文章总数:241篇
评论总数:38条
页面总数:0 个
分类总数:32个
标签总数:467个
运行天数:16657 天7559人阅读

用Qt做过开发的朋友,不知道是否曾为下面这些问题疑惑过:
我们知道Qt是基于C++的,Qt写的代码最终还是要由C++编译器来编译,但是我们的Qt代码中有很多C++里没有的关键字,比如slots\signals\Q_OBJECT等,为什么C++编译器会放过他们呢?
Qt的槽函数跟普通的成员函数有何区别?一个信号发出后,与之关联的槽函数是什么时候由谁来调用的?
Qt的信号定义跟函数定义有相同的形式,那信号跟普通函数有何区别?一个信号被emit时我们的程序到底在干什么?
信号和槽的连接是怎么建立的?又是如何断开的?
本篇博文里对这些问题作了详尽的解释,初学Qt或者用了很长时间Qt却很少思考过这些问题的朋友,可以在下面的段落中找到答案。
下文出自- original:
译:NewThinker_Jiwey NewThinker_wei @CSDN
【译】Qt的信号-槽机制是如何工作的
(译注:如果阅读过程中有感觉疑惑的地方,可以参考一下本文的原文-译文对照版:)

很多人都知道Qt的信号和槽机制,但它究竟是如何工作的呢?在本篇博文中,我们会探索QObject&和 QMetaObject 内部的一些具体实现,揭开信号-槽的神秘面纱。
在本篇博文中,我会贴出部分Qt5的源码,有时候会根据需要改变一下格式并做一些简化。
首先,我们看一个,借此回顾一下信号和槽的使用方法。
头文件是这样的:
***********************************************
&&& int m_value;
&&& int ()const {returnm_value; }
&&& void (intvalue);
&&& void (intnewValue);
***********************************************
在源文件的某个地方,可以找到setValue()函数的实现:
***********************************************
void::setValue(intvalue)
&&&if (value !=){
=value; (value);
***********************************************
然后开发者可以像下面这样使用Counter的对象:
***********************************************
& ::(&a,(valueChanged(int)),
&&&&&&&&&&&&&&&&&& &b, (setValue(int)));
& a.(12);&//
a.value() == 12, b.value() == 12
***********************************************
这是从1992年Qt最初阶段开始就沿用下来而几乎没有变过的原始语法。
虽然基本的API并没有怎么变过,但它的实现方式却变了几次。很多新特性被添加了进来,底层的实现也发生了很多变化。不过这里面并没有什么神奇的难以理解的东西,本篇博文会向你展示这究竟是如何工作的,
MOC,元对象编译器
Qt的信号/槽和属性系统都基于其能在运行时刻对对象进行实时考察的功能。实时考察意味着即使在运行过程中也可以列出一个对象有哪些方法(成员函数)和属性,以及关于它们的各种信息(比如参数类型)。如果没有实时考察这个功能,QtScript&和
QML 就基本不可能实现了。
C++本身不提供对实时考察的支持,所以Qt就推出了一个工具来提供这个支持。这个工具就是MOC。注意,它是一个代码生成器,而不是很多人说的“预编译器”。
MOC会解析头文件并为每一个含有Q_OBJECT宏的头文件生成一个对应的C++文件(这个文件会跟工程中的其他代码一块参与编译)。这个生成的C++文件包含了实时考察功能所需的全部信息(文件一般被命名为moc_HeaderName。cpp)。
因为这个额外的代码生成器,Qt有时对语言会有很严格的要求。 这里我就让这篇来解释这个严格的要求。代码生成器没有什么错误,MOC起到了很大的作用。
几个神奇的宏
你能看出这几个关键字并不是标准C++的关键字吗?signals, slots, Q_OBJECT, emit, SIGNAL, SLOT. 这些都是Qt对C++的扩展。这几个关键字其实都是很简单的宏定义而已,在
头文件中可以找到他们的定义。
#define signals public
#define slots /* nothing */
没错,信号和槽都是很简单的功能:编译器会将他们与其他任何宏一样处理。不过这些宏还有一个特殊的作用:MOC会发现他们。
Signals在Qt4之前都是protected类型的,他们在Qt5中变为了public,这样就可以使用一些了。
#define Q_OBJECT \
static const QMetaObject staticMetaO \
virtual const QMetaObject *metaObject() \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
QT_TR_FUNCTIONS /* translations helper */ \
private: \
Q_DECL_HIDDEN static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
Q_OBJECT defines a bunch of functions and a static QMetaObject Those functions are implemented in the file generated by MOC.
#define emit /* nothing */
emit是个空的宏定义,而且MOC也不会对它进行解析。也就是,emit完全是可有可无的,他没有任何意义(除了对开发者有提示作用)。
Q_CORE_EXPORT const char *qFlagLocation(const char *method);
#ifndef QT_NO_DEBUG
# define QLOCATION &\0& __FILE__ &:& QTOSTRING(__LINE__)
# define SLOT(a)
qFlagLocation(&1&#a QLOCATION)
# define SIGNAL(a)
qFlagLocation(&2&#a QLOCATION)
# define SLOT(a)
# define SIGNAL(a)
(译注:对于#define的一些高级用法,参见我整理的一片文章:)
上面这些宏,会利用预编译器将一些参数转化成字符串,并且在前面添加上编码。
在调试模式中,如果singnal的连接出现问题,我们提示警告信息的时候还会注明对应的文件位置。这是在Qt4.5之后以兼容方式添加进来的功能。为了知道代码对应的行信息,我们可以用qFlagLocation ,它会将对应代码的地址信息注册到一个有两个入口的表里。
MOC生成的代码
我们现在就来看看Qt5的moc生成的部分代码。
The QMetaObject
***********************************************
::staticMetaObject = {
&&& { &::,qt_meta_stringdata_Counter.data,
&&&&& ,&qt_static_metacall,0,0}
*Counter::()const
&&& return ::
: &staticMetaObject;
***********************************************&
我们在这里可以看到Counter::metaObject()和&Counter::staticMetaObject 的实现。他们都是在Q_OBJECT宏中被声明的。
QObject::d_ptr-&metaObject 只被用于动态元对象(QML对象),随意通常虚函数metaObject()
只是返回类的staticMetaObject 。
staticMetaObject被创建为只读数据。
文件中QMetaObject的定义如下:
&struct QMetaObject
/* ... Skiped all the public functions ... */
enum Call { InvokeMetaMethod, ReadProperty, WriteProperty, /*...*/ };
struct { // private data
const QMetaObject *
const QByteArrayData *
const uint *
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
StaticMetacallFunction static_
const QMetaObject **relatedMetaO
void * //reserved for future use
代码中用的d是为了表明那些数据都本应为私有的。然而他们并没有成为私有的是为了保持它为POD和允许静态初始化。(译注:在C++中,我们把传统的C风格的struct叫做POD(Plain Old Data),字面意思古老的普通的结构体)。
这里会用父类对象的元对象(此处就是指QObject::staticMetaObject
)来初始化QMetaObject的superdata,而它的stringdata 和&data 这两个成员则会用之后要讲到的数据初始化。static_metacall是一个被初始化为 Counter::qt_static_metacall的函数指针。
实时考察功能用到的数据表
首先,我们来分析 QMetaObject的这个整型数组:
***********************************************
static const
// content:
&&&&&& 7,&&&&&& // revision
&&&&&& 0,&&&&&& // classname
&&&&&& 0,&&& 0, // classinfo
&&&&&& 2,&& 14, // methods
&&&&&& 0,&&& 0, // properties
&&&&&& 0,&&& 0, // enums/sets
&&&&&& 0,&&& 0, // constructors
&&&&&& 0,&&&&&& // flags
&&&&&& 1,&&&&&& // signalCount
// signals: name, argc, parameters, tag, flags
&&&&&& 1,&&& 1,&& 24,&&& 2, 0x05,
// slots: name, argc, parameters, tag, flags
&&&&&& 4,&&& 1,&& 27,&&& 2, 0x0a,
// signals: parameters
&&& ::,::,&&&3,
// slots: parameters
&&& ::,::,&&&5,
&&&&&& 0&&&&&&& // eod
***********************************************
开头的13个整型数组成了结构体的头信息。对于有两列的那些数据,第一列表示某一类项目的个数,第二列表示这一类项目的描述信息开始于这个数组中的哪个位置(索引值)。
这里,我们的Counter类有两个方法,并且关于方法的描述信息开始于第14个int数据。
每个方法的描述信息由5个int型数据组成。第一个整型数代表方法名,它的值是该方法名(译注:方法名就是个字符串)在字符串表中的索引位置(之后会介绍字符串表)。第二个整数表示该方法所需参数的个数,后面紧跟的第三个数就是关于参数的描述(译注:它表示与参数相关的描述信息开始于本数组中的哪个位置,也是个索引)。我们现在先忽略掉tag和flags。对于每个函数,Moc还会保存它的返回类型、每个参数的类型、以及参数的名称。
***********************************************
stringdata[47];
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
offsetof(,
stringdata) + ofs \
- idx * sizeof() \
static const qt_meta_stringdata_Counter = {
QT_MOC_LITERAL(0,0,7),
QT_MOC_LITERAL(1,8,12),
QT_MOC_LITERAL(2,21,0),
QT_MOC_LITERAL(3,22,8),
QT_MOC_LITERAL(4,31,8),
QT_MOC_LITERAL(5,40,5)
&&& &Counter\0valueChanged\0\0newValue\0setValue\0&
&&& &value\0&
#undef QT_MOC_LITERAL
***********************************************
这主要就是一个QByteArray的静态数组。QT_MOC_LITERAL 这个宏可以创建一个静态的QByteArray
,其数据就是参考的在它下面的对应索引处的字符串。
MOC还实现了信号signals(译注:根据前面的介绍我们已经知道signals其实就是publib,因此所有被定义的信号其实都必须有具体的函数定义,这样才能C++编译器编译,而我们在开发中并不曾写过信号的定义,这是因为这些都由MOC来完成)。所有的信号都是很简单的函数而已,他们只是为参数创建一个指针数组并传递给QMetaObject::activate函数。指针数组的第一个元素是属于返回值的。在我们的例子中将它设置为了0,这是因为我们的返回类型是void。
传递给activate 函数的第3个参数是信号的索引(在这里,该索引为0)。
***********************************************
// SIGNAL 0
void ::(int_t1)
&&& void *_a[] = { 0,const_cast&void*&(reinterpret_cast&const void*&(&_t1)) };
&&& ::(this,
&staticMetaObject,0,_a);
***********************************************
通过一个槽的索引来调用一个槽函数也是行得通的,这要借助qt_static_metacall这个函数:
***********************************************
void ::qt_static_metacall(
*_o, ::_c,int_id,void
&&& if (_c == ::)
&&&&&&& Counter *_t =static_cast&
&&&&&&& switch (_id) {
&&&&&&& case 0:
_t-&((*reinterpret_cast&int(*)&(_a[1])));break;
&&&&&&& case 1:
_t-&setValue((*reinterpret_cast&int(*)&(_a[1])));break;
&&&&&&& default: ;
***********************************************
函数中的指针数组与在上面介绍signal时的那个函数中的指针数组格式相同。只不过这里没有用到_a[0],因为这里所有的函数都是返回void。
关于索引需要注意的地方
在每个 QMetaObject中,对象的槽、信号和其他一些被涉及到的方法都被分配了一个索引,这些索引值从0开始。他们是按照“先信号、再槽、最后其他方法”的顺序排列。这样得到的索引被称为相对索引(relative index),相对索引与该类的父类(就是基类)和祖宗类中的方法数量无关。
但是通常,我们不是想知道相对索引,而是想知道在包含了从父类和祖宗类中继承来的所有方法后的绝对索引。为了得到这个索引,我们只需要在相关索引(relative index)上加上一个偏移量就可以得到绝对索引absolute index了。这个绝对索引就是在Qt的API中使用的, 像QMetaObject::indexOf{Signal,Slot,Method}这样的函数返回的就是绝对索引。
另外,在信号槽的连接机制中还要用到一个关于信号的向量索引。这样的索引表中如果把槽也包含进来的话槽会造成向量的浪费,而一般槽的数量又要比信号多。所以从Qt4.6开始,Qt内部又多出了一个专门的信号索引signal index&,它是一个只包含了信号的索引表。
在用Qt开发的时候,我们只需要关心绝对索引就行。不过在浏览Qt源码的时候,要留意这三种索引的不同。
连接是如何进行的
在进行信号和槽的连接时Qt做的一件事就是找出要连接的信号和槽的索引。Qt会在meta object的字符串表中查找对应的索引。
然后会创建一个QObjectPrivate::Connection对象并添加到内部的链表中。
一个&connection 中需要存储哪些数据呢?我们需要一种能根据信号索引signal index快速访问到对应的connection的方法。因为可能会同时有不止一个槽连接到同一个信号上,所以每一个信号都要有一个槽列表;每个connection必须包含接收对象的指针以及被连接的槽的索引;我们还想让一个connection能在与之对应的接收者被销毁时自动取消连接,所以每个接收者对象也需要知道谁与他建立了连接这样才能在析构时将connection清理掉。
下面是定义在
中的QObjectPrivate::Connection :
(译注:只认识QObject不认识QObjectPrivate?看这里:)
***********************************************
struct ::Connection
*receiver;
&&& union {
callFunction;
&&&&&&& QtPrivate::
&&& // The next pointer for the singly-linked ConnectionList
&&& Connection *nextConnectionList;
&&& //senders linked list
&&& Connection *next;
&&& Connection **prev;
&&& &const int&
argumentTypes;
method_offset;
method_relative;
signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
isSlotObject : 1;
ownArgumentTypes : 1;
Connection() :
nextConnectionList(0),
ownArgumentTypes(true) {
&&&&&&& //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
~Connection();
method() const { return
method_offset +
method_relative; }
ref() { ref_.();
&&&&&&& if (!ref_.())
&&&&&&&&&&& (!receiver);
&&&&&&&&&&& delete this;
***********************************************
每一个对象有一个connection vector:每一个信号有一个 QObjectPrivate::Connection的链表,这个vector就是与这些链表相关联的。
每一个对象还有一个反向链表,它包含了这个对象被连接到的所有的 connection,这样可以实现连接的自动清除。而且这个反向链表是一个双重链表。
使用链表是因为它们可以快速地添加和移除对象,它们靠保存在QObjectPrivate::Connection中的next/previous前后节点的指针来实现这些操作。
注意senderList的prev指针是一个“指针的指针”。这是因为我们不是真的要指向前一个节点,而是要指向一个指向前节点的指针。这个“指针的指针”只有在销毁连接时才用到,而且不要用它重复往回迭代。这样设计可以不用对链表的首结点做特殊处理。
(译注:对连接的建立如果还有疑惑,请参考:)
信号的发送
我们已经知道当调用一个信号的时候,最终调用的是MOC生成的代码中的QMetaObject::activate函数。
这里是中这个函数的实现代码,这里贴出来的只是一个注解版本。
***********************************************
void ::activate(
*sender, const
*m,intlocal_signal_index,
&&&&&&&&&&&&&&&&&&&&&&&&&& void **argv)
&&& (sender,::(m),local_signal_index,argv);
&&& /* We just forward to the next function here. We pass the signal offset of
* the meta object rather than the QMetaObject itself
* It is split into two functions because QML internals will call the later. */
void ::activate(
*sender, intsignalOffset,intlocal_signal_index,void
&&& int signal_index =signalOffset +local_signal_index;
&&& /* The first thing we do is quickly check a bit-mask of 64 bits. If it is 0,
* we are sure there is nothing connected to this signal, and we can return
* quickly, which means emitting a signal connected to no slot is extremely
* fast. */
&&& if (!sender-&()-&(signal_index))
&&&&&&& return; // nothing connected to these signals, and no spy
&&& ......
&&& ......
&&& /*译注:获得当前正在运行的线程的ID*/
currentThreadId = ::();
&&& /* ... Skipped some debugging and QML hooks, and some sanity check ... */
&&&/*跳过一些调试代码和完整性检测*/
&&& /* We lock a mutex because all operations in the connectionLists are thread safe */
&&&&/*这里用一个互斥量锁住,因为在ConnectionList里的所有操作都应是线程安全的*/
locker((sender));
&&& /* Get the ConnectionList for this signal. I simplified a bit here. The real code
* also refcount the list and do sanity checks */
&&&/*得到这个信号的ConnectionList。这里我做了一些简化。原来的代码还有完整性检测等*/
*connectionLists =sender-&()-&;
&&& const ::
&&&&&&& &connectionLists-&(signal_index);
&&& if (!c) continue;
&&& // We need to check against last here to ensure that signals added
// during the signal emission are not emitted in this emission.
&&& /* Now iterates, for each slot */
&&&&&&& if (!c-&)
&&&&&&&&&&& continue;
receiver = c-&;
&&&&&&& /*译注:比较当前正在运行的线程的ID与receiver所属的线程的ID是否相同*/
&&&&&&& const bool
receiverInSameThread = ::()
== receiver-&()-&-&;
&&&&&&& // determine if this connection should be sent immediately or
// put into the event queue
&&&&&&&//译注:注意下面这一段,从这里可以看出对于跨线程的连接,信号发出
&&&&&&&//后槽函数不会立即在当前线程中执行。其执行要等到槽函数所在的线程被
&&&&&&&//激活后。有时间了再研究一下queued_activate这个函数。
&&&&&&& if ((c-&
&& !receiverInSameThread)
&&&&&&&&&&& || (c-&
&&&&&&&&&&& /* Will basically copy the argument and post an event */
&&&&&&&&&&& (sender,signal_index,c,argv);
&&&&&&&&&&& continue;
&&&&&&& } else if (c-&
&&&&&&&&&&& /* ... Skipped ... */
&&&&&&&&&&& continue;
&&&&&&& /* Helper struct that sets the sender() (and reset it backs when it
* goes out of scope */
&&&&&&& if (receiverInSameThread)
&&&&&&&&&&& sw.(receiver,sender,signal_index);
&&&&&&& const ::callFunction
&&&&&&& const int
method_relative = c-&;
&&&&&&& if (c-&)
&&&&&&&&&&& /* ... Skipped.... Qt5-style connection to function pointer */
&&&&&&& } else if (callFunction &&c-&
&=receiver-&()-&())
&&&&&&&&&&& /* If we have a callFunction (a pointer to the qt_static_metacall
* generated by moc) we will call it. We also need to check the
* saved metodOffset is still valid (we could be called from the
* destructor) */
&&&&&&&&&&& locker.();//
We must not keep the lock while calling use code
&&&&&&&&&&& callFunction(receiver,::,method_relative,argv);
&&&&&&&&&&& locker.();
&&&&&&& } else {
&&&&&&&&&&& /* Fallback for dynamic objects */
&&&&&&&&&&& const int method =method_relative +c-&;
&&&&&&&&&&& locker.();
&&&&&&&&&&& (receiver,::,method,argv);
&&&&&&&&&&& locker.();
&&&&&&& // Check if the object was not deleted by the slot
&&&&&&& if (connectionLists-&)break;
&&& } while (c !=
last && (c =
c-&) !=0);
***********************************************




版权声明:本文为博主原创文章,欢迎转载(文中有强调禁止转载的例外),但请说明出处。如用于培训等商业用途请先与博主联系并支付部分授权费
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

我要回帖

更多关于 qt400是什么材料 的文章

 

随机推荐