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) 閱讀(2022)
評論(2) 編輯 收藏 引用 所屬分類:
GacUI