• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-341  評(píng)論-2670  文章-0  trackbacks-0

                趁此機(jī)會(huì)做個(gè)廣告,http://www.gaclib.net終于上線啦!

                GacUI的列表控件的第二個(gè)Demo是關(guān)于列表項(xiàng)的多選的。跟Windows一樣,我們可以通過鼠標(biāo)和方向鍵,配合CTRL和SHIFT選擇列表的多個(gè)內(nèi)容。因此這次我實(shí)現(xiàn)了一個(gè)簡單的“名字選擇窗口”,就跟QQ邀請(qǐng)好友入群的界面一樣,兩個(gè)列表,兩個(gè)按鈕。先看圖:



                列表內(nèi)容始終是排序的。當(dāng)我們選中一邊的內(nèi)容之后,可以按按鈕把內(nèi)容復(fù)制到另一邊?,F(xiàn)在我們先來看一看創(chuàng)建和排版這些控件的代碼。這里我用了一個(gè)五行三列的表格。左右方列表,中間的第二個(gè)第四行放按鈕,第三行64個(gè)像素高,按鈕32*32,第一行和第五行平均地充滿剩下的空間:

            #include "..\..\Public\Source\GacUIIncludes.h"
            #include 
            <Windows.h>

            // for SortedList, CopyFrom and Select
            using namespace vl::collections;

            int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
            {
                
            return SetupWindowsDirect2DRenderer();
            }

            class NameSelectorWindow : public GuiWindow
            {
            private:
                GuiTextList
            *                    listSource;
                GuiTextList
            *                    listDestination;
                GuiButton
            *                        buttonAdd;
                GuiButton
            *                        buttonRemove;

                (略)
            public:
                NameSelectorWindow()
                    :GuiWindow(GetCurrentTheme()
            ->CreateWindowStyle())
                {
                    
            this->SetText(L"Controls.ListBox.NameSelector");

                    GuiTableComposition
            * table=new GuiTableComposition;
                    table
            ->SetRowsAndColumns(53);
                    table
            ->SetCellPadding(3);
                    table
            ->SetAlignmentToParent(Margin(0000));

                    table
            ->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
                    table
            ->SetRowOption(1, GuiCellOption::MinSizeOption());
                    table
            ->SetRowOption(2, GuiCellOption::AbsoluteOption(64));
                    table
            ->SetRowOption(3, GuiCellOption::MinSizeOption());
                    table
            ->SetRowOption(4, GuiCellOption::PercentageOption(0.5));

                    table
            ->SetColumnOption(0, GuiCellOption::PercentageOption(0.5));
                    table
            ->SetColumnOption(1, GuiCellOption::MinSizeOption());
                    table
            ->SetColumnOption(2, GuiCellOption::PercentageOption(0.5));

                    
            this->GetContainerComposition()->AddChild(table);

                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(0051);

                        listSource
            =g::NewTextList();
                        listSource
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        
            // make listSource's horizontal scroll bar disappeared when it is not needed.
                        listSource->SetHorizontalAlwaysVisible(false);
                        listSource
            ->SetMultiSelect(true);
                        listSource
            ->SelectionChanged.AttachMethod(this&NameSelectorWindow::listSource_SelectionChanged);
                        cell
            ->AddChild(listSource->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(0251);

                        listDestination
            =g::NewTextList();
                        listDestination
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        
            // make listSource's horizontal scroll bar disappeared when it is not needed.
                        listDestination->SetHorizontalAlwaysVisible(false);
                        listDestination
            ->SetMultiSelect(true);
                        listDestination
            ->SelectionChanged.AttachMethod(this&NameSelectorWindow::listDestination_SelectionChanged);
                        cell
            ->AddChild(listDestination->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(1111);

                        buttonAdd
            =g::NewButton();
                        buttonAdd
            ->SetText(L">>");
                        buttonAdd
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        buttonAdd
            ->GetBoundsComposition()->SetPreferredMinSize(Size(3232));
                        buttonAdd
            ->Clicked.AttachMethod(this&NameSelectorWindow::buttonAdd_Clicked);
                        buttonAdd
            ->SetEnabled(false);
                        cell
            ->AddChild(buttonAdd->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(3111);

                        buttonRemove
            =g::NewButton();
                        buttonRemove
            ->SetText(L"<<");
                        buttonRemove
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        buttonRemove
            ->GetBoundsComposition()->SetPreferredMinSize(Size(3232));
                        buttonRemove
            ->Clicked.AttachMethod(this&NameSelectorWindow::buttonRemove_Clicked);
                        buttonRemove
            ->SetEnabled(false);
                        cell
            ->AddChild(buttonRemove->GetBoundsComposition());
                    }

                    
            // Add names into listSource
                    LoadNames(listSource);

                    
            // set the preferred minimum client size
                    this->GetBoundsComposition()->SetPreferredMinSize(Size(640480));
                    
            // 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();
                }
            };

            void GuiMain()
            {
                GuiWindow
            * window=new NameSelectorWindow;
                GetApplication()
            ->Run(window);
                delete window;
            }


                剩下的內(nèi)容分為三部分。首先是如何在列表沒有選中內(nèi)容的時(shí)候把按鈕變灰。在上面的代碼中我們知道listSource和listDestination都監(jiān)聽了SelectionChanged事件。事件處理函數(shù)的內(nèi)容如下:

                void listSource_SelectionChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    buttonAdd
            ->SetEnabled(listSource->GetSelectedItems().Count()>0);
                }

                
            void listDestination_SelectionChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    buttonRemove
            ->SetEnabled(listDestination->GetSelectedItems().Count()>0);
                }


                代碼內(nèi)容十分簡潔明了。第二部分是NameSelectorWindow構(gòu)造函數(shù)中調(diào)用的LoadNames函數(shù)。我們首先把所有的名字都放在一個(gè)const wchar_t* DataSource[]數(shù)組里面,內(nèi)容是沒有排過序的:

            const wchar_t* DataSource[]=
            {
                L
            "Weierstrass",
                L
            "Cantor",
                L
            "Bernoulli",
                L
            "Fatou",
                L
            "Green",
                L
            "S.Lie",
                L
            "Euler",
                L
            "Gauss",
                L
            "Sturm",
                L
            "Riemann",
                L
            "Neumann",
                L
            "Caratheodory",
                L
            "Newton",
                L
            "Jordan",
                L
            "Laplace",
                L
            "Wiener",
                L
            "Thales",
                L
            "Maxwell",
                L
            "Riesz",
                L
            "Fourier",
                L
            "Noether",
                L
            "Kepler",
                L
            "Kolmogorov",
                L
            "Borel",
                L
            "Sobolev",
                L
            "Dirchlet",
                L
            "Lebesgue",
                L
            "Leibniz",
                L
            "Abel",
                L
            "Lagrange",
                L
            "Ramanujan",
                L
            "Ljapunov",
                L
            "Holder",
                L
            "Poisson",
                L
            "Nikodym",
                L
            "H.Hopf",
                L
            "Pythagoras",
                L
            "Baire",
                L
            "Haar",
                L
            "Fermat",
                L
            "Kronecker",
                L
            "E.Laudau",
                L
            "Markov",
                L
            "Wronski",
                L
            "Zermelo",
                L
            "Rouche",
                L
            "Taylor",
                L
            "Urysohn",
                L
            "Frechet",
                L
            "Picard",
                L
            "Schauder",
                L
            "Lipschiz",
                L
            "Liouville",
                L
            "Lindelof",
                L
            "de Moivre",
                L
            "Klein",
                L
            "Bessel",
                L
            "Euclid",
                L
            "Kummer",
                L
            "Ascoli",
                L
            "Chebyschev",
                L
            "Banach",
                L
            "Hilbert",
                L
            "Minkowski",
                L
            "Hamilton",
                L
            "Poincare",
                L
            "Peano",
                L
            "Zorn",
            };


                然后LoadNames函數(shù)如下所示:

                void LoadNames(GuiTextList* list)
                {
                    
            // Use linq for C++ to create sorted TextItem(s) from DataSource
                    CopyFrom(
                        list
            ->GetItems(),
                        FromArray(DataSource)
                            
            >>OrderBy(_wcsicmp)
                            
            >>Select<const wchar_t*, list::TextItem>(
                                [](
            const wchar_t* name){return list::TextItem(name);}
                            )
                        );
                }


                首先我們用FromArray函數(shù)從const wchar_t* DataSource[]數(shù)組創(chuàng)建出一個(gè)IEnumerable<const wchar_t*>,然后用_wcsicmp進(jìn)行排序,最后把每一個(gè)const wchar_t* name都用list::TextItem(name)轉(zhuǎn)變成一個(gè)列表項(xiàng)。

                最后一步比較復(fù)雜,就是如何在移動(dòng)列表的內(nèi)容的時(shí)候還保持兩個(gè)列表的內(nèi)容是排序的。首先,從一個(gè)排序列表中刪除東西,結(jié)果肯定是排序的。其次,把一堆新的名字插入一個(gè)列表,最簡單的方法就是把所有的東西連起來重新排序一遍,然后放回去:

                static list::TextItem GetTextItem(GuiTextList* list, int index)
                {
                    
            return list->GetItems()[index];
                }

                
            static int CompareTextItem(list::TextItem a, list::TextItem b)
                {
                    
            return _wcsicmp(a.GetText().Buffer(), b.GetText().Buffer());
                }

                
            static int ReverseCompareInt(int a, int b)
                {
                    
            return b-a;
                }

                
            void MoveNames(GuiTextList* from, GuiTextList* to)
                {
                    CopyFrom(
                        to
            ->GetItems(),
                        to
            ->GetItems()
                            
            >>Concat(
                                from
            ->GetSelectedItems()>>Select(Curry(GetTextItem)(from))
                                )
                            
            >>OrderBy(CompareTextItem)
                        );

                    List
            <int> selectedItems;
                    CopyFrom(
                        selectedItems.Wrap(),
                        from
            ->GetSelectedItems()
                            
            >>OrderBy(ReverseCompareInt)
                        );
                    FOREACH(
            int, index, selectedItems.Wrap())
                    {
                        from
            ->GetItems().RemoveAt(index);
                    }
                }

                
            void buttonAdd_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    MoveNames(listSource, listDestination);
                }

                
            void buttonRemove_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    MoveNames(listDestination, listSource);
                }


                我們可以看到MoveNames函數(shù)里面做了三件事情。

                第一件事情就是把to列表中的內(nèi)容,和from列表中選中的內(nèi)容Concat起來,也就是一個(gè)連著一個(gè)組成一個(gè)沒有排序過的IEnumerable<list::TextItem>,然后用CompareTextItem進(jìn)行排序。其中Curry(GetTextItem)(item)的意思是,將item作為GetTextItem的第一個(gè)參數(shù),把“填補(bǔ)剩下的參數(shù)”的這個(gè)過程產(chǎn)生一個(gè)新的函數(shù),就跟bind1st函數(shù)的意思是一樣的。所以經(jīng)過這個(gè)Select,就可以吧GetSelectedItems()返回的所有選中的item的下標(biāo),給轉(zhuǎn)換成原原本本的列表項(xiàng)。這樣將to里面的列表項(xiàng)和from里面選中的列表項(xiàng)所有的內(nèi)容合起來排序,最后放回to列表里面,這樣?xùn)|西就挪過去了。

                第二件事情就是要把from->GetSelectedItems()的內(nèi)容都復(fù)制下來,然后逆序。

                第三件事情,就是遍歷逆序后的GetSelectedItems的結(jié)果,一個(gè)一個(gè)刪除掉選中的項(xiàng)目了。列表控件只要內(nèi)容一變化,選中就會(huì)全部清空,因此如果不先保留GetSelectedItems的結(jié)果的話,刪除了一個(gè)列表項(xiàng)之后,GetSelectedItems就會(huì)變空,這樣就會(huì)出bug。

                這個(gè)Demo就介紹到這里了。GacUI下一個(gè)列表控件的Demo將是關(guān)于虛擬模式的。也就是說,這次我們不一個(gè)一個(gè)Add進(jìn)去了,而是直接告訴列表控件一共有多少個(gè)項(xiàng)目,然后列表要顯示的時(shí)候回調(diào)一下獲得真正的內(nèi)容。這個(gè)功能是很有用的,特別是當(dāng)內(nèi)容特別多,我們沒辦法一下子準(zhǔn)備好的時(shí)候,可以讓界面很快的出來,讓用戶感覺起來,程序運(yùn)行的很流暢。

            posted on 2012-05-25 21:54 陳梓瀚(vczh) 閱讀(3642) 評(píng)論(12)  編輯 收藏 引用 所屬分類: GacUI

            評(píng)論:
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-26 01:42 | phoenixbing
            我是來支持老大的  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-26 06:35 | 溪流
            linq 能合起來寫不?哈~  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-26 07:29 | 朱峰e(cuò)verettjf
            學(xué)習(xí)。
            請(qǐng)問,能否說,gaclib是一個(gè).NET WinForm風(fēng)格的c++界面庫?
            GPU accelerated 是針對(duì)顯示做了優(yōu)化(相對(duì)于使用sdk或mfc、wtl)?  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-26 09:19 | 陳梓瀚(vczh)
            @朱峰e(cuò)verettjf
            我覺得,應(yīng)該是WPF風(fēng)格的吧。GPU是針對(duì)WinForm、MFC、WTL這種傳統(tǒng)的界面而言的。  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-26 09:20 | 陳梓瀚(vczh)
            @溪流
            能啊,里面不是合了嗎,還嵌套了  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-26 18:23 | 朱峰e(cuò)verettjf
            @陳梓瀚(vczh)
            嗯。向博主學(xué)習(xí)。  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-27 16:42 | tb
            向博主學(xué)習(xí)  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-27 20:49 | 溪流
            @陳梓瀚(vczh)
            我是說類sql的寫法:)  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-27 23:09 | TianJun
            單擊列表控件里面的名字有時(shí)候會(huì)選擇到其它名字, 不是我單擊的名字。  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-28 01:23 | 陳梓瀚(vczh)
            @TianJun
            有沒有重現(xiàn)方法?然后我去查一查  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-28 01:23 | 陳梓瀚(vczh)
            @溪流
            沒有那種寫法,C++搞不定這種……  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-28 03:44 | Scan
            在C++中倒是可以弄出a.OrderBy().Select([](){}).ToList()這種語法的linq,借助一個(gè)代理類,用.來連接操作,至少在代碼補(bǔ)全方面更好用。
            我以前倒是也試過在C++11中借助閉包實(shí)現(xiàn)linq to object,閉包用于延遲迭代。  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++ 2012-05-29 19:13 | TianJun
            @陳梓瀚(vczh)
            剛打開程序時(shí)不會(huì), 把一些名字移動(dòng)到右邊后, 就會(huì)出現(xiàn)單擊左邊列表控件會(huì)選擇不對(duì)的名字。  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++[未登錄] 2012-05-29 19:35 | 陳梓瀚(vczh)
            @TianJun
            我去看一看  回復(fù)  更多評(píng)論
              
            # re: GacUI Demo:列表控件內(nèi)容的排序和移動(dòng),以及Linq for C++[未登錄] 2012-05-29 20:13 | 陳梓瀚(vczh)
            @TianJun
            refactor的時(shí)候犯了點(diǎn)小錯(cuò)誤,這個(gè)問題已經(jīng)解決了。感謝提供信息。  回復(fù)  更多評(píng)論
              
            日本一区精品久久久久影院| 97久久国产露脸精品国产| 久久综合给合久久狠狠狠97色 | 国产国产成人精品久久| 丰满少妇高潮惨叫久久久| 99久久精品免费看国产| 思思久久99热免费精品6| 久久夜色精品国产噜噜麻豆| 97久久香蕉国产线看观看| 久久久久99精品成人片| 色欲久久久天天天综合网| 婷婷综合久久中文字幕| 久久精品国产久精国产果冻传媒 | 久久精品桃花综合| 久久精品无码一区二区无码| 精品久久久久久无码中文野结衣| 久久久亚洲裙底偷窥综合| 久久精品国产91久久综合麻豆自制 | 久久综合五月丁香久久激情| 97精品国产97久久久久久免费| 日本三级久久网| 97久久久精品综合88久久| 性做久久久久久久久浪潮| 久久精品国产亚洲麻豆| 日韩人妻无码精品久久久不卡 | 久久综合中文字幕| 久久久久亚洲av无码专区导航 | 99久久精品毛片免费播放| 久久久久久精品成人免费图片| 办公室久久精品| 久久最近最新中文字幕大全| 少妇久久久久久被弄高潮| 久久精品成人欧美大片| 一极黄色视频久久网站| 国产精品免费久久| 国产精品无码久久综合网| 99久久国产综合精品网成人影院| 精品久久香蕉国产线看观看亚洲| 亚洲国产另类久久久精品黑人| 精品多毛少妇人妻AV免费久久| 久久精品国产亚洲av麻豆图片 |