GacUI Demo:标签页
GacUI新增了一个Demo。这里模拟了一个简单到过头了的编辑程序。界面是一个标签页,第一页里面只有一个按钮:Add Page。点中了他之后,其它页包含一个用来关掉自己的按钮,和一个多行的文本框。
这个Demo要展示的其中一个问题是,在按下关闭按钮的时候,由于那个Page会被移除并删除,会导致按钮自己也被删除。但是事件发生过后,实际上还有很多事情要做的。所以这里展示了如何使用GacUI进行“延迟执行”,在事件结束之后再删除自己。为了方便,这个Demo使用了C++11(但是库的实现并不依赖与C++11)。先上图:
然后我们来看代码:
那一大段的注释,就是在讲延迟执行的事情。看过C++11的人都知道,lambda expression实际上就是一个functor。在旧C++里面,调用InvokeInMainThread的时候,要么可以传一个void(*)(void*)和void*,要么可以传一个带operator()()的struct。在新C++里面,直接把lambda expression写在里面就好了。
如果不使用延迟执行,在事件发生的时候把自己删掉,会导致Access Violation的发生,因为接下来要访问的对象被你删掉了。如果使用延迟执行,就可以在input message处理完之后,执行删除的代码。这样一切都是好的。
下一个Demo就是关于文本框的操作,再下一个Demo是关于如何做用来显示代码的高亮文本框的事情。敬请期待,啊哈哈哈。
这个Demo要展示的其中一个问题是,在按下关闭按钮的时候,由于那个Page会被移除并删除,会导致按钮自己也被删除。但是事件发生过后,实际上还有很多事情要做的。所以这里展示了如何使用GacUI进行“延迟执行”,在事件结束之后再删除自己。为了方便,这个Demo使用了C++11(但是库的实现并不依赖与C++11)。先上图:
然后我们来看代码:
#include
"
..\..\Public\Source\GacUIIncludes.h
"
#include < Windows.h >
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
{
return SetupWindowsDirect2DRenderer();
}
class TextBoxPage : public GuiTabPage
{
private :
static int pageCounter;
GuiButton * closeButton;
GuiMultilineTextBox * textBox;
void closeButton_Clicked(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
// deleteing the tab page will also delete the button, because the button is in the page
// when an event is processing, the button is not going to be deleted
// because there are many works to do after this event
// and maybe someone has already added another event handler to this button
// so it use GetApplication()->InvokeInMainThread to send a function to the queue
// so that this function will be executed after this input message (an input message raises multiple events)
// to the user, this page is closed after cliking this button
GetApplication() -> InvokeInMainThread([ this ]()
{
// remove the page and delete it
this -> GetOwnerTab() -> RemovePage( this );
delete this ;
});
}
void OnPageContainerReady(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
// create a table to place a button and a text box
GuiTableComposition * table = new GuiTableComposition;
table -> SetRowsAndColumns( 2 , 1 );
table -> SetRowOption( 0 , GuiCellOption::MinSizeOption());
table -> SetRowOption( 1 , GuiCellOption::PercentageOption( 1.0 ));
table -> SetColumnOption( 0 , GuiCellOption::PercentageOption( 1.0 ));
table -> SetAlignmentToParent(Margin( 0 , 0 , 0 , 0 ));
table -> SetCellPadding( 2 );
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
cell -> SetSite( 0 , 0 , 1 , 1 );
closeButton = g::NewButton();
closeButton -> SetText(L " Close Me! " );
closeButton -> Clicked.AttachMethod( this , & TextBoxPage::closeButton_Clicked);
cell -> AddChild(closeButton -> GetBoundsComposition());
}
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
cell -> SetSite( 1 , 0 , 1 , 1 );
textBox = g::NewMultilineTextBox();
textBox -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 , 0 , 0 , 0 ));
textBox -> SetText(L " You can input several lines of text here.\r\nThis is a multiple line text box. " );
cell -> AddChild(textBox -> GetBoundsComposition());
}
this -> GetContainer() -> GetContainerComposition() -> AddChild(table);
}
public :
TextBoxPage()
:closeButton( 0 )
,textBox( 0 )
{
PageContainerReady.AttachMethod( this , & TextBoxPage::OnPageContainerReady);
this -> SetText(L " Page " + itow( ++ pageCounter));
}
~ TextBoxPage()
{
}
};
int TextBoxPage::pageCounter = 0 ;
class TextBoxPageWindow : public GuiWindow
{
private :
GuiTab * tabControl;
GuiTabPage * controlPanelPage;
GuiButton * buttonAddPage;
void buttonAddPage_Clicked(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
// when the button is clicked, it creates a new TextBoxPage and adds it to the tab control
TextBoxPage * page = new TextBoxPage;
tabControl -> CreatePage(page);
tabControl -> SetSelectedPage(page);
}
public :
TextBoxPageWindow()
:GuiWindow(GetCurrentTheme() -> CreateWindowStyle())
{
this -> SetText(L " Controls.Tab.TextBoxPage " );
this -> GetBoundsComposition() -> SetPreferredMinSize(Size( 640 , 480 ));
// create a tab control
tabControl = g::NewTab();
tabControl -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 2 , 2 , 2 , 2 ));
this -> AddChild(tabControl);
// the first page is a control panel
controlPanelPage = tabControl -> CreatePage();
controlPanelPage -> SetText(L " Control Panel " );
// add a button to the control panel
buttonAddPage = g::NewButton();
buttonAddPage -> SetText(L " Add a tab page " );
buttonAddPage -> Clicked.AttachMethod( this , & TextBoxPageWindow::buttonAddPage_Clicked);
controlPanelPage -> GetContainer() -> GetContainerComposition() -> SetInternalMargin(Margin( 2 , 2 , 2 , 2 ));
controlPanelPage -> GetContainer() -> AddChild(buttonAddPage);
this -> ForceCalculateSizeImmediately();
this -> MoveToScreenCenter();
}
~ TextBoxPageWindow()
{
}
};
void GuiMain()
{
GuiWindow * window = new TextBoxPageWindow();
GetApplication() -> Run(window);
delete window;
}
#include < Windows.h >
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
{
return SetupWindowsDirect2DRenderer();
}
class TextBoxPage : public GuiTabPage
{
private :
static int pageCounter;
GuiButton * closeButton;
GuiMultilineTextBox * textBox;
void closeButton_Clicked(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
// deleteing the tab page will also delete the button, because the button is in the page
// when an event is processing, the button is not going to be deleted
// because there are many works to do after this event
// and maybe someone has already added another event handler to this button
// so it use GetApplication()->InvokeInMainThread to send a function to the queue
// so that this function will be executed after this input message (an input message raises multiple events)
// to the user, this page is closed after cliking this button
GetApplication() -> InvokeInMainThread([ this ]()
{
// remove the page and delete it
this -> GetOwnerTab() -> RemovePage( this );
delete this ;
});
}
void OnPageContainerReady(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
// create a table to place a button and a text box
GuiTableComposition * table = new GuiTableComposition;
table -> SetRowsAndColumns( 2 , 1 );
table -> SetRowOption( 0 , GuiCellOption::MinSizeOption());
table -> SetRowOption( 1 , GuiCellOption::PercentageOption( 1.0 ));
table -> SetColumnOption( 0 , GuiCellOption::PercentageOption( 1.0 ));
table -> SetAlignmentToParent(Margin( 0 , 0 , 0 , 0 ));
table -> SetCellPadding( 2 );
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
cell -> SetSite( 0 , 0 , 1 , 1 );
closeButton = g::NewButton();
closeButton -> SetText(L " Close Me! " );
closeButton -> Clicked.AttachMethod( this , & TextBoxPage::closeButton_Clicked);
cell -> AddChild(closeButton -> GetBoundsComposition());
}
{
GuiCellComposition * cell = new GuiCellComposition;
table -> AddChild(cell);
cell -> SetSite( 1 , 0 , 1 , 1 );
textBox = g::NewMultilineTextBox();
textBox -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 , 0 , 0 , 0 ));
textBox -> SetText(L " You can input several lines of text here.\r\nThis is a multiple line text box. " );
cell -> AddChild(textBox -> GetBoundsComposition());
}
this -> GetContainer() -> GetContainerComposition() -> AddChild(table);
}
public :
TextBoxPage()
:closeButton( 0 )
,textBox( 0 )
{
PageContainerReady.AttachMethod( this , & TextBoxPage::OnPageContainerReady);
this -> SetText(L " Page " + itow( ++ pageCounter));
}
~ TextBoxPage()
{
}
};
int TextBoxPage::pageCounter = 0 ;
class TextBoxPageWindow : public GuiWindow
{
private :
GuiTab * tabControl;
GuiTabPage * controlPanelPage;
GuiButton * buttonAddPage;
void buttonAddPage_Clicked(GuiGraphicsComposition * sender, GuiEventArgs & arguments)
{
// when the button is clicked, it creates a new TextBoxPage and adds it to the tab control
TextBoxPage * page = new TextBoxPage;
tabControl -> CreatePage(page);
tabControl -> SetSelectedPage(page);
}
public :
TextBoxPageWindow()
:GuiWindow(GetCurrentTheme() -> CreateWindowStyle())
{
this -> SetText(L " Controls.Tab.TextBoxPage " );
this -> GetBoundsComposition() -> SetPreferredMinSize(Size( 640 , 480 ));
// create a tab control
tabControl = g::NewTab();
tabControl -> GetBoundsComposition() -> SetAlignmentToParent(Margin( 2 , 2 , 2 , 2 ));
this -> AddChild(tabControl);
// the first page is a control panel
controlPanelPage = tabControl -> CreatePage();
controlPanelPage -> SetText(L " Control Panel " );
// add a button to the control panel
buttonAddPage = g::NewButton();
buttonAddPage -> SetText(L " Add a tab page " );
buttonAddPage -> Clicked.AttachMethod( this , & TextBoxPageWindow::buttonAddPage_Clicked);
controlPanelPage -> GetContainer() -> GetContainerComposition() -> SetInternalMargin(Margin( 2 , 2 , 2 , 2 ));
controlPanelPage -> GetContainer() -> AddChild(buttonAddPage);
this -> ForceCalculateSizeImmediately();
this -> MoveToScreenCenter();
}
~ TextBoxPageWindow()
{
}
};
void GuiMain()
{
GuiWindow * window = new TextBoxPageWindow();
GetApplication() -> Run(window);
delete window;
}
那一大段的注释,就是在讲延迟执行的事情。看过C++11的人都知道,lambda expression实际上就是一个functor。在旧C++里面,调用InvokeInMainThread的时候,要么可以传一个void(*)(void*)和void*,要么可以传一个带operator()()的struct。在新C++里面,直接把lambda expression写在里面就好了。
如果不使用延迟执行,在事件发生的时候把自己删掉,会导致Access Violation的发生,因为接下来要访问的对象被你删掉了。如果使用延迟执行,就可以在input message处理完之后,执行删除的代码。这样一切都是好的。
下一个Demo就是关于文本框的操作,再下一个Demo是关于如何做用来显示代码的高亮文本框的事情。敬请期待,啊哈哈哈。