PB从入坑到放弃(五)窗口使用技巧
PB
应用程序就是由许多共同协作完成特定任务的窗口组成的集合。
窗口在应用程序的开发工作中占有很大的比重,是非常重要的一个 PB
对象
一、窗口类型
窗口类型 | 描述 |
---|---|
Main |
①可以覆盖其他窗口,也可以被其他窗口覆盖 ②可以最大、最小化,可以用鼠标改变其 大小 ③可以有边框,可以有菜单 ④常用于应用主操作窗口 |
Child |
①可以被其他窗口覆盖,也可以覆盖其他窗口 ②可以最大或最小化,也可以用鼠标改变 其大小,父窗口最小或最大化时, Child 类型的窗口也相应的被最大或最小化 ③可以 有边框,但不能有菜单 ④位置是相对于其父窗口而言,用鼠标拖放其位置不能超过其 父窗口的范围 ⑤常被其他窗口打开 |
Response |
①不能最大、最小化,没有边框,不能用鼠标改变其大小 ②在继续执行程序之前,必须 对这种类型的窗口做出响应 ③常用于显示非常重要的信息 |
Popup |
①可以最大或最小化,在对这种类型的窗口响应之前,可以操作其他窗口 ②不随父窗口 最大和最小化 ③可以拥有菜单、边框 ④常用于显示其他窗口的辅助信息 |
二、窗口属性
-- General 属性页属性 | --Scroll 属性页属性 |
---|---|
-- ToolBar 属性页属性 | --Other 属性页 |
2.1 General 属性页属性
属性 | 简介 |
---|---|
Title |
窗口的标题 |
Tag |
和窗口相关的一个文本属性,可以理解成窗口的注释 |
MenuName |
和窗口相连的菜单 |
Visibl |
窗口是否可见 |
Enabled |
确定窗口的功能是否可用 |
TitleBar |
确定窗口是否有标题栏 |
ControlMenu, MaxBox, MinBox |
三个属性确定在窗口的标题栏是否显示最大、最小化以及关闭按钮 |
ClientEdge |
是否显示用户工作区边框 |
PaletteWindow |
该属性只用于 Popup 类型的窗口,确定是否显示标题栏图标和最大、最小化按钮 |
ContextHelp |
只用在 Response 类型的窗口上。确定是否支持上下文帮助。如果支持就在窗口的右上角显示一个问号图标 |
RightToLeft |
确定由右到左显示 |
Center |
窗口居中显示,不管屏幕分辨率如何设置。该属性在 PB 7.0 中没有,新增 |
Resizable |
决定窗口在运行时是否可以改变其大小 |
Border |
决定窗口是否有边框 |
WindowType |
确定窗口的类型,可用取值的含义,从字面意思可以理解。该属性在窗口打开时起作用 |
BackColor |
设置窗口的背景颜色 |
MdiClientColor |
用来确定 MDI 用户区的颜色 |
Icon |
用来设置窗口标题栏的图标 |
2.2 Scroll 属性页属性
属性 | 简介 |
---|---|
HscrollBar, VscrollBar |
是否需要显示水平或垂直滚动条 |
UnitsPerLine |
用户在垂直滚动条上每次单击移动的 PB单位数。默认为 0,表示每次 滚动窗口高度的 1/100 |
UnitsPerColumn |
用户在水平滚动条上每次单击向左或者向右移动的 PB单位数。默认为 0,表示每次滚动窗口宽度的 1/100 |
ColumnsPerPage |
表示每页显示的列数。默认为 0,表示显示 10 列 |
LinesPerPage |
表示每页显示的行数。默认为 0,表示显示 10 行 |
2.3 ToolBar 属性页属性
属性 | 简介 |
---|---|
ToolBarVisible |
工具条是否可见 |
ToolBarAlignment |
确定工具条在窗口上的初始位置。 有 5 个可用的枚举型取值: AlignAtBootom!(底部)、AlignAtLeft!(左)、 AlignAtRight!(右)、 AlignAtTop!(顶部)、 Floating!(浮动) |
ToolBarX, ToolBarY, ToolBa rHeight 和 ToolBarWidth |
用来设置当工具条浮动显示时工具条的起始位置及高宽。默认取值都是 0 |
2.4 Other 属性页中的属性
用来设置窗口的真实坐标、宽高和鼠标的默认指针。
当屏幕分辨率是 800 × 600 时,全屏显示的窗口 X, Y, Width 和 Height 分别是 0, 0, 3658, 2407。
三、11种常用控件
窗口可以看作是一个容器,所以在窗口上可以放各种控件,来完成用户与程序的交互
控件 | 说明 |
---|---|
Button |
用来执行特定的命令,接受用户的键盘或鼠标操作。 该控件的 Text 属性一般用来 向用户说明该按钮的功能。 典型事件是 Clicked |
Picture button |
和控件 Button 相同,只是在它的上面还可以显示图形,提供更漂亮友好的界面。 典型事件也是 Clicked |
Static text |
显示指示性或解释性信息,文字只能单行显示。 一般很少在该控件上编程 |
Singlelineedit |
单行编辑,一般用来接受用户比较少的文字输入。 典型事件是 Modified,通常在该 事件上判断用户的输入是否符合既定规则,如是否是数字等 |
Multilineedit |
多行编辑,用来接收用户比较多的文字输入。 典型事件也是 Modified,通常在该事 件上判断用户的输入是否符合既定规则 |
Check box |
复选框,用来界定用户的输入,一般输入信息作为其他命令执行时的选项。 当有多个复选框时,它们间的连接符习惯性认为是“ and”。 重要属性是 Checked,通常用来判断该控件是否选中 |
Radio box |
单选按钮,用来界定用户的输入只能是给定值中的一个。 它的输入信息通 常用来选择其他命令互斥的执行方式。 重要属性 是 Checked,true 表示选中 |
Dropdownlistbox |
以紧凑列表框的形式给用户显示信息,通常在该控件中进行单选。 经常和光标 ( cursor ) 配 合 使 用 , 显 示 从 数 据 库 中 提 取 的 数 据 。 典 型 事 件 是 SelectionChanged ,通常在该事件上读取当前用户的选择信息 |
Listbox |
列表框,是显示信息的,但其显示格式不如 Dropdownlistbox 紧凑,也通常和光 标(cursor)配合使用,显示从数据库中提取的数据。但是,该控件经常可以同时 选中多行。典型事件也是 SelectionChanged ,通常在该事件上读取当前用户的选 择信息 |
DataWindow |
是 PB中最重要的、也是 PB最具特色的一个控件。 可以 完成对数据库中的所有数据操作 |
Group box |
将功能类似的或在功能模块上关系紧密的部件放置在一起,界面美观,可以 给用户一个操作上的暗示。很少在该控件上编程 |
四、窗口事件
4.1 常用事件
事件 | 事件说明 |
---|---|
open |
在窗口打开之后,显示之前发生。 调整窗口大小、设置窗口实例变量、初始化一些控件 |
close |
窗口被关闭时发生。触发该事件后,没有办法阻止窗口的关闭 |
closequery |
在开始关闭窗口时发生,该事件返回一个0或1的返回值 如果返回值为1,则窗口不关闭,close事件也不会产生 如果返回值为0,则窗口被关闭 |
resize |
当窗口大小发生变化时变化,窗口被打开时也触发此事件 |
key |
当用户在键盘上按下一个键且插入点不在编辑区域时发生 |
activate |
在窗口成为活动窗口之前、 Open 事件触发完后触发 ,此事件发生后,Tab 值最小的对象得到焦点,如果没有 排序号,则窗口本身获得焦点 |
deactivate |
窗口变为不活动时发生 |
clicked |
户单击窗口的空白区域时发生,此区域不能有任何的空间或数据窗口 |
doubleclicked |
用户双击窗口的空白区域时发生,此区域不能有任何的空间或数据窗口 |
dragleave |
当可拖放对象或控件,离开空白区时发生 |
dragleave |
当可拖放对象或控件,在窗口中被拖动时发生 |
hotlinkalarm |
在动态数据交换(DDE)服务器应用发送了新的(修改后)的数据,且客 户DDE应用程序已经接收到数据时发生 |
mousedown |
空白区,单击鼠标左击时发生。 此事件与click事件相同,flags的值总为1 |
mousemove |
鼠标在窗口中移动时发生 |
mouseup |
放开鼠标左键时发生 |
rbuttondown |
空白区,按下鼠标右键时发生 |
remoteexec |
当一个DDE客户应用程序发送了一条命令时发生 |
remotehotlinkstart |
当一个DDE客户应用程序要开始一个热连接(hotlink)时发生 |
remotehotlinkstop |
当一个DDE客户应用程序要结束一个热链接时发生 |
remoterequest |
当一个DDE客户应用程序请求数据时发生 |
remotesend |
当一个DDE客户应用程序已经发送了数据时产生 |
systemkey |
当插入点不在编辑框中且用户按下【alt】或【alt+其他组合键时发生】 |
timer |
调用timer函数,启动定时器、设定时间后发生 |
toolbarmoved |
当MDI窗口中的工具栏被移动时发生 |
4.2 举个栗子
① open事件
Cb_Save.Enabled=False //禁用“保存”按钮的功能
SetPointer(HourGlass!) //将鼠标形状置为沙漏形
Dw_1.SetTransObject(SQLCA) //为数据窗口设置事务对象
Dw_1.Retrieve() //检索数据
② 避免用户因疏忽退出窗口而丢掉在数据窗口中的修改数据 ,通常在 CloseQuery
事件中判
断某些工作是否完成,并显示一个提示窗口询问用户,根据用户的确认,返回一个值来决定
是否触发窗口的 Close 事件。
返回值为 1,表示取消关闭动作;返回值为 0,表示继续执行Close 事件
Int li_flag
//如果数据窗口中没有修改,则允许执行 Close,直接返回
If dw_1.ModifiedCount() <= 0 And dw_1.DeletedCount() <= 0 Then Return 0
//如果数据窗口有修改,询问用户是否保存
li_flag = MessageBox("提示","数据已经修改,是否保存? ",Question!,YesNoCancel!,1)
Choose Case flag_i //根据用户选择执行
Case 1 //用户选择要保存数据
If dw_1.Update() = 1 Then //如果修改数据成功
Commit; //提交
Return 0 //继续执行 Close 事件
Else //修改数据不成功
rollback; //回退事务
li_flag = MessageBox("提示","数据错误,是否继续关闭!",Question!,YesNoCancel!,2) //显示错误
If li_flag = 1 Then
Return 0 //允许关闭
Else
Return 1 //不允许关闭
End If
End If
Case 2 //用户选择不保存数据
Rollback; //回退事务
Return 0 //允许执行 Close 事件
Case 3 //用户选择取消
Return 1 //不允许关闭
End Choose //用户所有的选择情况处理完毕
③ 在窗口的 Resize 事件中编写脚本,当用户调整窗口大小时,根据用户调整的
比例对窗口上的控件大小进行调整。首先定义两个实例变量用来保存调整之前的窗口大小
//open事件中代码
ii_width = This.width
ii_height = This.height
//Resize事件中代码
Int li_index //循环变量
DragObject lobj_every //用来获取窗口上的控件
For li_index = 1 To UpperBound(this.control[]) //对窗口中的所有控件逐一处理
lobj_every = control[li_index] //保存当前控件
lobj_every.x = lw_obj.x * (newwidth / ii_width) //重新设置 x 坐标
lobj_every.width = lobj_every.width * (newwidth / ii_width) //重新设置宽度
lobj_every.y = lobj_every.y * (newheight / ii_height) //重新设置 y 坐标
lobj_every.height = lobj_every.height * (newheight / ii_height) //重新设置高度
Next
ii_width = newwidth //保存当前宽度
ii_height = newheight //保存当前高度
五、窗口常用函数
5.1 open 函数
函数用来打开其他的窗口
① 语法
Open ( Windowvar)
② 参数
Windowvar
是一个Window
类型的参数,是要打开的窗口名称
③ 返回
- 成功时返回1,否则返回-1
- 数为 Null, 则返回 Null
④ 举个栗子
//打开主窗口
Open(w_main)
注:连续调用Open函数,窗口不会被打开两次,只是第二次调用时会再次触发窗口 Activate 事件。为了避免这种情况,可以将脚本修改如下
If Not IsValid(w_main) Then //如果窗口没有打开
Open(w_main) //则打开该窗口
Else //如果窗口已经打开
W_main.BringToTop = True //将该窗口显示在最顶层
End If
竟然open函数调用两次也不能打开两个窗口,那么问题来了,怎么才能打开多个窗口呢?代码如下
① 打开和 w_edit 完全相同的一个窗口
w_edit lws_edit //定义一个窗口变量
Open(lws_edit) //创建窗口实例
②通过数组,打开多个实例窗口
w_edit lws_edit[3]
Int li_index
For li_index =1 To 3
Open(lws_edit[li_index])
Next
5.2 close 函数
函数的作用是关闭窗口,释放窗口及其上面的控件所占用的内存空间,窗口的
CloseQuery
事件和Close
事件触发
① 语法
Close ( Windowname )
② 参数
Windowname
是要关闭的窗口名称,是一个Window
类型的变量- 成功返回 1,否则返回-1
- 参数为 Null,则返回 Null
5.3 MessageBox 函数
函数可以打开一个小信息窗口,不仅可以以多种方式给用户显示提示信息,还可以将用户的选择信息返回 。
小信息窗口有标题、提示信息、图标、按钮等 4 个元素,可以通过不同的参数来决定显示哪些或者显示哪种样式。
① 简单模式
只能显示提示信息,并有一个确认按钮,不能让用户进行选择
- 语法
MessageBox(title,text)
-
参数
- title 为信息窗口标题
- text 为提示信息
-
举个栗子
MessageBox(“错误提示” ,“数据保存错误! ” )
② 复杂模式
-
语法
MessageBox ( title, text {, icon {, button {, default } } } )
-
参数
- title 为信息窗口标题
- text 为提示信息
- icon 用来表示使用哪种图标
- button 用来表示提供哪些按钮
图标icon取值如下
按钮button取值如下
参数取值 | 显示样式 | 返回值 |
---|---|---|
OK! |
显示 【确定】 按钮,该取值为默认值 | 总返回 1 |
OKCancel! |
显示 【确定】 和 【取消】按钮 | 1-【确定】, 2-【取消】 |
YesNo! |
显示 【是】 和 【否】按钮 | 1-【是】, 2-【否】 |
YesNoCancel! |
显示 【是】、 【否】 和 【取消】 三个按钮 | 1-【是】, 2-【否】, 3-【取消】 |
RetryCancel! |
显示 【重试】 和 【取消】按钮 | 1-【重试】, 2-【取消】 |
AbortRetryIgnore! |
显示 【放弃】、 【重试】和 【忽略】三个按钮 | 1-【放弃】, 2-【重试】, 3-【忽略】 |
-
举个栗子
li_flag = MessageBox("提示","是否保存数据? ",Question!,YesNoCancel!,1) Choose Case li_flag Case 1 //用户选择 Yes,保存数据 . . . . . . //处理语句 Case 2 //用户选择 No,不保存 . . . . . . //处理语句 Case 3 //用户选择了 Cancel,不进行任何操作 . . . . . . //处理语句 End Choose
六、值传递与接收
6.1 字符串
① 打开一个窗口,并传递一个字符串
string ls_str
ls_str = '个人公众号:XiezhrSpace'
openwithparm( 窗口名,ls_str)
② 接收字符串
string ls_str
ls_str = message.stringparm
6.2 数值
① 打开一个窗口,并传递一个数值
openwithparm( 窗口名,1)
② 接收数值
long ll_row
ll_row = message.doubleparm
6.3 结构体
① 打开一个窗口,并传递一个结构体
st_parameter s_pm
s_pm.a = 1
openwithparm( 窗口名,s_pm)
② 接收结构体
st_parameter s_pm
s_pm = message.powerobjectparm
messagebox('提示',s_pm.a)
6.4 用户对象
① 打开一个窗口,并传递一个用户对象
//(1)、创建类用户对象u_parameter,并定义实例变量
//(2)、给用户对象赋值,并传递该用户对象
u_parameter u_pm
u_pm.a = '1'
openwithparm(窗口名,u_pm)
② 接收用户对象
u_parameter u_pm
u_pm = message.powerobjectparm
messagebox('提示',u_pm.a)
6.5 exe应用程序
① 打开一个exe,并传递参数
ls_exe = 'a.exe' + '|值1|' + '|值2|'
run(ls_exe)
② 接收exe传递的参数
string ls_parameter
ls_parameter = commandparm()
6.6 传递消息和接收消息
① 传递string消息
w_main.triggerevent('ue_open',0,'test')
//在用户自定义事件ue_open中接收消息:
string ls_msg
ls_msg = string(message.longparm,'address')
② 传递long消息
w_main.triggerevent('ue_open',100,0)
//在用户自定义事件ue_open中接收消息:
long ll_msg
ll_msg = message.wordparm
6.7 可视化类传值
u_customvisual u_cv
u_cv = create u_customvisual
openuserobjectwithparm(u_cv,1)
6.8 关闭窗口传递数据
① 语法
CloseWithReturn ( windowname, Returnvalue )
② 参数
windowname
是要关闭的窗口的名称Returnvalue
要返回的数值
注:只有被关闭的窗口是 response 类型才能有效地获取返回参数
七、触发事件
7.1 立即触发
obj.triggerevent(clicked!)
obj.trigger event ue_init()
obj.trigger function wf_init()
7.2 在事件队列最后触发
obj.postevent(clicked!)
obj.post event ue_init()
obj.post function wf_init()
7.3 动态绑定触发
obj.dynamic event ue_init()
obj.dynamic function wf_init()
注:
动态调用和静态调用的区别
静态调用就是在编译代码时就对函数进行彻底编译
动态调用就是在程序执行的时候才回去查找和调用相应的函数
7.4 规定的时间内触发某事件
idle(60) //如果60秒没有操作的话就触发application对象的idle事件
timer(60) //每隔60秒就触发一次窗口的timer事件
八、窗口使用技巧
8.1 创建窗口实例
① 创建窗口实例
w_edit lws_edit
Open(lws_edit)
② 打开多个窗口实例
w_edit lws_edit[3]
Int li_index
For li_index =1 To 3
Open(lws_edit[li_index])
Next
8.2 使用窗口属性编程
根据 tag 的取值对各个控件进行初始化
Int li_index,li_total
DataWindow ldw_temp
DropDownListbox lddlb_temp
RadioButton lrb_temp
li_total = Upperbound(Parent.Control[])
For li_index = 1 To li_total
Choose Case Lower(Parent.Control[li_index].Tag)
Case "DataWindow"
ldw_temp = Parent.Control[li_index]
ldw_temp.Reset()
Case "DropDownListbox"
lddlb_temp = Parent.Control[li_index]
lddlb_temp.SelectItem(0)
Case "radiobutton"
lrb_temp = Parent.Control[li_index]
lrb_temp.Checked = False
Case Else
…
End Choose
Next
8.3 窗口最小化时设置动态图标
当程序最小化时打开 timer(在 deactive 中加入 timer(1)语句),并在 timer 事件中编写
程序激活时关闭 Timer 事件(在 Active 事件中加入 timer(0)语句)
If This.Icon = "appico.ico" Then
This.Icon = "reverse.ico"
Else
This.Icon = "appico.ico"
End If
8.4 放置闪烁文字
以闪烁文字显示重要信息可以吸引用户的注意力,避免这些重要信息被忽略。通过周期性修改 visible 属性,可以实现闪烁效果
在窗口中,假设放置一个静态文本 st_1,在窗口的 Open 事件中定义 Timer 事件的间隔:Timer(1)
Timer 事件 中代码如下
If Mod(Second(Now()),2) = 1 Then
st_1.visible = False
Else
st_1.Visible = True
End If
8.5 提高窗口的打开速度
窗口的 Open 事件中经常编写脚本来进行初始处理工作,如果这些工作花费的时间比较长,在窗口显示之前用户就得等待很长的时间
这时,可以如下脚本优化
第一种方案:
① open
事件中添加代码
PostEvent("ue_openpost")
② ue_openpost
事件中添加代码
SetPoInter(HourGlass!)
dw_1.SetTransObject(SQLCA)
dw_1.Retrieve()
SetPoInter(Arrow!)
第二种方案:
open
事件中添加如下代码
dw_1.SetRedraw(False)
TriggerEvent("ue_openpost")
Dw_1.SetRedraw(True)
8.6 移动不带标题栏的窗口
在开发应用程序中,可能要用到不带标题栏的窗口,而带有标题栏的窗口可以通过拖放
标题栏来移动窗口,如何移动没有标题栏窗口呢?
在要拖放窗口的 MouseDown
事件中编写代码,代码如下
Send(handle(this),274,61458,0)
8.7 给窗口添加自动滚动条功能
窗口的 Resize 事件中编写脚本,根据当前窗口的大小来设置是否显示滚动条
① 声明函数
Subroutine GetScrollRange(Uint hWindow,Int nScrollBarFlag,ref Int nMin,ref Int nMax) Library "user.exe"
Function Int GetScrollPos(Uint hWindow,Int nScrollBarFlag) Library "user.exe"
② 定义实例变量
Int ii_width,ii_height
③ open
事件中添加代码
ii_width = This.Width
ii_height = This.Height
④ Resize
事件中实现
Uint hwindow
Int nScrollPos,nMinPos,nMaxPos
If This.WindowState = Minimized! Then //如果正在进行最小化,则直接返回
Return
End If
HWindow = Handle(This) //获取当前窗口的句柄
//下面开始处理水平滚动条
If This.Width < i_Width Then //如果小于打开时的宽度
This.HscrollBar = True //则显示水平滚动条
Elseif This.HscrollBar Then //如果大于或等于打开时的宽度,并且已经有滚动条
NScrollPos = GetScrollPos(hwindow,0) //使用 API 函数获取当前滚动条位置
GetScrollRange(hwindow,0,nMinPos,nMaxPos) //使用 API 函数获取滚动范围
If nScrollPos > nMinPos Then //如果用户滚动了滚动条并且此时不需要显示滚动条
Post(hwindow,276,6,0) //则在水平方向调整窗口中的内容到原来的位置
End If
This.HscrollBar = False //取消滚动条特性
End If
//下面开始处理垂直滚动条
If This.Height < i_Height Then //如果小于打开时的高度
This.VscrollBar = True //则显示垂直滚动条
Elseif This.VscrollBar Then //如果大于或等于打开时的高度,并且已经有滚动条
NScrollPos = GetScrollPos(hWindow,1) //使用 API 函数获取当前滚动条位置
GetScrollRange(hwindow,1,nMinpos,nMaxPos) //使用 API 函数获取滚动范围
If nScrollPos > nMinPos Then //如果用户滚动了垂直滚动条且不需再显示
Post(hwindow,277,6,0) //则垂直调整窗口中的内容到原来的位置
End If
This.VscrollBar = False //取消滚动条特性
End If
8.8 自动调整窗口
实现窗口居中
//***************************************************************
//* 功能: 将窗口移到屏幕的中央
//* 参数 1: aw_window 要处理的窗口
//* 返回值: (none)
//* 调用举例: gf_window_center(w_pay_mode) //将窗口置于屏幕的中央
//***************************************************************
Environment le_env
Int li_ScreenHeight, li_ScreenWidth
Long ll_posx,ll_posy
GetEnvironment(le_env)
li_ScreenHeight = PixelsToUnits(le_env.ScreenHeight,YPixelsToUnits!)
li_screenwidth = PixelsToUnits(le_env.ScreenWidth,XPixelsToUnits!)
If aw_window.width > li_ScreenWidth Then //如果窗口超宽
ll_posx = 1
Else
ll_posx = (li_ScreenWidth - aw_window.Width) / 2
End If
If aw_window.height > li_ScreenHeight Then //如果窗口超高
ll_posy = 1
Else
ll_posy = (li_ScreenHeight - aw_window.Height) / 2
End If
aw_window.Move(ll_posx ,ll_posy)
以上就是本期内容的全部,希望对你有所帮助。我们下期再见 (●'◡'●)