一般创建控件有两种方法,一种是动态创建,调用CWND::Create()方法,还有就是采用SubclassDlgItem()方法绑定一个资源ID.
这两者有什么区别?比如,我继承CTreeCtrl,重载PreCreateWindow(),发现后面一种方法并没有调用该函数,结果导致我的树形控件不能显示ToolTips,但是我在属性里面选了显示提示信息风格阿?最后没办法,在外部直接调用m_tree.EnableToolTips(1);这时候又可以显示提示信息了!我在扩展中还遇到第二个问题,无法拖放,跟踪调试发现TVN_BEGINRDRAG的处理函数根本就没有调用,这是什么原因?是不是消息反射机制有特殊要求?

解决方案 »

  1.   

    两种方法差不多,不同的有用第一种方法会执行到OnCreate函数,但是用第二种方法不会执行到OnCreate,所以像不会显示ToolTip的问题,估计就跟你的OnCreate函数里面的代码有关,没有执行到该段代码就不会显示ToolTip
      

  2.   

    至于你的BeginDrag不会被调用,你要确保TreeView的Style支持拖放;
    你重载PreCreateWindow试试:
     BOOL CDragDropTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) 
     {
         // Make sure the control's TVS_DISABLEDRAGDROP flag is not set.
         // If you subclass an existing tree view control rather than create
         // a CDragDropTreeCtrl outright, it's YOUR responsibility to see that
         // this flag isn't set.
         cs.style &= ~TVS_DISABLEDRAGDROP;
         return CTreeCtrl::PreCreateWindow(cs);
     }
      

  3.   

    一个是你自己创建,一个是由对话框模版创建之后Subclass的区别。对于后者,不能更改Subclass之前的行为,同时窗口风格是在对话框模版中指定的。
      

  4.   

    多谢,但我还是有点不大明白。对于第二种方法,在资源管理器中,可以直接修改其风格,如果子类化以后,其风格是否也会相应修改(即内部是否会按照在资源管理器里设定修改其cs.style)?如果不修改,那么岂不是没有意义?此外,由于不再调用PreCreateWindow(),那么在扩展时,将该函数里的操作放到哪里为好?对于消息反射,我在msdn里面看到如下一段话,有点不知所云,希望各位大哥大姐帮我翻译一下:
    If you have supplied a handler for a specific message, or for a range of messages, in your parent window's class, it will override reflected message handlers for the same message provided you don't call the base class handler function in your own handler. For example, if you handle WM_CTLCOLOR in your dialog box class, your handling will override any reflected message handlers.If, in your parent window class, you supply a handler for a specific WM_NOTIFY message or a range of WM_NOTIFY messages, your handler will be called only if the child control sending those messages does not have a reflected message handler through ON_NOTIFY_REFLECT(). If you use ON_NOTIFY_REFLECT_EX() in your message map, your message handler may or may not allow the parent window to handle the message. If the handler returns TRUE, the message will be handled by the parent as well, while a call that returns FALSE does not allow the parent to handle it. Note that the reflected message is handled before the notification message.When a WM_NOTIFY message is sent, the control is offered the first chance to handle it. If any other reflected message is sent, the parent window has the first chance to handle it and the control will receive the reflected message. To do so, it will need a handler function and an appropriate entry in the control's class message map.The message-map macro for reflected messages is slightly different than for regular notifications: it has _REFLECT appended to its usual name. For instance, to handle a WM_NOTIFY message in the parent, you use the macro ON_NOTIFY in the parent’s message map. To handle the reflected message in the child control, use the ON_NOTIFY_REFLECT macro in the child control’s message map. In some cases, the parameters are different, as well. Note that ClassWizard can usually add the message-map entries for you and provide skeleton function implementations with correct parameters.
      

  5.   

    问题解决了,呵呵,居然是我眼花,将TVN_BEGINDRAG选成TVN_BEGIN人RDRAG了!
    楼上大大们,顺便问一句,能将vs.net2003里面的外挂字体变大吗?
      

  6.   

    第二种情况子类化之前是连窗口都没有,更不用谈窗口风格。初始化函数视情况而定。通常可以放在构造函数/PrecreatWindow/Create/WM_CREATE处理函数/PreSubclassWindow里面。有的时候放在WM_PAINT处理函数里面,第一次Paint的时候初始化。
    两种情况下都会调用PreSubclassWindow,如果你要为两种情况使用同一个类,这是不错的初始化位置。