從壓縮包程式設計 Gambas/表單排列
GridView 和 TableView 通常在包含它們的視窗調整大小後進行拉伸和收縮。表單(即視窗)知道如何調整大小並排列其包含的控制元件。即使在表單開啟時,任何可以排列和擴充套件的控制元件都會被擴充套件。
建立一個帶有一個 TableView 的小型表單。
將表單的 *arrangement* 屬性設定為 Vertical。將 tableview 的 *expand* 屬性設定為 True。執行程式 (f5)。更改視窗大小,並注意 tableview 的大小如何隨之變化。
將表單的 *padding* 屬性調整為 8。再次執行程式 (F5)。TableView 和表單邊緣之間的空間增加了。表單內部的邊距即為填充。表格單元格也具有填充。
在 tableview 下方新增一個按鈕。再次執行程式。將按鈕移動到 tableview 的一側。再次執行程式。將 arrangement 屬性更改為 Horizontal 並再次嘗試。將其更改回 Vertical。
刪除按鈕。新增一個 HBox。在 HBox 中新增一個按鈕。(或者,右鍵單擊按鈕並選擇“*嵌入到容器中*”,然後右鍵單擊容器(它是一個面板)並*更改為...* HBox。)
HBox 中的控制元件水平排列。
彈簧將按鈕儘可能地推到右邊。嘗試使用和不使用彈簧。
如果你使按鈕變寬或變窄,它將保持你在 HBox 中給定的寬度。
按鈕垂直擴充套件以從上到下填充 HBox。更改 HBox 的高度並觀察。HBox 擴充套件其控制元件以填充其高度。在面板中,按鈕保持相同的高度,但你不能使用彈簧。
*tv1* 是一個 TableView。它的 *expand* 屬性設定為 True。
底部是一個 HBox。從左到右,裡面是一個標籤 *labC*、一個粗體標籤 *labAverage*、一個彈簧和一個名為 *bQuit* 的退出按鈕,其文字屬性為“退出”。
每輸入一個數字,就會重新計算平均值。空白單元格會被跳過。
*LabC* 顯示計數,*labAverage* 顯示平均值。
Public Names As New String[]
Public Scores As New Float[]
Public Sub bQuit_Click()
Quit
End
Public Sub Form_Open()
Names = ["Mereka AIKE", "Ernest AIRI", "John AME", "Stanley ANTHONY", "Natasha AUA", "Veronica AUFA", "John Taylor BUNA", "Romrick CLEMENT", "Philomena GAVIA", "Richard GHAM"]
tv1.Rows.Count = Names.count
Scores.Resize(Names.Count)
tv1.Columns.Count = 2
tv1.Columns[1].Alignment = Align.Right
End
Public Sub CalculateAverage()
Dim i, n As Integer
Dim t As Float
For i = 0 To Scores.Max
If Scores[i] = -1 Or IsNull(tv1[i, 1].text) Then Continue 'skip new but unfilled-in lines
n += 1 'number of scores
t += Scores[i] 'total
Next
If n = 0 Then Return
labC.Text = "N= " & n
labAverage.Text = "Avg= " & Format(t / n, "#0.00")
End
Public Sub tv1_Click()
If tv1.Column = 1 Then tv1.Edit 'numbers column is editable; Enter goes down
End
Public Sub tv1_Activate() 'double-clicked a cell
If tv1.Column = 0 Then tv1.Edit 'edit a name
End
Public Sub tv1_Save(Row As Integer, Column As Integer, Value As String)
tv1[Row, Column].text = Value
If Column = 1 Then
Scores[Row] = Value
CalculateAverage
Else
Names[Row] = Value
Endif
End
Public Sub tv1_Data(Row As Integer, Column As Integer)
If Column = 0 Then tv1[row, 0].text = Names[Row]
If Row Mod 2 = 0 Then tv1[Row, Column].Background = &hDDDDFF 'light blue
tv1.Columns[0].Width = -1 'Automatically set width based on contents
End
Public Sub tv1_Insert()
tv1.Rows.Count += 1
Scores.Add(-1)
Names.Add("")
tv1.MoveTo(tv1.Rows.max, 0)
tv1.Edit
End
一開始就建立了兩個公共陣列。*Names[]* 是一個學生姓名的列表。*Scores[]* 是他們的成績列表。它們匹配:第一個分數對應第一個姓名,第二個分數對應第二個姓名,依此類推。
*tv1_Data(Row As Integer, Column As Integer)* 事件在每次需要重繪單元格時觸發。它為你提供了 Row 和 Column。可以把它看作是繪製單元格。
*_DATA* 事件有一個特殊考慮因素:它不會繪製不需要繪製的單元格。這對於顯示大量行非常有用。如果有 100,000 行而你只顯示了 15 行,那麼只有這 15 行上的單元格才會觸發 *_DATA* 事件,而不是所有的十萬行。如果你使用 *_DATA* 事件將數字放入單元格,請注意!可能只有這 100,000 個單元格中的 15 個單元格中有資料。在這裡沒有問題,因為我們自己輸入數字,並且每次完成輸入一個新數字後,它都會在 *_SAVE* 事件中被放入單元格中。(*tv1[Row, Column].text = Valu**e**)。但是,當我們從資料庫中使用 **_***DATA* 事件放置值時,我們只會將資料放入我們看到的單元格中。然後我們必須記住對內部儲存的資料進行計算,而不是對單元格的顯示內容進行計算。為了養成良好的習慣,我使用 *DATA[ ]* 陣列來儲存分數,並在計算平均值時使用它。歸根結底是:*如果你確定所有資料都在單元格中,請使用它們;如果不是,請使用你確信有資料的地方。*
以下幾行建立了 TableView 的上下文選單,包含四個條目
Public Sub tv1_Menu()
Dim mn, su As Menu 'main menu and submenu
mn = New Menu(Me) 'brackets contain the parent, the main window
su = New Menu(mn) As "MenuCopyTable" 'submenu of mn; alias is MenuCopyTable
su.Text = "Copy table..." 'first submenu's text
su = New Menu(mn) As "MenuCopyNames"
su.Text = "Copy names..." 'second submenu's text
su = New Menu(mn) As "MenuDeleteRow"
su.Text = "Delete Row" 'third submenu's text
su = New Menu(mn) As "MenuRefresh"
su.Text = "Refresh" 'fourth submenu's text
mn.Popup
End
Public Sub MenuDeleteRow_Click()
Names.Remove(tv1.Row)
Scores.Remove(tv1.Row)
tv1.Rows.Remove(tv1.Row)
End
Public Sub MenuCopyTable_Click() 'clicked the Copy Table menu item
Dim z As String
For i As Integer = 0 To Names.Max
If Scores[i] = -1 Then Continue
z = If(IsNull(z), "", z & gb.NewLine) & Names[i] & gb.Tab & Scores[i]
Next
Clipboard.Copy(z)
Message("Table copied")
End
Public Sub MenuCopyNames_Click() 'clicked the Copy Names menu item
Dim z As String
For i As Integer = 0 To Names.Max
If IsNull(Names[i]) Then Continue
z = If(IsNull(z), "", z & gb.NewLine) & Names[i]
Next
Clipboard.Copy(z)
Message("Names copied")
End
Public Sub MenuRefresh_Click()
tv1.Clear 'clear the data
tv1.Rows.Count = Names.Count 'reset number of rows to match Names[ ]
For i As Integer = 0 To Names.Max
tv1[i, 0].Text = Names[i]
tv1[i, 1].Text = Scores[i]
If i Mod 2 = 0 Then
tv1[i, 0].Background = &hFFDDFF
tv1[i, 1].Background = &hFFDDFF
Endif
Next
End
*_Menu()* 事件屬於 *tv1*,即 TableView。當右鍵單擊該物件(以顯示選單)時,該事件就會觸發。*_Click()* 事件屬於 *TableviewMenu*。那是什麼?它是選單 *su* 所知的別名。別名讓人想起穿著黑色風衣的秘密人物,但它只是它所知的名稱。
**mn** 和 **su** 只在彈出選單的持續時間記憶體在,因為它們在 *_Menu()* 事件中。一旦你單擊彈出選單上的任何專案,該子程式就會結束,*mn* 和 *su* 就會消失。幸運的是,我們已經說過 *su* 也被稱為 *TableviewMenu*。選單本身,當它使用 *New* 建立時,就有了那個名字。因此,選單收到的任何點選都由 *TableviewMenu_Click()* 處理。
選單(無論是主選單、子選單還是選單項)都有多個事件、方法和屬性。有關詳細資訊,請檢視 Gambas 幫助

你可以告訴選單關閉、隱藏、彈出、顯示或刪除。
你可以告訴程式在單擊選單時、隱藏後或顯示之前執行操作。通常,在單擊選單時,選單就會開始工作。
一些屬性是布林值(例如 *enabled*、*checked* 和 *visible*),另一些屬性是字串(例如 *text*、*name*)、圖片(*picture*)或變體(即任何型別,*tag*)。
</syntaxhighlight>



