剩下要做的事就创建控件实例时给 p_this 和 member_func 赋值了,以button为例
[cpp]
struct button {
thunk
struct button {
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
listview() {
title.绑定(get_title, set_title);
}
void set_title(string s) { SetWindowText(...); }
string get_title() { GetWindowText(...); }
};
wnd
sting s = lv->title; //会调用 get_title()
lv->title = "new_title"; //会调用 set_title("new_title")
struct listview {
property::rw
listview() {
title.绑定(get_title, set_title);
}
void set_title(string s) { SetWindowText(...); }
string get_title() { GetWindowText(...); }
};
wnd
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
vector
void operator+=(fn_t f) {
handlers.push_back(f);
}
void operator()(_t... args