随笔-341  评论-2670  文章-0  trackbacks-0
    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(32);
        table
->SetCellPadding(3);
        table
->SetAlignmentToParent(Margin(0000));

        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(0031);

            dataSource
=new DataSource;
            listBox
=new GuiVirtualTextList(GetCurrentTheme()->CreateTextListStyle(), GetCurrentTheme()->CreateTextListItemStyle(), dataSource);
            listBox
->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
            listBox
->SetHorizontalAlwaysVisible(false);
            cell
->AddChild(listBox->GetBoundsComposition());
        }
        {
            GuiCellComposition
* cell=new GuiCellComposition;
            table
->AddChild(cell);
            cell
->SetSite(0111);

            buttonIncrease
=g::NewButton();
            buttonIncrease
->SetText(L"Increase 100000 Items");
            buttonIncrease
->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
            buttonIncrease
->Clicked.AttachMethod(this&VirtualModeWindow::buttonIncrease_Clicked);
            cell
->AddChild(buttonIncrease->GetBoundsComposition());
        }
        {
            GuiCellComposition
* cell=new GuiCellComposition;
            table
->AddChild(cell);
            cell
->SetSite(1111);

            buttonDecrease
=g::NewButton();
            buttonDecrease
->SetText(L"Decrease 100000 Items");
            buttonDecrease
->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
            buttonDecrease
->Clicked.AttachMethod(this&VirtualModeWindow::buttonDecrease_Clicked);
            cell
->AddChild(buttonDecrease->GetBoundsComposition());
        }

        
// set the preferred minimum client size
        this->GetBoundsComposition()->SetPreferredMinSize(Size(480480));
        
// 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) 阅读(2323) 评论(1)  编辑 收藏 引用 所属分类: GacUI

评论:
# re: GacUI Demo:列表的虚拟模式,不需要为每一个列表项分配内存的一种显示方法 2012-05-31 04:37 | 空明流转
师祖威武!帅不忍睹!  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理