写在前面
这是PB案例学习笔记系列文章的第二篇,该系列文章适合具有一定PB基础的读者,
通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。
文章中设计到的源码,小凡都上传到了gitee代码仓库https://gitee.com/xiezhr/pb-project-example.git

需要源代码的小伙伴们可以自行下载查看,后续文章涉及到的案例代码也都会提交到这个仓库【**pb-project-example**】
如果对小伙伴有所帮助,希望能给一个小星星⭐支持一下小凡。
一、小目标
掌握pb应用程序的创建、运行、中止等最基本操作。学会使用DropDownListBox控件、ListBox控件,以及
DirList 、SelectItem、DirSelect 、SetRedraw 等函数和SetPointer 系统函数使用。最终实现如下效果

二、 DropDownListBox控件
2.1 常用属性
| 属性 | 描述 | 
| AllowEdit  | 设置是否允许用户输入新的项目,默认为不允许 | 
| AutoHScroll | 设置当录入新项目或者删除数据时是否允许自动滚动编辑框,默认不允许 .下拉 列表框的宽度大于 Limit 规定的数值, 则没有必要设置该属性; 否则就应该设置该属性为 True
 | 
| Enabled | 设置是否允许进行选择,默认值是 True | 
| Limit   | 用来规定用户可以输入的字符的最大宽度, 0 表示没有限制,最大是 32 766 个, 默认是 0。
 | 
| ShowList   | 规定是否总显示下拉列表,当该属性为 True 时, PowerBuilder 自动将 AllowEdit 属性置为 True,并且此时列表框总显示,向下的小箭头取消。该属性默认为 False,通常情
 况下不将该属性置为 True
 | 
| Sorted   | 定义各个项目是否自动排序显示,默认为 False | 
| HScrollBar | 在需要时,是否显示水平滚动条 | 
| VScrollBar | 在需要时,是否显示垂直滚动条 | 
2.2  常用事件
| 事件 | 触发时机 | 
| SelectionChanged   | 默认事件,在重新选择了下拉列表中的项目时触发,参数 index 可以直接引用,是当前选中项目的索引号 | 
| Modified  | 在输入了新的项目后按下 Enter 或者 Tab 键而使下拉列表框失去焦点时 触发
 | 
2.3  常用函数
提供了 37 个函数,图形下拉列表框除此之外又增加了 3 个用户图形处理的函数  
2.3.1、**AddItem 函数**
①语法 
listbox.AddItem(String)
②功能
在列表框最后添加一个项目, 如果列表框的 Sorted 属性为 True, 添加的项目重新排序  
2.3.2、**DeleteItem   函数**
①语法
Lb.DeleteItem(index)  
返回值:
- -1 表示删除失败  
- Null 表示参数为 Null
- 正数,表示删除后列表框中的项目数  
② 功能
删除指定索引号的项目  
2.3.3、DirList 函数
① 语法
Lb.Dirlist(filespec,filetype,{statictext})
参数:
其中文件类型取值如下
| 文件类型-filetype | 描述 | 
| 0 | 可读写文件 | 
| 1 | 只读文件 | 
| 2 | 隐含文件 | 
| 4 | 系统文件 | 
| 16 | 子目录 | 
| 32 | 归档文件 | 
| 16 384 | 驱动器 | 
| 32 768 | 可读写文件以外的 | 
注:同时显示多种类型的文件,可以使用加号连接。例如同时要显示可读写、子目录、驱动器, 参数 filetype 可以使用表达式 0+16+16384
返回值:
- Null表示至少有一个参数为- Null
- True表示操作正确完成
- False表示列表框不能正确显示指定文件  (- ilespec不是一个目录  )
②功能
在列表框中显示指定类型的文件  
③ 例子
在 lb_1 列表框中显示目录“ c:\dos”下的后缀为txt 的所有可读写文件名称,并将路径名称“ c:\dos”显示在 statictext 控件 st_1 中  
lb_1.DirList("c:\dos\*.txt",0,st_1)
2.3.4、DirSelect函数
①语法
Listboxname.DirSelect ( selection )
返回值:
- Null表示至少有一个参数是- Null  
- True表示用户选择的是目录、驱动器
- False表示用户选择的是文件
② 功能
如果目前列表框中的内容是使用函数 Dirlist 获得的,该函数会将用户在列表框Listboxname 中选择的项目的内容保存在 String 类型变量 Selection 中;如果目前列表框中的内容不是使用 DirSelect 获得的,该函数返回的值不能正确反映实际的内容  
③ 例子
String ls_pathname
String ls_pattern
Ls_pattern = '*.txt'
If lb_1.DirSelect(ls_pathname) Then 
    lb_1.DirList(ls_pathname + ls_pattern,0) 
Else
End If
2.3.5、FindItem 函数
① 语法
listboxname.FindItem ( text, index )
返回:
- -1  表示没有找到或者发生错误  
- 有参数为 Null 时返回 Null  
- 正确执行并找到了匹配的项目则返回与之匹配的第一个项目的索引号  
②功能
在 listboxname 列表框中从索引号为index+1的项目开始搜索, 看是否有内容为text的项目。  
③ 例子
在 sle_1(单行文本输入框) 的 Modified 事件中,在 lb_1 查找所有和用户输入字符匹配的项目的索引号和内容  
Int li_pos,li_pri
li_pos = lb_1.FindItem(this.text,0)
li_pri = li_pos
Do
    MessageBox(String(li_pos),lb_1.text(li_pos))
    li_pri = li_pos
    li_pos = lb_1.FindItem(this.text,li_pos)
Loop Until li_pos <= li_pri
2.3.6、InsertItem 函数
① 语法
Lb_1.InsertItem(str,index)
参数:
返回值:
- -1 表示插入失败  
- Null 表示有参数为 Null  
- 正整数表示插入项目在列表框中最后的实际位置  
② 功能
在指定索引号前插入内容为 Item 的项目  
③ 例子
Lb_1.InsertItem(“倒数第二”,lb_1.TotalItems())  
Lb_1.InsertItem("倒数第二",lb_1.TotalItems())
2.3.7、Reset 函数
① 语法
listbox.Reset()
返回值:
② 功能
用来清除列表框中的所有项目  
2.3.8、SelectItem 函数
① 语法
listboxname.SelectItem ( item, index )
返回值:
- 如果正确执行并找到了匹配的项目,则返回匹配项目的索引号  
- 如果没有匹配的项目,则返回 0  
- 如果发生了错误则返回-1  
- 如果有参数为 Null,则返回 Null  
②功能
在不允许多选的 listboxname 列表框的索引号为 index 之后查找内容为 item 的项目,如果找到则选中该项目  
注: 该查找也是前面部分匹配,同函数 FindItem 的匹配相同。当列表框允许多选时,该函数不起作用,这时应该使用 FindItem 和 SetState 来实现该功能。函数 SetState 不影响已经选中行的状态。  
③ 例子
在 lb_1 列表框中选中内容为“ beautiful”的项目,能否正确执行都显示提示信息  
If lb_1.SelectItem("beautiful",0) > 0 Then
    MessageBox("提示", "正确选中了 beautiful")
Else
    MessageBox("提示","没有找到指定的项目")
End If
2.3.9、Text 函数
①语法
listbox.Text(index)
返回值:
index索引对应的item项目值
②功能
用来读取指定索引号的项目的内容  
2.3.10、TotalItems 函数
① 语法
listbox.TotalItems()  
返回值:
返回一个整型数值,表示列表框中总共有多少个项目  
注: 列表框的第一个项目的索引号是1,最后一个的索引号等于 listbox.TotalItems()  
②功能
该函数可以读取列表框中总共有多少个项目  
2.3.11、SelectedLength 函数
①语法
editname.SelectedLength ( )
返回值:
- -1 表示执行过程中发生了错误  
- 0 表示没有选中的项目  
- Null 表示 editname 为Null
- 其他正整数表示选中项目的字符数目    
② 功能
获取在 editname 中选中项目的字符数目,包括空格。
注:,该函数只有在下拉列表框选中项目并且没有失去焦点时,才能正确获得所选项目的字符数目,所以在很多的事件或控件中编程使用该函数都返回 0,因为这些事件触发时,下拉列表框失去了焦点,所以一般在下拉列表框的 SelectionChanged 事件中使用该函数。
另外,下拉列表框的 AllowEdit 属性必须为 True,才能正确执行该函数,否则该函数执行错误  
③ 例子
取消下拉列表框中选中的项目,可以在向下拉列表框添加初始数据时增加一个空值(“”),
选择空值即可表示取消选中项目。所以,在读取选中项目的内容时,首先判断选中字符的长度,如果不为 0 则继续处理,
否则表示取消选中,这时不做任何处理
If this.SelectedLength() > 0 Then
End If
2.3.12、SelectedText 函数
① 语法
editname.SelectedText ( )
返回值:
- 当有错误发生或者没有选中项目时返回空值(“”)  
- 当 editname 为 Null 返回 Null  
- 正确执行时返回选中项目的内容  
② 功能
返回 editname 中选中项目的内容。该函数在下拉列表框选中项目并且没有失去焦点时,可以正确返回选中项目的内容  
③ 例子
首先判断是否有选中项目,如果有就获取选中项目的内容并保存在变量中  
String ls_selected
If ddlb_1.SelectedLength() > 0 Then
    ls_selected = ddlb_1.SelectedText()
End If
2.3.13、SelectText 函数
① 语法
editname.SelectText ( start, length )
返回值:
- 返回选中的字符个数   
- 发生了错误则返回-1  
- 有参数为 Null 则返回Null  
② 功能
在 editname 的编辑框中,从第 start 字符开始选中 length 个字符。  
2.3.14、ReplaceText 函数啊
① 语法
editname.ReplaceText (string )
返回值:
- 返回 string 字符串的长度  
- 发生错误则返回-1  
- 有参数为 Null 则返回Null  
② 功能
在 editname 中用指定的字符串 string 来替换选中的字符  
③ 例子
本首先选中列表框 ddlb_1 中当前项目的第一个字符,然后替换成“ X”  
If ddlb_1.SelectText(1,1) > 0 Then
    ddlb_1.ReplaceText("X")
End If
三、 ListBox 控件
ListBox我们叫做列表框,可以逐条陈列出多条信息,当信息比较多时,可以使用滚动条
3.1 常用属性
ListBox 属性有35个,一般经常需要修改的有5个
| 属性 | 描述 | 
| Sorted | 指定列表框的内容是否排序,不管是数字还是字符都按字符处理,按照ASCII大小进行排序 | 
| VscrollBar   | 纵向滚动条 | 
| HscrollBar   | 横向滚动条 | 
| MultiSelect   | 表示是否可以选择多项 | 
| ExtendedSelect   | 多项进行同时选择,需要配合Ctrl或Shift键使用 | 
3.2 常用事件
这里只列举出该控件特有的事件,其他事件与上一篇文章介绍的【命令按钮】事件相同
| 事件 | 触发时机 | 
| SelectionChanged | 重新选择项目时,触发 | 
| DoubleClicked | 双击项目时触发 | 
3.3 常用函数
该控件总共有35个函数,常用的有14个
3.3.1 Reset 函数
① 语法
 listbox.Reset()
返回值:
② 功能
清除列表框中的所有项目  
3.3.2 AddItem 函数
① 语法
listbox.AddItem(String)
② 功能
列表框最后添加一个项目, 如果列表框的 Sorted 属性为 True, 则添加的项目重新排序  
注:Item[]是一个记录列表框项目的数组,通过指定索引号可以获取项目的内容,但使用 AddItem 函数不能修改该属性。  
3.3.3 TotalItems 函数
① 语法
listbox.TotalItems()
返回值:
一个整型数值,表示列表框中总共有多少个项目  
② 功能
读取列表框中总共有多少个项目  
注:列表框的第一个项目的索引号是1,最后一个的索引号等于listbox.TotalItems() 
3.3.4 State 函数
① 语法
listbox.State(index)
返回值:
- 1 表示指定索引号的项目是选中状态
- 0 表示指定索引号的项目没有被选中  
② 功能
用来判断指定索引号的项目是否选中  
3.3.5 Text 函数
① 语法
listbox.Text(index)
返回值:
返回一个String 类型的项目值
② 功能
用来读取指定索引号的项目的内容  
3.3.6 DeleteItem 函数
①语法
Lb.DeleteItem(index)
返回值:
- -1 表示删除失败  
- Null 表示参数为 Null  
- 其他正数值表示删除后列表框中的项目数。  
② 功能
删除指定索引号的项目  
3.3.7 InsertItem 函数
① 语法
Lb_1.InsertItem(str,index)
- str表示要插入的内容
- index表示插入项目的索引
返回值:
- -1 表示插入失败  
- Null 表示有参数为 Null  
- 其他正整数表示插入项目在列表框中最后的实际位置  
② 功能
在指定索引号前插入内容为 Item 的项目  
③ 例子
在 lb_1 列表框的倒数第二的位置插入一个内容为“倒数第二”的项目  
Lb_1.InsertItem("倒数第二",lb_1.TotalItems())
3.3.8 Dirlist 函数
① 语法
Lb.Dirlist(filespec,filetype,{statictext})
- filespec为要显示文件的路径及后缀
- statictext为窗口上的要显示路径的- statictext 控件名称
- filetype表示文件的类型  ,取值如下
| 文件类型 | 描述 | 
| 0 | 可读写文件 | 
| 1 | 只读文件 | 
| 2 | 隐藏文件 | 
| 4 | 系统文件 | 
| 16 | 子目录 | 
| 32 | 归档文件 | 
| 16 384 | 驱动器 | 
| 32 768 | 可读写文件以外的 | 
注:同时显示多种类型的文件,可以使用加号连接。例如同时要显示可读写、子目录、驱动器, 参数 filetype 可以使用表达式 0+16+16384
返回值:
- Null 表示至少有一个参数为 Null  
- True 表示操作正确完成  
- False 表示列表框不能正确显示指定文件  (当filespec不是一个目录  )
③ 例子
在 lb_1 列表框中显示目录“ c:\dos”下的后缀为txt 的所有可读写文件名称,并将路径名称“ c:\dos”显示在 statictext 控件 st_1 中  
lb_1.DirList("c:\dos\*.txt",0,st_1)
Lb_1.DirList("c:\dos\*.txt",0+16+16384,st_1)
3.3.9 DirSelect 函数
① 语法
Listboxname.DirSelect ( selection )
返回值:
- Null 表示至少有一个参数是 Null  
- True 表示用户选择的是目录、驱动器  
- False表示用户选择的是文件  
② 功能
如果目前列表框中的内容是使用函数 Dirlist 获得的,该函数会将用户在列表框Listboxname 中选择的项目的内容保存在 String 类型变量 Selection 中;
如果目前列表框中的内容不是使用 DirSelect 获得的,该函数返回的值不能正确反映实际的内容  
③ 例子
String ls_pathname
String ls_pattern
Ls_pattern = '*.txt'
If lb_1.DirSelect(ls_pathname) Then 
    lb_1.DirList(ls_pathname + ls_pattern,0) 
Else
End If
3.3.10 FindItem 函数
① 语法
listboxname.FindItem ( text, index )
- 没有找到或者发生错误则返回-1  
- 有参数为 Null 时返回 Null  
- 正确执行并找到了匹配的项目则返回与之匹配的第一个项目的索引号  
② 功能
在 listboxname 列表框中从索引号为 index+1 的项目开始搜索, 看是否有内容为 text的项目  
③ 例子
在 sle_1 的 Modified 事件中,在 lb_1 查找所有和用户输入字符匹配的项目的索引号和内容。  
Int li_pos,li_pri
li_pos = lb_1.FindItem(this.text,0)
    li_pri = li_pos
Do
    MessageBox(String(li_pos),lb_1.text(li_pos))
    li_pri = li_pos
    li_pos = lb_1.FindItem(this.text,li_pos)
Loop Until li_pos <= li_pri
3.3.11 SelectedIndex 函数
① 语法
listcontrolname.SelectedIndex ( )
返回值:
- 如果找到选中项目,则返回该第一个选中项目的索引号  
- 如果 listcontrolname为 Null 则返回 Null  
- 如果没有找到选中项目或者查找过程中发生了错误则返回-1  
② 功能
在 listcontrolname 列表框中查找第一个选中的项目  
③ 例子
如果列表框中有选中项目,则显示第一个选中项目的内容  
If lb_1.SelectedIndex() > 0 Then 
    MessageBox(“提示”,lb_1.Text(lb_1.SelectedIndex())) 
End If
3.3.12 SelectedItem 函数
① 语法
listboxname.SelectedItem ( )
返回值:
- 如果有选中项目,则返回选中项目的内容  
- 如果没有选中项目则返回空值””  
- 如果 listboxname 为 Null,则返回 Null  
② 功能
获取列表框 listboxname中选中项目的内容。通常在列表框不允许同时选中多行时
使用,当允许多行同时选中时,经常使用 state 和 text 函数来获取选中项目的内容  
③ 例子
下面程序在某按钮的单击事件中判断列表框 lb_1 中是否有选中项目,如果有,则
显示选中项目的内容,否则显示提示信息  
If Len(lb_1.SelectedItem()) > 0 Then
    MessageBox("提示",lb_1.SelectedItem())
Else
    Beep(2)
    MessageBox("提示","请首先选择! ")
End If
3.3.13 SelectItem 函数
① 语法
listboxname.SelectItem ( item, index )
返回值:
- 如果正确执行并找到了匹配的项目,则返回匹配项目的索引号  
- 如果没有匹配的项目,则返回 0  
- 如果发生了错误则返回-1  
- 如果有参数为 Null,则返回 Null  
②功能
在不允许多选的 listboxname 列表框的索引号为 index 之后查找内容为 item 的项目,
如果找到则选中该项目。注意,该查找也是前面部分匹配,同函数 FindItem 的匹配相同。当
列表框允许多选时,该函数不起作用,这时应该使用 FindItem 和 SetState 来实现该功能。函
数 SetState 不影响已经选中行的状态  
③ 例子
在 lb_1 列表框中选中内容为“ beautiful”的项目,能否正确执行都显示提示信息  
If lb_1.SelectItem("beautiful",0) > 0 Then
    MessageBox("提示", "正确选中了 beautiful")
Else
    MessageBox("提示","没有找到指定的项目")
End If
3.3.14 TotalSelected 函数
① 语法
listcontrolname.TotalSelected ( )
返回值:
-  正确执行时返回列表框中选中的项目数  
- 没有选中项目时返回 0  
- 执行错误时返回-1
- listcontrolname为- Null,则返回- Null  
② 功能
获取在 listcontrolname 列表框中选中的项目数。该函数只在列表框允许多选时起
作用,在不允许多选列表框中,即使有选中,项目也返回-1  
③ 例子
在某按钮的 Clicked 事件中,用来判断列表框是否允许多选,如果允许则使用函数 TotalSelected 显示选中的项目数,
如果不允许多选,则使用其他函数显示是否有选中项目  
If lb_1.MultiSelect or lb_1.ExtendedSelect Then
    If lb_1.TotalSelected() > 0 Then
        Messagebox("提示","该列表框允许同时选中多行,现有"&
        + String(lb_1.TotalSelected()) + "条数据选中!")
    Else
    Messagebox("提示","该列表框允许同时选中多行,没有选中的数据!")
    End If
Else
    If lb_1.SelectedIndex() > 0 Then
        MessageBox("提示","该列表框最多只允许选中一条,现有一条选中!")
    Else
        MessageBox("提示","该列表框最多只允许选中一条,现没有选中的数据!")
    End If
End If
四、搭建程序基本框架_
① 建立工作区
② 建立应用
③ 建立窗口
以上步骤忘记的小伙伴,可以参照第一篇文章创建
④ 添加控件
在窗口中建立一个DropDownListBox控件,两个ListBox控件以及一个CommandButton控件。布局如下图所示
各个控件名称为ddlb_disk、lb_filders 和lb_files

⑤ 保存窗口,将窗口命名为w_main
五、设置各个控件的外观属性
设置DropDownListBox控件和ListBox控件外观属性。勾选如下属性
Visible、Sorted、VScrollBar和Border四个属性
六、编写事件代码
这里只列举出常用函数的使用,如果想了解更多,可以参照上面小节函数多写代码实践
①在w_main 窗口的open  事件中编写如下代码
SetPointer(HourGlass!)
ddlb_disk.DirList("c:\*.*", 16384)
ddlb_disk.SelectItem("c", 0)
lb_folders.Dirlist("C:\*.*", 32768 + 16)
lb_files.Dirlist("C:\*.*", 39)
②在ddlb_disk控件的SelectionChanged事件中添加如下代码
string ls_disk
this.dirselect( ls_disk)
IF ls_disk <>""THEN
    SetPointer(HourGlass!)
    lb_folders.setredraw(false)
    lb_folders.dirlist(ls_disk,32768)
    lb_folders.DirList("*.*",32768 +16)
    lb_files.DirList("*.*",39)
end if
③ 在lb_folders控件的SelectionChanged事件中添加如下代码
String ls_dir
if this.DirSelect(ls_dir) then
    SetPointer(HourGlass!)
    this.DirList(ls_dir,32768+16)
    lb_files.dirlist("*.*",39)
 end if
七、运行程序

本期内容到这儿就结束了,希望对你有所帮助。我们下期再见 ヾ(•ω•`)o (●’◡’●)