• <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  評論-2670  文章-0  trackbacks-0
             
                GacUI在結(jié)束了文本框的介紹之后,開始進入列表的介紹。列表內(nèi)容豐富,包含各種預定義的列表控件、用來顯示和操作大量對象的虛擬模式、MVC分離、修改列表樣式等內(nèi)容。今天先從文本列表的簡單操作開始。這個Demo展示了如何對列表進行添加和刪除。窗口里面有一個列表,然后有添加和刪除兩個按鈕,分別用于把文本框的內(nèi)容添加到列表內(nèi),和刪除掉選中的列表項的。在這個Demo里面只允許列表項單選,并且水平滾動條默認不出現(xiàn)。先看圖:



                空間如何布局,我就不再贅述了,明顯是一個四行三列的表格。代碼如下:

            #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 NameEditorWindow : public GuiWindow
            {
            private:
                GuiTextList
            *                        listBox;
                GuiSinglelineTextBox
            *                textBox;
                GuiButton
            *                            buttonAdd;
                GuiButton
            *                            buttonRemove;
                
                
            void buttonAdd_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // add the specified name at the end of the list box
                    listBox->GetItems().Add(textBox->GetText());
                    textBox
            ->SelectAll();
                    textBox
            ->SetFocus();
                }

                
            void buttonRemove_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // remove the selected items using item index
                    listBox->GetItems().RemoveAt(listBox->GetSelectedItems()[0]);
                }

                
            void listBox_SelectionChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // disable the button if no item is selected
                    buttonRemove->SetEnabled(listBox->GetSelectedItems().Count()>0);
                }
            public:
                NameEditorWindow()
                    :GuiWindow(GetCurrentTheme()
            ->CreateWindowStyle())
                {
                    
            this->SetText(L"Controls.ListBox.NameEditor");

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

                    table
            ->SetRowOption(0, GuiCellOption::MinSizeOption());
                    table
            ->SetRowOption(1, GuiCellOption::MinSizeOption());
                    table
            ->SetRowOption(2, GuiCellOption::MinSizeOption());
                    table
            ->SetRowOption(3, GuiCellOption::PercentageOption(1.0));

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

                    
            this->GetContainerComposition()->AddChild(table);
                    
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(0041);

                        listBox
            =g::NewTextList();
                        listBox
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        listBox
            ->SetHorizontalAlwaysVisible(false);
                        listBox
            ->SelectionChanged.AttachMethod(this&NameEditorWindow::listBox_SelectionChanged);
                        cell
            ->AddChild(listBox->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(0111);

                        GuiLabel
            * label=g::NewLabel();
                        label
            ->SetText(L"Name to add: ");
                        label
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0-100));
                        cell
            ->AddChild(label->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(0211);

                        textBox
            =g::NewTextBox();
                        textBox
            ->GetBoundsComposition()->SetPreferredMinSize(Size(12023));
                        textBox
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        cell
            ->AddChild(textBox->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(1112);

                        buttonAdd
            =g::NewButton();
                        buttonAdd
            ->SetText(L"Add");
                        buttonAdd
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        buttonAdd
            ->Clicked.AttachMethod(this&NameEditorWindow::buttonAdd_Clicked);
                        cell
            ->AddChild(buttonAdd->GetBoundsComposition());
                    }
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(2112);

                        buttonRemove
            =g::NewButton();
                        buttonRemove
            ->SetText(L"Delete");
                        buttonRemove
            ->SetEnabled(false);
                        buttonRemove
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        buttonRemove
            ->Clicked.AttachMethod(this&NameEditorWindow::buttonRemove_Clicked);
                        cell
            ->AddChild(buttonRemove->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();
                }
            };

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

                這里需要注意的幾點就是,為了實現(xiàn)在列表沒有選中內(nèi)容的時候禁用刪除按鈕,我們需要監(jiān)聽GuiTextList::SelectionChanged事件。核心的代碼就是下面這幾行:

                void buttonAdd_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // add the specified name at the end of the list box
                    listBox->GetItems().Add(textBox->GetText());
                    textBox
            ->SelectAll();
                    textBox
            ->SetFocus();
                }

                
            void buttonRemove_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // remove the selected items using item index
                    listBox->GetItems().RemoveAt(listBox->GetSelectedItems()[0]);
                }

                
            void listBox_SelectionChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // disable the button if no item is selected
                    buttonRemove->SetEnabled(listBox->GetSelectedItems().Count()>0);
                }

                GuiTextList控件的GetItems函數(shù)返回所有的列表項。這個對象有Add、Insert、Clear、IndexOf、Remove、RemoveAt、Contains、Count等函數(shù),可以用來操作列表項。GuiTextList還有GetSelectedItems函數(shù)(其實是定義在GuiSelectableListControl里面的),可以用來獲得所有選中的列表項的下標(從0開始)。每當列表內(nèi)容被修改的時候,GetSelectedItems的結(jié)果就會被自動清空。

                下一個Demo將是關(guān)于如何處理允許多選的列表的操作方法。
            posted @ 2012-05-23 04:42 陳梓瀚(vczh) 閱讀(2346) | 評論 (4)編輯 收藏
                這是GacUI關(guān)于文本框高亮的最后一個Demo了。這個Demo是關(guān)于XML著色的。XML著色比起C++著色更難,主要是因為在類似<book name="C++ Primer">這樣的代碼里面,book和name的顏色不一樣,<和book的顏色也不一樣(參考Visual Studio)。這種時候單純依靠正則表達式來區(qū)分顏色是不夠的,我們還需要引入一個新的狀態(tài)機。這個狀態(tài)機只有三個狀態(tài),用來區(qū)分tag name,attribute name和text三種顏色。狀態(tài)機是手寫的,并且GacUI提供了一個回調(diào)來寫這個只有寥寥幾行狀態(tài)機。先看圖:



                跟C++一樣,XML著色首先是由正則表達式組成的。XML的正則表達式比較簡單,只有符號、name、字符串、CData、注釋和其它一些簡單的東西:

             1 class XmlColorizer : public GuiTextBoxRegexColorizer
             2 {
             3 public:
             4     XmlColorizer()
             5     {
             6         text::ColorEntry entry=win7::Win7GetTextBoxTextColor();
             7         SetDefaultColor(entry);
             8 
             9         entry.normal.text=Color(01280);
            10         AddToken(L"/<!--([^/-]|-[^/-]|--[^>])*--/>", entry);
            11 
            12         entry.normal.text=Color(1280255);
            13         AddToken(L"/<!/[CDATA/[([^/]]|/][^/]]|/]/][^>])*/]/]/>", entry);
            14 
            15         entry.normal.text=Color(000);
            16         AddToken(L"\"[^\"]*\"", entry);
            17 
            18         entry.normal.text=Color(00255);
            19         AddToken(L"[<>=]", entry);
            20 
            21         entry.normal.text=Color(25500);
            22         AddToken(L"[a-zA-Z0-9_/-:]+", entry);
            23 
            24         entry.normal.text=Color(1632121);
            25         AddExtraToken(entry);
            26 
            27         Setup();
            28     }
            29 
            30     void ColorizeTokenContextSensitive(const wchar_t* text, vint start, vint length, vint& token, int& contextState)override
            31     {
            32         
            33     }
            34 
            35     int GetContextStartState()override
            36     {
            37         
            38     }
            39 };

                其次要對三種地方的[a-zA-Z0-9_/-:]進行著色。Tag的名字用褐色,attribute的名字用紅色,而普通文本用黑色。因此我們可以做一個狀態(tài)機,初始狀態(tài)為0。如果讀進了<,狀態(tài)變成1。1遇到了一個Tag名字之后變?yōu)?。從2開始所有的名字就只能是attribute的名字了。我們只考慮正確的情況,錯誤的代碼著色出了問題不僅沒有壞處,還可以提醒程序員有什么地方寫錯了。之后遇到了>變回0,在0的狀態(tài)下所有的東西都是普通文本,所以名字就都是黑色的。因此上面ColorizeTokenContextSensitive函數(shù)中就需要填入這個邏輯。GetContextStartState返回0,作為第一行的起始狀態(tài)。代碼如下:

                void ColorizeTokenContextSensitive(const wchar_t* text, vint start, vint length, vint& token, int& contextState)override
                {
                    
            // 0 < 1 name 2 att > 0
                    switch(token)
                    {
                    
            case 3:
                        
            if(length==1)
                        {
                            
            switch(text[start])
                            {
                            
            case '<':
                                contextState
            =1;
                                
            break;
                            
            case '>':
                                contextState
            =0;
                                
            break;
                            }
                        }
                        
            break;
                    
            case 4:
                        
            switch(contextState)
                        {
                        
            case 0:
                            token
            =-1;
                            
            break;
                        
            case 1:
                            token
            =5;
                            contextState
            =2;
                            
            break;
                        }
                        
            break;
                    }
                }

                
            int GetContextStartState()override
                {
                    
            return 0;
                }

                這個函數(shù)里面有幾個魔法數(shù)字,其實都是關(guān)于Token的編號的。構(gòu)造函數(shù)里面我們使用AddToken將一個顏色關(guān)聯(lián)到正則表達式上,使用AddExtraToken創(chuàng)建一個沒有正則表達式關(guān)聯(lián)的顏色。所以在這個狀態(tài)機里面,所有的顏色都用Token的序號來表示。無論是使用AddToken還是AddExtraToken,第一個顏色編號為0,第二個顏色編號為1。因此case 3指的是[<>=],而case 4指的是[a-zA-Z0-9_/-:]+。而case 4里面的token=5則表示在狀態(tài)為1的時候,名字都用AddExtraToken指定的那個褐色進行染色。缺省的名字(也就是id為4的token)是紅色,所以不需要對contextState為2的時候進行處理。

                這樣我們就完成了XML的著色。GacUI接下來的幾個Demo將會是關(guān)于ListBox、ListView和TreeView的,敬請期待。
            posted @ 2012-05-20 00:41 陳梓瀚(vczh) 閱讀(2241) | 評論 (2)編輯 收藏
                GacUI終于把上一篇文章中提到的自動采用正則表達式進行高亮的Demo做出來了。這次實現(xiàn)的是C++ colorizer。而XML colorizer不僅需要正則表達式,還需要一個人工維護的狀態(tài),這個等到下一個Demo再提及。先看圖



                在不需要人工維護狀態(tài),僅通過正則表達式就可以著色的時候,編寫一個colorizer變得十分的簡單。這個Colorizer雖然不是一定非得通過繼承來實現(xiàn),但是這個Demo還是使用了繼承。首先編寫一個類,繼承自GuiTextBoxRegexColorizer,然后在構(gòu)造函數(shù)里面填寫下面的代碼:

            class CppColorizer : public GuiTextBoxRegexColorizer
            {
            public:
                CppColorizer()
                {
                    text::ColorEntry entry
            =win7::Win7GetTextBoxTextColor();
                    SetDefaultColor(entry);

                    entry.normal.text
            =Color(1280255);
                    AddToken(L
            "/d+(./d*)?([eE][+/-]?/d+)?", entry);

                    entry.normal.text
            =Color(1632121);
                    AddToken(L
            "\"([^\"]|\\\\/.)*\"", entry);

                    entry.normal.text
            =Color(01280);
                    AddToken(L
            "////[^\r\n]*", entry);
                    AddToken(L
            "///*(//|[*]*[^*//])*/*+//", entry);

                    entry.normal.text
            =Color(00255);
                    AddToken(L
            "#[a-zA-Z0-9_]*", entry);
                    AddToken(CppKeywords, entry);
                    
                    AddToken(L
            "[a-zA-Z0-9_]+", GetDefaultColor());

                    Setup();
                }
            };

                然后只需要把它綁定到文本框里面就可以了。在這個Demo里面,我們在下拉框的事件里面添加下面的代碼:

                void comboSelector_SelectedIndexChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            switch(comboSelector->GetSelectedIndex())
                    {
                    
            case 0:(略)
                    
            case 1:(略)
                    
            case 2:
                        textBox
            ->SetColorizer(new CppColorizer);
                        textBox
            ->SetText(
                            L
            "#include <iostream>\r\n"
                            L
            "using namespace std;\r\n"
                            L
            "\r\n"
                            L
            "int main()\r\n"
                            L
            "{\r\n"
                            L
            "\t//This is a comment\r\n"
                            L
            "\t/**This*is/another\r\n"
                            L
            "\tcomment**/\r\n"
                            L
            "\tcout<<\"Hello, world!\"<<endl;\r\n"
                            L
            "\treturn 0;\r\n"
                            L
            "}\r\n"
                            );
                        
            break;
                    
            default:
                        textBox
            ->SetColorizer(0);
                    }
                }

                當然這樣是不完整的,因為CppColorizer里面還有一個CppKeywords的常量。這實際上是一個正則表達式,里面用“|”字符把所有C++的關(guān)鍵字連了起來。內(nèi)容抄自MSDN的C++ Language Reference:

              1 const wchar_t* CppKeywords=
              2 L"__abstract|"
              3 L"__alignof|"
              4 L"__asm|"
              5 L"__assume|"
              6 L"__based|"
              7 L"__box|"
              8 L"__cdecl|"
              9 L"__declspec|"
             10 L"__delegate|"
             11 L"__event|"
             12 L"__except|"
             13 L"__fastcall|"
             14 L"__finally|"
             15 L"__forceinline|"
             16 L"__gc|"
             17 L"__hook|"
             18 L"__identifier|"
             19 L"__if_exists|"
             20 L"__if_not_exists|"
             21 L"__inline|"
             22 L"__int16|"
             23 L"__int32|"
             24 L"__int64|"
             25 L"__int8|"
             26 L"__interface|"
             27 L"__leave|"
             28 L"__m128d|"
             29 L"__m128|"
             30 L"__m128i|"
             31 L"__m64|"
             32 L"__multiple_inheritance|"
             33 L"__nogc|"
             34 L"__noop|"
             35 L"__pin|"
             36 L"__property|"
             37 L"__raise|"
             38 L"__sealed|"
             39 L"__single_inheritance|"
             40 L"__stdcall|"
             41 L"__super|"
             42 L"__try|"
             43 L"__except|"
             44 L"__finally|"
             45 L"__try_cast|"
             46 L"__unaligned|"
             47 L"__unhook|"
             48 L"__uuidof|"
             49 L"__value|"
             50 L"__virtual_inheritance|"
             51 L"__w64|"
             52 L"__wchar_t|"
             53 L"wchar_t|"
             54 L"abstract|"
             55 L"array|"
             56 L"bool|"
             57 L"break|"
             58 L"case|"
             59 L"catch|"
             60 L"char|"
             61 L"class|"
             62 L"const_cast|"
             63 L"const|"
             64 L"continue|"
             65 L"decltype|"
             66 L"default|"
             67 L"delegate|"
             68 L"delete|"
             69 L"do|"
             70 L"double|"
             71 L"dynamic_cast|"
             72 L"else|"
             73 L"enum|"
             74 L"event|"
             75 L"explicit|"
             76 L"extern|"
             77 L"false|"
             78 L"finally|"
             79 L"float|"
             80 L"for|"
             81 L"friend|"
             82 L"gcnew|"
             83 L"generic|"
             84 L"goto|"
             85 L"if|"
             86 L"initonly|"
             87 L"inline|"
             88 L"int|"
             89 L"interface|"
             90 L"interior_ptr|"
             91 L"literal|"
             92 L"long|"
             93 L"mutable|"
             94 L"namespace|"
             95 L"new|"
             96 L"new|"
             97 L"nullptr|"
             98 L"operator|"
             99 L"private|"
            100 L"property|"
            101 L"property|"
            102 L"protected|"
            103 L"public|"
            104 L"register|"
            105 L"reinterpret_cast|"
            106 L"return|"
            107 L"sealed|"
            108 L"short|"
            109 L"signed|"
            110 L"sizeof|"
            111 L"static_assert|"
            112 L"static_cast|"
            113 L"static|"
            114 L"struct|"
            115 L"switch|"
            116 L"template|"
            117 L"this|"
            118 L"__thiscall|"
            119 L"throw|"
            120 L"true|"
            121 L"try|"
            122 L"typedef|"
            123 L"typeid|"
            124 L"typeid|"
            125 L"typename|"
            126 L"union|"
            127 L"unsigned|"
            128 L"using|"
            129 L"virtual|"
            130 L"void|"
            131 L"volatile|"
            132 L"while";

                使用GacUI為文本框著色已經(jīng)變得如此簡單。
            posted @ 2012-05-17 09:03 陳梓瀚(vczh) 閱讀(2191) | 評論 (2)編輯 收藏
                 摘要:     GacUI的高亮Demo做了一半?,F(xiàn)在的進度是,可以手寫著色器的狀態(tài)轉(zhuǎn)換函數(shù),但是自動從正則表達式產(chǎn)生著色器的狀態(tài)轉(zhuǎn)換函數(shù)部分還沒有集成進GacUI。這篇博客還是照舊,看圖、看Demo代碼,說著色原理。    這次的Demo要做一個可以動態(tài)切換著色器的小程序,里面包含INI、XML和C++三種著色器。現(xiàn)在只實現(xiàn)了INI一中,手寫的...  閱讀全文
            posted @ 2012-05-11 08:58 陳梓瀚(vczh) 閱讀(3249) | 評論 (1)編輯 收藏
                 摘要:     GacUI添加了一個新的Demo。這個Demo用了幾個按鈕(之所以不用菜單是因為不想讓Demo一下子包含太多新東西)來實現(xiàn)剪貼板操作、只讀控制和行跳轉(zhuǎn)等功能。在剪貼板里面的內(nèi)容是文字的時候,Paste按鈕會被Enable。這個過程是自動的,也就是說,你在畫圖里面復制了一個圖片,這個按鈕也會變灰。Cut和Copy按鈕僅在文本框有文字被選中的時候可用,因此相應了文...  閱讀全文
            posted @ 2012-05-05 02:37 陳梓瀚(vczh) 閱讀(5300) | 評論 (5)編輯 收藏
                GacUI新增了一個Demo。這里模擬了一個簡單到過頭了的編輯程序。界面是一個標簽頁,第一頁里面只有一個按鈕:Add Page。點中了他之后,其它頁包含一個用來關(guān)掉自己的按鈕,和一個多行的文本框。

                這個Demo要展示的其中一個問題是,在按下關(guān)閉按鈕的時候,由于那個Page會被移除并刪除,會導致按鈕自己也被刪除。但是事件發(fā)生過后,實際上還有很多事情要做的。所以這里展示了如何使用GacUI進行“延遲執(zhí)行”,在事件結(jié)束之后再刪除自己。為了方便,這個Demo使用了C++11(但是庫的實現(xiàn)并不依賴與C++11)。先上圖:





                然后我們來看代碼:

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

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

            class TextBoxPage : public GuiTabPage
            {
            private:
                
            static int pageCounter;

                GuiButton
            *                closeButton;
                GuiMultilineTextBox
            *    textBox;

                
            void closeButton_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // deleteing the tab page will also delete the button, because the button is in the page
                    
            // when an event is processing, the button is not going to be deleted
                    
            // because there are many works to do after this event
                    
            // and maybe someone has already added another event handler to this button
                    
            // so it use GetApplication()->InvokeInMainThread to send a function to the queue
                    
            // so that this function will be executed after this input message (an input message raises multiple events)
                    
            // to the user, this page is closed after cliking this button
                    GetApplication()->InvokeInMainThread([this]()
                    {
                        
            // remove the page and delete it
                        this->GetOwnerTab()->RemovePage(this);
                        delete 
            this;
                    });
                }

                
            void OnPageContainerReady(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // create a table to place a button and a text box
                    GuiTableComposition* table=new GuiTableComposition;
                    table
            ->SetRowsAndColumns(21);
                    table
            ->SetRowOption(0, GuiCellOption::MinSizeOption());
                    table
            ->SetRowOption(1, GuiCellOption::PercentageOption(1.0));
                    table
            ->SetColumnOption(0, GuiCellOption::PercentageOption(1.0));
                    table
            ->SetAlignmentToParent(Margin(0000));
                    table
            ->SetCellPadding(2);

                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(0011);
                        
                        closeButton
            =g::NewButton();
                        closeButton
            ->SetText(L"Close Me!");
                        closeButton
            ->Clicked.AttachMethod(this&TextBoxPage::closeButton_Clicked);
                        cell
            ->AddChild(closeButton->GetBoundsComposition());
                    }
                    
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        cell
            ->SetSite(1011);
                        
                        textBox
            =g::NewMultilineTextBox();
                        textBox
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        textBox
            ->SetText(L"You can input several lines of text here.\r\nThis is a multiple line text box.");
                        cell
            ->AddChild(textBox->GetBoundsComposition());
                    }

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

            public:
                TextBoxPage()
                    :closeButton(
            0)
                    ,textBox(
            0)
                {
                    PageContainerReady.AttachMethod(
            this&TextBoxPage::OnPageContainerReady);
                    
            this->SetText(L"Page "+itow(++pageCounter));
                }

                
            ~TextBoxPage()
                {
                }
            };

            int TextBoxPage::pageCounter=0;

            class TextBoxPageWindow : public GuiWindow
            {
            private:
                GuiTab
            *                        tabControl;
                GuiTabPage
            *                    controlPanelPage;
                GuiButton
            *                    buttonAddPage;

                
            void buttonAddPage_Clicked(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    
            // when the button is clicked, it creates a new TextBoxPage and adds it to the tab control
                    TextBoxPage* page=new TextBoxPage;
                    tabControl
            ->CreatePage(page);
                    tabControl
            ->SetSelectedPage(page);
                }
            public:
                TextBoxPageWindow()
                    :GuiWindow(GetCurrentTheme()
            ->CreateWindowStyle())
                {
                    
            this->SetText(L"Controls.Tab.TextBoxPage");
                    
            this->GetBoundsComposition()->SetPreferredMinSize(Size(640480));

                    
            // create a tab control
                    tabControl=g::NewTab();
                    tabControl
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(2222));
                    
            this->AddChild(tabControl);

                    
            // the first page is a control panel
                    controlPanelPage=tabControl->CreatePage();
                    controlPanelPage
            ->SetText(L"Control Panel");

                    
            // add a button to the control panel
                    buttonAddPage=g::NewButton();
                    buttonAddPage
            ->SetText(L"Add a tab page");
                    buttonAddPage
            ->Clicked.AttachMethod(this&TextBoxPageWindow::buttonAddPage_Clicked);
                    controlPanelPage
            ->GetContainer()->GetContainerComposition()->SetInternalMargin(Margin(2222));
                    controlPanelPage
            ->GetContainer()->AddChild(buttonAddPage);

                    
            this->ForceCalculateSizeImmediately();
                    
            this->MoveToScreenCenter();
                }

                
            ~TextBoxPageWindow()
                {
                }
            };

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

                那一大段的注釋,就是在講延遲執(zhí)行的事情。看過C++11的人都知道,lambda expression實際上就是一個functor。在舊C++里面,調(diào)用InvokeInMainThread的時候,要么可以傳一個void(*)(void*)和void*,要么可以傳一個帶operator()()的struct。在新C++里面,直接把lambda expression寫在里面就好了。

                如果不使用延遲執(zhí)行,在事件發(fā)生的時候把自己刪掉,會導致Access Violation的發(fā)生,因為接下來要訪問的對象被你刪掉了。如果使用延遲執(zhí)行,就可以在input message處理完之后,執(zhí)行刪除的代碼。這樣一切都是好的。

                下一個Demo就是關(guān)于文本框的操作,再下一個Demo是關(guān)于如何做用來顯示代碼的高亮文本框的事情。敬請期待,啊哈哈哈。
            posted @ 2012-04-30 23:28 陳梓瀚(vczh) 閱讀(2022) | 評論 (2)編輯 收藏
                GacUI發(fā)布了一個新的Demo。這個Demo是關(guān)于多選框和單選框的。跟Windows一樣,直接創(chuàng)建出來的單選框其實是不會互斥的,除非你把他們放進同一個group里面。界面是左右各一個group box,使用table來保證兩邊的尺寸都一樣大。每一個group box里面放三個按鈕,而且每一個group box的最小尺寸都取決于兩邊所有6按鈕中最長的那個按鈕。每一邊的三個按鈕使用stack來排列成像一個列表一樣。左邊是多選框,右邊是單選框?,F(xiàn)在先上圖:

                第一張是剛打開的時候,窗口的尺寸自動變化到能顯示所有內(nèi)容的最小的尺寸。盡管因為文字的關(guān)系,左邊的按鈕比右邊的短,但是table可以控制兩個group box一樣大,并且共享最小尺寸。



                然后改變窗口的尺寸,按鈕始終靠左上角,兩個group box則保持一樣大。



                大家已經(jīng)看了前面的三個demo,所以有些東西其實已經(jīng)不需要重復解釋了。先上代碼:

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

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

            class CheckAndRadioWindow : public GuiWindow
            {
            private:

                GuiCellComposition
            * CreateButtons(const WString& groupName, const WString& buttonName, bool checkBox, GuiSelectableButton::GroupController* groupController)
                {
                    GuiCellComposition
            * cell=new GuiCellComposition;

                    GuiControl
            * groupBox=g::NewGroupBox();
                    groupBox
            ->GetBoundsComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
                    groupBox
            ->GetContainerComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
                    
            // all child controls should at least 10 pixels away from the group box
                    groupBox->GetContainerComposition()->SetInternalMargin(Margin(10101010));
                    
            // dock the group box to fill the cell
                    groupBox->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                    groupBox
            ->SetText(groupName);
                    
            // add the button to the cell
                    cell->AddChild(groupBox->GetBoundsComposition());

                    
            // create a stack to layout the 3 buttons from top to bottom shown like a list
                    GuiStackComposition* stack=new GuiStackComposition;
                    stack
            ->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
                    stack
            ->SetDirection(GuiStackComposition::Vertical);
                    stack
            ->SetAlignmentToParent(Margin(0000));
                    stack
            ->SetPadding(6);
                    groupBox
            ->GetContainerComposition()->AddChild(stack);

                    
            // create buttons
                    for(int i=0;i<3;i++)
                    {
                        GuiSelectableButton
            * button=checkBox?g::NewCheckBox():g::NewRadioButton();
                        button
            ->SetText(buttonName+itow(i+1));
                        button
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0000));
                        
            if(groupController)
                        {
                            button
            ->SetGroupController(groupController);
                        }

                        GuiStackItemComposition
            * stackItem=new GuiStackItemComposition;
                        stack
            ->AddChild(stackItem);
                        stackItem
            ->AddChild(button->GetBoundsComposition());
                    }

                    
            return cell;
                }
            public:
                CheckAndRadioWindow()
                    :GuiWindow(GetCurrentTheme()
            ->CreateWindowStyle())
                {
                    
            this->SetText(L"Controls.Button.CheckAndRadio");
                    
            // limit the size that the window should always show the whole content without cliping it
                    this->GetContainerComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

                    
            // create a table to layout the 2 group boxes
                    GuiTableComposition* table=new GuiTableComposition;
                    
            // make the table to have 2 rows
                    table->SetRowsAndColumns(12);
                    table
            ->SetRowOption(0, GuiCellOption::MinSizeOption());
                    table
            ->SetColumnOption(0, GuiCellOption::PercentageOption(0.5));
                    table
            ->SetColumnOption(1, GuiCellOption::PercentageOption(0.5));
                    
            // dock the table to fill the window
                    table->SetAlignmentToParent(Margin(4444));
                    table
            ->SetCellPadding(6);
                    
            // add the table to the window;
                    this->GetContainerComposition()->AddChild(table);

                    
            // add group box for check boxes
                    {
                        GuiCellComposition
            * cell=CreateButtons(L"Check Boxes", L"This is a check box "true0);
                        table
            ->AddChild(cell);
                        
            // this cell is the left cell
                        cell->SetSite(0011);
                    }

                    
            // add group box for radio buttons
                    {
                        
            // create a group controller to group those radio buttons together
                        
            // so that select a radio button will unselect the previous one automatically
                        GuiSelectableButton::GroupController* groupController=new GuiSelectableButton::MutexGroupController;
                        
            this->AddComponent(groupController);

                        GuiCellComposition
            * cell=CreateButtons(L"Radio buttons", L"This is a radio button "false, groupController);
                        table
            ->AddChild(cell);
                        
            // this cell is the right cell
                        cell->SetSite(0111);
                    }

                    
            // 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();
                }

                
            ~CheckAndRadioWindow()
                {
                }
            };

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

                需要關(guān)心的就是第二次調(diào)用CreateButtons函數(shù),用來構(gòu)造單選按鈕的時候,穿進去的最后一個參數(shù)。GuiSelectableButton::GroupController類是一個虛類,用來控制選中狀況。而預定義的MutexGroupController則可以控制連接到的所有GuiSelectionButton并保證他們互斥。如果需要更加復雜的情況,譬如說“最多只能選中N個按鈕”這樣的,則自己集成一個group controller就可以了。在創(chuàng)建了一個group controller,要調(diào)用GuiWindow::AddComponent保持他的生命周期,然后使用GuiSelectableButton::SetGroupController來幫頂一個按鈕和一個group controller。

                這個demo就介紹到這里了,下一個將是關(guān)于tab控件和文本框的demo。
            posted @ 2012-04-27 06:02 陳梓瀚(vczh) 閱讀(2255) | 評論 (25)編輯 收藏
                今天為GacUI寫了一個新的Demo,展示了一些可以自動排版的按鈕。主要的設想就是在窗口上放一個表格,分成兩行兩列。上面的按鈕占滿一整行,下面兩個單元格放兩個按鈕。然后就可以設置每個行和列占整個表格的比例,在這個Demo里面都設置成50%。這樣每當窗口縮放的時候,按鈕的位置也會隨之重新排版。然后設置表格充滿整個窗口,這樣窗口的最小值就會被表格的內(nèi)容所限定,這樣試圖把窗口縮小的時候,就會有一個最小的尺寸限制著,至始至終保證所有的東西都可以顯示出來,不會因為窗口太小而只顯示一半。按鈕也是同樣,可以設置它必須顯示所有的文字。所有的過程一旦配置好之后,計算尺寸的時候所有的操作都會自動做,程序員不需要為窗口的Resize事件寫任何代碼。

                下面先放圖。

                第一個圖是窗口剛剛打開的時候的樣子。因為Demo里面沒有設置窗口的尺寸,所以一上來就自動變成了最小的尺寸——并且剛好可以顯示所有的內(nèi)容。



                第二個圖是窗口放大之后的樣子。Disable按鈕被按下了,所以上面的按鈕就變灰。



                這個Demo使用了Direct2D渲染器,所有的繪制過程都十分高速。而且表格的尺寸計算也是經(jīng)過優(yōu)化的,在拖放窗口的時候十分流暢。事實上按鈕的漸變啊、邊框啊、文字等等也是借助表格排版的。由于尺寸計算過于復雜,除了表格之外整個框架都不保存控件的尺寸,所有的東西都在需要的時候——譬如說渲染的時候,譬如說計算鼠標點中的位置——的那一刻才開始算。因此無論是鼠標滑過,或者是窗口拖放,都拼命地執(zhí)行很多虛函數(shù)??梢奀++的虛函數(shù)的性能之高,幾乎永遠都不會成為程序的瓶頸。下面來看代碼:

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

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

            class EnableDisableWindow : public GuiWindow
            {
            private:
                GuiButton
            *            buttonTarget;
                GuiButton
            *            buttonEnable;
                GuiButton
            *            buttonDisable;

                
            void buttonEnable_OnClick(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    buttonTarget
            ->SetEnabled(true);
                }

                
            void buttonDisable_OnClick(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    buttonTarget
            ->SetEnabled(false);
                }
            public:
                EnableDisableWindow()
                    :GuiWindow(GetCurrentTheme()
            ->CreateWindowStyle())
                {
                    
            this->SetText(L"Controls.Button.EnableDisable");
                    
            // limit the size that the window should always show the whole content without cliping it
                    this->GetContainerComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

                    
            // create a table to layout the 3 buttons
                    GuiTableComposition* table=new GuiTableComposition;
                    
            // make the table to have 2 rows
                    table->SetRowsAndColumns(22);
                    table
            ->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
                    table
            ->SetRowOption(1, GuiCellOption::PercentageOption(0.5));
                    table
            ->SetColumnOption(0, GuiCellOption::PercentageOption(0.5));
                    table
            ->SetColumnOption(1, GuiCellOption::PercentageOption(0.5));
                    
            // dock the table to fill the window
                    table->SetAlignmentToParent(Margin(10101010));
                    
            // add the table to the window;
                    this->GetContainerComposition()->AddChild(table);

                    
            // add the target button
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        
            // this cell is the top cell
                        cell->SetSite(0012);

                        buttonTarget
            =g::NewButton();
                        buttonTarget
            ->SetText(L"Enable or disable me using the buttons below!");
                        
            // ensure that the buttonTarget display the whole text
                        buttonTarget->GetBoundsComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
                        
            // dock the button to fill the cell
                        buttonTarget->GetBoundsComposition()->SetAlignmentToParent(Margin(0003));
                        
            // add the button to the cell
                        cell->AddChild(buttonTarget->GetBoundsComposition());
                    }

                    
            // add the enable button
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        
            // this cell is the bottom left cell
                        cell->SetSite(1011);

                        buttonEnable
            =g::NewButton();
                        buttonEnable
            ->SetText(L"Enable");
                        buttonEnable
            ->GetBoundsComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
                        buttonEnable
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(0330));
                        buttonEnable
            ->Clicked.AttachMethod(this&EnableDisableWindow::buttonEnable_OnClick);
                        cell
            ->AddChild(buttonEnable->GetBoundsComposition());
                    }

                    
            // add the disable button
                    {
                        GuiCellComposition
            * cell=new GuiCellComposition;
                        table
            ->AddChild(cell);
                        
            // this cell is the bottom right cell
                        cell->SetSite(1111);

                        buttonDisable
            =g::NewButton();
                        buttonDisable
            ->SetText(L"Disable");
                        buttonDisable
            ->GetBoundsComposition()->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
                        buttonDisable
            ->GetBoundsComposition()->SetAlignmentToParent(Margin(3300));
                        buttonDisable
            ->Clicked.AttachMethod(this&EnableDisableWindow::buttonDisable_OnClick);
                        cell
            ->AddChild(buttonDisable->GetBoundsComposition());
                    }

                    
            // change the button font
                    {
                        FontProperties font;

                        font
            =buttonTarget->GetFont();
                        font.size
            =20;
                        buttonTarget
            ->SetFont(font);
                        buttonEnable
            ->SetFont(font);
                        buttonDisable
            ->SetFont(font);
                    }

                    
            // 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()
                    table->UpdateCellBounds();
                    
            // update the size
                    this->SetBounds(Rect());
                    
            // move to the screen center
                    this->MoveToScreenCenter();
                }

                
            ~EnableDisableWindow()
                {
                }
            };

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

                代碼里面充滿了注釋,而且主要的內(nèi)容也在上面介紹了,在這里我就不羅嗦了。所有的代碼都可以在http://gac.codeplex.com中,下載最新的代碼,然后在Libraries\GacUI\GacUIDemo\GacUIDemo.sln下面找到。
            posted @ 2012-04-25 02:46 陳梓瀚(vczh) 閱讀(2346) | 評論 (5)編輯 收藏
                今天我給GacUI添加了一個新Demo。我發(fā)現(xiàn)寫Demo也是一個測試的過程,可以用來檢驗類庫提供的API是否夠完整。前面這兩個Demo都促使我往類庫里面加入了新的函數(shù)。這次的Demo是用Label控件來模仿超鏈接。下載最新代碼之后,可以在“Libraries\GacUI\GacUIDemo\GacUIDemo.sln”下面找到最新的Demo代碼。

                為了模仿超鏈接,我們要做兩件事情。第一件事情就是鼠標懸浮在Label上的時候需要顯示出手的光標圖,第二件事情就是在鼠標進入Label的時候顯示下劃線,離開的時候去掉下劃線。因此我們需要監(jiān)聽三個事件,分別是MouseEnter,MouseLeave和LeftButtonDown。下面是Demo的圖:

                上圖:鼠標在Label外。下圖:鼠標在Label內(nèi)。單擊Label的時候會打開瀏覽器。



                代碼如下:

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

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

            class HyperlinkWindow : public GuiWindow
            {
            private:
                GuiLabel
            *                labelHyperlink;

                
            void labelHyperlink_OnMouseEnter(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    FontProperties font
            =labelHyperlink->GetFont();
                    font.underline
            =true;
                    labelHyperlink
            ->SetFont(font);
                }

                
            void labelHyperlink_OnMouseLeave(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
                {
                    FontProperties font
            =labelHyperlink->GetFont();
                    font.underline
            =false;
                    labelHyperlink
            ->SetFont(font);
                }

                
            void labelHyperlink_OnLeftButtonDown(GuiGraphicsComposition* sender, GuiMouseEventArgs& arguments)
                {
                    ShellExecute(NULL, L
            "OPEN", L"http://www.shnenglu.com/vczh", NULL, NULL, SW_SHOWNORMAL);
                }
            public:
                HyperlinkWindow()
                    :GuiWindow(GetCurrentTheme()
            ->CreateWindowStyle())
                {
                    SetText(L
            "Controls.Label.Hyperlink");
                    SetClientSize(Size(
            300200));
                    MoveToScreenCenter();

                    labelHyperlink
            =g::NewLabel();
                    labelHyperlink
            ->SetText(L"http://www.shnenglu.com/vczh");
                    labelHyperlink
            ->SetTextColor(Color(00255));
                    {
                        FontProperties font;
                        font.fontFamily
            =L"Segoe UI";
                        font.size
            =18;
                        font.antialias
            =true;
                        labelHyperlink
            ->SetFont(font);
                    }
                    {
                        INativeCursor
            * hand=GetCurrentController()->ResourceService()->GetSystemCursor(INativeCursor::Hand);
                        labelHyperlink
            ->GetBoundsComposition()->SetAssociatedCursor(hand);
                    }
                    labelHyperlink
            ->GetEventReceiver()->mouseEnter.AttachMethod(this&HyperlinkWindow::labelHyperlink_OnMouseEnter);
                    labelHyperlink
            ->GetEventReceiver()->mouseLeave.AttachMethod(this&HyperlinkWindow::labelHyperlink_OnMouseLeave);
                    labelHyperlink
            ->GetEventReceiver()->leftButtonDown.AttachMethod(this&HyperlinkWindow::labelHyperlink_OnLeftButtonDown);
                    AddChild(labelHyperlink);
                }

                
            ~HyperlinkWindow()
                {
                }
            };

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

                這里展示的主要是監(jiān)聽事件的方法。在使用control->GetEventReceiver()->event的時候,可以使用Attach、AttachMethod、AttachFunction和AttachLambda。AttachLambda傳入一個functor,在C++11里面可以直接使用lambda表達式。在這里使用AttachMethod給一個事件綁定類成員函數(shù)。C++運行類成員函數(shù)的時候,不僅需要參數(shù),還需要一個this對象,所以AttachMethod有兩個參數(shù),使用方法在Demo里面已經(jīng)展現(xiàn)出來了。

                在這里還引入了GetCurrentController函數(shù)。GetCurrentController返回的INativeController對象抽象了所有需要的操作系統(tǒng)的功能,其中獲得一個光標的對象就封裝在了ResourceService里面。INativeController還包含了很多其他的Service,這個留在以后的Demo展示。
            posted @ 2012-04-24 02:37 陳梓瀚(vczh) 閱讀(2117) | 評論 (8)編輯 收藏
                今晚終于把GacUI所有該加上的XML注釋都加上了,開始做起了Demo。需要做的Demo大概有幾十個,除了每個控件要那么幾個以外,還有一些其他功能,譬如換皮膚換風格啊,使用不同的渲染器啊,移植到Direct3D上什么的,好多啊,即將寫到手軟。今天寫了第一個Demo,是一個helloworld程序。創(chuàng)建一個GacUI程序是一件很容易的事情,首先下載GacUI的最新代碼(在有了Release之后會有更好的文件組織和html文檔),然后將“Libraries\GacUI\Public\Source”下面的5個文件添加進建好的Visual C++的Windows工程里面,然后開始寫main函數(shù):

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

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

            void GuiMain()
            {
                GuiWindow
            * window=g::NewWindow();
                window
            ->SetText(L"Hello, world!");
                window
            ->SetClientSize(Size(640480));
                window
            ->MoveToScreenCenter();
                
                GuiControl
            * label=g::NewLabel();
                label
            ->SetText(L"Welcome to GacUI Library!");
                {
                    FontProperties font;
                    font.fontFamily
            =L"Segoe UI";
                    font.size
            =40;
                    font.antialias
            =true;
                    label
            ->SetFont(font);
                }
                window
            ->AddChild(label);

                GetApplication()
            ->Run(window);
                delete window;
            }

                Main函數(shù)里面需要選擇渲染器,這里選的是Direct2D。如果要選擇GDI,則調(diào)用SetupWindowsGDIRenderer。至于void GuiMain(void)函數(shù)則是類庫自己的要求,一定要有那么一個,因為SetupWindowsDirect2DRenderer(或GDI)最終會進行一大段初始化工作之后調(diào)用一個聲明了卻沒有實現(xiàn)的void GuiMain(void)函數(shù),所以一個合法的GacUI工程需要包含void GuiMain(void)的實現(xiàn),也就是上面這樣。

                然后接下來的就是普通的工作了,創(chuàng)建一個GuiWindow,加點東西,Run一下當主窗口。當主窗口被關(guān)掉的時候Run函數(shù)就會結(jié)束,這個時候進行一下必要的清理,程序就可以結(jié)束了。運行之后就是下面這個樣子:



                至此HelloWorld的Demo就結(jié)束了。

            posted @ 2012-04-23 07:37 陳梓瀚(vczh) 閱讀(2471) | 評論 (12)編輯 收藏
            僅列出標題
            共35頁: First 2 3 4 5 6 7 8 9 10 Last 
            青青青伊人色综合久久| 久久99精品久久久久久齐齐| 国产亚州精品女人久久久久久| 欧美国产成人久久精品| 久久综合九色综合久99| 久久天天躁狠狠躁夜夜avapp| 久久精品www| 欧美亚洲色综久久精品国产| 久久91精品综合国产首页| 精品久久一区二区| 亚洲av成人无码久久精品 | 色综合久久中文字幕综合网| 久久99国产综合精品女同| 久久久国产视频| 久久综合精品国产一区二区三区| 91精品国产综合久久婷婷| 久久香综合精品久久伊人| 亚洲中文字幕无码久久2020 | 久久男人AV资源网站| 久久伊人精品青青草原高清| 亚洲AV日韩精品久久久久| 久久综合亚洲鲁鲁五月天| 婷婷久久综合九色综合九七| 精品人妻伦九区久久AAA片69 | 69久久精品无码一区二区| 亚洲AV无码1区2区久久| 久久青青草视频| 中文精品久久久久人妻| 欧美亚洲日本久久精品| 久久久久一本毛久久久| 国产精品美女久久久网AV| 亚洲国产精品人久久| 久久99毛片免费观看不卡 | 2020久久精品国产免费| 久久久一本精品99久久精品66| 日韩精品久久无码中文字幕| 日韩人妻无码精品久久免费一 | 伊人久久国产免费观看视频| 香蕉久久永久视频| 久久人人爽人人爽人人片AV高清| 漂亮人妻被中出中文字幕久久|