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) 阅读(2468)
评论(1) 编辑 收藏 引用 所属分类:
GacUI