VFP中制作磁盘分区列表和文件夹列表
红飞狐 作为一名程序员,经常要在程序中对磁盘和文件夹进行操作,VB、DELPHI中都有相应的可视控件,但VFP中没有这类控件, 我们通常用Getdir()或将List控件数据源设置为“7-文件”来实现对文件夹的操作, 但界面实在不敢恭维,操作上也不很方便。事实上利用Windows的公用控件结合Windows API函数, 我们也可以制作出类似的VFP可视类(效果见下图)。
例图是我在VFP6.0中制作并放入表单的两个可视类。左边是利用ImageComboBox和ImageList制作的磁盘列表, 右边是利用TreeView和ImageList制作的文件夹列表。好,下面让我们开始吧。
一、制作磁盘列表。
1、选定使用控件。 ImageComboBox、TerrView、ImageList三个控件都包含在MSComctl.ocx中,是随VFP一起安装的。 我这里选用版本的是6.0。使用时最好将他们加入表单控件工具栏,便于选定。 方法是VFP主菜单-〉工具—〉选项,点击控件页面,将此三项选定,然后点击“设置为默认值”。
2、创建新类。 VFP主菜单-〉文件-〉新建-〉新建文件。类命名为DirCom,派生于Control(容器),存储于c:/myvcx/DirCom.Vcx。确定
3、添加控件。点击表单工具栏查看类,选中ActiveX控件,将一个ImageComboBox和ImageList控件放入容器。为使用方便,将Name分别改为Ole1和Ole2。
4、新建属性。VFP主菜单-〉类-〉新建属性。名称定为SelDrv,说明为:“选定驱动器”,并将其值由“.F.”改为空(显示为“(无)”)。
5、设置属性。
DirCom:
Backstyle=0-透明;
BorderWidth=0 (这样在使用时不带边框)
6、添加图标。点中ImageList,即Ole2,按鼠标右键,选择最后一行“ImageLi…”,进入属性设置。首先一定选中16 x 16,将下面的UseMaskColor选中(这样图标就没有讨厌的背景),然后进入Images页,按“Insert Picture”,加入图标,我这里放入7张图标,依次代表软盘、软盘、硬盘、网络驱动器、光盘、Rom盘、我的电脑。然后点击应用,确定
7、添加代码。
在ImageComboBox,即Ole1的init event中加入以下代码:
*/将列表设置为与容器相适应的宽度
This.width=This.Parent.Width
If This.Width>2
This.Width=This.Width-2
Endif
*/调用Windows Api函数获取本机驱动器的符号和类型
Declare Integer GetLogicalDriveStrings In Win32Api Long, string @Alldrv
Declare integer GetDriveType In "kernel32" String
*/用GetLogicalDriveStrings获取所有驱动器,存入Alldrv,其形势为”A:/C:/D:/….”,最后为*/一空字符,应除去
Alldrv=Spac(120)
=GetLogicalDriveStrings(120,@Alldrv)
nQdqs=(len(allt(Alldrv))-1)/4 &&计算驱动器数量
cDqqdq=SyS(5)+"/" &&获取当前驱动器符号
nDqqdq=1
*/定义三维数组,存放驱动器信息
*/aDrive(n,1)存放驱动器符号
*/aDrive(n,2)存放驱动器类型的汉字名称和符号
*/aDrive(n,3)存放驱动器类型
Dime aDrive(nQdqs,3)
For i=1 To nQdqs
aDrive(i,1)=Upper(Subs(Alldrv,1,3)) &&依次取出驱动器符号
If Alltrim(cDqqdq)==aDrive(i,1)
nDqqdq=I &&当前驱动器值
Endif
*/调用GetDriveType 函数确定驱动器类型
nLx=GetDriveType(aDrive(i,1))
Do Case
Case nLx=2
aDrive(i,2)='软盘'
aDrive(i,3)=2
Case nLx=3
aDrive(i,2)='硬盘'
aDrive(i,3)=3
Case nLx=4
aDrive(i,2)='网络驱动器'
aDrive(i,3)=4
Case nLx=5
aDrive(i,2)='光盘'
aDrive(i,3)=5
Case nLx=6
aDrive(i,2)='RAM盘'
aDrive(i,3)=6
Endcase
cDrvName=aDrive(i,1)
aDrive(i,1)=aDrive(i,2)-Space(2)+Left(aDrive(i,1),Len(cDrvName)-1)
Alldrv=Subs(Alldrv,5)
Endf
*/下拉列表第一项紧靠左边
This.indentation = 0
*/设置下拉列表关联的ImageList
This.imageList = This.Parent.ole2
This.Comboitems.Add(1,"我的电脑","我的电脑") &&添加列表第一项
This.Comboitems("我的电脑").image = 7 &&设置第一项图标
*/从第二项起较第一项右缩进2个单位
This.indentation = 2
*/添加本机驱动器符号,名称和图标
For i=2 To nQdqs+1
This.Comboitems.Add(i,"驱动器"+Alltrim(str(i-1)),aDrive(i-1,1))
This.Comboitems("驱动器"+Alltrim(str(i-1))).image = aDrive(i-1,3)
Endfor
*/将当前驱动器设置为初始显示值
This.Selecteditem=This.Comboitems("驱动器"+Alltrim(str(nDqqdq)))
在Ole1的LostFocus中加入代码:
*/将使用者选定的驱动器存入SelDrv,供使用者调用
If This.Text<>"我的电脑"
This.Parent.SelDrv=Right(This.Text,2)+"/"
Else
This.Parent.SelDrv=""
Endif
好,你可以保存类,并将其加入表单看看效果。
二、制作文件夹列表
这里与制作磁盘列表步骤基本相同,只是将类名改为DirTree,第4步添加三个新属性:
cWjjsx 存放文件夹属性,供程序运行时调用;
Wjjsx 存放使用者要求列出的文件夹属性,即ADIR()函数的5个属性AHRSD的任意组合,最好在说明中加以注明;
Seleml 使用者选定的文件夹。
以上三个属性的初值均必须设为字符型,否则出错。
第6步的图标依次改为软盘、硬盘、网络驱动器、光盘、我的电脑、打开的文件夹、关闭的文件夹、回收站。
将Ole1(即Treeview)属性设置为:
Indentation=5;
LabelEdit=1-Manual;
Linestyle=1-RootLines
添加代码:
在Ole1的Init Event中加入:
*/设置使用者要求显示的文件夹的属性,即ADIR()的文件属性
This.Parent.cWjjsx="D" &&必须含有”D”,否则ADIR()不会找到文件夹
If "A"$Upper(This.Parent.wjjsx)
This.Parent.cWjjsx=This.Parent.cWjjsx+"A" &&普通
Endif
If "H"$Upper(This.Parent.wjjsx)
This.Parent.cWjjsx=This.Parent.cWjjsx+"H" &&隐藏
Endif
If "R"$Upper(This.Parent.wjjsx)
This.Parent.cWjjsx=This.Parent.cWjjsx+"R" &&只读
Endif
If "S"$Upper(This.Parent.wjjsx)
This.Parent.cWjjsx=This.Parent.cWjjsx+"S" &&系统
Endif
*/将Ole1的大小设置为与容器适应
*/以下与ImageComboBox相同部分不再做注释
This.Top=0
This.Left=0
This.Width=This.Parent.Width-1
This.Height=This.Parent.Height-1
Declare Integer GetLogicalDriveStrings In Win32Api Long, string @Alldrv
Declare integer GetDriveType In "kernel32" String
Alldrv=Spac(120)
=GetLogicalDriveStrings(120,@Alldrv)
nQdqs=(len(allt(Alldrv))-1)/4
cDqqdq=SyS(5)+"/"
nDqqdq=1
Dime aDrive(nQdqs,4) &&这里设为4维数组,多出的用来存放最后不含”/”的文件夹名
For i=1 To nQdqs
aDrive(i,1)=Upper(Subs(Alldrv,1,3))
If Alltrim(cDqqdq)==aDrive(i,1)
nDqqdq=i
Endif
nLx=GetDriveType(aDrive(i,1))
Do Case
Case nLx=2
aDrive(i,2)='软盘'
aDrive(i,3)=1
Case nLx=3
aDrive(i,2)='硬盘'
aDrive(i,3)=2
Case nLx=4
aDrive(i,2)='网络驱动器'
aDrive(i,3)=3
Case nLx=5
aDrive(i,2)='光盘'
aDrive(i,3)=4
Case nLx=6
aDrive(i,2)='RAM盘'
aDrive(i,3)=2
Endcase
cDrvName=aDrive(i,1)
aDrive(i,4)=aDrive(i,2)-Space(2)+Left(aDrive(i,1),Len(cDrvName)-1)
Alldrv=Subs(Alldrv,5)
Endf
This.imageList = This.parent.ole2
*/添加根节点:“我的电脑”
=This.Nodes.Add(, , "我的电脑", "我的电脑",5))
*/将本机驱动器作为根节点的子节点加入
For i=1 to nQdqs
=This.Nodes.Add("我的电脑",4,adrive(i,1) ,aDrive(i,4),adrive(i,3))
Endfor
*/判断某一驱动器是否有子文件夹,如有,将第一个加入成为其子节点,否则不会显示”+”。
*/这里为了减少加入列表的时间,只加入一个子节点,可以取得同样的效果
For i=1 To nQdqs
nMls=Adir(aWj,aDrive(i,1)+"*.*",This.Parent.cWjjsx)
For j=1 To nMls
If "D"$aWj(j,5)
=This.Nodes.Add(aDrive(i,1),4,aDrive(i,1)+aWj(j,1),aWj(j,1),7)
Exit
Endif
Endfor
Endfor
*/将当前驱动器设置为选定,这样可以将在开始就将根节点展开,并选中当前驱动器
This.selecteditem=This.Nodes(cDqqdq)
在Ole1的Expand event(展开某一节点)中加入代码:
*/以下两句为系统自动生成
*** ActiveX 控件事件 ***
LPARAMETERS node
*/如果展开根节点,不做处理
If node.Key="我的电脑"
Retu 0
Endif
*/判断此节点是否曾经展开,如已经展开,不做处理
If Empty(node.tag)
node.tag="打开"
Else
Retu 0
Endif
*/判断展开的节点是否驱动器,如不是将展开图标设置为“打开文件夹”
If Len(node.Key)<>3
node.Expandedimage=6
Endif
*/删除第一个子节点,因为为减少展开时间,没有展开过的文件夹只有一个子节点,必须*/删除重新添加所有下级节点
This.nodes.remove(node.child.key)
*/将展开节点的Key(此值唯一)给变量cDqml(当前目录)
cDqml=node.key
cDqsywj=Alltrim(cDqml)+"*.*"
*/利用DIR()将展开的文件夹下的所有文件和文件夹存入aWj_father数组
nWjs_Father=Adir(aWj_father,cDqsywj,This.Parent.cWjjsx)
Dime cNodeKey(nWjs_father,2)
For i=1 To nWjs_father
*/判断文件夹名第一个字符是否“.”或“..”,必须将这两个特殊的文件夹除去
If left(aWj_father(i,1),1)="."
cNodeKey(i,2)=.f.
Loop
Endif
If "D"$aWj_father(i,5)
cNodeKey(i,1)=cDqml+aWj_father(i,1)+"/"
cNodeKey(i,2)=.t.
*/判断文件夹是否为回收站,此处我的处理不全面,希望得到指正
*/如为回收站将其图标设为回收站,否则设为“关闭的文件夹”
If Upper(aWj_father(i,1))<>Upper("Recycled")
This.Nodes.Add(node,4,cNodeKey(i,1),aWj_father(i,1),7)
Else
This.Nodes.Add(node,4,cNodeKey(i,1),"回收站",8)
Endif
Else
cNodeKey(i,2)=.f.
Endif
Endfor
node.Sorted=.t. &&将加入的文件夹列表排序
*/以下同样是为了判断文件夹是否含有子文件夹,如有,将第一个加入作为子节点
For i=1 To nWjs_father
If cNodeKey(i,2)=.f.
Loop
Endif
nWjs_Child=Adir(aWj_Child,cNodeKey(i,1)+"*.*",This.Parent.cWjjsx)
For j=1 To nWjs_Child
If left(aWj_Child(j,1),1)="."
Loop
Endif
If "D"$aWj_child(j,5)
cNodeKey_child=cNodeKey(i,1)+aWj_child(j,1)
This.Nodes.Add(cNodeKey(i,1),4,cNodeKey_child,"")
Exit
Endif
Endfor
Endfor
This.getvisiblecount &&此句必须要,这样能避免在列表的最下端展开节点却看不见任何子节点
在Ole1的Nodeclick中加入代码:
*** ActiveX 控件事件 ***
LPARAMETERS node
*/如果选定了根节点,将Seleml置空,否则置为指定的文件夹
If node.Key<>"我的电脑"
This.parent.Seleml=Alltrim(node.Key)
Else
This.parent.Seleml=Space(1)
Endif
Ok,现在可以保存类,加入表单看看,是不是还有点专业的味?!
请大家注意,如果将这两个可视类加入你的应用程序,别忘了在制作安装盘时将MSComctl.ocx文件加入安装程序,安装或者拷到Windows的system文件夹中。
此主题相关图片如下: