Chromium GN 目标指南 - view_examples 自定义Button示例 (六)
1. 引言
在上一篇文章中,我们介绍了 views_examples
这一重要的示例程序,它展示了 Chromium Views 框架中各种控件的使用方法。在本篇文章中,我们将更进一步,尝试在 views_examples
中添加自定义的 Button 示例,以学习如何创建和使用自定义控件,并将其集成到现有的 GN 目标中。
2. 创建自定义 Button 示例
为了添加自定义的 Button 示例,我们需要创建新的头文件和源文件,并在其中定义我们的自定义 Button 类和相关的示例代码。
2.1 创建头文件
首先,我们在 ui/views/examples/
目录下创建一个名为 my_custom_button_example.h
的头文件,并在其中添加以下代码:
#ifndef UI_VIEWS_EXAMPLES_MY_CUSTOM_BUTTON_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_MY_CUSTOM_BUTTON_EXAMPLE_H_
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h"
#include "ui/views/examples/example_base.h"
namespace views::examples {
class MyCustomButtonExample : public ExampleBase {
public:
MyCustomButtonExample();
MyCustomButtonExample(const MyCustomButtonExample&) = delete;
MyCustomButtonExample& operator=(const MyCustomButtonExample&) = delete;
~MyCustomButtonExample() override = default;
// ExampleBase:
void CreateExampleView(View* container) override;
private:
void OnButtonClicked();
void OnIconButtonClicked();
void OnStyledButtonClicked();
raw_ptr<views::Label> status_label_ = nullptr;
};
} // namespace views::examples
#endif // UI_VIEWS_EXAMPLES_MY_CUSTOM_BUTTON_EXAMPLE_H_
这段代码定义了一个名为 MyCustomButtonExample
的类,它继承自 ExampleBase
。ExampleBase
是 views_examples
中所有示例的基类,提供了一些通用的功能。
在 MyCustomButtonExample
类中,我们声明了三个私有成员函数:OnButtonClicked
、OnIconButtonClicked
和 OnStyledButtonClicked
,分别用于处理三种不同按钮的点击事件。我们还声明了一个 raw_ptr<views::Label>
类型的成员变量 status_label_
,用于显示按钮点击后的状态信息。
2.2 创建源文件
接下来,我们在 ui/views/examples/
目录下创建一个名为 my_custom_button_example.cc
的源文件,并在其中添加以下代码:
#include "ui/views/examples/my_custom_button_example.h"
#include "base/functional/bind.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/vector_icons.h"
#include "base/logging.h"
namespace views::examples {
MyCustomButtonExample::MyCustomButtonExample() : ExampleBase("custom button example") {}
void MyCustomButtonExample::CreateExampleView(View* container) {
// 使用垂直布局
auto* layout = new views::BoxLayout(
views::BoxLayout::Orientation::kVertical,
gfx::Insets(10), // 边距
10); // 按钮间距
container->SetLayoutManager(std::unique_ptr<views::BoxLayout>(layout));
// 1. 基础按钮
auto* basic_button = new views::MdTextButton(
base::BindRepeating(&MyCustomButtonExample::OnButtonClicked,
base::Unretained(this)),
u"basic button");
container->AddChildView(basic_button);
// 2. 带图标的按钮
auto* icon_button = new views::MdTextButton(
base::BindRepeating(&MyCustomButtonExample::OnIconButtonClicked,
base::Unretained(this)),
u"icon button");
icon_button->SetImageModel(
views::Button::STATE_NORMAL,
ui::ImageModel::FromVectorIcon(views::kInfoIcon));
container->AddChildView(icon_button);
// 3. 自定义样式按钮
auto* styled_button = new views::MdTextButton(
base::BindRepeating(&MyCustomButtonExample::OnStyledButtonClicked,
base::Unretained(this)),
u"styled button");
styled_button->SetStyle(ui::ButtonStyle::kTonal);
container->AddChildView(styled_button);
// 4. 状态标签
status_label_ = new views::Label(u"click button to see effect");
container->AddChildView(status_label_);
}
void MyCustomButtonExample::OnButtonClicked() {
status_label_->SetText(u"basic button clicked");
LOG(INFO) << "Basic button clicked";
}
void MyCustomButtonExample::OnIconButtonClicked() {
status_label_->SetText(u"icon button clicked");
LOG(INFO) << "Icon button clicked";
}
void MyCustomButtonExample::OnStyledButtonClicked() {
status_label_->SetText(u"styled button clicked");
LOG(INFO) << "Styled button clicked";
}
} // namespace views::examples
这段代码实现了 MyCustomButtonExample
类的构造函数和 CreateExampleView
、OnButtonClicked
、OnIconButtonClicked
、OnStyledButtonClicked
方法。
MyCustomButtonExample::MyCustomButtonExample()
: 构造函数,调用了父类ExampleBase
的构造函数,并设置了示例的名称为 "custom button example"。MyCustomButtonExample::CreateExampleView(View* container)
: 这个方法负责创建并添加按钮到container
中。- 首先,它创建了一个垂直布局管理器
BoxLayout
,并将其设置给container
。 - 然后,它创建了三种不同类型的按钮:
basic_button
: 一个普通的文本按钮,点击后会调用OnButtonClicked
方法。icon_button
: 一个带图标的文本按钮,点击后会调用OnIconButtonClicked
方法。这里使用了views::kInfoIcon
作为按钮图标。styled_button
: 一个自定义样式的文本按钮,点击后会调用OnStyledButtonClicked
方法。这里使用了ui::ButtonStyle::kTonal
样式。
- 最后,它创建了一个
Label
控件status_label_
,用于显示按钮点击后的状态信息。
- 首先,它创建了一个垂直布局管理器
MyCustomButtonExample::OnButtonClicked()
: 当basic_button
被点击时,这个方法会被调用。它会将status_label_
的文本设置为 "basic button clicked",并在日志中输出 "Basic button clicked"。MyCustomButtonExample::OnIconButtonClicked()
: 当icon_button
被点击时,这个方法会被调用。它会将status_label_
的文本设置为 "icon button clicked",并在日志中输出 "Icon button clicked"。MyCustomButtonExample::OnStyledButtonClicked()
: 当styled_button
被点击时,这个方法会被调用。它会将status_label_
的文本设置为 "styled button clicked",并在日志中输出 "Styled button clicked"。
3. 修改 BUILD.gn 文件
为了将我们的自定义 Button 示例添加到构建系统中,我们需要修改 ui/views/examples/BUILD.gn
文件,将我们新创建的源文件添加到 examples
目标的 sources
属性中。
打开 ui/views/examples/BUILD.gn
文件,找到 views_examples_lib
部分,并在 sources
列表中添加以下两行:
"my_custom_button_example.cc",
"my_custom_button_example.h",
4. 注册示例
最后,我们需要在 ui/views/examples/create_examples.cc
文件中注册我们的自定义示例,这样 views_examples
程序才能找到并显示它。
打开 ui/views/examples/create_examples.cc
文件,找到 CreateExamples
函数,并在 examples
向量中添加以下代码:
#include "ui/views/examples/my_custom_button_example.h"
// exists code
examples.push_back(std::make_unique<MyCustomButtonExample>());
添加完后代码如下
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/examples/create_examples.h"
#include <memory>
#include <utility>
#include "build/build_config.h"
#include "ui/views/examples/actions_example.h"
#include "ui/views/examples/animated_image_view_example.h"
#include "ui/views/examples/animation_example.h"
#include "ui/views/examples/ax_example.h"
#include "ui/views/examples/badge_example.h"
#include "ui/views/examples/box_layout_example.h"
#include "ui/views/examples/bubble_example.h"
#include "ui/views/examples/button_example.h"
#include "ui/views/examples/button_sticker_sheet.h"
#include "ui/views/examples/checkbox_example.h"
#include "ui/views/examples/colored_dialog_example.h"
#include "ui/views/examples/colors_example.h"
#include "ui/views/examples/combobox_example.h"
#include "ui/views/examples/designer_example.h"
#include "ui/views/examples/dialog_example.h"
#include "ui/views/examples/fade_animation.h"
#include "ui/views/examples/flex_layout_example.h"
#include "ui/views/examples/ink_drop_example.h"
#include "ui/views/examples/label_example.h"
#include "ui/views/examples/link_example.h"
#include "ui/views/examples/login_bubble_dialog_example.h"
#include "ui/views/examples/menu_example.h"
#include "ui/views/examples/message_box_example.h"
#include "ui/views/examples/multiline_example.h"
#include "ui/views/examples/notification_example.h"
#include "ui/views/examples/progress_bar_example.h"
#include "ui/views/examples/radio_button_example.h"
#include "ui/views/examples/scroll_view_example.h"
#include "ui/views/examples/slider_example.h"
#include "ui/views/examples/square_ink_drop_example.h"
#include "ui/views/examples/tabbed_pane_example.h"
#include "ui/views/examples/table_example.h"
#include "ui/views/examples/text_example.h"
#include "ui/views/examples/textarea_example.h"
#include "ui/views/examples/textfield_example.h"
#include "ui/views/examples/throbber_example.h"
#include "ui/views/examples/toggle_button_example.h"
#include "ui/views/examples/tree_view_example.h"
#include "ui/views/examples/typography_example.h"
#include "ui/views/examples/vector_example.h"
#include "ui/views/examples/widget_example.h"
#include "ui/views/examples/my_custom_button_example.h"
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_FUCHSIA)
#include "ui/views/examples/color_chooser_example.h"
#endif
namespace views::examples {
// Creates the default set of examples.
ExampleVector CreateExamples(ExampleVector extra_examples) {
ExampleVector examples = std::move(extra_examples);
examples.push_back(std::make_unique<ActionsExample>());
examples.push_back(std::make_unique<AnimatedImageViewExample>());
examples.push_back(std::make_unique<AnimationExample>());
examples.push_back(std::make_unique<AxExample>());
examples.push_back(std::make_unique<BadgeExample>());
examples.push_back(std::make_unique<BoxLayoutExample>());
examples.push_back(std::make_unique<BubbleExample>());
examples.push_back(std::make_unique<ButtonExample>());
examples.push_back(std::make_unique<ButtonStickerSheet>());
examples.push_back(std::make_unique<CheckboxExample>());
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_FUCHSIA)
examples.push_back(std::make_unique<ColorChooserExample>());
#endif
examples.push_back(std::make_unique<ColoredDialogExample>());
examples.push_back(std::make_unique<ColorsExample>());
examples.push_back(std::make_unique<ComboboxExample>());
examples.push_back(std::make_unique<DesignerExample>());
examples.push_back(std::make_unique<DialogExample>());
examples.push_back(std::make_unique<FadeAnimationExample>());
examples.push_back(std::make_unique<FlexLayoutExample>());
examples.push_back(std::make_unique<InkDropExample>());
examples.push_back(std::make_unique<LabelExample>());
examples.push_back(std::make_unique<LinkExample>());
examples.push_back(std::make_unique<LoginBubbleDialogExample>());
examples.push_back(std::make_unique<MenuExample>());
examples.push_back(std::make_unique<MessageBoxExample>());
examples.push_back(std::make_unique<MultilineExample>());
examples.push_back(std::make_unique<NotificationExample>());
examples.push_back(std::make_unique<ProgressBarExample>());
examples.push_back(std::make_unique<RadioButtonExample>());
examples.push_back(std::make_unique<ScrollViewExample>());
examples.push_back(std::make_unique<SliderExample>());
examples.push_back(std::make_unique<SquareInkDropExample>());
examples.push_back(std::make_unique<TabbedPaneExample>());
examples.push_back(std::make_unique<TableExample>());
examples.push_back(std::make_unique<TextExample>());
examples.push_back(std::make_unique<TextareaExample>());
examples.push_back(std::make_unique<TextfieldExample>());
examples.push_back(std::make_unique<ToggleButtonExample>());
examples.push_back(std::make_unique<ThrobberExample>());
examples.push_back(std::make_unique<TreeViewExample>());
examples.push_back(std::make_unique<TypographyExample>());
examples.push_back(std::make_unique<VectorExample>());
examples.push_back(std::make_unique<WidgetExample>());
examples.push_back(std::make_unique<MyCustomButtonExample>());
return examples;
}
} // namespace views::examples
5. 重新编译并运行
完成以上步骤后,我们需要重新编译 views_examples
目标。在 Chromium 源码的 src
目录下执行以下命令:
autoninja -C out/Default views_examples
这里假设您的构建目录为 out/Default
,如果不是请对应修改
编译完成后,运行 views_examples
:
./out/Default/views_examples
如果一切顺利,你将在 "Views Examples" 窗口中看到一个新的标签页 "custom button example",点击该标签页,你将看到我们自定义的三种不同类型的按钮,以及一个用于显示状态信息的 Label。点击不同的按钮,Label 的文本会相应地改变,同时终端中也会输出相应的日志信息。
6. 结语
在本篇文章中,我们学习了如何在 views_examples
中添加自定义的 Button 示例,包括创建头文件和源文件、修改 BUILD.gn
文件、注册示例以及重新编译和运行。通过这个过程,我们学习了如何创建和使用自定义控件,并将其集成到现有的 GN 目标中。
希望这篇文章能够帮助你更好地理解 Chromium 的 Views 框架和 GN 构建系统,为你在 Chromium 平台上的 UI 开发提供帮助。在接下来的文章中,我们将继续探索 Chromium 和 GN 的更多高级用法。