写了一个自己的CMyListCtrl,现在使用CListView,但是CListView::GetListCtrl返回的是CListCtrl的对象,请问怎样能够替换CListView中的CListCtrl对象为自己的CMyListCtrl?有这个可能吗?

解决方案 »

  1.   

    安全的方法是复制代码到你的CListView派生类,或者使用模板来共享代码。
    CListView中并不包含一个CListCtrl。4 为什么一个类的指针可以强制转化为另外一个类的指针,即使它们之间没有派生关系?
    答:只要你访问的数据的内存表示是完全相同的,那么这种转化就是安全的。考虑MFC从CWnd到CEdit的派生过程,是一个纯粹的封装——既没有增加数据成员也没有增加虚函数(虚函数表的指针实际上是类的第一个成员,你可以在VC的监视窗口看到)——所有的代码只是在操作基类的成员。所以你可以在对话框的成员函数中安全地进行如下调用
    CEdit* pEdit=GetDlgItem (IDC_EDIT);
    也就是说,你可以安全地把CWnd指针转化为CEdit指针。在CWnd的窗口类为EDIT的情况下,你可以安全地用这个CEdit指针来访问CEdit具有的而CWnd不具有的特性。由于CEditView的窗口类也是EDIT,同时是从CWnd派生下来的,所以你也可以把CEditView指针转化成CEdit指针。MFC的CCtrlView的派生类都可以做这样的转化。在这样做之前,你需要查看类的定义头文件以确保类型安全。CEdit, CListCtrl, CTreeCtrl,CToolBarCtrl都是这样的封装,但是CToolTipCtrl是一个例外。除了对TTM_ADDTOOL消息的处理可能不一致之外。
    LRESULT CToolTipCtrl::OnAddTool(WPARAM wParam, LPARAM lParam)
    {
    TOOLINFO ti = *(LPTOOLINFO)lParam;
    if ((ti.hinst == NULL) && (ti.lpszText != LPSTR_TEXTCALLBACK)
    && (ti.lpszText != NULL))
    {
    void* pv;
    if (!m_mapString.Lookup(ti.lpszText, pv))
    m_mapString.SetAt(ti.lpszText, NULL);
    // set lpszText to point to the permanent memory associated
    // with the CString
    VERIFY(m_mapString.LookupKey(ti.lpszText, ti.lpszText));
    }
    return DefWindowProc(TTM_ADDTOOL, wParam, (LPARAM)&ti);
    }
    这里访问了CToolTipCtrl的数据成员,这样的话下面的代码就似乎未必安全
    _AFXCMN_INLINE CToolTipCtrl* CTreeCtrl::GetToolTips() const
    { ASSERT(::IsWindow(m_hWnd)); return (CToolTipCtrl*)CWnd::FromHandle((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L)); }不过CTreeCtrl::GetToolTips()返回的只是有效的CWnd,TVM_ADDTOOL消息也是被默认窗口过程而不是CToolTipCtrl的代码来处理, 所以上面的用法还是安全的。
    顺便说一下,尽管大部分这样的封装是用SendMessage实现的,但是Redmond的家伙似乎很热衷于用DefWindowProc替代SendMessage来节省CPU的时钟周期。这样的一个副作用是MFC不会有处理这样的消息的机会,例如PretranslateMessage和Subclass都会失效了。这样的一个副作用是protected修饰符不再是类成员的保护伞。考虑如下情况
    Class A
    {
        protected: int m_iProtected;
    };
    如果我想获得m_iProtected的public访问权,我可以写一个封装类
    Class B:public A
    {
    public:int & GetProtected(){return m_iProtected;}
    friend class C;
    };
    然后把A类型的指针强制转化成B类型的就可以以public方式访问声明为m_iProtected的成员了。在C类中访问B的成员也不受限制。尽管多继承是C++的一个特性,从理想情况来说,CEditView应该从CCtrlView和CEdit派生出来,但是所有的人都知道多继承是多么的麻烦。对于MFC的CObject派生类,默认的情况是不允许的——尽管你可以通过的MFC技术文档TN016: Using C++ Multiple Inheritance with MFC中提供的方法手动添加多继承支持。实际上,这些特性应该以接口的形式提供——把GetEditCtrl转换成QueryInterface,但是性能上又会损失很多,而且Windows通用控件和MFC对它的封装总是在不断地升级,所以MFC使用了如上的Hack方法来提供和多继承类似的功能。
      

  2.   

    这里有一篇文章:
    http://www.codeguru.com/Cpp/controls/listview/introduction/article.php/c901/
    不过我认为更好一点的方式是在view上画一个控件。
    1,视图从CView继承。
    2,在视图内动态创建CMyListCtrl.
    3, 将CMyListCtrl全视图显示。
    3,处理基本的界面缩放消息,CMyListCtrl中保存CView指针,通过它处理doc/view的串行动作。
    4,视图撤销时destroy listctrl.
      

  3.   

    同意jiangsheng。
    CListView派生自CCtrlView,CListView的构造函数显式调用CCtrlView的构造函数,CCtrlView的构造函数有两个参数,分别表示窗口类的类名和窗口风格。CListView传递给它的是预定义的窗口类WC_LISTVIEW,所以整个CListView其实就是一个win32 common ctrl ListView而已。
      

  4.   

    简单一点的:
    加一个Dialog,边框什么的不要,放一个ListCtrl进去,再将Dialog生成一个FormView的类。
    响应WM_SIZE消息,将ListCtrl的大小和FormView的大小一样。再把ListCtrl生成一个变量,关连到你的那个listctrl类就可以了。
      

  5.   

    呵呵,简单点,按照baberson说得就够了。
      

  6.   

    请问一下enoloo:
    你说的1,视图从CView继承。
    2,在视图内动态创建CMyListCtrl.
    3, 将CMyListCtrl全视图显示。
    3,处理基本的界面缩放消息,CMyListCtrl中保存CView指针,通过它处理doc/view的串行动作。怎么实现阿
      

  7.   

    CMyListCtrl m_listctrl; //类中//实现:
    CRect rect;
    GetClientRect(&rect);
             CRect rectctl(rect);
    rect.right = rect.right/2;
    rect.bottom = rect.bottom/2; m_listctrl.Create(WS_VISIBLE |WS_CHILD |LVS_REPORT |LVS_OWNERDRAWFIXED, rectctrl,this,IDC_LIST1);
    int i;
    m_listctrl.GetClientRect(&rect);
    m_listctrl.InsertColumn(0,"abc");
    m_listctrl.SetColumnWidth(0,rect.Width()/2);
    m_listctrl.InsertColumn(1,"ABC");
    m_listctrl.SetColumnWidth(1,rect.Width()/2);
      

  8.   


    listview是能接受所有发送到他本身的消息。但是,如果listview重绘,那么消息是发送到父窗口的,他自己怎么处理? 我猜楼主的意思可能是以对象的概念来处理消息。比如mfc的消息反射。重载DrawItem函数等等。