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)

以上就是本期内容的全部,希望对你有所帮助。我们下期再见 (●'◡'●)

热门相关:我的治愈系游戏   戏精老公今天作死没   金粉   上神来了   上神来了