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));
}
来源:oschina
链接:https://my.oschina.net/u/4340310/blog/4449883