GacUI新增了一个Demo。这里模拟了一个简单到过头了的编辑程序。界面是一个标签页,第一页里面只有一个按钮:Add Page。点中了他之后,其它页包含一个用来关掉自己的按钮,和一个多行的文本框。
这个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;
}
那一大段的注释,就是在讲延迟执行的事情。看过C++11的人都知道,lambda expression实际上就是一个functor。在旧C++里面,调用InvokeInMainThread的时候,要么可以传一个void(*)(void*)和void*,要么可以传一个带operator()()的struct。在新C++里面,直接把lambda expression写在里面就好了。
如果不使用延迟执行,在事件发生的时候把自己删掉,会导致Access Violation的发生,因为接下来要访问的对象被你删掉了。如果使用延迟执行,就可以在input message处理完之后,执行删除的代码。这样一切都是好的。
下一个Demo就是关于文本框的操作,再下一个Demo是关于如何做用来显示代码的高亮文本框的事情。敬请期待,啊哈哈哈。
posted on 2012-04-30 23:28
陈梓瀚(vczh) 阅读(2015)
评论(2) 编辑 收藏 引用 所属分类:
GacUI