从 Zip/模块编程 Gambas
随着向程序添加更多功能,程序往往会变得很大。更多的菜单项意味着更多的菜单处理程序。更多的按钮、更多的列表、更多的表格——所有这些都意味着更多的子程序。需要一种方法来组织它们,并且确实存在。计算机中的文件被组织成文件夹。程序中的子程序被组织成模块和类。
模块就像容器。类就像各种物种的动物。
您可以将您喜欢的任何东西放入容器中。您可以收集所有以某种方式相关的子程序并将它们放入模块中。例如,您可以创建一个名为 Time 的模块,并将所有与时间和日期相关的程序部分放入其中。您可能会将您编写的用于计算出给定出生日期的某人年龄的出色函数放入其中。您称之为
Public Sub AgeThisYear(DOB as date) as string
有了它,您可以将该函数放入其中,该函数将您完成拼图所需的时间(以秒为单位)转换为分钟和秒格式
Public Sub TidyTime(Secs as integer) as string
它们可以放入 Time 模块中,以节省表单代码的混乱。即使没有这些函数,也会有足够多的事件处理程序来填充它。您无法将这些事件处理程序移动到模块中。它们必须位于表单代码中,等待表单上的某项操作以触发它们。
如何调用已放入模块中的子程序?您必须引用它们所在的模块以及子程序的名称。这就像一群人聚集在公园里。您可以喊出“约翰!”或“玛丽!”约翰或玛丽会走上前来。但是,一旦您开始将人们放入房屋中,就必须是“HollyCottage.John”或“FernyVale.Mary”。可能有多个约翰或玛丽,一方面。因此我们将引用
Time.AgeThisYear(“1/6/1955”)
和
Time.TidyTime(258)
模块中的任何内容在您的整个程序中都是可用的。模块就像盒子、文件夹或文件柜:只是您可以停放子程序的地方。要调用它们,请放入模块名称、句点,然后是子程序。
类,就像动物的种类。在动物世界中,物种被分组到属中,属被分组到科中,依此类推直到界(现在还有一个更高的层次,域),它曾经是动物或植物,但现在包括其他(原核生物,主要是细菌,原生生物,包括藻类和原生动物,以及真菌,包括蘑菇、霉菌和酵母菌)。每种动植物都有一个由属和种组成的两部分名称。“属”的意思是“一般”,“种”的意思是“特定”。我的名字是,比如,Luke Bilgewater。Bilgewater 家族中有很多不同的人,但只有一个 Luke Bilgewater。Luke 是特指名称,Bilgewater 是通称或泛称。分类系统如下所示
域 → 界 → 门 → 纲 → 目 → 科 → 属 → 种
您会注意到“纲”在那里。在编程中,类是可以有示例的事物。表格视图是一个类。您可以在程序中拥有多个表格视图。按钮是一个类。您可以拥有多个按钮。菜单是一个类。您可以拥有多个菜单。表单是一个类。您可以拥有多个表单。
您还可以从其他类派生类。
让我们以马为例。维基百科说:“目前,家养马和野马被认为是一个物种,马的有效科学名称是Equus ferus”。想象一匹长着翅膀的马。它将拥有普通马的所有特征(属性,如尾巴和蹄子),并且可以做普通马可以做的一切(方法,如奔跑和嘶鸣),并且可以对普通马会做出反应的事物做出反应(事件,如接近水槽或被装上马鞍)。然而,除了这些之外,它还将拥有翅膀。这个新类,Equus Pegasus,将继承Equus的所有东西,但也将有Public Sub Wings() … End 特定于这种特殊类型的Equus。
类(不像模块)可以拥有任意多个实际存在的示例。每个示例都将拥有自己的翅膀。每个都将拥有自己的名称。“创建一个这些动物种类的新示例”在编程语言中是“实例化”或“创建一个新实例”。
类是一个抽象事物(就像一种动物)。您需要类的实例才能拥有任何您可以处理的东西。
在说类定义就像蓝图一样,这是通常的情况。如果您想让类作为唯一的动物存在,您可以通过使其静态来做到这一点。Gambas 有静态类。它们是始终存在的类。模块是静态类:始终存在,并且您只有一个。
静态类的示例是Key。在联机帮助中,关于Key,它说:“此类用于获取有关键盘事件的信息,并包含表示键的常量。...此类是静态的。” 它始终存在;它是一次性事物;像引用野兽的名字一样引用它,而不仅仅是它的种类。因此刚刚键入的键是Key.Text,该键的数字代码是Key.Code。就像马肯定有腿一样,Key 有几个您可以引用的常量,比如Key.Enter 和Key.Return 和Key.Del 和Key.Esc,它们是这些键的代码号。并且就像马可以有马鞍或没有马鞍一样,存在属性Key.Shift 和Key.Control,它们可以是向上或向下,也就是说,true 或false。
让我们以表格视图为例,并赋予它翅膀。我们的新类将包含表格视图的所有功能,但额外增加了通过键入几个字母来定位行。它是我们的SearchBox 再次出现,只是这次我们将它做成一个类。然后我们可以创建任意多个新SearchBox。我们只需要设计新车的原型;之后,我们就可以从装配线上生产任意多的汽车。
文件菜单有两个条目,向下和退出。不要给向下设置键盘快捷键。(如果在单元格中键入,您可能会陷入无限循环——没有任何反应。)菜单项分别称为MenuGoingDown 和MenuQuit。
菜单项向下使用其复选框。如果选中,则通过键入来搜索名称将被关闭。Enter 将光标向下移动到下一个单元格,一如往常。如果未选中(程序以这种方式启动),请键入几个字母来定位某人的姓名,然后按 Enter 输入分数。然后再次按 Enter 离开单元格并准备好搜索下一个姓名。此处关键的表格视图属性是NoKeyboard。菜单项设置或取消设置它。
步骤
- 启动一个新的图形应用程序。
- 创建一个新类,将其设为导出并将其命名为“SearchBox”。(右键单击“源”文件夹 > 新建 > 类...)
- 在类的顶部输入行 INHERITS TableView。
- 按 F5 运行应用程序。立即退出程序。现在应该在类中有一个 SearchBox。将它拖到表单FMain 上。您刚刚创建了一个新实例。您可以剥离任意多个副本。目前,我们只需要一个。现在,我们教我们的马飞翔。这段代码位于 SearchBox 类中
Export 'Without this you will not see the class in the toolbar of classes
Inherits TableView
Private ss As String
Public SearchColumn As Integer
Event EnterOnLine
Public Sub CheckKey()
Select Case Key.Code
Case Key.Esc, Key.BackSpace, Key.Del
ss = ""
Me.UnSelectAll
Case Key.Enter, Key.Return
Raise EnterOnLine 'action on pressing Enter
ss = ""
Case Key.Tab
SearchDown
Case Key.BackTab
SearchUp
Case Else
ss &= Key.Text
SearchDown
End Select
End
Private Sub SearchUp()
Dim i, Start As Integer
If Me.Rows.Selection.Count = 0 Then Start = -1 Else Start = Me.Rows.Selection[0] 'the selected line
For i = Start - 1 DownTo 0
If InStr(LCase(Me[i, SearchColumn].text), LCase(ss)) Then
Me.Rows.Select(i)
Return
Endif
Next
For i = Me.Rows.max DownTo Start
If InStr(LCase(Me[i, SearchColumn].text), LCase(ss)) Then
Me.Rows.Select(i)
Return
Endif
Next
End
Private Sub SearchDown()
Dim i, Start As Integer
If Me.Rows.Selection.Count = 0 Then Start = -1 Else Start = Me.Rows.Selection[0]
For i = Start + 1 To Me.Rows.Max 'if no selected line, start at top, else start at next line
If InStr(LCase(Me[i, SearchColumn].text), LCase(ss)) > 0 Then
Me.Rows.Select(i)
Return
Endif
Next
For i = 0 To Start 'if no more occurrences, you will end up at the line you are on
If InStr(LCase(Me[i, SearchColumn].text), LCase(ss)) > 0 Then
Me.Rows.Select(i)
Return
Endif
Next
End
Public Sub HandleClick()
If Me.Column = SearchColumn Then Return 'searchable column is not editable by clicking
ss = ""
Me.Edit
End
上面的代码现在是所有 SearchBox 的一部分。它仍然必须在适当的时候被调用。如果没有,它永远不会完成。因此,以下是主表单FMain 的代码
Public Sub sb1_EnterOnLine()
sb1.Column = 1
sb1.Edit
End
Public Sub Form_Open()
Dim Names As New String[]
Dim i As Integer
Names = ["Mereka AIKE", "Ernest AIRI", "John AME", "Stanley ANTHONY", "Natasha AUA", "Veronica AUFA", "John Taylor BUNA", "Romrick CLEMENT", "Philomena GAVIA", "Richard GHAM", "Gerard BUZOLIC", "John HEARNE", "Thomas EDISON"]
sb1.Rows.Count = Names.count
sb1.Columns.Count = 2
For i = 0 To Names.Max
sb1[i, 0].text = Names[i]
If i Mod 2 = 0 Then
sb1[i, 0].Background = &hDDDDFF
sb1[i, 1].Background = &hDDDDFF
End If
Next
sb1.Columns[0].Width = 140 '-1 for max needed width
sb1.Mode = Select.Single
sb1.NoKeyboard = True 'start with sb1 selecting the line when Enter is pressed in a cell
sb1.Expand = True
sb1.SetFocus
End
Public Sub MenuQuit_Click() 'Yes, I put in a Quit menuitem in a File menu.
Quit
End
Public Sub sb1_KeyPress()
sb1.CheckKey()
End
Public Sub sb1_DblClick()
sb1.Edit 'to edit the names in the searchable column, double-click one of them
End
Public Sub sb1_Save(Row As Integer, Column As Integer, Value As String)
sb1[Row, Column].text = Value
End
Public Sub sb1_Click()
sb1.HandleClick
End
Public Sub MenuGoingDown_Click()
MenuGoingDown.Checked = Not MenuGoingDown.Checked
sb1.NoKeyboard = Not sb1.NoKeyboard
End
这匹马知道如何飞翔。此表格视图现在以著名的和高贵的SearchBox 之名而闻名,它知道如何搜索您键入的内容的出现。
当马在倾听时,您与它交谈。当 SearchBox 向您提供可以拦截的事件时,您与它交谈。我们特定的 SearchBox,sb1,向我们提供了表格视图的所有事件,以及更多。它有一个自制事件EnterOnLine。
如果您使用它理解的词语,马会按照您的指示做。当表单从搜索框中获取keypress 事件时,告诉它CheckKey。SearchBox 知道如何检查您的键。SearchBox 将乐意向上或向下扫描,以查找您键入内容的下一个出现位置。如果您对它呈现给您的选定行感到满意,它会通过EnterInLine 事件通知您。否则,它会将该键添加到您已经键入的字母字符串中,并进行更多搜索,从下一行开始。
EnterOnLine 在您键入的键被检查时被触发。如果您键入了Enter 或Return,则会发生EnterOnLine 事件。在主窗口中,您决定要对它做什么(如果有的话)。在我们的例子中,这意味着我们找到了我们想要的行,我们想在第二列中键入。
- 从某种意义上说,您通过事件与类对话,类通过它自己触发的事件与您对话。
您的类向您提供的自制事件可能就像简单的问候语(“你好!”)或传递参数(“你好,我 5 分钟后到那里!”)。我们的EnterOnLine 可能会告诉我们您按了Enter 的哪一行。然后事件定义将读取
Event EnterOnLine(LineNum as integer)
事件处理程序可能读取
Public Sub sb1_EnterOnLine(LinNum As Integer)
sb1.Row = LinNum
sb1.Column = 1
sb1.Edit
End
当一行被突出显示时,它的Row 属性被设置为该行,因此没有必要。比如,当您已经在该行时,为什么要发出移动到该行的命令?因此LinNum 参数不是必需的,但马通过它触发的事件与您对话,并且可以在向您发送EnterOnLine 事件时告诉您您在哪个行如果您想让它那样做。
如果在创建类的新的实例时需要做一些事情,例如设置表格视图中应该有多少行和列或列标题的名称,那么这样做的地方是在一个名为_new() 的特殊子程序中。每当使用New 运算符创建一个新类的示例时,都会调用此事件。
在上面的 SearchBox 程序中,我们可以将所有在Form_Open() 事件处理程序中完成的设置移动到类本身中。删除Form_Open() 事件,并将代码放在 SearchBox 类中。运行程序后,它将以完全相同的方式工作。
现在,类自行设置。该表单不需要单独设置每个元素。
Public Sub _new()
Dim Names As New String[]
Dim i As Integer
Names = ["Mereka AIKE", "Ernest AIRI", "John AME", "Stanley ANTHONY", "Natasha AUA", "Veronica AUFA", "John Taylor BUNA", "Romrick CLEMENT", "Philomena GAVIA", "Richard GHAM", "Gerard BUZOLIC", "John HEARNE", "Thomas EDISON"]
Me.Rows.Count = Names.count
Me.Columns.Count = 2
For i = 0 To Names.Max
Me[i, 0].text = Names[i]
If i Mod 2 = 0 Then
Me[i, 0].Background = &hDDDDFF
Me[i, 1].Background = &hDDDDFF
End If
Next
Me.Columns[0].Width = 140 '-1 for max needed width
Me.Mode = Select.Single
Me.NoKeyboard = True 'start with sb1 selecting the line when Enter is pressed in a cell
Me.Expand = True
Me.SetFocus
End