日志存档:12, 2007

验证码识别02

2007-12-22,星期六 | 分类:未分类 | 135 views

三、

将下面的代码添加到fap模拟程序最前面的init脚本区块中即可

–从数据区块读取base64编码的图片数据
codekey = ape:loadTable("验证码样本");
local timg = {}; –这是一个图像数组,用来储存还原后的验证码样本的图片数据
–必须进行一个转换,因为codekey里面只是base64编码的普通字符串,而timg 将是真正的图片对象(二进制数据)

–还原到图片对象
toImage = function(k,v)
    local img = image.new();
    local str = string.decode( v ,"");–首先进行base64解码,将纯文本转换为二进制数据
    img:setBytes( str ,"*.jpg");–将二进制数据还原为图像
    timg[k] = img;
end;

–载入验证码样本
tkey = ape:loadTable("验证码样本");
for k,v in pairs(tkey) do –验证样本
    toImage(k,v); –转换为图像
end;
   
–转换图片验证码到字符串的函数
function ImgToString(img)
    function test(imgX) –test是一个被包含在函数中的内部函数
        sleep(0);
        local limit = (60 * 20) + (60 * 20); –最小相似度 local关键字声明为局部变量
        local chr = "A"; –读取的字符
   
   
        –testimg是一个被包含在函数中的内部函数,作为table.foreach的回调函数,k参数表示键,v参数表示值
        testimg = function(k,v)

            –调用image.testXX()函数得出相似度,类似的函数还有image.testX() image.test()
            local n = imgX:testXX(timg[k]);
            if(n<limit)then –比较最小相似度
                  limit = n;
                  chr = k.."";
            end;
        end;
   
        –遍历timg表,并调用testimg函数
        for k,v in pairs(timg) do
           testimg(k,v);
        end;

        return string.left(chr,1); –返回读取到的字符串首字符(如果每个字符有多个样本)
    end;
   
   
    –修剪图片   
    image.Crop(img, 4 ,3 , 56 ,18 )
    img:bpp(1);
    img:bpp(24);
    –上面的过程必须与下载样本时的代码完全一致。
   
    –使用split函数分割图片
    local img2,img3,img4,img5 = img:split(1,4);
    win.messagePrint("正在检测图片,请稍候….");
    return test(img2)..test(img3)..test(img4)..test(img5);

end;

需要识别验证码的地方添加类似下面的代码:

img = image.new()
img:getURL("http://www.***.com/test.asp","*.jpg")

–因为刷新了验证码与页面不一致,把验证码画到屏幕上
local x,y = mouse.getPos()
img:paint(x,y,60 ,20 )

local str = ImgToString(img);

–下面我们把验证码的每个字符都转换为大写,并控制键盘顺序按键
code1 = string.upper( string.sub(str,1,1) );
code2 = string.upper( string.sub(str,2,2) );
code3 = string.upper( string.sub(str,3,3) );
code4 = string.upper( string.sub(str,4,4) );
key.press(100,code1,code2,code3,code4);

上面我们用了模拟按键的方法输入验证码。
实际上大多时候可以用更简单的方法,如下:

ele = wb:getEle("验证码控件名字");
ele:setAttribute("value",str)

为什么我的验证码与页面上不一样

因为我们使用img:getURL读取验证码时已经刷新了验证码。
所以验证码与页面上显示的并不一样,您只需要识别最新的验证码即可。

如何直接获取页面的上图片,而不是重新下载

有些验证码是绑定页面的,必须识别页面上的验证码才行。
那么可以使用image.capture函数直接抓屏屏幕上的图片即可。
请参考:image.capture函数

更好的方法是使用ele:exec("Copy")函数直接拷贝页面上的图片到剪贴板。
然后使用 img:getClipBD() 获取图片。
请参考:ele:exec("Copy")函数 img:getClipBD()函数

四、关于剪切图片

看上面的示意图,Crop就是选取绿色方框内的区域去清除绿色方框外面的区域.
必须保证里面的面积正好可以平均分成四块(假设这里是四个验证码字符)

这样以后调用 img:split(1,4) 就正好分成四个字符了
分成四份的小图片其宽度应当正好是上面的红色小方块的宽度。
高度与绿色方框一样,我这里画的参次不齐是为了让大家看清楚。

如果你Crop的参数值不对,那么split就出错了.
下载验证码图片以后,可以使用图像编辑软件打开高倍放大。

五、使用种子填充算法去除验证码上的干扰线

模拟精灵识别验证码的能用是强大的,一个函数即可以去除杂色杂点。

img:bpp(1)
img:bpp(24)

经过上面两句代码的处理,速度很快,所有背景、干扰点、杂色荡然无存。

但是有时候验证码中有大量的干扰线,并且位置随机变动的太历害,
这时候我们在处理验证码以前首先去除这些干扰线并准确的去除背景提取字符.

下面是一个模拟精灵初步处理后的验证码图片.已经去除了杂色、杂点.但是上面还是有干扰线.

一个可选的办法是用中值滤波再处理一下。img:median(2); 一个函数调用就可以,但
是这样虽然去掉了干扰线,原来的字符也被少量的破坏了。

下面是使用种子填充算法去除干扰线的源代码,不但能去除杂点,
而且可以去除周围的空白(提取位置随机变化的验证码),
稍加修改还能有更多的用途.

下面是自动处理以后的效果

下面是全部的源代码:

–[[
用一个table结构{x=0; y=0}表示图像上的「坐标点」
用一组点构成table结构表示图像上的一条「线」。所有相连的黑色的点被认为是一条「连通线」。
找出最长的一条「连通线」,被认为是字符,其他的认为是杂点。

算法原理与种子填充算法相似。

首先让用img:bpp函数处理为黑白图片,并初步去除杂色。

先找到一个黑点,创建一个表示「坐标点」对象,并添加到「连通线」中。
然后在黑点周围8个点中,再找黑色的点,找到就添加到「连通线」,这样一直递归下去
直到遍历图像所有点,可能有几块。

清除杂点使用方法
image.scan(img);

清除杂点并切去掉周围的空白
image.scan(img,true);
--]]
f
unction image.scan(img,crop)
   
    –用一个table数组记录所有的「连通线」
     assert(img:ok(),"image.scan 的参数必须是一个有效的图片");
   
     local tlines ={};
    
     –首先计算出图片的高度宽度,避免重复的调用
     local w = img:width();
     local h = img:height();
         

    –[[以table形式定义一个数组,对应图象中的每个点。
    作用相当一个开关,首先值为false,但黑点首次被遍历到时。把这个值变为true。
    下次,再找到这个点时忽略。避免重复加入连通线。
    --]]
    local tchked ={};
    for i=0,w,1 do
        tchked[i]={};
        for j=0,h,1 do
            tchked[i][j]=false;
        end;
    end;
    
    —–去噪
    img:bpp(1);
    img:bpp(24);
    
    –首先计算出各点的颜色值,避免在循环递归中重复的取
    local tcl={};
    for i=0,w,1 do
        tcl[i]={};
        for j=0,h,1   do
            tcl[i][j]=img:getPos(i,j);
        end;
    end;

   
    –[[
    算点数函数
    参数x,y 坐标
    参数tab 所属连通线;
    --]]
    local   function seed(x,y,tab)
   
        —出界了则返回
        if(x<0 or y<0 or x>w or y>h) then
            return;
        end;
             
        —点的颜色为白色时,返回,不处理。
        if(tcl[x][y]==16777215)  then
            return;
        end;
       
        —值为1,则计数加1,返回
        if ( tchked[x][y]) then
            return ;
        else
            table.insert(tab,{x=x,y=y} );–添加到连通线里
            tchked[x][y]=true;—当值为0时,把值置为1。
            seed(x+1,y-1,tab);
            seed(x,y-1,tab);
            seed(x-1,y-1,tab);
            seed(x-1,y,tab);
            seed(x+1,y,tab);
            seed(x-1,y+1,tab);
            seed(x,y+1,tab);
            return seed(x+1,y+1,tab); –这里可以用一个尾调用(参考教程中的函数部份),加快递归的速度。
        end;
    end;

   
    —————————
      
    —-遍历图像中的所有点
    for i=0,w,1   do
        for j=0,h,1 do
            —如果是黑色的点,而且没有被计过数,则调用seed函数。
            if(tcl[i][j]==0 and (not tchked[i][j])) then       
                local tab = {}
                seed(i,j,tab);
                table.insert(tlines,tab); –添加一条连通线
   
            end;
        end;
    end;
         
    –现在tlines 里记录了的有的连通线,我们现在需要根据连通线的长度排序
    sproc = function(l,l2)  
        return table.maxn(l) > table.maxn(l2);–长的连通线排到前面
    end;
    table.sort(tlines,sproc)
              
    –把图像全部画成白色的点     
    for i=0,w,1  do
        for j=0,h,1  do
            img:setPos( i , j, 16777215);
        end;
    end;
         
    –然后把最长的一条连通线画上去
    for i,point in  ipairs(tlines[1])  do
        img:setPos( point.x, point.y , 0);  
    end;
   

    –如果需要去掉周围的空白
    if(crop)then
        local n = table.maxn(tlines[1])
           
        –排序最长连通线中的所有坐标点
        sproc = function(pt,pt2)  
            return (pt.x <pt2.x );–*左的排前面
        end;
        table.sort(tlines[1],sproc);
        local x,x2 = tlines[1][1].x, tlines[1][n].x;
   
        –排序最长连通线中的所有坐标点
        sproc = function(pt,pt2)  
            return (pt.y <pt2.y );–*上的排前面
        end;
        table.sort(tlines[1],sproc);
        local y,y2 = tlines[1][1].y, tlines[1][n].y;
       
        img:Crop( x,y,x2+1,y2)
    end;
   
end;
    

验证码识别技术

2007-12-22,星期六 | 分类:未分类 | 124 views

由于现在很多网站,为了加强安全性,以及防止程序的自动操作网站,都加入的了验证码技术。但却给广大站长推广宣传网站带来的麻烦。所以我准备写这篇关于验证码识别技术的文章,不足之处在所难免!本人从来不写东西,今天为了想落伍才写了!

    广大站长宣传推广自己的网站,经常要发布一些宣传广告,如果靠人工,太慢太昂贵,所以理想的办法是使用群发软件,可现在很多网站都有验证码,这成为群发软件的技术难点,而识别也就难点中的难点,好的,闲话少说,言归正传!

我举的例子是比较难于识别的验证码,不讨论不变形、不换字体、不换大小、不旋转的验证码,这里我可能不会写出代码,只是提供我编写的思路,按照这个思路,我写出的程序,比市场上出售的程序的识别率还要高很多。(有兴趣的可以问我,我不想在这里帮别人宣传,呵呵~~)

首先以数字验证码开始,字母的要比数字麻烦一些,不过搞清楚了数字验证码的识别,字母的也就不难了。

验证码一般都是图片,而且一般都是4位数,处理过程是:先分割为4个部分,然后逐一识别,由于分割比较简单,我这里就不说了,我这里只说如何识别。

我的方法是把需要识别的图片,划分为 5 行,3 列,15个块,为什么要划分为15个块呢?先看图!
○■○
■○■
■○■
■○■
○■○

○■○
■■○
○■○
○■○
■■■

■■■
○○■
■■■
■○○
■■■

■■■
○○■
■■■
○○■
■■■
我先举这4个例子吧,其余的大家可以自己画出来。如果做过验证码识别的朋友,肯定很快就明白为什么划分为15个块,其实主要就是因为这样划分更合理,也就更能提高识别率。

我的方法是把需要识别的图片,划分为 5 行,3 列,15个块,然后对每个块进行计算,当每个块里的有效象素超过多少百分比的时候,就标记为 ■,如果没超过就标记为○,(这里为了显示方便我使用了■,○,你完全可以把它标为1、0),这里要注意一下,这里的百分比根据字体的粗细可以取 67%,50%,33%,20%,为什么要取这几个数?主要和计算机的浮点数运算有关,选这几个数,运算更快,且不容易出错,否则计算机在进行大量计算时也是会出错的!当然这里,你完全可以选适合你的验证码图片的百分比!!

如果验证码不变形、不换字体、不换大小、不旋转,我们的识别工作到这一步基本上就结束了,因为已经可以得到比较清晰的块图,对付大多数论坛,就已经足够了。^_^

如果验证码的变形比较大、且有很多字体、大小也不固定、且有旋转,那么我们经过划分、取比率显示后,可能会得到这样一个图:
○■○
○○■
○■○
■○○
■■■
那么这个数字应该是什么数字,我们需要使用排除法!排除所有不可能,在0123456789中,这个图不可能是013456789,他只能是 :2。

写过验证码识别的朋友可能已经明白了!是的,我们需要建立一个类似的数据库,也就是识别库,出现哪些图,他就属于那个数字。
再举一个例子:
○■○
■○○
■■■
■○■
○■○
    这是哪个数字呢??是6,没错

    我这里我需要再说明一下为什么要取5行,3列,15个块,因为块太多了你 的识别库就会很大,块太少了,就会出现很多分不清楚的块图。

另外你取的百分比也需要注意,不能太大也不能太小。

    好了,等做好自己的数据库,这时就可以识别大部分数字了。

最后还有一个问题,就是重复的问题,比如,图片上的数字,明明是 5,可由于它的字体不是常见的字体,且发生了旋转,最后得到这样一个图:
■■■
■○○
■■■
■○■
■■■
在我的数据库里,这个块图,是6,也是就说识别错误,怎么办?

我的解决方法是,在数据库里先把这条数据删除因为这个是错误的。

遇到这种情况,就需要进行二次处理,我的方法是:降低百分比,这时就得到了:
■■○
■○○
■■○
○○■
■■○
    OK,经过降低百分比,图片就由“6”又变为“5”了,呵呵~~~由于降低了百分比,我们需要再建立一个识别库的来存储这些数据。

好了,我的文章就写到这里,只是给大家提供一个思路,可能还有一些细节我没写出来,但主要的方法都提供出来了,希望能起到抛砖引玉的作用

(转)复制出IE临时文件夹内的SWF文件

2007-12-22,星期六 | 分类:编 程|VisualBasic | 196 views

复制出IE临时文件夹内的SWF文件,也可以是其他类型的文件,这里只是简单演示用FSO遍历文件夹
‘引用Microsoft Scripting RunTime
Dim m_objFSO As New FileSystemObject   ‘定义文件系统对象

Private Declare Function SHGetSpecialFolderLocation Lib "Shell32" (ByVal hwndOwner As Long, ByVal nFolder As Integer, ppidl As Long) As Long
Private Declare Function SHGetPathFromIDList Lib "Shell32" Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal szPath As String) As Long
Const MAX_LEN = 200 ‘字符串最大长度
Const PAGETMP = &H20& ‘网页临时文件

Private Sub Command1_Click()
    Dim sTmp As String * MAX_LEN ‘存放结果的固定长度的字符串
    Dim nLength As Long ‘字符串的实际长度
    Dim pidl As Long ‘某特殊目录在特殊目录列表中的位置
    Dim TStr As String
   
    ‘获得网页临时文件夹
    SHGetSpecialFolderLocation 0, PAGETMP, pidl
    SHGetPathFromIDList pidl, sTmp
    TStr = Left(sTmp, InStr(sTmp, Chr(0)) – 1)
    SearchSwf TStr
End Sub

Private Sub SearchSwf(strPath As String)
    Dim objFolder   As Scripting.Folder   ‘文件夹对象
    Dim objFile   As Scripting.File   ‘文件对象
    Dim objSubdirs   As Scripting.Folders   ‘文件夹集合对象
    Dim objLoopFolder   As Scripting.Folder   ‘文件夹对象
   
    Set objFolder = m_objFSO.GetFolder(strPath)
   
    For Each objFile In objFolder.Files
        If UCase$(Right$(objFile.ShortPath, 4)) = ".SWF" Then
            FileCopy objFile.Path, "c:\TestSwf\" & objFile.Name
        End If
    Next objFile
   
    Set objSubdirs = objFolder.SubFolders
   
    For Each objLoopFolder In objSubdirs
        SearchSwf objLoopFolder.Path
    Next objLoopFolder
   
    Set objSubdirs = Nothing
    Set objFolder = Nothing
End Sub

来源:虫子

自动注册(没有测试)

2007-12-22,星期六 | 分类:综合分类|经典收藏 | 201 views

这个代码没有测试,代码中红色部分比我以前的方法好,所以记下来。
‘————————————–
Sub GotoHome()
‘先引用Microsoft Internet Controls
On Error Resume Next
Set IE = CreateObject("InternetExplorer.application")
IE.Navigate2 "http://www.officefans.net/cdb/logging.php?action=login&sid=mjeBXlv3"
IE.Visible = True

timeie = DateAdd("s", 60, Now())   ‘最久等待60秒
Do While IE.Busy And Not IE.readyState = READYSTATE_COMPLETE
       DoEvents
       If timeie < Now() Then
         MsgBox "o法B接网站,重新绦"
         IE.Quit
         Exit Sub
       End If
Loop
With IE.document
      .all("UserName").Value = "ak47" ‘用ぬ
      .all("Password").Value = "9999999"   ‘用裘艽a
      .all("questionid").Value = 5        ‘安全提
      .all("answer").Value = "9999999" ‘提答案
      .all("loginsubmit").Click
End With
Set IE = Nothing
End Sub

自动点网页中的JavaScript链接

2007-12-22,星期六 | 分类:编 程|VisualBasic | 219 views

‘点正常链接方法很多,这里介绍的是自动点JavaScript链接

Function RunJS(scripts)
‘VB 自动点网页中的Javascript链接
Dim Document
                On Error GoTo ErrHandle
                If scripts = "" Then Exit Function
Set Document = WebBrowser1.Document
                Document.ParentWindow.execScript scripts, "javascript"
                Exit Function
ErrHandle:
    MsgBox "Err"
End Function
‘——————
调用:Call RunJS(Javascript:jsfunci())

webbrowser控件中Navigate和Navigate2的用法有什么区别?

2007-12-22,星期六 | 分类:编 程|VisualBasic | 标签: | 186 views
关于 Navigate 的定义:
Sub Navigate(URL As String, [Flags], [TargetFrameName], [PostData], [Headers])
SHDocVwCtl.WebBrowser 的成员
Navigates to a URL or file.

关于 Navigate2 的定义:
Sub Navigate2(URL, [Flags], [TargetFrameName], [PostData], [Headers])
SHDocVwCtl.WebBrowser 的成员
Navigates to a URL or file or pidl.

差别就在与一个 pidl
PIDL 就是 PathIDList,就是说 Navigate2 不仅具有 Navigate 所有的功能还可以通过 pidl 直接浏览文件夹。

平时我们将 pidl 转化为文件夹路径的时候都需要使用 SHGetPathFromIDList 函数,那么 Navigate2 就可以不用使用 SHGetPathFromIDList 函数了,可以直接压入一个 Long 值。

这也就显示上面 Navigate 中 URL 数据类型是 String,而 Navigate2 中 URL 数据类型是 Variant,应为它可以接受 Long 数据类型的 pidl。

关于得到 pidl 的函数有:
SHGetSpecialFolderLocation: 获得系统目录的位置
SHBrowseForFolder: 显示浏览文件夹对话框

VB 显示网上的图片的两种方法

2007-12-21,星期五 | 分类:编 程|VisualBasic | 242 views

Private Declare Function OleLoadPicturePath Lib "oleaut32.dll" (ByVal szURLorPath As Long, ByVal punkCaller As Long, ByVal dwReserved As Long, ByVal clrReserved As OLE_COLOR, ByRef riid As TGUID, ByRef ppvRet As IPicture) As Long

Private Type TGUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type

‘加载函数
Public Function LoadPicture(ByVal strFileName As String) As Picture
Dim IID As TGUID
With IID
.Data1 = &H7BF80980
.Data2 = &HBF32
.Data3 = &H101A
.Data4(0) = &H8B
.Data4(1) = &HBB
.Data4(2) = &H0
.Data4(3) = &HAA
.Data4(4) = &H0
.Data4(5) = &H30
.Data4(6) = &HC
.Data4(7) = &HAB
End With

On Error GoTo LocalErr

OleLoadPicturePath StrPtr(strFileName), 0&, 0&, 0&, IID, LoadPicture
Exit Function
LocalErr:
Set LoadPicture = VB.LoadPicture(strFileName)
Err.Clear
End Function

使用方法:
Set 控件名.Pictue = LoadPicture(图片网络路径)

上面这个是无缓存加载的

下面这个是下载到硬盘后加载的
去除加载部分 就是下载了

Private Sub Command1_Click()

Dim b() As Byte
Dim strURL As String
strURL = "http://himg.baidu.com/sys/portraitn/item/43a67669636d69616ffe00.jpg"

b() = Inet2.OpenURL(strURL, icByteArray)

Open "c:\csdn.jpg" For Binary Access _
Write As #1
Put #1, , b()
Close #1

Image1.Picture = LoadPicture("c:\csdn.jpg")
End Sub

来源:Baidu

比尔盖茨嘴里吐出的十条“金玉良言”

2007-12-21,星期五 | 分类:人力资源|项目管理 | 118 views
关键字:比尔 盖茨 管理

TOM科技讯 据英国《金融时报》调查:全球25个国家的1000位CEO、基金经理认为:微软仍是最受尊敬的公司,并在企业创新、投资价值两项中排名第一。

调查结果发现:今天的比尔・盖茨成为最受尊敬的商界领袖,其地位和影响力仅次于世界管理学之父杜拉克。

以下为盖茨先生在一次讲话中给出的十条忠告。

盖茨的十条“金玉良言”

1、社会充满不公平现象。你先不要想去改造它,只能先适应它。(因为你管不了它)。

2、世界不会在意你的自尊,人们看的只是你的成就。在你没有成就以前,切勿过分强调自尊。(因为你越强调自尊,越对你不利)。

3、你只是中学毕业,通常不会成为CEO,直到你把CEO职位拿到手为止。(直到此时,人们才不会介意你只是中学毕业)。

4、当你陷入人为困境时,不要抱怨,你只能默默地吸取教训。(你要悄悄地振作起来,重新奋起)。

5、你要懂得:在没有你之前,你的父母并不像现在这样“乏味”。你应该想到,这是他们为了抚养你所付出的巨大代价。(你永远要感恩和孝敬他们,才是硬道理)。

6、在学校里,你考第几已不是那么重要,但进入社会却不然。不管你去到哪里,都要分等排名。(社会、公司要排名次,是常见的事,要鼓起勇气竞争才对)。

7、学校里有节假日,到公司打工则不然,你几乎不能休息,很少能轻松地过节假日。(否则你职业生涯中一起跑就落后了,甚至会让你永远落后)。

8、在学校,老师会帮助你学习,到公司却不会。如果你认为学校的老师要求你很严格,那是你还没有进入公司打工。因为,如果公司对你不严厉,你就要失业了。(你必须清醒地认识到:公司比学校更要严格要求自己)。

9、人们都喜欢看电视剧,但你不要看,那并不是你的生活。只要在公司工作,你是无暇看电视剧的。(奉劝你不要看,否则你走上看电视连续剧之路,而且看得津津有味,那你将失去成功的资格)。

10、永远不要在背后批评别人,尤其不能批评你的老板无知、刻薄和无能。(因为这样的心态,会使你走上坎坷艰难的成长之路)。

动态创建和删除VB控件

2007-12-20,星期四 | 分类:编 程|VisualBasic | 128 views

摘要:介绍在Visual Basic环境中利用动态创建和删除控件的方法,比较了两者异同,阐述了在实际应用中,Active X控件在程序运行时动态加载和删除的方法。

关键词Visual Basic 6.0;控件;控件集合;控件数组;属性;Active X

1.概述

在使用Visual Basic 进行程序设计的过程中,如果能在运行时刻动态地创建和删除控件,可以极大地丰富界面的处理和变化。本人在设计网络监控系统时,需要在原理图与实物示意图间切换。切换的过程采用本文介绍控件的动态创建和删除来实现,有效地节省了系统资源,同时也有利于简化界面的维护。下面将就Visual Basic 6.0中的控件在运行时刻的创建和删除的两种方法——控件数组和控件集合作详细的阐述。

2.基于控件数组的动态控件的创建与删除

VB中的控件数组实际上也是一种数组,其中的每个控件具有相同的Name属性,但具有不同的Index属性,在这里Name属性类似于数组的名字,而Index属性类似于数组的下标。同时,控件数组也支持普通VBA数组的LBound UBoundCount方法,控件数组中的控件可以共享一个事件过程,便于代码的编写和集中处理,这正是使用控件数组的最大的理由。

但是控件数组与普通的数组并非完全一样,它不需要定义大小,只有这样我们才可以动态的扩展它。

下面给出利用Load命令动态添加控件和Unload命令动态删除控件的一般方法:

(1)         首先在窗体上放置一个TextBox,其Name属性设置为Text1Index属性设置为0,这样我们就创建了一个TextBox控件数组,其中有一个成员。

(2)         在窗体上放置一个命令按钮Command1,在其Click事件中添加如下的代码:

Load Text1(1)

Text1(1).left=0

Text1(1).visible=true

(3)         在窗体上放置一个命令按钮Command2,在其Click事件中添加如下的代码:

Unload Text1(1)

(4)         运行。单击命令按钮Command1,窗体上会出现一个新的文本框;单击命令按钮Command2,窗体上刚出现的新的文本框就被删除。

需要注意的是:Load命令创建的控件Text1(1)与设计时已经放在窗体上的控件Text1(0)有完全相同的属性,也包括大小和位置等属性,例外的就是Index属性不一样,Visible属性默认为False,所以必须在Load方法执行之后,执行调整控件位置的语句,并把其Visible属性设置为True,以便在窗体上可见。Unload命令只能删除动态加载的控件,若删除设计时创建的控件会产生错误。

另外,利用上面提到的数组的一些方法,可以有效的简化代码的编写。以下的代码可以删除所有动态创建的Text1控件数组中的控件:

Do While Text1.Count>1

    Unload Text1(Text1.Ubound)

Loop

需要说明的是,菜单数组是控件数组的一种特殊的形式,只是它是在菜单编辑器中设置相应的NameIndex属性,而且要求一个菜单控件数组中的菜单项必须是同一级菜单,但是不能创建新的顶级菜单。而动态创建和删除菜单项的方法也使用LoadUnload方法,只是默认情况下其Visible属性是True,而且不用重新设置相应的位置。

3.基于控件集合的动态控件的创建与删除

VB中提供一个Controls集合,用以包含当前窗体中的所有的控件,这对于实现一些功能相对复杂的操作相当有好处。而且Controls集合也是集合的一种,它支持一般集合的Count等方法和相应的检索机制。以下两例就是利用这个控件集合的巧妙实现。

要清空当前窗体上的所有的文本框,可以如下实现:

Dim Ctl as Control

For Each Ctl in Controls

    If Typeof Ctl is Textbox then

        Ctl.Text=””

    Endif

Next Ctl

也可以利用集合的Count方法如下实现:

For i=0 To  Controls.Count-1

    If Typeof Ctl is TextBox

        Controls(i).Text=””

    Endif

Next i

当然,控件集合毕竟是一种特殊的集合,下面给出利用Add方法动态添加控件,Remove方法动态删除控件的一般方法:

(1)         Controls集合的Add方法

其语法格式为:

Set mycontrol = controld.Add(ProgId, Name, [Container])

在这里,mycontrol是一个自定义的控件对象,若需要新创建的控件对事件做出反应,还要再定义该对象时增加WithEvents关键字。

ProgId是库名.控件名形式的控件类的名字,ToolBox 中的控件一般具有类似于VB.CommandButton这样的形式。而Active X控件的形式则有所差别,比如若使用Windowless控件库中的控件一般具有类似于MsWless.WlText的形式。

Name参数是想赋给控件的名字,与控件的Name属性相对应。

Container参数是可选的,它代表欲放置控件的容器,默认情况下是放置在窗体上。

下例是在窗体上动态创建一个命令按钮,然后单击命令按钮时,执行相应的动作:

Dim WithEvents mycontrol As CommandButton

Private Sub Form_Load()

Set mycontrol = Controls.Add("VB.commandbutton", "mycontrol")

mycontrol.Left = 0

mycontrol.Caption = "my"

mycontrol.Visible = True

End Sub

Private Sub mycontrol_click()

  MsgBox "You click me!", vbExclamation

End Sub

需要注意,动态创建的控件必须指定相应的属性,而且在默认情况下,其Visible属性是False

(2)         Controls集合的Remove方法

利用Controls集合的Remove方法可以删除用Add方法动态创建的控件。其语法格式为:

Controls.Remove 控件名

比如以上创建的mycontrol要删除可以使用如下的命令:

  Controls.Remove "mycontrol"

同样应该注意,不能删除一个不存在或者在设计时创建的控件。

4. Active X控件的动态创建和删除

以上论述的方法适合于控件在应用程序工具箱(TOOLBOX)中的情况,而Active X控件一般在应用程序运行机器上,但没有在工具箱中,这种情况则需要先进行注册,方法是利用Regsvr32Windows环境中注册,或者在VB代码中进行注册,方法如下:

Shell(Systempath regsvr32.exe /s /I" & MyControlName, vbHide)

其中SystempathRegsvr32.exe所在的路径, MyControlName是控件名字(包括路径)

若要撤销,可以如下操作:

Shell(Systempath regsvr32.exe /s /U" MyControlName, vbHide)

下面讨论注册但是未出现在工具箱(TOOLBOX)中的Active X控件的情况,这其中也包括VB自带的一些Active X控件的使用。具体的方法就是利用VBControlExtender对象。VBControlExtender对象与EventInfo相结合能提供事件陷井捕捉,它提供了一套通用的属性、方法、事件给开发人员,它的一个突出特点是能编程设计控件的事件,声明时若使用WithEvents关键字,则会有个特殊的事件ObjectEvent(Info As EventInfo),它能捕捉到对象使用RaiseEvent产生的所有事件,EventInfo数据结构映射了事件的名称、参数个数和参数的值。VBControlExtender EventInfo相结合,采用Select Case 就可以预先将不同类对象的事件放置一起,各自独立运作。

下面的例子是使用未在工具箱(TOOLBOX)中出现的RichTextBox的方法,其他的Active X控件的使用方法与此类似:

Dim WithEvents myControl As VBControlExtender

Private Sub Form_Load()

Licenses.Add "RichText.RichTextctrl.1"

Set myControl = Controls.Add("RichText.RichTextctrl.1", "mycontrol")

myControl.Left = 0

myControl.Visible = True

End Sub

Private Sub myControl_ObjectEvent(Info As EventInfo)

Select Case Info.Name

Case "MouseDown"

MsgBox "mousedown"

Case Else

其他事件

End Select

End Sub

需要注意,Licenses.Add "RichText.RichTextctrl.1"是响应控件的对象编号在VB中的注册,若此控件已经出现在工具箱(TOOLBOX)中,则会出错。

另外,若Active X控件已经出现在TOOLBOX中,需要动态建立控件,则应该作如下的处理:首先去掉Licenses.Add "RichText.RichTextctrl.1"这一句,然后,在“工程属性窗口”的“Make”页面下,确保“remove information about unused ActiveX controls”不被选中即可。

还有,若Active X控件已经出现在TOOLBOX中,需要动态建立控件,还可以用类似于前面介绍的控件集合的方法,比如上面示范的RichTextBox的例子还可以如下实现(只是这种方法不再支持ObjectEvent事件):

Dim WithEvents myControl As RichTextLib.RichTextBox

Private Sub Form_Load()

Set myControl = Controls.Add("RichText.RichTextctrl.1", "mycontrol")

myControl.Left = 0

myControl.Visible = True

End Sub

Private Sub myControl_Click()

  MsgBox "click"

End Sub

.结束语

通过以上对Visual Basic中的控件动态建立和删除进行了讨论,我们了解到控件数组合于应用程序中需要该控件,但需要控件实例的具体数量不定的情况;而控件集合则适合于为了完成不同的任务,制作了多个不同功能的控件,在特定条件下只需要一个或几个控件的情况。对于Active X控件,若没有添加到VB工具箱中,当应用程序执行时,可以根据需要由程序自动加载或者删除。总之,合理地选择使用以上的各种方法,对于提高编程的效率和代码的运行效率都是大有裨益的。

以上有关的代码都已在Windows 2000 Professional Visual Basic 6.0 企业版环境下测试通过。

最爱班得瑞

2007-12-18,星期二 | 分类:休闲娱乐|音影收藏 | 标签: | 141 views

班得瑞中文网站可以在线听很多专辑,在工作累的时候听听这样的音乐真是一种享受!

1990年发迹瑞士的班得瑞,来自一群爱好生命的年轻作曲家、演奏家及音源采样工程师等等青年才俊。团长奥利弗史瓦兹是一位多才多艺的音乐人,不但专长多种乐器,更熟稳先进的录音工程。他的特别率先采用先进的数字采样技术,将自然界的声响,运用后期母带24bit数字录制,钜细糜遗地记录下来清晰无比音质。奥利弗史瓦兹更曾与为莎拉布莱曼制作“Timeto Say Good-bye”的天王制作人亚历士克里斯坦森合作,但挚爱新世纪音乐的他,最终选择将一身才华奉献给瑞士山林!

班得瑞闻名全球的独特之处
莫过于班得瑞每当执行音乐制作时,从头到尾,深居在阿尔卑斯山林中,坚持不掺杂一丝毫的人工混音,直到母带完成!置身在欧洲山野中,让班得瑞拥有源源不绝的创作灵感,也找寻到自然脱俗的音质。每一声虫声、鸟鸣、花落流水,都是深入山林、湖泊,走访瑞士的阿尔卑斯山,罗春湖畔、玫瑰峰山麓,少女峰等处实地纪录。

媲美国家地理杂志的专业精神
有时为了采集自然音效,上山下水、甚至露宿荒野,对班得瑞来说算是家常便饭。比如必须熟知每一种候鸟的季节性与飞行路径,有时为了数分钟的音效,往往在荒野守侯达数月之久!有时必须举着比人身还长的录音架往峡谷中采集风声,整个过程险象环生,但也因为如此,班得瑞才能将这些天然的音效栩栩如生地融合在专辑之中……

更胜Discovery的听觉新感受
班得瑞成功的将新世纪风格结合大自然音效,扩展了音乐深度,构成现今最具高临场感的大自然音乐!班得瑞的音乐,从头到尾只强调一种轻柔的绝对性,没有艰涩难懂的曲风,没有生硬的个人风格,不只是悦耳好听,同时也是最纯净、最一尘不染的新世纪音乐典范!

大自然的『心灵投手』要你好听
奥利费史瓦兹展现他独特的编曲手法,以清爽的配器架构出零压力,零负担的乐曲,加上长年的录音室经验,细酌每一轨声道的分辨率,全音场效果更具神秘的空灵感!奥利费史瓦兹说:“班得瑞的音乐是兼具视觉、触觉、与听觉的,我们从大自然中所得到的创作灵感,宛如物线般将一直延伸,飞向到地球另一端,它不只是新世纪音乐,更是淬炼自大自然的心灵投手!”
班得瑞音乐最强的3大特色:
1. 实地走访瑞士的罗春湖畔和玫瑰山簏、阿尔卑斯山收藏自然元音。
2. 主要强调一种轻柔的绝对性,是最纯净、最能安定人心的音乐处方签 。
3. 独特超广角音场、空灵缥缈的编曲构成最具高临场感的大自然音乐。

班得瑞中文网站 http://www.bandari.net/

Pages: Prev 1 2 3 Next