duilib入門簡明教程 -- 界面布局(9) (轉)


原文轉自:http://www.cnblogs.com/Alberl/p/3343806.html

 

    上一個教程實現的標題欄代碼中,並沒有看到處理自適應窗口大小的代碼,但是窗口大小變化后,按鈕的位置會跟着變化,這是因為我們將按鈕放到了HorizontalLayout、VerticalLayout,這樣duilib就會幫我們自動布局按鈕的位置和大小,顧名思義,HorizontalLayout就是水平布局,VerticalLayout就是垂直布局。
    最開始的教程里面,窗口大小變化時,Hello World按鈕會沾滿整個窗口,並且文字始終居中,這就是HorizontalLayout的效果:
        <HorizontalLayout> <Button name="btnHello" text="Hello World"/> </HorizontalLayout>

    那么HorizontalLayout和VerticalLayout有什么區別呢? 其實這個Alberl也不怎么懂,Alberl都是直接試效果的,HorizontalLayout不行就換VerticalLayout ~O(∩_∩)O  這個還得請各位大神多多賜教,等寫完這個入門教程后,Alberl會繼續學習duilib,到時候再繼續寫教程。

    由於官方木有文檔,所有的東西都靠自己去看,去Demo里調試,所以這個布局的准確文字定義我也不好說,就直接用實驗的方式跟大家講解啦~
 
    現在開始講解上一個教程中的界面布局:
    1、首先得到一個漸變的背景窗口,將XML的內容改成下面這樣
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> </VerticalLayout> </Window>

效果如圖:

    從duilib的源碼里可以看到:
    (1)XML的 <VerticalLayout> 節點對應於duilib里的CVerticalLayoutUI控件
    (2)CVerticalLayoutUI控件繼承於CContainerUI,而CContainerUI繼承於CControlUI。
    所以其實CVerticalLayoutUI 也是一個控件啦,把它和CButtonUI同等對待,就比較好理解了。
為了進一步表現他們的類似,可以將XML里面的VerticalLayout 換成 Button、Control、Container 試試,你會發現效果是一樣的哦~
 
    再次強調下win32/MFC的界面 和duilib 界面的區別:
    (1)MFC中將按鈕、菜單、標題欄等等都當作不同的東西(例如標題欄只能放在最上面,按鈕不能直接拖到標題欄等等);
     duilib中將所有的東西都同等對待,所以處理起來非常方便(別說把按鈕放到標題欄上,就算把標題欄放在按鈕上都沒問題)。
    (2)MFC中所有的窗口和控件都是繼承於CWnd(win32繼承於HWND)。
     duilib中所有的控件都繼承於CControlUI,所有的窗口都繼承於CWindowWnd(內部包裝了HWND)。
     所以如果用MFC做一個界面,那么上面就是很多個CWnd,用Spy++可以看到不同的窗口句柄。
     如果用duilib做一個界面,那么上面就是很多個CControlUI,但是用Spy++只能看到一個窗口句柄。
     這是因為duilib整個窗口只有一個HWND,其他的CControlUI雖然是控件,但是其實都是自己繪制出來的,並不是真正的HWND,所以你可以把這些控件理解為自繪,整個duilib的界面繪制,就是在自繪一個HWND。
 
    2、加上標題欄,將XML的內容改成下面這樣:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

其中height="32" 是指這個HorizontalLayout 只占用32個像素高度。
 
    3、將標題欄移到下面,將XML的內容改成下面這樣:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <HorizontalLayout /> <!-- 占空位,占據上面所有的空位--> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

這里只加了一行代碼<HorizontalLayout />,就讓標題欄移到了下面,這行代碼的意思是:占據空白的部分。
由於這行代碼放在標題欄HorizontalLayout 的上面,所以標題欄被擠了下去,如果放到下面,是沒有效果的。
 
4、將標題欄移到中間,將XML的內容改成下面這樣:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <HorizontalLayout /> <!-- 占空位,占據上面所有的空位--> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> </HorizontalLayout> <HorizontalLayout /> <!-- 占空位,占據下面所有的空位--> </VerticalLayout > </Window>
復制代碼

效果如圖:

    為什么標題欄就跑到中間了呢? 
    在標題欄的上面和下面都有一個占空位的<HorizontalLayout />,如果沒有指定高度,那么他們會默認各占一半高度,相當於有一個默認的屬性 height="***"
 
    那么我們給它指定一個高度試試,比如把上面那個<HorizontalLayout /> 改為<HorizontalLayout height="32" />,效果如圖:
 
    現在應該明白<HorizontalLayout />占位的作用了吧~\(^o^)/~
    這里有一點要注意的就是:
占位的時候,
<HorizontalLayout /> 一般是指定height屬性,也就是說占的位置是從上往下算的。因為水平方向的位置都會占據。
<VerticalLayout/>       一般是指定width屬性,也就是說占的位置是從左往右算的。因為垂直方向的位置都會占據。
並且HorizontalLayout 和VerticalLayout一般都是交叉包含,而不是重復包含(比如<HorizontalLayout> 子節點里再包含一個<HorizontalLayout> 節點)。
    當然,上面指的是一般情況,如果對布局很熟悉了,就可以隨意包含了。
    這里講的都是把標題欄水平放置,把標題欄垂直放置相信也難不倒大家了,就請自行試驗,以便熟悉這些布局。
 
    5、回到前面第2個步驟,我們來添加客戶區布局。
    因為背景色已經是漸變的了,所以就不給客戶區加背景了,那么客戶區暫且不管。
 
    6、添加最大化、最小化、關閉按鈕:
    上一個教程的最后部分已經解釋了按鈕的外觀等屬性,這里為了簡明,就不加那么多屬性了,先加上一個最小化按鈕試試效果:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> <Button name="minbtn" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' "/> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

可以看到整個最小化按鈕都被拉伸了,其中兩邊的矩形色塊是因為圖片的邊框也被拉伸了。
 
我們再加上最大化按鈕和關閉按鈕,XML如下:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> <Button name="minbtn" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' "/> <Button name="maxbtn" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' "/> <Button name="closebtn" normalimage=" file='SysBtn\closeNormal.bmp' " hotimage=" file='SysBtn\closeFocus.bmp' "/> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

    可以發現三個按鈕被均勻拉伸了。
    但是我們顯然不想讓按鈕被拉伸,怎么辦呢?
    還記得前面說的占位布局嗎?因為我們想讓按鈕顯示到右邊,所以我們要占住左邊的部分。 那我們加一個占位試試。
不過,
    (1)親們知道這個占位要加到哪一行么?
        當然是加到按鈕的上面! 那我們加到按鈕上面試試。
    (2)親們知道這個占位布局用<HorizontalLayout/>還是<VerticalLayout/>么?
        其實我也不知道,那咱們就試試吧。
        先加個<HorizontalLayout/>玩玩,XML如下:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> <HorizontalLayout /> <Button name="minbtn" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' "/> <Button name="maxbtn" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' "/> <Button name="closebtn" normalimage=" file='SysBtn\closeNormal.bmp' " hotimage=" file='SysBtn\closeFocus.bmp' "/> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

    (其實換成VerticalLayout等任何CControlUI,效果都是一樣的)
    果然占到了左邊的部分,但是為什么還是均分呢,怎么讓它只占用左邊的一大部分呢?
    這就是width的用處了, 我們給HorizontalLayout 加上一個屬性 width = "600",可以看到如下效果:
    好家伙,果然有用!
    下一步我們再把width加大一點,應該就可以讓按鈕正常了吧?
    先別急着管大小,我們先拖動一下窗口大小,或者點擊最大化按鈕~
    是不是有新問題啦? 為什么按鈕還是被放大了呢?
    因為我們給HorizontalLayout加上了width屬性,那么在水平方向,它就失去自適應效果啦,因為寬度永遠是前面指定的600.
    那怎么樣才能讓按鈕不被放大呢?
    很顯然,不應該給左邊的占位布局HorizontalLayout 指定width屬性,而應該給右邊的按鈕指定width屬性。
    但是按鈕有 width屬性嗎?
    按鈕是有,但是我們應該添加一個占位布局 HorizontalLayout  來指定width屬性。 XML如下:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> <HorizontalLayout /> <HorizontalLayout width = "77"> <Button name="minbtn" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' "/> <Button name="maxbtn" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' "/> <Button name="closebtn" normalimage=" file='SysBtn\closeNormal.bmp' " hotimage=" file='SysBtn\closeFocus.bmp' "/> </HorizontalLayout> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

    現在窗口大小怎么變,按鈕都不會被拉伸啦,恭喜小伙伴們~
    可以看到那3個Button節點都被放到了HorizontalLayout 節點下,下面是時候講一下布局了:
    其實duilib整個界面都是由各種布局組成,我們把上面的XML簡化一下,就是下面這樣子:
復制代碼
<Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout > <HorizontalLayout height="32" > <HorizontalLayout /> <HorizontalLayout width = "77" /> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

    很明顯,最外層是整個窗口的布局<VerticalLayout>,之后又包含了一個 <HorizontalLayout height="32" >布局(即標題欄),

再里面又包含了兩個HorizontalLayout布局,所以一切框架和位置都是由布局決定。
    這里先簡要介紹一下duilib的UI設計器:
    1、在duilib源碼的bin目錄下,【DuiDesigner.exe】就是UI設計器啦。
    2、把XML拖拽上去即可直接看到界面效果,
    我們把前面那個完整的XML拖進去,即可看到如下效果:
    紅色邊框圍起來的就是一個個HorizontalLayout 等布局啦~
 
    7、調整按鈕的位置和大小。
    雖然已經將按鈕顯示到最后邊,但是按鈕沾滿了右邊部分,我們現在把他們的高度調小一點:
    給Button節點都加上屬性 height ="20",效果如圖:
    嗯,效果看起來還行。
 
    再加上width="23"屬性,效果如圖:
    那怎么樣讓按鈕不挨着頂部呢?
    前面介紹過float屬性,是用於絕對定位,由於現在按鈕的位置都是由布局自動調整的,所以沒辦法調節位置,如果不想讓布局自動調整位置,就要加上float="true",這樣就可以自己指定位置啦。我們給最小化按鈕加上 float="true" pos="0,5,22,24" 試試,效果如圖:
 
    額,最小化按鈕哪里去了~~~
    雖然最小化按鈕使用了絕對定位,但是其他兩個按鈕還是自動布局,所以需要給他們也加上,XML如下:
復制代碼
            <HorizontalLayout width = "77"> <Button name="minbtn" height ="20" width="23" float="true" pos="0,5,22,24" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' "/> <Button name="maxbtn" height ="20" width="23" float="true" pos="22,5,44,24" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' "/> <Button name="closebtn" height ="20" width="23" float="true" pos="44,5,74,24" normalimage=" file='SysBtn\closeNormal.bmp' " hotimage=" file='SysBtn\closeFocus.bmp' "/> </HorizontalLayout>
復制代碼

效果如圖:

 
    對比一下上個教程完整的圖片:
    發現我們這個這個圖有點不對,三個按鈕的中間的線有點粗~
    這是因為圖片畫的不對(這些圖片是Alberl早幾年畫的,用於MFC,所以並沒有考慮duilib),可以把最大化按鈕兩邊的邊框都去掉,這樣就OK啦~
    不過呢,沒必要那么做,我們恰好可以再學習一點新知識~
    我們可以看到,雖然給關閉按鈕指定的寬度也是23,但是它卻比其他按鈕大。  這說明width屬性已經失效了,這是因為我們在pos屬性里面已經指定了位置大小,它會優先以pos屬性為准,那么顯然height屬性也失效了。(感謝網友【糖加三勺】的提醒,Alberl的這個 說法有誤,重新試了一下,如果pos屬性放在后面,就會以pos為准,height屬性放在后面就會以height為准,並不是屬性失效。)
    回到剛剛那個按鈕圖片的問題,由於每個按鈕圖片都畫了邊框,所以會有加在一起就有兩個邊框了,所以中間的線有點粗,那么我們現在可以將最大化、關閉按鈕往左邊移動一個像素。
效果如圖:
    嘿嘿,好了吧~
    但是這個關閉按鈕貌似有點寬~
    我們當然可以再次調整pos屬性,但是這不科學~~
    還記得失效的那兩個屬性么?
    那是因為pos屬性的后面兩個值都填了非0值,所以導致那兩個屬性失效,下面我們把pos后面的兩個值改為0試試。
可以發現那兩個屬性又生效啦~(感謝網友【糖加三勺】的提醒,Alberl的這個 說法有誤,重新試了一下,如果pos屬性放在后面,就會以pos為准,height屬性放在后面就會以height為准,並不是屬性失效。)
    現在只要去掉width、height屬性中的一個,按鈕都會不見了,Alberl以為按鈕的大小會調整成圖片的大小呢~~~
看來只能指定寬度和高度了(為了方便后期的位置調整,建議pos屬性后面兩個值填0,使用width/height屬性來指定按鈕大小)
這幾個圖片的寬高分別是19 * 23、19*28,所以就手動指定了,XML如下:
復制代碼
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0"> <!-- 標題欄區 --> <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0"> <HorizontalLayout /> <HorizontalLayout width = "77"> <Button name="minbtn" float="true" pos="0,5,0,0" height="19" width="23" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' "/> <Button name="maxbtn" float="true" pos="22,5,0,0" height="19" width="23" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' "/> <Button name="closebtn" float="true" pos="44,5,0,0" height="19" width="28" normalimage=" file='SysBtn\closeNormal.bmp' " hotimage=" file='SysBtn\closeFocus.bmp' "/> </HorizontalLayout> </HorizontalLayout> </VerticalLayout > </Window>
復制代碼

效果如圖:

    (上面的XML里,Button的父節點HorizontalLayout 換成 VerticalLayout也是一樣的效果,所以有時候他們是沒有什么分別的,不過個人的理解應該是要交叉使用的)
    好啦,最關鍵的布局部分講完啦,另外,在duilib的官方群里,有共享一個布局案例,Alberl已整理出來【 duilib入門和xml培訓 布局案例.rar】,那里有9個布局案例,相信看完本教程的講解之后,再看看那9個XML布局,應該就很熟悉布局啦,如果還有不懂的話,請留言~
    注意:一切結果以實際運行效果為准,切勿完全相信本文的言論,因為Alberl搞不好手一抖打錯個字母啥的,或者復制上來的代碼有誤,或者本來理解就有誤,很可能會誤導大家。如有錯誤的地方,多謝指正~\(^o^)/~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM