时也？运也？命也？

前言：

至今为止，本人最后悔的一件事就是当初家里人都劝我学理，而我却偏偏选择了文科，否则是不是我也能报计算机专业？唉！事已至此，多说无益，一切都是命啊！

打上班起，我曾学过Visual Basic，也曾用过Visual Foxpro，不过最终还是选择了PowerBuilder，原因很多，说之无益，不管怎么说，先精通一门数据库语言再说吧！

唉！真的很惭愧，自学计算机已三年有余，至今一无所成，不过也算是小有成就，也总结了很多经验，若干时后我再看到此篇文章不知该作何感想？

→我是小木鱼（Lag）

2000年11月27日完成此页


PowerBuilder常见问题解答

声明：

本帮助文件为李宏伟个人收藏集，内容为本人的一些实际编程经验及来自网络上的一些文章，版权归实际作者所有，本人无意侵权，也绝不外借！

作者简介：

姓名： | 李宏伟
性别： | 男
出生日期： | 1975年1月19日
毕业学校： | 辽宁大学经济管理学院统计专业
网名： | 我是小木鱼（Lag）
E-mail： | lag@sina.com
工作单位： | 沈阳变压器有限责任公司经营计划处综合统计科
工作电话： | （024）25851211-3459
个人传呼： | （024）126 传 999-750733
兴趣爱好： | 计算机、足球，最喜欢的游戏：仙剑奇侠传、帝国时代Ⅱ
我是小木鱼 | 版权所有：Copyright(C) 李宏伟

资料来源：欢迎来到PB编程俱乐部!

摆渡人工作室

杨杨得意——首页

陶清PB编程精品站点

2000年11月27日完成此页


PowerBuilder中的应用对象

应用对象是整个应用系统或某个应用子系统的入口点，就好像是C语言中的main函数一样。一般情况下是将应用系统开始前的准备工作放在应用对象中，例如，为连接数据库而进行的参数赋值、打开主窗口等工作。应用对象的属性是定义整个应用系统级的属性，例如应用系统中使用的字符大小、字体、应用程序的图标等。

→我是小木鱼（Lag）

写于2000年11月29日


事务对象浅析?

问：事务对象到底是何方神圣呢？

答：它是PowerBuilder众多对象中最重要的一个对象，并且也是最不好理解的一个对象。它实际上是PowerBuilder程序与数据库之间传递信息的一个结构变量，共有15个成员。

[注]事务对象的15个成员

序号 | 名称 | 类型 | 说明
1 | DBMS | string | 所使用的数据库管理系统的名字，如Sybase,Oracle,ODBC。
2 | Database | string | 要连接的数据库名字。
3 | UserID | string | 连接数据库所用的用户名。有的DBMS不需要此项。
4 | DBPass | string | 用户连接数据库的口令。
5 | Lock | string | 这是数据库的保护级别，一般不必给出。
6 | LogID | string | 登录到数据库服务器上的用户名，有的DBMS不需要此项，但Sybase和Oracle需要指定这个参数。
7 | LogPass | string | 登录到数据库服务器上的用户口令。这个属性可设可不设，但Sybase和Oracle需要指定口令。
8 | ServerName | string | 数据库服务器名。
9 | AutoCommit | boolean | 指定是否将数据库设置成自动提交所有事务。默认是False，也就是说，必须在应用程序中进行事务管理，并在适当的时候对数据库提交事务。如果选择True，则每个事务都由系统自动提交。
10 | DBParm | string | 用于向数据库传递特殊信息的属性。
11 | SQLCode | long | 指示最近一次SQL操作失败或成功。它的取值为：
 |  | 返回结果 | 0 | 无错误。
 |  |  | -1 | 出现一个错误。
 |  |  | 100 | 没有检索到数据。
12 | SQLNRows | long | 最近一次SQL操作影响的行数，数据库不同其含义也不同。
13 | SQLDBCode | long | 数据库错误代码。不同的数据库的含义不同。
14 | SQLErrText | string | 相应于SQLDBCode属性中错误码的文字说明。
15 | SQLReturnData | string | 返回DBMS执行SQL的附加信息，不同的DBMS其值不同。

例子：这是一个连接Sybase数据库所需的代码实例：

sqlca.dbms="Sybase"
sqlca.database="testdatabase"
sqlca.logid="lihongwei"
sqlca.logpass="lag"
sqlca.servername="jhc_server"
sqlca.autocommit=false

这是一个连接ODBC数据库(如Sybase SQLAnywhere 5.0)所需的代码实例：

sqlca.dbms="odbc"
sqlca.dbparm="connectstring='dsn=testdatabase'"

→我是小木鱼（Lag）

写于2001年01月16日


如何限制应用程序只运行一次?

问：请问如何限制应用程序只运行一次呢？

答：利用Windows的API函数FindWindow()、BringWindowToTop()、ShowWindow()可实现上述功能。

①定义API：
Funtion ulong FindWindowA( ulong winhandle, string wintitle ) Library "user32"
Funtion uLong BringWindowToTop( ulong hwnd ) Library "user32"
Funtion uLong ShowWindow( ulong winhandle, int wincommand ) Library "user32"

②创建主窗口"w_test"，将title设置为"Test Window"

③在application的Open事件中加入如下代码:
ulong ulng_winhandle
ulng_winhandle = FindWindowA( 0,"Test Window" )
If ulng_winhandle > 0 Then
BringWindowToTop( ulng_winhandle )
ShowWindow( ulng_winhandle, 5 )
Return
End If
Open( w_test )

[注]FindWindow()函数

说明： | 寻找窗口列表中第一个符合指定条件的顶级窗口。
返回值： | ulong，找到窗口的句柄，如未找到相符窗口，则返回零。
参数 | 类型及说明
winhandle | String，指向包含了窗口类名的空中止（C语言）字串的指针；或设为零，表示接收任何类。
wintitle | String，指向包含了窗口文本（或标签）的空中止（C语言）字串的指针；或设为零，表示接收任何窗口标题。

BringWindowToTop()函数

说明： | 将指定的窗口带至窗口列表顶部。倘若它部分或全部隐藏于其他窗口下面，则将隐藏的部分完全显示出来。该函数也对弹出式窗口、顶级窗口以及MDI子窗口产生作用。
返回值： | ulong，非零表示成功，零表示失败。
参数 | 类型及说明
hwnd | ulong，欲带至顶部的那个窗口的句柄。

ShowWindow()函数

说明： | 控制窗口的可见性。
返回值： | ulong，如窗口之前是可见的，则返回TRUE（非零），否则返回FALSE（零）。
参数 | 类型及说明
winhandle | ulong，窗口句柄，要向这个窗口应用由wincommand指定的命令。
wincommand | integer，为窗口指定可视性方面的一个命令。请用下述任何一个常数
 | 0 | 隐藏窗口，活动状态给另一个窗口。
 | 1 | 用原来的大小和位置显示一个窗口，同时令其进入活动状态。与9同。
 | 2 | 最小化窗口，并将其激活
 | 3 | 最大化窗口，并将其激活。
 | 4 | 用最近的大小和位置显示一个窗口，同时不改变活动窗口。
 | 5 | 用当前的大小和位置显示一个窗口，同时令其进入活动状态。
 | 6 | 最小化窗口，活动状态给令一个窗口。
 | 7 | 最小化一个窗口，同时不改变活动窗口。
 | 8 | 用当前的大小和位置显示一个窗口，不改变活动窗口。
 | 9 | 用原来的大小和位置显示一个窗口，同时令其进入活动状态。

→我是小木鱼（Lag）

写于2000年11月29日


如何实现数据库的备份?

问：数据库的备份在数据库应用程序中是很重要的一环，那么我将如何实现它呢？

答：用Windows的API函数可以办到。

方法一：在PB中调用DOS命令(dbbackup.exe)备份并判断其运行结束。

①定义API：
Funtion ulong FindWindowA( ulong winhandle, string wintitle ) Library "user32"
Function boolean IsWindow (Long hwnd ) Library "user32.dll"

②脚本：
ulong ll_handle
int li_loop

SetPointer(HourGlass!) //设置鼠标指针
//运行备份数据库程序dbbackup，并使其最小化
run("dbbackup -c ~"uid=dba;pwd=sql; dbf=D:\Sybase\Adaptive Server Anywhere 6.0\asademo.db~" d:\backup", Minimized!)
ll_handle = 0
//循环至dbbackup窗口打开
Do While ll_handle = 0
ll_handle = FindWindowA("tty","dbbackup")
yield()
loop
//等待dbbackup窗口关闭
Do While isWindow(ll_handle)
Yield()
Loop
//应用执行完成
MessageBox("提示信息", "备份完成!")

[注]IsWindow()函数

说明： | 判断一个窗口句柄是否有效。
返回值： | Long，非零表示成功，零表示失败。
参数 | 类型及说明
hwnd | Long，待检查窗口的句柄。

相关资料：当在程序中运行DOS命令时如何隐藏DOS窗口并判断其结束？

→我是小木鱼（Lag）

写于2000年12月08日


如何隐藏应用程序运行时显示在系统状态条上的数据库日志图标？

问：在应用程序运行时，数据库Sysbase SQL Anywhere 5.0启动后在系统状态条上会有图标，有时用户会不小心将其关闭，造成系统出错。请问如何隐藏Sysbase SQL Anywhere 5.0在系统状态条上的的图标？

答：可以通过更改系统注册表来实现。以Powersoft Demo DB V6 为例：

运行注册程序regedit，找到注册表中HKEY_CURRENT_USER\Software\ODBC\ODBC.INI\Powersoft Demo DB V6中名为Start的项目，如其原值为“C:\Program Files\Sybase\SQL Anywhere 5.0\Win32\dbeng50.exe”，在其后加上参数 －Q，改为“C:\Program Files\Sybase\SQL Anywhere 5.0\Win32\dbeng50.exe －Q”即可。

    //对于自己创建的其它Sysbase SQL Anywhere 5.0数据库可用同样方法实现。

→我是小木鱼（Lag）

写于2000年12月04日


如何实现用一个表中的数据修改另一个表中的数据?

问：我想根据一定的条件实现用一个表中的数据修改另一个表中的数据，这该如何办到呢？

答：这有何难，用SQL语言UPDATE嘛。

表一 | student
stu_id | stu_name | stu_age
1 | aa | 20
2 | bb | 21
3 | cc | 22
4 | dd | 23

另一个表如下：

表二 | lag
lag_id | lag_name | lag_another
1 | 1111 | abcd
3 | 2222 | efgh

我想用表lag中的1与3中的1111与2222替换表student中的1与3中的数据，修改后的结果如下表：

表一 | student
stu_id | stu_name | stu_age
1 | 1111 | 20
2 | bb | 21
3 | 2222 | 22
4 | dd | 23

执行语句如下：

Update student
Set student.stu_name = ( Select lag.lag_name from lag where lag.lag_id = student.stu_id )
Where student.stu_id in ( Select lag.lag_id from lag )

→我是小木鱼（Lag）


如何提高SQL语言的查询效率?

问：请问我如何才能提高SQL语言的查询效率呢？

答：这得从头说起：

由于SQL是面向结果而不是面向过程的查询语言，所以一般支持SQL语言的大型关系型数据库都使用一个基于查询成本的优化器，为即时查询提供一个最佳的执行策略。对于优化器，输入是一条查询语句，输出是一个执行策略。
一条SQL查询语句可以有多种执行策略，优化器将估计出全部执行方法中所需时间最少的所谓成本最低的那一种方法。所有优化都是基于用记所使用的查询语句中的where子句，优化器对where子句中的优化主要用搜索参数(Serach Argument)。

搜索参数的核心思想就是数据库使用表中字段的索引来查询数据，而不必直接查询记录中的数据。

带有 =、<、<=、>、>= 等操作符的条件语句可以直接使用索引，如下列是搜索参数：
emp_id = "10001" 或 salary > 3000 或 a =1 and c = 7

而下列则不是搜索参数：
salary = emp_salary 或 dep_id != 10 或 salary * 12 >= 3000 或 a=1 or c=7

应当尽可能提供一些冗余的搜索参数，使优化器有更多的选择余地。请看以下3种方法：

第一种方法：
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (department.dep_code='01') and (employee.dep_code='01');

它的搜索分析结果如下：
Estimate 2 I/O operations
Scan department using primary key
for rows where dep_code equals '01'
Estimate getting here 1 times
Scan employee sequentially
Estimate getting here 5 times

第二种方法：
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (department.dep_code='01');

它的搜索分析结果如下：
Estimate 2 I/O operations
Scan department using primary key
for rows where dep_code equals '01'
Estimate getting here 1 times
Scan employee sequentially
Estimate getting here 5 times

第一种方法与第二种运行效率相同，但第一种方法最好，因为它为优化器提供了更多的选择机会。

第三种方法：
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (employee.dep_code='01');

这种方法最不好，因为它无法使用索引，也就是无法优化……

使用SQL语句时应注意以下几点：

1、避免使用不兼容的数据类型。例如，Float和Integer，Char和Varchar，Binary和Long Binary不兼容的。数据类型的不兼容可能使优化器无法执行一些本可以进行的优化操作。例如：

select emp_name form employee where salary > 3000;

在此语句中若salary是Float类型的，则优化器很难对其进行优化，因为3000是个整数，我们应在编程时使用3000.0而不要等运行时让DBMS进行转化。

2、尽量不要使用表达式，因它在编绎时是无法得到的，所以SQL只能使用其平均密度来估计将要命中的记录数。

3、避免对搜索参数使用其他的数学操作符。如：

select emp_name from employee where salary * 12 > 3000;

应改为：

select emp_name from employee where salary > 250;

4、避免使用 != 或 <> 等这样的操作符，因为它会使系统无法使用索引，而只能直接搜索表中的数据。

→我是小木鱼（Lag）

写于2000年12月16日


如何制作表形视图控件?

问：表形视图控件真的很好用噢，可我不会作，教教我呗!

答：说起来容易作起来难啊。

原理：实际上表形视图控件与树形视图控件大同小异，它的内容大都来源于某一表中的内容，在程序中写进去的。

[例]如下图所示：

listviewitem llvi_new

//若为详细列表方式则设列标题
lv_1.addcolumn("姓名",center!,300)
lv_1.addcolumn("代码",center!,300)
lv_1.addcolumn("部门",center!,300)
lv_1.addcolumn("其它",center!,300)
//增加各列内容及图标索引
llvi_new.label="李宏伟~t100~t计划处~t无"
llvi_new.pictureindex=1
lv_1.additem(llvi_new)
//增加第二列
llvi_new.label="赵光浩~t200~t计划处~t无"
llvi_new.pictureindex=2
lv_1.additem(llvi_new)
//增加第三列
llvi_new.label="崔昌银~t300~t计划处~t无"
llvi_new.pictureindex=3
lv_1.additem(llvi_new)

具体信息请参照有关语法。

→我是小木鱼（Lag）

写于2001年01月09日


如何制作树形视图控件?

问：树形视图控件真的很好用噢，可我不会作，教教我呗!

答：说起来容易作起来难啊。

原理：实际上表形视图控件与表形视图控件大同小异，它的内容大都来源于某一表中的内容，在程序中写进去的。

[例]如下图所示：

第一步：制作第一层

TreeViewItem ltvi_Item

SetPointer(HourGlass!)
// Add a root for each department
ltvi_Item.level=1 //树视图项在树视图控件中的级别
ltvi_Item.label = "R & D" //树视图项的显示信息
ltvi_Item.data = 100 //树视图项的内部信息
ltvi_Item.pictureindex = 1 //树视图项的图标索引
ltvi_Item.selectedpictureindex = 7 //树视图项被选中时使用的图标索引
ltvi_Item.children = True //树视图是否有下一级的标志
tv_1.InsertItemLast(0, ltvi_Item) //将加入项放在指定项的后面

ltvi_Item.label = "Sales"
ltvi_Item.data = 200
ltvi_Item.pictureindex = 2
tv_1.InsertItemLast(0, ltvi_Item)

ltvi_Item.label = "Finance"
ltvi_Item.data = 300
ltvi_Item.pictureindex = 3
tv_1.InsertItemLast(0, ltvi_Item)

ltvi_Item.label = "Marketing"
ltvi_Item.data = 400
ltvi_Item.pictureindex = 4
tv_1.InsertItemLast(0, ltvi_Item)

ltvi_Item.label = "Shipping"
ltvi_Item.data = 500
ltvi_Item.pictureindex = 5
tv_1.InsertItemLast(0, ltvi_Item)

第二步：当第一层第一次展开时触发[ItemPopulate]事件，将其子内容加入

Integer li_Rows, li_Cnt
TreeViewItem ltvi_Dept, ltvi_Emp

If GetItem(handle, ltvi_Dept) = -1 Then Return
SetPointer(HourGlass!)
// Populate(板上组装) the department with its employees
ids_Source.Reset() //数据存储对象
li_Rows = ids_Source.Retrieve(Integer(ltvi_Dept.data))
ltvi_Emp.pictureindex = 6
ltvi_Emp.selectedpictureindex = 6
ltvi_Emp.children = false
For li_Cnt = 1 To li_Rows
ltvi_Emp.label = ids_Source.Object.emp_name[li_Cnt]
ltvi_Emp.data = ids_Source.Object.emp_id[li_Cnt]
InsertItemSort(handle, ltvi_Emp) //插入时排序
Next

具体信息请参照有关语法。

→我是小木鱼（Lag）

写于2001年01月08日


如何使窗口自动居中?

问：我想使应用程序的主窗口自动显示在屏幕的中心而不管屏幕的分辨率、操作系统版本如何改变，这该怎么办呢？

答:It's too easy ……

原理：利用PB中的Environment对象和窗口的Move函数。

窗口(w_main)代码如下：

//变量声明
Environment env_system
 Integer int_scrwidth,int_scrheight

    //关闭窗口刷新
SetRedraw(False)
//获得屏幕的宽度和高度
GetEnvironment(env_system)
int_scrwidth=PixelsToUnits(env_system.screenwidth,xpixelstounits!)
int_scrheight=PixelsToUnits(env_system.screenheight,ypixelstounits!)
//移动窗口到屏幕中心
move((int_scrwidth - this.width)/2,(int_scrheight -
this.height)/2)
//打开窗口刷新
SetRedraw(True)

→我是小木鱼（Lag）

写于2001年01月03日


如何向窗口传送多个参数？

问：我想一次向窗口传送多个参数，这该如何实现呢？

答：这就要用到结构了，定义一个结构，将此结构作为单个参数传送即可。

例如：(1)创建一个结构变量stc_emp，它有两个成员：一个是emp_id，一个是dep_code。

(2)为此结构赋值：
stc_emp stc_lag
stc_lag.emp_id = "1001"
stc_lag.dep_code = "01"

(3)向窗口w_main传送参数：
opensheetwithparm ( w_emp ,stc_lag ,w_main)

(4)在窗口w_main中接收此参数：
stc_emp i_stc_lag
i_stc_lag = message.objectparm

→我是小木鱼（Lag）

写于2000年12月08日


如何在窗口退出时检测数据是否被修改？

问：怎样检测数据窗口中数据是否被修改，以避免用户不小心关闭窗口而导致数据窗口中大量修改数据未保存而丢失？

答：在窗口的closequery事件加入如下代码即可：

    integer int_returncode
//将“漂浮”在数据窗口控件上编辑框的内容放入到数据窗口控件的当前项中(主缓冲区)
dw_1.accepttext()
    if dw_1.deletedcount() + dw_1.modifiedcount() > 0 then
  int_returncode = messagebox("你自己决定","数据已经被修改，是否存盘？",Question!,YesNoCancel!)
  choose case int_returncode
case 1
    if dw_1.update() = 1 then
     commit;
    return 0
else
  rollback;
  messagebox("出错","存盘时出错,请检查数据的正确性!")
  return 1
  end if
case 2
    return 0
  case 3
    return 1
  end choose
    end if

→我是小木鱼（Lag）

写于2000年12月04日


如何使用动画鼠标指针?

问：我想在PowerBuilder中使用动画鼠标指针，那么该如何做呢？

答：尽管在PowerBuilder的帮助中没有提到，实际上在PowerBuilder中是可以使用动画鼠标指针的，只需指定路径和文件名即可：

例如： st_1.Pointer = "c:\windows\cursor\hourglas.ani"

→我是小木鱼（Lag）

写于2000年12月01日


如何实现单击文本框时选中所有内容?

问：请问如何实现当用户单击单行编辑框时，选中编辑框内的所有字符，以便用户“替换录入”？

答：不要在getfocus()中直接写入代码：

①创建单行编辑框的自定义单击事件 ue_clicked() ，Event ID 为 pbm_bnclicked ：
 this.selecttext( 1, len( this.text ) )

②getfocus事件的代码为：This.Post Event ue_clicked()

→我是小木鱼（Lag）

写于2000年11月30日


当某一数据列为空时如何设置计算列的值?

问：我的一个报表中要有一个计算域，是几个NUM型列相加，加的时候几个列中有一为空就加不出来，这该如何是好？

答：有二种方法可以解决上述问题：

方法一：

设置此数据列的初使值为0.0。但必需在数据窗口对象中设，即选菜单Rows中的Column Specifications……选项，在Initial Value列中写上0.0即可。

方法二：

计算列公式采用如下：
if(isnull(A), 0,A) + if(isnull(B), 0,B) + if(isnull(C), 0,C) 就可以了。
//原： A + B + C

→我是小木鱼（Lag）

写于2000年12月20日


如何创建一个动态的数据窗口对象?

问：我想在程序运行中根据需要动态地建立一个数据窗口对象，该怎么做呢？

答：方法有四：

第一种方法：

在程序中用Describe()函数得到某个已经存在的数据窗口对象的源代码。如：

string str_dwsyntax,str_lag
//获得数据窗口1的语法
str_dwsyntax=dw_1.object.datawindow.syntax
//根据数据窗口1的语法动态生成数据窗口2的语法
dw_2.create(str_dwsyntax)
//对数据窗口2的内容作局部修改
str_lag="stu_id_t.font.height='-12' stu_id_t.font.face='楷体_GB2312'"
//字体变12号字体，由宋体改为楷体
dw_2.modify(str_lag)
dw_2.settransobject(sqlca)
dw_2.retrieve()

第二种方法：

在程序中使用系统函数LibraryExport()得到某个已经存在的数据窗口对象的源代码。

第三种方法：

在PowerBuilder开发环境的库管理画笔(Library Painter)中使用移出功能(右键→Export)将某个数据窗口对象的语法保存到文本文件中。

第四种方法：

1、设计窗口时在窗口上设置一个数据窗口控件，该控件用于展示动态创建的数据窗口。

2、构造一条SELECT语句。

3、利用事务对象的对象函数SyntaxFromSQL()生成符合数据窗口对象语法的字符串。

4、使用数据窗口控件的对象函数Create()创建数据窗口。

例子：string str_err_sql,str_err_create,str_sql,str_syntax

     str_sql="select
emp_id,emp_data,emp_name from employee where emp_salary>750"
//生成SELECT语句对应的自由风格的数据窗口语法
str_syntax=SQLCA.SyntaxFromSQL(str_sql,'style(type=Form)',str_err_sql)
if len(str_err_sql)>0 then
messagebox("错误","取得SQL语法时出错")
return
else
dw_1.create(str_syntax,str_err_create)
if len(str_err_create)>0 then
messagebox("错误","创建数据窗口时出错！")
return
end if
end if
dw_1.settransobject(sqlca)
dw_1.retrieve()

[注]SyntaxFromSQL()函数

说明： | 根据SQL SELECT语句生成数据窗口对象的源代码，通常用于创建动态数据窗口对象。
语法： | transaction.SyntaxFromSQL(sqlselect,presentation,err )。
返回值： | string，成功时返回生成的指定风格数据窗口对象的源代码，错误时返回空字符串，err参数可说明原因。
参数 | 类型及说明
transaction | 事务对象名。
sqlselect | string，其值为一条有效的SQL SELECT语句。
presentation | string，指定数据窗口缺省的表现风格。
 | 完整语法 | Style(Type=value property=value ……) //数据窗口风格
 |  | Type | Tabular | 缺省值，列表风格
 |  |  | Grid | 列表风格
 |  |  | Form | 自由格式
 |  |  | Crosstab | 交叉列表
 |  |  | Graph | 统计图风格
 |  |  | Group | 分组风格
 |  |  | Label | 标签风格
 |  |  | Nested | 复合风格
 |  |  | Ole 2.0 | Ole风格
 |  |  | RichText | 超文本风格
 |  | DataWindow(Property=value ……) //数据窗口本身的属性
 |  | Column(Property=value ……) //列对象属性
 |  | Group(groupby_colnum1 by_colnum2 …… property ……) //分组特性
 |  | Text(property=value ……) //文本对象属性
 |  | Title('titlestring') //数据窗口的标题
err | string，当生成数据窗口源代码发生错误时，该参数用于保存出错信息。

[注]Create()函数

说明： | 使用指定的源代码创建数据窗口对象，并用新的数据窗口对象来取代旧的，但新的不会自动成为应用库的一部份。
语法： | dwcontrol.Create( syntax {,errorbuffer})
返回值： | integer，成功为1，错误为-1。
参数 | 类型及说明
dwcontrol | 数据窗口控件名。
syntax | 数据窗口源代码，Create()函数将使用该代码来创建数据窗口对象。
errorbuffer | 可选，保存创建时的出错信息，若省略则系统将使用消息对话框显示出错信息。
用法 | 数据窗口对象源代码语法相当复杂，因此手工从头构造该语法几乎是不可能的，但也不用泄气，Powersoft提供了几个办法构造数据窗口对象的源代码。
 | 1 | 程序中使用数据窗口控件的Describe()函数得到某个已经存在的数据窗口对象的源代码，再据此修改。
 | 2 | 程序中使用系统函数LibraryExport()得到某个已经存在的数据窗口对象的源代码，再据此修改。
 | 3 | 在PowerBuilder开发环境的库管理画笔(Library Painter)中使用移出功能(Export)将某个数据窗口对象的语法保存到文本文件中，再据此修改。
 | 4 | 程序中使用事务对象函数SyntaxFromSQL()，该函数根据SQL语句创建数据窗口对象的源代码，再据此修改。

→我是小木鱼（Lag）

写于2000年12月16日


如何在程序中随意修改数据窗口对象的各个带区、标题或格式等?

问：我的报表是动态生成的，现在希望随意修改各个带区的宽度、位置；希望随意在报表中增加文本（标题），或对标题栏的文本进行修改；希望能够在报表中划线，改变报表的格式等，这该如何办到呢？

答：PB动态报表其实就是动态数据窗口，我个人认为动态数据窗口的难处在参数的设定，要做到各项都可随意设定。刚开始做时可以手工设置datawindow对象，再在程序中用dw_1.object.datawindow.syntax将其结构倒出来分析，以便有个参考。对于数据窗口中各项的更改可以用Modify()函数来实现，举几个例子：

1、改变detail区的高度：dw_1.Modify("DataWindow.detail.Height=200")
2、对标题栏文本的更改(文本名为dept_name_t)：dw_1.modify("dept_name_t.text
= '单位名称'")
3、增加计算域：假设一grid型的数据窗口，其中有个字段为部门号dept_id，我们要增加一个统计部门数的计算域count(dept_id
for all)：
string ls_modrow
dw_1.Modify("DataWindow.summary.Height=64")
ls_modrow = 'Create compute(band=summary font.charset="0"
font.face="MS Sans Serif" font.family="2"
font.height="-8" font.pitch="2" font.weight="400"
background.mode="1" background.color="536870912"
color="0" x="9" y="4" height="52"
width="297" format="[general]"
expression="count(dept_id for all)" alignment="1"
border="0" crosstab.repeat=no )~r~n'
dw_1.modify( ls_modrow )
4、以下程序段让grid数据窗口中网格线不见，并在detail区增加加一条线
string ls_line
DW_1.Modify("DataWindow.Grid.Lines='1' ")
dw_1.Modify("DataWindow.detail.Height=332")
ls_line = 'Create line(band=detail background.mode="2"
background.color="16777215" pen.style="0"
pen.width="5" pen.color="0" x1="37"
y1="320" x2="1458" y2="316" )~r~n'
dw_1.modify( ls_line )
象这种数据窗口动态增加控件的方法，也可以先在数据窗口画板中手工加上去，倒成sytnax后，查看其语法，再反写回去即可。

→我是小木鱼（Lag）

写于2000年12月20日


如何在Grid类型的报表上面的Header区增加文字标题？

问：Grid类型的报表倒是很好用，可是却如何给它加上文字标题呢？

答：骗骗机器好了。

(1)虽然在数据窗口画笔中所看到的数据窗口感觉上是平面的，但实际上它是一个立体对象，由前景(ForeGround)、区和背景(BackGround)三种不同的层次组合而成。当文字对象(如字段标题)放在数据窗口上时，缺省设置是将其与字段数据一样放在区层。因此，如果要将字段标题横跨不同的字段时，利用更改字段标题位置(Position)的属性设成前景或背景即可。

(2)要改变文字对象(标题)的颜色属性，将背景颜色改成和数据窗口对象背景相同的颜色即可(因为文字对象缺省是透明的)，然后调整文字对象大小直到把所有Header格线全部庶住为止。

→我是小木鱼（Lag）

写于2000年12月16日


如何参考数据窗口中其他行的数据?

问：我想在数据窗口对象中加入一计算域，其公式为(本行数据 - 上一行数据)，这该如何实现呢？

答：会者不难，难者不会

当您在写一个复杂的计算式时，能参考到其他行的数据是非常有用的， 为了参考其它行，只要把数据作为一个大的数组，在字段名的后面加上一个[num]， 其中num为相对该行的偏移量。

例如：您可以用如下的代码显示当某两行的某些数据不同是显示标记：
 if( customer[ -1 ] = customer, 0, 1 )

//如果上一个costomer和本行的costomer相同则为1，否则为0

→我是小木鱼（Lag）

写于2000年12月01日


如何在计算域中统计性别为男的个数?

问：我想在DataWindow对象中添加一计算域，统计一下性别为男的记录个数，该如何实现呢？

答：添加一计算域，公式为：sum( if( stu_sex ='男', 1, 0 ))

→我是小木鱼（Lag）

写于2000年11月30日


如何在DataWindow中实现列的自动折行?

问：在PowerBuilder应用程序的开发过程中, 使用DataWindow时, 经常会遇到某列的数据太长, 不能同时全部显示的情况. 若采用自动水平滚动, 操作起来又不够简便，那么我们将如何实现列数据多行显示, 即实现列数据的自动折行呢？

答：具体步骤如下：

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来判断。

→我是小木鱼（Lag）

写于2000年11月30日


数据窗口控件

数据窗口控件与其它控件相似，也是放置在窗口或用户对象上的一个控件，它主要用于显示、修改、更新数据库中的数据。它与数据窗口对象相关联就是整个PowerBuilder程序中的精华。

很难掌握的哟……

→我是小木鱼（Lag）

写于2000年11月29日


如何实现点击列标题对列进行排序?

问：我想实现当点击列标题时上面有一个位图指示并实现对列进行排序，该怎么办呢？

答：也不是很难。如下图：

//实例变量：string i_str_oldcol

string str_objectname,str_curcol,str_addpic
integer int_pic_x

str_objectname=string(dwo.name) //对象名称
if row=0 and this.describe(str_objectname+".band")="header" and this.describe(str_objectname+".text")<>"!" then //是否点击列对象
str_curcol=left(str_objectname,len(str_objectname) - 2) //当前列对象名称
if str_curcol<>i_str_oldcol then //点击的是不同列对象
this.modify("destroy p_sort") //不管有没有位图对象都删除
i_str_oldcol=str_curcol //保存上次点击的列对象
//画图
int_pic_x=integer(this.describe(str_objectname+".x"))+(integer(this.describe(str_objectname+".width")) - 70)
str_addpic='create bitmap(band=foreground filename="up.bmp" x="'+string(int_pic_x)+'" y="24" height="33" width="51" border="0" name=p_sort visible="1")'
this.modify(str_addpic) //动态画个图
this.setsort(str_curcol +" A") //头一次点击当然是升序了
this.sort()
else //当前列已经点过了
if this.describe("p_sort.filename")="up.bmp" then //上次是升序
this.modify("p_sort.filename='down.bmp'")
this.setsort(str_curcol+" D") //这次是降序
else
this.modify("p_sort.filename='up.bmp'")
this.setsort(str_curcol+" A")
end if
this.sort()
end if
end if

→我是小木鱼（Lag）

写于2001年02月20日


如何实现连续页号打印多个数据窗口?

问：在嵌套报表中（NEST）类型中经常需要实现连续页号打印多个数据窗口的情况，这该如何是好呢？

答：关键是要活用《全局变量》：

第一步：建立一个全局变量

integer g_int_page=0

第二步：建立一个全局函数f_setpage()

return g_int_page

第三步：在数据窗口对象中加入一计算域gs_pagenum

page() + f_setpage()
//利用全局涵数来传递全局变量

第四步：在每一个数据窗口控件的printend事件中改变全局变量的值，以使计算域的值发生变化

g_int_page=dw_1.getitemnumber(dw_1.rowcount(),"gs_pagenum")

第五步：当所有窗口打印完毕后将全局变量恢复

g_int_page=0

→我是小木鱼（Lag）

写于2001年01月21日


如何实现两个数据窗口的合并打印?

问：我有两个数据窗口，一个主，一个从数据窗口，那我如何才能实现两个数据窗口中的数据在一张纸上打印呢？

答：数据窗口一般都是打印一个就走一张纸，很难实现同一张纸上打印两个数据窗口，当然也并非完全不可以，但有限制。原理：
第一个DW最好为FREEFORM的风格，第二个DW不能为GRID风格，例如将第一个数据窗口的DETAIL区的一条记录加入到第二个数据窗的HEADER区中，再打印第二个数据窗口，以实现两个数据窗口的合并打印。

代码：

//这里用到两个函数f_print_dw（）与f_print_dw_describe（）

1、打印按纽代码：

//将dw_1中数据与dw_2中数据合并打印
f_print_dw(dw_1,dw_2)

2、f_print_dw（fp_dw_key[datawindow],fp_dw[datawindow]）函数说明

///////////////////////////////
//参数一定要为传址形式 //
//fp_dw_key → reference //
//fp_dw → reference //
/////////////////////////////

//fp_dw_key必须为一自由格式的DATAWINDOW
//本函数实现在同一页纸上打印两个DATAWINDOW
//实现方法
//先把一个数据窗口作为文本对象加入到另一个数据窗口中,然后打印，打印完后再恢复数据窗口
string l_attr_list //数据窗口对象的语法
string l_error
string l_object_list // DWO对象列表,以TAB键分开
string l_object
int l_new_field
int l_pos, l_start
int l_dw_height // 数据窗口fp_dw中header区的高度
int l_dw_key_height // 数据窗口fp_dw_key中detail区的高度

l_dw_key_height = integer(fp_dw_key.describe("datawindow.detail.height"))
l_dw_height = integer((fp_dw.describe("datawindow.header.height")))
//增加DW中HEADER区的尺寸，为DW_key上的东西设置空间
//modify()成功返回空字符串
l_error = fp_dw.modify("datawindow.header.height=" + &
string(l_dw_key_height + l_dw_height))
if l_error <> "" then
l_object = "header"
//发生错误时程序转移
goto Error_City
end if
//将对象移到DW中的开阔区域
// 取得以TAB字符分离的数据窗口fp_dw中DWO对象的列表
l_object_list = fp_dw.describe("datawindow.objects")
l_pos = 0
do // 假定列表不为空
l_start = l_pos
l_pos = pos(l_object_list, "~t", l_start + 1)
if l_pos = 0 then l_pos = 9999
l_object = mid(l_object_list, l_start + 1, l_pos - l_start - 1)
//将header区的所有对象都向下移
if fp_dw.describe(l_object + ".band") = "header" then
//行控件比较特殊，它是X1,X2,Y1,Y2
if fp_dw.describe(l_object+".type")="line" then
fp_dw.modify(l_object + ".y1 ='" + &
string(integer(fp_dw.describe(l_object+".y1")) + &
l_dw_key_height) + "'")
fp_dw.modify(l_object+".y2='" + fp_dw.describe(l_object+".y1") +"'")
else
fp_dw.modify(l_object + ".y ='" + &
string(integer(fp_dw.describe(l_object+".y")) + &
l_dw_key_height) + "'")
end if
end if
loop until l_pos = 9999
//把数据窗口fp_dw_key中的对象以TEXT的形式 COPY 到数据窗口fp_dw中的header区
//取得以TAB字符分离的数据窗口fp_dw_key中DWO对象的列表
l_object_list = fp_dw_key.describe("datawindow.objects")
l_pos = 0
l_new_field = 0
do // 假定列表不为空
l_start = l_pos
l_pos = pos(l_object_list, "~t", l_start + 1)
if l_pos = 0 then l_pos = 9999
l_object = mid(l_object_list, l_start + 1, l_pos - l_start - 1)
l_attr_list = f_print_dw_describe(fp_dw_key, l_object)
if l_attr_list = "" then return false
l_new_field = l_new_field + 1
l_error = fp_dw.modify("create text (" + &
l_attr_list + " name = hdr" + string(l_new_field) + ")")
if l_error <> "" then goto Error_City
loop until l_pos = 9999
// 打印
print(fp_dw)
//如果没有打印机，可以将以下部份RETURN TRUE之前的代码屏蔽起来，就可以看到变化后的后果了
// 恢复数据窗口
// 去除新增加的FIELD
//for l_pos = 1 to l_new_field
// fp_dw.modify("destroy hdr" + string(l_pos))
//next
//// 移动列
//l_object_list = fp_dw.describe("datawindow.objects")
//l_pos = 0
//do
// l_start = l_pos
// l_pos = pos(l_object_list, "~t", l_start + 1)
// if l_pos = 0 then l_pos = 9999
// l_object = mid(l_object_list, l_start + 1, l_pos - l_start - 1)
// if fp_dw.describe(l_object + ".band") = "header" then
// fp_dw.modify(l_object + ".y ='" + &
// string(integer(fp_dw.describe(l_object+".y")) - &
// l_dw_key_height) + "'")
// end if
//loop until l_pos = 9999
//
//// 收宿数据窗口header区
//fp_dw.modify("datawindow.header.height=" + string(l_dw_key_height))
//
return true
////////////////////
Error_City:
messagebox("Error in col " + l_object, l_error)
return false

3、f_print_dw_describe（fp_dw[datawindow],fp_col[string]）

//////////////////////////////////////////////
//fp_dw → reference 传值 //
//fp_col → value 传直 //
// 目的: 描述各列的属性，返回给f_print_dw //
//////////////////////////////////////////////

string l_error
string l_bg_color, l_color, l_fontface, l_height, l_text, l_x, l_y, l_width
string l_fontheight

l_bg_color = fp_dw.describe(fp_col + ".background.color")
if l_bg_color = "!" then
l_error = "bg_color"
goto Error_City
end if
l_color = fp_dw.describe(fp_col + ".color")
if l_color = "!" then
l_error = "color"
goto Error_City
end if
l_fontface = fp_dw.describe(fp_col + ".font.face")
if l_fontface = "!" then
l_error = "fontface"
goto Error_City
end if
l_fontheight = fp_dw.describe(fp_col + ".font.height")
if l_fontface = "!" then
l_error = "fontheight"
goto Error_City
end if
l_height = fp_dw.describe(fp_col + ".height")
if l_height = "!" then
l_error = "height"
goto Error_City
end if
l_width = fp_dw.describe(fp_col + ".width")
if l_width = "!" then
l_error = "width"
goto Error_City
end if
l_x = fp_dw.describe(fp_col + ".x")
if l_x = "!" then
l_error = "x"
goto Error_City
end if
l_y = fp_dw.describe(fp_col + ".y")
if l_y = "!" then
l_error = "y"
goto Error_City
end if
choose case left(fp_dw.describe(fp_col + ".coltype"), 5)
case "char("
l_text = fp_dw.getitemstring(1, fp_col)
case "datet"
l_text = string(fp_dw.getitemdatetime(1, fp_col))
case "numbe"
l_text = string(fp_dw.getitemnumber(1,(fp_col)))
case "!" // 假定为text
l_text = fp_dw.describe(fp_col + ".text")
end choose
l_color = "33554432"
l_bg_color = "1086374080"
return " band = header " + &
" color = '" + l_color + "'" + &
" background.color = '" + l_bg_color + "'" + &
" font.face = '" + l_fontface + "'" + &
" font.height = '" + l_fontheight + "'" + &
" height = '" + l_height + "'" + &
" text = '" + l_text + "'" + &
" width = '" + l_width + "'" + &
" x = '" + l_x + "'" + &
" y = '" + l_y + "'"

Error_City:
messagebox("Error in col " + fp_col, l_error)
return ""

→我是小木鱼（Lag）

写于2001年01月16日


如何实现数据窗口的多行选择?

问：我想在PowerBuilder的数据窗口中实现多行选择，这该如何办呢？

答：作一数据窗口通用对象（UserObject），在CLICKED事件中写入如下代码：

long lng_currentrow,lng_j

if row=0 then
return
else
lng_currentrow=row //当前鼠标点中行
end if
if keydown(keyshift!) then //按下SHIFT键
if i_lng_lastrow=0 then //上次没选中任何行
this.selectrow(lng_currentrow,true)
i_lng_lastrow=lng_currentrow
//i_lng_lastrow为实例变量，记录上次单击的行
else
this.selectrow(0,false) //全都不选中
if lng_currentrow>i_lng_lastrow then
for lng_j=i_lng_lastrow to lng_currentrow
this.selectrow(lng_j,true)
end for
else
for lng_j=i_lng_lastrow to lng_currentrow step -1
this.selectrow(lng_j,true)
end for
end if
end if
else
i_lng_lastrow=lng_currentrow
if keydown(keycontrol!) then //按下CTRL键
if this.isselected(lng_currentrow) then
this.selectrow(lng_currentrow,false)
else
this.selectrow(lng_currentrow,true)
end if
else //无任何键按下
this.selectrow(0,false)
this.selectrow(lng_currentrow,true)
end if
end if

在窗口的OPEN事件中写入如下代码：

dw_1.object.datawindow.readonly=true

→我是小木鱼（Lag）

写于2001年01月16日


单击数据窗口中的列对象进行排序

问：我想通过单击数据窗口中的列对象来对表进行排序，这该如何办到呢？

答：这还不简单：

一、在窗口中声明二实例变量：

//取得上次单击的列对象
string i_str_precolumn=""
//判断上次是按升还是按降来排序
integer i_int_clicktime=0

二、在数据窗口控件中的单击事件中写入以下代码：

string str_column,str_format

str_column=dwo.name //取点击的对象
if right(str_column,2) <> "_t" then return
//对于列标题，取得的对象是列名+"_t"
str_column=left(str_column,len(str_column) - 2)
if str_column=i_str_precolumn then //已点击过
if i_int_clicktime=0 then //0表示原来按降序
i_int_clicktime=1
str_format=str_column + " A"
else
i_int_clicktime=0
str_format=str_column + " D"
end if
else
i_int_clicktime=1 //1表示原来按升序
str_format=str_column + " A"
end if
i_str_precolumn = str_column
dw_1.SetSort(str_format)
dw_1.Sort()

→我是小木鱼（Lag）

写于2000年12月21日


如何动态实现打印不固定的数据列?

问：我做一个程序，其中的一个功能是：例如：数据库。雇员（序号，姓名，年龄，性别，出生年月，学历，职务，工资，等等）。客户要求在程序的运行中进行选择（对表的项任意选），然后打印出来。如选择姓名，年龄，出生。则打印姓名，年龄，出生。又如选择姓名，工资。则打印姓名，工资。我不知道如何去实现？

答：有二种方法可以实现上述问题：

方法一：(简单)

建数据窗口对象时，选用Grid风格(Grid风格数据窗口的字段宽度可以随意拖动，如同Excel)，不需要打印的字段可以随时将其宽度拖动为零。我认为这种方法比较好，我们单位工资表的打印就是采用这种方法，不过得作一 *.ini配置文件，将各列的宽度记录下来(如：with=12!20!25!16!0!0!12!21!15)，这样以后就可一直采用此宽度了。

方法二：(复杂)

用列表框显示出所有的列，可以多选高亮列。通过Modify函数动态定义选中列的位置，宽度以及是否可见等属性(这得把人累死)。

→我是小木鱼（Lag）

写于2000年12月20日


如何实现数据窗口控件中某一列的增量查询?

问：请问在PB的数据窗口中怎样实现某一列的增量查询功能，就是说在单行编辑器控件中每输入一个字符，数据窗口能找到这一列值左边部分与单行编辑器中内容相等的行，并加亮显示。例如数据窗口是按整型字段“ID”升序排列的，用户在单行编辑器中输入1，则数据窗口滚动到ID字段第一位为“1”的第一行并加亮显示；再在1后输入0，则数据窗口滚动到ID字段前两位为“10”的第一行，依次类推？

答：增量查询功能实现的关键有两点，一是单行编辑器能实时响应键盘的输入，捕捉每一个按键，获得其中的文本；二是数据窗口的模糊查询功能，即能够找到列ID左边文本与单行编辑器文本相等的行，这可以用“like”来实现。下面给出具体方法：

    1．定义单行编辑器的用户事件ue_enchange，事件的ID为：pbm_enchange。这个事件能响应键盘的输入。
2．在单行编辑器的ue_enchange事件中编写如下脚本：
long lng_found_row
string str_find

//查找条件（左部分与单行编辑器文本相等）
str_find = "ID like " + "'" + this.text +
"%'"
//查找符合条件的行
lng_found_row = dw_name.Find(str_find, 1, dw_name.RowCount())
if lng_found_row <= 0 then return
//滚动到相匹配的行
dw_name.ScrollToRow(lng_found_row)
dw_name.SelectRow(0 , false)
//将匹配行加亮显示
dw_name.SelectRow(lng_found_row , true)

[注]Find()函数

用法： | dwcontrol.Find( expression , start , end )
说明： | 查找满足条件的下一行。
返回值： | long，返回指定范围内满足查找条件的第一个数据行的行号；未找到返回0；出错返回-1。
参数 | 类型及说明
dwcontrol | 数据窗口控件名。
expression | string，用于指定要查找的条件，其值是个逻辑表达式，表达式中可以使用列名。
start | long，用于指明从哪一行开始查找。该参数可以大于数据的总行数。
end | long，用于指明查找到哪一个结束查找。该参数可以大于数据的总行数，如果想从后向前找，那么让end参数的值小于start参数即可。

→我是小木鱼（Lag）

写于2000年12月04日


如何取得复合报表中的计算域的值？

问：我想取得复合窗口(或报表)中的计算域的值，这该如何办呢？

答：跟取得一般数据窗口中的计算域差不多。

对于一般类型的数据窗口，我们可以用这种办法：先为计算域取名，如“count_id”，取值过程如下（除了分组的数据窗口，一般计算域都用1）：
    long lng_count_id
    lng_count_id = dw_1.getitemnumber(1,"count_id")

    而对于复合报表(或窗口)，须先用GetChild()函数得到其中的report，再取此report中计算域的值。假设此 report name 为“report_department”（注意不要混淆report name 与子数据窗口本身的名字），计算域名为count_id，则取值过程如下：
    DataWindowChild dwc_child
    long lng_count_id
    dw_1.GetChild("report_department",dwc_child)
    lng_count_id = dwc_child.getitemnumber(1,″count_id″)

[注]GetChild()函数

语法： | dwcontrol.GetChild( name , dwchildvariable )
说明： | 得到指定子数据窗口的引用并将其保存到变量中，然后应用程序就可以使用该变量来操作子数据窗口对象。
返回值： | Integer，1表示成功，-1表示失败。
参数 | 类型及说明
dwcontrol | 数据窗口控件名。
name | string，列名，该列包含了欲得到引用的子数据窗口对象。
dwchildvariable | DataWindowChild，用于存储该函数得到的子数据窗口对象的引用。
用法： | 这里所说的子数据窗口包括两方面的意义：一是数据窗口对象中的下拉数据窗口(DropDownDataWindow)，一是复合风格数据窗口对象中的子报表。注意，在创建复合风格的数据窗口对象时，它使用的子报表必须要设置其Name属性，否则不能引用。

例子：

本例中，主数据窗口的emp_state列是个子数据窗口对象，该子数据窗口对象需要一个"地区"值为提取参数，为了不让PowerBuilder显示输入提取参数的对话框，代码中首先检索了子数据窗口的数据，之后再提取主数据窗口的数据：

DataWindowChild state_child //说明一个DataWindowChild类型的变量
integer int_returncode

//得到名称为emp_state的子数据窗口对象的引用
int_returncode=dw_1.getchild("emp_state",state_child)
if int_returncode=-1 then messagebox("错误","不是子数据窗口")
connect using sqlca;
state_child.settransobject(sqlca)
state_child.retrieve("East")
//设置主数据窗口使用的事务对象并提取数据
dw_1.settransobject(sqlca);
dw_1.retrieve()

→我是小木鱼（Lag）

写于2000年12月04日


如何得到数据窗口中的所有列名及其text的文字说明?

问：我想做一个数据窗口的组合条件查询，要得到数据窗口中的所有列名及其text的文字说明，请问怎样才能取得？

答：Describe()函数可以得到数据窗口的多项属性值，用它实现如下：

long lng_column_count
integer i
string str_column[] //列名
string str_column_text[]　　//text的名字

    //得到数据窗口的总列数
lng_column_count =
long(dw_1.Describe("DataWindow.Column.Count"))
//循环依次读取
for i = 1 to lng_column_count
str_column[i] = dw_1.Describe("#"＋string(i)＋".name")
str_column_text[i] = dw_1.Describe(str_column[i] ＋
"_t.text")
next

    //说明：数组str_column[]保存当前数据窗中所有列名，数组ls_column_text[]保存当前数据窗中列对应的text的文字说明。
 //注：数据窗口dw_1的对象（DataObject）中text命名须用默认值，即列名＋ _t的形式，如列名为“name”，则其对应text应取名为“name_t”，否则返回值不正确。

→我是小木鱼（Lag）

写于2000年12月04日


如何取得数据窗口中下拉数据窗口的显示值?

问：我想取得数据窗口中下拉数据窗口的显示值，但getitem...()只能得到实际值，有什么办法得到显示值吗？

答：这么做：

dw_1.Describe ( "Evaluate('LookupDisplay(column_naem)',4)" )

[注]Describe()函数

说明： | 返回数据窗口控件结构方面的指定信息，包括DataWindow对象以及数据窗口对象中其它对象的属性取值。使用Describe()函数也可以计算表达式的值，表达式中可以使用指定行/列的值。
语法： | dwcontrol.Describe( propertylist )。
返回值： | string，它是由对应于propertylist中各属性的具体取值构成，用换行字符(~n)分隔。
参数 | 类型及说明
dwcontrol | 数据窗口控件名。
propertylist | 属性列表，字符串，由要查看其取值的一个或多个属性或表达式组成，用空格分隔。
例子： | str_bandname=dw_1.describe("datawindow.bands")
结果： | header~tdetail~tsummary~tfooter。

[注]Evaluate()函数

说明： | 可以把它作为Describe()函数的参数来计算数据窗口画笔表达式的值。
语法： | Evaluate( "expression" , rownumber)
返回值： | 字符串型。
参数 | 类型及说明
expression | 希望计算其值的数据窗口画笔表达式。
rownumber | 数据行的行号，画笔表达式根据该行的数据计算其值。
例子： | 下面的语句根据数据窗口第3行salary列的值返回255或0：
str_ret=dw_1.Describe("Evaluate('if(salary>100000,255,0)',3)")

→我是小木鱼（Lag）

写于2000年12月01日


如何判断CTRL+W复合键?

问：我想在数据窗口控件中判断用户是否按下CTRL+W复合键来保存数据该如何做呢？

答：让我思考、思考：

创建数据窗口控件自定义事件 ue_keydown() ，Event ID 为 pbm_dwnkey ：

If KeyDown(KeyControl!) and KeyDown(KeyW!) Then
Messagebox("ok","你按的是CTRL+W键")
End if

//这样的话可以判断各种复合按键

→我是小木鱼（Lag）

写于2000年11月30日


如何利用左右键及回车键来转移列的焦点?

问：请问如何实现利用左右键及回车键进行列的焦点转移?

答：这要用到Windows中的API函数keybd_event()

①定义API：
Subroutine keybd_event(uint bVk,uint bScan,long dwFlags,long dwExtraInfo ) library
"user32.dll"

②自定义一用户事件(ue_keydown  ID:pbm_dwnkey)：
integer VK_TAB = 09
integer VK_SHIFT = 16

if key = KeyLeftArrow! then
keybd_event(VK_SHIFT,0,0,0) //按下shift
keybd_event(VK_TAB,0,0,0) //按下tab
keybd_event(VK_TAB,0,2,0) //释放tab
keybd_event(VK_SHIFT,0,2,0) //释放shift
return 1
end if
if key = KeyRightArrow! or key=KeyEnter! then
keybd_event(VK_TAB,0,0,0) //按下tab
keybd_event(VK_TAB,0,2,0) //释放tab
return 1
end if

如若只是想利用ENTER键来实现TAB键的功能可以用以下代码：
if key=keyenter! then
Send(Handle(this),256,9,Long(0,0)) //发送TAB键
    Return 1 //取消原ENTER键的动作
end if

[注]keybd_event()函数

说明： | 这个函数模拟了键盘行动。
参数 | 类型及说明
bVk | 欲模拟的虚拟键码。
bScan | 键的OEM扫描码。
dwFlags | Long，零；或设为下述两个标志之一
 | &H1 | 指出是一个扩展键，而且在前面冠以0xE0代码。
 | &H2 | 模拟松开一个键。
dwExtraInfo | Long，通常不用的一个值。api函数GetMessageExtraInfo可取得这个值。允许使用的值取决于特定的驱动程序。

→我是小木鱼（Lag）

写于2000年11月29日


浅析用户自定义事件中的ID含义

问：在用户自定义事件中Event ID的具体含义到底是什么呢？

答：下面我们解释一下PowerBuilder中以pbm开头的内部映射事件的含义,按类举一些主要例子,其余的事件类推。

Event ID 含义 | 内容浅析
单选或多选按钮消息（前缀:pbm_bm）
pbm_bmgetcheck | 单选按钮或多选按钮是否被选。
pbm_bmgetstate | 按钮是否加亮。
pbm_bmsetcheck | 将无线按钮或确认框的选中状态改为未选中状态,反之亦然。
pbm_bmsetstate | 加亮或不加亮按钮。
pbm_bmchange | 改变按钮的风格,例如,改为单选按钮或组合框。
单选或多选按钮通知消息（前缀:pbm_bn）
pbm_bnclicked | 按钮控件被点中。
pbm_bndisable | 使按钮控件无效。
pbm_bndoubleclicked | 按钮控件被双点。
pbm_bndragdrop | 一个对象被放到按钮控件。
pbm_bndragenter | 一个对象被拖到按钮控件。
pbm_bndragleave | 一个对象被拖离按钮控件。
pbm_bndragover | 一个对象被拖经按钮控件。
pbm_bnhilite | 按钮控件被加亮。
pbm_bnpaint | 按钮控件被绘制。
pbm_bnsetfocus | 按钮控件获得聚焦。
pbm_bnunhilite | 按钮控件不被加亮。
通用对话框消息（前缀:pbm_cb）
pbm_cbaddstring | 将字符串加到通用对话框。
pbm_cbdeletestring | 从通用对话框删除一个字符串。
pbm_cbdir | 加一个目录列表到通用对话框。
pbm_cbfindstring | 搜索以一组字符开头的字符串。
pbm_cbfindstringexact | 搜索与所提供的字符完全匹配的字符串。
pbm_cbgetcount | 列表框中的项数。
pbm_cbgetcursel | 当前被选项的数目。
pbm_cbgetdroppedcontrolset | 列表框在屏幕上的坐标位置。
pbm_cbgeteditsel | 编辑器控件中被选字符的范围。
pbm_cbgetextendedui | 缺省或扩展的用户界面。
pbm_cbgetitemdata | 重画的列表框中的4字节(32位)项。
pbm_cbgetitemheight | 列表框中某一项的高度。
pbm_cbgetlbtext | 列表框中的文本。
pbm_cbgetlbtextlen | 列表框中文本的长度。
pbm_cbinsertstring | 向列表框中增加新的字符串或4字节项。
pbm_cblimittext | 限制能被输入到列表框中的字符数。
pbm_cbresetcontent | 删除列表框中所有元素。
pbm_cbselectstring | 搜索匹配的字符串并显示。
pbm_cbsetcursel | 在列表框中选择并显示一项。
pbm_cbseteditsel | 在列表框的编辑区域中选择一块文本。
pbm_cbsetextendedui | 设置缺省或扩展的用户界面。
pbm_cbsetitemdata | 在列表框中设定4字节(32位)项。
pbm_cbsetitemheight | 设置列表框中项的高度。
pbm_cbshowdropdown | 转换(显示或隐藏)列表框中拖放区域。
通用对话框通知消息（前缀:pbm_cbn）
pbm_cbndblclk | 用户在列表中某一项上双点。
pbm_cbndragdrop | 一个对象被放到通用对话框控件上。
pbm_cbndragenter | 一个对象被拖到通用对话框控件上。
pbm_cbndragleave | 一个对象被拖离通用对话框控件。
pbm_cbndragover | 一个对象被拖经通用对话框控件。
pbm_cbndropdown | 列表框的下放区域即将被显示。
pbm_cbneditchange | 编辑器控件中的文本发生变化。
pbm_cbneditupdate | 列表框编辑器控件中的文本即将被改变。
pbm_cbnerrspace | 列表框满,不能再向其中加入项。
pbm_cbnkillfocus | 通用列表框失去聚焦。
pbm_cbnselchange | 列表框中被选文本被改变。
pbm_cbnselendcancel | 用户按下了"取消"按钮。
pbm_cbnselendok | 用户按下了"确认"按钮。
pbm_cbnsetfocus | 通用对话控件拥有聚焦。
数据窗口消息（前缀:pbm_dw）
pbm_dwclosedropdown | 关闭下拉式数据窗口。
pbm_dwscrollend | 在数据窗口中卷滚到最后一行。
pbm_dwscrollhome | 在数据窗口中卷滚到第一行。
pbm_dwscrolllineend | 卷滚到当前行的行尾(水平方向)。
pbm_dwscrolllinehome | 卷滚到当前行的行首(水平方向)。
数据窗口通知消息（前缀:pbm_dwn）
pbm_dwnbacktabout | 即将通过Shift+Tab组合键离开该控件。
pbm_dwnchanging | 控件即将被改变。
pbm_dwndropdown | 下拉式列表框的下拉部分即将可见。
pbm_dwngraphcreate | 即将创建图形。
pbm_dwnitemchangefocus | 数据窗口控件中当前项的聚焦改变。
pbm_dwnitemvalidationerror | 对当前项的修改引起了一个合法性检查错误。
pbm_dwnkey | 有键被按下。使用KeyDown()处理键盘值。
pbm_dwnlbuttondown | 鼠标左键被按下。
pbm_dwnlbuttonup | 鼠标左键被松开。
pbm_dwnmbuttonclk | 鼠标中键点击。
pbm_dwnmbuttondbclk | 鼠标中键双击。
pbm_dwnmousemove | 鼠标移动。
pbm_dwnprintmarginchange | 打印边界被改变。
pbm_dwnprocessenter | 回车键被按下。
pbm_dwnrowchange | 数据窗口中聚焦从一行转向另一行。
pbm_dwntabdownout | 用户在数据窗口最后一行按了下箭头键。
pbm_dwntabout | 用户在数据窗口的最后一行/列中按了tab键。
pbm_dwntabupout | 用户在数据窗口第一行中按了上箭头键。
动态数据交换(DDE)消息（前缀:pbm_dde）
pbm_ddeddeack | 收到一个DDE消息。
pbm_ddeddeinitiate | 开始一个DDE会话。
pbm_ddeddeterminate | 终止一个DDE会话。
编辑器控件消息（前缀:pbm_em）
pbm_emcanundo | 编辑器控件是否能撤消上一次修改。
pbm_ememptyundobuffer | 清空由Windows管理的取消操作的缓冲区。
pbm_emfmtlines | 在多行编辑器控件的行尾增加或删除回车换行。
pbm_emgetfirstvisibleline | 返回编辑器控件中可见的第一行的行号。
pbm_emgethandle | 获得编辑器控件使用的内存句柄。
pbm_emgetline | 从编辑器控件中复制一行到内存中的一个缓冲区。
pbm_emgetlinecount | 返回多行编辑器控件的行数。
pbm_emgetmodify | 文本是否被用户修改。
pbm_emgetrect | 返回控件的长方形域。
pbm_emgetsel | 返回被选文本的起始位置。
pbm_emlimittext | 限制用户键入的文本长度。
pbm_emlinefromchar | 返回被选文本的行号。
pbm_emlineindex | 返回编辑器控件中被选行第一个字符在编辑串中的位置。
pbm_emlinelength | 返回编辑器控件中被选行中的字符数。
pbm_emlinescroll | 水平或垂直卷滚编辑器控件。
pbm_emreplacesel | 从剪贴板或从键盘上用新文本替换被选文本。
pbm_emsethandle | 设置编辑器控件的句柄指向内存中的一个缓冲区。
pbm_emsetmodify | 设置编辑器控件的modified标志。
pbm_emsetpasswordchar | 设置用户输入任何文本时显示的字符,在输入密码时的显示。
pbm_emsetrect | 设置/重置编辑器控件所在的长方形区域,编辑器控件中的文本被重画。
pbm_emsetrectnp | 除了不重画文本,大致与setrect相同。
pbm_emsetsel | 选择字符。
pbm_emsettabstops | 在多行编辑器控件中设置tabstops。
pbm_emsetwordbreak | 设置新的词拆分函数。
pbm_emsetwordbreakproc | 设置新的词拆分过程。
pbm_emundo | 撤消最近的编辑操作。
编辑控件通知消息（前缀:pbm_en）
pbm_enchange | 编辑器控件中的文本发生改变。
pbm_enerrspace | 编辑器控件内存缓冲区溢出。
pbm_enhscroll | 用户点中上水平卷滚条。
pbm_enmaxtext | 用户试图输入比允许更多的文本。
pbm_enupdate | 编辑器控件即将显示用户的修改。
pbm_envscroll | 用户点中了垂直卷滚条。
列表框消息(前缀:pbm_lb)
pbm_lbaddstring | 向列表框控件中增加一项或一个字符串。
pbm_lbdeletestring | 从列表框中删除一项或一个字符串。
pbm_lbdir | 用目录列表填充列表框。
pbm_lbfindstring | 在列表框中搜索与所给字符串部分匹配的第一项。
pbm_lbfindstringexact | 在列表框中搜索与所给字符串精确匹配的第一项。
pbm_lbgetcaretindex | 在列表框中搜索拥有聚焦的项。
pbm_lbgetcount | 确定列表框中的项数。
pbm_lbgetcursel | 确定所选项是第几项。
pbm_lbgethorizontalextent | 获得列表框的宽度、计算水平卷滚。
pbm_lbgetitemheight | 确定列表框控件中项的高度。
pbm_lbgetitemrect | 确定列表框的尺寸。
pbm_lbgetsel | 获得列表框中当前所选的项。
pbm_lbgetselcount | 在多选列表框中获得所选项的数目。
pbm_lbgetselitems | 用列表框中表框各自的项号填充一个给定的整数数组。
pbm_lbgettext | 获得列表框中当前所选项的文本。
pbm_lbgettextlen | 获得列表框中当前所选项的文本中的字符数。
pbm_lbgettopindex | 确定列表框中可见的最上面一项的项号。
pbm_lbinsertstring | 向列表框中加入一个新字符串。
pbm_lbresetcontent | 重置(消除)列表框中的内容。
pbm_lbselectstring | 搜索并加亮与所给字符匹配的字符串。
pbm_lbselitemrange | 选择/取消列表框中某一范围中的项。
pbm_lbsetcaretindex | 设置列表框中的某一项拥有聚焦。
pbm_lbsetcolumnwidth | 设置列表框中列的宽度。
pbm_lbsetcursel | 在列表框中选择并加亮一项;如果需要,卷滚到列表框。
pbm_lbsethorizontaltext | 设置列表框中被水平卷滚的单元数。
pbm_lbsetitemdata | 设置与列表框相关的32位/4字节值。
pbm_lbsetitemheight | 设置列表框中项的高度。
pbm_lbsetsel | 在列表框中选择一个字符串。
pbm_lbsettabstops | 设置列表框控件中tabstops的位置。
pbm_lbsettopindex | 卷滚列表框使特定的项成为可见的最上面一项。
列表框通知消息（前缀:pbm_en）
pbm_endblclk | 用户在列表框控件中的某一项上双击。
pbm_enerrspace | 用户试图超越可在列表框中输入字符的最大限制。
pbm_enselcancel | 当前选取文本被取消。
pbm_enselchange | 用户在列表框中选择或取消了一项。
窗口消息（前缀:pbm_）
pbm_activateapp | 被激活的窗口属于另外一个应用。
pbm_askcbformatname | 要求剪贴板中的内容被复制到一个使用自定义格式的文本缓冲区中。
pbm_char | 传送键盘上按下的键。
pbm_chartoitem | 通过转换键盘来的字符,帮助列表框定位其中的项。
pbm_childactivate | 一个子窗口被移动或激活。
pbm_clear | 用户要删除当前编辑器控件中的内容。
pbm_command | 用户选择了一个菜单项、控件,或使用了加速键。
pbm_compacting | 系统内存资源不足;当Windows占用了多于1/8的CPU时间紧缩内存时,产生这条消息。
pbm_compareitem | 当新的一项被加入列表框或组合框时产生此消息,Window用这条消息进行项之间的比较。
pbm_ctlcolor | 一个控件即将被画出,可在此时改变控件的颜色。
pbm_deadchar | 用户选择了一种非英语字符集或其它特殊字符集,这将改变下面将要输入的字符。
pbm_deleteitem | 从列表框或通用对话框中移去一项。
pbm_destroyclipboard | 剪贴板内容被清除。
pbm_devmodechanged | WIN.INI中的一个设备名被修改。
pbm_drawclipboard | 剪贴板内容发生改变。
pbm_drawitem | 列表框或通用对话框的一项内容被改变。
pbm_dropfiles | 当鼠标左键在一个注册为拖放文件接受器的应用上释放时,发出该消息。
pbm_erasebkgnd | 窗口的客户区需要重画。
pbm_fontchange | 应用可用的字体数改变。
pbm_getdlgcode | 通知消息,说明当前使用哪种类型的键盘。
pbm_getfont | 获取当前激活的字体。
pbm_getminmaxinto | Windows正在检查最小化或最大化窗口的尺寸。
pbm_gettext | 从一个控件(如按钮或编辑器控件)中复制文本到一个内存缓冲区。
pbm_gettextlength | 用来确定一个控件中的字符数。
pbm_hscrollclipboard | 剪贴板的水平卷滚条被使用。
pbm_iconerasebkgnd | 一个最小化窗口需要重化背景。
pbm_initdialog | 一个对话框即将被显示。
pbm_initmenu | 一个菜单即将被显示。
pbm_initmenupopup | 一个弹出式窗口即将被显示。
pbm_keydown | 键盘上的一个键被按下。
pbm_keyup | 键盘上的一个键被释放。
pbm_mdiactive | 一个MDI子窗口(表单)被激活。
pbm_mdicascade | 以重叠的形式重排所有的表单。
pbm_mdicreate | 创建一个表单。
pbm_mdidestroy | 从MDI框架中移去一个表单。
pbm_mdigetactive | 获得当前活动的MDI表单的句柄。
pbm_mdiiconrange | 在一个MDI框架中重排最小化表单的图标。
pbm_mdimaximize | 最大化一个MDI子表单。
pbm_mdinext | 激活下一个MDI表单(紧接着活动表单的表单)。
pbm_mdirestore | 把MDI表单恢复到它原来的大小。
pbm_mdisetmenu | 将一个菜单与一个MDI表单联系起来。
pbm_mdifitle | 平铺所有的MDI表单。
pbm_measureitem | 这个消息被送给即将创建的、内有按钮或其它控件的窗口。
pbm_menuchar | 用户使用了一个快捷键,但系统不支持该快捷键。
pbm_menuselect | 用户选择了一个菜单项。
pbm_mouseactivate | 用户在一个非活动窗口中点击了鼠标。
pbm_mousemove | 用户移动了鼠标。
pbm_ncactivate | 窗口的非客户区即将被激活。
pbm_nccalcsize | 窗口的尺寸需要重新计算。
pbm_nccreate | 窗口即将创建它的非客户区。
pbm_ncdestroy | 窗口的非共享区被析构。
pbm_nchittest | 每次非客户区被移动时都发送该消息。
pbm_nclbuttondblclk | 用户在非客户区双点了鼠标左键。
pbm_ncpaint | 非客户需要画出。
pbm_nextdlgctl | 在对话框中将聚焦转给另一个控件。
pbm_paint | 窗口的客户区需要被画出。
pbm_paintclipboard | 剪贴板应用有剪贴操作,剪贴板查看器需重画。
pbm_palettechanged | 系统调色板被改变。
pbm_paletteischanging | 系统调色板即将被改变。
pbm_parentnotify | 通知父窗口一个子窗口即将被创建。
pbm_querydragicon | 用户要拖一个最小化窗口。
pbm_queryendsession | 通知消息,说明窗口即将被关闭。
pbm_querynewpalette | 应用即将收到输入聚焦,应该执行必要的颜色调整。
pbm_queryopen | 一个最小化窗口即将被恢复。
pbm_quit | 应用处理的最后一个消息。
pbm_renderallformats | 通知一个剪贴板格式的拥有者,应用将失去所有的格式。
pbm_renderformats | 通知消息,说明放在剪贴板中的数据应该用一种特殊格式传送。
pbm_setcursor | 通知消息,说明鼠标指针在一个窗口中移动。
pbm_setfont | 用来在对话框中改变字体。
pbm_setredraw | 在加一个新项之前发送给列表框或通用对话框。
pbm_settext | 用来改变窗口的标题或文本。
pbm_sizeclipboard | 剪贴板查看器应用改变尺寸。
pbm_spoolerstatus | 一个打印管理器任务被添加或删除。
pbm_syschar | <ALT>键和其它某键同时被按下。
pbm_syscolorchange | 一种或多种系统颜色被改变。
pbm_syscommand | 用户选择了一个系统菜单命令。
pbm_sysdeadchar | 通知消息，说明一种非英语字符集被选定。
pbm_syskeydown | 用户按下某键的同时按下了<ALT>键。
pbm_syskeyup | 用户释放了<ALT>组合键。
pbm_timechange | 系统时钟被修改。
pbm_undo | 从undo缓冲区复制文本到编辑器控件。
pbm_vkeytoitem | 当一个列表框拥有聚焦时,用户按下了一个键。
pbm_vscroll | 用户点击了垂直卷滚条。
pbm_vscrollclipboard | 剪贴板查看器的垂直卷滚条被点击。
pbm_windowposchanged | 窗口位置发生改变。
pbm_windowposchanging | 窗口位置即将发生改变。
pbm_wininichange | WIN.INI文件被修改。

→我是小木鱼（Lag）

写于2000年11月29日


如何在PowerBuilder中实现串口编程?

问：我想在PowerBuilder中实现对有关串口的编程，这该如何实现呢？

答：可以利用微软公司提供的通讯控件mscomm32.ocx来实现，使用方法如下：
 选择菜单Controls→OLE→Insert Control→Microsoft Communications Control，加入后我们点击其OLE Control Properties，可以设置它的基本属性如通讯端口(C)、设置参数 (S) 等，当然我们也可以在程序中动态设置。以下是一段脚本例子：
    String ls_data
    ole_1.object.CommPort = 1 //使用COM1端口
    ole_1.object.Settings = "9600,N,8,1" //设置或返回串行端的波特率、奇偶校验位、 数据位数、停止位
    ole_1.object.InputLen = 0 //初始化Input
    ole_1.object.PortOpen = True //打开端口
    ole_1.Object.Output = "h" //向COM口发送字符
    Do
         Yield() //等待数据
    LOOP Until ole_1.Object.InBufferCount >= 1
    ls_Output = ole_1.Object.Input //取数据
    ole_1.object.PortOpen = FALSE //关闭端口

→我是小木鱼（Lag）

写于2000年12月20日


如何注册OCX控件?

问：我写的系统中带了OCX控件，当系统编译后发行时必须带上该OCX控件，但在用户的机子上必须注册该OCX控件才能使用，否则程序运行会出错，是否要通过程序来注册该OCX控件或者还有其它的方法？

答：提供以下几种方法：
1、在DOS或Windows命令行下运行：regsvr32 ocxname.OCX 注册。
2、用Install Shield，在里面选“Self-Registered”，安装程序将自动注册。
3、在PB应用程序中注册：
函数声明：
Function long DllRegisterServer() Library "ocxname.OCX"
调用：
LONG ll_RC
ll_RC = DllRegisterServer()

怎么样，你会了吗？

→我是小木鱼（Lag）

写于2000年11月30日


如何在PowerBuilder中加载声音文件?

问：请教各位，如何将声音文件在PowerBuilder中播放，请具体说明一下好吗？

答：可利用"winmm.dll"(在windows\system下)

①声明函数：
 Function boolean sndPlaySoundA (string SoundName, ulong Flags) Library "WINMM.DLL"

②脚本：
SndPlaySoundA( " c:\windows\media\Notify.wav " , 1 )

→我是小木鱼（Lag）

写于2000年11月30日


其它问题

其实PowerBuilder只是一种前端开发工具，它有很多方面都是借助Windows中的API函数来实现的，因此我在这里收集了一些比较常见的非PowerBuilder的有关Windows方面的问题，看一看还是很有帮助的哟……

→我是小木鱼（Lag）

2000年11月27日完成此页


如何在应用程序中启动控制面板?

问：我想在应用程序中启动控制面板中的密码选项，这该如何办呢？

答：要想在应用程序中启动控制面板，只需用ShellExecute函数打开对应的CPL文件即可，例如要在应用程序中修改Windows密码，只需打开Password.cpl文件，启动ODBC管理器只要打开ODBCCP32.CPL即可。

函数声明：
Function Long ShellExecute(Long hwindow, String lpOperation, String lpFile, String lpParameters, String lpDirectory, Long nShowCmd) Library 'shell32.dll' Alias for ShellExecuteA
Function Long GetDesktopWindow() Library 'user32.dll'

脚本如下：
String ls_cpl_name
String ls_null

SetNull(ls_null)
ls_cpl_name = "Password.cpl"

ShellExecute(GetDesktopWindow(), ls_null, 'rundll32.exe', "shell32.dll,Control_RunDLL " + ls_cpl_name + ",", ls_null, 0)

[注]ShellExecute()函数

说明： | 查找与指定文件关联在一起的程序的文件名。
参数 | 类型及说明
hwnd | Long，指定一个窗口的句柄，有时候，windows程序有必要在创建自己的主窗口前显示一个消息框。
lpOperation | String，指定字串“open”来打开lpFlie文档，或指定“Print”来打印它。
lpFile | String，想用关联程序打印或打开一个程序名或文件名。
lpParameters | String，如lpszFlie是可执行文件，则这个字串包含传递给执行程序的参数。
lpDirectory | String，想使用的完整路径。
nShowCmd | Long，定义了如何显示启动程序的常数值。参考ShowWindow函数的nCmdShow参数。

→我是小木鱼（Lag）

写于2000年12月21日


当在程序中运行DOS命令时如何隐藏DOS窗口并判断其结束?

问：我想在程序中运行有关DOS命令，可又不想让用户看到DOS窗口，并想判断一下DOS命令是否已运行结束，难死我了？

答：你的要求也太高了，这样试试吧：

第一步：定义全局外部函数：

Function long ShellExecuteA (long hwnd, string lpOperation ,String lpFile, String lpParameters, String lpDirectory, Long nShowCmd) Library "shell32.dll"
Function long FindWindowA (String lpClassName , String lpWindowName ) Library "user32.dll"
Function boolean IsWindow (Long hwnd ) Library "user32.dll"

[用API函数，可以隐藏应用程序的窗口，但是调用bat批处理命令时需要先建立一个PIF(批处理命令的快捷键方式)文件指定执行完成后关闭窗口(其中的一个属性)，否则窗口不会自行关闭。]

第二步：在窗口上建立按扭，clicked事件中包含如下Script:

ulong ll_handle,lu_return
string ls_path

SetPointer(HourGlass!) //设置鼠标指针
//运行DOS批处理命令的快捷键方式，并将其窗口隐藏
lu_return = ShellExecutea(handle(parent), "open", "xxx.pif", "", ls_path, 0)
//最后一个参数改为 4，可以显示执行情况，0为隐藏窗口
if lu_return>32 then
 ll_handle = 0
//循环至DOS窗口打开
Do While ll_handle = 0
ll_handle = FindWindowA("tty","xxx")
yield()
loop
//等待DOS窗口关闭
Do While isWindow(ll_handle)
Yield()
Loop
//应用执行完成
MessageBox("提示信息", "运行完毕!")
end if

  相关资料：如何实现数据库的备份？

→我是小木鱼（Lag）

写于2000年12月20日


如何在程序中自动切换中英文输入法?

问：我想在程序中自动切换中英文输入法，将如何实现呢？

答：用Windows的API函数可以办到。

①定义API：
function boolean ImmSimulateHotKey (ULong hWnd, ULong dwHotKeyID) library "IMM32.dll"
function ulong GetKeyboardLayout(ulong dwLayout) LIBRARY "user32.dll"
function boolean ImmIsIME(uLong hklKeyboardLayout) library "IMM32.DLL"

②脚本：
ulong hklCurrent
ulong hnd

//切换到英文输入法
hklCurrent=GetKeyboardLayout(0)
if ImmIsIME(hklCurrent) then
hnd=Handle(parent)
ImmSimulateHotKey(hnd,112)
end if

//切换到中文输入法
hklCurrent=GetKeyboardLayout(0)
if not ImmIsIME(hklCurrent) then
hnd=Handle(parent)
ImmSimulateHotKey(hnd,112)
end if

<对其它的两个API函数尚无资料，并似乎也好象不太好使，只是一种思路而已! →小木鱼>

[注]GetKeyboardLayout()函数

说明： | 取得一个句柄，描述指定应用程序的键盘布局。
返回值： | ulong，键盘布局的句柄。
参数 | 类型及说明
dwLayout | ulong，欲检查的线程的标识符。

→我是小木鱼（Lag）

写于2000年12月05日


如何在PowerBuilder中使用反三角函数？

问：我发现在PowerBuilde中没有反三角函数，这该如何办呢？

答：确实如此，PB中只提供了三角函数如sin()、cos()，要想使用反三角函数须借助于数据库。

一般数据库如Sybase SQL Anywhere、MS SQL SERVER等都提供反三角函数，使用方法select 函数名(参数) into 变量……
//如在Sybase SQL Anywhere 5 中：
    double ldb_value
    SELECT asin(search.id) INTO :ldb_value FROM search　WHERE search.id = 1；

    如果是对一般的内存变量的反三角计算可用变通的办法：
    double ldb_value = 1
    double ldb_asin
    SELECT asin( :ldb_value ) INTO :ldb_asin FROM department;

→我是小木鱼（Lag）

写于2000年12月04日


如何得到一个应用程序如 EXCEL 的路径?

问：我想在PowerBuilder中得到EXCEL的安装路径，这该如何实现呢？

答：这你只好到WINDOWS注册表中去查找了。

string str_excel_path
RegistryGet ("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\Excel.exe","Path", Regstring!,str_excel_path)

    执行此脚本后，EXCEL的路径将保存在string型变量str_excel_path中,返回值为：
C:\Program Files\Microsoft Office\Office\

[注]RegistryGet()函数

用法： | RegistryGet( key , valuename , valuetype , valuevariable )
说明： | 从系统注册表中得到指定键的值。
返回值： | long，1表示成功，-1表示失败。
参数 | 类型及说明
key | string，指定键名。
valuename | string，指定要访问值的名称，每个键可以有一个未命名的值和多个命名的值。要访问未命名的值，把该参数指定为空字符串。
valuetype | RegistryValueType，枚举，指定值的数据类型。
 | RegString! | 以空字符串结束的字符串。
 | RegExpandString! | 以空字符串结束的字符串，其中包括了对环境变量的非扩展应用。
 | RegBinary! | 二进制数据。
 | ReguLong! | 32位数据。
 | ReguLongBigEndian! | 32位大数据。
 | RegLink! | Unicode符号链。
 | RegMultiString! | 动态字符串数组。
valuevariable | 用于保存键值的变量，其数据类型应该与valuetype参数指定的类型相匹配。

→我是小木鱼（Lag）

写于2000年12月02日


如何在PowerBuilder中打开一个其它类型的文件?

问：在PowerBuilder中如何打开一个文件（如*.txt ，*.doc），就像在资源管理器中双击打开文件一样？

答：用Windows的API函数ShellExecute()来实现。

①定义API：
Function ulong ShellExecute(ulong hwnd,ref string lpOperation,ref string lpFile,ref string lpParameters,ref string lpDirectory,ulong nShowCmd) LIBRARY "shell32.dll" ALIAS FOR "ShellExecuteA"

②作一按纽，脚本：
    String str_null,str_filename
    SetNull ( str_null )
str_filename="c:\lag.txt"
    ShellExecute( Handle(Parent), str_null, str_filename , str_null, str_null, 1 )

[注]ShellExecute()函数

说明： | 查找与指定文件关联在一起的程序的文件名。
返回值： | ulong，非零表示成功，零表示失败。
参数 | 类型及说明
hwnd | ulong，指定一个窗口的句柄，有时候，windows程序有必要在创建自己的主窗口前显示一个消息框。
lpOperation | String，指定字串“open”来打开lpFlie文档，或指定“Print”来打印它。
lpFile | String，想用关联程序打印或打开一个程序名或文件名。
lpParameters | String，如lpszFlie是可执行文件，则这个字串包含传递给执行程序的参数。
lpDirectory | String，想使用的完整路径。
nShowCmd | ulong，定义了如何显示启动程序的常数值。参考ShowWindow函数的nCmdShow参数。

→我是小木鱼（Lag）

写于2000年11月29日


怎样得到程序运行时的绝对路径?

问：我如何能在PowerBuilder中得到程序运行时的绝对路径？

答：用Windows的API函数GetModuleFileName()来实现。

①定义API：
Function ulong GetModuleFileName(ulong hModule,ref string lpFileName,ulong nSize) LIBRARY "kernel32.dll" ALIAS FOR "GetModuleFileNameA"

②脚本：
    string str_AppPath
    integer int_ret
    str_AppPath = Space (128)
    int_ret = GetModuleFileName (Handle (GetApplication ()), str_Apppath, 128)

    说明：要编译成可执行文件*.exe才可用，否则得到的是Powerbuilder的pb60.exe或PB050.exe的路径。程序路径保存在变量ls_AppPath中。

[注]GetModuleFileName()函数

说明： | 获取一个已装载模板的完整路径名称。
返回值： | ulong，如执行成功，返回复制到lpFileName的实际字符数量；零表示失败。
参数 | 类型及说明
hModule | ulong，一个模块的句柄。可以是一个DLL模块，或者是一个应用程序的实例句柄。
lpFileName | String，指定一个字串缓冲区，要在其中容纳文件的用NULL字符中止的路径名，hModule模块就是从这个文件装载进来的。
nSize | ulong，装载到缓冲区lpFileName的最大字符数量。

→我是小木鱼（Lag）

写于2000年12月01日


在PowerBuilder中实现延时的两种方法?

问：请问如何在PowerBuilder中实现延时呢？

答：有二种方法。

方法一：
在PB中有一个yield()函数可用来延时 ，编程如下：
long n
for n=1 to 80000
yield()
next

[小解]这种方法的缺点是无法精确定时,只能大概估计。

方法二：
用Windows中的API函数Sleep()

①定义API：
Function long Sleep(Long ms)library "kernel32" (注意函数的字母大小写）
 ②脚本：
调用：Sleep(500) //延时0.5秒

挺好用吧……

→我是小木鱼（Lag）

写于2000年11月30日


如何在PowerBuilder应用程序中创建目录?

问：请问如何在PowerBuilder中创建一个目录呢？

答：用Windows的API函数CreateDirectory()。

①定义API：
Function boolean CreateDirectoryA(ref string pathname,int sa) Library "Kernel32.dll"

②脚本：
boolean bln_return
string str_dir

str_dir = "c:\testdir"
bln_return = CreateDirectoryA(str_dir,0)
if bln_return then
Messagebox("Succeed","Succeed!" )
else
Messagebox("Failed","Failed!")
End if

[注]CreateDirectory()函数

说明： | 创建一个新目录。
返回值： | Long，非零表示成功，零表示失败。
参数 | 类型及说明
pathname | String，新目录的名字。
sa | 定义了目录的安全特性——如果操作系统支持的话。（我也不太明白）

→我是小木鱼（Lag）

写于2000年11月30日


如何关闭Windows系统?

问：在PowerBuilder将如何实现关闭 Windows 系统功能呢？

答：用Windows的API函数ExitWindowEx()。

①定义API：
Function long ExitWindowsEx (long uFlags , long dwReserved ) Library "user32"

②脚本：
ExitWindowEx( 1, 0 )

[注]ExitWindowEx()函数

说明： | 退出windows，并用特定的选项重新启动。
返回值： | Long，非零表示成功，零表示失败。
参数 | 类型及说明
uFlags | Long，指定下述一个或多个标志（用OR运算符合并到一起）
 | 4 | 强迫中止没有响应的进程。
 | 0 | 中止进程，然后注销。
 | 1 | 关掉系统电源（如果可能的话，ATX电源就可以）。
 | 2 | 重新引导系统。
dwReserved | Long，保留，设为零。
注解
这个函数调用后会立刻返回，系统关闭过程是在后台进行的。注意先中止自己的应用程序，使关闭过程更显平顺。当然，您的进程必须有足够的优先权，否则也不能执行这种操作。

[补]如果要强行关闭计算机，使它不提示有用户连接是否关闭信息等请用：ExitWindowsEx(5,0)

→我是小木鱼（Lag）

写于2000年11月30日


如何隐藏windows的任务栏?

问：请问在程序中要如何隐藏windows的任务栏呢？

答：用Windows的API函数FindWindowEx()与ShowWindow()即可。

①定义API：
Function ulong FindWindowEx(ulong hWnd1,ulong hWnd2,ref string lpsz1,ref string lpsz2) LIBRARY "user32.dll" ALIAS FOR "FindWindowExA"
Function ulong ShowWindow( ulong winhandle, int wincommand ) Library "user32"

②脚本：
// Names of the shell windows we'll be looking for
String str_ShellViewWnd = "Progman"
String str_ShellTaskBarWnd = "Shell_TrayWnd"
String str_Null
Long lng_HTaskBar, lng_HDeskTop

// 隐藏任务栏
lng_HTaskBar = FindWindowEx( 0, 0, str_ShellTaskBarWnd, str_Null )
ShowWindow( lng_HTaskBar, 0 )

// 显示任务栏
lng_HTaskBar = FindWindowEx( 0, 0, str_ShellTaskBarWnd, str_Null )
ShowWindow( lng_HTaskBar, 5 )

[注]FindWindowEx()函数

说明： | 在窗口列表中寻找与指定条件相符的第一个子窗口。
返回值： | ulong，找到的窗口的句柄。如未找到相符窗口，则返回零。
参数 | 类型及说明
hWnd1 | ulong，在其中查找子的父窗口。如设为零，表示使用桌面窗口（通常说的顶级窗口都被认为是桌面的子窗口，所以也会对它们进行查找）。
hWnd2 | ulong，从这个窗口后开始查找。这样便可利用对FindWindowEx的多次调用找到符合条件的所有子窗口。如设为零，表示从第一个子窗口开始搜索。
lpsz1 | String，欲搜索的类名。零表示忽略。
lpsz2 | String，欲搜索的类名。零表示忽略。

ShowWindow()函数

说明： | 控制窗口的可见性。
返回值： | ulong，如窗口之前是可见的，则返回TRUE（非零），否则返回FALSE（零）。
参数 | 类型及说明
winhandle | ulong，窗口句柄，要向这个窗口应用由wincommand指定的命令。
wincommand | integer，为窗口指定可视性方面的一个命令。请用下述任何一个常数
 | 0 | 隐藏窗口，活动状态给另一个窗口。
 | 1 | 用原来的大小和位置显示一个窗口，同时令其进入活动状态。与9同。
 | 2 | 最小化窗口，并将其激活
 | 3 | 最大化窗口，并将其激活。
 | 4 | 用最近的大小和位置显示一个窗口，同时不改变活动窗口。
 | 5 | 用当前的大小和位置显示一个窗口，同时令其进入活动状态。
 | 6 | 最小化窗口，活动状态给令一个窗口。
 | 7 | 最小化一个窗口，同时不改变活动窗口。
 | 8 | 用当前的大小和位置显示一个窗口，不改变活动窗口。
 | 9 | 用原来的大小和位置显示一个窗口，同时令其进入活动状态。

→我是小木鱼（Lag）

写于2000年11月29日


如何获得Windows系统目录?

问：在PowerBuilder中是如何获得Windows系统目录的呢？

答：用Windows的API函数GetWindowsDirectory()即可。

①定义API：
Function ulong GetWindowsDirectory(ref string lpBuffer,ulong nSize) LIBRARY "kernel32.dll" ALIAS FOR "GetWindowsDirectoryA"

②脚本：
string str_WinPath

str_WinPath = space( 128 )
GetWindowsDirectory( str_WinPath, 128 )

//str_winpath的返回值为：c:\windows

 [注]GetWindowsDirectory()函数

说明： | 这个函数能获取Windows目录的完整路径名。在这个目录里，保存了大多数windows应用程序文件及初始化文件。
返回值： | ulong，复制到lpBuffer的一个字串的长度(如c:\windows，返回10)。如lpBuffer不够大，不能容下整个字串，就会返回lpBuffer要求的长度。零表示失败。
参数 | 类型及说明
lpBuffer | String，指定一个字串缓冲区，用于装载Windows目录名。除非是根目录，否则目录中不会有一个中止用的“\”字符。
nSize | ulong，lpBuffer字串的最大长度。

→我是小木鱼（Lag）

写于2000年11月29日


如何拷贝文件?

问：PowerBuilder的文件函数中没有拷贝函数，那么我将如何实现文件的拷贝呢？

答：方法有二，一是用Windows的API函数CopyFile()，二是用DOS下的COPY命令。

方法一：

①定义API：
Function ulong CopyFile(ref string lpExistingFileName,ref string lpNewFileName,ulong bFailIfExists) LIBRARY "kernel32.dll" ALIAS FOR "CopyFileA"

②脚本：
string str_source, str_des
ulong ulng_result

str_source = "c:\lag.txt" //源文件
str_des = "c:\tmp\111.txt" //目标文件
ulng_result=CopyFile(str_source,str_des, 0)
if ulng_result<>0 then
messagebox("OK","拷贝文件成功!")
end if

方法二：

①先做一批处理文件lag.bat：
copy c:\lag.txt c:\tmp\lll.txt

②在程序中调用此批处理文件：
run("lag.bat")

强烈建议用WINDOWS中的API函数 CopyFile()。

[注]CopyFile()函数

说明： | 复制文件。
返回值： | ulong，非零表示成功，零表示失败。
参数 | 类型及说明
lpExistingFileName | String，源文件名。
lpNewFileName | String，目标文件名。
bFailIfExists | ulng，如果设为TRUE（非零），那么一旦目标文件已经存在，则函数调用会失败。否则目标文件被改写。

→我是小木鱼（Lag）

写于2000年11月29日


如何调用HTML格式的帮助文件?

问：我做了一个HTML格式的帮助文件，在PowerBuilder中该如何调用它呢？

答：用RUN()函数或用Windows中的API函数HtmlHelp（），这个函数驻留在HtmlHelp ActiveX控件Hhctrl.ocx中。

①定义API：
Function Long HtmlHelpA (long hwnd ,string lpHelpFile , long wCommand, string dwData) Library "hhctrl.ocx"

②菜单帮助选项脚本：
Parentwindow.triggerevent("ue_help")

③MDI窗体中自定义事件（"ue_help"）脚本：
HtmlHelpA(handle(this),"chm_name>chm_win_name",0,"htm_name")

例如：chm帮助文件的名字是help.chm，help.chm的主窗口名是main，要调出的相关页面是my.htm，相应的脚本是：
HtmlHelpA(handle(this), "help.chm>main",0, "my.htm")
或：HtmlHelpA(handle(this),"help.chm",0,0) //省事

如果你的计算机安装了HtmlHelp阅读器Hh.exe，就可以直接运行HtmlHelp帮助文件。
run("hh help.chm")

[注]HtmlHelp()函数

说明： | 调用HTML格式的帮助文件。
参数 | 类型及说明
hwnd | 窗口的句柄，可用handle()函数取得。
lpHelpFile | HTML帮助文件的路径和名称。
wCommand | 执行的操作。
dwData | wCommand参数所需要的值。

→我是小木鱼（Lag）

写于2000年11月28日


如何关闭打开的dos窗口?

问：如何关闭打开的dos窗口? 如：调用run(*.bat)函数，该函数运行完毕后有一个打开的dos窗口，如何关闭?

答：这要用到Windows中的API函数FindWindow()

①定义API：
Function ulong FindWindowA (String lpClassName , String lpWindowName) Library "user32.dll"

②脚本：
long lHandler
string sClass
setnull(sClass)
lHandler = FindWindowA(sClass, "MS-DOS 方式")
If lHandler <> 0 Then
send(lHandler, 16,0, 0)
End If

[注]FindWindow()函数

说明： | 寻找窗口列表中第一个符合指定条件的顶级窗口。
返回值： | Long，找到窗口的句柄。如未找到相符窗口，则返回零。
参数 | 类型及说明
lpClassName | String，指向包含了窗口类名的空中止（C语言）字串的指针；或设为零，表示接收任何类。
lpWindowName | String，指向包含了窗口文本（或标签）的空中止（C语言）字串的指针；或设为零，表示接收任何窗口标题。

→我是小木鱼（Lag）

写于2000年11月27日