??xml version="1.0" encoding="utf-8" standalone="yes"?>国产亚洲精久久久久久无码AV,一本久久综合亚洲鲁鲁五月天,欧美激情一区二区久久久http://www.shnenglu.com/Walker/category/16501.html先学会{文章Q在仔细L章,最后自己写点东?.......zh-cnThu, 26 May 2011 18:51:06 GMTThu, 26 May 2011 18:51:06 GMT60一些开源项目网址http://www.shnenglu.com/Walker/articles/145927.html漫步者?amp;…?K?/dc:creator>漫步者?amp;…?K?/author>Sun, 08 May 2011 01:35:00 GMThttp://www.shnenglu.com/Walker/articles/145927.htmlhttp://www.shnenglu.com/Walker/comments/145927.htmlhttp://www.shnenglu.com/Walker/articles/145927.html#Feedback0http://www.shnenglu.com/Walker/comments/commentRss/145927.htmlhttp://www.shnenglu.com/Walker/services/trackbacks/145927.htmlhttp://code.ijinshan.com/
http://search.csdn.net/
CSDN搜烦QCSDNq是有非常多的编E资源的Q用它的搜烦能搜Z东ѝ代码类别也比较全面?/p>

http://snippets.org/
单实用的代码攉|站Q强力推荐。比如你要找个DES加密Q要找个数据压羃Q找个INI文g操作的C代码{,均能手到擒来?/p>

http://www.codase.com/index.html
它是一个代码搜索引擎,特别是搜索c/c++的开源代码,可以通过函数名、类名等搜烦Q很酷噢

http://sourceforge.net
有名的开源代码库Q只要能惛_的功能,上面都有对应的源?/p>

http://www.tigris.org/
和上面的sourceforge一L开源代码库Q不qsourceforge用CVSQ而这个用SVN版本理?/p>

http://cosoft.org.cn/
中文版的开源代码库Q好像是由sourceforge直接译q来的。其同步性等未考察?/p>

http://codeguru.com
http://codeproject.com
q两个站Ҏ较类|放一起吧。以WINDOWS下的Visual studio~程代码、教Eؓ丅R在以前可是使用MFC的h的必l之地?/p>

http://www.experts-exchange.com/Programming/
q是专家问答的网站,在编E方面能够解决不问题?/p>

http://www.koders.com/
也是一个代码搜索引擎,与codase差不多,q且能查找指定许可的代码

http://groups.google.com/
找代码,决不能忘记google的groups。一定要d。国内的兄弟可能讉K时不E_Q就用代理吧。如果你用firefoxQ可以用我开发的xyzproxy切换代理Q很方便?)

http://www.thefreecountry.com/sourcecode/index.shtml
q也是个源码码网站。这个网站的资源q是很多的?/p>

http://www.vckbase.com/
VC知识库,国内比较好的VC资源站 

http://www.programmersheaven.com/
开发者天堂? 有一些教E好像不错?/p>

http://www.cprogramming.com/
攉C/C++~程斚w资源的网?/p>

http://csourcesearch.net
又一个代码搜索网站,大家试试Q?/p>

http://www.netlib.org/
源代库烦引,有很多数学方面的库,很好用。要扑ֺQ以此网站着手较?/p>

50个c/c++源代码网?br>C/C++是最主要的编E语a。这里列Z50名优U|站和网|单,q些|站提供c/c++源代码。这份清单提供了源代码的链接以及它们的小说明。我已尽力包括最佳的C/C++源代码的|站。这不是一个完整的清单Q您有徏议可以联pLQ我欢q您的徏议,以进一步加斚w的清单?/p>

1?a >http://snippets.dzone.com/tag/c/ --C千计的有用的C语言源代码片D?br>2?a >http://www.hotscripts.com/category/c-cpp/scripts-programs/ Hotscripts --提供C百计的C和C++脚本和程序。所有程序都分ؓ不同的类别?br>3?a >http://www.planetsourcecode.com/vb/default.asp?lngWId=3 --过万行C和C++免费的源代码
4?a >http://freshmeat.net/browse/164/ --过9000个C~写的项目?br>5?a >http://www.daniweb.com/code/c.html --DANIWEB提供的实用代码段?br>6?a >http://www.programmersheaven.com/tags/C/ --programmersheaven.com上的C~程资源?br>7?a >http://www.ddj.com/code/ddj.html --Dr. Dobb’s Journal的源代码?br>8?a >http://www.cprogramming.com/cgi-bin/source/source.cgi --C和C + +~程资源?br>9?a >http://www.codecogs.com/ --CodeCogs是一协作的开放源码库QC/C++的数值方面的lg?br>10、[URL=http://www.google.com /codesearch?q=programming++lang:c&cs_r=lang:c ]http://www.google.com/codesearch?q=programming++lang:c&cs_r=lang:c [/URL] --h代码的C源代码?br>11?a >http://www.codepedia.com/1/C --CodePedia是一个开攄关于pȝ~程和其他与电脑有关的议题?br>12?a >http://www.cis.temple.edu/~ingargio/cis71/code/ --为学生提供的一个简单的C语言E序的列表?br>13?a >http://www.codeproject.com/?cat=2 --codeproject提供的C/C++资源代码目?br>14?a >http://www.thefreecountry.com/sourcecode/cpp.shtml --以下是一些C和C++库的DLLQVCLsQ源代码Q元Ӟ模块Q应用程序框ӞcdQ源代码片段{,你可以在您的目中用而不需要支付费用和版税?br>15、[URL=http://people.sc.fsu.edu /~burkardt/cpp_src/cpp_src.html ]http://people.sc.fsu.edu/~burkardt/cpp_src/cpp_src.html [/URL] --q是一个全面的关于C++?45个源代码清单?br>16?a >http://www.cplusplus.com/src/ --C++写的通用控制台程序和WindowsE序代码清单?br>17?a >http://users.cs.fiu.edu/~weiss/dsaa_c++/code/ --C++语言数据l构与算法分析(W二版)的源代码?br>18?a >http://c.snippets.org/ --C源代码片Dc?br>19?a >http://www.bbdsoft.com/downloads.html --C++源代码?br>20?a >http://www.moshier.net/ 天文学和数DY件源代码
21?a >http://cplus.about.com/od/cgames/C_Games_with_Source_Code.htm --游戏有关的C++源代码?br>22、[URL=http://cliodhna.cop.uop.edu /~hetrick/c-sources.html ]http://cliodhna.cop.uop.edu/~hetrick/c-sources.html [/URL] --免费的C/C++数D源代码?br>23?a >http://www.mathtools.net/C_C__/Utilities/index.html --C/C++工具?br>24?a >http://www.programmerworld.net/resources/c_library.htm --免费C++源代码和其它有用的工兗?br>25?a >http://www.cmcrossroads.com/bradapp/links/cplusplus-links.html --布拉德阿普尔的C++链接-资源Q项目,图书馆,教学和编码?br>26?a >http://www.robertnz.net/cpp_site.html --q是一个收集了数C/C++|站链接列表的网c?br>27?a >http://www.josuttis.com/libbook/examples.html --在这里,你可以看到ƈ下蝲所有的本书的C++标准库例??br>28?a href="ftp://66.77.27.238/sourcecode/cuj/">ftp://66.77.27.238/sourcecode/cuj/ --C/C++用户杂志
29?a href="ftp://66.77.27.238/sourcecode/wd/">ftp://66.77.27.238/sourcecode/wd/ --Windows开发者网l?br>30?a >http://www.einet.net/directory/65892/Developers.htm --CE序
31?a >http://www.daniweb.com/code/cplusplus.html --实用代码Dc?br>32?a >http://snippets.dzone.com/tag/c --C++源代?br>33?a >http://www.programmersheaven.com/tags/C --C++~程资源Qprogrammersheaven.com
34?a >http://www.google.com/codesearch?hl=en&lr=&q=programming --h代码搜烦-C++~程语言
35?a >http://www.codepedia.com/1/Cpp --CodePedia是一个开攄关于pȝ~程和其他与电脑有关的议题的|站?br>36?a >http://www.codebeach.com/index.asp?TabID=1&CategoryID=3 --C++源代码,Codebeach提供
37?a >http://freshmeat.net/browse/165/ --5000目写的C++~程语言
38?a >http://cplus.about.com/od/codelibrary/Code_Library_for_C_C_and_C.htm --代码库C、C + +和CQ?br>39?a >http://www.c.happycodings.com/ --Visual Basic、PHP、ASP技术、C、C++大全?br>40?a >http://www.blueparrots.com/ --Borland C游戏Q图像和声音源代码范例?br>41?a >http://www.java2s.com/Code/Cpp/CatalogCpp.htm --C++源代码?br>42?a >http://www.yeohhs.com/modules/mydownloads/ --C与C++电子书和源代码示例?br>43?a >http://www.brpreiss.com/books/opus4/programs/index.html C++的数学方E和公式源代码?br>44、[URL=http://users.cs.fiu.edu][/URL]http://users.cs.fiu.edu/ C++?br>45、[URL=http://www.josuttis.com/libbook/examples.html][/URL]http://www.josuttis.com/libbook/examples.html --C++标准?教程和参考资料?br>46?a >http://emr.cs.uiuc.edu/~reingold/calendars.shtml Edward M. Reingold's Calendar Book, Papers, and Code?br>47?a >http://cpp.snippets.org/ --c++源代码档案?br>48?a >http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/ --用C和C++的解决科学问题?br>49?a >http://c.ittoolbox.com/topics/core-c/ --C/C++的IT工具框?br>50?a >http://www.le.ac.uk/cc/tutorials/c/ccccdbas.html --本文件中包含有大量的CCZE序?/p>

 

本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/fisher_jiang/archive/2010/05/06/5561556.aspx



]]>
信号(signals)和槽(slots) _讲http://www.shnenglu.com/Walker/articles/145870.html漫步者?amp;…?K?/dc:creator>漫步者?amp;…?K?/author>Sat, 07 May 2011 00:47:00 GMThttp://www.shnenglu.com/Walker/articles/145870.htmlhttp://www.shnenglu.com/Walker/comments/145870.htmlhttp://www.shnenglu.com/Walker/articles/145870.html#Feedback0http://www.shnenglu.com/Walker/comments/commentRss/145870.htmlhttp://www.shnenglu.com/Walker/services/trackbacks/145870.html信号(signals)和槽(slots) _讲
2010-11-01 22:54

信号(signals)和槽(slots)

信号和信h被用于对?object)之间的通信。信号和槽机制是QT的重要特征ƈ且也许是QT与其他框架最不相同的部分?/p>

前言

在GUIE序设计中,通常我们希望当对一个窗口部?widget)q行改变时能告知另一个对此改变感兴趣的窗口部件。更一般的Q我们希望Q何一cȝ对象(object)都能和其他对象进行通信。例如,如果用户单击一个关闭按钮,我们可能希望窗口的 close() 函数被调用?/p>

早期的工具包用回?backcalls)的方式实C面所提到的对象间的通信。回调是指一个函数的指针Q因此如果你希望一个处理函数通知你一些事情,你可以传递另一个函敎ͼ回调函数Q指针给q个处理函数。这个处理函数就会在适当的时候调用回调函数。回调有两个重要的缺P首先Q它们不是类型安全的。我们无法确定处理函数是用正的参数调用q个回调函数。其ơ,回调与处理函数紧密的联系在一起以致处理函数必ȝ道调用哪个回调?/p>

消息和槽

在QT中,我们使用一U可替代回调的技术:信号和槽机制。当一个特别的事g产生时则发出一个信受QT的窗口部件有很多已经预定义好的信P我们也可以通过l承Q给H口部g的子cL加他们自׃受槽是一个可以被调用处理特定信号的函数。QT的窗口部件有很多预定义好的槽Q但是通常的做法是l子cȝ口部件添加自q信号Q这样就可以操纵自己加入的信号了?/p>

  




上面q个图一定要好好理解Q每个signal和Slot都是一个Object的属性,不同Object的signal可以对应不用的Object的Slot?/strong>


信号和槽机制是类型安全的Q一个信L{֐必须和该信号接受槽的{֐相匹配。(事实上以一个槽的签名可以比他可接受的信L{֐,因ؓ它可以忽略一些签名)。因此签名是一致的Q编译器可以帮助我们检类型匹配。信号和槽是松耦合的:一个类不知道也不关心哪个槽接受了它所发出的信受QT的信号和槽机制确保他们自生的正确q接Q槽会在正确的时间用信号参数而被调用。信号和槽可以用Q何数量、Q何类型的参数。他们完全是cd安全的?/p>

所有承至QObject或是其子c(?QWidgetQ的c都可包含信号和槽。当对象改变它们自n状态的时候,信号被发送,从某U意义上Ԍ它们也许对外面的世界感兴。这是所有对象在通讯时所做的一切。它不知道也不关心有没有其他的东西接受它发出的信受这是真正的消息封装,q且保对象可用作一个Y件组件?/p>

槽被用于接收信号Q但是他们也是正常的成员函数。正如一个对象不知道是否有东西接受了他信P一个槽也不知道它是否被某个信号q接。这q保QT能创建真正独立的lg?/p>

你可以将L个信可接到你想q接的信hQƈ且在需要时可将一个信可接到多个槽。将信号直接q接到另一个信号也是可能的Q这hZ时当W一个信可发出后会立即发出W二个)?/p>

M来看Q信号和槽构成了一个强有力的组件编E机制?/p>

单示?/p>

一个极的 C++ c?声明如下Q?/p>

class Counter
{
public:
Counter() {m_value = 0;}

int value() const {return m_value;}
void setValue(int Value);
private:
int m_value;
};


一个小型的 QObject 子类声明为:

#include <QObject>

class Counter : public QObject
{
Q_OBJECT

public:
Counter() {m_value = 0;}

int value() const {return m_value;}

public slots:
void setValue(int value);
signals:
void valueChanged(int newValue);

private:
int m_value;
};

QObject版本的类与前一个C++cL着相同的域Qƈ且提供公有函数接受这个域Q但是它q增加了对信号和?signals-slots)lg~程的支持。这个类可以通过valueChanged()发送信号告诉外部世界他的域发生了改?q且它有一个可以接受来自其他对象发ZL槽?/p>

所有包含信号和槽的c都必须在他们声明中的最开始提到Q_OBJECT。ƈ且他们必ȝ承至Q直接或间接QQObject?/p>

槽可以由应用E序的编写者来实现。这里是Counter::setVaule()的一个可能的实现Q?/p>

void Counter::setValue(int value)
{
if(value != m_value)
{
m_value = value;
emit valueChanged(value);
}
}

emit所在的q一行从对象发出valueChanged信号Qƈ使用新值做为参数?/p>

在下面的代码片段中,我们创徏两个Counter对象q且使用QObject::connect()函数第一个对象的valueChanged()信号q接到第二个对象的setValue()槽?/p>

Counter a, b;
QObject::connect (&a, SIGNAL(valueChanged(int)),
&b, SLOT(setValue(int)));
a.setValue(12);    // a.value() == 12, b.value() == 12
b.setValue(48);    // a.value() == 12, b.value() == 48

函数a.setValue(12)的调用导致信号valueChange(12)被发?对象b的setValue()槽接受该信号Q即函数setValue()被调用。然后b同样发出信号valueChange()Q但是由于没有槽q接到b到valueChange()信号Q所以该信号被忽略?/p>

注意Q只有当 value != m_value Ӟ函数 setValue() 才会讄新值ƈ发出信号。这样就避免了在循环q接的情况下Q比如b.valueChanged() 和a.setValue()q接在一P出现无休止的循环的情c?/p>

信号被发送给M你徏立了q接的槽Q如果重复连接,会发送两个信受L可以使用QObject::disconnect()函数断开一个连接?/p>

q个例子说明了对象之间可以不需要知道相互间的Q何信息而系协同工作。ؓ了实现这一目的Q只需要将对象通过函数QObject::connect()的调用相q接QconnectQ?或者利用uic的automatic connections的特性?/p>

~译q个CZ

C++预编译器会改变或去除关键字signals,slots,和emitQ这样就可以使用标准的C++~译器?/p>

在一个定义有信号和槽的类上运行mocQ这样就会生成一个可以和其它对象文g~译和连接成应用E序的C++源文件。如果用qmake工具Q将会在你的makefile文g里加入自动调用moc的规则?/p>

信号

当对象的内部状态发生改变,信号p发射Q在某些斚w对于对象代理或者所有者也许是很有的。只有定义了信号的对象或其子对象才能发射该信受?/p>

当一个信可发出Q被q接的槽通常会立刻运行,像执行一个普通的函数调用。当q一切发生时Q信号和槽机制是完全独立于Q何GUI事g循环之外的。槽会在emit域下定义的代码执行完后返回。当使用队列q接Qqueued connectionsQ时会有一些不同;q种情况下,关键字emit后的代码会l执行,而槽在此之后执行?/p>

如果几个槽被q接C个信P当信可发出后,槽会以Q意顺序一个接一个的执行?/p>

关于参数需要注意:我们的经验显C如果信号和槽不使用Ҏ的类型将会变得更具重用性。如果QScrollBar::valueChanged() 使用了一个特D的cdQ比如hypothetical QRangeControl::RangeQ它只能被q接到被设计成可以处理QRangeControl的槽。再没有象教E?q样单的例子?/p>

?br style="LINE-HEIGHT: normal">
当一个信可发出时连接他的槽被调用。槽是一个普通的C++函数q按普通方式调用;他的特点仅仅是可以被信号q接?/p>

׃槽只是普通的成员函数Q当调用时直接遵循C++规则。然而,对于槽,他们可以被Q何组仉过一个信?槽连接(signal-slot connectionQ调用,而不其讉K权限。也是_一个从L的类的实例发出的信号可导致一个不与此cȝ关的另一个类的实例的U有槽被调用?/p>

你还可以定义一个虚拟槽Q在实践中被发现也是非常有用的?/p>

׃增加来灵zL,与回调相比,信号和槽E微慢一些,管q对真实的应用程序来说是可以忽略掉的。通常Q发Zq接了某个槽的信P比直接调用那些非虚拟调用的接受器要慢十倍。这是定位连接对象所需的开销Q可以安全地重复所有地q接Q例如在发射期间查ƈ发接收器是否被破坏)q且可以按一般的方式安排M参数。当十个非虚函数调用听v来很多时Q实际上他比Mnew和delete操作的开销都少Q例如,当你执行一个字W串、矢量或列表操作Ӟ需要用到new和deleteQ而信号和槽的开销只是全部函数调用p的一部分?/p>

无论何时你用槽进行一个系l调用和间接的调用超q?0个以上的函数旉都是一L。在i586-500机器上,每秒钟你可以发送超q?,000,000个信L一个接受者,或者每U发?,200,000个信L两个接受者。相对于信号和槽机制的简z性和灉|性,他的旉开销是完全值得的,你的用户甚至察觉不出来?/p>

注意Q若其他的库变量定义ؓsignals和slots,可能D~译器在q接ZQT的应用程序时出错或警告。ؓ了解册个问题,请?undef预处理符受?/p>

元对象信?/p>

元对象编译器QmocQ解析一个C++文g中的cd明ƈ且生成初始化元对象的C++代码。元对象包括信号和槽的名字,和指向这些函数的指针?/p>

if (widget->inherits("QAbstractButton")) {
QAbstractButton *button = static_cast<QAbstractButton *>(widget);
button->toggle();
}

元对象信息的使用也可以是qobject_cast<T>(), 他和QObject::inherits() 怼Q但更不Ҏ出错?/p>

if (QAbstractButton *button = qobject_cast<QAbstractButton *>(widget))
button->toggle();

查看Meta-Objectpȝ可获取更多信息?/p>

一个实?/p>

q是一个注释过的简单的例子Q代码片断选自qlcdnumber.hQ?/p>

#ifndef LCDNUMBER_H
#define LCDNUMBER_H

#include <QFrame>

class LcdNumber : public QFrame
{
Q_OBJECT

LcdNumber通过QFrame和QWigetl承至QObjectQ它包含了大部分signal-slot知识。这是有点类g内置的QLCDNumber部g?/p>

Q_OBJECT宏由预处理器展开Q用来声明由moc实现的机个成员函敎ͼ如果你的~译器出现错误如?undefined reference to vtable for LcdNumber", 你可能忘了运行moc或者没有用q接命o包含moc输出?/p>

public:
LcdNumber(QWidget *parent = 0);

LcdNumberq不明显的与moc相关Q但是如果你l承了QWidegeQ那么可以几乎肯定在你的构造函C有父对象的变量,q且希望把它传给基类的构造函数?/p>

析构函数和一些成员函数在q里省略Qmoc会忽视成员函数?/p>

signals:
void overflow();

当LcdNumbe被要求显CZ个不可能的值时Q便发出信号?/p>

如果你没有留意溢出,或者你知道溢出不会出现Q你可以忽略overflow()信号Q比如不其q接CQ何槽?/p>

如果另一斚wQ当有数字溢出时你想调用两个不同的错误处理函敎ͼ可以这个信L单的q接C个不同的槽。QT调用两个函敎ͼ无序的)?/p>

public slots:
void display(int num);
void display(double num);
void display(const QString &str);
void setHexMode();
void setDecMode();
void setOctMode();
void setBinMode();
void setSmallDecimalPoint(bool point);
};

#endif

一个槽是一个接受函敎ͼ用于获得其他H口部g的信息变化。LcdNumber使用它,像上面的代码一P来设|显C的数字。因为display()是这个类和程序的其它的部分的一个接口,所以这个槽是公有的?/p>

几个例程把QScrollBar的valueChanged()信号q接到display()槽,所以LCD数字可以l箋昄滚动条的倹{?/p>

h意display()被重载了Q当一个信可接到槽时QT选择一个最适合的一个。而对于回调,你会发现五个不同的名字ƈ且自己来跟踪cd?/p>

一个不相干的成员函数在例子中被忽略?/p>

高信号和槽的?/p>

在当你需要信号发送者的信息ӞQT提供了一个函数QObject::sender()Q他q回指向一个信号发送对象的指针?/p>

当有几个信号被连接到同一槽上Qƈ且槽需要处理每个不同的信号Q可使用 QSignalMappercR?/p>

假设你用三个按钮来决定打开哪个文gQTax File", "Accounts File", or "Report File"?/p>

Z能打开真确的文Ӟ你需要分别将它们的信?QPushButton::clicked()q接?readFile()。然后用QSignalMapper ?setMapping()来映所?clicked()信号C?QSignalMapper对象?/p>

signalMapper = new QSignalMapper(this);
signalMapper->setMapping(taxFileButton, QString("taxfile.txt"));
signalMapper->setMapping(accountFileButton, QString("accountsfile.txt"));
signalMapper->setMapping(reportFileButton, QString("reportfile.txt"));

connect(taxFileButton, SIGNAL(clicked()),
signalMapper, SLOT (map()));
connect(accountFileButton, SIGNAL(clicked()),
signalMapper, SLOT (map()));
connect(reportFileButton, SIGNAL(clicked()),
signalMapper, SLOT (map()));

然后Q连接信?mapped()?readFile() Q根据被按下的按钮,可以打开不同的文件?/p>

connect(signalMapper, SIGNAL(mapped(const QString &)),
this, SLOT(readFile(const QString &)));

在QT中用第三方signals slots

在QT中用第三方signals slots是可能的。你甚至可以在同一cM使用两种机制。仅仅需要在你的qmake工程文g(.pro)中加入下面语句:

CONFIG += no_keywords

它告诉QT不要定义moc关键字signals,slots和emitQ因些名字可能将被用于第三方库,例如Boost。你只需单的用QT宏将他们替换?Q_SIGNALS, Q_SLOTSQ和 Q_EMITQ就可以l箋使用信号和槽了?/p>

Qt源码分析之信号和槽机?/div>
2009/09/17 13:21

Qt的信号和槽机制是Qt的一大特?实际上这是和MFC中的消息映射机制怼的东?要完成的事情也差不多,是发送一个消息然后让其它H口响应,当然,q里的消息是q义?br>说法,单点说就是如何在一个类的一个函C触发另一个类的另一个函数调?而且q要把相关的参数传递过?好像q和回调函数也有点关p?但是消息机制可比回调函数有用
多了,也复杂多?/p>

MFC中的消息机制没有采用C++中的虚函数机?原因是消息太?虚函数开销太大.在Qt中也没有采用C++中的虚函数机?原因与此相同.其实q里q有更深层次上的原因,大体说来,
多态的底层实现机制只有两种,一U是按照名称查表,一U是按照位置查表,两种方式各有利弊,而C++的虚函数机制无条件的采用了后?D的问题就是在子类很少重蝲基类实现
的时候开销太大,再加上象界面~程q样子类众多的情?基本上C++的虚函数机制废掉了,于是各家库的~写者就只好自谋生\?说到?q确实是C++语言本n的缺?/p>

CZ代码Q?br>#include <QApplication>
#include <QPushButton>
#include <QPointer>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

    QPushButton quit("Quit");
quit.resize(100, 30);
quit.show();
QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));

return app.exec();
}

q里主要是看QPushButton的clicked()信号和app的quit()槽如何连?又是如何响应?
前面已经说过?Qt的信h机制其实是按照名称查表,因此q里的首要问题是如何构造这个表?
和C++虚函数表机制cM?在Qt?q个表就是元数据?Qt中的元数据表最大的作用是支持信号槽机?当然,也可以在此基上扩展出更多的功?因ؓ
元数据是我们可以直接讉K到的,不再是象虚函数表那样被编译器遮遮掩掩的藏了v?不过Qtgq没有完全发挥元数据的能?动态属?反射之类的机制好像还没有

M从QObjectz的类都包含了自己的元数据模型Q一般是通过宏Q_OBJECT定义?br>#define Q_OBJECT \
public: \
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
QT_TR_FUNCTIONS \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
private:

首先声明了一个QMetaObjectcd的静态成员变?q就是元数据的数据结?/p>

struct Q_CORE_EXPORT QMetaObject
{
...
struct { // private data
const QMetaObject *superdata;
const char *stringdata;
const uint *data;
const QMetaObject **extradata;
} d;
}
QMetaObject中有一个嵌套类装了所有的数据
const QMetaObject *superdata;//q是元数据代表的cȝ基类的元数据
const char *stringdata;//q是元数据的{֐标记
const uint *data;//q是元数据的索引数组的指?br>const QMetaObject **extradata;//q是扩展元数据表的指?一般是不用?nbsp;      

q里的三个虚函数metaObjectQqt_metacastQqt_metacall是在moc文g中定义的
metaObject的作用是得到元数据表指针
qt_metacast的作用是Ҏ{֐得到相关l构的指?注意它返回的可是void*指针
qt_metacall的作用是查表然后调用调用相关的函?/p>

宏QT_TR_FUNCTIONS是和译相关?br>#  define QT_TR_FUNCTIONS \
static inline QString tr(const char *s, const char *c = 0) \
{ return staticMetaObject.tr(s, c); }

好了,看看实际的例子吧:

QPushButton的元数据表如?
static const uint qt_meta_data_QPushButton[] = {

 // content:
1,       // revision
0,       // classname
0,    0, // classinfo
2,   10, // methods
3,   20, // properties
0,    0, // enums/sets

 // slots: signature, parameters, type, tag, flags
13,   12,   12,   12, 0x0a,
24,   12,   12,   12, 0x08,

 // properties: name, type, flags
44,   39, 0x01095103,
56,   39, 0x01095103,
64,   39, 0x01095103,

       0        // eod
};

static const char qt_meta_stringdata_QPushButton[] = {
"QPushButton\0\0showMenu()\0popupPressed()\0bool\0autoDefault\0default\0"
"flat\0"
};

const QMetaObject QPushButton::staticMetaObject = {
{ &QAbstractButton::staticMetaObject, qt_meta_stringdata_QPushButton,
qt_meta_data_QPushButton, 0 }
};

在这里我们看C静态成员staticMetaObject被填充了
const QMetaObject *superdata;//q是元数据代表的cȝ基类的元数据,被填充ؓ基类的元数据指针&QAbstractButton::staticMetaObject
const char *stringdata;//q是元数据的{֐标记,被填充ؓqt_meta_stringdata_QPushButton
const uint *data;//q是元数据的索引数组的指?被填充ؓqt_meta_data_QPushButton
const QMetaObject **extradata;//q是扩展元数据表的指?一般是不用?被填充ؓ0

首先应该看qt_meta_data_QPushButton,因ؓq里是元数据的主要数?它被填充Z个整数数l?正因里只有整?不能有Q何字W串存在,因此才有
qt_meta_stringdata_QPushButton发挥作用的机?可以说真正的元数据应该是qt_meta_data_QPushButton加上qt_meta_stringdata_QPushButton,那么Z?br>不把q两个东西合在一起呢?估计是两者都不是定长的结?合在一起反而麻烦吧

qt_meta_data_QPushButton实际上是以以下结构开头的

struct QMetaObjectPrivate
{
int revision;
int className;
int classInfoCount, classInfoData;
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
};

一般用中是直接用以下函数做个{?br>static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }

q种转换怎么看都有些黑客的味?q确实是十的C风格

再结合实际的数据看一?br>static const uint qt_meta_data_QPushButton[] = {

 // content:
1,       // revision  版本h1
0,       // classname cd存储在qt_meta_stringdata_QPushButton?索引?,因此是QPushButton?br>0,    0, // classinfo  cM息数量ؓ0,数据也是0
2,   10, // methods  QPushButton?个自定义Ҏ,Ҏ数据存储在qt_meta_data_QPushButton?索引?0,是下面的slots:开始的地方
3,   20, // properties QPushButton?个自定义属?属性数据存储在qt_meta_data_QPushButton?索引?0,是下面的properties:开始的地方
0,    0, // enums/sets QPushButton没有自定义的枚D

 // slots: signature, parameters, type, tag, flags
13,   12,   12,   12, 0x0a,
W一个自定义Ҏ的签名存储在qt_meta_data_QPushButton?索引?3,是showMenu()?br>24,   12,   12,   12, 0x08,
W二个自定义Ҏ的签名存储在qt_meta_data_QPushButton?索引?4,popupPressed()?/p>

 // properties: name, type, flags
44,   39, 0x01095103,  
W一个自定义属性的{֐存储在qt_meta_data_QPushButton?索引?4,是autoDefault?br>W一个自定义属性的cd存储在qt_meta_data_QPushButton?索引?9,是bool
56,   39, 0x01095103,  
W二个自定义属性的{֐存储在qt_meta_data_QPushButton?索引?6,是default?br>W二个自定义属性的cd存储在qt_meta_data_QPushButton?索引?9,是bool
64,   39, 0x01095103,  
W三个自定义属性的{֐存储在qt_meta_data_QPushButton?索引?4,是flat?br>W三个自定义属性的cd存储在qt_meta_data_QPushButton?索引?9,是bool

       0        // eod 元数据的l束标记
};

static const char qt_meta_stringdata_QPushButton[] = {
"QPushButton\0\0showMenu()\0popupPressed()\0bool\0autoDefault\0default\0"
"flat\0"
};

QPushButton\\showMenu()\popupPressed()\bool\autoDefault\default\flat\
q里把\0直接替换为\是ؓ了数数的方便

当然我们q可以看看QPushButton的基cQAbstractButton的元数据
static const uint qt_meta_data_QAbstractButton[] = {

 // content:
1,       // revision
0,       // classname
0,    0, // classinfo
12,   10, // methods
9,   70, // properties
0,    0, // enums/sets

 // signals: signature, parameters, type, tag, flags
17,   16,   16,   16, 0x05,
27,   16,   16,   16, 0x05,
46,   38,   16,   16, 0x05,
60,   16,   16,   16, 0x25,
70,   38,   16,   16, 0x05,

 // slots: signature, parameters, type, tag, flags
89,   84,   16,   16, 0x0a,
113,  108,   16,   16, 0x0a,
131,   16,   16,   16, 0x2a,
146,   16,   16,   16, 0x0a,
154,   16,   16,   16, 0x0a,
163,   16,   16,   16, 0x0a,
182,  180,   16,   16, 0x1a,

 // properties: name, type, flags
202,  194, 0x0a095103,
213,  207, 0x45095103,
224,  218, 0x15095103,
246,  233, 0x4c095103,
260,  255, 0x01095103,
38,  255, 0x01195103,
270,  255, 0x01095103,
281,  255, 0x01095103,
295,  255, 0x01094103,

       0        // eod
};

static const char qt_meta_stringdata_QAbstractButton[] = {
"QAbstractButton\0\0pressed()\0released()\0checked\0clicked(bool)\0"
"clicked()\0toggled(bool)\0size\0setIconSize(QSize)\0msec\0"
"animateClick(int)\0animateClick()\0click()\0toggle()\0setChecked(bool)\0"
"b\0setOn(bool)\0QString\0text\0QIcon\0icon\0QSize\0iconSize\0"
"QKeySequence\0shortcut\0bool\0checkable\0autoRepeat\0autoExclusive\0"
"down\0"
};

QAbstractButton00pressed()0released()0checked0clicked(bool)0clicked()0toggled(bool)0size0setIconSize(QSize)0msec0animateClick(int)0animateClick()0click()0toggle()0setChecked(bool)0b0setOn(bool)0QString0text0QIcon0icon0QSize0iconSize0QKeySequence0shortcut0bool0checkable0autoRepeat0autoExclusive0down0

基本上都是大同小异的

  QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));
下面开始看信号和槽q接的源码了

// connect的源?br>connect函数是连接信号和槽的桥梁Q非常关?br>bool QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
Qt::ConnectionType type)
{
#ifndef QT_NO_DEBUG
bool warnCompat = true;
#endif
if (type == Qt::AutoCompatConnection) {
type = Qt::AutoConnection;
#ifndef QT_NO_DEBUG
warnCompat = false;
#endif
}

 // 不允许空输入
if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
#ifndef QT_NO_DEBUG
qWarning("Object::connect: Cannot connect %s::%s to %s::%s",
sender ? sender->metaObject()->className() : "(null)",
signal ? signal+1 : "(null)",
receiver ? receiver->metaObject()->className() : "(null)",
method ? method+1 : "(null)");
#endif
return false;
}
QByteArray tmp_signal_name;

#ifndef QT_NO_DEBUG
// 查是否是信号标记
if (!check_signal_macro(sender, signal, "connect", "bind"))
return false;
#endif
// 得到元数据类
const QMetaObject *smeta = sender->metaObject();
++signal; //skip code跌信号标记,直接得到信号标识
// 得到信号的烦?br>int signal_index = smeta->indexOfSignal(signal);
if (signal_index < 0) {
// check for normalized signatures
tmp_signal_name = QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
signal = tmp_signal_name.constData() + 1;
signal_index = smeta->indexOfSignal(signal);
if (signal_index < 0) {
#ifndef QT_NO_DEBUG
err_method_notfound(QSIGNAL_CODE, sender, signal, "connect");
err_info_about_objects("connect", sender, receiver);
#endif
return false;
}
}

    QByteArray tmp_method_name;
int membcode = method[0] - '0';

#ifndef QT_NO_DEBUG
// 查是否是?用QSLOT_CODE 1标记
if (!check_method_code(membcode, receiver, method, "connect"))
return false;
#endif
++method; // skip code

  // 得到元数据类
const QMetaObject *rmeta = receiver->metaObject();
int method_index = -1;
// q里是一个case,信号卛_以和信号q接也可以和槽连?br>switch (membcode) {
case QSLOT_CODE:
// 得到槽的索引
method_index = rmeta->indexOfSlot(method);
break;
case QSIGNAL_CODE:
// 得到信号的烦?br>method_index = rmeta->indexOfSignal(method);
break;
}
if (method_index < 0) {
// check for normalized methods
tmp_method_name = QMetaObject::normalizedSignature(method);
method = tmp_method_name.constData();
switch (membcode) {
case QSLOT_CODE:
method_index = rmeta->indexOfSlot(method);
break;
case QSIGNAL_CODE:
method_index = rmeta->indexOfSignal(method);
break;
}
}

    if (method_index < 0) {
#ifndef QT_NO_DEBUG
err_method_notfound(membcode, receiver, method, "connect");
err_info_about_objects("connect", sender, receiver);
#endif
return false;
}
#ifndef QT_NO_DEBUG
// 查参?信号和槽的参数必M?槽的参数也可以小于信L参数
if (!QMetaObject::checkConnectArgs(signal, method)) {
qWarning("Object::connect: Incompatible sender/receiver arguments"
"\n\t%s::%s --> %s::%s",
sender->metaObject()->className(), signal,
receiver->metaObject()->className(), method);
return false;
}
#endif

    int *types = 0;
if (type == Qt::QueuedConnection
&& !(types = ::queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))
return false;

#ifndef QT_NO_DEBUG
{
// 得到Ҏ的元数据
QMetaMethod smethod = smeta->method(signal_index);
QMetaMethod rmethod = rmeta->method(method_index);
if (warnCompat) {
if(smethod.attributes() & QMetaMethod::Compatibility) {
if (!(rmethod.attributes() & QMetaMethod::Compatibility))
qWarning("Object::connect: Connecting from COMPAT signal (%s::%s).", smeta->className(), signal);
} else if(rmethod.attributes() & QMetaMethod::Compatibility && membcode != QSIGNAL_CODE) {
qWarning("Object::connect: Connecting from %s::%s to COMPAT slot (%s::%s).",
smeta->className(), signal, rmeta->className(), method);
}
}
}
#endif
// 调用元数据类的连?br>QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
// 发送连接的通知,现在的实现是I的
const_cast<QObject*>(sender)->connectNotify(signal - 1);
return true;
}

查信h记其实比较简?是用signal的第一个字W和用QSIGNAL_CODE=2的标记比较而已
static bool check_signal_macro(const QObject *sender, const char *signal,
const char *func, const char *op)
{
int sigcode = (int)(*signal) - '0';
if (sigcode != QSIGNAL_CODE) {
if (sigcode == QSLOT_CODE)
qWarning("Object::%s: Attempt to %s non-signal %s::%s",
func, op, sender->metaObject()->className(), signal+1);
else
qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s",
func, op, sender->metaObject()->className(), signal);
return false;
}
return true;
}

得到信号的烦引实际上要依ơ找每个基类的元数据,得到的偏UM是所有元数据表加在一起后的一个烦?br>int QMetaObject::indexOfSignal(const char *signal) const
{
int i = -1;
const QMetaObject *m = this;
while (m && i < 0) {
// ҎҎ的数目倒序的查?br>for (i = priv(m->d.data)->methodCount-1; i >= 0; --i)
// 得到该方法的cd
if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & MethodTypeMask) == MethodSignal
&& strcmp(signal, m->d.stringdata
// 得到Ҏ名称的偏U?br>+ m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) {
//如果扑ֈ了正的Ҏ,再增加所有基cȝҎ偏移?br>i += m->methodOffset();
break;
}
// 在父cMl箋?br>m = m->d.superdata;
}
#ifndef QT_NO_DEBUG
// 判断是否于基cM的冲H?br>if (i >= 0 && m && m->d.superdata) {
int conflict = m->d.superdata->indexOfMethod(signal);
if (conflict >= 0)
qWarning("QMetaObject::indexOfSignal:%s: Conflict with %s::%s",
m->d.stringdata, m->d.superdata->d.stringdata, signal);
}
#endif
return i;
}

// q里是所有基cȝҎ偏移量算?是累加基类所有的Ҏ数目
int QMetaObject::methodOffset() const
{
int offset = 0;
const QMetaObject *m = d.superdata;
while (m) {
offset += priv(m->d.data)->methodCount;
m = m->d.superdata;
}
return offset;
}

// 得到Ҏ的元数据
QMetaMethod QMetaObject::method(int index) const
{
int i = index;
// 要减dcȝ偏移
i -= methodOffset();
// 如果本类找不?到基类中去?br>if (i < 0 && d.superdata)
return d.superdata->method(index);

 // 如果扑ֈ?填充QMetaMethodl构
QMetaMethod result;
if (i >= 0 && i < priv(d.data)->methodCount) {
// q里是类的元数据
result.mobj = this;
// q里是方法相x据在data数组中的偏移?br>result.handle = priv(d.data)->methodData + 5*i;
}
return result;
}

bool QMetaObject::connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index, int type, int *types)
{
// 得到全局的连接列?br>QConnectionList *list = ::connectionList();
if (!list)
return false;
QWriteLocker locker(&list->lock);
// 增加一个连?br>list->addConnection(const_cast<QObject *>(sender), signal_index,
const_cast<QObject *>(receiver), method_index, type, types);
return true;
}

void QConnectionList::addConnection(QObject *sender, int signal,
QObject *receiver, int method,
int type, int *types)
{
// 构造一个连?br>QConnection c = { sender, signal, receiver, method, 0, 0, types };
c.type = type; // don't warn on VC++6
int at = -1;
// 如果有中间被删除的连?可以重用q个I间
for (int i = 0; i < unusedConnections.size(); ++i) {
if (!connections.at(unusedConnections.at(i)).inUse) {
// reuse an unused connection
at = unusedConnections.takeAt(i);
connections[at] = c;
break;
}
}
if (at == -1) {
// append new connection
at = connections.size();
// 加入一个连?br>connections << c;
}
// 构造sender,receiverq接的哈希表,加速搜索速度
sendersHash.insert(sender, at);
receiversHash.insert(receiver, at);
}

通过connect函数,我们建立了信号和槽的q接,q且把信L+信号索引+槽类,槽烦引作录写C全局的connect列表?/p>

一旦我们发送了信号,应该调用相x中的Ҏ?q个q程其实是查找全局的connect列表的过E?当然q要注意其中要对相关的参数打包和解包

// emit是发送信L代码
void Foo::setValue(int v)
{
if (v != val)
{
val = v;
emit valueChanged(v);
}
}

// 发送信L真正实现在moc里面
// SIGNAL 0
void Foo::valueChanged(int _t1)
{
// 首先把参数打?br>void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
// 调用元数据类的激z?br>QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
{
// 增加一个基cdU量
int offset = m->methodOffset();
activate(sender, offset + local_signal_index, offset + local_signal_index, argv);
}

void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv)
{
// q里得到的是QObject的数?首先判断是否为阻塞设|?br>if (sender->d_func()->blockSig)
return;

 // 得到全局链表
QConnectionList * const list = ::connectionList();
if (!list)
return;

    QReadLocker locker(&list->lock);

    void *empty_argv[] = { 0 };
if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
locker.unlock();
qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index,
argv ? argv : empty_argv);
locker.relock();
}

 // 在sender的哈希表中得到sender的连?br>QConnectionList::Hash::const_iterator it = list->sendersHash.find(sender);
const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd();

    if (it == end) {
if (qt_signal_spy_callback_set.signal_end_callback != 0) {
locker.unlock();
qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
locker.relock();
}
return;
}

    QThread * const currentThread = QThread::currentThread();
const int currentQThreadId = currentThread ? QThreadData::get(currentThread)->id : -1;

 // 记录senderq接的烦?br>QVarLengthArray<int> connections;
for (; it != end && it.key() == sender; ++it) {
connections.append(it.value());
// 打上使用标记,因ؓ可能是放在队列中
list->connections[it.value()].inUse = 1;
}

    for (int i = 0; i < connections.size(); ++i) {
const int at = connections.constData()[connections.size() - (i + 1)];
QConnectionList * const list = ::connectionList();
// 得到q接
QConnection &c = list->connections[at];
c.inUse = 0;
if (!c.receiver || (c.signal < from_signal_index || c.signal > to_signal_index))
continue;

  // 判断是否攑ֈ队列?br>// determine if this connection should be sent immediately or
// put into the event queue
if ((c.type == Qt::AutoConnection
&& (currentQThreadId != sender->d_func()->thread
|| c.receiver->d_func()->thread != sender->d_func()->thread))
|| (c.type == Qt::QueuedConnection)) {
::queued_activate(sender, c, argv);
continue;
}

  // 为receiver讄当前发送?br>const int method = c.method;
QObject * const previousSender = c.receiver->d_func()->currentSender;
c.receiver->d_func()->currentSender = sender;
list->lock.unlock();

        if (qt_signal_spy_callback_set.slot_begin_callback != 0)
qt_signal_spy_callback_set.slot_begin_callback(c.receiver, method, argv ? argv : empty_argv);

#if defined(QT_NO_EXCEPTIONS)
c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
#else
try {
// 调用receiver的方?br>c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
} catch (...) {
list->lock.lockForRead();
if (c.receiver)
c.receiver->d_func()->currentSender = previousSender;
throw;
}
#endif

        if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(c.receiver, method);

        list->lock.lockForRead();
if (c.receiver)
c.receiver->d_func()->currentSender = previousSender;
}

    if (qt_signal_spy_callback_set.signal_end_callback != 0) {
locker.unlock();
qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
locker.relock();
}
}

// 响应信号也是在moc里实现的
int Foo::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
// 首先在基cM调用Ҏ,q回的id已经变成当前cȝҎid?br>_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
// q里是真正的调用方法了,注意参数的解包用?br>case 0: valueChanged(*reinterpret_cast< int(*)>(_a[1])); break;
case 1: setValue(*reinterpret_cast< int(*)>(_a[1])); break;
}
_id -= 2;
}
return _id;
}


]]>Android 的消息队列模型(转)http://www.shnenglu.com/Walker/articles/145869.html漫步者?amp;…?K?/dc:creator>漫步者?amp;…?K?/author>Fri, 06 May 2011 23:53:00 GMThttp://www.shnenglu.com/Walker/articles/145869.htmlhttp://www.shnenglu.com/Walker/comments/145869.htmlhttp://www.shnenglu.com/Walker/articles/145869.html#Feedback0http://www.shnenglu.com/Walker/comments/commentRss/145869.htmlhttp://www.shnenglu.com/Walker/services/trackbacks/145869.html本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/ghj1976/archive/2011/05/06/6398896.aspx

Android是参考Windows的消息@环机制来实现Android自n的消息@环的?
Android通过Looper、Handler来实现消息@环机ӞAndroid消息循环是针对线E的Q每个线E都可以有自q消息队列和消息@环)?
Androidpȝ中,Looper负责理U程的消息队列和消息循环。我们可以通过Loop.myLooper()得到当前U程的Looper对象Q通过Loop.getMainLooper()可以获得当前q程的主U程的Looper对象?
一个线E可以存在(当然也可以不存在Q一个消息队列和一个消息@环(LooperQ?
Activity是一个UIU程Q运行于ȝE中QAndroidpȝ在启动的时候会为Activity创徏一个消息队列和消息循环QLooperQ?
Handler的作用是把消息加入特定的QLooperQ消息队列中Qƈ分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象Q如果不指定则利用当前线E的Looper创徏?
Activity、Looper、HandlerQThread的关pd下图所C:

 

一个Activity中可以创建多个工作线E或者其他的lgQ如果这些线E或者组件把他们的消息放入Activity的主U程消息队列Q那么该消息׃在主U程中处理了?/p>

因ؓȝE一般负责界面的更新操作Qƈ且Androidpȝ中的widget不是U程安全的,所以这U方式可以很好的实现Android界面更新。在Androidpȝ中这U方式有着q泛的运用?

那么一个线E怎样把消息放入主U程的消息队列呢Q答案是通过Handle对象Q只要Handler对象以主U程的Looper创徏Q那么调用Handler的sendMessage{接口,会把消息放入队列都是攑օȝE的消息队列。ƈ且将会在HandlerȝE中调用该handler的handleMessage接口来处理消息?/p>

更多Android消息队列的信息请参看Q?http://my.unix-center.net/~Simon_fu/?p=652

下面q个图从另外一个角度描qC他们的关p:

 

参考资料:

Android异步加蝲囑փ结
http://blog.csdn.net/sgl870927/archive/2011/03/29/6285535.aspx

深入理解Android消息处理pȝ——Looper、Handler、Thread

http://my.unix-center.net/~Simon_fu/?p=652

AndroidU程模型QPainless ThreadingQ?
http://android.group.iteye.com/group/blog/382683

androidU程控制UI更新QHandler 、post()、postDelayed()、postAtTimeQ?
http://lepeng.net/blogger/?p=21

Android – Multithreading in a UI environment
http://www.aviyehuda.com/2010/12/android-multithreading-in-a-ui-environment/

Android中的Handler, Looper, MessageQueue和Thread
http://www.cnblogs.com/xirihanlin/archive/2011/04/11/2012746.html

Android Runnable
http://blog.csdn.net/michaelpp/archive/2010/06/30/5704682.aspx


 



]]>
Chrome的小胡瓜(Courgette) http://www.shnenglu.com/Walker/articles/145114.html漫步者?amp;…?K?/dc:creator>漫步者?amp;…?K?/author>Tue, 26 Apr 2011 23:54:00 GMThttp://www.shnenglu.com/Walker/articles/145114.htmlhttp://www.shnenglu.com/Walker/comments/145114.htmlhttp://www.shnenglu.com/Walker/articles/145114.html#Feedback0http://www.shnenglu.com/Walker/comments/commentRss/145114.htmlhttp://www.shnenglu.com/Walker/services/trackbacks/145114.htmlChrome的小胡瓜(Courgette) 收藏

转自http://blog.csdn.net/xingtian713/archive/2009/08/25/4483810.aspx


在Chrome中有一个很有意思的工具courgetteQ翻译成中文是小胡瓜的意思。我很难把这个单词和q个工兯pd一P也许作者比较偏p个蔬菜吧Q?

背景
我们用C++~写E序Ӟl常会出C改了一行代码,重新~译一下之后,再去Ҏ一下新的二q制文gQ就可以发现千差万别了。往往出现我们要发布一个修改了一行代码的补丁Q需要替换整个DLL或者EXE。这对于Chrome中类gChrome.dllQ?0M左右Q文件来_升一ơ的代hq是挺高的。本人在d下半q负责的一个升U服务器目中,曾动过念头Q是否有一U方法可以寻扑և两个二进制文件的差异Q将q个差异打成一个补丁,用户下蝲后,可以通过q个补丁Q可以自动生成新的DLL。可惜功力不够,最后放弃了。最q读Chrome的代码时Q发现Chrome已经实现了该功能。这个就是Courgette的功劳了?

Courgette做什么的Q?
Courgette主要用于Chrome的升U过E,他的主要作用是,针对两个版本不同的二q制文g(Binary File)Q寻扑օ中区别,生成补丁文gQ另外就是根据这个补丁文件加上旧版本的二q制文g生成新版本的二进制文件的q原q程了。类g加解密流E?

Courgette的实现原理?
Courgette构徏在一个开源代码bsdiff和bspatch 基础上的。ƈ在bsdiff的基上做了一些优化?

本h是半路出家的人,对编译原理和汇编了解不深Q按照我对bsdiff的算?理解Q一个二q制文g里面Q包含了代码部分Q函敎ͼ数据Q,指向q些函数的指针列表(~译链接产生Q包含了如何定位函数{信息)Q由于这些地址是内部的相对地址Q即使更改了一行代码Q重新编译后Q函数的地址发生变化了Q指向这些函数的指针g全部变化了。因此,即更改了一个小的变量Q也会导致很多部分的修改。bsdiff的原理就是对二进制文件进行反汇编Q将上面所说的两部分进行分别处理,对于代码部分Q其实就和普通的文本文gcM了,改变不会太大Q这部分体积基本上占M整个二进制文件的80%左右。然后对动态指针部分进行一些更新处理,基本上辑ֈ了打补丁的目标了?

    server:

        diff = bsdiff(original, update)

        transmit diff


    client:

        receive diff

        update = bspatch(original, diff)
大致程如上Q制作补丁时调用bsdiff函数Q根据两个不同版本的二进制文Ӟ生成补丁文g。客L下蝲补丁后,调用bspatch函数Q根据旧版本二进制文件和补丁生成新的二进制文件?/p>

Chrome在bsdiff的基上做了一些优化,主要体现在动态指针列表部分,chrome对代码部分的每一个模块地址分配了一个标{(LabelQ,q些标签都是整数Qƈ把这些标{保存到一个数l中Q然后指针列表中映射的地址改ؓ指向数组的烦引,׃一些函数地址被调用多ơ,通过q种Ҏ实可以减少一些体U。做了一些优化后Q在bsdiff的基上又减少?0%左右吧(q是google的说法,我没验证q)?
    server:
        asm_old = disassemble(original)
        asm_new = disassemble(update)
        asm_new_adjusted = adjust(asm_new, asm_old)
        asm_diff = bsdiff(asm_old, asm_new_adjusted)
        transmit asm_diff


    client:
        receive asm_diff
        asm_old = disassemble(original)
        asm_new_adjusted = bspatch(asm_old, asm_diff)
        update = assemble(asm_new_adjusted)
Chrome的大致处理流E如上,和bsdiff程cMQ多?asm_new_adjusted = adjust(asm_new, asm_old)q一个步骤,q个步骤主要是上面说的对地址标签化的q程?/p>

]]>
chrome 源码分析http://www.shnenglu.com/Walker/articles/145113.html漫步者?amp;…?K?/dc:creator>漫步者?amp;…?K?/author>Tue, 26 Apr 2011 23:52:00 GMThttp://www.shnenglu.com/Walker/articles/145113.htmlhttp://www.shnenglu.com/Walker/comments/145113.htmlhttp://www.shnenglu.com/Walker/articles/145113.html#Feedback0http://www.shnenglu.com/Walker/comments/commentRss/145113.htmlhttp://www.shnenglu.com/Walker/services/trackbacks/145113.html
Z对庞大的源码目q行分析Q先Ҏ码目录树作一个简单的介绍Q粗略的了解一下各个模块的功能分布情况Qchrome源代码src目录下的l构如下图:

  appQ该目录下的代码主要是和各个操作pȝq_相关的应用上层代码的提炼。不同操作系l可能对应不同的c++实现文g。比如裁剪板操作、操作系l数据交换接口、资源管理等。代码量不大?/p>

  baseQ基设施代码Q该目录下的代码对理解chrome的基架构设计是必不可的Q这里面是大量的工具性、框架性代码实玎ͼ比如对进E、线E、消息@环的l一装Q对字符串处理、c++对象生命周期理、json解析、\径服务、日期时间、日志框架等?/p>

  breakpadQ崩溃服务框架库Q在E序发生异常Ӟ对异常进行捕获后可以崩溃现场数据发送给googleq行分析?/p>

  buildQ编译构建相关的工具支持?/p>

  chromeQ浏览器ȝ序实C码,包括了UI实现和Render部分两大部分Q当然这两部分又是以大量的其他基设施代码为基的,比如Render部分是对webkit的封装。这部分代码量很大,google自代码Q频J的改动代码主要集中在这里?/p>

  chrome_frameQ这是google针对IE开发的一个插Ӟ使得IE可以使用chrome的渲染引擎来昄|页?/p>

  courgetteQ小胡瓜Q这个项目是一个针对升U用的Q目的是减少升q程中数据下载的大小。比如版本升U可能需要更新某个DLL文gQ而这个文件可能有10M大小Q而新版本可能只是对该DLL改动了一行代码。通过courgette可以扑ևq两个DLL之间的差异部分,使得不需要下?0M大小Q而可能只需要下载几十K的差异描q数据即可完成升U?/p>

  gearsQ是一个用来开发离U网l应用的工具Q是一个JavaScript应用~程接口Q通过Google Gears可以允许多种Web应用E序脱机q行Q可以让用户在上U或者离U状态下q行|络E序。离U就需要作本地存储Q而在html5中就有本地存储相关的接口规范Q因此google放弃gears而采用html5的方式?/p>

  google_updateQgoogle更新Q用于自动升U?/p>

  googleurlQgoogle实现的URL解析辅助工具库?/p>

  ipcQ非帔R要的q程通信基础设施库。chrome是多q程架构Q而进E间的通信是以ipc库作为基支持的。具体在windows下的实现方式是命名管道、异步IOQ完成端口)、共享内存来实现q程间高效的数据传输。ipc不仅装了IO机制Q而且q定义了l一的消息传输格式?/p>

  mediaQ多媒体音频视频解码相关的内宏V?/p>

  native_clientQ在览器中q行native代码的技术,是一个插件。native_client目被视为微软ActiveX技术的lQ者。项目具体细节可参?a target=_blank>native client官网?/p>

  netQ网l协议实现基库,包括ftp、http{客L协议栈的实现代码?/p>

  o3dQ一个插Ӟ可在览器中创徏丰富的交互式三维应用E序Q以后在览器中?D游戏不再遥q。具体细节参?a target=_blank>o3d目官网?/p>

  printingQ打印方面的内容?/p>

  rlzQ用戯t,q个没有源码Q这个库的目的就是将用户行ؓ攉报告lgoogle。虽然这对品的改善有很大的帮助Q但也存在隐U问题?/p>

  sandboxQ沙盒安全技术,在浏览网늚时候,保护计算Z被恶意代码R入?/p>

  sdchQ一U新的压~技术。浏览器在httph时可以写成Accept-Encoding: sdch, gzip。服务器如果支持的话Q就可以q回sdch格式的压~数据给览器?/p>

  site_sconsQ一个工P里面是一个python脚本文gQ具体用处还未深入了解?/p>

  skiaQgoogle收购的一家公司提供的2D囑Ş渲染库,囑Ş库的优劣军_了浏览器的显C效果。据说IE9采用GPU昑֍渲染Q估计浏览器采用GPU渲染很快普及?/p>

  testingQc++单元试框架库?/p>

  third_partyQ该目录下是大量的第三方开源支持库Q最重要的当然是webkit内核了?/p>

  v8Qgoogle开发的高效的javascript引擎Q是chrome的重要内核库?/p>

  viewsQ界面控件元素库Q对不同操作pȝq_的UI事g交互机制、各U控件如按钮、菜单、树、checkbox{进行了l一的封装。界面绘刉用skia来实现?/p>

  webkitQgoogle对webkit内核的封装层Q其目的是在webkit内核和上层调用之间提供一个中间层。该目录下有一个重要的glue工程。是名副其实?#8216;胶水’层?/p>

  整个源码工程虽然庞大Q但其结构是非常清晰的,代码风格很统一Q就象是一个h写的一栗借助vs2008强大的可视化调试Q我们只要掌握好_度Q从_到l,从整体到局部逐渐深入Q带着问题去跟t调试,很快׃上手q入状态?/p>

]]>
源代码分析之如何实现自定义的标题?/title><link>http://www.shnenglu.com/Walker/articles/143886.html</link><dc:creator>漫步者?amp;…?K?/dc:creator><author>漫步者?amp;…?K?/author><pubDate>Sun, 10 Apr 2011 13:06:00 GMT</pubDate><guid>http://www.shnenglu.com/Walker/articles/143886.html</guid><wfw:comment>http://www.shnenglu.com/Walker/comments/143886.html</wfw:comment><comments>http://www.shnenglu.com/Walker/articles/143886.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Walker/comments/commentRss/143886.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Walker/services/trackbacks/143886.html</trackback:ping><description><![CDATA[<p>本文主要分析Visual Studio Samples\1033\C++\MFC\Visual C++ 2008 Feature Pack\MSMoneyDemoq个Sample<br>一般窗口的标题栏上面都是只有固定的最化Q恢复,最大化按钮Q这些按钮的大小Q图标都是系l自定义的,<br>本文分析VS2008 sp1 的事例代码实现自q标题栏?br>CMSMCaptionBar实现了,自定义的标题栏窗口,cd义如下?br>class CMSMCaptionBar : public CPane<br>{<br> DECLARE_DYNCREATE(CMSMCaptionBar)</p> <p>// Construction<br>public:<br> CMSMCaptionBar ();</p> <p> virtual ~CMSMCaptionBar ();<br> <br> virtual void SetIcon (HICON hIcon);</p> <p> void SetCaptionHeight (int nHeight);</p> <p> int GetCaptionHeight () const;</p> <p> void SetCaptionFont (const LOGFONT& lf);</p> <p> HFONT GetCaptionFont () const;</p> <p> virtual COLORREF GetCaptionTextColor () const;</p> <p> void SetParentActive (BOOL bParentActive = true);</p> <p> BOOL IsParentActive () const;</p> <p> void SetParentMaximize (BOOL bParentMaximize = true);</p> <p> BOOL IsParentMaximize () const;</p> <p>// Attributes<br>public:</p> <p>// Operations<br>public:</p> <p>// Overrides<br>public:<br> virtual BOOL Create(CWnd* pParentWnd, UINT nID = uiCaprionBarID);<br> virtual BOOL CreateEx(CWnd* pParentWnd, UINT nID = uiCaprionBarID);<br> virtual CSize CalcFixedLayout(BOOL, BOOL);<br>protected:<br> virtual BOOL PreCreateWindow(CREATESTRUCT& cs);<br> virtual void DoPaint(CDC* pDCPaint);<br> virtual BOOL PreTranslateMessage(MSG* pMsg);<br> virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);</p> <p>protected:<br> afx_msg LRESULT OnSetText(WPARAM, LPARAM lParam);<br> afx_msg void OnSize(UINT nType, int cx, int cy);<br> afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);<br> afx_msg void OnSysCommand(UINT nID, LPARAM lParam);</p> <p> DECLARE_MESSAGE_MAP()</p> <p> virtual UINT HitTest (const CPoint& pt) const;<br> virtual void ShowSysMenu (const CPoint& point);</p> <p>public:<br> CString      m_strCaption;</p> <p> HICON      m_hIcon;<br> CSize      m_szIcon;</p> <p> BOOL      m_bParentActive;<br> BOOL      m_bParentMaximize;</p> <p> int       m_SystemHeight;<br> int       m_CaptionHeight;<br> CFont      m_CaptionFont;</p> <p> CMSMCaptionBarButton m_BtnMinimize;<br> CMSMCaptionBarButton m_BtnMaximize;<br> CMSMCaptionBarButton m_BtnClose;<br>};</p> <p>下面是类的派生关pdQ?br>CObject <br>   CCmdTarget<br>      CWnd<br>         CBasePane<br>            CPane<br>       CMSMCaptionBar<br>从这个图上可以看出:CMSMCaptionBar也是一个窗口,Q从CWndcL生的都是一个窗口WIndowQ?/p> <p>2 如何设计设计一个Caption Window<br>一个窗口主要由UI部分以及消息响应部分l成?br>UI部分通俗的说是H口的外观描qͼ通过外观描述可以l制出窗口?br>消息响应部分是该窗口会处理哪些消息。比如双L最大化q是恢复Q点M面的关闭按钮Q程序关闭等{,下面会详l描q?br>2.1 Caption Window的组?br>1Q元素组成:标题图标Q窗口标题,最化按钮Q恢复按钮,最大化按钮?br>描述q些元素需要相应的成员变量Q也是CMSMCaptionBar的public成员Q?br> CString      m_strCaption;//H口标题<br> CFont      m_CaptionFont;//标题字体<br> <br> HICON      m_hIcon;//标题图标<br> CSize      m_szIcon;//图标大小</p> <p> </p> <p> //最化按钮Q恢复按钮,最大化按钮?br> CMSMCaptionBarButton m_BtnMinimize;<br> CMSMCaptionBarButton m_BtnMaximize;<br> CMSMCaptionBarButton m_BtnClose;</p> <p>对于Caption WindowQ还有自q一些属性,比如H口高度?/p> <p> int       m_SystemHeight;<br> int       m_CaptionHeight;//标题栏高?br> <br>2Q如何绘制元?br>Z保证H口接收双击事gQ需要组成S_DBLCLKS风格的窗口?br>LPCTSTR lpszClass = AfxRegisterWndClass(CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW),<br>  (HBRUSH)(COLOR_BTNFACE+1), NULL);</p> <p>Create->CreateEx<br>创徏H口<br>CWnd::Create(lpszClass, NULL, dwStyle | WS_CLIPSIBLINGS, rect, pParentWnd, nID)<br>创徏好窗口之后还必须加入到窗口的一个Pane的列表中?br>if (pParentWnd->IsKindOf (RUNTIME_CLASS (CFrameWndEx)))<br> {<br>  ((CFrameWndEx*) pParentWnd)->AddPane (this);<br> }<br> <br> <br>加蝲Capation IconQ设|Caption 标题<br>SetIcon (hIcon);<br>SetWindowText (strCaption);<br>创徏最化按钮Q恢复按钮,最大化按钮<br> m_BtnClose.Create (_T(""), BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, <br>                 rt, this, SC_CLOSE);<br> m_BtnClose.SetTooltip (_T("Close"));</p> <p> m_BtnMaximize.Create (_T(""), BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, <br>                 rt, this, SC_MAXIMIZE);<br> m_BtnMaximize.SetTooltip (_T("Maximize"));</p> <p> m_BtnMinimize.Create (_T(""), BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, <br>                 rt, this, SC_MINIMIZE);<br> m_BtnMinimize.SetTooltip (_T("Minimize"));</p> <p>对于按钮上图片的讄与加载是在CMSMVisualManager中设|的Q这是在VS2008 Sp1中有的可以设|多UUI主题风格Q类g换皮肤?br>下面列出了与Caption Window相关的函数?br>class CMSMVisualManager : public CMFCVisualManagerOffice2003<br>{<br>BOOL CMSMVisualManager::LoadMSMCaptionButtonsIcons (LPCTSTR lpszID);<br> virtual void MSMDrawCaptionButton (CDC* pDC, CRect rect, AFX_BUTTON_STATE state, UINT id);<br> BOOL LoadMSMCaptionButtonsIcons (LPCTSTR lpszID);</p> <p> const CSize& GetMSMCaptionButtonsSize () const;<br> <br> virtual void OnFillBarBackground (CDC* pDC, CBasePane* pBar,<br> CRect rectClient, CRect rectClip, BOOL bNCArea = FALSE);<br>      <br> CImageList m_CaptionButtonIconst;<br> CSize    m_CaptionButtonSize;<br>}<br>通过q些函数可以讄Button的图片以及Caption Windowd的背景?/p> <p><br>通过上面把H口UI元素d了,下面介绍消息的处?/p> <p>3QCaption Windows处理的消息又哪些Q?br> 鼠标左键单击Q需要判断是最化Q最大化Q恢复,q是关闭Q;<br> 鼠标右键单击Q弹出帮助菜单)<br> 鼠标左键双击Q最大化或者恢复)<br> WM_SIZE消息Q当H口大小变化Ӟ需要移动最化Q最大化Q恢复按钮的位置?br> <br> 也就是下面的一些消息?br> ON_MESSAGE(WM_SETTEXT, OnSetText)<br> ON_WM_SIZE()<br> ON_WM_CONTEXTMENU()<br> ON_WM_SYSCOMMAND()<br> <br> <br>4Q对于按钮消息的处理WM_XXX应当转化成WM_NCXXXQ也是说客L消息要{化成非客L消息。因为对于单文档E序来说Q?br>标题栏属于非客户区?/p> <p>BOOL CMSMCaptionBar::PreTranslateMessage (MSG* pMsg) <br>在其中调用HitTest函数判断鼠标的位|,如果是在Caption window中点击,?br>判断uiHit = HTCAPTION;q是uiHit = HTSYSMENU;<br>?br>   switch (pMsg->message)<br>   {<br>   case WM_LBUTTONDOWN:<br>    message = WM_NCLBUTTONDOWN;<br>    break;<br>   case WM_LBUTTONUP:<br>    message = WM_NCLBUTTONUP;<br>    break;<br>   case WM_LBUTTONDBLCLK:<br>    message = WM_NCLBUTTONDBLCLK;<br>    break;<br>   }</p> <p>   if (message != 0)<br>   {<br>    if (message == WM_NCLBUTTONDOWN && uiHit == HTSYSMENU)<br>    {<br>     CRect rt;<br>     GetWindowRect (rt);</p> <p>     ShowSysMenu (CPoint (rt.left, rt.bottom));<br>    }<br>    else<br>    {<br>     pParentWnd->SendMessage (message, wParam, lParam);<br>    }<br>   }</p> <p>对于Caption Window不感兴趣的消息会发送给父窗口处理?br> <br>5QWM_SIZE消息的处?/p> <p>对WM_SIZE的消息处理就是移动最下化Q最大化Q以及恢复按钮?/p> <p><br>3Q用Caption Window<br>int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) <br>讄风格Q去掉WS_CAPTION | FWS_ADDTOTITLEQ即创徏不带Caption的Mainframe,<br>因ؓCaption是我们自p创徏的,而不是自动创?/p> <p> ModifyStyle (WS_CAPTION | FWS_ADDTOTITLE, 0);<br>LH口的边?br> ModifyStyleEx (WS_EX_CLIENTEDGE, 0);<br>讄H口风格<br> CMFCVisualManager::SetDefaultManager (RUNTIME_CLASS (CMSMVisualManager));</p> <img src ="http://www.shnenglu.com/Walker/aggbug/143886.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Walker/" target="_blank">漫步者?…?K?/a> 2011-04-10 21:06 <a href="http://www.shnenglu.com/Walker/articles/143886.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Q{Qstrlen源码剖析 http://www.shnenglu.com/ant/archive/2007/10/12/32886.htmlhttp://www.shnenglu.com/Walker/articles/82347.html漫步者?amp;…?K?/dc:creator>漫步者?amp;…?K?/author>Sat, 09 May 2009 01:50:00 GMThttp://www.shnenglu.com/Walker/articles/82347.htmlhttp://www.shnenglu.com/Walker/comments/82347.htmlhttp://www.shnenglu.com/Walker/articles/82347.html#Feedback0http://www.shnenglu.com/Walker/comments/commentRss/82347.htmlhttp://www.shnenglu.com/Walker/services/trackbacks/82347.html阅读全文

]]>
þþþŮʦһ| Ʒþþþþҹҹ| vĻþ 뾫ƷþɪӰ | 99þۺϹƷ| þAV߳AVAV| avھƷþþþӰԺ| þþþޱٸ| þþþAV鶹| ھƷþþþþþcoent| þ99Ʒþþôѧ| ˾þþƷ| þ99Ʒþþþþhb| þþƷֻоƷ66 | ŷҹAŴƬþ| ˾þþƷ| AŮAVۺϾþþ| 69þҹɫƷ69| þ¶ݺɫ| þ99Ʒþþþþˮ| ݺɫþþۺƵպ | þwww˳ɿƬ| þþƷŷƬ| þer99ȾƷһ| պŷһþþþ| þþƷһ| þZYZԴվĶ| ղƷþþһ| þþù99þùһ| þ99Ʒ | þþ޾Ʒ| ҹƷþþþþžŵӰ | ŷ޾þþþƷ| þþþƷһ| 97þþþ| 99鶹þþùƷ| պavþþƷ| þ͵wcŮ| þþþ޾Ʒ| þþþAVƬ | 99þóĻ| þþþƷsmվ|