PB开发笔记(3)

pb 编程 专栏收录该内容
37 篇文章 0 订阅

//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_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/App Paths/MSIMN.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:/windows/media/ding.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


//在数据窗口中如何隐藏某计算单元
在它的properties/expression/visible属性中设置为"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

 
  • 0
    点赞
  • 1
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值