求一个易语言自绘模块的女孩

下次自动登录
现在的位置:
    最近因工作需求,需要自绘CTreeCtrl。由于原来从来没有自绘过,开始在网上搜索资料,查询(因此本文有些知识可能不全面,或许还有更好的办法来实现,还请大家多多指教。)经过一段时间的编写,终于写好了。在此,感谢网友提供的实例参考。
先贴上效果图,如果觉得还不错,那就继续往下看吧。如果觉得不行的,请飘过。
如何你看见这句话我会很高兴,因为至少我写的东西对你还是有一点点的吸引了。在此谢过!
很好,那现在让我们来说说为什么要自绘CTreeCtrl。我总结了以下2点需要自绘的情况。
1.当系统自带的树形控件已不满足我们的要求时,我们需要自绘。就像上图一样我们需要在后面显示我们额外的图标。
2.当你是一个追求界面美观的人时,我们需要自绘
我们需要自绘CTreeCtrl控件,我们就必须先了解一下自绘的方法,
CTreeCtrl自绘有2种方法可以实现。
第一种:通过从写NM_CUSTORMDRAW反射消息实现自绘。
第二种: 通过重写ON_PAINT实现自绘。
二种方法都是通过继承CTreeCtrl类,然后重写虚函数实现。
  下面分别介绍每一种的方法:
第一种:通过从写NM_CUSTORMDRAW反射消息实现自绘。从这个消息的英文单词我们翻译过来就是自定义绘制。当CTreeCtrl控件需要绘制就会触发这个消息。需要注意的是这个函数被调用的时候只是绘制了当前的某一个节点,意思就是当我们的CTreeCtrl有10个节点需要绘制的时候这个函数就需要调用10次。
这个是函数原型
void CMyTreeCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
这个函数会给我们传入一个pNMHDR指针,这个指针有我们很关心的数据,如当前的HDC,RECT,和当前的节点信息,但是必须要通过转换。下面是转换语句。
NMTVCUSTOMDRAW *ptvTreeCtrl=(NMTVCUSTOMDRAW *)pNMHDR
可能有的朋友会问为什么需要类型转换了,这是由于在我们的程序中收到NM_CUSTORMDRAW消息的不止CTreeCtrl一个,其它的控件也能收到,这里我们我为了区分是哪个控件收到的消息所以我们需要对应的类型转换。下面是常见控件的类型转换类型。
All other supported controls
很明显我们根据上面的图一眼就能看出CTreeCtrl对应的类型是NMTVCUSTOMDRAW。
下面我们在来看看我们最关心的NMTVCUSTOMDRAW 结构里面存的是什么数据。
NMTVCUSTOMDRAW结构定义:
typedef struct tagNMTVCUSTOMDRAW {
NMCUSTOMDRAW nmcd;//包含控件的基本信息(见下表)
COLORREF clrText;//节点的文本颜色
COLORREF clrTextBk;//文本背景色
}NMTVCUSTOMDRAW, *LPNMTVCUSTOMDRAW;
NMCUSTOMDRAW结构定义:
typedef struct tagNMCUSTOMDRAWINFO {
NMHDR hdr;//跟pNMHDR一样,我基本没用到
DWORD dwDrawStage;//绘画段,某项被檫出前,后,绘制前,后
  HDC hdc;//控件的设备上下文句柄
RECT rc;//要绘制的区域
DWORD dwItemSpec;//树控件不需要这个变量
UINT uItemState;//项的状态,只要是点击选中
LPARAM lItemlParam //项关联的数据,通过SetItemData函数设置的。
}NMCUSTOMDRAW, FAR* LPNMCUSTOMDRAW;
uItemState项的状态(来自MSDN)
Specifies the current item state. It can be a combination of the following values.
Value              Description
CDIS_CHECKED       The item is checked.  项被核记了
CDIS_DEFAULT       The item is in its default state. 默认状态
CDIS_DISABLED      The item is disabled.  项被禁止了
CDIS_FOCUS         The item is in focus.  项具有焦点
CDIS_GRAYED        The item is grayed.   项为灰颜色,
CDIS_HOT           The item is currently under the pointer (hot).  鼠标当前停留在这个项上
CDIS_SELECTED      The item is selected.  项被选中了
以上就是我们自绘需要知道的数据结构,如果你了解这些数据结构所代表的意思,那下面我们就可以开始绘制了。
NMCUSTOMDRAW消息自绘,使你可以决定在什么绘画端(就是NMCUSTOMDRAW 中的DWORD dwDrawStage)来绘制,比较常用的是在绘制前的阶段来绘制,如果你只是用了这种方法来绘制画,那么恭喜你选择对了一半,但是绘制失败了,因为你将什么也看不见。不急,让我们慢慢给你说明原因,因为你在绘制前的阶段绘制了,紧接这系统还会调用一次默认绘制,那么你原来的绘制就被覆盖了。
正确的方法是在绘制前绘制,然后过滤点系统的默认绘制,使之不在调用。这样我们所绘制就能看见了。于是乎在我们的OnNMCustomdraw函数中多了一下几句代码。(过滤系统的默认绘制)
if (lpnmcd -&nmcd.dwDrawStage == CDDS_PREPAINT)   
{        *pResult = CDRF_NOTIFYITEMDRAW;              }    else if (lpnmcd-&nmcd.dwDrawStage == CDDS_ITEMPREPAINT)      {    //自定义绘制  *pResult = CDRF_DODEFAULT;         
很好,现在你已经知道了绘制的基本方法了,那么接下来你就可以加上你自己的绘制了。
大致思路如下。
获取当前绘制节点的信息。如:节点状态,节点区域,节点文字等信息
需要掌握的函数:
CTreeCtrl::GetItemRect
BOOL GetItemRect( HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly );
如果项是可视的则返回非零值,以及包含在lpRect中的边界矩形。否则,返回0和没有被初始化的lpRect。
hItem    一个tree view项的句柄。
lpRect    指向一个用来接收边界矩形的RECT结构的指针。其中的坐标是相对于该tree view控件的左上角的。
bTextOnly    如果这个参数是非零值,则边界矩形值包括项的文本。否则,它包括该项在tree view控件所占据的整个一行。
CTreeCtrl::GetItemText
CString GetItemText( HTREEITEM hItem )
返回值:返回一个包含该项的文本的CString对象。
hItem    要获取其文本的项的句柄。
添加自己的绘制函数,如绘制图片,绘制文字等。
CTreeCtrl::ItemHasChildren
BOOL ItemHasChildren( HTREEITEM hItem );
如果由hItem指定的tree项有子项则返回非零值;否则返回0。
hItem    一个tree项的句柄。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如过你讨厌记住以上的这么多数据,那么恭喜你,你可以继续网下看,下面介绍另一种实现自绘的方法.通过重写ON_PAINT消息来实现自绘,也是我最终实现自绘的方法。因为我发现通过上面的方法来实现自绘解决不了我的问题。闪烁和热点,也许是我自己的能力有限。大家可以分享一下你们是如何解决我遇到的问题的。
我们获取树形控件的数据结构和DC,然后我们自己来定义绘制的规则。这里就可以发挥你的DIY兴趣了,想怎么画就怎么画。
很好,下面让我们进入另一种方法的介绍
首先我们要明白ON_PAINT消息在什么情况下触发,在win32程序中,当窗口需要重绘的时候会触发ON_PAINT消息,还有一种情况就是我们自己手动触发,手动触发的消息有两种,第一种是调用窗口无效函数Invalidate(FALSE),第2种是手动发送wm_paint消息。
明白了这个我们才知道我们以后需要窗口重绘的时候怎么处理,这里说点题外话,原来在做扫雷游戏的时候,鼠标单击之后要过20多毫秒才有反应,后来查了半天原因才发现是带用重绘的问题,因为我开始单机之后没有立即调用重绘,而是没隔50毫秒调用一次。
我们通过重写ON_PAINT消息就能获取当前窗口的DC,在这里我们就是整个树形控件的DC,不向上面那种方法一样只获取到树形控件某节点的DC,获取整个DC要比上面那种方法操作方便一些。
下面是onpaint方法:
void CMyCtreeCtrl::OnPaint()
CPaintDC dc(this); //这句就是获取绘制的DC
现在有了DC我们就可以绘制了,在这里我们为了让它绘制的时候不闪烁我们用双缓冲,于是乎我们有了下面的代码。
[cpp] view plaincopy
CPaintDC dc(this); // device context for painting 
GetClientRect(&m_ClientRect); 
CDC MemeDc; 
MemeDc.CreateCompatibleDC(&dc); 
bitmap.CreateCompatibleBitmap(&dc, m_ClientRect.Width(), m_ClientRect.Height()); 
CBitmap *pOldBitmap = MemeDc.SelectObject(&bitmap); 
DrawBack(&MemeDc); 
DrawItem(&MemeDc);  [cpp] view plaincopy
dc.BitBlt( m_ClientRect.left, m_ClientRect.top, m_ClientRect.Width(), m_ClientRect.Height(), &MemeDc, 0, 0,SRCCOPY);  MemeDc.SelectObject(pOldBitmap);  MemeDc.DeleteDC();  [cpp] view plaincopy
可以看见我们在函数中首先绘制了背景然后再背景上绘制了控件。具体的函数实现请看下面的介绍。  在这里我们基本的东西已经具备了现在我们就差数据了,首先我们要实现我们最开始的那种效果,我们需要定义一个结构体来存储这些数据。
struct TREE_STRUCT
int s_FirstI                  //第一张图片的信息
int s_SecondI            //第二张图片的信息
int s_ThreeI                //第三张图片的信息
int s_FourI                  //第四张图片的信息
COLORREF s_TextC   //文字的颜色
int    s_PeopleN              //人的数目
CString  s_ItemS                //每一项的文字
CString  s_StrU                   //每一项对应的URL地址
我们在定义一个map
map &HTREEITEM,TREE_STRUCT&  m_mapT 这是为了我们以后的绘制和判断热点用。
有了数据结构,我们现在就可以插入数据使之成为一颗拥有节点的数,这个插入我们也需要自己重写,因为插入的数据是我们自己定义的。
[cpp] view plaincopy
HTREEITEM CMyCtreeCtrl::InsertItemEx(TREE_STRUCT pStruct,HTREEITEM lparent,HTREEITEM  lpFont )//插入项  {      HTREEITEM tempTreeI      CS      str.Format(&%s(%d人)&,pStruct.s_ItemStr,pStruct.s_PeopleNum);      tempTreeItem = InsertItem(str,lparent,lpFont);      m_mapTree.insert(pair&HTREEITEM,TREE_STRUCT&(tempTreeItem,pStruct));      return  tempTreeI    } 
下面是绘制树形控件的具体实现
[cpp] view plaincopy
void CMyCtreeCtrl::DrawItem(CDC* pDc)  { 
HTREEITEM currentItem,parentI//当前的句柄,和它的父节点的句柄 
DWORD    treeS// 数的类型 
CRect    itemR//每一项的区域 
int      itemS//某项的状态 
//    //True:表示是需要高亮    
ImageAttributes alphaA  
alphaAttribut.SetColorKey(Color::Fuchsia,Color::Fuchsia);    
treeStyle =:: GetWindowLong( m_hWnd, GWL_STYLE );  [cpp] view plaincopy
currentItem = GetFirstVisibleItem();//获取第一个课可见的项  do   { 
if (GetItemRect(currentItem,itemRect,TRUE)) 
{    itemRect.left=itemRect.left-19;    CRect   fillRect(0,itemRect.top,m_ClientRect.right,itemRect.bottom);    itemState = GetItemState(currentItem,TVIF_STATE);    if (itemRect.top&m_ClientRect.bottom)  //说明这一项已超出窗口的边界,所以不绘制,很好理解吧!不用我说了撒    {        }    //绘制鼠标热点    if (currentItem==m_MouseMoveItem&&ItemHasChildren(currentItem)==NULL)    {     m_Gdiplus.usFillRectangle(pDc-&m_hDC,fillRect,0xB7F0FE,0xB7F0FE,edoVertical,true);    }      if(itemState&TVIS_SELECTED)    {     m_Gdiplus.usFillRectangle(pDc-&m_hDC,fillRect,0xFF00BB,0xFF00BB,edoVertical,true);      }    //绘制展开图片    if (ItemHasChildren(currentItem))    {     CP     point.x = itemRect.     point.y = itemRect.top+(itemRect.Height()-m_OpenHigh)/2;       if (itemState & TVIS_EXPANDED)     {      m_IconList.Draw(pDc,1,point,ILD_TRANSPARENT);     }else     {      m_IconList.Draw(pDc,0,point,ILD_TRANSPARENT);     }      }    itemRect.left+=m_OpenWidth+2;    itemRect.right+=m_OpenWidth+8;    //绘制图标1     m_iter=m_mapTree.find(currentItem);     Graphics tempGraphics(pDc-&m_hDC);     Rect rcD      if (m_iter-&second.s_FirstImage&=0&&m_iter-&second.s_FirstImage&m_IconNum)    {     rcDes=Rect(itemRect.left,fillRect.top+m_IconSpacing,m_IconWidt,m_IconHigh);    tempGraphics.DrawImag(m_IconBitmap,rcDes,m_iter&second.s_FirstImage*m_IconWidt,0,m_IconWidt,m_IconHigh,UnitPixel,&alphaAttribut);    itemRect.left =itemRect.left+m_IconW    itemRect.right = itemRect.right+m_IconW      }  [cpp] view plaincopy
   //绘制文字     DrawItemText(pDc,currentItem,itemRect);       //绘制后面的第2,3,4项图标     CSize  fontS     fontSize= pDc-&GetTextExtent(GetItemText(currentItem));     itemRect.left+=fontSize.     if (m_iter-&second.s_SecondImage&=0&&m_iter-&second.s_SecondImage&m_IconNum)     {      rcDes=Rect(itemRect.left,fillRect.top+m_IconSpacing,m_IconWidt,m_IconHigh);      tempGraphics.DrawImage(m_IconBitmap,rcDes,m_iter-&second.s_SecondImage*m_IconWidt,0,m_IconWidt,m_IconHigh,UnitPixel,&alphaAttribut);      itemRect.left=itemRect.left+m_IconWidt+4;     }      } 
} while ((currentItem=GetNextVisibleItem(currentItem)) != NULL);  } 
函数的主要思路首先通过GetFirstVisibleItem();获取第一个可见的节点,如果节点存在则按照我们的绘制顺序绘制,然后调用GetNextVisibleItem获得下一个可见的节点,一直循环,直到下一个可见节点为NULL的时候退出绘制函数。
下面讲一下获取项热点的方法。同样我们需要重写消息,这次是ON_MOUSEMOVE消息。
我们首先定义一个数据来记录当前鼠标移动到的节点的句柄。具体看代码。
[cpp] view plaincopy
HTREEITEM        m_MouseMoveI                                          //鼠标移动到的项  void CMyCtreeCtrl::OnMouseMove(UINT nFlags, CPoint point)  { 
// TODO: 在此添加消息处理程序代码和/或调用默认值    m_ptOldMouse = 
HTREEITEM hItem = HitTest(point); 
if ( hItem != NULL && hItem != m_MouseMoveItem ) 
{    m_MouseMoveItem = hI    Invalidate(FALSE); 
}  //CTreeCtrl::OnMouseMove(nFlags, point);  }    接下来我们通过获取当前绘制的节点和m_MouseMoveItem比对,如果相同则设置当前的背景颜色,从而实现热点时间    //绘制鼠标热点     if (currentItem==m_MouseMoveItem&&ItemHasChildren(currentItem)==NULL)     {      m_Gdiplus.usFillRectangle(pDc-&m_hDC,fillRect,0xB7F0FE,0xB7F0FE,edoVertical,true);     }    //通过获取当前状态来判断单击事件。       if(itemState&TVIS_SELECTED)     {      m_Gdiplus.usFillRectangle(pDc-&m_hDC,fillRect,0xFF00BB,0xFF00BB,edoVertical,true);       }  &p&这2句代码都在DrawItem函数中。&/p& 
之后在我们的一些常见操作之后触发WN_PAINT就可以了。
这种重写ON_PAINT消息实现自绘的方法就是这些了,有没有觉得比我们前面的那种方法要简单好理解一些了。下面说说我为什么选择这种方法而不用上面一种方法的原因,首先ON_PAINT可以获取到树形控件的整个DC,感觉绘制的时候方便一些,我想绘制到什么地方就绘制到什么地方,容易控制。其次是这种方法需要掌握的数据结构比较的少就需要知道几个常见的函数就OK了。
需要掌握的函数:
CTreeCtrl::GetFirstVisibleItem
HTREEITEM GetFirstVisibleItem( );
返回值:如果成功则返回第一个可视项的句柄;否则返回NULL。
此成员函数用来获取该tree view控件中的第一个可视项的句柄。
CTreeCtrl::GetNextVisibleItem
HTREEITEM GetNextVisibleItem( HTREEITEM hItem );
返回值:返回下一个可视项的句柄;否则返回NULL。
hItem    一个tree项的句柄。
说明:此成员函数用来获取hItem的下一个可视项。
CTreeCtrl::ItemHasChildren
BOOL ItemHasChildren( HTREEITEM hItem );
如果由hItem指定的tree项有子项则返回非零值;否则返回0。
hItem    一个tree项的句柄。
CTreeCtrl::GetItemText
CString GetItemText( HTREEITEM hItem )
返回值:返回一个包含该项的文本的CString对象。
hItem    要获取其文本的项的句柄。
此成员函数返回由hItem指定的项的文本。
CTreeCtrl::GetItemRect
BOOL GetItemRect( HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly );
如果项是可视的则返回非零值,以及包含在lpRect中的边界矩形。否则,返回0和没有被初始化的lpRect。
hItem    一个tree view项的句柄。
lpRect    指向一个用来接收边界矩形的RECT结构的指针。其中的坐标是相对于该tree view控件的左上角的。
bTextOnly    如果这个参数是非零值,则边界矩形值包括项的文本。否则,它包括该项在tree view控件所占据的整个一行。
【上篇】【下篇】
您可能还会对这些文章感兴趣!
百度站内搜索
同分类最新文章求一个新浪微博上发自绘的简短搞笑漫画的人_百度知道
求一个新浪微博上发自绘的简短搞笑漫画的人
二师兄会36变有一集是说 大师兄会72变,上帝,问沙师弟说你会什么,看
我有更好的答案
,还有论字的?。小品。,。。。,,。。,。。。。?
搞笑漫画,一般就4幅画面左右 黑白小清新的画风,那个人一直在连续更新的
每次题材不一样
有时还会只有对话框自己填词上去的互动
鳄鱼日记本
其他类似问题
为您推荐:
新浪微博的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁> 正文
4岁小女孩爱好画画 自写自绘出版故事书(图)
  早报讯 “晚上,小茉莉花走了,我看着她扇起巨大的翅膀飞向夜空。临走前,她把一袋子花粉和口诀交给我,如果我有需要,就望向夜空中最闪亮的那一颗星,那就是她的家;然后吹起花粉,念起口诀,她就会在那里。”你很难想象如此清新质朴的文笔,再配上十分可爱的儿童画,竟然会出自一名4岁小女孩之手。这个名叫孙一平的女孩最爱的就是画画,而她也已经出了一本书——《小茉莉花,开吧!》。
  4岁小女孩出插画书
  她是一个活泼可爱的小女孩,圆圆的脸,扎着马尾,大眼睛,不过最为让人关注的,是她可爱的笑容。“叔叔,我今年4岁了,你可以叫我小茉莉花。”这是孙一平的开场白。“我最喜欢的是听妈妈讲故事,然后把故事里的内容画下来。”孙一平说,童话故事都是那么美好,她出的这本书,是想告诉小朋友们,要爱身边的人和动物,要爱一草一木,要乐于助人。“这个故事是我在她出生的时候编出来的,在她小时候就讲给她听,然后她每听完一个故事就会画下来。”孙一平的妈妈刘千惠告诉记者,这本书主要讲的是小茉莉花仙子来到人间帮助人们的故事。《小茉莉花,开吧!》配有孙一平画的40幅画。
  见到什么都要画下来
  饭可以不吃,觉可以不睡,画必须画。“我平时最大的爱好就是画画,从小到现在,画画已成为一种习惯了。”孙一平说。“这个儿童画,她一共画了两天就完成了。”刘千惠告诉记者,孙一平从3岁的时候开始画画,本来是自己乱画,后来画得越来越好,他们索性给孙一平报了画画学习班。“她见了什么,听到什么,都想画下来。”刘千惠说。
  刘千惠告诉记者,她带着孙一平的手稿来到青岛某出版社。“一个4岁的小朋友能画出这样的作品来,出版社很惊奇。”刘千惠说,虽然出版社很喜欢孙一平的作品,但由于担心儿童画的销路问题,所以没有当场表态。为了能完成孙一平的梦想,刘千惠自费出了这本书。(记者 徐栋 摄影报道)
08-06·
07-19·
07-19·
05-31·
04-11·
04-10·
01-09·
11-07·
09-15·
06-26·
我要评论 提取评论...
用户名: 密码:
网友评论仅供其表达个人看法,并不表明青岛新闻网同意其观点或证实其描述。●●●●●●●●●●
本周热门内容
【分社导航】
|||||||||||||
|||||||||||||
【友情链接】
 |  |  |  |  | 
::::::::::::::::::::::::::::::中国新闻网版权所有::::::::::刊用本网站稿件务经书面授权:::::::::::::::::::::::::::::::
中国新闻网唐山新闻 地址:唐山市委院内付2楼2层 
电话: 传真:
河北杰大律师事务所 律师:王清河 为本网常年法律顾问 固定电话:
移动电话:
技术支持:中新社河北分社网络中心 监督电话:1}

我要回帖

更多关于 易语言自绘皮肤模块 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信