跳转到内容

从压缩包编程 Gambas/表单排列

来自 Wikibooks,开放世界中的开放书籍

使控件在表单调整大小后扩展

[编辑 | 编辑源代码]

GridView 和 TableView 通常在包含它们的窗口调整大小后进行拉伸和收缩。表单(即窗口)知道如何调整大小并排列其包含的控件。即使在表单打开时,任何可以排列和扩展的控件都会被扩展。

创建一个带有一个 TableView 的小型表单。

Gambas form with vertical arrangement Gambas form with vertical arrangement and panels, running


将表单的 *arrangement* 属性设置为 Vertical。将 tableview 的 *expand* 属性设置为 True。运行程序 (f5)。更改窗口大小,并注意 tableview 的大小如何随之变化。

将表单的 *padding* 属性调整为 8。再次运行程序 (F5)。TableView 和表单边缘之间的空间增加了。表单内部的边距即为填充。表格单元格也具有填充。

在 tableview 下方添加一个按钮。再次运行程序。将按钮移动到 tableview 的一侧。再次运行程序。将 arrangement 属性更改为 Horizontal 并再次尝试。将其更改回 Vertical。

删除按钮。添加一个 HBox。在 HBox 中添加一个按钮。(或者,右键单击按钮并选择“*嵌入到容器中*”,然后右键单击容器(它是一个面板)并*更改为...* HBox。)

HBox 中的控件水平排列。

弹簧将按钮尽可能地推到右边。尝试使用和不使用弹簧。

如果你使按钮变宽或变窄,它将保持你在 HBox 中给定的宽度。

按钮垂直扩展以从上到下填充 HBox。更改 HBox 的高度并观察。HBox 扩展其控件以填充其高度。在面板中,按钮保持相同的高度,但你不能使用弹簧。

用于平均学生成绩的电子表格

[编辑 | 编辑源代码]

Tall Gambas form to average student marks Gambas program to average student marks, running

*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 帮助

This suspicious character is known by an alias, as menus are.
这个可疑的字符有一个别名,就像菜单一样。

Methods and Events for Menus

你可以告诉菜单关闭、隐藏、弹出、显示或删除。

你可以告诉程序在单击菜单时、隐藏后或显示之前执行操作。通常,在单击菜单时,菜单就会开始工作。

Gambas Menu Properties

一些属性是布尔值(例如 *enabled*、*checked* 和 *visible*),另一些属性是字符串(例如 *text*、*name*)、图片(*picture*)或变体(即任何类型,*tag*)。

</syntaxhighlight>

从压缩包编程 Gambas
 ← 文本文件 表单排列 上下文菜单 → 
华夏公益教科书