一步一步实现自己的模拟控件(5)——隐藏类
隐藏驱动类:
为了让用户有更简单的使用接口,我们需要把不必要的东西进行一定的隐藏。前面我就提到WidgetDriver对于用户来说是不关心的东西,那么我们就将其进行隐藏。
方案1:
将WidgetDriver放到Widget.cpp中,这样的隐藏方式是最严密的,对于用户来说完全看不到WidgetDriver。但是随着我们的实现膨胀,这会让我们的Widget.cpp变得非常臃肿。
方案2:
不改变文件结构,将WidgetDriver私有化,通过友元声明使得只有Widget类对象能够访问WidgetDriver。这样用户虽然能够看到WidgetDriver这个类定义,但是却无法使用,这样对于代码的结构组织也更有利。
我采用了方案2
class Driver_{
friend class Widget;
DriverImpl_* pImpl_;
private:
explicit Driver_(HWND hWnd);
~Driver_();
Driver_(const Driver_&);
Driver_& operator =(const Driver_&);
private:
void SetRootWidget(Widget* pRootWidget);
HWND GetContainerWindow() const;
Widget* GetRootWidget() const;
};
因为我们隐藏了WidgetDriver,那么它的职能就能够进行简化。前面提到的根控件和WidgetDriver之间的关系我们就能够改为当方面控制了。于是我将WidgetDriver放到了根控件中进行管理,我们只需要操作根控件便可。
Widget::Widget(HWND hWnd)
: pImpl_(new WidgetImpl)
{
pImpl_->pDriver = new widget::Driver_(hWnd);
pImpl_->pDriver->SetRootWidget(this);
}
Widget::~Widget()
{
if (IsRoot())
{
delete pImpl_->pDriver;
}
delete pImpl_;
}
前面我们都没有提到应该何时结束我们的系统,但是我们的系统生命周期和窗口是息息相关的,在窗口销毁的时候那么和这个窗口相关联的控件体系就应该销毁。于是我们对消息过滤器做了一点点改动:
LRESULT MessageFilter::Filter(const Param& param, Widget* pRootWidget)
{
assert(param.originalProc);
assert(pRootWidget);
#ifdef _DEBUG
std::stringstream ss;
ss<<"窗口消息: "<<std::showbase<<std::hex<<param.message<<" 进入Widget消息过滤!\r\n";
::OutputDebugStringA(ss.str().c_str());
#endif // _DEBUG
LRESULT ret = ::CallWindowProc(
param.originalProc,
param.hWnd,
param.message,
param.wParam,
param.lParam);
if (WM_DESTROY == param.message)
{
// 销毁根控件
pRootWidget->Destroy();
}
return ret;
}
下一步我们便要开始对我们的控件进行设计了,我们自始至终都将控件抽象为窗口客户区的一个区域,所以说我们并不打算使用继承来扩展控件。后面会看到我们使用插入式的扩展,这样的方式具备动态替换的能力甚至还能将一个扩展共享给多个控件使用。
By Evil.Ghost