Views 提供了通过 Widget 对象创建对话框和其他类型窗口的支持。开发者通过实现一个 WidgetDelegate(或其子接口),为窗口提供显示所需的信息,并提供窗口事件的回调通知。
简单示例
以下是创建一个简单窗口的示例代码:
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/utf_string_conversions.h"
#include "ui/gfx/canvas.h"
#include "ui/views/controls/label.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
class WindowView : public views::WidgetDelegateView {
public:
WindowView() : label_(NULL) { Init(); }
virtual ~WindowView() {}
private:
// Overridden from views::View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
canvas->FillRect(GetLocalBounds(), SK_ColorWHITE);
}
virtual void Layout() OVERRIDE {
gfx::Size ps = label_->GetPreferredSize();
label_->SetBounds((width() - ps.width()) / 2, (height() - ps.height()) / 2,
ps.width(), ps.height());
}
virtual gfx::Size GetPreferredSize() OVERRIDE {
gfx::Size ps = label_->GetPreferredSize();
ps.set_width(ps.width() + 200);
ps.set_height(ps.height() + 200);
return ps;
}
// Overridden from views::WidgetDelegate:
virtual string16 GetWindowTitle() const OVERRIDE {
return ASCIIToUTF16("Hello World Window");
}
virtual bool CanResize() const OVERRIDE { return true; }
virtual bool CanMaximize() const OVERRIDE { return true; }
virtual views::View* GetContentsView() OVERRIDE { return this; }
void Init() {
label_ = new views::Label(ASCIIToUTF16("Hello, World!"));
AddChildView(label_);
}
views::Label* label_;
DISALLOW_COPY_AND_ASSIGN(WindowView);
};
...
views::Widget::CreateWindow(new WindowView)->Show();
这个窗口在用户关闭时会自行删除,这将导致其内的 RootView 被销毁,包括 WindowView。
WidgetDelegate
WidgetDelegate 是一个接口,为 Widget 类提供显示窗口时所需的信息,如标题和图标,以及窗口是否可调整大小等属性。它还提供了如关闭等事件的回调函数。WidgetDelegate 有一个访问器 window(),它提供对关联窗口对象的访问。一个 Widget 有一个 ContentsView,由 WidgetDelegate 提供,它是一个插入到窗口客户区的 View。
DialogDelegate
DialogDelegate 是一种专门用于对话框的 WidgetDelegate,通常带有 OK/Cancel 按钮。DialogDelegate 及其关联的 ClientView(见下文)提供了内置的 OK/Cancel 按钮、Esc/Enter 的键盘处理程序及这些功能的启用。作为用户,你编写的 View 将插入到 DialogClientView 中提供对话框的内容,并实现 DialogDelegate 以代替 WidgetDelegate,后者提供按钮点击时的回调函数以及提供按钮文本等方法。
Client 和 Non-Client Views

由于 Chrome 的非标准窗口设计,Views 支持自定义渲染的非客户区。这是通过 Window 类和 NonClientFrameView 子类来支持的。要提供自定义窗口框架,View 子类化 NonClientFrameView,允许重写的 View 来渲染和响应窗口非客户区的事件。Views 包含两个内置类型来实现这一点——CustomFrameView 和 NativeFrameView。它们用于标准对话框和顶级窗口。
对于浏览器窗口,使用了不同的 NonClientFrameView 子类(如 GlassBrowserFrameView 和 OpaqueBrowserFrameView)。为允许使用这些子类,浏览器重写了 Window 的 CreateFrameViewForWindow 方法,以构造适当的框架视图。
除了 RootView 之外,窗口 View 层次结构中的顶层 View 是 NonClientView。这个 View 是一个容器,包含上面描述的 NonClientFrameView 和 ClientView 或其子类。ClientView 子类包含窗口客户区的内容(标题栏/框架内的内容)。一个常见的 ClientView 子类是 DialogClientView,它提供了内置的 OK/Cancel 按钮处理和对话框主题背景。要使用的具体 ClientView 由 WidgetDelegate 在其 CreateClientView 实现中指定。DialogDelegate 的默认实现会自动创建一个 DialogClientView。自定义 WidgetDelegate 可以实现此方法以返回其自己的 ClientView,例如 BrowserView(浏览器窗口的 WidgetDelegate 实现者)返回它自己。ClientView API 相对简单,但它可以在进行非客户区命中测试时执行操作,这是在 TabStrip 内的可拖动标题栏和窗口调整大小角的实现方式。
ClientView 和 NonClientFrameView 是兄弟视图,因为 Views 通常会在它们被插入 View 层次结构时进行一次性初始化,而 Windows Vista 及更新版本的 DWM 切换意味着需要在启用或禁用 DWM 时更换 NonClientFrameView。因此,如果 ClientView 是 NonClientFrameView 的子视图,它将被重新父化,这意味着它的子视图可能会重新初始化,导致负面影响。
创建一个窗口
使用上面定义的 WindowView 创建窗口的简单代码如下:
views::Widget* window = views::Widget::CreateWindow(new WindowView);
window->Show();
这段代码展示了如何使用 Views 创建和管理自定义窗口。