??xml version="1.0" encoding="utf-8" standalone="yes"?>久久亚洲色一区二区三区,久久水蜜桃亚洲av无码精品麻豆,9191精品国产免费久久http://www.shnenglu.com/vivence/c++ programmerzh-cnTue, 06 May 2025 23:27:10 GMTTue, 06 May 2025 23:27:10 GMT60AVL?/title><link>http://www.shnenglu.com/vivence/archive/2011/06/17/AVLTree.html</link><dc:creator>EvilGhost</dc:creator><author>EvilGhost</author><pubDate>Fri, 17 Jun 2011 12:01:00 GMT</pubDate><guid>http://www.shnenglu.com/vivence/archive/2011/06/17/AVLTree.html</guid><wfw:comment>http://www.shnenglu.com/vivence/comments/148880.html</wfw:comment><comments>http://www.shnenglu.com/vivence/archive/2011/06/17/AVLTree.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vivence/comments/commentRss/148880.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vivence/services/trackbacks/148880.html</trackback:ping><description><![CDATA[<p> </p><p>AVLTree.h文g</p> <p> </p><div id="s8ssy80" class="cnblogs_Highlighter"> <pre class="brush:cpp;gutter:false;">#ifndef AVL_TREE_H #define AVL_TREE_H #include <cassert> #include <algorithm> #ifdef _PRINT #include <vector> #include <iostream> #include <memory> #include <functional> #endif // _PRINT namespace ghost{ /// AVL? template<typename ComparableT> class AVLTree{ public: typedef ComparableT DataType; private: /// 节点Q缓存了(jin)自n的高? struct Node_{ DataType data; // 可进行比较的数据 Node_* pLeftChild; // 指向左儿? Node_* pRightChild; // 指向叛_? int height; // 作ؓ(f)根节点的?wi)高度? Node_() : pLeftChild(0) , pRightChild(0) , height(0) // U定叶子高度?Q故节点高度初始化ؓ(f)0 { } explicit Node_(const DataType& d) : data(d) , pLeftChild(0) , pRightChild(0) , height(0) // U定叶子高度?Q故节点高度初始化ؓ(f)0 { } Node_(const Node_&) = delete; Node_& operator =(const Node_&) = delete; }; Node_* pRoot_; // 指向根节? public: /// 默认初始化ؓ(f)I树(wi) AVLTree() : pRoot_(0) { #ifdef _PRINT std::cout<<"创徏AVL?<<std::endl; #endif // _PRINT } ~AVLTree() { Clear(); } AVLTree(const AVLTree&) = delete; AVLTree& operator =(const AVLTree&) = delete; public: /// 获取?wi)高度,I树(wi)q回-1Q只有个节点q回0 int GetHeight() const{return GetHeight_(pRoot_);} #ifdef _PRINT /// 打印者,即需要打印的对象 class Printer{ public: virtual ~Printer(){} public: virtual void Print() const{} virtual bool IsValid() const{return false;} }; typedef std::shared_ptr<Printer> PSharedPrinter; // 打印者共享指? typedef std::vector<PSharedPrinter> PrinterContainer; // 打印者共享指针的容器 /// 节点打印? class NodePrinter : public Printer{ Node_* pNode_; size_t width_; PrinterContainer& nextPrinters_; public: NodePrinter(Node_* p, PrinterContainer& printers) : pNode_(p) , width_(0) , nextPrinters_(printers) { assert(pNode_); UpdateWidth(); } virtual ~NodePrinter(){} NodePrinter(const NodePrinter&) = delete; NodePrinter& operator =(const NodePrinter&) = delete; public: void UpdateWidth() { width_ = CalcDataWidth_(pNode_->data); } virtual void Print() const { // 计算左右子树(wi)宽度 size_t leftChildWidth = CalcWidth_(pNode_->pLeftChild); size_t rightChildWidth = CalcWidth_(pNode_->pRightChild); // +1是ؓ(f)?jin)将数据隔开 // 打印左边I白 for (size_t i = 0; i < leftChildWidth; ++i) { std::cout<<' '; } // 打印节点 std::cout<<"["<<pNode_->data<<"]"; // 打印双I白 for (size_t i = 0; i < rightChildWidth; ++i) { std::cout<<' '; } // 左儿子攑օ下一层需要打印的节点集合? if (pNode_->pLeftChild) { nextPrinters_.push_back(PSharedPrinter(new NodePrinter(pNode_->pLeftChild, nextPrinters_))); } // 自w所占空位放入下一层需要打印的节点集合? nextPrinters_.push_back(PSharedPrinter(new BlankPrinter(width_))); // 右儿子攑օ下一层需要打印的节点集合? if (pNode_->pRightChild) { nextPrinters_.push_back(PSharedPrinter(new NodePrinter(pNode_->pRightChild, nextPrinters_))); } // 自w所占空位放入下一层需要打印的节点集合? nextPrinters_.push_back(PSharedPrinter(new BlankPrinter(width_))); } virtual bool IsValid() const{return true;} }; /// I白打印者,主要完成打印父节Ҏ(gu)占用的空? class BlankPrinter : public Printer{ size_t count_; public: explicit BlankPrinter(size_t c) : count_(c){} virtual ~BlankPrinter(){} public: virtual void Print() const { for (size_t i = 0; i < count_; ++i) { std::cout<<' '; } } }; /// q度优先打印节点Q目前只支持打印int型数? void Print() const { std::cerr<<"不支持打印的数据cdQ?<<typeid(DataType).name()<<"\n"; } private: /// 计算十进制数位数 static size_t CalcDataWidth_(int n) { assert(false); } /** 计算?wi)宽? 因ؓ(f)U定I树(wi)宽度?Q叶子宽度ؓ(f)1Q所以树(wi)宽度{于左右子树(wi)宽度?数据所占的位数 */ static size_t CalcWidth_(const Node_* pRoot) { if (!pRoot) { return 0; } return CalcWidth_(pRoot->pLeftChild) + CalcWidth_(pRoot->pRightChild) + CalcDataWidth_(pRoot->data); } #endif // _PRINT public: /// 插入数据 void Insert(const DataType& data) { #ifdef _PRINT std::cout<<"插入数据Q?<<data<<std::endl; #endif // _PRINT Insert_(data, pRoot_); } /// 删除数据 void Erase(const DataType& data) { #ifdef _PRINT std::cout<<"删除数据Q?<<data<<std::endl; #endif // _PRINT Erase_(data, pRoot_); } /// 清空 void Clear() { #ifdef _PRINT std::cout<<"清空"<<std::endl; #endif // _PRINT // 销毁所有节? RecursDestroyNode_(pRoot_); pRoot_ = 0; } private: /// 创徏节点 static Node_* CreateNode_(const DataType& data) { return new Node_(data); } /// 销毁节? static void DestroyNode_(Node_* pNode) { delete pNode; } /// 递归销毁节? static void RecursDestroyNode_(Node_* pNode) { if (pNode) { // 先递归销毁子节点 RecursDestroyNode_(pNode->pLeftChild); RecursDestroyNode_(pNode->pRightChild); // 再销毁自w? DestroyNode_(pNode); } } /// 获取?wi)高度,U定I树(wi)高度?1 static int GetHeight_(const Node_* pRoot) { return pRoot ? pRoot->height : -1; } /** 计算?wi)高? 因ؓ(f)U定I树(wi)高度?1Q叶子高度ؓ(f)0Q所以树(wi)高度{于左右子树(wi)较高者高?1 */ static int CalcHeight_(const Node_* pRoot) { assert(pRoot); // 断言?wi)存? return std::max(GetHeight_(pRoot->pLeftChild), GetHeight_(pRoot->pRightChild)) + 1; } /** 与子?wi)进行单旋{ ׃旋{后节点将成ؓ(f)其原儿子的儿子,故节Ҏ(gu)针pNode会(x)指向其原儿子 pChild1指向被旋转的儿子成员指针QpChild2指向另一个儿子成员指? */ static void SingleRatateWithChild_(Node_*& pNode, Node_* Node_::* pChild1, Node_* Node_::* pChild2) { assert(pChild1 && pChild2); // 断言成员变量指针有效 assert(pNode); // 断言节点存在 // 节点的儿?重定向于儿子1的儿? Node_* pOriginalChild = pNode->*pChild1; pNode->*pChild1 = pOriginalChild->*pChild2; // 节点的原儿子1的儿?重定向于节点 pOriginalChild->*pChild2 = pNode; // 旋{之后需要重新计高? pNode->height = CalcHeight_(pNode); pOriginalChild->height = CalcHeight_(pOriginalChild); // pNode指向其原儿子 pNode = pOriginalChild; } /// 与左子树(wi)q行单旋? static void RotateWithLeftChild_(Node_*& pNode) { SingleRatateWithChild_(pNode, &Node_::pLeftChild, &Node_::pRightChild); } /// 与右子树(wi)q行单旋? static void RotateWithRightChild_(Node_*& pNode) { SingleRatateWithChild_(pNode, &Node_::pRightChild, &Node_::pLeftChild); } /** 与子?wi)进行双旋{ ׃旋{后节点将成ؓ(f)其原儿子的儿子,故节Ҏ(gu)针pNode会(x)指向其原儿子 pChild1指向被旋转的儿子成员指针QpChild2指向另一个儿子成员指? */ static void DoubleRatateWithChild_(Node_*& pNode, Node_* Node_::* pChild1, Node_* Node_::* pChild2) { assert(pChild1); // 断言成员变量指针有效 // 先对儿子q行一ơ旋? SingleRatateWithChild_(pNode->*pChild1, pChild2, pChild1); // 再对自己q行一ơ旋? SingleRatateWithChild_(pNode, pChild1, pChild2); } /// 与左子树(wi)q行双旋? static void DoubleRotateWithLeftChild_(Node_*& pNode) { DoubleRatateWithChild_(pNode, &Node_::pLeftChild, &Node_::pRightChild); } /// 与右子树(wi)q行双旋? static void DoubleRotateWithRightChild_(Node_*& pNode) { DoubleRatateWithChild_(pNode, &Node_::pRightChild, &Node_::pLeftChild); } /** 定左子?wi)是否过高(破坏了(jin)AVLq条gQ,是则与其q行旋{ 当在左子?wi)中插入新节点,或者在叛_?wi)中删除节点时? */ static void RatateWithLeftChildIfNeed_(Node_*& pNode) { // AVLq条g为左叛_?wi)高度相差不? // 左子?wi)比叛_?wi)?Q需要通过旋{来之重新达到AVLq条g if (2 == GetHeight_(pNode->pLeftChild) - GetHeight_(pNode->pRightChild)) { if (GetHeight_(pNode->pLeftChild->pLeftChild) > GetHeight_(pNode->pLeftChild->pRightChild)) { // 左子?wi)的左子树(wi)高于左子?wi)的右子树(wi)Q应当与左子?wi)进行单旋{ RotateWithLeftChild_(pNode); } else { // 左子?wi)的叛_?wi)高于左子?wi)的左子树(wi)Q应当与左子?wi)进行双旋{ DoubleRotateWithLeftChild_(pNode); } } } /** 定叛_?wi)是否过高(破坏了(jin)AVLq条gQ,是则与其q行旋{ 当在叛_?wi)中插入新节点,或者在左子?wi)中删除节点时? */ static void RatateWithRightChildIfNeed_(Node_*& pNode) { // AVLq条g为左叛_?wi)高度相差不? // 叛_?wi)比左子树(wi)?Q需要通过旋{来之重新达到AVLq条g if (2 == GetHeight_(pNode->pRightChild) - GetHeight_(pNode->pLeftChild)) { if (GetHeight_(pNode->pRightChild->pRightChild) > GetHeight_(pNode->pRightChild->pLeftChild)) { // 叛_?wi)的叛_?wi)高于右子?wi)的左子树(wi)Q应当与叛_?wi)进行单旋{ RotateWithRightChild_(pNode); } else { // 叛_?wi)的左子树(wi)高于右子?wi)的右子树(wi)Q应当与叛_?wi)进行双旋{ DoubleRotateWithRightChild_(pNode); } } } /** 插入新节点:(x) 如果当前节点为空则说明找C(jin)插入的位|,创徏新节点,q回插入成功 如果数据于当前节点数据则到左子?wi)中插入Q如果插入成功,可能需要旋转之重新^衡(左子?wi)过高?j)Q重新计高? 如果数据大于当前节点数据则道叛_?wi)中插入Q如果插入成功,可能需要旋转之重新^衡(叛_?wi)过高?j)Q重新计高? 如果数据{于当前节点数据则什么都不做Q返回插入失? */ static bool Insert_(const DataType& data, Node_*& pNode) { if (!pNode) { // 扑ֈ位置Q创? pNode = CreateNode_(data); assert(pNode); // 断言创徏节点成功 return true; } else if (data < pNode->data) { // 较?yu)的数据插入到左子?wi) if (Insert_(data, pNode->pLeftChild)) { // 成功插入新节? // 如果需要,则与左子?wi)进行旋转以l持AVLq条g RatateWithLeftChildIfNeed_(pNode); // 重新计算高度 pNode->height = CalcHeight_(pNode); return true; } } else if (data > pNode->data) { // 较大的数据插入到右子树(wi) if (Insert_(data, pNode->pRightChild)) { // 成功插入新节? // 如果需要,则与叛_?wi)进行旋转以l持AVLq条g RatateWithRightChildIfNeed_(pNode); // 重新计算高度 pNode->height = CalcHeight_(pNode); return true; } } else { // 重复数据Q什么也不做Q或者进行计敎ͼ(j) } return false; } /** 删除节点 查找被删除的节点Q? 如果当前节点为空则说明没有找到被删除的节点,q回删除p| 如果被删除的数据于节点数据Q则在节点的左子?wi)中查找q删除,如果删除成功Q可能需要旋转之重新^衡(叛_?wi)过高?j)Q重新计高? 如果被删除的数据大于节点数据Q则在节点的叛_?wi)中查找q删除,如果删除成功Q可能需要旋转之重新^衡(左子?wi)过高?j)Q重新计高? 如果被删除的数据{于节点数据Q则扑ֈ被删除的节点Q开始删除,q回删除成功 删除节点q程Q将被删除的节点作ؓ(f)标记节点Q? 如果标记节点存在左右双子?wi),利用叛_?wi)的最节点的数据替换此节Ҏ(gu)据,然后删除叛_?wi)的最节点:(x) 如果叛_?wi)有左子树(wi),从左子?wi)中找到最节点,其叛_?wi)提升一U,可能需要旋转其父节点重新qQ其父节点的叛_?wi)过高?j)Q重新计其父节炚w? 如果叛_?wi)没有左子?wi)Q此时右子树(wi)则即是最节点,其叛_?wi)提升一U? 可能需要旋转标记节点重新qQ标记节点的左子?wi)过高?j)Q重新计标记节炚w? 如果标记节点不存在左叛_子树(wi)Q删除标记节点,提升其子? */ static bool Erase_(const DataType& data, Node_*& pNode) { if (!pNode) { // 没有扑ֈ节点 return false; } else if (data < pNode->data) { // 节点较小Q在左子?wi)中删? if (Erase_(data, pNode->pLeftChild)) { // 成功删除节点 // 如果需要,则与叛_?wi)进行旋转以l持AVLq条g RatateWithRightChildIfNeed_(pNode); // 重新计算高度 pNode->height = CalcHeight_(pNode); return true; } } else if (data > pNode->data) { // 节点较大Q在叛_?wi)中删? if (Erase_(data, pNode->pRightChild)) { // 成功删除节点 // 如果需要,则与左子?wi)进行旋转以l持AVLq条g RatateWithLeftChildIfNeed_(pNode); // 重新计算高度 pNode->height = CalcHeight_(pNode); return true; } } else { // 扑ֈ?jin)需要被删除的节? if (pNode->pLeftChild && pNode->pRightChild) { // 存在双子?wi),利用叛_?wi)最节Ҏ(gu)换,q删除右子树(wi)最节? Node_* pMin = pNode->pRightChild; if (pNode->pRightChild->pLeftChild) { // 叛_?wi)存在左子?wi)Q从叛_?wi)的左子树(wi)中找最节? Node_* pMinParent = pNode->pRightChild; while (pMinParent->pLeftChild->pLeftChild) { pMinParent = pMinParent->pLeftChild; } pMin = pMinParent->pLeftChild; // 提升最节点的叛_? pMinParent->pLeftChild = pMin->pRightChild; // 如果需要,最节点的父节点则与其叛_?wi)进行旋转以l持AVLq条g RatateWithRightChildIfNeed_(pMinParent); // 重新计算最节点的父节点的高度 pMinParent->height = CalcHeight_(pMinParent); } else { // 叛_?wi)不存在左子树(wi),那么提升叛_?wi)的叛_? pNode->pRightChild = pNode->pRightChild->pRightChild; } // 用最节Ҏ(gu)? pNode->data = pMin->data; // 删除最节? DestroyNode_(pMin); // 如果需要,则与左子?wi)进行旋转以l持AVLq条g RatateWithLeftChildIfNeed_(pNode); // 重新计算高度 pNode->height = CalcHeight_(pNode); } else { // 不存在双子树(wi)Q则直接用儿子替? Node_* pTemp = pNode; pNode = pNode->pLeftChild ? pNode->pLeftChild : pNode->pRightChild; // 销毁节? DestroyNode_(pTemp); } return true; } return false; } }; // class AVLTree #ifdef _PRINT template<> void AVLTree<int>::Print() const { if (!pRoot_) { return; } PrinterContainer nextPrinters; // 下一层需要打印的对象集合 nextPrinters.push_back(PSharedPrinter(new NodePrinter(pRoot_, nextPrinters))); while (nextPrinters.end() != std::find_if(nextPrinters.begin(), nextPrinters.end(), std::mem_fn(&Printer::IsValid))) { auto printers(std::move(nextPrinters)); // 当前需要打印的对象集合 // 打印一? std::for_each(printers.begin(), printers.end(), std::mem_fn(&Printer::Print)); // 换行 std::cout<<std::endl; } } template<> size_t AVLTree<int>::CalcDataWidth_(int n) { if (0 == n) { return 1+2; // +2是ؓ(f)[]W号占位 } size_t ret = 2; // 2是ؓ(f)[]W号占位 if (0 > n) { // 复数Q添加符号位 ++ret; n = -n; } while (n) { ++ret; n /= 10; } return ret; } #endif // _PRINT } // namespace ghost #endif // AVL_TREE_H </pre> </div> <p> </p> <p>main.cpp文g</p> <p> </p><div id="w0cugio" class="cnblogs_Highlighter"> <pre class="brush:cpp;gutter:false;">#define _PRINT #include "AVLTree.h" #include <iostream> #include <ctime> /// 打印AVL? template<typename T> void PrintAVLTree(const ghost::AVLTree<T>& tree) { #ifdef _PRINT std::cout<<"--------------AVLTree--------------"<<std::endl; tree.Print(); std::cout<<"------------------------------------------"<<std::endl; #else std::cerr<<"未开启打印预处理器,不提供AVL?wi)的打印Q\n"; #endif // _PRINT } static const size_t TEST_DATA_COUNT = 10; // 试数据的个? static const size_t TEST_DATA_LOWER_LIMIT = 0; // 试数据的下? static const size_t TEST_DATA_UPPER_LIMIT = 10; // 试数据的上? /// 随机构造测试数? int BuildTestData() { return TEST_DATA_LOWER_LIMIT + rand() % (TEST_DATA_UPPER_LIMIT-TEST_DATA_LOWER_LIMIT); } int main() { srand((int)time(0)); ghost::AVLTree<int> tree; // 随机插入试数据 for (size_t i = 0; i < TEST_DATA_COUNT; ++i) { tree.Insert(BuildTestData()); PrintAVLTree(tree); } // 随机删除试数据 for (size_t i = 0; i < TEST_DATA_COUNT; ++i) { tree.Erase(BuildTestData()); PrintAVLTree(tree); } // tree.Insert(5); // PrintAVLTree(tree); // // tree.Insert(2); // PrintAVLTree(tree); // // tree.Insert(8); // PrintAVLTree(tree); // // tree.Insert(1); // PrintAVLTree(tree); // // tree.Insert(4); // PrintAVLTree(tree); // // tree.Insert(7); // PrintAVLTree(tree); // // tree.Insert(3); // PrintAVLTree(tree); // // tree.Insert(6); // 此时应触发一ơ单旋{ // PrintAVLTree(tree); return 0; } </pre> </div> <p> </p><img src="http://www.cnblogs.com/EvilGhost/aggbug/2083622.html?type=0" width="1" height="1" alt="" /><p>作? <a target="_blank">Evil.Ghost</a> 发表?2011-06-17 14:53 <a target="_blank">原文链接</a></p><p>评论: 0 <a target="_blank">查看评论</a> <a target="_blank">发表评论</a></p><hr /><p>最新新闻:(x)<br />· <a target="_blank">郭台铭赞沛_工h素质?iPhone生落户郑州</a><span style="color:gray">(2011-06-17 17:53)</span><br />· <a target="_blank">RIM首席q营官病休离?U季重返工作岗位</a><span style="color:gray">(2011-06-17 17:50)</span><br />· <a target="_blank">土豆|下半年赴纳斯达克上?融资1.5亿美?/a><span style="color:gray">(2011-06-17 17:48)</span><br />· <a target="_blank">传McAfee总裁蟩槽至初创公司ZQCEO</a><span style="color:gray">(2011-06-17 17:47)</span><br />· <a target="_blank">搜h功能正式上线 搜搜C֌化战略再升</a><span style="color:gray">(2011-06-17 17:46)</span><br /></p><p>~辑推荐Q?a target="_blank">像h脑一h?揭秘Kinect工作原理</a><br /></p><p>|站DQ?a target="_blank">博客园首?/a>  <a target="_blank">我的园子</a>  <a target="_blank">新闻</a>  <a target="_blank">闪存</a>  <a target="_blank">组</a>  <a target="_blank">博问</a>  <a target="_blank">知识?/a></p><br />文章来源:<a >http://www.cnblogs.com/EvilGhost/archive/2011/06/17/AVLTree.html</a><img src ="http://www.shnenglu.com/vivence/aggbug/148880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vivence/" target="_blank">EvilGhost</a> 2011-06-17 20:01 <a href="http://www.shnenglu.com/vivence/archive/2011/06/17/AVLTree.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一步一步实现自q模拟控gQ?Q——消息处?/title><link>http://www.shnenglu.com/vivence/archive/2011/04/24/Abstract_Widget_9.html</link><dc:creator>EvilGhost</dc:creator><author>EvilGhost</author><pubDate>Sun, 24 Apr 2011 02:48:00 GMT</pubDate><guid>http://www.shnenglu.com/vivence/archive/2011/04/24/Abstract_Widget_9.html</guid><wfw:comment>http://www.shnenglu.com/vivence/comments/144894.html</wfw:comment><comments>http://www.shnenglu.com/vivence/archive/2011/04/24/Abstract_Widget_9.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.shnenglu.com/vivence/comments/commentRss/144894.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vivence/services/trackbacks/144894.html</trackback:ping><description><![CDATA[ <p> </p><p>q次我们要lWidget增加一些状态,q其能够接受出消息处理扩展Q测试工E中实现?jin)一个按钮的消息处理扩展?/p> <p><strong>Widget状态:(x)</strong></p> <p>之前的控件只是绘制了(jin)一个边框,q且L?x)在H口中显C。实际上我们往往?x)希望能够让某个控g昄或者隐藏、可用或者不可用{等Q那么控件应该具有能够标识这些状态的属性,于是我们lWidget增加?jin)状态概c(din)?/p> <p> </p><div id="08wi0o0" class="cnblogs_code"> <pre><div><span style="color: #008000;">//</span><span style="color: #008000;"> 状态相?/span><span style="color: #008000;"><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;"> AddStates(size_t states);<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;"> SubStates(size_t states);<br></span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> CheckState(widget::StateBitField s);</span></div></pre> </div> <p> </p> <p>上面是状态相关的几个接口Q包括了(jin)增加状态组Q减状态组Q检状态。这里有个状态组的概念,是因为我状态用位域来实玎ͼ那么他们可以通过orq算来得到多个状态的集合Q我p个集合称为状态组?/p> <p> </p><div id="eagsww8" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">enum</span><span style="color: #000000;"> StateBitField{<br> STATE_VISIBLE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> </span><span style="color: #000000;"><<</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">, </span><span style="color: #008000;">//</span><span style="color: #008000;"> 控g可见Q决定控件是否被l制</span><span style="color: #008000;"><br></span><span style="color: #000000;"> STATE_ENABLE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> </span><span style="color: #000000;"><<</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">, </span><span style="color: #008000;">//</span><span style="color: #008000;"> 控g可用Q决定控件是否响应鼠标键盘消?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> STATE_TRANSPARENT </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> </span><span style="color: #000000;"><<</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">, </span><span style="color: #008000;">//</span><span style="color: #008000;"> 控g透明Q决定控件是否响应鼠标键盘消息以?qing)是否显Ctooltip</span><span style="color: #008000;"><br></span><span style="color: #000000;">};</span></div></pre> </div> <p> </p> <p>目前我给Widget定义?个状态:(x)可见、可用、透明。默认创建的Widget是不可见、不可用、不透明的,需要在创徏成功后手动设|,例如Q?/p> <p> </p><div id="8wiwgeu" class="cnblogs_code"> <pre><div><span style="color: #008000;">//</span><span style="color: #008000;"> 建立Ҏ(gu)?/span><span style="color: #008000;"><br></span><span style="color: #000000;">auto pRootWidget </span><span style="color: #000000;">=</span><span style="color: #000000;"> ghost::Widget::Create();<br>pRootWidget</span><span style="color: #000000;">-></span><span style="color: #000000;">AddStates(</span></div><div><span style="color: #000000;">  ghost::widget::STATE_VISIBLE</span><span style="color: #000000;">|</span><span style="color: #000000;">ghost::widget::STATE_ENABLE</span><span style="color: #000000;">|</span><span style="color: #000000;">ghost::widget::STATE_TRANSPARENT);</span></div></pre> </div> <p> </p> <p><strong>消息处理扩展Q?/strong></p> <p>通常对于控g来说Q没有消息处理就{于没有生命意义Q那么ؓ(f)Widgetd消息处理扩展意味着使Widgetzv来,q次我们来完成q个dQ期待Widgetzv来的那激动h?j)的一刅R和以往d扩展支持一P为扩展编写一个抽象基c,在Widget的关联对象管理中dq个扩展的关联处理,然后在Widget的SendMessage处理逻辑里增加对消息处理扩展的支持。那么我们的SendMessage实现变成了(jin)q样Q?/p> <p> </p><div id="cu80kqy" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">int</span><span style="color: #000000;"> Widget::SendMessage(widget::Message message, </span><span style="color: #0000ff;">void</span><span style="color: #000000;">*</span><span style="color: #000000;"> param1</span><span style="color: #008000;">/*</span><span style="color: #008000;"> = 0</span><span style="color: #008000;">*/</span><span style="color: #000000;">, </span><span style="color: #0000ff;">void</span><span style="color: #000000;">*</span><span style="color: #000000;"> param2</span><span style="color: #008000;">/*</span><span style="color: #008000;"> = 0</span><span style="color: #008000;">*/</span><span style="color: #000000;">)<br>{<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (</span><span style="color: #000000;">!</span><span style="color: #000000;">CheckState(widget::STATE_ENABLE))<br> {<br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 不响应鼠标键盘消?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ((widget::MSG_MOUSE_FIRST </span><span style="color: #000000;"><=</span><span style="color: #000000;"> message <br> </span><span style="color: #000000;">&&</span><span style="color: #000000;"> widget::MSG_MOUSE_LAST </span><span style="color: #000000;">>=</span><span style="color: #000000;"> message)<br> </span><span style="color: #000000;">||</span><span style="color: #000000;">(widget::MSG_KEY_FIRST </span><span style="color: #000000;"><=</span><span style="color: #000000;"> message <br> </span><span style="color: #000000;">&&</span><span style="color: #000000;"> widget::MSG_KEY_LAST </span><span style="color: #000000;">>=</span><span style="color: #000000;"> message))<br> {<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> widget::MSG_RESULT_NONE;<br> }<br> }<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (CheckState(widget::STATE_TRANSPARENT))<br> {<br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 不响应鼠标键盘消息,不显Ctooltip</span><span style="color: #008000;"><br></span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ((widget::MSG_MOUSE_FIRST </span><span style="color: #000000;"><=</span><span style="color: #000000;"> message <br> </span><span style="color: #000000;">&&</span><span style="color: #000000;"> widget::MSG_MOUSE_LAST </span><span style="color: #000000;">>=</span><span style="color: #000000;"> message)<br> </span><span style="color: #000000;">||</span><span style="color: #000000;">(widget::MSG_KEY_FIRST </span><span style="color: #000000;"><=</span><span style="color: #000000;"> message <br> </span><span style="color: #000000;">&&</span><span style="color: #000000;"> widget::MSG_KEY_LAST </span><span style="color: #000000;">>=</span><span style="color: #000000;"> message))<br> {<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> widget::MSG_RESULT_NONE;<br> }<br> }<br><br> auto pRelatedObject </span><span style="color: #000000;">=</span><span style="color: #000000;"> GetRelatedObject();<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (pRelatedObject)<br> {<br> auto pMessageHandle </span><span style="color: #000000;">=</span><span style="color: #000000;"> pRelatedObject</span><span style="color: #000000;">-></span><span style="color: #000000;">GetMessageHandle();<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (pMessageHandle)<br> {<br> </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> handled </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br> </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> res </span><span style="color: #000000;">=</span><span style="color: #000000;"> pMessageHandle</span><span style="color: #000000;">-></span><span style="color: #000000;">OnMessage(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">, message, param1, param2, handled);<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (handled)<br> {<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> res;<br> }<br> }<br> }<br><br> </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (message)<br> {<br>#ifdef _DEBUG<br> </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> widget::MSG_DRAW:<br> {<br> HBRUSH hBrush </span><span style="color: #000000;">=</span><span style="color: #000000;"> ::CreateSolidBrush(pImpl_</span><span style="color: #000000;">-></span><span style="color: #000000;">testFrameColor_);<br> ::FrameRect((HDC)param1, </span><span style="color: #000000;">&</span><span style="color: #000000;">pImpl_</span><span style="color: #000000;">-></span><span style="color: #000000;">absoluteRect_, hBrush);<br> ::DeleteObject(hBrush);<br> }<br> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">#endif</span><span style="color: #000000;"> </span><span style="color: #008000;">//</span><span style="color: #008000;"> _DEBUG</span><span style="color: #000000;"><br> </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> widget::MSG_HIT_TEST:<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (::PtInRect(</span><span style="color: #000000;">&</span><span style="color: #000000;">pImpl_</span><span style="color: #000000;">-></span><span style="color: #000000;">absoluteRect_, </span><span style="color: #000000;">*</span><span style="color: #000000;">(</span><span style="color: #0000ff;">const</span><span style="color: #000000;"> POINT</span><span style="color: #000000;">*</span><span style="color: #000000;">)param1))<br> {<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">~</span><span style="color: #000000;">widget::MSG_RESULT_NONE;<br> }<br> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br> }<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> widget::MSG_RESULT_NONE;<br>}</span></div></pre> </div> <p> </p> <p>我多ơ提C(jin)tooltipQ但是我们这ơƈ没有为Widget增加其支持,它将在后面被加入到Widget中来。可以看到这里处理有Ҏ(gu)息处理扩展的支持Q还有状态对于消息的影响。这里出C(jin)一个MSG_HIT_TESTQ这是一个新增的消息。这ơؓ(f)Widgetd?jin)很多的消息Q包括了(jin)鼠标、键盘等Q要鼠标消息准的发送给正确的控Ӟ那么点击试是必不可的Q这个MSG_HIT_TEST消息则是用于控g处理点击试的?/p> <p><strong>点击试Q?/strong></p> <p>当容器生了(jin)鼠标事g的时候,我们能够得到鼠标热点在容器中的坐标。前面我也多ơ提刎ͼ模拟控g是容器中的某个区域,那么当鼠标热点位于某个控件所处的区域的时候,那么q个鼠标事g我们应当交p个控件进行处理(q是通常情况Q也有可能某个控件作为透明控gQ不接受M点击试Q。于是我们便通过点击试QHitTestQ这个访问接口来扑ֈ应该处理鼠标事g的控件。在扑ֈ控g之后Q我们还坐标映到?jin)控件的相对坐标p,q样控g可以以自n的相对位|来处理鼠标事g?jin)?/p> <p>当然Q这ơ的内容非常多,包括坐标映射、区域映,捕获鼠标的控件、活动控件、焦Ҏ(gu)件等概念都未提到Q但在代码中q是能够看到q些概念的。如果一一介绍Q那文章׃(x)非常冗长Q也?x)Widget实现q展~慢Q因此我通常都会(x)省略一些内容,q些内容也就只能通过代码阅读来得C(jin)?/p> <p><strong>按钮Q?/strong></p> <p>Z(jin)试我们q次实现的内容,我们~写?jin)一个按钮的消息处理扩展。简单v见,我们使其不生命令、不l制文本Q仅仅只是展C对鼠标消息的处理和状态的变化而已?/p> <p>?img src="http://pic002.cnblogs.com/images/2011/95718/2011042410321772.png"></p> <p>我们原先测试代码中的中间那个控件关联了(jin)按钮的消息处理,那么它就UCؓ(f)?jin)一个按钮控件了(jin)。我们可以将鼠标Ud它上面点ȝ看会(x)发生什么?/p> <p><span style="font-size: 18pt;"><strong><a >下蝲试工程代码</a> </strong></span>因ؓ(f)我一直都在用VC10来编写WidgetQ也用到?jin)一些新的特性,所以子啊这ơ的试工程我生成了(jin)一份release下的E序Q没有VC10的h臛_能够看到其运行效果?/p><img src="http://www.cnblogs.com/EvilGhost/aggbug/2026106.html?type=0" width="1" height="1" alt=""><p>作? <a target="_blank">Evil.Ghost</a> 发表?2011-04-24 10:48 <a target="_blank">原文链接</a></p><p>评论: 0 <a target="_blank">查看评论</a> <a target="_blank">发表评论</a></p><hr><p>最新新闻:(x)<br>· <a target="_blank">Zh赴美上市(jng)Q无奈大杂烩 挟资本对阵Facebook</a><span style="color:gray">(2011-04-24 11:07)</span><br>· <a target="_blank">位置隐私事gq展QGoogle 回应Q华?dng)街日报质?/a><span style="color:gray">(2011-04-24 10:19)</span><br>· <a target="_blank">消息U苹果正试T-Mobile版iPhone</a><span style="color:gray">(2011-04-24 10:04)</span><br>· <a target="_blank">报告U?020q全球云计算规模?410亿美?/a><span style="color:gray">(2011-04-24 10:03)</span><br>· <a target="_blank">沃尔玛在国加州试在线商品配送服?/a><span style="color:gray">(2011-04-24 09:40)</span><br></p><p>~辑推荐Q?a target="_blank">南方都市(jng)报:(x)|络正在改写我们的思维Q?/a><br></p><p>|站DQ?a target="_blank">博客园首?/a>  <a target="_blank">我的园子</a>  <a target="_blank">新闻</a>  <a target="_blank">闪存</a>  <a target="_blank">组</a>  <a target="_blank">博问</a>  <a target="_blank">知识?/a></p><img src ="http://www.shnenglu.com/vivence/aggbug/144894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vivence/" target="_blank">EvilGhost</a> 2011-04-24 10:48 <a href="http://www.shnenglu.com/vivence/archive/2011/04/24/Abstract_Widget_9.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一步一步实现自q模拟控gQ?Q——重?/title><link>http://www.shnenglu.com/vivence/archive/2011/04/19/Abstract_Widget_8.html</link><dc:creator>EvilGhost</dc:creator><author>EvilGhost</author><pubDate>Tue, 19 Apr 2011 12:06:00 GMT</pubDate><guid>http://www.shnenglu.com/vivence/archive/2011/04/19/Abstract_Widget_8.html</guid><wfw:comment>http://www.shnenglu.com/vivence/comments/144690.html</wfw:comment><comments>http://www.shnenglu.com/vivence/archive/2011/04/19/Abstract_Widget_8.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vivence/comments/commentRss/144690.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vivence/services/trackbacks/144690.html</trackback:ping><description><![CDATA[ <p> </p><p>模拟控g已经Z(jin)雏ŞQ是应该重构一下了(jin)?/p> <p><strong>新概念:(x)</strong></p> <p>其实说是新概念也不尽?dng)只是在这几步的实C可以发现Q这个模拟控件框架中有两个大的概念:(x)容器和控件。我们一直一来都说的是容器窗口,但是其实q是个可以上升的概念。容器容U一个控件体p,也就是关联一个根控gQ那么它?yu)有点类g我们的根控g?jin)。但是容器由必须实现和具体窗口和控g的交互,所以我们不能简单的根控g作ؓ(f)容器。ƈ且对于某些特D的实现Q我们还可能需要对容器的某些功能加以扩展,所以我们这ơ重构ؓ(f)容器抽象?jin)一个基c,q实C(jin)一个窗口容器?/p> <p> </p><div id="eyceq0i" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">class</span><span style="color: #000000;"> Container : </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Monopolistic{<br> </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> Monopolistic::pWidget_;<br> </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> Monopolistic::GetWidget;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br> Container();<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #000000;">~</span><span style="color: #000000;">Container();<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br> Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> GetRootWidget() </span><span style="color: #0000ff;">const</span><span style="color: #000000;">{</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> GetWidget();}<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> IsValid() </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Invalidate(</span><span style="color: #0000ff;">const</span><span style="color: #000000;"> RECT</span><span style="color: #000000;">&</span><span style="color: #000000;"> rect){} </span><span style="color: #008000;">//</span><span style="color: #008000;"> 无效化容器矩形区?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Invalidate(HRGN hRgn){} </span><span style="color: #008000;">//</span><span style="color: #008000;"> 无效化容器不规则区域</span><span style="color: #008000;"><br></span><span style="color: #000000;"> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Invalidate(){} </span><span style="color: #008000;">//</span><span style="color: #008000;"> 无效化整个容器区?/span><span style="color: #008000;"><br></span><span style="color: #000000;">};</span></div></pre> </div> <p> </p> <p><strong>解耦:(x)</strong></p> <p>到目前ؓ(f)止,我们的容器驱动和控g之间h十分紧密的耦合关系Q生命周期耦合Q,q次重构打算此解耦,使得我们的容器创建和控g体系创徏互不相关Q仅仅通过一ơ操作来使得他们兌或者解除关联?/p> <p> </p><div id="w8ei0eo" class="cnblogs_code"> <pre><div><span style="color: #008000;">//</span><span style="color: #008000;"> 建立H口容器</span><span style="color: #008000;"><br></span><span style="color: #000000;">ghost::widget::WindowContainer container;<br>container.AttachWindow(hWnd);<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;"> 建立Ҏ(gu)?/span><span style="color: #008000;"><br></span><span style="color: #000000;">auto pRootWidget </span><span style="color: #000000;">=</span><span style="color: #000000;"> ghost::Widget::Create();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;"> 兌容器</span><span style="color: #008000;"><br></span><span style="color: #000000;">pRootWidget</span><span style="color: #000000;">-></span><span style="color: #000000;">CreateRelationship(</span><span style="color: #000000;">&</span><span style="color: #000000;">container);</span></div></pre> </div> <p> </p> <p><strong>减少c:(x)</strong></p> <p>q次q有一个大的变化就是将原先的一些概念融合成?jin)新的概念?x)驱动、消息过滤、消息映都融合C(jin)容器当中Q因三个概念和具体容器关pȝ密,所以将他们q行融合以减我们的cL目?/p> <p><strong>收获Q?/strong></p> <p>q次重构建立?jin)容器这个概忉|们是有一定收L(fng)Q原先我们无法访问控件所兌的容器,现在可以?jin)。原先控件的容器实现不易扩展Q现在可以通过l承来扩展(例如layeredH口Q,甚至可以为容器实现特有的l制机制Q例如用openglQ以后我们抽象了(jin)l制概念便可以看刎ͼ目前q只能用GDIQ?/p> <p>q次没有什么新的内Ҏ(gu)加,但重构还是有必要的,周期性重构利于我们对整个框架的管理,在重构过E中较容易发现和修改BUG?/p> <p><span style="font-size: 18pt;"><strong><a >下蝲试工程源码</a></strong></span></p><img src="http://www.cnblogs.com/EvilGhost/aggbug/2021452.html?type=1" width="1" height="1" alt=""><p>作? <a target="_blank">Evil.Ghost</a> 发表?2011-04-19 20:06 <a target="_blank">原文链接</a></p><p>评论: 0 <a target="_blank">查看评论</a> <a target="_blank">发表评论</a></p><hr><p>最新新闻:(x)<br>· <a target="_blank">满|炮轰分众哄抬广告h(hun)Q江南春承诺调?/a><span style="color:gray">(2011-04-20 18:08)</span><br>· <a target="_blank">周`:(x)技术颠?商业颠覆?60颠覆?jin)行?/a><span style="color:gray">(2011-04-20 18:03)</span><br>· <a target="_blank">XJPQ网购冷?rn)期恐成一U空?/a><span style="color:gray">(2011-04-20 18:00)</span><br>· <a target="_blank">L非:(x)一?两制 三宣?/a><span style="color:gray">(2011-04-20 17:24)</span><br>· <a target="_blank">微YQChrome和Opera存在HTML5执行漏洞</a><span style="color:gray">(2011-04-20 17:20)</span><br></p><p>~辑推荐Q?a target="_blank">再谈“我是怎么招聘E序员的”</a><br></p><p>|站DQ?a target="_blank">博客园首?/a>  <a target="_blank">我的园子</a>  <a target="_blank">新闻</a>  <a target="_blank">闪存</a>  <a target="_blank">组</a>  <a target="_blank">博问</a>  <a target="_blank">知识?/a></p><img src ="http://www.shnenglu.com/vivence/aggbug/144690.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vivence/" target="_blank">EvilGhost</a> 2011-04-19 20:06 <a href="http://www.shnenglu.com/vivence/archive/2011/04/19/Abstract_Widget_8.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一步一步实现自q模拟控gQ?Q——可扩展布局子控?/title><link>http://www.shnenglu.com/vivence/archive/2011/04/12/Abstract_Widget_7.html</link><dc:creator>EvilGhost</dc:creator><author>EvilGhost</author><pubDate>Tue, 12 Apr 2011 13:17:00 GMT</pubDate><guid>http://www.shnenglu.com/vivence/archive/2011/04/12/Abstract_Widget_7.html</guid><wfw:comment>http://www.shnenglu.com/vivence/comments/144069.html</wfw:comment><comments>http://www.shnenglu.com/vivence/archive/2011/04/12/Abstract_Widget_7.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vivence/comments/commentRss/144069.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vivence/services/trackbacks/144069.html</trackback:ping><description><![CDATA[ <p> </p><p><strong>可扩展:(x)</strong></p> <p>要得我们的控g具备一定的可扩展性,那么必定?x)生控件之外的对象作?f)扩展Qƈ且这个对象对于控件来说是可插入可U除的。用于扩展的对象和控件之间应该具备一定的关系Q例如:(x)1-1Q?-nQn-n{。我们将q样的对象关pL象了(jin)出来Q称之ؓ(f)对象关系?/p> <p><strong>对象关系Q?/strong></p> <p>一个对象可能允许单个对象对其进行关联,也可能允许多个对象对其进行关联,甚至可能卛_许多个对象进行关联,但却Ҏ(gu)些类型的对象限制为只能单个的对其q行兌。我们将q些对象抽象为:(x)单对象关p, 多对象关p,独占式对象关p(q是对多对象关系的一U扩展)(j)?/p> <p><img src="http://pic002.cnblogs.com/images/2011/95718/2011041220560533.png"></p> <p> </p><div id="8q00yyg" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">class</span><span style="color: #000000;"> ObjectRelationship{<br></span><span style="color: #0000ff;">protected</span><span style="color: #000000;">:<br> ObjectRelationship(){}<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #000000;">~</span><span style="color: #000000;">ObjectRelationship(){}<br><br></span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br> ObjectRelationship(</span><span style="color: #0000ff;">const</span><span style="color: #000000;"> ObjectRelationship</span><span style="color: #000000;">&</span><span style="color: #000000;">);<br> ObjectRelationship</span><span style="color: #000000;">&</span><span style="color: #000000;"> </span><span style="color: #0000ff;">operator</span><span style="color: #000000;"> </span><span style="color: #000000;">=</span><span style="color: #000000;">(</span><span style="color: #0000ff;">const</span><span style="color: #000000;"> ObjectRelationship</span><span style="color: #000000;">&</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> CreateRelationship(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> pObject)<br> {<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (</span><span style="color: #000000;">!</span><span style="color: #000000;">DoCreateRelationship_(pObject))<br> {<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br> }<br> RelationshipCreated_(pObject);<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br> }<br> </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> DestroyRelationship(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> pObject)<br> {<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (</span><span style="color: #000000;">!</span><span style="color: #000000;">DoDestroyRelationship_(pObject))<br> {<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br> }<br> RelationshipDestroyed_(pObject);<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br> }<br><br></span><span style="color: #0000ff;">protected</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> DoCreateRelationship_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #008000;">/*</span><span style="color: #008000;">pObject</span><span style="color: #008000;">*/</span><span style="color: #000000;">) </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> DoDestroyRelationship_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #008000;">/*</span><span style="color: #008000;">pObject</span><span style="color: #008000;">*/</span><span style="color: #000000;">) </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;<br><br></span><span style="color: #0000ff;">protected</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> RelationshipCreated_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #008000;">/*</span><span style="color: #008000;">pObject</span><span style="color: #008000;">*/</span><span style="color: #000000;">){}<br> </span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> RelationshipDestroyed_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #008000;">/*</span><span style="color: #008000;">pObject</span><span style="color: #008000;">*/</span><span style="color: #000000;">){}<br>};</span></div></pre> </div> <p> </p> <p>q是对象关系基类Q接口只有两个:(x)建立关系Q销毁关pR?/p> <p>单对象关p, 多对象关p都z于这个基c,而独占式对象关系是实现的两个帮助函数来辅助多对象关系。我们的Widgetz于多对象关系Q它便具备了(jin)和多个对象徏立关pȝ能力Q我们将有不同的扩展兌到WidgetQ。ؓ(f)?jin)便于管理和扩展Q我们将所有和W(xu)idget兌的扩展放C个对象当中进行管理,W(xu)idget和扩展之间的关系建立和销毁都委托q个对象来进行?/p> <p> </p><div id="0mewsuk" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">class</span><span style="color: #000000;"> LayoutChildren;<br><br>typedef std::</span><span style="color: #0000ff;">set</span><span style="color: #000000;"><</span><span style="color: #000000;">LayoutChildren</span><span style="color: #000000;">*></span><span style="color: #000000;"> LayoutChildrenSet;<br><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;"> RelatedObject{<br> Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> pWidget_; </span><span style="color: #008000;">//</span><span style="color: #008000;"> 控g<br><br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 控g所兌的对?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> LayoutChildrenSet layoutChildrens_; </span><span style="color: #008000;">//</span><span style="color: #008000;"> 可以有多个布局理理不同的子控g布局</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br> friend </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Widget;<br> </span><span style="color: #0000ff;">explicit</span><span style="color: #000000;"> RelatedObject(Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> pWidget);<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">: </span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取兌对象的接?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> LayoutChildrenSet</span><span style="color: #000000;">&</span><span style="color: #000000;"> GetLayoutChildrens() </span><span style="color: #0000ff;">const</span><span style="color: #000000;">{</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> layoutChildrens_;}<br><br></span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> RelationshipCreated_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> pObject);<br> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> RelationshipDestroyed_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> pObject);<br>};</span></div></pre> </div> <p> </p> <p> </p><div id="y0wgiw0" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">void</span><span style="color: #000000;"> Widget::RelationshipCreated_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> pObject)<br>{<br> GetRelatedObject()</span><span style="color: #000000;">-></span><span style="color: #000000;">RelationshipCreated_(pObject);<br>}<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Widget::RelationshipDestroyed_(ObjectRelationship</span><span style="color: #000000;">*</span><span style="color: #000000;"> pObject)<br>{<br> GetRelatedObject()</span><span style="color: #000000;">-></span><span style="color: #000000;">RelationshipDestroyed_(pObject);<br>}</span></div></pre> </div> <p> </p> <p><strong>布局子控Ӟ(x)</strong></p> <p>我们为Widgtd?jin)一个布局子控件的接口Q当控g自n区域变化的时候会(x)自动的调用这个接口,当然用户也可以随时调用此接口对子控gq行布局。此接口负责操作传递给扩展Q我们考虑到子控g的布局{略可能?x)各有不同,因此我们能够兌多个布局子控件扩展到WidgetQ这使得我们能够以不同的布局{略来区别对待不同的子控件?/p> <p> </p><div id="ywwq800" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">void</span><span style="color: #000000;"> Widget::LayoutChildren()<br>{<br> auto pRelatedObject </span><span style="color: #000000;">=</span><span style="color: #000000;"> GetRelatedObject();<br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (pRelatedObject)<br> {<br> </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> widget::LayoutChildrenSet</span><span style="color: #000000;">&</span><span style="color: #000000;"> layoutChildrens </span><span style="color: #000000;">=</span><span style="color: #000000;"> pRelatedObject</span><span style="color: #000000;">-></span><span style="color: #000000;">GetLayoutChildrens();<br> std::for_each(<br> layoutChildrens.begin(), layoutChildrens.end(), <br> std::bind(std::mem_fn(</span><span style="color: #000000;">&</span><span style="color: #000000;">widget::LayoutChildren::Layout), std::placeholders::_1, </span><span style="color: #0000ff;">this</span><span style="color: #000000;">));<br> }<br>}</span></div></pre> </div> <p> </p> <p>我们创徏?jin)一个边~式布局自控件扩展进行测试,试效果在测试工E中能够看到?/p> <p><strong><span style="font-size: 18pt;"><a >下蝲试工程源码</a></span></strong></p><img src="http://www.cnblogs.com/EvilGhost/aggbug/2014101.html?type=1" width="1" height="1" alt=""><p>作? <a target="_blank">Evil.Ghost</a> 发表?2011-04-12 21:17 <a target="_blank">原文链接</a></p><p>评论: 0 <a target="_blank">查看评论</a> <a target="_blank">发表评论</a></p><hr><p>最新新闻:(x)<br>· <a target="_blank">消息UiPad 3仍不采用Retina屏幕</a><span style="color:gray">(2011-04-12 20:29)</span><br>· <a target="_blank">nginx 1.0.0发布</a><span style="color:gray">(2011-04-12 20:27)</span><br>· <a target="_blank">2011Mozilla开发者大?x)亮?gu)先看</a><span style="color:gray">(2011-04-12 20:24)</span><br>· <a target="_blank">亚马逊成hW一大广告主 每年2亿美元(图)(j)</a><span style="color:gray">(2011-04-12 20:16)</span><br>· <a target="_blank">?ji)城OpenFeint中国首秀Q与联通推手游</a><span style="color:gray">(2011-04-12 20:13)</span><br></p><p>~辑推荐Q?a target="_blank">体验Managed Extensibility Framework_֦的设?/a><br></p><p>|站DQ?a target="_blank">博客园首?/a>  <a target="_blank">我的园子</a>  <a target="_blank">新闻</a>  <a target="_blank">闪存</a>  <a target="_blank">组</a>  <a target="_blank">博问</a>  <a target="_blank">知识?/a></p><img src ="http://www.shnenglu.com/vivence/aggbug/144069.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vivence/" target="_blank">EvilGhost</a> 2011-04-12 21:17 <a href="http://www.shnenglu.com/vivence/archive/2011/04/12/Abstract_Widget_7.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一步一步实现自q模拟控gQ?Q——控件树(wi)?qing)控件区?/title><link>http://www.shnenglu.com/vivence/archive/2011/04/09/Abstract_Widget_6.html</link><dc:creator>EvilGhost</dc:creator><author>EvilGhost</author><pubDate>Sat, 09 Apr 2011 11:05:00 GMT</pubDate><guid>http://www.shnenglu.com/vivence/archive/2011/04/09/Abstract_Widget_6.html</guid><wfw:comment>http://www.shnenglu.com/vivence/comments/143840.html</wfw:comment><comments>http://www.shnenglu.com/vivence/archive/2011/04/09/Abstract_Widget_6.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vivence/comments/commentRss/143840.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vivence/services/trackbacks/143840.html</trackback:ping><description><![CDATA[ <p> </p><p><strong>控g?/strong></p> <p><a target="_parent" >一步一步实现自q模拟控gQ?Q?/a>中的图上我们可以看到Q我们的控g体系其实是一个控件树(wi)。每一个窗口关联一个根控gQ所有控仉在这个根控g之下Q父控g包容q管理子控gQ那么我们的Widget应该是一个树(wi)l点。一个树(wi)l点臛_有对Parent和Chilren的设|和讉K接口Q?/p> <p> </p><div id="000msqc" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">void</span><span style="color: #000000;"> SetParent(Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> pNewParent);<br>Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> GetParent() </span><span style="color: #0000ff;">const</span><span style="color: #000000;">;<br><br></span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> InsertChild(Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> pChild);<br></span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> RemoveChild(Widget</span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> pChild);</span></div></pre> </div> <p> </p> <p>在父控g销毁的时候它要负责销毁其下所有的子控ӞcMH口销毁也?x)销毁其子窗口)(j)Q?/p> <p> </p><div id="0uya8qg" class="cnblogs_code"> <pre><div><span style="color: #000000;">Widget::</span><span style="color: #000000;">~</span><span style="color: #000000;">Widget()<br>{<br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 销毁所有子控g</span><span style="color: #008000;"><br></span><span style="color: #000000;"> WidgetSet temp(std::move(pImpl_</span><span style="color: #000000;">-></span><span style="color: #000000;">children_));<br> std::for_each(temp.begin(), temp.end(), std::mem_fn(</span><span style="color: #000000;">&</span><span style="color: #000000;">Widget::Destroy));<br><br> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (IsRoot()) <br> {<br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 作ؓ(f)Ҏ(gu)Ӟ同时销毁驱?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> delete pImpl_</span><span style="color: #000000;">-></span><span style="color: #000000;">pDriver_;<br> }<br> </span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br> {<br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 不是Ҏ(gu)Ӟ则脱ȝ控g</span><span style="color: #008000;"><br></span><span style="color: #000000;"> SetParent(</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br> }<br><br> delete pImpl_;<br>}</span></div></pre> </div> <p> </p> <p>实现中我们用std::set来保存子控gQ这样便于防止子控g重复讄Q也便于U除子控Ӟ~点是不能对子控gq行排序。如果以后我们提供控件的z-order概念Q那么我们就?x)用能够进行排序的容器来容U_控g?/p> <p><strong>控g区域Q?/strong></p> <p>windows下,我们使用RECTl构来保存控件自w相对于H口客户区的区域Q那么窗口客户区寸改变时也是我们控gq行布局的时机,那我们就要在消息qo(h)中处理WM_SIZE消息?jin)?/p> <p> </p><div id="me08esq" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">case</span><span style="color: #000000;"> WM_SIZE: </span><span style="color: #008000;">//</span><span style="color: #008000;"> 让根控g适应真个客户?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> {<br> RECT clientRect;<br> ::GetClientRect(param.hWnd, </span><span style="color: #000000;">&</span><span style="color: #000000;">clientRect);<br> pRootWidget</span><span style="color: #000000;">-></span><span style="color: #000000;">SetAbsoluteRect(clientRect, </span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br> }<br> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;</span></div></pre> </div> <p> </p> <p>我们控件的布局交由父控件管理,也就是说我们只需要更新根控g区域便可。根控g负责对其子控件进行布局Q如此递归?/p> <p><strong>控g更新Q?/strong></p> <p>当控件区域改变了(jin)Q那么相应的其显CZ应相应的q行更新Q所以我们的SetAbsoluteRect接口有一个update参数用于控制是否让窗口生无效区域激zȝ制?/p> <p> </p><div id="8sum800" class="cnblogs_code"> <pre><div><span style="color: #008000;">//</span><span style="color: #008000;"> 此处的update作用是控制是否立x新显C?br></span><span style="color: #008000;">//</span><span style="color: #008000;"> 因ؓ(f)模拟控g只是H口客户区的一个区域,当区域改变时应该产生原区域和新区域orq算后区域的脏矩?br></span><span style="color: #008000;">//</span><span style="color: #008000;"> 以得窗口去重绘q部分区域?br></span><span style="color: #008000;">//</span><span style="color: #008000;"> 可能有些扚w性质的操作会(x)在操作多个控件后q行整体更新Q所以在对单个控件设|新区域的时候可能不?x)想要更新?br></span><span style="color: #008000;">//</span><span style="color: #008000;"> 所以才加上q个是否立即更新的开兟?/span><span style="color: #008000;"><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;"> SetAbsoluteRect(</span><span style="color: #0000ff;">const</span><span style="color: #000000;"> RECT</span><span style="color: #000000;">&</span><span style="color: #000000;"> rect, </span><span style="color: #0000ff;">bool</span><span style="color: #000000;"> update </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">true</span><span style="color: #000000;">);</span></div></pre> </div> <p> </p> <p>既然提到?jin)绘Ӟ那么我们也应该让我们的控件展C在H口上了(jin)?/p> <p><strong>控gl制Q?/strong></p> <p>通常我们的窗口程序都是在WM_PAINT消息中进行绘Ӟ我们的控件系l当然也需要处理此消息?/p> <p> </p><div id="m0g8aqo" class="cnblogs_code"> <pre><div><span style="color: #0000ff;">case</span><span style="color: #000000;"> WM_PAINT:<br> {<br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 使用内存DC来缓冲绘?br> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 目前没有计算脏矩形区?/span><span style="color: #008000;"><br></span><span style="color: #000000;"> wnd_msg_assistant::OnPaint opAssistant(param.hWnd);<br> pRootWidget</span><span style="color: #000000;">-></span><span style="color: #000000;">Draw(opAssistant.GetMemDC());<br> }<br> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> S_OK;</span></div></pre> </div> <p> </p> <p>q里引入?jin)一个辅助对象帮助我们生内存DCQ优化我们的l制效率。我们直接return?jin)这个消息,也就是说我们这个消息过滤掉了(jin)。前面WM_SIZE和W(xu)M_DESTROY我们都没有过滤,只是在这个时机对控gq行?jin)通知或者操作。之所以要qo(h)WM_PAINT消息是因为外部的l制和控件的l制难以协调Q那么我们干脆就接管?jin)窗口客户区的绘制?jin)?/p> <p>当然Q控件也需要负责绘制其子控Ӟ那么Draw接口中便?x)调用子控g的DrawQ如此递归使得每个控g都能够得以绘制?/p> <p><strong>首次直观的看到我们的控gQ?/strong></p> <p>我们在调试版本中Qؓ(f)每个控g生成?jin)一个随机的颜色Q根据控件的区域l制?jin)其?gu)Q这h们就W一ơ直观的在窗口中看到?jin)我们的控g?/p> <p>?img src="http://pic002.cnblogs.com/images/2011/95718/2011040918550120.png"></p> <p>q不?qing)待Q具有了(jin)区域的控Ӟ我们已经急切的想要对其布局q行控制Q绘制进行定制了(jin)。布局控制和绘制定制当然属于扩展部分,那么下面将要引入我们的扩展体系?jin),请期待?/p> <p><span style="font-size: 18pt;"><strong><a >下蝲试工程源码</a></strong></span></p><img src="http://www.cnblogs.com/EvilGhost/aggbug/2010698.html?type=1" width="1" height="1" alt=""><p>作? <a target="_blank">Evil.Ghost</a> 发表?2011-04-09 19:05 <a target="_blank">原文链接</a></p><p>评论: 0 <a target="_blank">查看评论</a> <a target="_blank">发表评论</a></p><hr><p>最新新闻:(x)<br>· <a target="_blank">Ҏ(gu)iPad 2通过3C认证 最?月国内上?/a><span style="color:gray">(2011-04-10 09:18)</span><br>· <a target="_blank">盲目依赖iPhone{工具导?英国驴友q\?/a><span style="color:gray">(2011-04-10 09:14)</span><br>· <a target="_blank">谈Q想担QCEO的话Q最好是去苹果工作,其次是微软,再才是Google</a><span style="color:gray">(2011-04-10 08:26)</span><br>· <a target="_blank">腾讯徏立新数据中心(j)Q规模ؓ(f)Ҏ(gu)的两?/a><span style="color:gray">(2011-04-10 08:25)</span><br>· <a target="_blank">轻量化的微型博客Tumblr</a><span style="color:gray">(2011-04-10 08:03)</span><br></p><p>~辑推荐Q?a target="_blank">非战之罪Q从怸Office谈v</a><br></p><p>|站DQ?a target="_blank">博客园首?/a>  <a target="_blank">我的园子</a>  <a target="_blank">新闻</a>  <a target="_blank">闪存</a>  <a target="_blank">组</a>  <a target="_blank">博问</a>  <a target="_blank">知识?/a></p><img src ="http://www.shnenglu.com/vivence/aggbug/143840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vivence/" target="_blank">EvilGhost</a> 2011-04-09 19:05 <a href="http://www.shnenglu.com/vivence/archive/2011/04/09/Abstract_Widget_6.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一步一步实现自q模拟控gQ?Q——隐藏类http://www.shnenglu.com/vivence/archive/2011/04/07/Abstract_Widget_5.htmlEvilGhostEvilGhostThu, 07 Apr 2011 12:55:00 GMThttp://www.shnenglu.com/vivence/archive/2011/04/07/Abstract_Widget_5.htmlhttp://www.shnenglu.com/vivence/comments/143841.htmlhttp://www.shnenglu.com/vivence/archive/2011/04/07/Abstract_Widget_5.html#Feedback0http://www.shnenglu.com/vivence/comments/commentRss/143841.htmlhttp://www.shnenglu.com/vivence/services/trackbacks/143841.html 

隐藏驱动c:(x)

Z(jin)让用h更简单的使用接口Q我们需要把不必要的东西q行一定的隐藏。前面我提到WidgetDriver对于用户来说是不兛_(j)的东西,那么我们将其进行隐藏?/p>

  Ҏ(gu)1Q?/strong>

  WidgetDriver攑ֈWidget.cpp中,q样的隐藏方式是最严密的,对于用户来说完全看不到WidgetDriver。但是随着我们的实现膨胀Q这?x)让我们的Widget.cpp变得非常臃肿?/p>

  Ҏ(gu)2Q?/strong>

  不改变文件结构,WidgetDriverU有化,通过友元声明使得只有Widgetcd象能够访问WidgetDriver。这L(fng)戯然能够看到WidgetDriverq个cd义,但是却无法用,q样对于代码的结构组l也更有利?/p>

我采用了(jin)Ҏ(gu)2

class Driver_{
friend
class Widget;

DriverImpl_
* pImpl_;

private:
explicit Driver_(HWND hWnd);
~Driver_();
Driver_(
const Driver_&);
Driver_
& operator =(const Driver_&);

private:
void SetRootWidget(Widget* pRootWidget);
HWND GetContainerWindow()
const;
Widget
* GetRootWidget() const;
};

 

因ؓ(f)我们隐藏?jin)WidgetDriverQ那么它的职能就能够q行化。前面提到的Ҏ(gu)件和W(xu)idgetDriver之间的关pL们就能够改ؓ(f)当方面控制了(jin)。于是我WidgetDriver攑ֈ?jin)根控g中进行管理,我们只需要操作根控g便可?/p>

Widget::Widget(HWND hWnd)
: pImpl_(
new WidgetImpl)
{
pImpl_
->pDriver = new widget::Driver_(hWnd);
pImpl_
->pDriver->SetRootWidget(this);
}

Widget::
~Widget()
{
if (IsRoot())
{
delete pImpl_
->pDriver;
}
delete pImpl_;
}

 

前面我们都没有提到应该何时结束我们的pȝQ但是我们的pȝ生命周期和窗口是息息相关的,在窗口销毁的时候那么和q个H口相关联的控g体系应该销毁。于是我们对消息qo(h)器做?jin)一点点改动Q?/p>

LRESULT MessageFilter::Filter(const Param& param, Widget* pRootWidget)
{
assert(param.originalProc);
assert(pRootWidget);
#ifdef _DEBUG
std::stringstream ss;
ss
<<"H口消息: "<<std::showbase<<std::hex<<param.message<<" q入Widget消息qo(h)Q\r\n";
::OutputDebugStringA(ss.str().c_str());
#endif // _DEBUG

LRESULT ret
= ::CallWindowProc(
param.originalProc,
param.hWnd,
param.message,
param.wParam,
param.lParam);

if (WM_DESTROY == param.message)
{
// 销毁根控g
pRootWidget->Destroy();
}

return ret;
}
我们在接收到WM_DESTROYH口消息的时候销毁根控gQ根控g析构的时候又?x)销毁控仉动,控g驱动析构的时候会(x)解除和窗口的兌?p> 

下一步我们便要开始对我们的控件进行设计了(jin)Q我们自始至l都控件抽象ؓ(f)H口客户区的一个区域,所以说我们q不打算使用l承来扩展控件。后面会(x)看到我们使用插入式的扩展Q这L(fng)方式具备动态替换的能力甚至q能一个扩展共享给多个控g使用?/p>

下蝲试工程源码

作? Evil.Ghost 发表?2011-04-07 20:55 原文链接

评论: 0 查看评论 发表评论


最新新闻:(x)
· Ҏ(gu)iPad 2通过3C认证 最?月国内上?/a>(2011-04-10 09:18)
·
盲目依赖iPhone{工具导?英国驴友q\?/a>(2011-04-10 09:14)
·
谈Q想担QCEO的话Q最好是去苹果工作,其次是微软,再才是Google(2011-04-10 08:26)
· 腾讯徏立新数据中心(j)Q规模ؓ(f)Ҏ(gu)的两?/a>(2011-04-10 08:25)
·
轻量化的微型博客Tumblr(2011-04-10 08:03)

~辑推荐Q?a target="_blank">非战之罪Q从怸Office谈v

|站DQ?a target="_blank">博客园首?/a>  我的园子  新闻  闪存    博问  知识?/a>



EvilGhost 2011-04-07 20:55 发表评论
]]>
一步一步实现自q模拟控gQ?Q——根控ghttp://www.shnenglu.com/vivence/archive/2011/04/06/Abstract_Widget_4.htmlEvilGhostEvilGhostWed, 06 Apr 2011 13:21:00 GMThttp://www.shnenglu.com/vivence/archive/2011/04/06/Abstract_Widget_4.htmlhttp://www.shnenglu.com/vivence/comments/143842.htmlhttp://www.shnenglu.com/vivence/archive/2011/04/06/Abstract_Widget_4.html#Feedback0http://www.shnenglu.com/vivence/comments/commentRss/143842.htmlhttp://www.shnenglu.com/vivence/services/trackbacks/143842.html 

H口、控仉动、根控g之间的关p?/strong>

前面我们已经说了(jin)Q一个窗口只能关联一个控仉动,一个控仉动也同样对应一个根控g。ؓ(f)什么呢Q因为我们的驱动需要作用于一个控件体p,一个控件体pd有一个根控gQ这个根控g理?jin)整个窗口的客户区。这h们才能在q个Ҏ(gu)件下创徏L的控Ӟq活动在H口客户区?/p>

生命周期控制

Z上面的关p,控g驱动和根控g的生命息息相养I那么我们让其怺制约。既然是他们自n怺制约Q那么用户就不应该管理其生命周期Q我们特意引入一个简单的对象池来理Qƈ用访问控制来避免外部直接构造?/p>

private:
explicit Widget(widget::Driver* pDriver);
~Widget();
Widget(
const Widget&);
Widget
& operator =(const Widget&);

// 让对象池能够创徏Widget对象
friend class ObjectPool<Widget>;
#pragma warning(push)
#pragma warning(disable:4396)
friend
void std::_Destroy(Widget _FARQ *);
#pragma warning(pop)

public:
static Widget* Create(HWND hWnd); // 创徏Ҏ(gu)?/span>
void Destroy();

 

我们提供?jin)一个静(rn)态接口Create用于创徏Ҏ(gu)Ӟ可以注意到的一Ҏ(gu)参数是窗口句柄。其实用户对于什么驱动、什么过滤的都不兛_(j)Q用户只兛_(j)控g体系Q所以说我们可以通过q个接口透明的创建根lgQ实C?x)自动的去驱动此H口?/p>

Widget* Widget::Create(HWND hWnd)
{
return GetWidgetPool_().Construct(widget::Driver::Create(hWnd));
}

 

驱动构造时?x)创建根控gQ析构时销毁根控g

Driver::Driver(HWND hWnd)
: pImpl_(
new DriverImpl(hWnd))
{
// 创徏Ҏ(gu)?/span>
pImpl_->SetRootWidget(Widget::Create_(this));
}
~DriverImpl()
{
// 销毁根控g
Widget* pOldRootWidget = GetRootWidget();
pRootWidget_
= 0;
if (pOldRootWidget)
{
pOldRootWidget
->Destroy();
}
}

 

同样Q根控g析构时也销毁控仉?/p>

Widget::~Widget()
{
if (IsRoot())
{
pImpl_
->GetDriver()->Destroy();
}
delete pImpl_;
}

 

q样Q用户其实有两个入口可以q入到我们的控gpȝQ一个是通过控g驱动Q一个是通过控g本n。我们提倡用户不d?j)控仉动。那么甚x们可以隐藏Driverq个c,目前我没有这样做?/p>

下蝲试工程源码

作? Evil.Ghost 发表?2011-04-06 21:21 原文链接

评论: 0 查看评论 发表评论


最新新闻:(x)
· Ҏ(gu)iPad 2通过3C认证 最?月国内上?/a>(2011-04-10 09:18)
·
盲目依赖iPhone{工具导?英国驴友q\?/a>(2011-04-10 09:14)
·
谈Q想担QCEO的话Q最好是去苹果工作,其次是微软,再才是Google(2011-04-10 08:26)
· 腾讯徏立新数据中心(j)Q规模ؓ(f)Ҏ(gu)的两?/a>(2011-04-10 08:25)
·
轻量化的微型博客Tumblr(2011-04-10 08:03)

~辑推荐Q?a target="_blank">非战之罪Q从怸Office谈v

|站DQ?a target="_blank">博客园首?/a>  我的园子  新闻  闪存    博问  知识?/a>



EvilGhost 2011-04-06 21:21 发表评论
]]>
一步一步实现自q模拟控gQ?Q——Widget驱动http://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_3.htmlEvilGhostEvilGhostSun, 03 Apr 2011 05:56:00 GMThttp://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_3.htmlhttp://www.shnenglu.com/vivence/comments/143843.htmlhttp://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_3.html#Feedback0http://www.shnenglu.com/vivence/comments/commentRss/143843.htmlhttp://www.shnenglu.com/vivence/services/trackbacks/143843.html 

前面我们利用现有的微软ATL实现的thunk已经为我们截L(fng)口消息做好了(jin)准备Q此L们应该编写我们的Widget驱动的初步实C(jin)?/p>

利用thunk对窗口消息过E进行子cdQ那么窗口消息就?x)先入到我们的Widget驱动对象QW(xu)idget驱动对象负责消息传递给消息qo(h)器。现在我们的消息qo(h)器还未实玎ͼ于是我们打印?jin)进入消息过滤器的消息IDg观察消息的流动情c(din)?/p>

以下是我们的Widget驱动c,我们其攑օ?jin)一个名为widget的名字空间中Q以后我们widget相关的名字都?x)放入到q个名字I间中?/p>

class DriverImpl;

class Driver{
DriverImpl
* pImpl_;

public:
explicit Driver(HWND hWnd);
~Driver();

private:
Driver(
const Driver&);
Driver
& operator =(const Driver&);

public:
inline HWND GetContainerWindow()
const;
};

因ؓ(f)Driver的实现我们ƈ不关?j),所以我们将其实现进行了(jin)一个隐藏,q样也便于我们修改其实现方式。Drivercd象要求用于构造它的窗口句柄必Mؓ(f)有效的窗口句柄,q且每个H口句柄只能被驱动一ơ,所以我们在调试版本中做?jin)断a来约束我们的~码Q在发布版本中不?x)做M判断?/p>

#ifdef _DEBUG
assert(::IsWindow(hContainerWnd_));
// 不能多次驱动同一H口
assert(GetContainerWindows_().insert(hContainerWnd_).second);
#endif // _DEBUG
此处有一?span style="color: #ff0000;">GetContainerWindows_()是一个只在调试版本中才有的实玎ͼ其返回一个std::set<HWND>&?rn)态对象引用,用于保存已经被驱动的H口句柄Q我们断aH口句柄未曾保存到这个set之中?/span>

现在我们实现的Driver接口非常单,只有一个构造接口和查询光动的H口句柄的接口,昄没有M可以控制驱动或者解除驱动的Z(x)Q此处我们先放一放,因ؓ(f)q在以后?x)涉及(qing)到q个驱动所兌的Widget体系的一些问题?/p>

通过thunk截获的窗口消息将?x)进入到Driver实现中,Driver的功能仅仅是作ؓ(f)Widget的驱动(也就是消息驱动)(j)Q它不负责Q何消息的处理Q所以这个窗口过E在截获到窗口消息后立即交由消息qo(h)处理?/p>

LRESULT WndProc_(UINT message, WPARAM wParam, LPARAM lParam)
{
// q行消息qo(h)
MessageFilter::Param param;
param.hWnd
= hContainerWnd_;
param.originalProc
= originalProc_;
param.message
= message;
param.wParam
= wParam;
param.lParam
= lParam;
return MessageFilter::Filter(param);
}

q里消息qo(h)器的实现不在q一D讨Z中,所以我们简单的以一个类?rn)态接口来作ؓ(f)qo(h)入口?/p>

好了(jin)Q我们到q里已经开启了(jin)Widget内核的运作系l的实现Q从试工程中感受得C定的体验?jin)?/p>

下蝲试工程源码

作? Evil.Ghost 发表?2011-04-03 13:56 原文链接

评论: 0 查看评论 发表评论


最新新闻:(x)
· Ҏ(gu)iPad 2通过3C认证 最?月国内上?/a>(2011-04-10 09:18)
·
盲目依赖iPhone{工具导?英国驴友q\?/a>(2011-04-10 09:14)
·
谈Q想担QCEO的话Q最好是去苹果工作,其次是微软,再才是Google(2011-04-10 08:26)
· 腾讯徏立新数据中心(j)Q规模ؓ(f)Ҏ(gu)的两?/a>(2011-04-10 08:25)
·
轻量化的微型博客Tumblr(2011-04-10 08:03)

~辑推荐Q?a target="_blank">非战之罪Q从怸Office谈v

|站DQ?a target="_blank">博客园首?/a>  我的园子  新闻  闪存    博问  知识?/a>



EvilGhost 2011-04-03 13:56 发表评论
]]>
一步一步实现自q模拟控gQ?Q——窗口过Ethunkhttp://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_2.htmlEvilGhostEvilGhostSun, 03 Apr 2011 05:55:00 GMThttp://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_2.htmlhttp://www.shnenglu.com/vivence/comments/143844.htmlhttp://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_2.html#Feedback0http://www.shnenglu.com/vivence/comments/commentRss/143844.htmlhttp://www.shnenglu.com/vivence/services/trackbacks/143844.html 

实现Window Proc ThunkQ?/strong>

好像水泵一P我们的系l也需要一个܇——消息܇Q也是前面图上的Message Driver。这个Driver的可以依靠一个Window Proc Thunk来截L(fng)口消息,那么我们得先实现一个Window Proc Thunk?/p>

q里我选择的方法是拿现成的代码来用Q微软ATL框架中提供有thunk的实玎ͼ我将其提取出来稍加修改就能ؓ(f)我们所用了(jin)?/p>

以下是其实现的一点代码片D:(x)

void* __stdcall AllocStdCallThunk(void);
void __stdcall FreeStdCallThunk(void*);

#pragma pack(push, 1)
class StdCallThunk_{
DWORD mov_;
// mov dword ptr [esp+0x4], this_ (esp+0x4是W一个参?
DWORD this_; //
BYTE jmp_; // jmp proc
DWORD relproc_; // relative jmp

public:
bool Init(DWORD_PTR proc, void* pThis)
{
mov_
= 0x042444C7; //C7 44 24 0C
this_ = PtrToUlong(pThis);
jmp_
= 0xe9;
relproc_
= DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(StdCallThunk_)));
// 用自w更新指令缓?/span>
return ::FlushInstructionCache(::GetCurrentProcess(), this, sizeof(StdCallThunk_)) ? true : false;
}
// 某些thunk动态的Z码分配内?/span>
void* GetCodeAddress()
{
return this;
}
void* operator new(size_t)
{
return AllocStdCallThunk();
}
void operator delete(void* pThunk)
{
FreeStdCallThunk(pThunk);
}
};
#pragma pack(pop)

下蝲试工程源码

作? Evil.Ghost 发表?2011-04-03 13:55 原文链接

评论: 0 查看评论 发表评论


最新新闻:(x)
· Ҏ(gu)iPad 2通过3C认证 最?月国内上?/a>(2011-04-10 09:18)
·
盲目依赖iPhone{工具导?英国驴友q\?/a>(2011-04-10 09:14)
·
谈Q想担QCEO的话Q最好是去苹果工作,其次是微软,再才是Google(2011-04-10 08:26)
· 腾讯徏立新数据中心(j)Q规模ؓ(f)Ҏ(gu)的两?/a>(2011-04-10 08:25)
·
轻量化的微型博客Tumblr(2011-04-10 08:03)

~辑推荐Q?a target="_blank">非战之罪Q从怸Office谈v

|站DQ?a target="_blank">博客园首?/a>  我的园子  新闻  闪存    博问  知识?/a>



EvilGhost 2011-04-03 13:55 发表评论
]]>
一步一步实现自q模拟控gQ?Q——消息驱动设?/title><link>http://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_1.html</link><dc:creator>EvilGhost</dc:creator><author>EvilGhost</author><pubDate>Sun, 03 Apr 2011 05:53:00 GMT</pubDate><guid>http://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_1.html</guid><wfw:comment>http://www.shnenglu.com/vivence/comments/143845.html</wfw:comment><comments>http://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_1.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vivence/comments/commentRss/143845.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vivence/services/trackbacks/143845.html</trackback:ping><description><![CDATA[ <p> </p><p><strong>目标Q?/strong></p> <p>实现一套windows下简单且可扩展的抽象模拟控g内核?/p> <p><strong>抽象模拟控gQ?/strong></p> <p>我们windowspȝ的窗口客户区作ؓ(f)模拟控g的容器,每个模拟控g是其中的一个抽象矩形区域,q且能够模拟控gq行递归嵌套。控件支持基本的鼠标和键盘消息,能够在窗口大改变时q行布局?/p> <p><strong>分析Q?/strong></p> <p>因ؓ(f)我们要实现的是抽象的模拟控gQ不是真正的H口控gQ那么就需要将H口消息适时z֏到相应控件。下面以一个图来规划窗口消息的向?/p> <p><a ><img height="471" width="660" src="http://images.cnblogs.com/cnblogs_com/EvilGhost/201103/201103302107388838.png" alt="Abstract Widget" border="0" title="Abstract Widget" style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;"></a></p> <p>在这个图上我们可以看到除?jin)我们的控g体系以外q需要实现几个核?j)模块来驱动控g。他们分别是Q消息驱动、消息过滤、消息{换。消息驱动通过某种Ҏ(gu)截获H口消息Q图上用thunkQ,然后窗口消息交l过滤器q行qo(h)Q因为模拟控件不是所有窗口消息都感兴)(j)Q消息过滤出控g感兴的消息交给消息转换器,其他消息交还l窗口的原有H口q程q行处理Q?strong>此处要注意的是消息过滤后控g感兴的消息不会(x)再回到原H口q程</strong>Q。消息{换器窗口消息{换ؓ(f)控g消息Q之所以要q行转换是因为控件体pd能支持的消息pȝ?x)有别于H口消息Q也可能需要进行坐标映等?/p> <p>图上q能看到Q我们的控g是能够递归嵌套的。每个窗口对应一个根控gQ所有的控g都是在这个根lg之中的。ؓ(f)?jin)要能够使用H口的整个客户区Q那么根lg所处区域就是窗口的整个客户区?/p> <p>现在我们要开始进行设计了(jin)Q设计过E中引入代码,代码随着设计的演化进行演化,最lŞ成我们这个简单且可扩展的抽象模拟控g核心(j)?/p><img src="http://www.cnblogs.com/EvilGhost/aggbug/2000310.html?type=1" width="1" height="1" alt=""><p>作? <a target="_blank">Evil.Ghost</a> 发表?2011-04-03 13:53 <a target="_blank">原文链接</a></p><p>评论: 0 <a target="_blank">查看评论</a> <a target="_blank">发表评论</a></p><hr><p>最新新闻:(x)<br>· <a target="_blank">Ҏ(gu)iPad 2通过3C认证 最?月国内上?/a><span style="color:gray">(2011-04-10 09:18)</span><br>· <a target="_blank">盲目依赖iPhone{工具导?英国驴友q\?/a><span style="color:gray">(2011-04-10 09:14)</span><br>· <a target="_blank">谈Q想担QCEO的话Q最好是去苹果工作,其次是微软,再才是Google</a><span style="color:gray">(2011-04-10 08:26)</span><br>· <a target="_blank">腾讯徏立新数据中心(j)Q规模ؓ(f)Ҏ(gu)的两?/a><span style="color:gray">(2011-04-10 08:25)</span><br>· <a target="_blank">轻量化的微型博客Tumblr</a><span style="color:gray">(2011-04-10 08:03)</span><br></p><p>~辑推荐Q?a target="_blank">非战之罪Q从怸Office谈v</a><br></p><p>|站DQ?a target="_blank">博客园首?/a>  <a target="_blank">我的园子</a>  <a target="_blank">新闻</a>  <a target="_blank">闪存</a>  <a target="_blank">组</a>  <a target="_blank">博问</a>  <a target="_blank">知识?/a></p><img src ="http://www.shnenglu.com/vivence/aggbug/143845.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vivence/" target="_blank">EvilGhost</a> 2011-04-03 13:53 <a href="http://www.shnenglu.com/vivence/archive/2011/04/03/Abstract_Widget_1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.pf925.cn" target="_blank">þ91Ʒ91þ鶹</a>| <a href="http://www.qikan99.cn" target="_blank">þþþþþƷο</a>| <a href="http://www.reepee.cn" target="_blank">ŷ˼Ծþ</a>| <a href="http://www.ttwa.com.cn" target="_blank">޾Ʒþþ</a>| <a href="http://www.xfqbaby.cn" target="_blank">ٸִִˬëƬþú </a>| <a href="http://www.99j9.cn" target="_blank">˾þۺ</a>| <a href="http://www.myswiss.cn" target="_blank">þþþAVרJN </a>| <a href="http://www.grzzc358.cn" target="_blank"> þۺϾɫۺϾ99</a>| <a href="http://www.rqhsjc.cn" target="_blank">Ʒһþ</a>| <a href="http://www.deiden.cn" target="_blank">ƷþӰԺ</a>| <a href="http://www.amazinghall.com.cn" target="_blank">Ʒþþþþ12 </a>| <a href="http://www.wxbdd.cn" target="_blank">þۺۺϾþúݺݺ97ɫ88</a>| <a href="http://www.youk6.cn" target="_blank">ɫۺϾþ88ɫۺ</a>| <a href="http://www.ryftw.cn" target="_blank">þù㽶һƷ</a>| <a href="http://www.sme369.cn" target="_blank">ŷþþþþ</a>| <a href="http://www.xgpzgs8.cn" target="_blank">þ×Ʒþþþþ</a>| <a href="http://www.003kd.cn" target="_blank">þùƷһ</a>| <a href="http://www.iningyu.cn" target="_blank">Ӱһþþþó˾Ʒۺ </a>| <a href="http://www.189oa.cn" target="_blank">þþþAVۺ </a>| <a href="http://www.egpk.cn" target="_blank">þþþһ</a>| <a href="http://www.cad77.cn" target="_blank">þþþŮۺ</a>| <a href="http://www.woweikeji.cn" target="_blank">޾ƷƵþþ</a>| <a href="http://www.magifts.cn" target="_blank">ɫۺϾþþþר</a>| <a href="http://www.stargaze3s.cn" target="_blank">þþƷһ</a>| <a href="http://www.awo6.cn" target="_blank">ɫۺϾþ</a>| <a href="http://www.hongyunjp.cn" target="_blank">97þþþ</a>| <a href="http://www.g8360.cn" target="_blank">¾þþþa</a>| <a href="http://www.masterflexpump.com.cn" target="_blank">˾þں2019</a>| <a href="http://www.xinkecheng.net.cn" target="_blank">þþWWW˳ɾƷ</a>| <a href="http://www.dt175.cn" target="_blank">þҹɫƷվ</a>| <a href="http://www.837666.cn" target="_blank">þþƷר </a>| <a href="http://www.ssc629.cn" target="_blank">ݹ97þ÷ѹۿ</a>| <a href="http://www.hanshigu.cn" target="_blank">ɫۺϾþĻ</a>| <a href="http://www.baochong.com.cn" target="_blank">ɫۺϾþĻ</a>| <a href="http://www.spiralstar.com.cn" target="_blank">þsmȤ</a>| <a href="http://www.dqezb.cn" target="_blank">˾þۺ</a>| <a href="http://www.tril.cn" target="_blank">ݺݾþ</a>| <a href="http://www.dingbay.cn" target="_blank">㽶aaþëƬ</a>| <a href="http://www.stargaze3s.cn" target="_blank">99þҹɫƷվ</a>| <a href="http://www.starlight-caraccessories.cn" target="_blank">ŷۺϾþþ </a>| <a href="http://www.jw62.cn" target="_blank">Ʒþþø</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>