C++界面库:使用Graphic Element Template制作按钮模板
这一次制作的按钮模板具有通过模板属性动态配置图形的功能。模板的属性一共有6个:x、y、w、h、state、content,其中state有normal、hot和press三个取值。XML、代码和截图如下:
下面的模板文件有两个模板,分别是background和button。background制作玻璃效果,button给background加上一个边框,展示了property evaluation和template reference的功能:
1
<?
xml version="1.0" encoding="utf-8"
?>
2 < irconfig xmlns ="http://tempuri.org/irconfig.xsd" >
3 < resources >
4 < brush name ="outer_border_brush" kind ="solid" >
5 < main_color r ="96" g ="128" b ="255" a ="255" />
6 </ brush >
7
8 < brush name ="up_content_brush_normal" kind ="linear_gradient" gradient_angle ="0" >
9 < main_color r ="224" g ="224" b ="224" a ="255" />
10 < gradient_color r ="192" g ="192" b ="192" a ="255" />
11 </ brush >
12 < brush name ="down_content_brush_normal" kind ="linear_gradient" gradient_angle ="0" >
13 < main_color r ="128" g ="128" b ="128" a ="255" />
14 < gradient_color r ="160" g ="160" b ="160" a ="255" />
15 </ brush >
16
17 < brush name ="up_content_brush_hot" kind ="linear_gradient" gradient_angle ="0" >
18 < main_color r ="224" g ="224" b ="255" a ="255" />
19 < gradient_color r ="192" g ="192" b ="255" a ="255" />
20 </ brush >
21 < brush name ="down_content_brush_hot" kind ="linear_gradient" gradient_angle ="0" >
22 < main_color r ="128" g ="128" b ="255" a ="255" />
23 < gradient_color r ="160" g ="160" b ="255" a ="255" />
24 </ brush >
25
26 < brush name ="up_content_brush_press" kind ="linear_gradient" gradient_angle ="0" >
27 < main_color r ="224" g ="224" b ="255" a ="255" />
28 < gradient_color r ="160" g ="160" b ="255" a ="255" />
29 </ brush >
30 < brush name ="down_content_brush_press" kind ="linear_gradient" gradient_angle ="0" >
31 < main_color r ="32" g ="32" b ="255" a ="255" />
32 < gradient_color r ="96" g ="96" b ="255" a ="255" />
33 </ brush >
34
35 < brush name ="background_brush" kind ="solid" >
36 < main_color r ="255" g ="255" b ="255" a ="255" />
37 </ brush >
38 < brush name ="text_brush" kind ="solid" >
39 < main_color r ="0" g ="0" b ="0" a ="255" />
40 </ brush >
41 < pen name ="outer_border_pen" brush ="outer_border_brush" endcap ="round" join ="round" weight ="1" />
42 < font name ="text_font" face ="微软雅黑" size ="18" />
43 </ resources >
44 < templates >
45 < template name ="background" >
46 < properties >
47 < property name ="x" type ="int" default ="0" />
48 < property name ="y" type ="int" default ="0" />
49 < property name ="w" type ="int" default ="100" />
50 < property name ="h" type ="int" default ="100" />
51 < property name ="state" type ="str" default ="normal" />
52 < property name ="content" type ="str" default ="" />
53 </ properties >
54 < content >
55 < rectangle name ="client" x ="$x" y ="$y" width ="$w" height ="$h" >
56 < text brush ="text_brush" font ="text_font" text ="$content" x ="(client.width-this.width)/2" y ="(client.height-this.height)/2" />
57
58 < rectangle brush ="up_content_brush_normal" visible ="$state=='normal'"
59 x ="0" y ="0" width ="client.width" height ="client.height/2" />
60 < rectangle brush ="down_content_brush_normal" visible ="$state=='normal'"
61 x ="0" y ="client.height/2" width ="client.width" height ="client.height/2+1" />
62
63 < rectangle brush ="up_content_brush_hot" visible ="$state=='hot'"
64 x ="0" y ="0" width ="client.width" height ="client.height*4/9" />
65 < rectangle brush ="down_content_brush_hot" visible ="$state=='hot'"
66 x ="0" y ="client.height*4/9" width ="client.width" height ="client.height*5/9+1" />
67
68 < rectangle brush ="up_content_brush_press" visible ="$state=='press'"
69 x ="0" y ="0" width ="client.width" height ="client.height*5/9" />
70 < rectangle brush ="down_content_brush_press" visible ="$state=='press'"
71 x ="0" y ="client.height*5/9" width ="client.width" height ="client.height*4/9+1" />
72 </ rectangle >
73 </ content >
74 </ template >
75 < template name ="button" >
76 < properties >
77 < property name ="x" type ="int" default ="0" />
78 < property name ="y" type ="int" default ="0" />
79 < property name ="w" type ="int" default ="100" />
80 < property name ="h" type ="int" default ="100" />
81 < property name ="state" type ="str" default ="normal" />
82 < property name ="content" type ="str" default ="" />
83 </ properties >
84 < content >
85 < rectangle name ="border" brush ="background_brush" pen ="outer_border_pen" x ="$x" y ="$y" width ="$w" height ="$h" >
86 < instance reference ="background" >
87 < setter name ="x" value ="1" />
88 < setter name ="y" value ="1" />
89 < setter name ="w" value ="border.client_width-2" />
90 < setter name ="h" value ="border.client_height-2" />
91 < setter name ="state" value ="$state" />
92 < setter name ="content" value ="$content" />
93 </ instance >
94 </ rectangle >
95 </ content >
96 </ template >
97 </ templates >
98 </ irconfig >
2 < irconfig xmlns ="http://tempuri.org/irconfig.xsd" >
3 < resources >
4 < brush name ="outer_border_brush" kind ="solid" >
5 < main_color r ="96" g ="128" b ="255" a ="255" />
6 </ brush >
7
8 < brush name ="up_content_brush_normal" kind ="linear_gradient" gradient_angle ="0" >
9 < main_color r ="224" g ="224" b ="224" a ="255" />
10 < gradient_color r ="192" g ="192" b ="192" a ="255" />
11 </ brush >
12 < brush name ="down_content_brush_normal" kind ="linear_gradient" gradient_angle ="0" >
13 < main_color r ="128" g ="128" b ="128" a ="255" />
14 < gradient_color r ="160" g ="160" b ="160" a ="255" />
15 </ brush >
16
17 < brush name ="up_content_brush_hot" kind ="linear_gradient" gradient_angle ="0" >
18 < main_color r ="224" g ="224" b ="255" a ="255" />
19 < gradient_color r ="192" g ="192" b ="255" a ="255" />
20 </ brush >
21 < brush name ="down_content_brush_hot" kind ="linear_gradient" gradient_angle ="0" >
22 < main_color r ="128" g ="128" b ="255" a ="255" />
23 < gradient_color r ="160" g ="160" b ="255" a ="255" />
24 </ brush >
25
26 < brush name ="up_content_brush_press" kind ="linear_gradient" gradient_angle ="0" >
27 < main_color r ="224" g ="224" b ="255" a ="255" />
28 < gradient_color r ="160" g ="160" b ="255" a ="255" />
29 </ brush >
30 < brush name ="down_content_brush_press" kind ="linear_gradient" gradient_angle ="0" >
31 < main_color r ="32" g ="32" b ="255" a ="255" />
32 < gradient_color r ="96" g ="96" b ="255" a ="255" />
33 </ brush >
34
35 < brush name ="background_brush" kind ="solid" >
36 < main_color r ="255" g ="255" b ="255" a ="255" />
37 </ brush >
38 < brush name ="text_brush" kind ="solid" >
39 < main_color r ="0" g ="0" b ="0" a ="255" />
40 </ brush >
41 < pen name ="outer_border_pen" brush ="outer_border_brush" endcap ="round" join ="round" weight ="1" />
42 < font name ="text_font" face ="微软雅黑" size ="18" />
43 </ resources >
44 < templates >
45 < template name ="background" >
46 < properties >
47 < property name ="x" type ="int" default ="0" />
48 < property name ="y" type ="int" default ="0" />
49 < property name ="w" type ="int" default ="100" />
50 < property name ="h" type ="int" default ="100" />
51 < property name ="state" type ="str" default ="normal" />
52 < property name ="content" type ="str" default ="" />
53 </ properties >
54 < content >
55 < rectangle name ="client" x ="$x" y ="$y" width ="$w" height ="$h" >
56 < text brush ="text_brush" font ="text_font" text ="$content" x ="(client.width-this.width)/2" y ="(client.height-this.height)/2" />
57
58 < rectangle brush ="up_content_brush_normal" visible ="$state=='normal'"
59 x ="0" y ="0" width ="client.width" height ="client.height/2" />
60 < rectangle brush ="down_content_brush_normal" visible ="$state=='normal'"
61 x ="0" y ="client.height/2" width ="client.width" height ="client.height/2+1" />
62
63 < rectangle brush ="up_content_brush_hot" visible ="$state=='hot'"
64 x ="0" y ="0" width ="client.width" height ="client.height*4/9" />
65 < rectangle brush ="down_content_brush_hot" visible ="$state=='hot'"
66 x ="0" y ="client.height*4/9" width ="client.width" height ="client.height*5/9+1" />
67
68 < rectangle brush ="up_content_brush_press" visible ="$state=='press'"
69 x ="0" y ="0" width ="client.width" height ="client.height*5/9" />
70 < rectangle brush ="down_content_brush_press" visible ="$state=='press'"
71 x ="0" y ="client.height*5/9" width ="client.width" height ="client.height*4/9+1" />
72 </ rectangle >
73 </ content >
74 </ template >
75 < template name ="button" >
76 < properties >
77 < property name ="x" type ="int" default ="0" />
78 < property name ="y" type ="int" default ="0" />
79 < property name ="w" type ="int" default ="100" />
80 < property name ="h" type ="int" default ="100" />
81 < property name ="state" type ="str" default ="normal" />
82 < property name ="content" type ="str" default ="" />
83 </ properties >
84 < content >
85 < rectangle name ="border" brush ="background_brush" pen ="outer_border_pen" x ="$x" y ="$y" width ="$w" height ="$h" >
86 < instance reference ="background" >
87 < setter name ="x" value ="1" />
88 < setter name ="y" value ="1" />
89 < setter name ="w" value ="border.client_width-2" />
90 < setter name ="h" value ="border.client_height-2" />
91 < setter name ="state" value ="$state" />
92 < setter name ="content" value ="$content" />
93 </ instance >
94 </ rectangle >
95 </ content >
96 </ template >
97 </ templates >
98 </ irconfig >
程序由4个按钮组成,4个按钮都是button的实例化,但是只处理了最后一个按钮的消息。因为现在只有画图,所以消息处理部分是手动的。下面是截图:
下面是代码:
1
class
ConfigForm :
public
VL_WinForm
2 {
3 protected :
4 IVL_IrFactory::Ptr FFactory;
5 IVL_IrCanvas::Ptr FCanvas;
6 VL_IrConfigLoader::Ptr FLoader;
7 VL_IrConfig::Ptr FConfig;
8 VL_IrTemplateInstance::Ptr FNormalButton;
9 VL_IrTemplateInstance::Ptr FHotButton;
10 VL_IrTemplateInstance::Ptr FPressButton;
11 VL_IrTemplateInstance::Ptr FButton;
12 VBool FClickedOnButton;
13
14 VL_IrTemplateInstance::Ptr CreateButton(VL_IrPoint Position , VUnicodeString State , VUnicodeString Text)
15 {
16 VL_IrTemplateInstance::Ptr Instance = FConfig -> FindTemplate(L " button " ) -> CreateInstance();
17 for (VInt i = 0 ;i < Instance -> GetRootElements().GetCount();i ++ )
18 {
19 FCanvas -> GetRootElement() -> Container() -> AddChild(Instance -> GetRootElements()[i]);
20 }
21
22 Instance -> GetInts()[L " x " ] = Position.X;
23 Instance -> GetInts()[L " y " ] = Position.Y;
24 Instance -> GetInts()[L " w " ] = 100 ;
25 Instance -> GetInts()[L " h " ] = 30 ;
26 Instance -> GetStrs()[L " state " ] = State;
27 Instance -> GetStrs()[L " content " ] = Text;
28 Instance -> Update();
29
30 return Instance;
31 }
32
33 VBool IsOnButton(VLS_MouseStruct Struct)
34 {
35 return FButton -> GetRootElements()[ 0 ] -> Properties() -> ContainedPoint(VL_IrPoint(Struct.X,Struct.Y)) != IVL_IrElement::htrNone;
36 }
37
38 void Form_MouseDown(VL_Base * Sender , VLS_MouseStruct Struct)
39 {
40 FClickedOnButton = IsOnButton(Struct);
41 FButton -> GetStrs()[L " state " ] = FClickedOnButton ? L " press " :L " normal " ;
42 FButton -> Update();
43 FCanvas -> Render();
44 }
45
46 void Form_MouseMove(VL_Base * Sender , VLS_MouseStruct Struct)
47 {
48 VUnicodeString PreviousState = FButton -> GetStrs()[L " state " ];
49 if (FClickedOnButton)
50 {
51 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " press " :L " hot " ;
52 }
53 else if (Struct.LeftButton)
54 {
55 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " hot " :L " normal " ;
56 }
57 else
58 {
59 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " hot " :L " normal " ;
60 }
61 if (FButton -> GetStrs()[L " state " ] != PreviousState)
62 {
63 FButton -> Update();
64 FCanvas -> Render();
65 }
66 }
67
68 void Form_MouseUp(VL_Base * Sender , VLS_MouseStruct Struct)
69 {
70 FClickedOnButton = false ;
71 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " hot " :L " normal " ;
72 FButton -> Update();
73 FCanvas -> Render();
74 }
75 public :
76 ConfigForm():VL_WinForm( true )
77 {
78 SetBorder(vwfbSingle);
79 SetMinimizeBox( false );
80 SetMaximizeBox( false );
81 SetClientWidth( 800 );
82 SetClientHeight( 600 );
83 SetText(L " Vczh Interaction Renderer Template Test " );
84
85 OnLeftButtonDown.Bind( this , & ConfigForm::Form_MouseDown);
86 OnLeftButtonUp.Bind( this , & ConfigForm::Form_MouseUp);
87 OnMouseMove.Bind( this , & ConfigForm::Form_MouseMove);
88 FClickedOnButton = false ;
89
90 FFactory = CreateInteractionFactory(L " GDI " );
91 FCanvas = FFactory -> CreateCanvas( this );
92 FLoader = new VL_IrConfigLoader(FFactory);
93 FConfig = FLoader -> Load(VFileName(GetApplication() -> GetAppName()).MakeAbsolute(L " ..\\Renderer\\IrConfig_Test.xml " ).GetStrW());
94
95 VL_IrBrushRec WhiteBrushRec;
96 WhiteBrushRec.BrushKind = VL_IrBrushRec::bkSolid;
97 WhiteBrushRec.MainColor = VL_IrColor( 255 , 255 , 255 );
98 IVL_IrBrush::Ptr WhiteBrush = FFactory -> CreateBrush(WhiteBrushRec);
99
100 IVL_IrRectangle::Ptr Root = FFactory -> CreateRectangle();
101 Root -> Properties() -> SetBrush(WhiteBrush);
102 Root -> Update(VL_IrPoint( 0 , 0 ),VL_IrPoint( 800 , 600 ));
103 FCanvas -> SetRootElement(Root);
104
105 FNormalButton = CreateButton(VL_IrPoint( 10 , 10 ),L " normal " ,L " Normal " );
106 FHotButton = CreateButton(VL_IrPoint( 10 , 50 ),L " hot " ,L " Hot " );
107 FPressButton = CreateButton(VL_IrPoint( 10 , 90 ),L " press " ,L " Press " );
108 FButton = CreateButton(VL_IrPoint( 10 , 130 ),L " normal " ,L " Click Me " );
109
110 FCanvas -> Render();
111 }
112 };
2 {
3 protected :
4 IVL_IrFactory::Ptr FFactory;
5 IVL_IrCanvas::Ptr FCanvas;
6 VL_IrConfigLoader::Ptr FLoader;
7 VL_IrConfig::Ptr FConfig;
8 VL_IrTemplateInstance::Ptr FNormalButton;
9 VL_IrTemplateInstance::Ptr FHotButton;
10 VL_IrTemplateInstance::Ptr FPressButton;
11 VL_IrTemplateInstance::Ptr FButton;
12 VBool FClickedOnButton;
13
14 VL_IrTemplateInstance::Ptr CreateButton(VL_IrPoint Position , VUnicodeString State , VUnicodeString Text)
15 {
16 VL_IrTemplateInstance::Ptr Instance = FConfig -> FindTemplate(L " button " ) -> CreateInstance();
17 for (VInt i = 0 ;i < Instance -> GetRootElements().GetCount();i ++ )
18 {
19 FCanvas -> GetRootElement() -> Container() -> AddChild(Instance -> GetRootElements()[i]);
20 }
21
22 Instance -> GetInts()[L " x " ] = Position.X;
23 Instance -> GetInts()[L " y " ] = Position.Y;
24 Instance -> GetInts()[L " w " ] = 100 ;
25 Instance -> GetInts()[L " h " ] = 30 ;
26 Instance -> GetStrs()[L " state " ] = State;
27 Instance -> GetStrs()[L " content " ] = Text;
28 Instance -> Update();
29
30 return Instance;
31 }
32
33 VBool IsOnButton(VLS_MouseStruct Struct)
34 {
35 return FButton -> GetRootElements()[ 0 ] -> Properties() -> ContainedPoint(VL_IrPoint(Struct.X,Struct.Y)) != IVL_IrElement::htrNone;
36 }
37
38 void Form_MouseDown(VL_Base * Sender , VLS_MouseStruct Struct)
39 {
40 FClickedOnButton = IsOnButton(Struct);
41 FButton -> GetStrs()[L " state " ] = FClickedOnButton ? L " press " :L " normal " ;
42 FButton -> Update();
43 FCanvas -> Render();
44 }
45
46 void Form_MouseMove(VL_Base * Sender , VLS_MouseStruct Struct)
47 {
48 VUnicodeString PreviousState = FButton -> GetStrs()[L " state " ];
49 if (FClickedOnButton)
50 {
51 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " press " :L " hot " ;
52 }
53 else if (Struct.LeftButton)
54 {
55 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " hot " :L " normal " ;
56 }
57 else
58 {
59 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " hot " :L " normal " ;
60 }
61 if (FButton -> GetStrs()[L " state " ] != PreviousState)
62 {
63 FButton -> Update();
64 FCanvas -> Render();
65 }
66 }
67
68 void Form_MouseUp(VL_Base * Sender , VLS_MouseStruct Struct)
69 {
70 FClickedOnButton = false ;
71 FButton -> GetStrs()[L " state " ] = IsOnButton(Struct) ? L " hot " :L " normal " ;
72 FButton -> Update();
73 FCanvas -> Render();
74 }
75 public :
76 ConfigForm():VL_WinForm( true )
77 {
78 SetBorder(vwfbSingle);
79 SetMinimizeBox( false );
80 SetMaximizeBox( false );
81 SetClientWidth( 800 );
82 SetClientHeight( 600 );
83 SetText(L " Vczh Interaction Renderer Template Test " );
84
85 OnLeftButtonDown.Bind( this , & ConfigForm::Form_MouseDown);
86 OnLeftButtonUp.Bind( this , & ConfigForm::Form_MouseUp);
87 OnMouseMove.Bind( this , & ConfigForm::Form_MouseMove);
88 FClickedOnButton = false ;
89
90 FFactory = CreateInteractionFactory(L " GDI " );
91 FCanvas = FFactory -> CreateCanvas( this );
92 FLoader = new VL_IrConfigLoader(FFactory);
93 FConfig = FLoader -> Load(VFileName(GetApplication() -> GetAppName()).MakeAbsolute(L " ..\\Renderer\\IrConfig_Test.xml " ).GetStrW());
94
95 VL_IrBrushRec WhiteBrushRec;
96 WhiteBrushRec.BrushKind = VL_IrBrushRec::bkSolid;
97 WhiteBrushRec.MainColor = VL_IrColor( 255 , 255 , 255 );
98 IVL_IrBrush::Ptr WhiteBrush = FFactory -> CreateBrush(WhiteBrushRec);
99
100 IVL_IrRectangle::Ptr Root = FFactory -> CreateRectangle();
101 Root -> Properties() -> SetBrush(WhiteBrush);
102 Root -> Update(VL_IrPoint( 0 , 0 ),VL_IrPoint( 800 , 600 ));
103 FCanvas -> SetRootElement(Root);
104
105 FNormalButton = CreateButton(VL_IrPoint( 10 , 10 ),L " normal " ,L " Normal " );
106 FHotButton = CreateButton(VL_IrPoint( 10 , 50 ),L " hot " ,L " Hot " );
107 FPressButton = CreateButton(VL_IrPoint( 10 , 90 ),L " press " ,L " Press " );
108 FButton = CreateButton(VL_IrPoint( 10 , 130 ),L " normal " ,L " Click Me " );
109
110 FCanvas -> Render();
111 }
112 };
程序创建了一个白色的全屏的长方形当背景,然后把button的四个实例产生的图形都加入长方形中。使用类似的方法就可以将不同的东西堆叠起来,最后组成一个完整的程序界面了。接下来开始设计界面库的架构,做一系列可以自动排版、基于MVC和上面那个模板的组件。