duilib 窗口创建流程梳理

a 夏天 提交于 2020-08-19 05:45:09

 

1 duilib窗口类

<Window size="400,150" caption="0,0,0,60" roundcorner="16,16" shadowattached="false">

   duilib自己封装了Window类

class UILIB_API Window : public virtual nbase::SupportWeakCallback
{
public:
    Window();
	~Window();

	/**
	 * @brief 获取窗口所属的 Windows 句柄
	 * @return 返回窗口关联的 Windows 窗口句柄
	 */
    HWND GetHWND() const;

	/**
	 * @brief 注册窗口类
	 * @return 返回 true 表示成功,否则表示失败
	 */
    bool RegisterWindowClass();

	/**
	 * @brief 注册控件窗口类(与窗口的过程函数不同)
	 * @return 返回 true 表示成功,否则表示失败
	 */
    bool RegisterSuperClass();

	/**
	 * @brief 获取窗口类名称
	 * @return 返回窗口类名称
	 */
	virtual std::wstring GetWindowClassName() const;

	/**
	 * @brief 获取控件窗口类
	 * @return 返回控件窗口类
	 */
	virtual std::wstring GetSuperClassName() const;

	/**
	 * @brief 获取窗口类的样式,该方法由实例化的子类实现,https://docs.microsoft.com/en-us/windows/desktop/winmsg/window-class-styles
	 * @return 返回窗口类的样式
	 */
	virtual UINT GetClassStyle() const;

	/**
	 * @brief 子类化窗口(更改窗口过程函数)
	 * @param[in] 窗口句柄
	 * @return 新的窗口句柄
	 */
	HWND Subclass(HWND hWnd);

	/**
	 * @brief 取消子类化窗口(恢复原来的窗口过程函数)
	 * @return 无
	 */
	void Unsubclass();

	/**
	 * @brief 创建窗口
	 * @param[in] hwndParent 父窗口句柄
	 * @param[in] pstrName 窗口名称
	 * @param[in] dwStyle 窗口样式
	 * @param[in] dwExStyle 窗口拓展样式
	 * @param[in] isLayeredWindow 是否带有层窗口属性,默认为 true
	 * @param[in] rc 窗口大小
	 * @return 返回窗口句柄
	 */
	virtual HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow = true, const UiRect& rc = UiRect(0, 0, 0, 0));

	/**
	 * @brief 关闭窗口
	 * @param[in] 关闭消息
	 * @return 无
	 */
	virtual void Close(UINT nRet = IDOK);



 

   其中,创建窗口使用

     * @brief 创建窗口
     * @param[in] hwndParent 父窗口句柄
     * @param[in] pstrName 窗口名称
     * @param[in] dwStyle 窗口样式
     * @param[in] dwExStyle 窗口拓展样式
     * @param[in] isLayeredWindow 是否带有层窗口属性,默认为 true
     * @param[in] rc 窗口大小
     * @return 返回窗口句柄
     */
    virtual HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow = true, const UiRect& rc = UiRect(0, 0, 0, 0));








 

2 窗口管理类,对窗口统一管理

//map<窗口类名,map<窗口id,窗口指针>>, 如果同一类只有一个窗口,使用类名作为id
typedef std::map<std::wstring, std::map<std::wstring, WindowEx*>> WindowsMap; 
typedef std::list<WindowEx *> WindowList;


class WindowsManager
{
public:
	SINGLETON_DEFINE(WindowsManager);
	WindowsManager();
	virtual ~WindowsManager();

	//根据窗口类名和id注册窗口
	bool RegisterWindow(const std::wstring wnd_class_name, const std::wstring wnd_id, WindowEx *wnd);
	//根据窗口类名和id注销窗口
	void UnRegisterWindow(const std::wstring &wnd_class_name, const std::wstring &wnd_id, WindowEx *wnd);
	//根据窗口类名和id获取窗口
	WindowEx* GetWindow(const std::wstring &wnd_class_name, const std::wstring &wnd_id);
	//获取所有窗口
	WindowList GetAllWindows();
	//获取指定class对应的所有窗口
	WindowList GetWindowsByClassName(LPCTSTR classname);
	//关闭所有窗口
	void DestroyAllWindows();
	//设置禁止窗口创建
	void SetStopRegister(bool stop=true){stop_register_ = stop;}
	//是否禁止窗口创建
	bool IsStopRegister(){return stop_register_;}

	template<typename WindowType>
	static WindowType* SingletonShow(const std::wstring& window_id,int nParam=-1,bool bSHow=true,HWND hParent=NULL)
	{
		if (nParam > 0)
			kClass_Param_map[WindowType::kClassName] = nParam;


		WindowType *window = (WindowType*)(WindowsManager::GetInstance()->GetWindow(WindowType::kClassName, window_id));
		if (!window)
		{
			window = new WindowType;
			window->Create(hParent, WindowType::kClassName, WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX, 0);
			
			window->CenterWindow();
		
			if (bSHow)
			{
				window->ShowWindow();
			}
			
		}
		else
		{
			window->ActiveWindow();
		}

		return window;
	}

private:
	WindowsMap					windows_map_;	//所有窗口
	std::string					user_id_;
	bool						stop_register_;	//禁止窗口创建
public:
	static std::map<std::wstring, int> kClass_Param_map; // 窗口创建前,对应kClassName窗口中的参数,用此参数可以进行不同的初始化处理
};

 

其中,单例模板中,负责窗口创建

            调用dulib窗口类创建函数, 创建默认duilib窗口

             virtual HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow = true, const UiRect& rc = UiRect(0, 0, 0, 0));

 

            window = new WindowType;
            window->Create(hParent, WindowType::kClassName, WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX, 0);

 

3 窗口创建流程

       以登录窗口创建为例,看看窗口创建流程

       nim_comp::WindowsManager::SingletonShow<LoginForm>(LoginForm::kClassName);

 

 

 

在窗口创建Create中,RegisterWindowClass 注册窗口处理函数

bool Window::RegisterWindowClass()
{
	WNDCLASS wc = { 0 };
	wc.style = GetClassStyle();
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hIcon = NULL;
	wc.lpfnWndProc = Window::__WndProc;
	wc.hInstance = ::GetModuleHandle(NULL);
	wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = NULL;
	wc.lpszMenuName = NULL;
	std::wstring className = GetWindowClassName();
	wc.lpszClassName = className.c_str();
	ATOM ret = ::RegisterClass(&wc);
	ASSERT(ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
	return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

窗口处理函数

LRESULT CALLBACK Window::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    Window* pThis = NULL;
    if( uMsg == WM_NCCREATE ) {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<Window*>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    }
    else {
        pThis = reinterpret_cast<Window*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
        if( uMsg == WM_NCDESTROY && pThis != NULL ) {
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
            if( pThis->m_bSubclassed ) pThis->Unsubclass();
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }

	if (pThis != NULL) {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    } 
    else {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

其中,通过GWLP_USERDATA 记录窗口指针

typedef struct tagCREATESTRUCT
{
  LPVOID  lpCreateParams;  //指向将被用于创建窗口的数据的指针。  
  HANDLE  hInstance;       //标识了拥有新窗口的模块的模块实例的句柄。  
  HMENU   hMenu;           //标识了要被用于新窗口的菜单。如果是子窗口,则包含整数ID。  
  HWND    hwndParent;      //标识了拥有新窗口的窗口。如果新窗口是一个顶层窗口,这个参数可以为NULL。  
  int     cy;              //指定了新窗口的高。  
  int     cx;              //指定了新窗口的宽。  
  int     y;               //指定了新窗口的左上角的y轴坐标。  
  int     x;               //指定了新窗口的左上角的x轴坐标。 
  LONG    style;           //指定了新窗口的风格。  
  LPCSTR  lpszName;        //指向一个以null结尾的字符串,指定了新窗口的名字。  
  LPCSTR  lpszClass;       //指向一个以null结尾的字符串,指定了新窗口的Windows类名
  DWORD   dwExStyle;       //指定了新窗口的扩展风格。  
} CREATESTRUCT;

 

WM_GETMINMAXINFO       0x0024     36

WM_NCCREATE 非客户区创建消息    0x0081  129

WM_NCCALCSIZE           0x0083    131

WM_CREATE                    0x0001

WM_STYLECHANGING    7C  124

WM_STYLECHANGED      7D  125

WM_WINDOWPOSCHANGING   0X46  70

WM_WINDOWPOSCHANGED  0X 46  71

窗口创建时 消息顺序,在WM_NCCREATE 时,保存 窗口指针 句柄等信息

    if( uMsg == WM_NCCREATE ) {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<Window*>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    }




 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!