GacUI新Demo:按钮和排版
今天为 GacUI写了一个新的Demo,展示了一些可以自动排版的按钮。主要的设想就是在窗口上放一个表格,分成两行两列。上面的按钮占满一整行,下面两个单元格放两个按钮。然后就可以设置每个行和列占整个表格的比例,在这个Demo里面都设置成50%。这样每当窗口缩放的时候,按钮的位置也会随之重新排版。然后设置表格充满整个窗口,这样窗口的最小值就会被表格的内容所限定,这样试图把窗口缩小的时候,就会有一个最小的尺寸限制着,至始至终保证所有的东西都可以显示出来,不会因为窗口太小而只显示一半。按钮也是同样,可以设置它必须显示所有的文字。所有的过程一旦配置好之后,计算尺寸的时候所有的操作都会自动做,程序员不需要为窗口的Resize事件写任何代码。
下面先放图。
第一个图是窗口刚刚打开的时候的样子。因为Demo里面没有设置窗口的尺寸,所以一上来就自动变成了最小的尺寸——并且刚好可以显示所有的内容。
第二个图是窗口放大之后的样子。Disable按钮被按下了,所以上面的按钮就变灰。
这个Demo使用了Direct2D渲染器,所有的绘制过程都十分高速。而且表格的尺寸计算也是经过优化的,在拖放窗口的时候十分流畅。事实上按钮的渐变啊、边框啊、文字等等也是借助表格排版的。由于尺寸计算过于复杂,除了表格之外整个框架都不保存控件的尺寸,所有的东西都在需要的时候——譬如说渲染的时候,譬如说计算鼠标点中的位置——的那一刻才开始算。因此无论是鼠标滑过,或者是窗口拖放,都拼命地执行很多虚函数。可见C++的虚函数的性能之高,几乎永远都不会成为程序的瓶颈。下面来看代码:
#include
"
..\..\Public\Source\GacUIIncludes.h
"
#include < Windows.h >
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
{
return SetupWindowsDirect2DRenderer();
}
class EnableDisableWindow : public GuiWindow
{
private :
GuiButton * buttonTarget;
GuiButton * buttonEnable;
GuiButton * buttonDisable;
void buttonEnable_OnClick(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
buttonTarget -> SetEnabled( true );
}
void buttonDisable_OnClick(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
buttonTarget -> SetEnabled( false );
}
public :
EnableDisableWindow()
:GuiWindow(GetCurrentTheme() -> CreateWindowStyle())
{
this -> SetText(L " Controls.Button.EnableDisable " );
// limit the size that the window should always show the whole content without cliping it
this -> GetContainerComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
// create a table to layout the 3 buttons
GuiTableComposition * table = new GuiTableComposition;
// make the table to have 2 rows
table -> SetRowsAndColumns( 2 , 2 );
table -> SetRowOption( 0 , GuiCellOption::PercentageOption( 0.5 ));
table -> SetRowOption( 1 , GuiCellOption::PercentageOption( 0.5 ));
table -> SetColumnOption( 0 , GuiCellOption::PercentageOption( 0.5 ));
table -> SetColumnOption( 1 , GuiCellOption::PercentageOption( 0.5 ));
// dock the table to fill the window
table -> SetAlignmentToParent(Margin( 10 , 10 , 10 , 10 ));
// add the table to the window;
this -> GetContainerComposition() -> AddChild(table);
// add the target button
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
// this cell is the top cell
cell -> SetSite( 0 , 0 , 1 , 2 );
buttonTarget = g::NewButton();
buttonTarget -> SetText(L " Enable or disable me using the buttons below! " );
// ensure that the buttonTarget display the whole text
buttonTarget -> GetBoundsComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
// dock the button to fill the cell
buttonTarget -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 , 0 , 0 , 3 ));
// add the button to the cell
cell -> AddChild(buttonTarget -> GetBoundsComposition());
}
// add the enable button
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
// this cell is the bottom left cell
cell -> SetSite( 1 , 0 , 1 , 1 );
buttonEnable = g::NewButton();
buttonEnable -> SetText(L " Enable " );
buttonEnable -> GetBoundsComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
buttonEnable -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 , 3 , 3 , 0 ));
buttonEnable -> Clicked.AttachMethod( this , & EnableDisableWindow::buttonEnable_OnClick);
cell -> AddChild(buttonEnable -> GetBoundsComposition());
}
// add the disable button
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
// this cell is the bottom right cell
cell -> SetSite( 1 , 1 , 1 , 1 );
buttonDisable = g::NewButton();
buttonDisable -> SetText(L " Disable " );
buttonDisable -> GetBoundsComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
buttonDisable -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 3 , 3 , 0 , 0 ));
buttonDisable -> Clicked.AttachMethod( this , & EnableDisableWindow::buttonDisable_OnClick);
cell -> AddChild(buttonDisable -> GetBoundsComposition());
}
// change the button font
{
FontProperties font;
font = buttonTarget -> GetFont();
font.size = 20 ;
buttonTarget -> SetFont(font);
buttonEnable -> SetFont(font);
buttonDisable -> SetFont(font);
}
// call this to calculate the size immediately if any indirect content in the table changes
// so that the window can calcaulte its correct size before calling the MoveToScreenCenter()
table -> UpdateCellBounds();
// update the size
this -> SetBounds(Rect());
// move to the screen center
this -> MoveToScreenCenter();
}
~ EnableDisableWindow()
{
}
};
void GuiMain()
{
GuiWindow * window = new EnableDisableWindow();
GetApplication() -> Run(window);
delete window;
}
#include < Windows.h >
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
{
return SetupWindowsDirect2DRenderer();
}
class EnableDisableWindow : public GuiWindow
{
private :
GuiButton * buttonTarget;
GuiButton * buttonEnable;
GuiButton * buttonDisable;
void buttonEnable_OnClick(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
buttonTarget -> SetEnabled( true );
}
void buttonDisable_OnClick(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
buttonTarget -> SetEnabled( false );
}
public :
EnableDisableWindow()
:GuiWindow(GetCurrentTheme() -> CreateWindowStyle())
{
this -> SetText(L " Controls.Button.EnableDisable " );
// limit the size that the window should always show the whole content without cliping it
this -> GetContainerComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
// create a table to layout the 3 buttons
GuiTableComposition * table = new GuiTableComposition;
// make the table to have 2 rows
table -> SetRowsAndColumns( 2 , 2 );
table -> SetRowOption( 0 , GuiCellOption::PercentageOption( 0.5 ));
table -> SetRowOption( 1 , GuiCellOption::PercentageOption( 0.5 ));
table -> SetColumnOption( 0 , GuiCellOption::PercentageOption( 0.5 ));
table -> SetColumnOption( 1 , GuiCellOption::PercentageOption( 0.5 ));
// dock the table to fill the window
table -> SetAlignmentToParent(Margin( 10 , 10 , 10 , 10 ));
// add the table to the window;
this -> GetContainerComposition() -> AddChild(table);
// add the target button
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
// this cell is the top cell
cell -> SetSite( 0 , 0 , 1 , 2 );
buttonTarget = g::NewButton();
buttonTarget -> SetText(L " Enable or disable me using the buttons below! " );
// ensure that the buttonTarget display the whole text
buttonTarget -> GetBoundsComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
// dock the button to fill the cell
buttonTarget -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 , 0 , 0 , 3 ));
// add the button to the cell
cell -> AddChild(buttonTarget -> GetBoundsComposition());
}
// add the enable button
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
// this cell is the bottom left cell
cell -> SetSite( 1 , 0 , 1 , 1 );
buttonEnable = g::NewButton();
buttonEnable -> SetText(L " Enable " );
buttonEnable -> GetBoundsComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
buttonEnable -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 , 3 , 3 , 0 ));
buttonEnable -> Clicked.AttachMethod( this , & EnableDisableWindow::buttonEnable_OnClick);
cell -> AddChild(buttonEnable -> GetBoundsComposition());
}
// add the disable button
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
// this cell is the bottom right cell
cell -> SetSite( 1 , 1 , 1 , 1 );
buttonDisable = g::NewButton();
buttonDisable -> SetText(L " Disable " );
buttonDisable -> GetBoundsComposition() -> SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
buttonDisable -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 3 , 3 , 0 , 0 ));
buttonDisable -> Clicked.AttachMethod( this , & EnableDisableWindow::buttonDisable_OnClick);
cell -> AddChild(buttonDisable -> GetBoundsComposition());
}
// change the button font
{
FontProperties font;
font = buttonTarget -> GetFont();
font.size = 20 ;
buttonTarget -> SetFont(font);
buttonEnable -> SetFont(font);
buttonDisable -> SetFont(font);
}
// call this to calculate the size immediately if any indirect content in the table changes
// so that the window can calcaulte its correct size before calling the MoveToScreenCenter()
table -> UpdateCellBounds();
// update the size
this -> SetBounds(Rect());
// move to the screen center
this -> MoveToScreenCenter();
}
~ EnableDisableWindow()
{
}
};
void GuiMain()
{
GuiWindow * window = new EnableDisableWindow();
GetApplication() -> Run(window);
delete window;
}
代码里面充满了注释,而且主要的内容也在上面介绍了,在这里我就不罗嗦了。所有的代码都可以在 http://gac.codeplex.com中,下载最新的代码,然后在Libraries\GacUI\GacUIDemo\GacUIDemo.sln下面找到。