PowerBasic高效易用,从Visual Basic转到PowerBasic并不是难事,但是PowerBasic建立窗口困难,可能让新用户望而却步,随后PwrDev等软件诞生了,填补了它的不足。不过PwrDev并不像VB那样简单,每个控件都对应有各自的函数,但是查遍整个帮助文档,却没有看到它对ProgressBar的介绍。

PwrDev不支持ProgressBar吗?不是,在它的“Common ctrls”(标准控件)中就有一个ProgressBar,但是不知道什么原因的,PwrDev并没有它的相关函数,固然PwrDev是不支持ProgressBar1.Value这种用法的,然而又不能使用像TextBox那样的VD_GetText、VD_SetText等函数来设置或获取值,但是这个控件确实是一个常用控件,如果要使用它怎么办,看来只能动用Windows API了。
 

本文来自www.sacour.cn 转载请注明来源

Windows是一个句柄当道的系统,每个控件都有各自的句柄,PwrDev建立的程序更是不例外,使用GetWindow函数的话,我们可以实现遍历所有控件的目标。

GetWindow
函数功能:该函数返回与指定窗口有特定关系(如Z序或所有者)的窗口句柄。
函数原型:HWND GetWindow(HWND hWnd,UNIT nCmd);


PwrDev中和PowerBasic一样,引用了win32api.inc,所以不需要额外声明就可以直接调用这个函数,不过我们首先得获取主窗体的句柄,用什么函数吗?不需要,PwrDev中有个保留字就是用来存储主窗体句柄的,它是:nCbHndl (代码区会显示蓝色的),这样,有了它一切都好办了。

建立一个Button,一个ProgressBar,Function Form1_Button1_Click( ByVal nCbHndl As Long, ByVal nCbCtl As Long ) As Long的代码为:
遍历主窗体,找到一个类名为msctls_progress32注意不是PwrDev自己说的Class:ProgressBar)的控件,它就是我们先前加上去的ProgressBar进度条了。

那么有了句柄怎么给它传递信息呢?估计你也想到了,使用SendMessage函数。

SendMessage
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
函数原型: LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);

如果像我一样不熟悉ProgressBar而直接在VB6提供的API浏览器里面找WM_开头的常量,那是肯定找不到的,因为操作ProgressBar的Msg是PBM开头的,而API浏览器里面根本没这个常量……

请参考MSDN:http://msdn.microsoft.com/en-us/library/bb760816(VS.85).aspx (Progress Bar Controls)
请参考MSDN:http://msdn.microsoft.com/en-us/library/ff485990(v=VS.85).aspx (Progress Bar Control Reference --> Messages)
请参考MSDN:
http://msdn.microsoft.com/en-us/library/bb760844(VS.85).aspx (PBM_SETPOS Message)
请参考BCB代码:http://www.functionx.com/bcb/controls/progressbar.htm

我们所需要的就是PBM_SETPOS这个常量,顾名思义,ProgressBarMessage-SetPosition。

在使用之前也许我们需要阅读一下,了解下它的规则(摘自PBM_SETPOS Message,网址见上方):

Sets the current position for a progress bar and redraws the bar to reflect the new position.

Parameters
wParam
Signed integer that becomes the new position.

lParam
Must be zero.

Return Value
Returns the previous position.

Remarks
If wParam is outside the range of the control, the position is set to the closest boundary.

Do not send this message to a control that has the PBS_MARQUEE style.


翻译一下,

为进度条设置当前位置并重绘进度条以便反应实时位置。
参数: wParam, 有符号整数, 表明新位置
参数: lParam, 必须为0
返回值:返回之前位置
注意:如果wParam超出范围(大于最大值(.Max)或小于最小值(.Min)),位置会被设置到最近的边界(即最大值或最小值); 不要向有PBS_MARQUEE风格的控件发送这条指令。

好了,一切都准备完了,下面就可以直接写代码了。 测试用的代码如下: (行末有注释)

Static hnd As Dword, isChecked As Long  'hnd用于存储其句柄,不用每次都遍历控件;isChecked用于标记是否检查过。注意PwrDev(PowerBasic)没有Boolean布尔型,可以使用长整型或其他类型替代。
Static value As Long   'value用于测试效果
 value+=1   'value自加一
 If isChecked = 0 Then   '如果没有检测那么
   Dim dc As Dword,hdc As Dword       '存储句柄用
   Dim buff As Asciiz*255     'GetClassName需要Asciiz类型的变量
   dc = GetWindow(nCbHndl ,%GW_CHILD)
   hdc = GetWindow(dc,%GW_HWNDFIRST)   '获取第一个控件的句柄
   While(hdc)   '一直到获取不到句柄位置
      GetClassName(hdc,buff,255)    '获取类名
        If (Trim$(buff)= "msctls_progress32") Then  '如果类名是msctls_progress32那么
          SendMessage(hdc,%PBM_SETPOS,value,0)  '修改进度为value
          isChecked=1   '标记为已检测
          hnd=hdc  '存储句柄
          Exit Do  '退出循环
        End If 
      hdc = GetWindow(hdc,%GW_HWNDNEXT)  '不是msctls_progress32则继续
   Wend
 Else
      SendMessage(hnd,%PBM_SETPOS,value,0)  '已经检测过则直接修改进度为value
 End If  '结束。
 
等等,等等,这儿几个常量没有定义啊?常量在哪儿声明?之前我有发过一个帖子,名为《PwrDev中函数的声明位置》(http://www.sacour.cn/view.asp?id=61),只不过这次我们换到Constants(常数)



在里面写上:

Option Explicit

%GW_HWNDFIRST = 0
%GW_CHILD = 5        
%GW_HWNDNEXT = 2
%PBM_SETPOS = &H402
 
这样就可以了!

顺便附上一些PBM常量的值:
%WM_USER = &H400
%PBM_SETRANGE = (%WM_USER + 1)
%PBM_SETPOS = (%WM_USER + 2)
%PBM_DELTAPOS = (%WM_USER + 3)
%PBM_SETRANGE32 = (%WM_USER + 6)
%PBM_GETRANGE = (%WM_USER + 7)
%PBM_GETPOS = (%WM_USER + 8)

按下F5编译运行程序,点击几次按钮,ProgressBar的值成功改变,修改成功!