用c++11封装win32界面库 (二)

2014-11-24 03:23:30 · 作者: · 浏览: 1
_code) 大小的内存,然后调用init()来填充,参考 thunk.h 和 heap.h)

剩下要做的事就创建控件实例时给 p_this 和 member_func 赋值了,以button为例


[cpp]
struct button {
thunk wnd_thunk;

button() {
wnd_thunk.init(this, &button::wnd_proc); // 给 thunk 的 p_this 和 member_func 赋值
}

LRESULT wnd_proc(HWND hwnd, DWORD msg, WPARAM wp, LPARAM lp) {
if(msg == WM_CLICK) {
this->on_click();
}
}
void on_click() {}
void create() {
CreateWindow("BUTTON", ...);

// 创建完后替换原 wnd_proc 为 thunk
::SetWindowLong(hwnd, GWL_WNDPROC, wnd_thunk.addr());
}
};

struct button {
thunk wnd_thunk;

button() {
wnd_thunk.init(this, &button::wnd_proc); // 给 thunk 的 p_this 和 member_func 赋值
}

LRESULT wnd_proc(HWND hwnd, DWORD msg, WPARAM wp, LPARAM lp) {
if(msg == WM_CLICK) {
this->on_click();
}
}
void on_click() {}
void create() {
CreateWindow("BUTTON", ...);

// 创建完后替换原 wnd_proc 为 thunk
::SetWindowLong(hwnd, GWL_WNDPROC, wnd_thunk.addr());
}
};

_gui的所有控件都是用的这种方式处理事件,所以thunk的初始化放在了基类 wnd_base 中(参考 wnd_base.h)

3 property

操作属性的通常做法是对外提供两个接口 getter 和 setter,类似这样


[cpp]
struct listview {
void set_title(string s) { SetWindowText(...); }
string get_title() { GetWindowText(...); }
};

struct listview {
void set_title(string s) { SetWindowText(...); }
string get_title() { GetWindowText(...); }
};
把"属性"的概念封装起来就变成
[cpp]
struct listview {
property::rw title;

listview() {
title.绑定(get_title, set_title);
}
void set_title(string s) { SetWindowText(...); }
string get_title() { GetWindowText(...); }
};

wnd lv;
sting s = lv->title; //会调用 get_title()
lv->title = "new_title"; //会调用 set_title("new_title")

struct listview {
property::rw title;

listview() {
title.绑定(get_title, set_title);
}
void set_title(string s) { SetWindowText(...); }
string get_title() { GetWindowText(...); }
};

wnd lv;
sting s = lv->title; //会调用 get_title()
lv->title = "new_title"; //会调用 set_title("new_title")这样对外只要访问属性 title 就好了,按权限控制可以分为 property::r property::w property::rw,是不是感觉好一些。

实现时只要重载两个个操作符:


[cpp]
string s = lv->title; // 重载 operator string() { return getter(); }

lv->title = "new_title"; // 重载 operator=(const string& s) { setter(s); }

string s = lv->title; // 重载 operator string() { return getter(); }

lv->title = "new_title"; // 重载 operator=(const string& s) { setter(s); }
再看个复杂点,带参数的情况。操作listview中(1,2)的单元格:


[cpp]
lv_item i = lv->item(1,2); // lv->item(1,2) 返回一个 r_helper, 重载r_helper::operator lv_item()
lv->item(1,2) = lv_item("item_1_2"); // lv->item(1,2) 返回一个 r_helper,重载 r_helper 的 operator=(const lv_item& )

lv_item i = lv->item(1,2); // lv->item(1,2) 返回一个 r_helper, 重载r_helper::operator lv_item()
lv->item(1,2) = lv_item("item_1_2"); // lv->item(1,2) 返回一个 r_helper,重载 r_helper 的 operator=(const lv_item& )
具体参数类型是用template,不定的参数个数是用 c++11 不定长模板解决,详见 property.h


4 event


[cpp]
btn->event.click += on_btn_click_1;
btn->event.click += []() { cout << "button clicked" << endl; };
btn->event.click += bind(x::func, &x_obj);

btn->event.click += on_btn_click_1;
btn->event.click += []() { cout << "button clicked" << endl; };
btn->event.click += bind(x::func, &x_obj);

有一点 .net 的味道,这样用起来比较方便。 每个事件都是一个event_handler:


[cpp]
template
struct event_handler {
typedef function fn_t;
vector handlers; //每次 += 就放到这个vector中

void operator+=(fn_t f) {
handlers.push_back(f);
}
void operator()(_t... args