第八章 使用者界面(二)
在 winform 上使用控件
控件就是類,派生自 system.windows.forms.control,由此類派生出的任何類都能顯示在窗體上,隻要将它添加到窗體對象的 controls 集合中。
現在我們看一下用控件畫樹形的方法。winforms 庫定義了 treeview 類,這是專門用于顯示樹形結構的;自然,我們就用這個控件來顯示樹。使用 treeview,需要建立它的執行個體,并設定屬性、調用方法,對它進行配置。最重要的,是将需要顯示的結點添加到 nodes 集合中。這個控件準備好以後,就可以将它添加到窗體的 controls 集合。
treeview 類用 treenode 對象表示結點,是以,我們定義函數 maptreetotreenode,遞歸周遊樹形結構,建立 treenode 圖形。清單 8-2 中的程式産生圖 8-3 的樹。
清單 8-2 用控件 treeview 畫樹
opensystem.windows.forms
//the tree type
type ‘a
tree =
|node of ‘a
tree * ‘a tree
|leaf of ‘a
//the definition of the tree
let tree =
node(
node(
leaf "one",
node(leaf "two", leaf"three")),
node(leaf "four", leaf"five"),
leaf "six"))
// afunction to transform our tree into a tree of controls
let maptreetotreenode t=
let rec maptreetotreenodeinner t (node :treenode) =
match t
with
| node (l, r) ->
let newnode =
new treenode("node")
node.nodes.add(newnode) |> ignore
maptreetotreenodeinner l newnode
maptreetotreenodeinner r newnode
| leaf x ->
node.nodes.add(new
treenode(sprintf "%a" x)) |> ignore
let root =
new treenode("root")
maptreetotreenodeinner t root
root
//create the form object
let form =
let temp =
new form()
let treeview =
new treeview(dock =
dockstyle.fill)
treeview.nodes.add(maptreetotreenode tree)|> ignore
treeview.expandall()
temp.controls.add(treeview)
temp
application.run(form)
//form.show()
圖 8-3. 用 treeview 控件顯示樹
這段代碼大約隻有清單 8-1 (自己畫樹)的一半,還有更多的功能,因為,它可以折疊樹中你不感興趣的部分,這極大地改進了以可管理的方式顯示樹的大小。
在這個例子中,使用“停靠(dock)風格”控制控件的外觀。即,設定控件的 dock 屬性為一個 dockstyle 枚舉值。停靠的控件能更可能占用窗體上的可用空間,如果使用 dockstyle.left 屬性,控件就停在左邊;如果使用dockstyle.right,則停在右邊;dockstyle.top;則停在頂部;dockstyle.bottom,則停在底部;dockstyle.fill,則充填整個窗體。如果隻有幾個控件時,這非常好,因為它有很好的動态效果,當使用者調整大小的窗體時,控件的大小也将調整。然而,當有大量控件時會有問題,因為很難用這種方法将大量的控件完美地組合在一起。例如,如果有兩個控件都停在左邊,就很難确定到底哪一個停靠在最左邊,應該占用左邊多大的地方。當有大量控件時,更好的方法是要明确地用
top 和 left 屬性控制其布局。用 anchor 屬性可以建立動态效果,把控件錨定(anchor)在窗體的邊緣。下面的例子建立了一個有文本框的窗體,文本框的大小會随着窗體大小的改變而改變:
open system
// create a form
// create a text box and set its anchors
let textbox =
new textbox(top=8, left=8, multiline=true,
width=temp.width -30, height=temp.height-52,
anchor = (anchorstyles.left |||
anchorstyles.right |||
anchorstyles.top |||
anchorstyles.bottom))
// add the text box to the form and return the form
temp.controls.add(textbox)
[<stathread>]
do
[
與原文略有改變,現在文本框為多行模式。
]
然而,這種方法使用控件并不總是令人滿意的。這裡是隻顯示了一個控件,而通常在一個窗體上,會有十多個控件,甚至上百個。如果要寫出所有的控件建立、配置代碼,既單調,也容易出錯。為了解決這種問題,visual studio 提供了窗體設計器,可以可視化地建立窗體。
然而,到現在這止,還沒有針對 f# 的設計器,是以,下一節我們讨論f# 如何使用 c# 設計器建立的窗體。
對于 winform 的程式員,使用控件的一個困難在于,如何從衆多控件中進行選擇。在這一章中,我們隻讨論了一個控件。然而,說到學習,沒有什麼可以取代經驗。msdn 庫(http://msdn.microsoft.com)提供了一個很好的參考,但是,它的資訊量對于這些新主題也很難讓人滿意。是以,我把一些最有用的部分進行了彙總,列在表 8-3 中,有助于使用學習曲線變得平坦一些。
表 8-3 winform 常用控件及用法
控件
描述
label
顯示文本資訊。
通常,大多數其他控制應附帶 label,以說明其用途。在 label 的 text 屬性的文本中加 &,會使其後的一個字母有下劃線,通過按鍵可以跳到與此 label 相關(即 tab 序号的下一個)的控件,方法是按alt+<字母>。這極大地提高了應用程式的可用性。
textbox
用于輸入文本的框。
預設情況下文本框是單行,如果将 multiline 屬性設定為 true,可以支援多行;根據自己的喜好,也可以選擇 wordwrap 和 scrollbar 屬性;如果想讓文本框中顯示的文本可以複制、粘貼,可以通過設定 readonly 屬性實作。
maskedtextbox
這個控件與文本框有許多相似之處。
通過設定 mask 屬性,可以限制使用者輸入的資料。
button
按鈕控件,使用者可以單擊。
像 label 控件一樣,在按鈕的 text 屬性的文本中加 &,使其後的一個字母有下劃線,通過按鍵可以跳到此按鈕,方法是按 alt+<字母>。這極大地提高了應用程式的可用性。
linklabel
這個控件的名字有點誤導,它不像标簽,而更像按鈕,看起來像 html 連結。這個控件非常适合于網站環境,當單擊這個按鈕,打開頁面。
checkbox
。用于選擇一組不互斥的選擇項。
radiobutton
與 選擇框控件相似,但選擇項是互斥的。
放在同一個容器中的選擇項自動互斥。容器通常是窗體。
datetimepicker
從下拉的月曆中選取日期。
monthcalander
月曆。
combobox
,使用者可以從下拉清單中選擇。通過資料綁定顯示動态資料集(在第九章更細讨論)。
listbox
清單框,與組合框相似,隻是清單項顯示在窗體上,而不是在下拉清單中。如果窗體上有大量的空間可以用這個控件。
datagridview
資料網格視圖,雖然可以顯示任何表格資料,但是更适宜顯示資料庫表。應該用這個控件代替以前的 datagrid(到第九章會進一步讨論)。
treeview
樹視圖,這是另一個适合顯示動态資料的控件,最适合顯示樹形資料。
progressbar
進度條,對于長時間運作的任務,給使用者以回報是極其重要的。
richtextbox
顯示和編輯富文本,比标準的文本框有更多的格式。
webbrowser
顯示 html 文檔,因為很多資訊是以 html 格式提供的。
panel
把窗體分成不同的部分,配合 hscrollbar 和 vscrollbar 更有效。
hscrollbar
水準滾動條,使 form 或 panel 容納更多的資訊
vscrollbar
垂直滾動條,使 form 或 panel 容納更多的資訊
tabcontrol
帶頁籤的使用者控件