为什么控件window显示不出来?

Why the window of control coulnd't appear?

在微软网站上看到一篇文章MSDN介绍了一种高级的写法

我把它应用到class的扩展中,通常我没有问题。

但是最近在尝试写一个class的时候遇到了问题。 我想实现一个listview class 方便我们操作listview控件的时候

template <class DERIVED_TYPE>
class BaseWindow
{
public:
    LPCTSTR className = "myWindows";
    LPCTSTR Caption = "myWindows";
    DWORD Style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
    UINT classStyle = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    DWORD ExStyle = 0;
    ...
    other_property
    ...
    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        DERIVED_TYPE *pThis = NULL;
        if (uMsg == WM_NCCREATE)
        {
            CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
            pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);

            if (pThis)pThis->m_hwnd = hwnd;

        }else{
            pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
            if(pThis)pThis->m_hwnd = hwnd;
        }

        if (pThis)
        {
            return pThis->HandleMessage(hwnd, uMsg, wParam, lParam);

        }else{
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
    }
    ATOM RegClass()
    {
        WNDCLASS wc = { 0 };
        wc.lpfnWndProc = BaseWindow::WindowProc;
        wc.hInstance = hInst;
        wc.lpszClassName = className;
        wc.style = classStyle;
        wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
        return RegisterClass(&wc);
    }
    BOOL CreateWinEx(   LPCTSTR className_,LPCTSTR Caption_,
                        DWORD Style_,DWORD ExStyle_,
                        int x_,int y_,int w_,int h_,
                        HWND hWndParent_,HMENU hMenu_,HINSTANCE hInst_)
    {
        m_hwnd = CreateWindowEx(
            ExStyle_, className_, Caption_, Style_,
            x_, y_, w_, h_, 
            hWndParent_, hMenu_, hInst_, this
            );
        return (m_hwnd ? TRUE : FALSE);
    }
    BOOL Create()
    {
        ATOM rst = RegClass();
        if(rst == 0) return FALSE;
        m_hwnd = CreateWindowEx(
            ExStyle, className, Caption, Style,
            x, y, w, h, 
            hWndParent, hMenu, hInst, this
            );
        return (m_hwnd ? TRUE : FALSE);
    }
}

基于以上,我导出了两个class,一个作为主窗体,一个作为我要设计的listviewclass

class FirstWindow : public BaseWindow<FirstWindow>
{
public:
    FirstWindow(){};
    ...
    some_property
    ...
    LRESULT HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    LRESULT CALLBACK ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:

};

class listView : public BaseWindow<listView>
    {

    public:
        listView();
        
        int init(LPCTSTR className_,HWND hWndParent_,int x,int y,int w,int h)
        {
             this->className = className_;
             this->hWndParent = hWndParent_;

             this->Style = WS_CHILD| WS_VISIBLE | ~WS_CAPTION;
           
             this->x = x;
             this->y = y;
             this->w = w;
             this->h = h;

             this->Create();

             hWndMsgWindow = m_hwnd;

             CreateListView(hWndMsgWindow);



             ShowWindow(hWndMsgWindow,SW_SHOW);
             ShowWindow(hWndListView,SW_SHOW);

             UpdateWindow(hWndMsgWindow);
             UpdateWindow(hWndListView);

             idebug("listview::init >> hWndMsgWindow:%d,parent:%d, error:%d\n",hWndMsgWindow,GetParent(hWndMsgWindow), GetLastError());
             idebug("listview::init >> hWndListView:%d,parent:%d,error:%d\n",hWndListView,GetParent(hWndListView), GetLastError());
             return 1;

        }
        LRESULT HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

        
    LRESULT listView::CreateListView(HWND hwndParent_)
    {

        InitCommonControls();

        bool rst = CreateWinEx(WC_LISTVIEW, NULL,
        WS_CHILD | WS_VISIBLE | LVS_REPORT |LVS_EDITLABELS | LVS_NOCOLUMNHEADER | LVS_OWNERDATA |LVS_OWNERDRAWFIXED | WS_BORDER,0,
            x,y,w,h,
            hwndParent_, NULL, GetModuleHandle(NULL));

        if(rst)
            hWndListView = m_hwnd;

        idebug("CreateListView >> rst:%d,hwndlistview:%d,parent:%d,hwndParent_:%d, error:%d\n",rst,hWndListView,GetParent(hWndListView),hwndParent_,    GetLastError());

        return rst;

    }
        LRESULT AddItem();
        LRESULT OnListViewNotify(HWND hwnd, LPARAM lParam);
        void OwnerDraw(LPDRAWITEMSTRUCT lpdis, HDC hdc, HWND hWnd, const TCHAR* szDraw);

        void on_drawItem(HWND hWnd, LPARAM lParwm);
        void on_notify(HWND hWnd, WPARAM wParwm, LPARAM lParam);
        void on_create(HWND hWnd);
        void on_measureItem(LPARAM lParam);

        bool add_item();
        bool add_item_sub();
        ...
        some_property
        ...

    };

首先触发 FirstWindow


FirstWindow * pFirstWnd;

listView  lv;


int main(int argc, char** argv)
{

    FirstWindow win;
    pFirstWnd = &win;
    win.className = "FirstWindow";
    win.Style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    win.x = 100;
    win.y = 100;
    win.w = 600;
    win.h = 300;
    bool rst = win.Create();
    if (!rst)
    {
        idebug("getlasterror:%d,line:201\n", GetLastError());
        bug.ShowErr();
    }
    else {
        lv.init("mylistview",pFirstWnd->m_hwnd,20,20,300,200);
        ShowWindow(lv.m_hwnd, SW_SHOW);
    }

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

listview_class 的目标是能够独立接收和处理 window 消息。 不是这样的:

LRESULT FirstWindow::HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

    switch (uMsg)
    {
            case WM_CREATE:
            {
                //lv.init("mylistview2",pFirstWnd->m_hwnd,20,20,300,200);
                //ShowWindow(lv.m_hwnd, SW_SHOW);
                break;
            }
            case WM_NOTIFY:
            {
                lv.on_notify(hWnd,wParam,lParam);
                break;
            }
            ...
            }
            default:
                return DefWindowProc(m_hwnd, uMsg, wParam, lParam);

    }

    return TRUE;
}

相反,我想在列表视图中独立处理消息class,像这样:


LRESULT listView::HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    static HDC hdc;
    HRESULT lResult;
    switch (uMsg) 
    {
    case WM_CREATE:
    {
        
        idebug("class_listview >> WM_CREATE >> hWnd :%d, className:%s, parent:%d\n",hWnd, className , GetParent(hWnd));
        
        //HWND h = CreateWindowEx(0, WC_LISTVIEW, NULL,
                    WS_CHILD | WS_VISIBLE | LVS_REPORT |LVS_EDITLABELS | LVS_NOCOLUMNHEADER | LVS_OWNERDATA |LVS_OWNERDRAWFIXED | WS_BORDER,
                    20,20,300,200,
                    hWnd,NULL, GetModuleHandle(NULL),NULL);

        //ShowWindow(h,SW_SHOW);
        //UpdateWindow(hWnd);

        //idebug("class_listview >> WM_CREATE >> hwnd:%d,parent:%d,error:%d\n",h,GetParent(h), GetLastError());
 
        //ShowWindow(h,SW_SHOW);
        //UpdateWindow(h);
        break;
    }
    case WM_NOTIFY:
    {
        on_notify(hWnd,wParam,lParam);
        break;
    }
    case WM_MEASUREITEM:     
    {     
        on_measureItem(lParam);
        break;
    }
    case WM_DRAWITEM:
    {
        on_drawItem(hWnd,lParam);
        break;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 2));
        EndPaint(hWnd, &ps);
        idebug("class_listview >> WM_PAINT->hWnd:%d,id:%d,err:%d\n", hWnd, id, GetLastError());
        break;
    }

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

现在的问题是除了FirstWindow可以正常显示外,我看不到其他控件windows

更新: 来自调试的一些消息:

class_listview >> WM_CREATE >> hWnd :1443146, className:mylistview, parent:262350,error:0
listView >> WM_SIZE >> hWnd:1443146,parent:262350
CreateListView >> rst:1,hwndlistview:853318,parent:1443146,hwndParent_:1443146, error:5
listview::init >> hWndMsgWindow:1443146,parent:262350, error:5
listview::init >> hWndListView:853318,parent:1443146,error:5

问题的关键是 WM_NOTIFY 消息的 return 值。

我输入了:

case WM_NOTIFY:
    {
        retnrn on_notify(hWnd,wParam,lParam);
    }

问题已解决。