owner_t& operator(const value_t& val) {
value = val;
return *owner;
}
};
struct initor {
attr
attr
initor() {
text.owner = this;
visible.owner = this;
}
};
后来发觉,这个initor是不可扩展的
[cpp]
struct checkbox_initor : initor {
attr
checkbox_initor() {
checked.owner = this;
}
};
checkbox_initor().checked(true).text("."); // 这样ok
checkbox_initor().text(".").checked(true); // 这样不行,因为.text(".")返回一个initor基类,不具备checked
struct checkbox_initor : initor {
attr
checkbox_initor() {
checked.owner = this;
}
};
checkbox_initor().checked(true).text("."); // 这样ok
checkbox_initor().text(".").checked(true); // 这样不行,因为.text(".")返回一个initor基类,不具备checked
解决办法是给基类 initor 加上模板参数
[cpp]
template
struct initor {
attr
attr
...
};
template
struct initor {
attr
attr
...
};
详见 initor.h
每种控件对应的initor,用traits来定义:
[cpp]
// wnd_traits 定义
template
struct wnd_traits {
typedef initor::wnd initor_t;
};
// 针对按钮的特化
struct button;
template<>
struct wnd_traits
// wnd_traits 定义
template
struct wnd_traits {
typedef initor::wnd initor_t;
};
// 针对按钮的特化
struct button;
template<>
struct wnd_traits
6 layout
_gui 分为两种控件,普通控件和容器,容器多出了 layout 和 children 两样东西,所以window, tab, panel 这些从 container 继承,而 button,label 等从 wnd_base 继承。
布局这个概念只有容器才有,当容器获大小改变会收到 WM_SIZE 消息,这时候用 layout 进行布局。 参考 container.h
layout 只有一个接口 apply
[cpp]
namespace layout {
struct base {
virtual void apply(wnd_ptr& parent, vector
};
}
namespace layout {
struct base {
virtual void apply(wnd_ptr& parent, vector
};
}
各种layout实现这个apply来布置窗口,比如 fit 是把子窗口填充满整个容器
[cpp]
// fit layout
namespace layout {
struct fit : base {
virtual void apply(wnd_ptr& p, vector
rect r = p->client_rect;
for(auto& c : ch) { // 通常只有一个子窗口
c->rect = r;
}
}
};
}
// fit layout
namespace layout {
struct fit : base {
virtual void apply(wnd_ptr& p, vector
rect r = p->client_rect;
for(auto& c : ch) { // 通常只有一个子窗口
c->rect = r;
}
}
};
}
比如垂直分割布局 vsplit:
[cpp]
// layout/split.h
namespace layout {
struct vsplit : base {
wnd
vsplit(int offset) {
sp = 创建vsplitter;
}
virtual void apply(wnd_ptr& p, vector
std::call_once(在容器p上画出 sp);
ch[0]->rect = 分隔条左边区域大小;
// splitter
sp->rect = ..;// 拉伸分隔条高度 = 容器高度
ch[1]->rect = 分隔条右边区域大小;
}
};
}
// layout/split.h
namespace layout {
struct vsplit : base {
wnd
vsplit(int offset) {
sp = 创建vsplitter;
}
virtual void apply(wnd_ptr& p, vector
std::call_once(在容器p上画出 sp);
ch[0]->rect = 分隔条左边区域大小;
// splitter
sp->rect = ..;// 拉伸分隔条高度 = 容器高度
ch[1]->rect = 分隔条右边区域大小;
}
};
}
总之在 apply 内可以实现所有布局,比如可以做一套传统的java布局,我没有考虑实现那些,觉得不够通用。以经典 border 为例,支持5个东西以 "东南西北中" 放置,但我要在界面上放7个东西 “东南西北中发白”, 他就不支持了,除非用嵌套 panel 的方法, 既浪费一些内存,代码写出来也不易读。
需要一个万能的布局。为此我google了老半天,发觉两个还不错
1. PageLayout A Layout Manager for Java Swing/AWT
它的 doc 里说道 PageLayout: The Only Layout Manager You Will Ever Need
2. DesignGridLayout for java
如果装了java,可以直接运行他的demo
但还是