GacUI的所有列表控件都支持虛擬模式。虛擬模式是一種不需要為每一個列表項分配內存的一種顯示方法。在開始的時候,需要高速列表一共有多少個列表項。之后,列表控件在渲染的時候,會跟數據源要求獲取某一個下標所包含的數據,并且在這個數據一直處于屏幕上的時候,只會跟數據源獲取一次。完整的代碼可以在
http://www.gaclib.net/Demos/Controls.ListBox.VirtualMode/Demo.html看到。先上圖:

先看創建界面的代碼。一般來說,所有可以隨著窗口的變化自動排版的控件組織方法,都是使用一個或多個GuiTableComposition來實現的。
class VirtualModeWindow : public GuiWindow
{
private:
GuiVirtualTextList* listBox;
GuiButton* buttonIncrease;
GuiButton* buttonDecrease;
DataSource* dataSource;
void buttonIncrease_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
{
dataSource->SetCount(dataSource->Count()+100000);
}
void buttonDecrease_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
{
dataSource->SetCount(dataSource->Count()-100000);
}
public:
VirtualModeWindow()
:GuiWindow(GetCurrentTheme()->CreateWindowStyle())
{
this->SetText(L"Controls.ListBox.VirtualMode");
GuiTableComposition* table=new GuiTableComposition;
table->SetRowsAndColumns(3, 2);
table->SetCellPadding(3);
table->SetAlignmentToParent(Margin(0, 0, 0, 0));
table->SetRowOption(0, GuiCellOption::MinSizeOption());
table->SetRowOption(1, GuiCellOption::MinSizeOption());
table->SetRowOption(2, GuiCellOption::PercentageOption(1.0));
table->SetColumnOption(0, GuiCellOption::PercentageOption(1.0));
table->SetColumnOption(1, GuiCellOption::MinSizeOption());
this->GetContainerComposition()->AddChild(table);
{
GuiCellComposition* cell=new GuiCellComposition;
table->AddChild(cell);
cell->SetSite(0, 0, 3, 1);
dataSource=new DataSource;
listBox=new GuiVirtualTextList(GetCurrentTheme()->CreateTextListStyle(), GetCurrentTheme()->CreateTextListItemStyle(), dataSource);
listBox->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
listBox->SetHorizontalAlwaysVisible(false);
cell->AddChild(listBox->GetBoundsComposition());
}
{
GuiCellComposition* cell=new GuiCellComposition;
table->AddChild(cell);
cell->SetSite(0, 1, 1, 1);
buttonIncrease=g::NewButton();
buttonIncrease->SetText(L"Increase 100000 Items");
buttonIncrease->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
buttonIncrease->Clicked.AttachMethod(this, &VirtualModeWindow::buttonIncrease_Clicked);
cell->AddChild(buttonIncrease->GetBoundsComposition());
}
{
GuiCellComposition* cell=new GuiCellComposition;
table->AddChild(cell);
cell->SetSite(1, 1, 1, 1);
buttonDecrease=g::NewButton();
buttonDecrease->SetText(L"Decrease 100000 Items");
buttonDecrease->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
buttonDecrease->Clicked.AttachMethod(this, &VirtualModeWindow::buttonDecrease_Clicked);
cell->AddChild(buttonDecrease->GetBoundsComposition());
}
// set the preferred minimum client size
this->GetBoundsComposition()->SetPreferredMinSize(Size(480, 480));
// 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()
this->ForceCalculateSizeImmediately();
// move to the screen center
this->MoveToScreenCenter();
}
};
GuiVirtualTextList就是只有虛擬模式的GuiTextList。事實上GuiVirtualTextList是GuiTextList的基類,而GuiTextList.GetItems()返回的對象也是一個數據源。因此非虛擬模式其實也是通過虛擬模式來實現的。在數據比較少的時候,非虛擬模式操作起來十分的簡單,而在數據比較多的時候,虛擬模式可以帶來很好的性能。上面的代碼創建了一個DataSource類來做數據源,并且有一個SetCount的函數用來更改列表里面的數量的總量,然后每一個列表項的內容都是Item xxx。這是怎么做到的呢?我們來看數據源的代碼:
class DataSource : public list::ItemProviderBase, private list::TextItemStyleProvider::ITextItemView
{
protected:
int count;
public:
DataSource()
:count(100000)
{
}
void SetCount(int newCount)
{
if(0<=newCount)
{
int oldCount=count;
count=newCount;
// this->InvokeOnItemModified(affected-items-start, affected-items-count, new-items-count);
// this function notifies the list control to update it's content and scroll bars
if(oldCount<newCount)
{
// insert
this->InvokeOnItemModified(oldCount, 0, newCount-oldCount);
}
else if(oldCount>newCount)
{
// delete
this->InvokeOnItemModified(newCount, oldCount-newCount, 0);
}
}
}
// GuiListControl::IItemProvider
int Count()
{
return count;
}
IDescriptable* RequestView(const WString& identifier)
{
if(identifier==list::TextItemStyleProvider::ITextItemView::Identifier)
{
return this;
}
else if(identifier==GuiListControl::IItemPrimaryTextView::Identifier)
{
return this;
}
else
{
return 0;
}
}
void ReleaseView(IDescriptable* view)
{
}
// list::TextItemStyleProvider::ITextItemView
WString GetText(int itemIndex)
{
return L"Item "+itow(itemIndex+1);
}
bool GetChecked(int itemIndex)
{
// DataSource don't support check state
return false;
}
void SetCheckedSilently(int itemIndex, bool value)
{
// DataSource don't support check state
}
// GuiListControl::IItemPrimaryTextView
WString GetPrimaryTextViewText(int itemIndex)
{
return GetText(itemIndex+1);
}
bool ContainsPrimaryText(int itemIndex)
{
return true;
}
};
對于GuiVirtualTextList來說,只需要實現vl::presentation::controls::list::TextItemStyleProvider::ITextItemView就可以了。GacUIIncludes.h里面已經有了using namespace vl::presentation::controls,所以在這里只需要從list::開始寫。list::TextItemStyleProvider::ITextItemView還要求實現GuiListControl::IItemPrimaryTextView。在目前的GacUI里面,IItemPrimaryTextView是專門為下拉框準備的。因為下拉框允許接受任何一種列表對象當做下拉內容,所以GacUI的列表數據源默認都要求實現IItemPrimaryTextView。
實現數據源的時候,其實并不要求數據源類繼承自ITextItemView和IItemPrimaryTextView。因為GacUI都是通過RequestView來獲取一個View的接口指針的,代碼如上。實現這兩個View也很簡單,在這里就不贅述了。
GuiTextList就介紹到這里了,接下來的幾個Demo都將是關于ListView的。下一個Demo是ListView山寨Windows 7的資源管理器界面,可以在
http://www.gaclib.net/Demos/Controls.ListView.ViewSwitching/Demo.html看到。具體內容將在下一篇博客中闡述。
posted on 2012-05-30 07:19
陳梓瀚(vczh) 閱讀(2477)
評論(1) 編輯 收藏 引用 所屬分類:
GacUI