1. 程式人生 > >GacUI Demo:列表的虛擬模式,不需要為每一個列表項分配記憶體的一種顯示方法

GacUI Demo:列表的虛擬模式,不需要為每一個列表項分配記憶體的一種顯示方法

    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 sizethis->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 centerthis->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 barsif(oldCount<newCount)
            {
                
// insertthis->InvokeOnItemModified(oldCount, 0, newCount-oldCount);
            }
            
elseif(oldCount>newCount)
            {
                
// deletethis->InvokeOnItemModified(newCount, oldCount-newCount, 0);
            }
        }
    }

    
// GuiListControl::IItemProviderint Count()
    {
        
return count;
    }

    IDescriptable
* RequestView(const WString& identifier)
    {
        
if(identifier==list::TextItemStyleProvider::ITextItemView::Identifier)
        {
            
returnthis;
        }
        
elseif(identifier==GuiListControl::IItemPrimaryTextView::Identifier)
        {
            
returnthis;
        }
        
else
        {
            
return0;
        }
    }

    
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 statereturnfalse;
    }

    
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)
    {
        
returntrue;
    }
};

    對於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看到。具體內容將在下一篇部落格中闡述。