剖析Net 精简版中Treeview控件Treenode的自描绘处理

连日暴雨倾盘,我养的小猫整日卷缩在阳台的角落象只死老鼠般一动不动,而我则在数据仓库的十多个表的联系独立分析中迷惘,枯燥无味的数据绑定使用程序失去了所有的生趣。我却定做一些其它的事情来放松绷紧的猫脑。

Treeview控件是我的老伙伴了,但直到前几天,一个希望设定treenode背景色的问题才令我发现,我一直没有深入到它的核心。不过一切都会好转,我决定重新复习windows的基础控件的内部动作。有部电影的对白令我记忆深刻:面包会有的,牛奶会有的。一个能自描绘Treenode的Treeview也会有的8)

 根据网上得到的部分代码资料及MSDN的帮助,我先在完整版中继承了一个Treeview对象,并试图处理TreeView的OCM_NOTIFY消息,所有的一切令人愉快,我轻易地截获了TreeNode对象在重绘前发出OCM_NOTIFY消息,消息中的lParam参数代表的NMTVCUSTOMDRAW结构的子结构NMTVCUSTOMDRAW中包含的dwDrawStage成员代表CDDS_ITEMPREPAINT/CDDS_ITEMPOSTPAINT标志,而且这个结构还包含有Treenode重绘时的DC,这意意味着我可以在Treenode的重绘前/后处理这个消息,并不再使用默认的Treeview消息处理过程而达到自描绘的效果。代码片段如下:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

    Select Case m.Msg

      Case OCM_NOTIFY

        Dim NMTVCD As NMTVCUSTOMDRAW

 

        NMTVCD = Marshal.PtrToStructure(m.LParam, GetType(NMTVCUSTOMDRAW))

 

        Select Case NMTVCD.NMCD.hdr.code

          Case NM_CUSTOMDRAW

            Select Case NMTVCD.NMCD.dwDrawStage

              Case CDDS_PREPAINT

                ' 我要得到Treenode中绘图处理前后的通知

                m.Result = CDRF_NOTIFYITEMDRAW

 

              Case CDDS_ITEMPREPAINT //这个通知将在Treenode绘图处理前收到

   

                Dim ptr As New IntPtr

                Dim rcItem As New Rectangle

                Dim g As Graphics = Graphics.FromHdc(NMTVCD.NMCD.hdc)

                Dim b As New SolidBrush(Color.Blue)

 

                rcItem.X = NMTVCD.NMCD.dwItemSpec

               SendMessageItemRect(m.HWnd, TVM_GETITEMRECT, 1, rcItem)

                                    

                                     //你可以利用Graphics对象g来进行TreeNode的绘图,例如:

                g.FillRectangle(New SolidBrush(Color.Yellow), New RectangleF(rcItem.X, rcItem.Y, rcItem.Width, rcItem.Height))

 

 

                g.Dispose()

                b.Dispose()

 

                m.Result = CDRF_SKIPDEFAULT //这个返回值将通知Treeview控件不需再进行这个Treenode的绘图操作

 

              Case CDDS_ITEMPOSTPAINT 这个通知将在Treenode处理后收到

                                      //和你可以以这儿进行和CDDS_ITEMPREPAINT过程相似的绘图操作

//这代表在Treeview进行treenode描绘后你还可以为treenode再多画一些东西8)

//代码略…

                 m.Result = CDRF_SKIPDEFAULT

            End Select

 

        End Select

      Case Else

        MyBase.WndProc(m)

    End Select

 End Sub

 但在精简版中,我挂接了TreeView控件的消息处理过程,却始终无法收到OCM_NOTIFY消息,查阅了PPC2003的SDK也没有发现该消息的说明,讨厌的WinCE系统没有提供这个通知。然后我在文档中迷醉了7~80分钟才发现,系统提供的Treeview只向父窗体发送WM_NOTIFY消息,消息的lParam代表的意义和OCM_NOTIFY通知完全一致。与是我不再继承,而是采取了使用一个自定义控件上放一个Treeview的方法。然后我在这个自定义控件中截到了WM_NOTIFY通知消息,接下来的Treenode绘图处理就和上面的示例大同小异了。

   //本控件的消息处理过程

    private int ThisWindowProc(IntPtr hwnd, uint uMsg, uint wParam, uint lParam)

    {

      bool tblnUseOldWinProc = true;

      int tintFuncReturn = 0;

 

      switch (uMsg)

      {

        case WM_NOTIFY:

          tagNMHDR tudtNMHDR;

          tagNMCUSTOMDRAWINFO tudtTreeViewCustomDrawInfo;

          tagNMTVCUSTOMDRAW tudtTreeViewCustomDraw;

 

 

          tudtNMHDR = (tagNMHDR)Marshal.PtrToStructure(new IntPtr(lParam), typeof(tagNMHDR));

          if (tudtNMHDR.hwndFrom == treMain.Handle)

          {

            switch (tudtNMHDR.code)

            {

              case NM_CUSTOMDRAW:

                tudtTreeViewCustomDraw = (tagNMTVCUSTOMDRAW)Marshal.PtrToStructure((IntPtr)lParam,

                  typeof(tagNMTVCUSTOMDRAW));

 

                tudtTreeViewCustomDrawInfo = tudtTreeViewCustomDraw.nmcd;

 

                switch (tudtTreeViewCustomDrawInfo.dwDrawStage)

                {

                  case CDDS_PREPAINT:

                    //本控件在Item重画前后都将获得Treeview控件的 NM_CUSTOMDRAW消息

                    tintFuncReturn = (int)CDRF_NOTIFYITEMDRAW;

                    tblnUseOldWinProc = false;//不再使用原始窗体的消息处理过程

                    break;

 

                  case CDDS_ITEMPREPAINT:

                    {

 

                      tintFuncReturn = fnCDDS_ITEMPREPAINT_NotifyMessage(hwnd, uMsg, wParam, lParam,

                        ref tudtTreeViewCustomDraw, ref tblnUseOldWinProc);

                      Marshal.StructureToPtr(tudtTreeViewCustomDraw, (IntPtr)lParam, false);//这是重绘TreeNode的处理过程

 

                      break;

                    }

                  default:

                    break;

 

                }//end switch

 

                break;

 

            }//end switch

          }//end if

 

 

          break;

 

 

        default:

          //对不处理的消息使用treeview的默认消息处理过程

          break;

      }//end switch

       if (tblnUseOldWinProc == true)

        return clsCECoreAPI.CallWindowProc(m_intThisPreviousWinProc, hwnd, uMsg, wParam, lParam);

      else

        return tintFuncReturn;

      //end if

 

}//end function

 

得到的运行效果如下:


如移动设备开发感兴趣可以加入以下群24123368

入群需知:

1、不是编程开发人员请勿加入。

2、没时间讨论问题或喜欢潜水的请勿加入。

3、只想获得源程序的请勿加入

 

本blog文档,未经作者同意,谢绝转载。谢谢你对我的blog的访问.

联系方式: missilecat@163.com QQ:85403578


转载于:https://www.cnblogs.com/DreamlikeAttic/archive/2006/08/05/468876.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值