精华内容
下载资源
问答
  • VBA调用Windows API的方法

    千次阅读 2019-10-08 17:52:14
    通过使用VBA处理一个或多个Office应用程序对象模型,可以容易地修改Office应用程序的功能或者能够使两个或多个Office应用程序协同工作以完成单个应用程序无法完成的任务。然而,使用VBA仅能控制操作系统的一小部分。...

    【转自“文韬武略,天下第一!”】:在VBA中使用Windows API

    VBA是一种强大的编程语言,可用于自定义Microsoft Office解决方案。通过使用VBA处理一个或多个Office应用程序对象模型,可以容易地修改Office应用程序的功能或者能够使两个或多个Office应用程序协同工作以完成单个应用程序无法完成的任务。然而,使用VBA仅能控制操作系统的一小部分。Windows API提供了控制操作系统绝大多数方面的功能。下面,介绍在VBA中使用Windows API的一些知识。

    理解APIs

    API只是一组函数,可用于处理组件、应用程序或操作系统。通常,API由一个或多个提供某种特定功能的DLLs组成。

    DLLs是包含函数的文件,能够从任何运行的Windows应用程序中调用DLLs。在运行时,DLL中的函数被动态链接到调用它的应用程序里。无论多少应用程序调用DLL中的函数,该函数仅存在于磁盘的单个文件中,并且DLL在内存中仅被创建一次。

    您可能最经常听说的API是Windows API,它包括组成Windows操作系统的DLLs。每个Windows应用程序都直接或间接地与Windows API相交互,Windows API确保运行在Windows下的所有应用程序都按一致的方式工作。

    除了Windows API外,还有其它发布的APIs可用。例如,邮件应用程序编程接口(MAPI)是一组用于编写电子邮件应用程序的DLLs。

    APIs通常是由创建Windows应用程序的C和C++程序员编写,但能够使用VBA调用DLL中的函数。因为大多数DLLs最初都是由C/C++程序员编写和文档规范,所以调用DLL函数与调用VBA函数不同。为了使用API,必需理解如何传递参数到DLL函数。

    为了调用Windows API中的函数,需要描述这些可用的函数的文档规范,如何在VBA中声明这些函数,以及如何调用它们。下面是两个有用的资源:

    1、Win32API.txt文件,包含Windows API中大多数函数的VBA Declare(声明)语句。可以使用API Viewer加载宏查找和复制需要的Declare语句。可以在下面的站点下载API声明查看器:

    http://www.activevb.de/rubriken/apiviewer/index-apiviewereng.html

    win32api.txt文件下载:

    2、Microsoft Platform SDK,包含复杂的Windows API文档。可以在下面的地址中查看:
    https://docs.microsoft.com/en-us/windows/win32/api/_winmsg/

    使用Declare语句

    在从VBA中调用DLL里的函数之前,必须为VBA提供在哪里找到函数以及如何调用该函数的信息,有两种方法:

    1、设置对DLL类型库的引用。

    2、在模块中使用Declare语句。

    设置对DLL类型库的引用是使用DLL中的函数的最容易的方法。一旦设置引用,就可以将其当作工程里的一部分一样调用DLL函数。然而,也要注意一些事项。首先,设置对多个类型库的引用会影响应用程序的性能;其次,不是所有的DLLs都提供类型库,虽然可以对没有提供类型库的DLL设置引用,但不能调用该DLL中的函数。

    注意,组成Windows API的DLLs没有提供类型库,因此不能设置对它们的引用并调用其中的函数。要调用Windows API中的函数,必须在工程里模块的声明部分包括Declare语句。

    Declare语句是一个定义,告诉VBA在哪里找到特定的DLL函数以及如何调用该函数。在代码中添加Declare语句最简单的办法是使用API Viewer加载宏,其中包含Windows API中大多数函数的Declare语句,也包含一些函数所需要的常量和类型定义。

    Declare语句声明的形式如下:

    [Public|Private]Declare Sub name Lib "libname" [Alias "aliasname"][([arglist])]
    [Public|Private]Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type]
    

    下面是GetTempPath函数的Declare语句的示例,该函数返回Windows临时文件夹的路径(默认为C:\Windows\Temp):

    Private Declare Function GetTempPath Lib "kernel32" _
    Alias "GetTempPathA" (ByVal nBufferLength As Long, _
    ByVal lpBuffer As String) As Long
    

    关键字Declare告诉VBA在工程中要包含的DLL函数的定义。在标准模块中的Declare语句可以是公共的或私有的,取决于你希望API函数仅用于单个模块还是整个工程。在类模块中,Declare语句必须是私有的。

    在关键字Function之后是函数的名字,具体地说,是从VBA中调用该函数时使用的名字。这个名字可以与API函数本身的名字相同,也可以在Declare语句中使用关键字Alias指定打算在VBA中通过不同的名字(别名)调用该函数。

    在上面的示例中,在DLL中API函数的名字是GetTempPathA,从VBA中调用该函数时使用的名字是GetTempPath。注意,DLL函数的实际名字出现在关键字Alias之后,同时也注意到GetTempPath是Win32API.txt文件用于该函数的别名,但你可以将其改变为任何你想要的名字。

    下面是为什么要在Declare语句中使用别名的一些理由:

    • 一些API函数的名字以下划线(_)开始,在VBA中是不合乎语法的。为了从VBA中调用该函数,需要使用别名。
    • 因为别名允许将DLL函数命名为你所希望的名字,所以可以使函数名字遵循你自已在VBA中的命名标准。
    • 因为API函数是区分大小写的,而VBA函数则不,所以可以使用别名来改变函数名的大小写。
    • 一些DLL函数带有接受不同数据类型的参数,这些函数的VBA声明语句定义这些参数为类型Any,调用带有声明为Any的参数的DLL函数是危险的,因为VBA不会执行任何数据类型检查。如果想避免传递类型为Any的参数的危险,可以声明相同的DLL函数的多个版本,每一个都具有不同的名字和不同的数据类型。
    • Windows API为所有接受字符串参数的函数都包含两个版本:ANSI版和Unicode版。ANSI版带有"A"后缀,正如上例所示,而Unicode版带有"W"后缀。虽然VBA使用Unicode,但在调用DLL中的函数之前,它将所有的字符串转换为ANSI字符串,因此在从VBA中调用Windows API函数时通常使用ANSI版。API Viewer加载宏自动为所有接6受字符串参数的函数命名别名,因此可以不必包含"A"后缀而调用该函数。

    关键字Lib指定包含函数的DLL。注意,在声明语句里以字符串形式包含DLL的名字。如果在系统中没有找到关键字Lib之后指定的DLL,对该函数的调用将失败,导致运行时错误:48,装载DLL错误。因为可以在VBA代码中处理这种错误,所以可以编写健壮的代码得体地处理错误。

    下面列出了Windows API中最常使用的DLLs:

    • Kernel32.dll:低级别的操作系统函数,例如内存管理和资源处理。
    • User32.dll:Windows管理函数,例如消息处理、计时器、菜单和通讯。
    • GDI32.dll:图像设备接口(GDI)库,包含设置输出的函数,例如绘图、显示上下文和字体管理。

    大多数DLLs,包括Windows API中的DLLs,都采用C/C++编写,因此,传递参数到DLL函数需要参数的理解以及C/C++接受的数据类型,而这些不同于VBA函数。

    同时,DLL函数的许多参数按值传递。默认情况下,VBA中的参数按引用传递。因此,当DLL函数需要按值传递的参数时,在函数定义中包括关键字ByVal是必要的。在函数定义中忽略ByVal关键字可能会在应用程序中导致无效的页错误。有时,可能会发生VBA运行时错误:49,坏的DLL调用协议。

    按引用传递参数传递该参数的内存位置到被调用的过程,如果该过程修改了参数的值,那么会修改该参数的唯一的副本,因此,当返回到调用过程时,参数包含的是修改后的值。

    按值传递参数到DLL函数,将传递该参数的副本,函数操作该参数的副本,避免了修改实际参数的内容。当返回到调用过程时,该参数包含与调用其它过程前相同的值。

    因为按引用传递允许在内存中修改参数值,如果不恰当地按引用传递参数,DLL函数可能会覆盖它不应该覆盖的内存,导致错误或者不可预料的结果。Windows维护许多值不应该被覆盖,例如,Windows为每个窗口赋惟一的32位标识符,称作句柄(handle)。句柄总是按值传递给API函数,因为如果Windows修改了某窗口的句柄,那么不再能够追踪到该窗口。(虽然关键字ByVal出现在String类型的一些参数前面,但是字符串总是按引用被传递到Windows API函数)

    上述声明语句接受两个参数,一个为Long型,另一个为String型,并返回一个Long型值。

    使用常量

    除了DLL函数的声明语句外,一些函数还需要定义常量以及在函数中使用的类型。在模块的声明部分包括常量和用户定义类型。

    如何知道函数需要的常量和用户定义类型呢?需要查看该函数的文档。Win32API.txt文件包含函数的常量和用户定义类型的定义。可以使用API Viewer加载宏找出这些常量和用户定义类型,并将它们复制到代码中。不巧的是,常量和用户定义类型不会以任何方式与需要它们的声明语句相联系,因此,仍然需要检查DLL函数的文档,决定哪个常量和类型与哪个声明语句匹配。

    函数可能需要传递常量来指明想要函数返回的信息。例如,GetSystemMetrics函数接受75个常量,每一个都指定操作系统的不同方面,该函数返回的信息取决于传递给它的常量。要调用GetSystemMetrics,不需要包括所有的75个常量,只需包括要使用的就可以了。

    建议定义常量而不是简单地传递它们代表的值。Microsoft确保在将来的版本中仍然会保留相同的常量,但不保证常量的值相同。

    DLL函数需要的常量通常是隐含的,因此需要查阅函数的文档来确定传递的常量,以返回特定的值。

    在《Professional Excel Development》中介绍了如何查找常量的值的方法。即在Microsoft的站点下载并安装核心SDK软件包,其中有一个名为"include"的子目录,所有用于创建动态链接库(DLL)的C++头文件都存放在这个目录中。通过搜索就能找到常量所在的文件,例如查找SM_CXSCREEN,会返回文件"winuser.h",打开该文件查询就可找到相关的常量。

    下面的示例是包括GetSystemMetrics函数的声明语句,接受两个常量,然后展示如何从属性过程中调用GetSystemMetrics,以像素为单位返回屏幕的高度。

    Declare Function GetSystemMetrics Lib "User32" (ByVal nIndex As Long) As Long
    Const SM_CXSCREEN As Long = 0 '屏幕宽度
    Const SM_CYSCREEN As Long = 1 '屏幕高度
    
    Public Property Get ScreenHeight() As Long
    '以像素为单位返回屏幕的高度
    ScreenHeight = GetSystemMetrics(SM_CYSCREEN)
    End Property
    
    Public Property Get ScreenWidth() As Long
    '以像素为单位返回屏幕的宽度
    ScreenWidth = GetSystemMetrics(SM_CXSCREEN)
    End Property
    

    使用用户定义类型

    用户定义类型是一种数据结构,可以存储多个相关的不同类型的变量,与C/C++中的结构一致。有时,传递空的用户定义类型到DLL函数,函数填充值;有时,从VBA填充用户定义类型,并将其传递给DLL函数。

    可以将用户定义类型作为一箱抽屉,每个抽屉可以包含不同类型的项目,但将它们组合在一起可以当作相关项目的单个箱子。可以从任何抽屉获得项目而不必担心存储在任何其它抽屉中的项目。

    要创建用户定义类型,使用Type … End Type语句。在Type…End Type语句里,列出了每个项目,包含值和数据类型。用户定义类型的元素可以是数组。

    下面的代码段展示如何定义RECT用户定义类型,和管理屏幕矩形块的几个Windows API函数一起使用。例如,GetWindowRect函数接受RECT类型的数据结构,使用关于窗口的左侧、顶部、右侧和底部位置的信息填充。

    Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
    End Type
    

    要传递用户定义类型到DLL函数,必须创建该类型的变量。例如,如果打算传递RECT类型的用户定义类型到DLL函数,那么就要包括变量声明,如下所示:

    Private rectWindow As RECT
    

    可以引用用户定义类型里的单个元素,如下所示:

    Debug.Print rectWindow.Left
    

    使用句柄

    调用DLLs中的函数之前需要理解的另一个重要的概念是句柄(handle)。简单地说,句柄是32位正整数,Windows用于识别窗口或另一个对象,例如字体或位图。

    在Windows中,窗口有许多不同的表现形式。事实上,在屏幕中看到的几乎所有事情都在窗口里,并且不能看到的大多数事情也在窗口里。窗口能够是一个绑定的屏幕矩形区域,就像您习惯看到的应用程序窗口一样。窗体中的控件,例如列表框或滚动条,也都是窗口,虽然不是所有类型的控件都是窗口。在桌面上显示的图标以及桌面本身,都是窗口。

    因为所有这些类型的对象都是窗口,所以Windows能够相同地对待它们。Windows提供给每个窗口一个唯一的句柄,并使用该句柄去处理窗口。许多API函数返回句柄或者接受句柄作为其参数。

    当窗口创建时Windows赋句柄给该窗口,当窗口销毁时Windows释放该句柄。虽然句柄保留的时间与窗口存在的时间相同,但不保证一个窗口在销毁并重新创建后有相同的句柄。因此,如果在变量中存储句柄,那么记住该窗口销毁后,该句柄不再有效。

    GetActiveWindow函数是返回窗口句柄的函数示例,此时,应用程序窗口是当前活动的窗口。GetWindowText函数接受某窗口的句柄,并且如果窗口有标题的话返回该窗口的标题。下面的程序使用GetActiveWindow返回活动窗口的句柄,GetWindowText返回其标题:

    Declare Function GetActiveWindow Lib "user32" () As Long
    Declare Function GetWindowText Lib "user32" _
    Alias "GetWindowTextA" (ByVal Hwnd As Long, _
    ByVal lpString As String, ByVal cch As Long) As Long
     
    Function ActiveWindowCaption() As String
    Dim strCaption As String
    Dim lngLen As Long
    '创建使用空字符填充的字符串
    strCaption = String$(255, vbNullChar)
    '返回字符串的长度
    lngLen = Len(strCaption)
    '调用GetActiveWindow来返回活动窗口的句柄
    '与字符串和其长度一起,传递句柄到GetWindowText
    If (GetWindowText(GetActiveWindow, strCaption, lngLen) > 0) Then
    '返回Windows已写入的值给字符串
    ActiveWindowCaption = strCaption
    End If
    End Function
    

    GetWindowText函数接受三个参数:窗口的句柄、将返回窗口标题里的空结尾的字符串、以及字符串的长度。

    下面列出了Excel中常用的窗口类名称:

    • Excel主窗口:XLMAIN
    • Excel桌面:XLDESK
    • Excel工作表:EXCEL7
    • Excel用户窗体:ThunderDFrame(Excel 2000以后版本)、ThunderRT6DFrame(Excel 2000以后版本,用于作为COM加载项时)、ThunderXFrame(Excel 97)
    • Excel状态栏:EXCEL4
    • Excel图表窗口:EXCELE(Excel2007以前版本)

    FindWindow函数使用类名和窗口标题查找窗口。下面的代码以像素为单位查找Excel主窗口的位置和大小:

    '包含窗口大小的用户定义类型
    Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
    End Type
    
    '查找窗口的API函数
    Declare Function FindWindow Lib "user32" _
    Alias "FindWindowA" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long
     
    '获取窗口大小的API函数
    Declare Function GetWindowRect Lib "user32" ( _
    ByVal hWnd As Long, _
    lpRect As RECT) As Long
     
    Sub ShowExcelWindowSize()
    Dim hWnd As Long, uRect As RECT
    '获取Excel主窗口的句柄
    'Excel 2002及以后版本也可使用hWnd=Application.Hwnd
    hWnd = FindWindow("XLMAIN", Application.Caption)
    '将窗口大小信息存入到RECT结构中
    GetWindowRect hWnd, uRect
    '显示结果
    MsgBox "这个Excel窗口的尺寸为:" & _
    vbCrLf & "左侧:" & uRect.Left & _
    vbCrLf & "右侧:" & uRect.Right & _
    vbCrLf & "顶部:" & uRect.Top & _
    vbCrLf & "底部:" & uRect.Bottom & _
    vbCrLf & "宽度:" & (uRect.Right - uRect.Left) & _
    vbCrLf & "高度:" & (uRect.Bottom - uRect.Top)
    End Sub
    

    调用函数

    虽然调用DLL函数的许多方式与调用VBA函数相似,但是开始时有一些不同可能会使DLL函数混淆。下面将介绍如何输入DLL函数中的参数并加前缀、如何返回字符串、如何传递数据结构、能够接受什么返回值、以及如何获取错误信息。

    参数数据类型

    在C/C++中使用的数据类型、用于描述它们的标记都不同于在VBA中的用法,下面描述了DLL函数中常用的数据类型以及它们在VBA中的等效表示。

    C/C++数据类型匈牙利前缀描述等效的VBA表示
    BOOLb8位布尔值。0表示False;非0表示TrueBoolean或Long
    BYTEch8位无符号整数Byte
    HANDLEh32位无符号整数,代表Windows对象的句柄Long
    intn16位符号整数Integer
    longl32位符号整数Long
    LPlp32位对内存中C/C++结构、字符串、函数或其它数据的长指针Long
    LPZSTRlpsz32位对C类型空结尾字符串的长指针Long

    虽然您应该熟悉这些数据类型和前缀,但前面提到的Win32API.txt文件包含了准备在VBA中使用的声明语句。如果在代码中使用这些声明语句,那么函数参数已经定义了正确的VBA数据类型。

    在《Excel 2007 VBA参考大全》的第27章,详细介绍了如何将C-样式声明转换为VBA声明语句。

    只要已经定义并传递了正确的数据类型,调用DLL函数与调用VBA函数采取相同的方法。当然也有例外,这将在下面的内容中介绍。

    从DLL函数中返回字符串

    DLL函数不会以VBA函数相同的方法返回字符串。因为字符串总是按引用传递到DLL函数,DLL函数能够修改字符串参数的值。宁可返回字符串作为函数的返回值,就像可能在VBA中做的那样,DLL函数返回字符串到传递给该函数的String类型的参数。函数的实际返回值经常是一个长整型值,指定写入到字符串参数的字节数量。

    接受字符串参数的DLL函数获得指针,指向内存中该字符串的位置。指针只是内存地址,表明在哪里存储字符串。因此,当从VBA中传递字符串到DLL函数时,传递给DLL函数一个指针,指向内存中的字符串。接着,这个DLL函数修改存储在那个地址的字符串。

    要调用写到String变量的DLL函数,需要采取额外的步骤合适地格式字符串。首先,String变量必须是空结尾字符串。一个空结尾字符串以特定的空字符结束,空字符通过VBA常量vbNullChar来指定。

    其次,DLL函数不能修改已经创建的字符串的大小。因此,需要确保传递给函数的字符串足够大以容纳整个返回值。当传递字符串到DLL函数中时,通常需要指定在另一个传递的参数中字符串的大小。Windows追踪字符串的长度,以确保不会覆盖掉字符串已使用过的内存。

    传递字符串到DLL函数中的一个好方法是创建String变量,并使用String$函数在其中填充空字符,使其足够大以容纳函数返回的字符串。例如,下面的代码创建一个144字节长的字符串,并使用空字符串填充:

    Dim strTempPath As String
    strTempPath = String$(144, vbNullChar)
    

    当传递字符串到DLL函数中时,如果不知道字符串的长度,那么可以使用Len函数确定其长度。

    获取Windows临时文件夹的GetTempPath函数,就是返回String值的DLL函数的例子。该函数接受两个参数,一个空结尾的字符串变量和一个包含字符串长度的数值变量。修改该字符串以便包含路径,例如C:\Temp\。(Windows需要一个临时文件夹存在,于是该函数应该总是返回该文件夹的路径。如果由于某种原因不存在临时文件夹,GetTempPath返回0)。

    下面的程序调用GetTempPath函数获取Windows临时文件夹的路径:

    Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _
    (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
    
    Property Get GetTempFolder() As String
    '返回用户临时文件夹的路径.
    '对于根目录,Windows需要一个临时文件夹存在
    '因此应该总是返回其路径
    '以防万一,检查GetTempPath的返回值
    Dim strTempPath As String
    Dim lngTempPath As Long
    '使用空字符填充字符串
    strTempPath = String(144, vbNullChar)
    '获得字符串的长度
    lngTempPath = Len(strTempPath)
    '调用GetTempPath,传递字符串长度和字符串
    If (GetTempPath(lngTempPath, strTempPath) > 0) Then
    'GetTempPath返回路径到字符串中.
    '截去字符串开始的空字符
    GetTempFolder = Left(strTempPath, InStr(1, strTempPath, vbNullChar) - 1)
    Else
    GetTempFolder = ""
    End If
    End Property
    

    注意,当传递字符串到函数中时,使用空字符填充该字符串。函数写入返回的字符串值"C:\Temp"到字符串变量的第一部分中,并且剩下的保留空字符填充,接着使用Left函数截取字符串。

    GetTempPath函数的实际返回值是已经被写到字符串变量中的字符数。如果返回的字符串是"C:\Temp",那么GetTempPath函数返回8。

    注意,这仅对从函数返回字符串时传递空结尾字符串及其大小是必需的。如果函数不返回字符串到字符串参数中,而是接受对函数指定信息的字符串,那么只需传递正常的VBA字符串变量。

    传递用户定义类型到DLL函数

    许多DLL函数需要通过使用预定义的格式传递数据结构。当从VBA中调用DLL函数时,根据函数的需求传递已经定义的用户定义类型。

    通过查看函数的声明语句,您能够理解什么时候需要传递用户定义类型以及需要在代码中包括哪种类型定义。需要数据结构的参数总是被声明为长指针:指向内存中数据结构的32位数字值。为长指针参数约定的前缀是"lp"。此外,参数的数据类型是数据结构的名称。

    例如,看看GetLocalTime函数和SetLocalTime函数的声明语句:

    Private Declare Sub GetLocalTime Lib "kernel32" _
    (lpSystem As SYSTEMTIME)
    Private Declare Function SetLocalTime Lib "kernel32" _
    (lpSystem As SYSTEMTIME) As Long
    

    两个函数都接受SYSTEMTIME类型的参数,即包含日期和时间信息的数据结构。下面是SYSTEMTIME类型的定义:

    Private Type SYSTEMTIME
    wYear As Integer
    wMonth As Integer
    wDayOfWeek As Integer
    wDay As Integer
    wHour As Integer
    wMinute As Integer
    wSecond As Integer
    wMilliseconds As Integer
    End Type
    

    要将数据结构传递给函数,必须声明SYSTEMTIME类型的变量,如下所示:

    Private sysLocalTime As SYSTEMTIME
    

    当调用GetLocalTime时,传递SYSTEMTIME类型的变量到该函数,并且使用表示当前本地的年、月、日、星期几、小时、分、秒、毫秒的数字值填充该数据结构。例如,下面的Property Get程序调用GetLocalTime返回表明当前小时的值:

    Public Property Get Hour() As Integer
    '返回当前时间,然后返回小时
    GetLocalTime sysLocalTime
    Hour = sysLocalTime.wHour
    End Property
    

    当调用SetLocalTime时,也传递了SYSTEMTIME类型的变量,但首先提供数据结构的一个或多个元素的值。例如,下面的Property Let程序设置本地系统时间的小时值。首先,调用GetLocalTime函数获取本地时间的当前值到数据结构中,然后使用传递给属性过程的值更新数据结构的sysLocalTime.wHour的值。最后,调用SetLocalTime函数,传递相同的数据结构,包含通过GetLocalTime加新小时值而取得的值。

    Public Property Let Hour(intHour As Integer)
    '获取当前时间以便所有值都是当前的
    '然后设计本地时间的小时部分
    GetLocalTime sysLocalTime
    sysLocalTime.wHour = intHour
    SetLocalTime sysLocalTime
    End Property
    

    GetLocalTime函数和SetLocalTime函数与GetSystemTime函数和SetSystemTime函数相似。主要的不同在于,GetSystemTime函数和SetSystemTime函数表达的时间为格林威治标准时间。例如,如果本地时间是午夜12时,而您居住在西海岸,那么格林威治标准时间就是上午8时,有8小时的时差。GetSystemTime函数返回当前时间即8:00 A.M,而GetLocalTime返回午夜12:00。

    理解Any数据类型

    一些带有一个参数的DLL函数可以接受多个数据类型。在DLL函数的声明语句中,这样的参数被声明为类型Any。VBA允许传递任何数据类型到这个参数。然而,DLL函数可能被设计为接受仅仅两个或三个不同的数据类型,因此传递错误的数据类型可能会导致应用程序错误。

    通常,当在VBA工程中编译代码时,VBA对传递给每个参数的值执行类型检查。也就是说,确保传递的值的数据类型与函数定义中的参数的数据类型相匹配。例如,如果参数定义为Long型,而试图传递String型的数值,则会发生编译时错误。这适用于调用内置的VBA函数、用户定义函数、或者DLL函数。当将参数声明为类型Any时,不会进行类型检查,因此当传递值到这种类型的参数时应该谨慎。

    一些具有一个参数的DLL函数可以接受字符串或者指向字符串的空指针。指向字符串的空指针是一个特别的指针,指令Windows忽略所给的参数。它与零长度字符串("")不同。在VBA的早期版本中,程序员必须声明参数为类型Any,或者声明DLL函数的两个版本,即一个版本定义参数类型为String,一个版本定义参数类型为Long。现在VBA包括vbNullString常量,代表指向字符串的空指针,这样可以声明参数为String类型,并且在需要传递空指针的情形下传递vbNullString常量。

    获取错误信息

    DLL函数中发生的运行时错误的行为不同于VBA中的运行时错误,即没有错误消息框显示。当运行时错误发生时,DLL函数返回某值表时发生了错误,而且错误不会中断VBA代码的执行。

    Windows API中的一些函数存储运行时错误的错误信息。如果使用C/C++编程,可以使用GetLastError函数获取关于发生的最后一次错误的信息。然而,从VBA中,GetLastError函数可能返回不确切的结果。要从VBA获得关于DLL错误的信息,可以使用VBA的Err对象的LastDLLError属性。LastDLLError属性返回发生的错误号。

    为了使用LastDLLError属性,需要知道与错误相对应的错误号。在Win32API.txt文件没有这方面的可用信息,而Microsoft Platform SDK中可以找到。

    下面的示例展示在已经调用了Windows API中的函数后如何使用LastDLLError属性。PrintWindowCoordinates程序接受窗口句柄,并调用GetWindowRect函数。GetWindowRect使用组成窗口的矩形的边的长度填充RECT数据结构。如果传递了无效的句柄,将发生错误,并且可以通过LastDLLError属性获得错误号。

    Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, _
    lpRect As RECT) As Long
     
    Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
    End Type
     
    Const ERROR_INVALID_WINDOW_HANDLE As Long = 1400
    Const ERROR_INVALID_WINDOW_HANDLE_DESCR As String = "无效的窗口句柄."
     
    Sub PrintWindowCoordinates(hwnd As Long)
    '以像素为单位打印窗口左侧,右侧,顶部和底部位置
    Dim rectWindow As RECT
    '传递窗口句柄和空的数据结构
    '如果函数返回0,那么错误就发生了
    If GetWindowRect(hwnd, rectWindow) = 0 Then
    '因为传递了无效的句柄
    '所以如果发生错误则检查LastDLLError并显示对话框
    If Err.LastDllError = ERROR_INVALID_WINDOW_HANDLE Then
    MsgBox ERROR_INVALID_WINDOW_HANDLE_DESCR, _
    Title:="错误!"
    End If
    Else
    Debug.Print rectWindow.Bottom
    Debug.Print rectWindow.Left
    Debug.Print rectWindow.Right
    Debug.Print rectWindow.Top
    End If
    End Sub
    

    要获得活动窗口的坐标,可以通过使用GetActiveWindow函数返回活动窗口的句柄,并将结果传递到前面示例定义的过程中。要使用GetActiveWindow函数,包括下面的声明语句:

    Declare Function GetActiveWindow Lib "user32" () As Long
    

    输入下面的过程后运行:

    Sub test()
    PrintWindowCoordinates (GetActiveWindow)
    End Sub
    

    要生成一条错误消息,随便使用一个长整型数值调用这个过程。

    参考资源:

    David Shank,《Office VBA and the Windows API》

    《Excel 2007 VBA参考大全》

    《Professional Excel Development》

    《VBA and Macros for Microsoft Excel》

    展开全文
  • vba完整的例子,有用户窗口操作,选择文件操作,读取文件,进行逻辑计算,获得结果,输出到excel表中。贪心算法,欧几里得定律。
  • 朋友工作中有多个Word文件,每次做更新时都要更新文档内的日期,每次手工更改都比较耗费时间,加上公司电脑不能装未授权的软件,且只支持英文,于是就根据这个需求,参考一些网上的代码,并做了一些升级,增加了界面...

    背景:朋友工作中有多个Word文件,每次做更新时都要更新文档内的日期,每次手工更改都比较耗费时间,加上公司电脑不能装未授权的软件,且只支持英文,于是就根据这个需求,参考一些网上的代码,并做了一些升级,增加了界面、备份等功能,制作出这个VBA。下面是几个主要部分的VBA代码。

    图1 VBA结构图

    VBA结构图

    图2 窗体界面

    窗体界面

    '窗体界面
    Private Sub CommandButton1_Click() 'Replace按钮
    Call Start_replace
    Unload Me
    End Sub
    
    Private Sub CommandButton2_Click() 'Clear按钮
    'CheckBox1.Value = False
    'CheckBox2.Value = False
    'CheckBox3.Value = False
    'CheckBox4.Value = False
    TextBox1.Value = ""
    TextBox2.Value = ""
    End Sub
    
    '调用窗体界面(模块1)
    Sub Replace_text()
    UserForm1.Show
    End Sub
    
    '开始替换(模块2)
    Public Sub Start_replace()
    Application.ScreenUpdating = False  '关闭屏幕闪
    Dim myFile$, myPath$, backup_file, Backup_path, i%, myDoc As Object, myBackup As Object, myAPP As Object, txt$, Re_txt$
    Set myAPP = New Word.Application
    With Application.FileDialog(msoFileDialogFolderPicker) '允许用户选择一个文件夹
        .Title = "选择目标文件夹"
        If .Show = -1 Then
            myPath = .SelectedItems(1) '读取选择的文件路径
        Else
            Exit Sub
        End If
    End With
    myPath = myPath & ""
    
    MatchCase_Value = UserForm1.CheckBox1.Value
    MatchWholeWord_Value = UserForm1.CheckBox2.Value
    MatchByte_Value = UserForm1.CheckBox3.Value
    MatchWildcards_Value = UserForm1.CheckBox4.Value
    Backup = UserForm1.CheckBox5.Value
    Be_replaced = UserForm1.TextBox1.Value
    Replace_with = UserForm1.TextBox2.Value
    
    txt = Be_replaced
    Re_txt = Replace_with
    myAPP.Visible = True '是否显示打开文档
    
    'Backup
    If (Backup = True) Then
        Backup_path = "E:\backup\"
        backup_file = Dir(myPath & "\*.doc*")
        Do While backup_file <> ""
            Set myBackup = myAPP.Documents.Open(myPath & "\" & backup_file)
            myBackup.SaveAs "E:\backup\" & backup_file
            myBackup.Close
            backup_file = Dir
        Loop
    End If
    
    'Replace
    myFile = Dir(myPath & "\*.doc*")
    Count = 0
    Do While myFile <> "" '文件不为空
        Set myDoc = myAPP.Documents.Open(myPath & "\" & myFile)
        If myDoc.ProtectionType = wdNoProtection Then '是否受保护
            With myDoc.Content.Find
                .Text = txt
                .Replacement.Text = Re_txt
                .Forward = True
                .Wrap = 2
                .Format = False
                .MatchCase = MatchCase_Value
                .MatchWholeWord = MatchWholeWord_Value
                .MatchByte = MatchByte_Value
                .MatchWildcards = MatchWildcards_Value
                .MatchSoundsLike = False
                .MatchAllWordForms = False
                .Execute Replace:=2
            End With
        End If
        myDoc.Save
        myDoc.Close
        myFile = Dir
        Count = Count + 1
    Loop
    myAPP.Quit '关掉临时进程
    Application.ScreenUpdating = True
    If (Backup = True) Then
        MsgBox (Count & " documents replaced successfully and backup in " & Backup_path)
    ElseIf (Backup = False) Then
        MsgBox (Count & " documents replaced successfully!")
    End If
    End Sub
    
    
    图3 运行结果

    运行结果

    • 不足之处:目前还只能对一个文件夹里的全部word批量替换,不能进行选择;不能实时查看到匹配到内容,所以建议替换时将文件拷贝到临时文件夹再进行替换。(尽管有备份功能)
    • 本文Word下载地址

    链接:https://pan.baidu.com/s/1ZsrfjK3GY4cLOlkm-h12rQ
    提取码:mup5

    展开全文
  • Excel VBA(08)窗体和控件

    千次阅读 2020-04-29 16:36:58
    要么用代码调用窗体的 show 方法 3、关闭窗体 代码关闭是 unload testform方法 4、显示设置 窗体标题:caption 背景色:backcolor 背景图片:picture,代码里面可以使用loadpicture()方法进行加载 属性窗口...

    基础部分

    一、窗体的基本操作

    1、窗体插入

    2、运行窗体

    • 要么直接在窗体的界面点击运行按钮
    • 要么用代码调用窗体的 show 方法

    3、关闭窗体

    • 代码关闭是 unload testform方法

    4、显示设置

    • 窗体标题:caption
    • 背景色:backcolor
    • 背景图片:picture,代码里面可以使用loadpicture()方法进行加载

    属性窗口里面可以查看

    5、位置大小

    • top、left、height、width
    • startupPosition 启动显示位置

    6、显示行为

    • showModal 的值就是 true 或者false 可以设置显示窗体的时候是否可以进行其他的操作

    7、删除窗体

    二、控件的基本操作

    1、控件插入

    在这里插入图片描述

    2、删除

    3、对齐

    • 菜单栏格式里面
    • 可以选中多个控件进行布局的操作

    4、tab键相关

    在这里插入图片描述

    5、控件循环

    • 所有控件集合 controls
    • controls(index) controls("name")可以选定具体的控件

    6、控件类型判断

    • typename 判断控件类型
    Private Sub UserForm_Click()
        For i = 0 To Controls.Count - 1
            If TypeName(Controls(i)) = "TextBox" Then
                MsgBox Controls(i).Value
            End If
        Next i
    End Sub
    

    窗体事件

    • 和前面讲的工作表事件等是一样的,只需要特别注意一下键盘事件和鼠标事件
      在这里插入图片描述

    一、键盘事件

    1、keydown

    • keyCode 唯一,shift 参数不同的值分别代表ctrl、shift、alt
    Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    ''''''''''''''code
    End Sub
    

    2、keyup

    Private Sub UserForm_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    ''''''''''''''code
    End Sub
    

    3、keypress

    Private Sub UserForm_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    ''''''''''''''code
    End Sub
    

    keydown keypress 都是按键按下,但是一般使用keydown,功能更加强大

    二、鼠标事件

    1、mousedown

    • button不同的值分别代表左右和中键
    • shift 也是和上面一样
    • x 和 y 就是鼠标的位置坐标
    Private Sub UserForm_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    
    End Sub
    

    2、mouseup

    Private Sub UserForm_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    
    End Sub
    

    3、mousemove

    Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    
    End Sub
    

    vba一行的代码很长的话可以使用空格加下划线然后enter的方式进行换行


    标签和按钮

    一、按钮

    1、快捷键设置

    • 就是设置 Accelerator 属性,然后通过 alt 键加设置的键就可以激活按钮的 click 事件

    2、enter 和 esc 响应

    • 就是 default 和 cancel 属性都设置为true,然后窗体显示并且焦点在按钮上的时候按 esc 和 enter 就会激发按钮的 click 事件

    二、标签

    • label 标签基本就是用来显示一定的提示内容
    • 具体的属性使用的时候可以通过属性窗口进行摸索

    文字框

    • maxLength 和 autoTab 属性可以实现输入多少个字符自动切换
    • 基本的事件也是可以通过名字完全看懂的,不多说
    • 其他的使用基本上也是琢磨属性窗口的内容

    列表和组合框

    • 这两个的用法基本是一致的,就是下拉框比一般的列表更加节省空间而已
    • 选项的填充可以使用 additem 方法,可以用数组赋值给 list 属性,可以直接引用单元格区域赋值到RowSource 属性
    • 选项的移除使用 removeitem 方法

    一、combobox

    • listIndex 代表当前选中项的索引:ComboBox1.List(ComboBox1.ListIndex, 2)
    • list 可以获取到具体的某个行列的值,第一个参数是行数,后一个是列数

    二、listbox

    • multiselect 设置是否可以选中多行
    • selected 方法可以判断选项是否选中
    Private Sub ComboBox1_Change()
        Label1.Caption = "选中项的返回值是:" & ComboBox1.Value
    End Sub
    
    Private Sub CommandButton1_Click()
        Dim arr
        arr = Sheets(1).Range("a8:e15")
        ComboBox1.ColumnCount = 5 '设置下拉框显示的列数
        ComboBox1.BoundColumn = 3 '设置选中返回的列的数据
        ComboBox1.TextColumn = 3 '设置选中下拉框的显示列
        ComboBox1.List = arr
    End Sub
    Private Sub CommandButton2_Click()
        ListBox1.RowSource = "Sheet1!A8:E12"
        ListBox1.ColumnCount = 5
        ListBox1.ColumnHeads = True
        ListBox1.BoundColumn = 3
        ListBox1.TextColumn = 2
    End Sub
    
    Private Sub CommandButton3_Click()
        MsgBox ComboBox1.List(ComboBox1.ListIndex, 2)
    End Sub
    
    Private Sub CommandButton4_Click()
        For i = 0 To ListBox1.ListCount - 1
            If ListBox1.Selected(i) Then
                MsgBox ListBox1.List(i, 2)
            End If
        Next i
    End Sub
    

    在这里插入图片描述


    单选、复选、框架、多页

    一、单选、复选、框架

    • 单选和复选必须要通过框架才能成组
    • 不然对于单选框一个窗体的话只能有一个被选中
    Private Sub Frame1_Click()
        If 男.Value Then sr = "you sex:" & 男.Caption
        If 女.Value Then sr = "you sex:" & 女.Caption
        If 中.Value Then sr = "you sex:" & 中.Caption
        TextBox1.Value = sr
    End Sub
    
    Private Sub Frame2_Click()
        Dim sr As String
        sr = "爱好:"
        If 唱歌.Value Then sr = sr & 唱歌.Caption & Chr(10)
        If 跳舞.Value Then sr = sr & 跳舞.Caption & Chr(10)
        If 篮球.Value Then sr = sr & 篮球.Caption & Chr(10)
        TextBox2.Value = sr    
    End Sub
    

    在这里插入图片描述

    二、微调、滚动调节

    • 二者基本的使用都是一致的
    • 都包含 max 、min最大最小值属性
    • 滚动条支持步长 smallChange 和 largeChange 属性,微调只支持前者
    • 对滚动条来说 smallChange 设置的是点击箭头按钮的该表量,largeChange 是设置直接点击滚动条的改变量
    Private Sub ScrollBar1_Change()
        ScrollBar1.SmallChange = 2
        ScrollBar1.LargeChange = 10
        ScrollBar1.Min = 10
        ScrollBar1.Max = 80
        TextBox4.Value = ScrollBar1.Value
    End Sub
    
    Private Sub SpinButton1_Change()
        SpinButton1.SmallChange = 2
        TextBox3.Value = SpinButton1.Value
    End Sub
    

    在这里插入图片描述

    vba 中的Me变量代表代码所在的对象,如果是工作表代码就代表该工作表,如果是窗体代码就代表窗体

    三、多页

    1、图片控件

    Private Sub Image1_Click()
        f = Dir("C:\Users\user\Desktop\*.jpg")
        Do
            ListBox1.AddItem f
            f = Dir
        Loop While (Len(f) <> 0)
    End Sub
    Private Sub ListBox1_Click()
        Dim path As String
        path = "C:\Users\user\Desktop\" & ListBox1.Value
        Image1.Picture = LoadPicture(path)
    End Sub
    

    在这里插入图片描述

    2、多页

    • 选项卡的索引是从 0 开始的
    • style 属性设置为 2 可以隐藏上面的 tab 卡
    Private Sub Label1_Click()
        MultiPage1.Style = 2
    End Sub
    
    Private Sub MultiPage1_Change()
        MsgBox MultiPage1.Value
        MultiPage1.Value = 3
    End Sub
    

    ListView控件


    TreeView控件


    日期和进度条(略)


    综合实例


    命令栏操作(略)
    功能区操作(略)
    代码操作代码(略)

    展开全文
  • 14 日志导出 15 excle文件格式转换 16 VBA隐藏表格 17 改变窗体外观 18 更改Sheet名 19 对文件夹中多个文件进行操作 20 合并单元格 21 插入一行单元格 22 在指定单元格内输入字符 23 调整行高和列宽 24 跳转到该列...
    											目   录
    
    编号名称编号名称编号名称编号名称编号名称
    1错误类2全局变量3开关4弹窗5换行
    6调试打印7引用8延时9日志窗口显示(全局文本)10调用外部软件
    11按钮状态改变12调用参数13路径选择14日志导出15excle文件格式转换
    16VBA隐藏表格17改变窗体外观18更改Sheet名19对文件夹中多个文件进行操作20合并单元格
    21插入一行单元格22在指定单元格内输入字符23调整行高和列宽24跳转到该列最后一个数值25获取当前单元格所在的行号和列号
    26格式刷(公式复用)27筛选28查找替换29单元格颜色30字符居中
    31添加公式32复制某个单元格33单元格引用34单元格边框35复选框执行
    36取消(退出软件)37If Else38For Next39While wend40Do Loop
    41附 录:42434445
    											 代   码
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    1、错误类
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    错误类:
    On Error Resume Next '忽略运行过程中可能出现的错误(添加在函数的前面)
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    2、设置全局变量
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    设置全局变量:
    public i '将i设置成全局变量
    sub 全局变量()
    end sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳、
    3、开关
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    开关:
    	public i '将i设置成全局变量
    	sub 点击一下开再点击一下关()
    	if i = 0 then
    		'编写需要的代码满足何种条件后将i置为1
    		i = 1
    	else
    		'编写需要的代码满足何种条件后将i置为0
    		i = 0
    	end if
    	end sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    4、弹窗
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    弹窗:
    sub 弹窗()
    	MsgBox("这里编写弹出的提示框显示内容")
    end sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    5、换行
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    换行显示:
    & chr(10)
    长代码连写:
     _
    If i = 1 _
    Then
    i = 0
    End If
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    6、调试打印
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    打印参数值:
    Debug.print *'*为变量、引用值、固定字符等
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    7、引用
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    引用:
    x = 1
    msgbox("这是要引用值x显示的地方") & x’文本后引用
    MsgBox ("文件执行" & x & "日志已导出到")'这是中间引用
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    8、延时
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    延时:
    Application.Wait Now + TimeValue("00:00:1")'最低延时为1秒
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    9、日志窗口显示(全局文本)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    日志:
    public x '将x设置成全局日志内容
    sub 日志()
    日志.text = "这是日志类容"'固定日志(方法1)
    全局日志.text = x + "这是新日志类容"'x为之前日志类容(方法2)
    x = 全局日志.text
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    10、调用外部软件
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    调用外部软件:
    sub 调用外部软件()
    On Error Resume Next '忽略运行过程中可能出现的错误
    Set oShell = CreateObject("WSCript.shell")
    ret = oShell.Run(Application.ActiveWorkbook.Path & "\调用软件名称.exe " & " 传入的参数", 0, True) 
    Set oShell = Nothing
    end sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    11、按钮状态改变
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    按钮控件状态改变:
    '总窗口名称为该用户窗体最外层的背景窗口
    总窗口名称.Controls("按钮控件名称").Value = False'False为关
    总窗口名称.Controls("按钮控件名称").Value = True'True为开
    判断复选框是否被选中:
    if 总窗口名称.Controls("按钮控件名称").Value = True Then'True为选中
    '这里写被选中后要执行的代码
    else
    '这里写没被选中时要执行的代码
    End if
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    12、调用参数
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    调用参数:
    调用.text = "在对应窗口显示这一段字符"'在文本窗口显示文字(调用为控件名称)
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    13、路径选择
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    路径选择:
    public x '将x设置成全局路径变量
    Private Sub 路径选择_Click()
    Set objFD = Application.FileDialog(msoFileDialogFolderPicker)
    With objFD
    If .Show = -1 Then
    ' 如果单击了确定按钮,则问将选取的路径保存在变量中
    x = .SelectedItems(1)
    End If
    End With
    Debug.Print x
    文件路径.Text = x'输出文件路径日志
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    14、日志导出
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    导出日志txt:
    public x '将x设置成全局路径变量
    public i '将i设置成全局日志变量
    Private Sub 日志导出_Click()
    Dim Fso, Fil
    日志导出.Caption = "日志已导出"'将按钮文字变成日志已导出
    日志导出.Enabled = False'日志导出按钮不可编辑
    Application.Wait Now + TimeValue("00:00:5")'按钮文字改变延时
    myPath1 = "" & x  '导出的日志所在的文件夹路径
    Set Fso = CreateObject("Scripting.FileSystemObject") '访问系统文件
    Set Fil = Fso.OpenTextFile(myPath2, 8, 1) '打开文本文件
        Fil.Write i '将i中所含所有字符写入文本
        Fil.WriteBlankLines (5) '换5行
    Fil.Close '关闭文本文档
    日志导出.Caption = "导出日志"'将日志导出按钮文字变成导出日志
    日志导出.Enabled = True'日志导出按钮不可编辑
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    15、excle文件格式转换
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Private Sub CSV转xlsx_Click() 'CSV转Xlsx
         Dim sDir As String
         Dim curdir As String
         curdir = "设置文件路径" '找到需要转换的文件路径
         sDir = Dir(curdir & "\*.csv")'显示文件列表
         While Len(sDir)'循环当前文件夹中文件个数
         Workbooks.Open FileName:=curdir & "\" & sDir'打开当前文件夹中符合条件的文件
         Dim temp As String'(这个定义需要在循环内部)
         temp = Left(sDir, Len(sDir) - 4)
         'Left函数从给定输入字符串的左侧返回指定数量的字符
         '语法:Left(String, Length)
         'String - 必需的参数。 输入从左侧返回指定数量的字符的字符串
         'Length - 必需的参数。 一个整数,指定要返回的字符数
         ActiveWorkbook.SaveAs FileName:=curdir & "\" & temp & ".xlsx", _
            FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False'另存为 & temp & .xlsx类型的文件
            ActiveWorkbook.Save'保存当前显示文件
            ActiveWindow.Close'关闭当前显示文件
         sDir = Dir
         Wend
    End If
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    16、自动打开excle中用户窗体和隐藏VBA中excle表格(只显示用户窗体)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻
    样例

    自动打开excle中用户窗体和隐藏VBA中excle表格(只显示用户窗体)
    在Microsoft excle 对象中的ThisWorkbook中
    Private Sub WORKBOOK_OPEN()
    用户主窗体名称.Show'自动打开用户窗体
    Application.Visible = False '隐藏EXCEL主窗口
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    17、改变窗体外观(背景色,是否隐藏等)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    改变窗体外观(背景色,是否隐藏等)
    Private Sub 改变外观_Click() 
        窗体控件1.BackStyle = fmBackStyleOpaque '背景显示白色
        窗体控件2.BackStyle = fmBackStyleTransparent '背景显示为透明
        窗体控件1路径显示.BackStyle = fmBackStyleOpaque '背景显示白色
        窗体控件2路径显示.BackStyle = fmBackStyleTransparent '背景显示为透明
        窗体控件1路径显示.SpecialEffect = fmSpecialEffectSunken '路径显示背景框
        窗体控件2路径显示.SpecialEffect = fmSpecialEffectFlat '路径不显示背景框
        窗体控件1.Enabled = True '可以点击操作
        窗体控件2.Enabled = False '不可点击操作
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    18、更改Sheet名
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    更改Sheet名
    Private Sub 更改Sheet名_Click() 
    Dim sDir As String
    Dim curdir As String
    curdir = "" & sPath1 '找到需要转换的文件路径
    If Dir(curdir & "\*.csv") = "" Then'判断文件后缀
    sDir = Dir(curdir & "\*.xlsx")
    Else
    sDir = Dir(curdir & "\*.csv")
    End If
    While Len(sDir)'遍历文件后依次操作
    Workbooks.Open FileName:=curdir & "\" & sDir
    Dim temp As String
    temp = Left(sDir, Len(sDir) - 4)
    ActiveWorkbook.SaveAs FileName:=curdir & "\" & temp & ".xlsx", _
        FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
        Sheets(1).Name = "Sheet1" '修改文件表的Sheet名称为Sheet1
        ActiveWorkbook.Save
        ActiveWindow.Close
    sDir = Dir
    Wend
    End If
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    19、对文件夹中多个文件进行操作
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Dim sPath1 As String'定义的sPath1为全局变量
    Private Sub 多文件操作_Click()
            Dim aList() As String
                curdir1 = "" & sPath1 '文件夹目录
                sDir1 = Dir(curdir1 & "\*.xlsx") '不同后缀记得替换:(csv、xlsx、xlsm)
                '可以将sDir1增加判断对不同类型的文件进行操作。
            Do While sDir1 <> 'sDir1不等于空
            If sDir1 = "" Then '用来判断文件夹中是否还存在文件,如果没有文件则跳出循环
            MsgBox ("当前文件夹中没有符合筛选条件的文件,请确认路径是否正确")
            Exit Sub'退出当前函数
            End If
                    ReDim Preserve aList(0 To i) As String  '重定义数组大小
                    aList(i) = sDir1 '列表a
                    Workbooks.Open FileName:=curdir1 & "\" & aList(i) '打开文件
                    Application.WindowState = xlMaximized '窗口最大化
                    '在这里添加操作代码,例如增、删、改、查等
    				ActiveWorkbook.Save
                    ActiveWindow.Close
    		i = i + 1
    		sDir = Dir()'查找下一个目录
    		Loop
    	end Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    20、单元格格式设置(合并单元格)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

     Range("A1:B1").Select'单元格A1到B1
            With Selection
                .HorizontalAlignment = xlCenter '水平对齐
                .VerticalAlignment = xlCenter '垂直对齐
                .WrapText = False '文字换行(居中为True)
                .Orientation = 0 '方向(文本方向)
                .AddIndent = False '添加缩进
                .IndentLevel = 0 '缩进量(范围0-15)
                .ShrinkToFit = False '收缩到合适(自动调整)
                .ReadingOrder = xlContext '读写次序(从左往右写还是从右往左写)
                .MergeCells = False '合并单元格
            End With
            Selection.Merge'选择并合并
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    21、插入一行单元格
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

     Rows("1:1").Select'插入首行
            Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove 
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    22、在指定单元格内输入字符
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Range("A1").Select
    ActiveCell.FormulaR1C1 = "这是需要输入的字符"
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    23、调整行高和列宽
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Rows("1:1").Select'调整第一行行高
    Selection.RowHeight = 90'行高90
    Columns("Z:Z").ColumnWidth = 7 '设置Z列单元格列宽为7
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    24、跳转到该列最后一个数值
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Range("A1").Select'从A1开始
    Selection.End(xlDown).Select '到有字符的最后一行,相当于按住ctlr+shift+↓
    x = Selection.Row() '获取当前选择框所在的行号
    y = Selection.Column() '获取当前选择框所在的列号
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    25、获取当前单元格所在的行号和列号
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    x = Selection.Row() '获取当前选择框所在的行号
    y = Selection.Column() '获取当前选择框所在的列号
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    26、格式刷(公式快速复用)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    该方法一般需要配合获取当前单元格所在的行号和列号使用
    先找有数据的单元格,使用Selection.End(xlDown).Select '到有字符的最后一行,相当于按住ctlr+shift+↓方法跳转到最后一行,然后使用x = Selection.Row() '获取当前选择框所在的行号, y = Selection.Column() '获取当前选择框所在的列号。然后让单元格在需要写入公式的最后一行中写入1(1没有任何意义,只是为了让该单元格有字符)其他需要同样操作的单元格类似,然后使用下面的代码,将该列所需要复用的公式进行复用。
    公式复用演示

    Range("I2").Select
    ActiveCell.FormulaR1C1 = "=RC[-6]-RC[-4]" '以当前单元格(I2)为坐标,用负轴(-6)单元格减去(-4)单元格(从后往前数6个格子和4个格子)
    Range("J2").Select
    ActiveCell.FormulaR1C1 = "= RC[-7]-RC[-4]" '以当前单元格(J2)为坐标,用负轴(-7)单元格减去(-4)单元格(从后往前数7个格子和4个格子)
    Range("K2").Select
    ActiveCell.FormulaR1C1 = "=RC[-8]-RC[-4]"
    Range("K3").Select
    Range("I2:K2").Select '选中I2,J2,K2单元格(三个连在一起全选)
    Range(Selection, Selection.End(xlDown)).Select '将上面的三个全选单元格选中后按住ctlr+shift+↓到有数值的最后一行(之前写的3个1)
    Selection.FillDown '按ctrl+D实现前面三个单元格同样的公式操作
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    27、筛选
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    添加筛选
                Range("A1:K1").Select '选中A1到K1
                Selection.AutoFilter '增加筛选功能
    筛选条件
                Columns("E:E").Select '选择E列
                '单项筛选
                ActiveSheet.Range("$A$1:$K$" & x).AutoFilter Field:=5, Criteria1:="=" '选择5列进行筛选,筛选值为空
                '多项筛选
                ActiveSheet.Range("$A$1:$K$" & x).AutoFilter Field:=5, Criteria1:="=null", _
                  Operator:=xlOr, Criteria2:="=" '选择第5列筛选值为null(Criteria1:="=null")和空白值(Criteria2:="=" )
                e = ActiveSheet.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1 '返回筛选后的符合条件的个数
    
    取消筛选(全选显示)
     			Columns("G:G").Select
                ActiveSheet.Range("$A$1:$K$" & x).AutoFilter Field:=7 '全选第7列筛选(取消第7列的筛选)
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    28、查找替换
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Cells.Replace What:="null", Replacement:="", LookAt:=xlPart, SearchOrder _
        :=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False '查找并替换null值为空白(不写入任何字符)
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    29、单元格颜色
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    去除颜色
                Columns("A:K").Select'选择A列到K列
                With Selection.Interior '循环将填充颜色去除
                    .Pattern = xlNone
                End With
    

    添加颜色
    Range(“L3:P3”).Select’L3到P3这些单元格添加绿色
    With Selection.Interior
    .Pattern = xlSolid
    .PatternColorIndex = xlAutomatic
    .ThemeColor = xlThemeColorAccent6
    .TintAndShade = 0.799981688894314
    '07***为浅绿,0.599993896298105中浅绿,0.399975585192419浓绿
    .PatternTintAndShade = 0
    End With

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    30、单元格设置(字符居中)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    '这段代码是录制的,单元格格式参数如果懒得一一百度就使用录制
    Columns("A:K").Select
                Selection.Borders(xlDiagonalDown).LineStyle = xlNone'选择。边框(xl对角线向下)。线条样式 = xlNone
                Selection.Borders(xlDiagonalUp).LineStyle = xlNone'选择。边框(xl对角线向上)。线条样式 = xlNone
                With Selection.Borders(xlEdgeLeft)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlEdgeTop)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlEdgeBottom)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlEdgeRight)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlInsideVertical)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlInsideHorizontal)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection '循环被选中的单元格设置居中
                    .HorizontalAlignment = xlCenter’水平对齐
                    .VerticalAlignment = xlCenter‘垂直对齐
                End With
                HorizontalAlignment = xlCenter
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    31、在单元格内添加公式(SUMPRODUCT)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Range("AA3").Select
         ActiveCell.FormulaR1C1 = _
            "=SUMPRODUCT((R2C9:R" & x4 - dy & "C9>-1)*(R2C9:R" & x4 - dy & "C9<1))"
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    32、复制某个单元格
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Range("AB3").SelectTr
    Application.CutCopyMode = True
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    33、单元格引用
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Range("T5:AA5").Select '将表格T5至AA5
       ActiveCell.FormulaR1C1 = "=R" & x4 + 1 & "C[-12]" '上一行代码需要取值的单元格(该单元格值等于哪一个单元格值)
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    34、单元格边框
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Selection.Merge '将表格加边框
                Range("L1:AS5").Select
                Selection.Borders(xlDiagonalDown).LineStyle = xlNone
                Selection.Borders(xlDiagonalUp).LineStyle = xlNone
                With Selection.Borders(xlEdgeLeft)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlEdgeTop)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlEdgeBottom)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlEdgeRight)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlInsideVertical)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
                With Selection.Borders(xlInsideHorizontal)
                    .LineStyle = xlContinuous
                    .ColorIndex = xlAutomatic
                    .TintAndShade = 0
                    .Weight = xlThin
                End With
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    35、复选框执行
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Private Sub Checkbox1_Click()
    if box1 = True and w1 = 1 Then'这里使用判断来控制复选框执行。用户只点击复选框时,复选框可以被勾选但不执行。必须要点击下面的执行按钮才能剩下执行。(这是折中方案)
    '这里写入该模块的功能代码
    end if
    end sub
    

    Private Sub Checkbox2_Click()
    if box2 = True and w2 = 2 Then'这里使用判断来控制复选框执行。用户只点击复选框时,复选框可以被勾选但不执行。必须要点击下面的执行按钮才能剩下执行。(这是折中方案)
    '这里写入该模块的功能代码
    end if
    end sub
    

    Private Sub Checkbox3_Click()
    if box3 = True and w3 = 3 Then'这里使用判断来控制复选框执行。用户只点击复选框时,复选框可以被勾选但不执行。必须要点击下面的执行按钮才能剩下执行。(这是折中方案)
    '这里写入该模块的功能代码
    end if
    end sub
    

    Pubilc w1, w2, w3'定义三个全局变量
    Private Sub 执行_Click() '
    j = "" '初始化为空
    For m = 1 To 3 '开始循环,有几个复选框选项则写几。该项目中有3个选项所以写3
        If 用户主窗体名称.Controls("Checkbox" & m).Value = True Then '如果复选框被选中(""&m)引号给的是复选框名字
        If m = 1 Then
        box1 = True
        End If
        If m = 2 Then
        box2 = True
        End If
        If m = 3 Then
        box3 = True
        End If
        If j = "" Then '并且字符串当时为空
        j = 用户主窗体名称.Controls("Checkbox" & m).Caption '就将复选框的名字即j存放到char中
        Else: j = j & "," & 用户主窗体名称.Controls("Checkbox" & m).Caption '如果字符串已经有个1或2或3了,那么将新的内容用逗号与字符串中已经有的值连接起来
        End If
        End If
        Next
        if box1 = True Then'如下注释1
         用户主窗体名称.Controls("Checkbox1").Value = False'将Checbox1变成去勾选状态
         w1 = 1'将w1赋值为1
         用户主窗体名称.Controls("Checkbox1").Value = True'将Checbox1变成勾选状态
         w1 = 0'将w1赋值为1
         end if
         '注释1:这里之所以这样写是没有找到勾选复选框时不执行,只有点执行时才会执行的办法,所以选择了
         '折中先判断复选框是否被勾选了,如果勾选了将下面的box置为True。然后在所有的条件判断完成后再
         '将已被勾选的窗体去勾选,由于不满足执行条件,该控件下的代码不会执行,紧接着将w赋值后再将窗体
         '勾选,这样控件执行的条件满足后就能够正常执行控件下面的代码。而去勾选和再勾选的过程因为时间极
         '短用户基本无感知。也可以不用该方法直接把代码放在执行模块下面直接执行。(技术有限,勿喷)
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    36、取消(退出软件)
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Unload Me'退出软件
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    37、If Else
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    sub ifelse()
    i = 0
    If i = 0 Then
    i = 1'这里编写需要执行的代码
    ElseIf i = 1 Then
    i = 2'这里编写需要执行的代码
    Else
    i = 0'这里编写需要执行的代码
    End If
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    38、For Next
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    Sub forNext()
    Dim i%, j%
    For i = 1 To 10
    j = j + i
    Next
    MsgBox j
    End Sub
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    39、While wend
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    i = 0
    while i < 10
    i = i + (i+1)
    wend
    

    ┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳
    40、Do Loop
    ┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻

    当条件成立,开始循环:
    sub Do()
    Dim i%
    Do While i<3
        i = i + 1
        MsgBox i
    Loop
    End Sub
    直到条件成立,跳出循环:
    sub Dountil()
    i  = 0
    Do Until i > 10:
    	i = i+1
    Loop
    msgbox("")  & i
    

    														  附     录:
    

    不同Sub含义:
    Public 表示 Sub 过程可被所有其他地方引用。和Sub性质一致,等价于Sub。
    Private 表示 Sub 过程只能被当前页或者窗体引用,所以只能在本模块内部可以访问。


    变量或字符串类型:
    Variant:变体型变量(类型可变),能够表除了定长string数据和用户自定义类型外可以包含任何种类的 数据,也可以包含empty、error、nothing、null等特殊值。使用该类型定义会导致代码执行时间变长。非必要时不要用。
    String:字符串类型。
    integer:整数(范围:-32768~32768)
    integer1:初始化是一个Variant类型的空值,随着对其的操作变成任意类型。
    integer2:会被正常的初始化为0。
    Dim integer1 as interger,integer2 as integer’这样1和2都为空值
    Long:长整型(范围:-214743648 ~ 214743648)
    Single 和 Double:单精度浮点数(Single) 和双精度浮点数(Double)
    Currency:货币型
    Byte:字节型
    Boolean:布尔型(表示逻辑值True或False)
    Date:日期(范围100年 ~ 9999年,0:00:00 ~ 23:59:59)
    object:对象型。利用set语句,声明为对象型的变量可以赋值为任何对象引用
    枚举型:

    Public Enum words 'Pubilc(公共)或Private(私有)
        中国
        英国
        美国
        法国
    End Enum
    Sub ad()
    	Dim from As words
    	from = 英国
    	from = 法国
    End Sub
    

    枚举型
    用户自定义类型:

    Type i
    i as Double
    End Type
    

    展开全文
  • VBA刷新窗体数据的3种方法

    万次阅读 2018-05-23 15:23:18
    refresh 和requery的区别:以子窗体为例。第一种:Me.frmChild.Requery这是最有效,最简单的方法。第二种:Me.frmChild.Form.Refresh这种方法并不能使窗体中的数据立即改变。第三种:Me.frmChild.SourceObject =...
  •  TextBox事件  →KeyPress事件的语法如下: ...KeyANSI只是参数,所以可以改成任何喜欢的名字,每键入一值的时候,都会触发KeyANSI,通过设置,可以实现限制默写值的键入。 →KeyDown事件 按下触发
  • EXCEL用窗体调用

    千次阅读 2011-01-04 21:29:00
    None
  • Excel VBA用户窗体常用的方法

    千次阅读 2013-03-28 16:23:38
    1、显示用户窗体 用于以编程方式显示用户窗体的语法是: UserFormName.Show 若要显示用户窗体名为 UserForm1,使用以下代码: UserForm1.Show 时可以加载到内存用户窗体而不实际显示它。 可能需要复杂的用户...
  • Excel_VBA用户窗体常用方法

    万次阅读 2012-05-25 13:30:21
    Excel VBA用户窗体常用的方法 2009-06-20 23:40 1、显示用户窗体 用于以编程方式显示用户窗体的语法是: UserFormName.Show 若要显示用户窗体名为 UserForm1,使用以下代码: UserForm1.Show 时可以加载...
  • VBA调用doc命令,doc窗口关闭之后,继续执行代码 Option Explicit 'Docワィンドワ閉じるした後、後続けの処理実施 Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandel As Long, ByVal...
  • 实例需求:某预测模型有4个输入参数,使用过程中需要依次分别加载4组不同的参数,参数组位于工作表中的第4行到第7行,并且在A列中创建了四个窗体控件按钮,单击某个按钮将相应行的数据加载到第2行单元格中。...
  • 在上一讲中我们讲了使用WithEvents定义响应事件的对象,那么有了对象自然要跟进到事件了,这讲就给大家讲解两新技能——在类中定义和触发自己的事件(Event)。这两技能,再加上上讲介绍的WithEvents,这三项技能...
  • 1 窗体 form 1.1创建窗体 form (默认名:userform) ...据说,单写一句 userform1.show 也是可以的,因为VBE会自动先 load 这个窗体 load form1 '加载窗体,加载到内存,但不显示 form1.show '显示窗体 (必须...
  • 大家好,在上两讲中讲了类模块的调试行为,对于我们写代码人员来讲,要充分地理解每知识点的概念,才能在实际工作中灵活运用,在我的第一套教程《VBA代码解决方案》中,我推出的是一种积木编程的思想,要求大家...
  • 个事件是在用户窗体关闭之前发生。 第一参数Cancel :默认是0,除了0之外的任何数都会停止QueryClose事件; 第二参数CloseMode:有以下四参数。这参数的意思是关闭这程序的方式有哪些,比如说用户点了...
  • 表达式 一代表 DoCmd 对象的变量。 参数 名称 必选/可选 数据类型 说明 FormName 必选 Variant 字符串表达式 (字符串表达式:任一求值为一列连续字符的表达式。表达式的元素可以是:返回字符串或字...
  • 按钮点击一次即可运行宏1、宏2、宏3、宏4、宏5、宏6、宏7.代码怎么写?
  • EXCEL编程VBA高级教程

    2015-04-16 11:40:55
    三.Property属性过程和Event事件过程.........................................5 第十二节内部函数............................................................................................................
  • VBA 64 32 调用dll的区别

    千次阅读 2017-03-09 15:22:05
     函数会被替换为 DLL 文件中过程的实际名称,表示在从 VBA 代码调用过程时所使用的名称。如果需要,您还可以为过程名称指定  AliasName 参数。包含要调用的过程的 DLL 文件的名称位于  Lib  关键字之后。最后...
  • 最终可能有几个窗体中有一些共同都要执行的代码,为了在两个窗体中不产生重复代码,可创建一个独立的模块,用它实现代码公用。该独立模块即是标准模块。此外还可以建立包含共享代码与数据的类模块。  每个标
  • VBA两种打开文件窗口的方式

    千次阅读 2020-10-20 10:32:33
    VBA两种打开文件窗口的方式第一种第二种结语 第一种 获取文件夹路径,返回完整路径 Dim Fso, Fld '定义文件路径 Set Fso = CreateObject("Scripting.FileSystemObject") Set Fld = Fso.getfolder(CreateObject(...
  • C#窗体设计基础学习

    千次阅读 2019-06-08 00:18:00
    :剪辑展开有多个选项。comboBox.SelectedIndex选中第几个;comboBox.DataSource显示可选类容设置;comboBox.Items.Add()添加选项类容 RadioButton单选控件: 当同一个容器中(Form、Panel、GroupBox、...
  • VBA事件过程

    千次阅读 2018-12-03 16:43:29
    当用户在某个对象上引发一动作时,Windows会通知VBA产生一个事件,并且VBA会自动地调用与该事件相关的事件过程。 事件Sub子过程的调用格式如下: Private Sub 对象名_事件名([参数表]) 语句块 End Sub 对象名是...
  • 在网上找EXCEL文件合并的方法,思路: 一、Linux 或者window+cmder,直接用命令行cat合并EXCEL文件,但是,需要安装辅助东西才能直接处理(也许也不可以,但是,可以用文件格式转换工具转换是可行的,把EXCEL文件...
  • 在《异步委托实现等待窗体(loading界面),执行任务超时可以取消操作》一文,通过异步委托貌视能很好的实现了所要的效果,但因异步委托无法控制线程进度,也就是说不能人工干预线程,所以取消操作就是一摆设,存在...
  • 你已选中了添加链接的内容蓝字关注,加微信NZ9668获资料信息VBA解决方案 系列丛书作者头条百家平台 VBA资深创作者_______________________________(接上讲)3.类模块类模块是面向对象编程的基础,可以在类模块中编写...
  • 方法1:在窗体上添加 medieplayer控件 窗体的默认控件里没有 音乐控件,需要添加 mediaplayer 工具栏上邮件:添加 找到 microsoft mediaplayer 音乐控件的播放 播放音乐的属性 播放器.url 播放器.controls...
  • 用户界面篇 01斯是陋室:"立即"窗口开篇序:都9102年了,VBA还用着那个丑丑的IDE界面——VBE。但对于非专业编程从业人员来讲,这多年以前设计的东西在今天依然足够强大并满足使用需求。接下来,我会以数篇文章来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,752
精华内容 700
关键字:

vba事件调用多个窗体