orbtk目前内置的控件并不多,基础控件主要有:
首先,我们先创建一个包含基础控件的窗口,看看效果:
use orbtk::*;
use styling::vector_graphics::material_font_icons::CHECK_FONT_ICON;
fn main() {
let mut application = Application::default();
//创建控件
let text_block = TextBlock::create().with_property(Label::from("textblock"));
let text_box = TextBox::create().with_property(Label::from("textbox"));
let water_mark_text_box = TextBox::create().with_property(WaterMark::from("watermark..."));
let btn = Button::create().with_property(Label::from("button"));
let toggle_btn = ToggleButton::create().with_property(Label::from("togglebutton"));
let switch = Switch::create();
let check_box = CheckBox::create().with_property(Label::from("checkbox"));
let font_icon_block = FontIconBlock::create().with_property(FontIcon::from(CHECK_FONT_ICON));
let image_widget = ImageWidget::create()
.with_property(Image::from_path("src/bin/img/home.png").unwrap_or(Image::default()));
let water_mark_text_block = TextBlock::create()
.with_property(Label::from(""))
.with_property(WaterMark::from("textblockmark..."));
let water_mark_text_block2 = WaterMarkTextBlock::create()
.with_property(Label::from(String::new()))
.with_property(WaterMark::from("yyyy..."));
//所有控件放入Row布局控件中
//直接把所有控件加入rootde Template控件会重叠
//所以把所有控件都放在一个layout控件中
let column = Column::create()
.with_child(text_block)
.with_child(text_box)
.with_child(water_mark_text_box)
.with_child(btn)
.with_child(toggle_btn)
.with_child(switch)
.with_child(check_box)
.with_child(font_icon_block)
.with_child(image_widget)
.with_child(water_mark_text_block)
.with_child(water_mark_text_block2);
//rootde parent_tyep可以设置为Multi,但是控件会重叠
//所以初学者,建议root就设置为single,root只放一个layout控件
let root = Template::default()
.as_parent_type(ParentType::Single)
.with_child(column);
application
.create_window()
.with_bounds(Bounds::new(100, 100, 320, 260))
.with_title("OrbTk - Widgets")
.with_resizable(true)
.with_root(root)
//.with_debug_flag(true)
.build();
application.run();
}
当然,上述代码只是为了方便入门学习,可以用更加Rustacean的方式写代码:
use orbtk::*;
use styling::vector_graphics::material_font_icons::CHECK_FONT_ICON;
struct MainView;
impl Widget for MainView {
fn create() -> Template {
Template::default()
.as_parent_type(ParentType::Single)
.with_child(
Column::create()
.with_child(TextBlock::create().with_property(Label::from("textblock")))
.with_child(TextBox::create().with_property(Label::from("textbox")))
.with_child(TextBox::create().with_property(WaterMark::from("watermark...")))
.with_child(Button::create().with_property(Label::from("button")))
.with_child(ToggleButton::create().with_property(Label::from("togglebutton")))
.with_child(Switch::create())
.with_child(CheckBox::create().with_property(Label::from("checkbox")))
.with_child(
FontIconBlock::create().with_property(FontIcon::from(CHECK_FONT_ICON)),
)
.with_child(ImageWidget::create().with_property(
Image::from_path("src/bin/img/home.png").unwrap_or(Image::default()),
))
.with_child(
TextBlock::create()
.with_property(Label::from(""))
.with_property(WaterMark::from("textblockmark...")),
)
.with_child(
WaterMarkTextBlock::create()
.with_property(Label::from(String::new()))
.with_property(WaterMark::from("yyyy...")),
),
)
}
}
fn main() {
let mut application = Application::default();
application
.create_window()
.with_bounds(Bounds::new(100, 100, 320, 260))
.with_title("OrbTk - Widgets")
.with_resizable(true)
.with_root(MainView::create())
//.with_debug_flag(true)
.build();
application.run();
}
cargo run编译运行后显示窗口如下:
orbtk所有控件的定义都是空结构体,即:
pub struct TextBlock;
pub struct Button;
pub struct Row;
orbtk所有控件都实现了Widget trait,并且目前所有控件都只实现了这一个trait。Widget trait也只有一个方法create()。
impl Widget for TextBlock {
fn create() -> Template {
...
}
impl Widget for Row {
fn create() -> Template {
...
}
也就是说目前所有orbtk控件都只包含一个create方法。这个create方法返回一个Template。创建控件的时候事实上就是使用create方法创建一个Template。我们可以看到上节代码中使用Button::create()
,TextBox::create()
等等创建控件。
设置控件属性也是使用Template的with_property()方法来设置的。所有的控件都是Template的实例,只是不同控件的属性及默认render不同。每个orbtk控件都在create()方法中设置了默认的render,orbtk绘制窗口的时候调用默认的render根据Template的属性绘制控件树。
orbtk自定义控件,就相当于新建一个Template并设置相关属性。难点主要在于render是否需要重写。
所有的控件都使用create()方法创建,比如:
let btn=Button::create();
let text_block=TextBlock::create();
控件都通过Template的方法进行属性设置,主要包括
使用with_child()方法添加子控件,比如:
Row::create().with_child(btn);
添加多个子控件可以多次调用with_child()方法,支持链式调用。
Row::create().with_child(btn).with_child(text_block);
//也可以
let row=Row::create().with_child(btn);
let row=row.with_child(text_block)
注意helloworld节已经提到的,Template有一个parent_type成员,其值表示能够添加多少个子控件。
parent_type
值为ParentType::None
,不能添加子控件parent_type
值为ParentType::Single
,只能添加一个子控件,如果已经有一个子控件,则覆盖/替换parent_type
值为ParentType::Multi
,可以添加任意多个子控件为Template控件添加子控件之前都必须先设置一下parent_type。方法为as_parent_type()
Template::default().as_parent_type(ParentType::Single)
orbtk内置的控件都有默认的parent_type值,添加子控件前不用再设置。比如TextBlock为None,Container为Single,Row为Multi。
使用with_property()方法设置属性
btn.with_property(Label::from("button"));
可以多次调用with_property()方法多次设置属性。
大家可以看到设置属性的时候并没有提供属性的名称,Template是根据属性类型来分辨不同属性的。所以Template中不同的属性都是不同的类型。
这也就是为什么Button在设置Label属性的时候不直接使用String,而使用一个Label结构把String包装起来的原因。Label的定义事实上就是
pub struct Label(pub String)
。
Template还有一个with_shared_property方法,这个shared_property我们后边再讲。
with_state()
,with_event_handler()
两个方法分别用于添加状态和事件处理器,都是用于处理用户交互的,后续再讲。
with_render_object()
和with_layout()
两个方法分别用于添加render和layout。都是和绘制控件相关的,所有orbtk内建的控件都设置了默认的render和layout,入门学习可以暂时不用管这两个方法。
orbtk控件支持使用css样式,每个控件都可以通过设置selector属性来关联css选择器。
样式我们后续再讲讲。
所有控件都支持的属性:
btn.with_property(Bounds::new(20,20,20,20));
btn.with_property(Visibility::Hidden);//控件不可见
btn.with_property(Visibility::Collapsed);//控件不可见,且不占位置
btn.with_property(
Selector::from("button").with_class("primary")
)//css中使用button选择器,primary class定义btn的样式
TextBlock控件的功能就是现实文本,不能编辑,不能交互。
TextBlock通常只需要设置Label属性
TextBlock::create().with_property(Label::from("textblock"));
WaterMarkTextBlock控件类似TextBlock,但是会在Label属性为空的时候现实WaterMark属性的内容。
WaterMarkTextBlock控件主要属性包括:
WaterMarkTextBlock::create()
.with_property(Label::from("textblock"))
.with_property(WaterMark::from("wartermark..."));
目前事实上TextBlock设置WaterMark属性后和watermarktextblock效果一样。
以下两种代码效果相同:
WaterMarkTextBlock::create()
.with_property(Label::from(String::new()))
.with_property(WaterMark::from("yyyy..."));
TextBlock::create()
.with_property(Label::from(""))
.with_property(WaterMark::from("textblockmark..."));
但是watermarktextblock貌似有bug,只有在WaterMarkTextBlock后方没有控件的时候才能正常显示,否则会被后方控件遮住。把WaterMarkTextBlock放在container或者Row中也会出现被裁剪的问题,大家可以试一下。
TextBox是一个文本框,可以交互输入。主要属性有
TextBox::create()
.with_property(WaterMark::from("watermark..."))
.with_property(Focused(true))
.with_property(Enabled(false))
貌似目前TextBox还不能用小键盘输入。
Button控件是个按钮控件,ToggleButton是一个开关型按钮。主要属性有:
Button::create()
.with_property(Label::from("btn"))
.with_property(FontIcon::from(CHECK_FONT_ICON))
.with_property(Pressed(true))
.with_property(Enabled(false))
checkbox的主要属性有
CheckBox::create()
.with_property(Label::from("checkbox"))
.with_property(FontIcon::from(FLOPPY_FONT_ICON))
.with_property(Selected(true))
.with_property(Enabled(true))
属性设置方法和checkbox相同,大多数时候只需要设置Selected属性就ok了。
ImageWidget用于显示图片,主要属性为Image
ImageWidget::create()
.with_property(
Image::from_path("src/bin/img/home.png").unwrap_or(Image::default())
)
FontIconBlock显示一个FontIcon图标,图标为font内的特殊字体。
use styling::vector_graphics::material_font_icons::{CHECK_FONT_ICON, FLOPPY_FONT_ICON};
FontIconBlock::create().with_property(FontIcon::from(CHECK_FONT_ICON))
FontIcon::from()的参数实际上是一个&str
,所以可以这样用:
FontIconBlock::create().with_property(FontIcon::from(""))
本文代码在https://github.com/hustlei/RustGuiOrbtkTutorial
可以使用下面命令编译运行
cargo run --bin widgets
cargo run --bin primitive_widgets