`
阅读更多

这是刚毕业时在某一“大”公司使用PB6.5开发联通营帐系统时的笔记,虽然好久没有也许以后也不会再使用pb开发程序了,但这算是我使用过的唯一一个前端专业开发工具,把笔记记录下来,权当作纪念吧,^_^

//PB中标准调用sql语句
ls_sql = "select road_name from bb_data_wide_bus_temp_t where register_number = '" + ls_register_number + "'"
declare cur_get dynamic cursor for sqlsa ;
prepare sqlsa from :ls_sql ;
open dynamic cur_get;
fetch cur_get into :ls_value;
if sqlca.sqlcode <> 0 then
messagebox('操作信息','提取失败!',exclamation!)
end if
close cur_get;


//PB中标准循环调用sql语句
DECLARE cur_sql DYNAMIC CURSOR FOR SQLSA;
PREPARE SQLSA FROM :ls_sql;
OPEN DYNAMIC cur_sql;
do while sqlca.sqlcode = 0
FETCH cur_sql INTO :ls_register_number,:ls_complete_note;
ll_sqlcode = sqlca.sqlcode
if ll_sqlcode < 0 then
CLOSE cur_sql;
af_disconnect()
messagebox('错误提示','检索受理编号错误!',StopSign!)
return
elseif ll_sqlcode = 100 then
exit
end if
ddlb_register_number.additem(trim(ls_register_number + '|' + ls_complete_note))
loop
CLOSE cur_sql;


//窗口open事件通用脚本
//置窗口居中
af_center_window(this)
//连接数据库
af_connect()
//定义变量
dataWindowChild dwc
//获取城市代码下拉列表并取值
dw_city_code.getChild('city_code',dwc)
dwc.setTransObject(sqlca)
dwc.Retrieve(gs_citycode,gi_citylevel)
dw_city_code.setTransObject(sqlca)
dw_city_code.Retrieve()
dw_city_code.setItem(1,'city_code',dwc.getItemString(1,'city_code'))
is_city_code = dw_city_code.getItemString(dw_city_code.getRow(),'city_code')
//获取业务类型下拉列表并取值
dw_service_kind.getChild('service_kind',dwc)
dwc.setTransObject(sqlca)
dwc.Retrieve()
dw_service_kind.setTransObject(sqlca)
dw_service_kind.Retrieve()
dw_service_kind.setItem(1,'service_kind',10)
ii_service_kind = dw_service_kind.getItemNumber(dw_service_kind.getRow(),'service_kind')
//获取申请事项下拉列表并取值
dw_apply_event.getChild('apply_event',dwc)
dwc.setTransObject(sqlca)
dwc.Retrieve(ii_service_kind)
dw_apply_event.setTransObject(sqlca)
dw_apply_event.Retrieve()
dw_apply_event.setItem(1,'apply_event',dwc.getItemNumber(1,'apply_event'))
ii_apply_event = dw_apply_event.getItemNumber(dw_apply_event.getRow(),'apply_event')
//激发查询事件
cb_query.TriggerEvent(clicked!)
//断开数据库
af_disconnect()


//查询按钮通用脚本
//连接数据库
af_connect()
//定义变量
dataWindowChild dwc
//dw_1检索数据
dw_1.setTransObject(sqlca)
dw_1.Retrieve(ii_service_kind)
//dw_2检索数据
int li_row,li_row_temp
dw_2.getChild('action',dwc)
dwc.setTransObject(sqlca)
dwc.Retrieve(ii_service_kind)
dw_2.setRowFocusIndicator(hand!)
dw_2.setTransObject(sqlca)
li_row_temp = dw_2.Retrieve(ii_apply_event,ii_service_kind,is_city_code)
dw_2.scrollToRow(li_row_temp)
//如果未检索到数据插入一空行,有数据就过滤
string ls_filter
int li_action
if li_row_temp = 0 then
dw_2.insertRow(0)
else
for li_row = 1 to dw_2.rowCount()
li_action = dw_2.getItemNumber(li_row,'action')
ls_filter = ' action <> ' + string(li_action)
dw_1.setFilter(ls_filter)
dw_1.filter()
next
end if
//断开数据库
af_disconnect()


//增加按钮通用脚本
//变量定义
int li_step,li_action,li_auto_status,li_row
//确认选择要增加的记录
if dw_1.getSelectedRow(0) = 0 then
MessageBox('提示信息','请选择要添加的记录!',exclamation!)
return
end if
//取出要增加的信息
li_step = dw_2.getItemNumber(dw_2.getRow(),'step')
li_action = dw_1.getItemNumber(dw_1.getSelectedRow(0),'action')
li_auto_status = dw_1.getItemNumber(dw_1.getSelectedRow(0),'auto_status')
//添加信息
li_row = dw_2.insertRow(0)
dw_2.setItem(li_row,'step',li_step)
dw_2.setItem(li_row,'action',li_action)
dw_2.setItem(li_row,'auto_status',li_auto_status)
dw_2.scrollToRow(li_row)


//删除按钮通用脚本
//删除前先确认
IF dw_2.GetRow() = 0 THEN
MessageBox('提示信息','请选择要删除的记录!',exclamation!)
Return
ELSE
IF MessageBox("提示信息","确实要删除指定的记录?",Question!,YesNo!,2) = 2 THEN Return
dw_2.DeleteRow(dw_2.getRow())
END IF


//保存按钮通用脚本
//连接数据库
af_connect()
//定义变量
string ls_city_code,ls_error
int li_service_kind,li_apply_event,li_row,li_step
dataWindowChild dwc
//检测数据是否发生变化
dw_2.AcceptText()
IF dw_2.ModifiedCount() + dw_2.DeletedCount() = 0 THEN
MessageBox("操作提示","数据未发生变化,无需保存!",exclamation!)
return
END IF
//检测是否为空或零
dw_2.setSort('step a')
dw_2.sort()
FOR li_row = 1 TO dw_2.RowCount()
li_step = dw_2.GetItemNumber(li_row,'step')
IF IsNull(li_step) OR li_step = 0 THEN
MessageBox('操作提示','步骤不能为空或零,请重新输入!',exclamation!)
dw_2.setRow(li_row)
Return
END IF
NEXT
//保存
dw_2.SetTransObject(sqlca)
if dw_2.update() = 1 then
commit;
messagebox("提示信息","保存成功!")
dw_2.ScrollToRow(dw_2.RowCount())
else
ls_error = sqlca.sqlErrText
rollback;
messagebox("提示信息","保存失败!" + char(13) + ls_error,stopSign!)
return
end if
//断开数据库
af_disconnect()


//打印按钮通用脚本
if dw_1.rowCount() > 0 then
if PrintSetup() = -1 then
messagebox('提示信息','打印机设置出错!',Exclamation!)
return
else
if dw_1.print(true) = 1 then //显示可以取消打印的对话框
Messagebox('提示信息',"打印成功!")
else
Messagebox('提示信息',"打印失败!",stopSign!)
end if
end if
else
Messagebox('提示信息',"没有数据可以打印,请先查询数据!",exclamation!)
return
end if


//导出按钮通用脚本
if dw_1.rowcount() <= 0 then
messageBox('提示信息','没有数据可以导出,请先查询!',exclamation!)
return
end if
if dw_1.SaveAS('',text!,true) = 1 then
messageBox('提示信息','导出成功!')
end if


//导入按钮通用脚本
//变量定义
string ls_pathfile,ls_file,ls_title,ls_ext,ls_filter
int li_pos,li_fileid
long ll_buffer
//变量赋值
ls_title = "请选择数据文件"
ls_ext = "txt"
ls_filter = "文本文件(*.txt),*.txt,全部文件(*.*),*.*"
li_fileid = GetFileOpenName(ls_title,ls_pathfile,ls_file,ls_ext,ls_filter)
if(li_fileid = 0 or ls_file = "") then
return
end if
sle_file_name.text = ls_pathfile
cb_ok.enabled = true


//退出按钮通用脚本
close(parent) 或 closeWithReturn(parent,returnvalue)


//调用过程通用脚本
if dw_wp.rowcount() <= 0 then return
//变量定义
string ls_sql,ls_err_info
string ls_register_number,ls_accept_city,ls_department,ls_oper_person
integer li_err_code,li_apply_event
//变量赋值
ls_register_number = dw_wp.getitemstring(1,'register_number')
ls_accept_city = gs_citycode
li_apply_event = dw_wp.getitemnumber(1,'apply_event')
ls_department = gl_dealerid
ls_oper_person = gs_workerid
//连接数据库
af_connect()
//调用配号撤单过程
ls_sql = "execute bb_pstn_assign_no_repeal_p(?,?,?,?,?)"
declare proc_assign_no_repeal dynamic cursor for sqlsa ;
prepare sqlsa from :ls_sql ;
open dynamic proc_assign_no_repeal using :ls_register_number,:ls_accept_city,:li_apply_event,:ls_department,:ls_oper_person;
if sqlca.sqlcode = -1 then
ls_err_info = sqlca.sqlErrText
close proc_assign_no_repeal ;
Rollback;
Messagebox("错误信息1","执行异常!" + ls_err_info,stopSign!)
af_disconnect()
return
End if
fetch proc_assign_no_repeal into :li_err_code,:ls_err_info;
if li_err_code < 0 then
close proc_assign_no_repeal ;
Rollback;
Messagebox("错误信息2","执行异常!" + ls_err_info,stopSign!)
af_disconnect()
return
end if
close proc_assign_no_repeal ;
commit ;
//断开数据库
af_disconnect()
//撤单成功后打印工单
dw_wp.print()


//PB某些控件的中文显示问题
假如 PB 的 ListView 不能正常显示中文,则应该将ListView 的 FontCharSet 属性设置成其他类型。将
ListView 所在的对象 Export 成源码。在源码中找到ListView 定义部分,将 FontCharSet 属性该成
DefaultCharSet! 如果 PB 的其他控件也发生相应的现象时,同样调整一下它的FontCharSet 属性。一般
来说对于简体中文字体,在中文 WINDOWS 环境中应该设置成DefaultCharSet!。对显示中文有问题的控件
将它的 FontChatSet 属性强制设置成 DefaultCharSet! 应该没有问题。或者改变字体!!!


//PB6.5运行时动态连接库(Runtime Library)
PBVM60.DLL(PowerBuilder 虚拟机)(必需)
PBDWE60.DLL(DataWindow 引擎)(可选)
PBRTC60.DLL(Rich Text Control)(可选)
PBTRA60.DLL(DLL used for tracing db calls)(可选)
与所需连接的数据库的直连接口(Native Driver) 或 ODBC接口(ODBC Driver)
PBSYC60.DLL(连接Sybase 的直连接口)
PBO7360.DLL(连接Oracle7.3的直连接口)
所需连接的数据库的Client端(如Sybase的Open Client, Oracle 的SQL Net)
以上是Sybase公司的建议。
我的经验是,编译好的程序必须有pbdwe60.dll和pbvm60.dll才行。
另外,如果使用ODBC联结数据库则还需pbodb60.dll,如果使用的专用接口,则需对应数据库的DLL,
如Oracle7.3用PBO7360.DLL,Sybase用PBSYC60.DLL


//pb6.5升级到6.5.1后exe文件执行可能出现问题
重新拷贝SybaseShared下的pbvm60.dll(3.24M)代替未升级时pbvm60.dll(3.25M)就ok了!


//几个常用颜色
红:rgb(255,0,0) 醒目或改变作用
蓝:rgb(0,0,255) 注意作用
深绿:rgb(0,128,0) 提示作用


//SQL AnyWhere安装方法:
在安装PB65时的自定义安装中组件ODBC Databases Drives里的Sybase SQL anywhere 5.5.04 ,这只是
安装了PB组件的ODBC驱动程序,并未安装SQL ANYWHERE,如果你需要使用SQL Anywhere的管理工具,你
还得进行如下的操作:在正版PB6.5的第六张盘里,有一目录名是SQLANY5504,这里面就是SQL ANYWHERE
的安装盘了,运行SETUP即可。如果是盗版,那只好靠你自已去找了。 在安装目录下有一个SETUP.BMP,
上面有SQL ANHWERE字样。


//很多书上讲到FILE菜单中点CREATE DATABASE,怎么能让这个选项出来?
在pb第六张光碟(或使用D版第二张碟6sqlany5504),进入sqlany5504目录,安装sql anywhere 5.5,
默认安装路径为: C:Program FilesSybaseSQL Anywhere 5.0win32,安装完成以后,修改
autoexec.bat, 增加一行,用于将sqlanywhere的文件放到系统搜索路径中:
path %PATH%;C:Progra~1SybaseSQLAny~1.0win32
这样重新启动后,你就可以看到File菜单下多出了Create Database这一项。
特别说明:在...win32此目录下有一个很重要的文件,dbtl50t.dll,你可以做一个实验,进入
PB DataBase画板(不需要退出),然后切换到文件管理器中将dbtl50t.dll文件给改名,再切换回PB中,
点File菜单,你将会发现Create Database这一项又消失了。将dbtl50t.dll改名回来,回到PB中再点此
File菜单,一切又恢复正常。不过没有Create DataBase这一项都不是很重要,您还可以使用
Sybase Central来管理数据库,它才是Sql anywhere数据库的全面管理工具,可以建存贮过程,触发器。
(在"开始"->"程序"->"Sybase"->"Sql anywhere 5.0"下面,在硬盘中的执行文件名是scview.exe).

//不安装Oracle客户连接Oracle 8的方法
请将以下文件拷贝到运行文件所在目录
一、ODBC动态库 :
ctl3d32.dll msvcrt40.dll odbc16gt.dll odbc32.dll odbc32gt.dll odbccp32.dll odbccr32.dll odbcint.dll
二、建立EXTRA子目录,将MSVCRT.DLL文件拷贝到该子目录下
EXTRAMSVCRT.DLL
三、ORACLE动态库及配置文件
Tnsnames.ora CORE35O.DLL NASNSNT.DLL NAUNTSNT.DLL NCRNT.DLL Nlnt.dll NLSRTL32.DLL Nnfdnt.dll
NNFNNT.DLL NSNT.DLL NTNT.DLL NTTNT.DLL CIW32.DLL Ora73.dll OTRACE73.DLL Sqlnet.ora
Sqltnsnt.dll CORE35.DLL
四、PB动态库
pbvm70.dll pbdwe70.dll Pbo7370.dll PBO8470.DLL pbodb70.dll libjcc.dll


//不安装SQL7客户端,连接SQL7的方法:
只需要将SQL的DBNMPNTW.DLL、NTWDBLIB.DLL以及PB的PBVM60.DLL、PBDWE60.DLL拷贝到EXE文件所在目录
即可!


//设置对象的缺省属性
在用户界面的设计中,每添加一个对象如按钮,文本框等,PowerBuilder都会用缺省的字体,大小,颜色
等属性来定义对象。如果这不是我们所需要的属性,那么就需要逐个地去修改属性。可以通过将缺省的
属性修改为所需要的来简化这一操作。打开应用画笔,在属性中可以将缺省的字体,大小,颜色等属性
改成所需要的缺省属性。


//数据类型转换
数值类型之间的转换由系统自动完成,通常根据操作符转换到高一级精度参加运算.
数值类型精度优先级自高到低依次为:
double ← real ← decimal ← UnsignedLong,long ← UnsignedInteger
字符串到数值类型的转换函数:
integer(str),long(str),real(str),double(str),dec(str)
数值型到字符串的转换函数为:
string(number,format),number是任意一种数值类型,format指示转换后的格式,通常可以省略.


//代词
this:This代表窗口、用户对象、菜单、应用对象或控件本身,即代表正在为之编写事件处理程序的对象。
parent:Parent指当前控件所在的窗口。
ParentWindow:ParentWindow代表运行时菜单所在的窗口,该代词只能在菜单的事件处理程序中使用。
super:在编写控件或对象的子对象时,子对象中可以调用父对象的事件处理程序,程序中既可直接利用
父对象的名称调用它们,也可以使用Super代词来引用。例如,想调用父对象的Clicked事件处理程序时,
子对象中可以这样写: CALL Super::Clicked


//系统预定义的五个全局变量
sqlca,sqlda,sqlsa,error,message


//PowerBuilder中的颜色值和RGB值之间的关系如下:
color = R*256*256+G*256+B


//标准数据类型共有十四种
blob 二进制大对象,用于存储大量数据,例如图像、大文本等,如: blob{100} ib_test //长度100
boolean 布尔型,布尔型变量只有两个可能的值:TRUE或FALSE
char 或character,单个ASCII字符
date 日期,包括年(1000-3000)、月(01-12)、日(01-31)
datetime 日期及时间,仅用于访问数据库的DateTime型数据
dec 或decimal,带符号十进制数,最大18位精度,如: dec{2} ld_test //2位精度
double 带符号浮点数,15位有效数字
int 或integer,16位带符号整数
long 32位带符号整数
real 带符号浮点数,精度6位
string 字符串类型,用于存储任意的ASCII字符,长度为0到60,000(16位环境中),32位环境中长度
只受系统能力的限制。程序中直接写字符串时,用单引号(')或双引号(")将字符串括起来
缺省值空串("")
time 24小时制时间,包括小时(00~23)、分(00~59)、秒(00~59)以及秒的小数位(最多六位),
范围从00:00:00到23:59:59:999999
uint 或unsignedInteger,unsignedInt,16位无符号整数,范围从0到65535
ulong 或unsignedLong,32位无符号整数,范围从0到4,294,976,295
any 要想知道Any类型变量中保存数据的类型,可以使用函数ClassName()


//如何将照片存入数据库之中
定义一个Bolb 变量lb_file,将文件读到 lb_file,用 insertblob 或updateblob 就 OK 了


//变量的作用域
全局变量:在整个应用程序中都可访问,它的作用域是整个应用程序
实例变量:与对象相关联,只有在该对象的事件处理程序或函数中才能使用为该对象定义的实例变量。
实例变量在它所关联的对象被打开时创建,被关闭时消失
共享变量:是一种静态变量,这不仅意味着它所在的对象关闭后再次打开时共享变量依然保持对象关闭时
的值,而且还意味着同一个类多个实例中的同名共享变量保持相同的值
局部变量:在使用它的事件处理程序或函数中说明,其作用域仅限于说明它的程序段,在该程序段的任何
地方均可访问局部变量,但其它程序段都不能访问本程序段中的局部变量。运行程序后,进入
某个程序段时,系统自动为局部变量分配内存,退出程序段时,局部变量占用的内存被释放。


//exit,continue,return
1.exit(退出循环):
DO...LOOP和FOR...NEXT语句的循环体中,当我们想在中途退出循环时,EXIT语句后,程序的控制权
转至循环语句后的语句,在嵌套循环的情况下,EXIT语句退出当前层循环,而不是所有循环.
2.CONTINUE(继续循环):
在DO...LOOP和FOR...NEXT语句的循环体中,遇到CONTINUE语句后,将不执行CONTINUE语句后与循环结束
前的所有语句,而开始新一轮循环.
3.RETURN 语句:
返回控制给用户或调用函数的地方.(当希望终止应用程序的运行时,使用HALT语句),立即终止事件处理
程序或函数的执行,把控制返回到调用程序.当RETURN语句位于事件处理程序中且用户操作触发了该事件
处理程序后,执行到RETURN语句时,该语句立即终止事件处理程序的执行并等待用户的下次操作.当程序
中调用函数或事件处理程序时,执行到RETURN语句后,该语句立即终止事件处理程序或函数的执行,并把
控制返回到调用程序.
4.HALT {CLOSE} 语句:
HALT语句用于终止应用程序的运行.当HALT语句不带CLOSE选项时,该语句立即终止应用程序的运行;
当HALT语句带CLOSE选项时,执行到该语句后,应用程序先执行应用对象的Close事件处理程序,之后再
终止应用程序的运行.


//缓冲区
primary buffer,filter buffer,delete buffer,original buffer
当我们从数据库中读取数据时,所有数据会放在主要缓冲区(primary buffer),并且会复制一份放到原始
缓冲区(original buffer)内.在数据窗口中我们只能看到主要缓冲区(primary buffer)内的数据,任何
数据的处理也都是针对主要缓冲区的数据做处理.但是要记住,不管我们对缓冲区内的数据做任何处理,
除非我们运行update()这个函数,否则缓冲区内任何数据的改变,对于后端数据库是没有任何影响的.


//如何生成固定长度的前面加零的数字编号,例如:12生成"00012",1234生成"01234"。方法很简单:
String(ll_number, "00000")


//row表示行数,col表示字段名,val表示值
dw_1.setItem(row,'col',val)
dw_1.getItemX(row,'col') //读取单笔数据比点状表示法更快
dw_1.object.data //读取多笔数据函数表示法更快
dw_1.object.data[1]
dw_1.object.data[1,2]
dwc.object.data[1,1]
dw_1.object.data[1,1,2,2]
dw_1.object.col[1]
dw_1.object.col.current
dw_2.object.data = dw_1.object.data
dw_2.object.data = dw_1.object.data.select
//例子1(只用执行一次)
string ls_name[]
ls_name = dw_1.object.col.current //读取列col所有数据
//例子2(得执行dw_1.rowCount()次)
string ls_name[]
for li_row = dw_1.rowCount() to 1 step -1
ls_name[li_row] = dw_1.getItemString(li_row,'col')
next


//读取数据
retrieve()
>= 1 //实际从数据库中所读取的数据数目
= 0 //找不到任何符合条件的数据
= -1 //读取数据失败
//增加数据
dw_1.insertRow(row)
dw_1.insertRow(0) //增加到最后一笔
//删除数据:primary! => delete!
dw_1.deleteRow(row)
dw_1.deleteRow(0) //删除当前所有行数数据
//过滤数据:primary! => filter!
dw_1.setFilter('kind < 1000')
dw_1.filter()
//数据排序
dw_1.setSort('kind d')
dw_1.sort()
//数据清除
dw_1.reset() //将数据从所有的缓冲区中清除,但是对于数据库中的数据并不会有任何影响
//数据计算
dw_1.rowCount()
dw_1.filteredCount()
dw_1.deletedCount()
dw_1.modifiedCount() //计算所有行数状态为DataModified!或是NewModified!的总和
//数据状态
notModified!
dataModified!
new! //rows only
newModified! //rows only
//数据拷贝
dw_1.rowsCopy(startRow,endRow,sourceBuffer!,destDW,beforeRow,destBuffer!)
dw_1.RowsCopy(dw_1.GetRow(),dw_1.RowCount(),Primary!,dw_2,1,Primary!)
//数据移动
dw_1.rowsMove(startRow,endRow,sourceBuffer!,destDW,beforeRow,destBuffer!)
dw_1.RowsMove(1,dw_1.DeletedCount(),Delete!,dw_1,1,Primary!)
//数据滚动
dw_1.scrollToRow(row)
//dw参数
dwo.name
//describe()函数
ll_color = dw_1.describe('dataWindow.color') //ll_color = dw_1.dataWindow.color
ll_color = dw_1.describe('kind_t.color') //ll_color = dw_1.kind_t.color
//modify()函数
dw_1.modify("dataWindow.color='255'")
dw_1.modify("kind_t.color='255'")
dw_1.modify("kind_t.color='0~tif(kind>1000,255,0)'") //~t前面的0为默认值
//操作外部数据
fileExists()
fileRead()
fileLength()
fileClose()
fileSeek()
fileOpen()
fileWrite()
//将dbf格式的文件,或是以tab键区隔字段的文字文件,直接引入放在数据窗口缓冲区中
importFile(fileName,startRow,endRow,startCol,endCol,dwStartCol)


//如何将Grid型的datawindow改成Tabular型的
导出数据窗成 .srd 文件, 用记事本打开把 processing=1 改成 processing=0

//Yield()函数的作用
Yield()是一个不常用到的PowerBuilder函数。可是,在一个大的循环过程中,如果用户想在执行到一半时
通过单击按钮或菜单来退出的话,就一定要用到Yield()函数了,否则程序只会在执行完成整个循环后才会
响应按钮或菜单的Click事件。将Yield()函数放在循环体的中间。那么在循环执行的过程中发现有新的事
件消息在消息队列中就回立即去响应。


//sqlca.SQLCode
在利用Embedded SQL 的时候,每运行一次SQL指令就应该检查一次交易对象中的属性SQLCode,而不是等到
所有的SQL指令运行完毕后再去运行检查交易对象中的SQLCode属性.当我们使用数据窗口所提供的函数时,
要记住不要检查SQLCode来判断是否运行成功.而是要依照每一个函数运行后所返回的值来判断是否运行
成功.
update tab_test set col1 = 'test'
if sqlca.sqlCode = -1 then
rollback using sqlca;
if sqlca.sqlCode = -1 then
messageBox('错误','连接失败!')
end if
messageBox('错误','连接失败!')
else
commit using sqlca;
end if


//确保数据保存的成功
if dw_1.update() = -1 then
RollBack Using SQLCA;
MessageBox("警告!","数据保存失败!")
else
Commit Using SQLCA;
End if


//在PB中如何打开一个文件(如.txt,.doc),就像在资源管理器中双击打开文件一样?
答:可以通过API函数来实现。
在应用程序的Global External Functions中定义:
Function long ShellExecuteA(ulong hwnd, string lpOperation, string lpFile, & string
lpParameters, string lpDirectory, long nShowCmd) library "shell32.dll”
调用如下:
String ls_null
SetNull(ls_null)
ShellExecuteA(Handle(Parent), ls_null, "c:dochello.txt”, ls_null, ls_null, 1)


//插入一行后给了默认值但又没有对默认值进行修改时,CloseQuery事件不激发方法
long 1_Row
1_Row = dw_1,InsertRow(dw_1,GetRow())
dw_1.SetItem(1_Row,"discount_pct",0,10)
dw_1.SetItemStatus(1_Row,0,Primary!,New!)


//同一个数据窗口某列的值是根据另一列的值进行检索(放在DW的itemchanged事件中)
dataWindowChild dwc
if dwo.name = "vw_type_type1" then //省的字段名
s_type1 = data
this.getChild("vw_type_type2",dwc) //县的字段名
this.setItem(this.getRow(),"vw_type_type2","")
this.setItem(this.getRow(),"vw_type_type3","")
this.setItem(this.getRow(),"type",i_null)
s_sql = "Select distinct type2 From vw_type Where type1_code = " + "'" + s_type1 + "'" //动态生成SQL语句
dwc.setTransObject(sqlca)
dwc.SetSQLSelect(s_sql)
dwc.retrieve()
end if


//DW的DBError事件
string error_text
CHOOSE CASE sqlDBCode
case 1 error_text = '违反唯一索引!'
case 1400 error_text = '字段不能为空!'
case 1407 error_text = '字段不能为空!'
case 1401 error_text = '字段太长!'
case 1438 error_text = '数值大于列允许的最大精度!'
case 2291 error_text = '出现非法字段!'
case 1031 error_text = '权限不足!'
case 911 error_text = '注册名无效!' //权限专用
case 922 error_text = '特殊字符无效!' //权限专用
CASE 1017 error_text = '非法的用户名或口令,拒绝登录!'
CASE 12154 error_text = '不能分解服务名称!'
CASE 01005 error_text = '未给出口令或口令错误,拒绝登录!'
CASE 01935 error_text = '注册名项输入的名称为系统关键字,禁止作为注册名使用!'
CASE 540 error_text = '数据表或视图不存在!'
CASE 942 error_text = '数据表或视图不存在!'
CASE 903 error_text = '非法列名!'
CASE 1403 error_text = '未查找到符合条件的数据!'
CASE -3 error_text = '在您读入数据和存盘操作过程中,服务器中的数据已被别的用户或窗口改变,请重新读取数据后再试!'
CASE 6 error_text = '网络同数据库服务器的连接已经中断,请关闭应用程序然后重新打开.'
CASE 50 error_text = '网络同数据库服务器的连接已经中断,请关闭应用程序然后重新打开.'
case 1920 error_text = '用户名称与另外的用户或角色名称冲突'
case 988 error_text = '缺少口令或其非法!'
case 1918 error_text = '该ORACLE用户不存在!'
case 1940 error_text = '不能放弃一个当前被连接的操作员,即当前删除的操作员正在使用!'
CASE ELSE
if isnull(sqlca.sqlErrText) or sqlca.sqlErrText = '' then
error_text = '数据操作失败!'
else
error_text = sqlca.sqlErrText
end if
END CHOOSE
return MessageBox('错误',error_text,RetrYCancel!,1)
//DBError参数
Buffer 发生错误所在的缓冲区
Row 发生第一笔错误的行数
SqlDBCode 数据库错误代码
SqlErrText 数据库错误信息


//MessageBox(title,text,icon,button,default)
icon参数:
information! 提示(缺省)
stopSign! 中止
exclamation! 警告
question! 询问
none! 没有
button参数:
ok! 确定(缺省)
okCancel! 确定,取消
yesNo! 是,否
yesNoCancel! 是,否,取消
retryCancel! 重试,取消
abortRetryIgnore! 终止,重试,忽略


//如何在DBError event中处理多笔数据的错误
Rollback Using SQLCA;
If buffer = primary! Then
Messagebox("error in row:" + string(row),"Code:" + string(sqldbcode) + "," + sqlerrtext)
This.scrollToRow(row)
return 1 //避免显示PB缺省的错误信息
end if


//数据窗口的规则检查
当用户在编辑控件中输入数据时,数据并不会立即写入数据窗口的缓冲区中,直到发生下面任何一种情况,
PowerBuilder才会把数据从编辑控件写入数据窗口的缓冲区中.
1.用户按下Enter键
2.用户按下Tab键跳到下一个字段
3.用户按下鼠标键跳到其它字段
4.运行AcceptText()函数
在完全通过4个步骤的规则检查后,才会真正把数据从编辑控件写入数据窗口缓冲区.任何一个步骤的错误
都会产生数据窗口的ItemError Event.数据窗口的数据规则检查步骤如下:
1.数据是否改变?
2.数据类型是否符合?
3.是否符合用户自定字段规则?
4.是否符合ItemChanged Event的程序?


//编辑控件函数
AcceptText():将编辑控件中的数据写入数据窗口缓冲区中.
不要在Itemchanged或ItemError event中编写Acceptext()函数,因为Acceptext()函数有可能驱动
ItemChanged或ItemError event,这将造成死循环的出现.
GetText():读取编辑控件的文字.


//每一个事件event和函数Function类似,会有参数argument和返回值return value.
ItemChanged Event返回值:
0.接受数据的值(缺省)
1.拒绝数据的值
2.拒绝数据的值并改变焦点
ItemError Event返回值:
0.拒绝数据的值,并且显示系统错误信息(缺省)
1.拒绝数据的值,但是不显示系统错误信息
2.接受数据的值
3.拒绝数据的值并改变焦点


//dw的update属性
Where 条件子句的产生方式:
1. Key Columns:比较原始数据缓冲区和当前数据库的数据时所产生的where子句条件不够严谨,所以在同
一个时间内,当很多的用户在一起使用数据库时有可能会发生将别人所更改过的数据覆盖的情况.为了
避免这样的情况发生,通常我们会将KeyColumns的方式用在单一用户或是关系表格中,所有的字段都是
Primary Key的情况.
2.Key and Updateable Columns:因为在比较原始数据缓冲区内的数据和当前数据库的数据时所产生的
where条件子句非常的严谨,所以在同一个时间内,当很多的用户一起使用数据库时,不会发生将别人所
更改过的数据覆盖的情况.因此,我们可以得到数据保存时最大的一致性.
3.Key and Modified Columns:因为在比较数据缓冲区内的数据与当前数据库的数据时所产生的where子句
条件比较有弹性(当前所要修改Modified的字段的数值),所以在同一个时间内,当很多用户一起使用数据
库时,可能会发生将别人所更改过的数据覆盖的情况.
主要字段(Key Column)的修改的方式:
1.Use Delete then Insert:这是数据窗口在主要字段(Key Column)的修改时的缺省选项,选用这种方式
修改数据时,数据会先被删除然后再重新增加一笔数据.但是在使用上要特别注意的是,如果在关系
数据库中,当设计删除为Cascade Delete时,在修改数据时候可能会导致其它不希望删除的数据被删除.
另外,在选择字段时必须要选择所有的字段,否则会没有办法再重增加一笔数据.
2.Use Update:这个选项会直接修改Key字段的数值,但是并不是所有的关系数据库(DBMS)都提供这样的
功能.


//动态数据窗口
数据窗口对象语法:
ls_syntax = sqlca.syntaxFromSql('select kind,name from tab_t','style(type=tabular)',ls_err1)
dw_1.create(ls_syntax,ls_err2)
dw_1.setTransObject(sqlca)
dw_1.retrieve()


//读取多行数据
1. 用DECLARE说明游标;(后无须检查SQLCode属性,要使用分号结束该语句。)
2. 用OPEN语句打开游标;
3. 使用FETCH语句读取一行数据;
4. 处理数据;
5. 判断是否已经读完所有数据,未读完时重复执行3~5步;
6. 使用CLOSE语句关闭游标。
int Emp_num
string Emp_name
DECLARE Emp_cur CURSOR FOR
SELECT employee.emp_number, employee.emp_name FROM employee;
open emp_cur;
FETCH Emp_cur INTO :Emp_num, :Emp_name ;
if sqlca.sqlcode = -1 then
rollback;
messagebox('','')
return
end if
CLOSE Emp_cursor;


//动态SQL(有四种类型)
//1.既无输入参数、也无结果集
string Mysql
Mysql = "CREATE TABLE Employee "&
+"(emp_id integer not null,"&
+"dept_id integer not null,"&
+"emp_fname char(10) not null,"&
+"emp_lname char(20) not null)"
EXECUTE IMMEDIATE :Mysql USING SQLCA;
//2.有输入参数、但没有结果集
int Emp_id_var = 56
PREPARE SQLSA FROM "DELETE FROM employee WHERE emp_id=?" ;
EXECUTE SQLSA USING :Emp_id_var ;
//3.编译时已经知道参数和结果集的列(游标或存储过程)
int Emp_id_var
String Emp_state_var = "北京",Sqlstatement
Sqlstatament = "SELECT emp_id FROM employee WHERE emp_state = ?"
DECLARE my_cursor DYNAMIC CURSOR FOR SQLSA;
PREPARE SQLSA FROM :Sqlstatement;
OPEN DYNAMIC my_cursor using :Emp_state_var;
FETCH my_cursor INTO :Emp_id_var;
if sqlca.sqlcode = -1 then
rollback;
messagebox('','')
return
end if
CLOSE my_cursor;
//或
int Emp_id_var
String Emp_state_var = "北京",proc,ls_error,ls_prompt
proc = "execute bb_pstn_complete_wp_p(?)"
DECLARE my_cursor DYNAMIC CURSOR FOR SQLSA;
PREPARE SQLSA FROM :proc;
OPEN DYNAMIC my_cursor using :Emp_state_var;
if sqlca.sqlcode = -1 then
ls_error = sqlca.sqlErrText
rollback;
MessageBox('提示信息','过程执行失败!' + char(13) + ls_error)
end if
FETCH my_cursor INTO :Emp_id_var;
if li_flag = -1 then
rollback;
MessageBox('提示信息','过程执行失败!' + char(13) + ls_prompt)
end if
CLOSE my_cursor;
//4.开发程序时尚不知道参数和结果集
string Stringvar, Sqlstatement
int Intvar
Sqlstatement = "SELECT emp_id FROM employee"
PREPARE SQLSA FROM :Sqlstatement ;
DESCRIBE SQLSA INTO SQLDA ;
DECLARE my_cursor DYNAMIC CURSOR FOR SQLSA ;
OPEN DYNAMIC my_cursor USING DESCRIPTOR SQLDA ;
FETCH my_cursor USING DESCRIPTOR SQLDA ;
//当FETCH语句执行成功时,动态描述区SQLDA中包含了结果集的第一行数据,反复执行FETCH语句即可得到
//其余数据。SQLDA.NumOutputs中包含了输出参数的个数。SQLDA.OutParmType数组中包含了各参数的数据
//例如TypeInteger!, 或 TypeString!等,使用CHOOSE CASE语句针对不同的输出参数类型调用不同的对象
//函数得到相应参数的值。
CHOOSE CASE SQLDA.OutParmType[1]
CASE TypeString!
Stringvar = GetDynamicString(SQLDA, 1)
CASE TypeInteger!
Intvar = GetDynamicNumber(SQLDA, 1)
END CHOOSE
CLOSE my_cursor;
//除DECLARE语句外,其它语句执行后都应该检查事务对象的SQLCode属性,以判断当前SQL语句的执行是否
//成功。


//得到下拉数据窗口中的显示值
ls_value = dw_1.Describe("Evaluate('LookupDisplay(column_name)',"+string(row_number)+")")

//固定数据窗口前几列的方法,例如第一列名为“id”,固定该列且后半部分从下一列开始显示:
dw_1.HSplitScroll = True
dw_1.Object.DataWindow.HorizontalScrollSplit = dw_1.object.id.Width
dw_1.Object.DataWindow.HorizontalScrollPosition2 = dw_1.object.id.Width


//打印数据窗口最后一页的方法:
string ls_pagecount
ls_PageCount = dw_1.describe("Evaluate('PageCount()',0)")
dw_1.object.datawindow.print.page.range = '" + ls_PageCount + "'"
dw_1.print()


//当编辑框得到焦点时自动选中内容:
this.selecttext(1,len(sle_1.text))


//判断数据窗口中是否存在某列
可以利用Describe("column_name.width")是否为"!"来判断;


//隐藏任务栏的方法,在OnCreate事件里利用Window API函数SetWindowLong:SetWindowLong(Application.Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);
PB使用时首先声明函数FUNCTION long SetWindowLong(ulong hWnd, integer nIndex, ulong dwNewLong) library "user32.dll" ALIAS FOR "SetWindowLongA",
然后调用:SetWindowLong(Handle(this),-20,128);


//如果大于本月23号,则将时间设置为下月1号,否则取当前时间
//方法1:
if day(today())>23 then
if month(today())+1>12 then
this.text=left(string(today(),'yyyy-mm-dd'),5)+'01-01'
else
this.text=string(date(year(today()),month(today())+1,1))
end if
else
this.text=string(today())
end if
//方法2:
dateld_temp = today()
if day(ld_temp) > 23 then ld_temp = date(year(RelativeDate(ld_temp, 10)), month(RelativeDate(ld_temp, 10)), 1)
sle_1.text = string(ld_temp)


//两个有用的PB内部函数
1.shRunDefltBrowser 调用缺省的浏览器,打开指定页面
版本:PBVM60.dll,PBVM80.dll,PB7我没用过,不过我想应该有。
函数声明:function long shRunDefltBrowser(string szUrl) library "pbvm60.dll"
调用方法:shRunDefltBrowser("www.pdriver.com")
2 shCenterWindow 将窗口位于屏幕中央
版本:PBVM60.dll,PBVM80.dll,PB7我没用过,不过我想应该有。
函数声明:function long shCenterWindow(long hWnd) library "pbvm60.dll"
调用方法:shCenterWindow(handle(w_about))

//允许用户修改新增加的记录,而检索出来的记录则不允许修改。
打开列的属性中的Expressions,在protect中输入条件判别式:
if(isRowNew(),0,1)


//使用Ole对象与Word等通讯时,如何避免启动多个Word等程序:
OLEObject ole_object
ole_object = CREATE OLEObject
li_ret = ole_object.ConnectToObject("","word.application")
IF li_ret <> 0 THEN
//如果Word还没有打开,则新建。
li_ret = ole_object.ConnectToNewObject("word.application")
if li_ret <> 0 then
MessageBox('OLE错误','OLE无法连接!错误号:' + string(li_ret))
return
end if
ole_object.visible = true
END IF


//进展条的使用
在PowerBuilder中虽然没有这样的控件,可是在PowerBuilder所带的例子中有一用户对象
uo_progress_bar能够完成所需要求。将用户对象拷贝到用户的应用所在的库,将它放置在用户的界面中
需要出现的地方。然后在任务进展的时候,用对象的uf_set_position()函数指示当前任务的进展情况。


//在PB中调用屏幕保护的方法:
send(handle(This),274,61760,0)


//得到一个应用程序如Outlook的路径
RegistryGet("HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionApp PathsMSIMN.EXE", &
"Path",ls_outlook_path)
//Outlook的路径将保存在string型变量ls_outlook_path中。


//得到程序运行时的路径
//在global external functions声明:
Function uLong GetModuleFileNameA(long hinstModule, Ref String lpszPath, uLong cchPath) Library ″kernel32.dll″
//程序路径保存在变量ls_AppPath中
string ls_AppPath
int li_ret
ls_AppPath = Space(128)
li_ret = GetModuleFileNameA(Handle(GetApplication()),ls_apppath,128)
//要编译成可执行文件.exe才可用,否则得到的是Powerbuilder的pb60.exe或PB050.exe的路径。


//在程序中动态设定列的编辑风格为下拉数据窗口(DropDownDataWindow)
//假设所设定列为部门号"department_id",相关连的子数据窗口为"d_dddw_dep",
//显示列为部门名称"dept_name",数据列为部门号"dept_id",实现方法如下:
dw_1.Modify("department_id.DDDW.Name=d_dddw_dep ")
dw_1.Modify("department_id.DDDW.DisplayColumn='dept_name' ")
dw_1.Modify("department_id.DDDW.DataColumn='dept_id' ")
//或:
dw_1.object.department_id.dddw.name = "d_dddw_dep"
dw_1.object.department_id.DDDW.DisplayColumn = "dept_name"
dw_1.object.department_id.DDDW.DataColumn = "dept_id"
//注:PowerBuilder有一个小工具DWSyntax(程序名为:dwsyn60.exe),提供了获得及修改数据窗口、
//列等的各项属性值的语法,对编程非常有帮助。上述脚本在DWSyntax中都能找到。


//增量查询功能实现
//1.定义单行编辑器的用户事件ue_enchange,事件的ID为:pbm_enchange。这个事件能响应键盘的输入。
//2.在单行编辑器的ue_enchange事件中编写如下脚本:
long ll_found_row
string ls_find
ls_find = ″string(id) like ″ + ″′″ + this.text + ″%′″ //查找条件(左部分与单行编辑器文本相等)
ll_found_row = dw_1.Find(ls_find, 1, dw_name.RowCount()) //查找符合条件的行
if ll_found_row <= 0 then return
dw_1.ScrollToRow(ll_found_row) //滚动到相匹配的行
dw_1.SelectRow(0,false)
dw_1.SelectRow(ll_found_row,true) //将匹配行加亮显示


//如何在程序中对BLOB数据库进行写入
和后台数据库有关:以SQLANYWAY为例:
一般用 UPDATEBLOB 和 SELECTBLOB 两个SQL语句来实现。
建一个表TABLE1,一个字段是ID,另一个是BLOB,
SELECTBLOB BLOB FROM TABLE1 WHERE ID='xx';
UPDATEBLOB SET BLOB = :BLB_X FROM TABLE1 WHERE ID='yy';
删除时删除ID为'mm'的记录即可,新增是先插入一条ID为'mm'的记录,然后 用UPDATEBLOB将数据写入
表内。 其他的数据库可参照手册进行,其命令与上述差别不大!


//如何取出DDDW中的Display Column的内容。
dw_1.describe("Evaluate('lookupdisplay(column_name)',1)")
//column_name=列名 ,'1'表示第一行;看看Help中的Describe


//屏蔽窗口的ALT+F4键
//方法一:
1.在窗口的systemkey事件中增加以下代码:
IF KeyDown(KeyF4!) THEN
Message.Processed = TRUE
END IF
2.在窗口的closequery事件中增加如下代码:
Long ll_ret
IF KeyDown(keyF4!) THEN
ll_ret = 1
END IF
return ll_ret
//方法二:
建一实例变量,在你的关闭程序上赋一个True然后在closequery中判断该值, 如为False则Return 1


//当程序中用到了动态加入的对象,如BMP资源文件、数据窗口对象,PB编译时是扫描不到的,解决方法:
1.将此对象写入到资源文件中:
用记事本创建资源文件dw_object.pbr,写入:c:myprogram.pbl(dw_sj)
编译时将此文件选入Resource File Name处。
2.将应用编译成PBD、DLL文件。


//如何在PB中实现延时:
subroutine Sleep(long dwMilliseconds) library "kernel32.dll"
延时1秒则调用: Sleep(1000) //单位是毫秒。


//用下面表达式可得到记录在某组中的行号:
Getrow()-First(Getrow() for Group 1)+1


//调用API函数步骤:
1、在适当的位置声明函数,如窗口内,Application内,UserObject内,
定义在Local External Function或Global External Function中,如播放声音的:
Function boolean sndPlaySoundA(string SoundName, uint Flags) Library "WINMM.DLL"
Function uint waveOutGetNumDevs() Library "WINMM.DLL"
也可以创建一个UserObject,集中声明常用的API及函数本地化,如定义用户对象 u_external_function:
Declare Local External Function(定义外部函数):
Function boolean sndPlaySoundA(string SoundName, uint Flags) Library "WINMM.DLL"
Function uint waveOutGetNumDevs() Library "WINMM.DLL"
Declare User Object Function(定义用户对象函数):
uf_play_sound(string as_wave_name, integer ai_option)
函数内容如下:
//参数:as_wave_name :wav文件名 ai_option :同步或异步(1/0)
uint lui_numdevs
lui_numdevs = WaveOutGetNumDevs()
If lui_numdevs > 0 Then
sndPlaySoundA(as_wave_name,ai_option)
return 1
Else
return -1
End If
2、调用时在程序中定义一个实体并调用其函数:
u_external_function iu_external_function
iu_external_function = create u_external_function
iu_external_function.uf_play_sound('c:windowsmediading.wav',1)
试试看,如果有声卡,就会听到"叮”的一声。其它API函数也是如此处理。


//数据窗口的GRID格式下,根据实际情况控制每一行的背景
//调整detail的属性中的color的expression就可以了,如:
if(currentrow()=getrow(),rgb(255,240,194),if(mod(getrow(),2)=1, rgb(255,254,249) , rgb(247,247,239)))
//表达式中rgb(255,240,194)为黄色,rgb(255,254,249)为浅白色,rgb(247,247,239)为浅黄色。
//CurrentRow()得到数据窗口当前得到输入焦点的行的行号。
//GetRow()返回数据窗口相应带中的当前行行号。


//实现对数据窗口中的某一列/行显示为一指定颜色
//如果符合条件,则显示灰色的背景,否则白色;
本方法同样可以设置该列的字体颜色:其中"column_name"为列名。
dw_1.object.column_name.background.color = "16777215~tif(fromid='string',rgb(192,192,192),rgb(255,255,255))"
也可以是一行都变色:
dw_1.object.Datawindow.detail.color = "16777215~tif(fromid='string',rgb(192,192,192),rgb(255,255,255))"


//固定数据窗口前几列的方法,例如第一列名为"id”,固定该列且后半部分从下一列开始显示:
dw_1.HSplitScroll = True
dw_1.Object.DataWindow.HorizontalScrollSplit = dw_1.object.id.Width
dw_1.Object.DataWindow.HorizontalScrollPosition2 = dw_1.object.id.Width


//在数据窗口中如何隐藏某计算单元
在它的propertiesexpressionvisible属性中设置为"IF(1=2,1,0)”就可以了。


//超链接
Inet linet_base
GetContextService("Internet", linet_Base)
linet_Base.HyperlinkToURL('http://www.neusoft.com')
Destroy(linet_base)


//===========================================================================
//函数功能:返回计算表达式的值
//参数: string thestr 计算表达式,如 2 * (3+5)
//返回值:string retVal 计算表达式的结果值,如 2 * (3+5)的结果值为 16
// 如果是一个不正确的表达式,则返回 false.
//===========================================================================
string retVal
datastore lds_evaluate
lds_evaluate = create datastore
lds_evaluate.create('release 8;~r~ntable()')
retVal = lds_evaluate.describe("evaluate('" + thestr + "', 1)")
destroy lds_evaluate
return retVal


//通过代码更改数据窗口对象的方法
string error_syntaxfromSQL, error_create
string new_sql, new_syntax
new_sql = 'SELECT emp_data.emp_id,emp_data.emp_name from emp_data ' &
+ 'WHERE emp_data.emp_salary>45000'
new_syntax = SQLCA.SyntaxFromSQL(new_sql,'Style(Type=Form)', error_syntaxfromSQL)
IF Len(error_syntaxfromSQL) > 0 THEN // Display errors
mle_sfs.Text = error_syntaxfromSQL
ELSE // Generate new DataWindow
dw_new.Create(new_syntax, error_create)
IF Len(error_create) > 0 THEN
mle_create.Text = error_create
END IF
END IF
dw_new.SetTransObject(SQLCA)
dw_new.Retrieve()


//打开动态窗口的方法:
window newarray[3]
string win[3]
int i
win[1] = "w_employee"
win[2] = "w_customer"
win[3] = "w_sales"
for i = 1 to 3
Open(newarray[i], win[i])
next


//显示一个与Windows操作系统风格一致的About对话框。 首先声明如下外部函数:
function int ShellAboutA(ulong al_hWnd, string as_szApp, string as_szOtherStuff, ulong hIcon) library "shell32"
ShellAboutA(handle(parent),"关于...#摆渡人工作室","欢迎光临摆渡人工作室",0)


//如何将COLUMN的显示风格在EDIT、DDDW、DDLB之间相互切换:
(1)切换成DDDW:
dw_1.Modify("#1.dddw.Name='dddw_jg'")
dw_1.Modify("#1.dddw.DisplayColumn='name_jg'")
dw_1.Modify("#1.dddw.DataColumn='id_jg'")
(2)切换成DDLB:
dw_1.Modify("#1.ddlb.case='any'")
dw_1.Object.#1.Values ="red~t1/white~t2"
(3)切换成EDIT:
dw_1.Modify("#1.edit.case='any'")
dw_1.Modify("#1.edit.AutoSelect='Yes'")
(4)获取当前风格:
dw_1.Describe("#1.Edit.Style")
(5)如果还不行,可能得要如下操作:
dw_1.Modify("#1.dddw.Name=''")一下;


//在dw_1中选定想要打印的几条记录
long ll_pos
dataStore lds_ds
lds_ds = create dataStore
lds_ds.dataObject = dw_1.dataObject
for ll_pos = 1 to dw_1.rowCount()
if dw_1.IsSelected(ll_pos) then
dw_1.RowsCopy(ll_pos,ll_pos,Primary!,lds_ds,lds_ds.rowCount()+1,Primary!)
end if
next
lds_ds.print()


//实现在循环时可以通过点击按钮终止循环
integer n
//sb_interrupt 是共享变量
sb_interrupt=false
for n=1 to 3000
yield()
if sb_interrupt then //sb_interrupt的值在"取消”按纽的Clicked事件中修改为true
MessageBox("我不干了","你真坏!")
sb_interrupt=false
exit
else //其它处理,在单行编辑器中显示当前n值
sle_1.text = string(n)
end if
next


//SQL语句调用规范
INTEGER li_customer_id = 1
STRING ls_city_code = '501'
PREPARE SQLSA FROM "DELETE bb_customer_info_t WHERE city_code =? AND customer_id = ?" ;
EXECUTE SQLSA USING :ls_city_code,:li_customer_id;


//通过modify函数来同时修改多个表
1、新建一个数据窗口d_grid_dep_emp,它的Select语句为
SELECT department.dept_id,
department.dept_name,
employee.emp_id,
employee.emp_fname,
employee.emp_lname
FROM department, employee
WHERE employee.dept_id = department.dept_id
2、设置数据窗口d_grid_dep_emp的属性,将列的taborder改为非0值;并点击菜单Rows——>Update
Properties,设置此数据窗口Allow Updates,Table to Update设为department,Updateable Columns为
department.dept_id,department.dept_name。
3、在窗口中更新数据窗口按钮的clicked事件编写脚本:
long ll_rtn
// 修改Department表(Department表在第2步已设置为可更新)
ll_rtn = dw_1.update(true, false)
If ll_rtn = 1 then
//关闭对Department表的修改
dw_1.Modify("department_dept_name.Update = 'No'")
dw_1.Modify("department_dept_id.Update = 'No'")
dw_1.Modify("department_dept_id.Key = 'No'")
//设置Employee表成为新的可修改表
dw_1.Modify("DataWindow.Table.UpdateTable = 'employee'")
dw_1.Modify("employee_emp_id.Update = 'Yes'")
dw_1.Modify("employee_emp_fname.Update = 'Yes'")
dw_1.Modify("employee_emp_lname.Update = 'Yes'")
dw_1.Modify("employee_emp_id.Key = 'Yes'")
//修改Employee表
ll_rtn = dw_1.Update()
IF ll_rtn = 1 THEN
COMMIT USING SQLCA;
dw_1.retrieve()
messagebox('提示信息','更新成功!')
ELSE
ROLLBACK USING SQLCA;
MessageBox('提示信息', '更新失败!')
END IF
//重置修改标志
dw_1.Modify("department_dept_name.Update = 'Yes'")
dw_1.Modify("department_dept_id.Update = 'Yes'")
dw_1.Modify("department_dept_id.Key = 'Yes'")
dw_1.Modify("DataWindow.Table.UpdateTable = 'department'")
dw_1.Modify("employee_emp_id.Update = 'No'")
dw_1.Modify("employee_emp_fname.Update = 'No'")
dw_1.Modify("employee_emp_lname.Update = 'No'")
dw_1.Modify("employee_emp_id.Key = 'No'")
ELSE
ROLLBACK USING SQLCA;
MessageBox('提示信息', '更新失败!')
END IF
//可以将以上功能作成一个函数,在必要的时候调用即可。


//单击编辑框选中其中内容
getfocus事件中书写代码:this.selecttext(1,len(this.text))。保存后运行,却得不到我们想要的
效果。想到了一个另类办法:以pbm_bnclicked为事件ID,创建单行编辑框的自定义事件ue_clicked,
代码是:this.selecttext(1,len(this.text)),
getfocus事件的代码改为:This.Post Event ue_clicked()。保存后运行,效果出来了!


//怎样得到字符串中汉字的个数
For i = 1 to Len(aString)
ls_ch = Mid(aString,i,1)
If Asc(ls_ch) >= 128 then //是汉字
li_num++
i = i+1
End if
Next
//最后,li_num就是汉字的个数了


//DW支持双击标题进行排序
String ls_old_sort,ls_column,ls_name,ls_criteria
Char lc_sort
IF Right(dwo.Name,2) = '_t' THEN //取得是否是列标题名
ls_column = LEFT(dwo.Name, LEN(String(dwo.Name)) - 2)
ls_old_sort = this.Describe("Datawindow.Table.sort")
IF ls_column = LEFT(ls_old_sort,LEN(ls_old_sort) - 2) THEN
lc_sort = RIGHT(ls_old_sort,1)
IF lc_sort = 'A' THEN
lc_sort = 'D'
ELSE
lc_sort = 'A'
END IF
this.SetSort(ls_column + " " + lc_sort)
ELSE
ls_criteria = ls_column + " A"
this.SetSort(ls_criteria)
END IF
this.Sort()
END IF


//DW支持单击按Ctrl或Shift进行多选
int il_last_row //il_last_row为实例变量,记录上次单击的行
int li_current_row //当前单击行
int li_row //中间变量
//未选择就返回
if row = 0 then
return
else
li_current_row = row
end if
if keydown(keyshift!) then //按下SHIFT键
if il_last_row = 0 then
this.selectRow(row,true)
il_last_row = li_current_row
else
this.selectRow(0,false)
if li_current_row > il_last_row then
for li_row = il_last_row to li_current_row
this.selectrow(li_row,true)
end for
else
for li_row = il_last_row to li_current_row step -1
this.selectrow(li_row,true)
end for
end if
end if
else //未按下SHIFT键
il_last_row = li_current_row
if keydown(keycontrol!) then //按下CTRL键
if this.isSelected(li_current_row) then
this.selectrow(li_current_row,false)
else
this.selectrow(li_current_row,true)
end if
else //无CTRL键或SHIFT键按下
this.selectrow(0,false)
this.selectrow(li_current_row,true)
end if
end if


//改变DW的查询条件语句
string ls_select,ls_filter
ls_select = dw_1.getSqlSelect()
ls_select = mid(ls_select,1,pos(upper(ls_select),'FROM ')+30)
ls_filter="WHERE service_kind=" + vi_service_kind + " ORDER BY FEE_ID ASC "
ls_select = ls_select + ls_filter
dw_1.Reset()
dw_1.SetTransObject(SQLCA)
dw_1.SetSQLSelect(ls_select)
dw_1.Retrieve()


//数据窗口的closeQuery事件:提示保存数据
dw_1.AcceptText()
IF dw_1.ModifiedCount() + dw_1.DeletedCount() > 0 THEN
CHOOSE CASE MessageBox("操作提示","数据已经发生变化,是否保存?",Question!,YesNoCancel!,1)
CASE 1
cb_save.TriggerEvent(clicked!)
CASE 2
Return 0 //不做任何操作直接关闭窗口
CASE 3
Return 1 //不会运行Close Event,维持原来的情况
END CHOOSE
END IF


//提示:请选择要删除的记录
if dw_2.GetSelectedRow(0)= 0 then
MessageBox("提示信息","请选择要删除的记录!")
return
end if


//按某字段进行排序
IF dwo.name = "fee_id_t" THEN
this.setSort("fee_id a")
this.sort()
elseif dwo.name = "fee_position_t" then
this.setsort("fee_position a, fee_id a")
this.sort()
END IF


//控制DATAWINDOW里每页显示的行数
1、在Datawindow中增加一个计算域,起名为:ceil_page,此计算域必须放在Detail段中,
Expression中输入 ceiling(getrow()/25) 25表示每页打印25行,也可以是一个参数。
2、分组,选择菜单RowsCreate Group,选择ceil_page
按ceil_page分组,并选中New Page On Group Break(意思是新组开始时换页)。
3、将此计算域设为隐藏(在属性页中的expression页中在visible属性中写0)。
4、补空行:
在窗口的open事件中写如下代码:
long li_count,li_i
li_count=dw_1.retrieve()
if mod(li_count,25)<>0 then
for li_i=1 to 25 - mod(li_count,25)
dw_1.insertrow(0)
next
end if


//如何实现数据窗口数据的自动折行
1) 在DataWindow Painter中打开此DataWindow对象。
2) 在需设定自动折行的列上双击鼠标, 弹开此列的属性窗口。
3) 选择Position标签, 选中Autosize Height 多选框。
4) 选择Edit标签, 不选中Auto Horz Scroll多选框。
5) 单击OK按钮, 保存所做的修改。
6) 点中Detail Band (即写有Detail的灰色长带), 单击鼠标右键, 选择 Properties... 菜单项。
7) 选中Autosize Height多选框。
8) 单击OK按钮, 保存所做的修改。
9) 保存此DataWindow。
注意:连在一起的汉字(中间没有标点或空格分隔), 系统将认为是一个单词, 不会自动进行折行,
英文也是如此……DW窗口折行如果有汉字的话就必需中间加空格才会折行,否则怎样设置都不行。例如你
如果想在第20位折行,就先判断第20位是否是个汉字,如不是就在第20位后加空格,如果是汉字就在
第19位加空格。判断是否是汉字可以用它的ASCII码是否大于127来判断。


//按条件对某行数据进行颜色区分
case(cj when is >= 90 then rgb(255,0,0) when is < 60 then rgb(0,255,0) else rgb(0,0,255)))


//PB中同时连接多个数据库,如连接SQLServer2000和Oracle8
string ls_startupfile
ls_startupfile='hisini.ini'
sqlca.DBMS = ProfileString(ls_startupfile, "database", "dbms", "")
sqlca.database = ProfileString(ls_startupfile, "database", "database", "")
sqlca.userid = ProfileString(ls_startupfile, "database", "userid", "")
sqlca.dbpass = ProfileString(ls_startupfile, "database", "dbpass", "")
sqlca.logid = ProfileString(ls_startupfile, "database", "logid", "")
sqlca.logpass = ProfileString(ls_startupfile, "database", "LogPassWord", "")
sqlca.servername = ProfileString(ls_startupfile, "database", "servername", "")
sqlca.dbparm = ProfileString(ls_startupfile, "database", "dbparm", "")
remote_trans= CREATE transaction
remote_trans.DBMS = ProfileString(ls_startupfile, "Database_remote", "dbms", "")
remote_trans.database = ProfileString(ls_startupfile, "Database_remote", "database", "")
remote_trans.userid = ProfileString(ls_startupfile, "database_remote", "userid", "")
remote_trans.dbpass = ProfileString(ls_startupfile, "database_remote", "dbpass", "")
remote_trans.logid = ProfileString(ls_startupfile, "database_remote", "logid", "")
remote_trans.logpass = ProfileString(ls_startupfile, "database_remote", "LogPassWord", "")
remote_trans.servername = ProfileString(ls_startupfile, "database_remote", "servername", "")
remote_trans.dbparm = ProfileString(ls_startupfile, "database_remote", "dbparm", "")
//附hisini.ini
[Database]
DBMS=MSS Microsoft SQL Server 6.x
Database=his
UserId=
DatabasePassword=
ServerName=.
LogId=sa
Lock=
Prompt=0
computer='11'
ocx= 0
use0='之住院管理'
cfprint='1'
[Database_remote]
DBMS = "O84 Oracle8/8i(8.x.4+)"
ServerName = "oracle8"
LogId = "dba"
Database=zx
UserId=
DatabasePassword=
Lock=
Prompt=0
computer='11'
ocx= 0
cfprint='1'


//PB6.5连接Oracle8i和9i的情况
SQLCA.DBMS = "O84 Oracle8/8i (8.x.4+)"
SQLCA.LogPass = "test"
SQLCA.ServerName = "myora"
SQLCA.LogId = "test"
SQLCA.AutoCommit = False
SQLCA.DBParm = "TableCriteria=',test,''TABLE'',''VIEW'''"


//在检索的数据行上再加上一行记录
dataWindowChild dwc
dw_service.getchild('svcid',dwc)
dwc.settransobject(sqlca)
dwc.retrieve()
dwc.insertrow(1)
dwc.setitem(1,'svcid','00')
dwc.setitem(1,'svcname','不区分')
dw_service.setTransObject(sqlca)
dw_service.Retrieve()


//数据窗口中按enter键实现tab功能(在数据窗口的Enter事件中)
send(handle(this),256,9,long(0,0))
return 1


//send用法:Send(handle,message#,lowword,long)
//This statement scrolls the window w_emp up one page:
Send(Handle(w_emp), 277, 2, 0)
//Both of the following statements click the CommandButton cb_OK:
Send(Handle(Parent), 273, 0, Handle(cb_OK))
cb_OK.TriggerEvent(Clicked!)
//minimizes the DataWindow:
Send(Handle(dw_1), 274, 61472, 0)
//maximizes the DataWindow:
Send(Handle(dw_1), 274, 61488, 0)
//returns the DataWindow to its normal, defined size:
Send(Handle(dw_1), 274, 61728, 0)


//重设数据窗口的检索语句
ls_accept_city = gs_citycode
ld_beg_date = datetime(date(em_assign_beg_date.text),time('00:00:00'))
ld_end_date = datetime(date(em_assign_end_date.text),time('23:59:59'))
ls_where = " WHERE b.assign_date >= :id_begin_date &
AND b.assign_date <= :id_end_date &
AND a.register_number = b.register_number &
AND a.accept_city = :is_accept_city &
AND a.action = 6 AND current_action = 1 AND status IN(1,-1) "
ls_sql = dw_wp.Describe("DataWindow.Table.Select")
if pos(ls_sql,'WHERE') <> 0 then
ls_sql = mid(ls_sql,1,pos(ls_sql,'WHERE') - 1)
end if
ls_sql = 'DataWindow.Table.Select=" ' + ls_sql + ls_where + '"'
ls_err_info = dw_wp.modify(ls_sql)
if ls_err_info <> "" then
messagebox('提示信息','查询异常,请核查' + ls_err_info)
return
end if
af_connect()
dw_wp.settransobject(sqlca)
dw_wp.retrieve(ld_beg_date,ld_end_date,ls_accept_city)
af_disconnect()


//常用API函数例解
1.如何使PB窗口总在最上层(Always On Top)
通过SetWindowPos函数把窗口的显示层次修改为HWND—TOPMOST,就可使指定窗口永远不会被其它窗口覆
盖,该函数声明为:
Function Long SetWindowPos(Long hwnd,Long ord,Long x,Long y,Long dx,Long dy,Long uflag) Library ″user32″
参数1为要顶层显示的窗口句柄,参数2指定显示的层次,参数7为附加选项,其余参数指定窗口位置和
大小,均可忽略。在窗口的Open或Activate事件中加入如下函数调用:
SetWindowPos(Handle(This),-1,0,0,0,0,3)
参数2取-1表示在最顶层显示窗口,取1表示在最底层显示;最后一个参数若取1,表示窗口大小保持不
变,取2表示保持位置不变,因此,取3(=1+2)表示大小和位置均保持不变,取0表示将窗口的大小和
位置改变为指定值。

2.在PB中如何获得光盘盘符
通过GetDriveType函数可以获取驱动器(如:软驱、硬盘、光驱、网络映射驱动器等)的信息,该函数
声明为:
Function Uint GetDriveTypeA(String drive) Library ″kernel32.dll″
参数为一个盘符(如"C:"),返回值:1表示未知,2表示软驱,3表示本地硬盘,4表示网络驱动器,
5表示光驱。因此如下代码可以获得光盘的盘符:
For i=Asc(′D′) to Asc(′Z′)
//列举所有可能的CDROM驱动器
  If GetDriveTypeA(Char(i)+″:″)=5 Then
//若找到CDROM
MessageBox(″CDROM″,Char(i)+″:″)
//显示光盘盘符
Exit //退出列举
  End If
Next

3.在PB中如何获取目录信息
⑴获取当前目录。通过GetCurrentDirectory函数可以获取当前目录,该函数声明为:
Function Ulong GetCurrentDirectoryA(Ulong buflen, ref String dir) Library ″kernel32.dll″
参数2为接收当前目录的字符缓冲区,前面必须加ref表示地址引用;参数1用来指定字符缓冲区的长度。
调用过程为:
String curdir
curdir=Space(256)
//为字符缓冲区开辟内存空间
GetCurrentDirectoryA(256,curdir)
MessageBox(″Current Directory″,curdir)
⑵获取Windows及系统目录。要用到GetWindowsDirectory和GetSystemDirectory两个函数,须作如下声明:
Function Uint GetWindowsDirectoryA(ref String dir,Uint buflen) Library ″kernel32.dll″
Function Uint GetSystemDirectoryA(ref String dir,Uint buflen) Library ″kernel32.dll″

4.在PB中如何注销当前用户、关闭计算机、重启计算机
通过ExitWindowsEx函数可实现这三个功能,首先作如下声明:
Function Long ExitWindowsEx(Long uflag,Long nouse) Library ″user32.dll″
参数2保留不用,可取0;参数1取0可以注销当前用户,取1可以关闭计算机,取2可以重启计算机,其值
再加4表示强制结束"未响应"的进程。

5.控制由Run运行的程序(简称Run程序)
在PB程序设计中,可以用Run()来运行一些程序。比如用户按了F1,就运行一个chm文件。但Run程序无法
与PB主程序协调工作,若用户按了多次F1,就会启动Run程序的多个实例,主程序退出时,Run程序依然
运行。可以用如下函数来使它们协调工作:
Function Ulong FindWindowA(Ulong classname, String windowname) Library ″user32.dll″
Function Long SetParent(Long childwin,Long parentwin) Library ″user32.dll″
⑴使Run程序只运行一个实例
handle=FindWindowA(nul,wtitle)
//查找Run程序是否已经运行,wtitle为Run程序的标题
IF handle〉0 Then Return
//若已经在运行就返回
Run(″C:Program FilesJointJoint.chm″)
//否则运行Run程序
⑵PB主程序退出时,Run程序也关闭
handle=FindWindowA(nul,wtitle)
SetParent(handle,Handle(w—main))
//使Run程序窗口成为PB主程序的子窗口

6.映射网络驱动器

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics