存档在 ‘用户窗体’ 分类中.

修改Excel用户窗体的窗口样式

Technorati 标签: ,,,

首先看看下图:

UserDifferentSytle

这是一个用户窗体,看不出来吧,但确实是一个用户窗体。我们使用代码去除了它的最大化、最小化和关闭按钮并作了一些设置,使得它好像是一个浮动工具栏。下面程序中的SetUserformAppearance过程用于设置用户窗体的样式,可作为通用的程序调用。该过程能够独立设置:

  • 窗体是否有标题栏
  • 用作浮动工具栏时,标题栏是否为常规尺寸或小尺寸
  • 是否可以改变窗体大小
  • 窗体是否有最大化按钮
  • 窗体是否有最小化按钮
  • 窗体是否有关闭按钮
  • 窗体是否有图标以及图标是否可用

(也可参考《Professional Excel Development》中的第10章)

在VBE中插入一个用户窗体,如上图所示,在其中放置一个标签并输入文本、放置一个按钮。

然后,插入一个标准模块,在其中输入下面的代码:

   1: ‘ 说明: 修改用户窗体的窗口样式
   2: Option Explicit
   3:  
   4: ‘ Windows API声明和常量声明
   5: Private Declare Function GetWindowLong Lib “user32″ Alias “GetWindowLongA” (ByVal hwnd As Long, ByVal nIndex As Long) As Long
   6: Private Declare Function SetWindowLong Lib “user32″ Alias “SetWindowLongA” (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
   7: Private Declare Function GetSystemMenu Lib “user32″ (ByVal hwnd As Long, ByVal bRevert As Long) As Long
   8: Private Declare Function DeleteMenu Lib “user32″ (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
   9: Private Declare Function DrawMenuBar Lib “user32″ (ByVal hwnd As Long) As Long
  10:  
  11: Private Const GWL_STYLE As Long = (-16)           ‘窗口样式偏移量
  12: Private Const GWL_EXSTYLE As Long = (-20)         ‘窗口扩展样式偏移量
  13: Private Const WS_CAPTION As Long = &HC00000       ‘添加标题栏
  14: Private Const WS_SYSMENU As Long = &H80000        ‘添加系统菜单
  15: Private Const WS_THICKFRAME As Long = &H40000     ‘添加可调整的框架
  16: Private Const WS_MINIMIZEBOX As Long = &H20000    ‘在标题栏中添加最小化框
  17: Private Const WS_MAXIMIZEBOX As Long = &H10000    ‘在标题栏中添加最大化框
  18: Private Const WS_EX_DLGMODALFRAME As Long = &H1   ‘控制是否窗口有图标
  19: Private Const WS_EX_TOOLWINDOW As Long = &H80     ‘工具窗口:最小标题栏
  20: Private Const SC_CLOSE As Long = &HF060           ‘关闭菜单项
  21:  
  22: ‘用户窗体样式枚举列表
  23: Public Enum UserformWindowStyles
  24:     uwsNoTitleBar = 0
  25:     uwsHasTitleBar = 1
  26:     uwsHasSmallTitleBar = 2
  27:     uwsHasMaxButton = 4
  28:     uwsHasMinButton = 8
  29:     uwsHasCloseButton = 16
  30:     uwsHasIcon = 32
  31:     uwsCanResize = 64
  32:     uwsDefault = uwsHasTitleBar Or uwsHasCloseButton
  33: End Enum
  34:  
  35: ‘ 说明: 设置用户窗体的窗口样式的程序
  36: 
  37: ‘ 参数:    frmForm    要改变样式的用户窗体
  38: ‘          lStyles    设置样式的枚举值,能够将枚举值添加在一起以设置多个样式
  39: ‘          sIconPath  如果设置uwsHasIcon样式,那么这是用于窗体的图标文件的路径
  40: 
  41: Sub SetUserformAppearance(ByRef frmForm As Object, ByVal lStyles As UserformWindowStyles, Optional ByVal sIconPath As String)
  42:  
  43:     Dim sCaption As String
  44:     Dim hwnd As Long
  45:     Dim lStyle As Long
  46:     Dim hMenu As Long
  47:  
  48:     ‘查找窗体的窗口句柄
  49:     sCaption = frmForm.Caption
  50:     frmForm.Caption = “FindThis” & Rnd
  51:     hwnd = FindOurWindow(“ThunderDFrame”, frmForm.Caption)
  52:     frmForm.Caption = sCaption
  53:  
  54:     ‘如果要小的标题栏,不要图标,也不要最大化或最小化按钮
  55:     If lStyles And uwsHasSmallTitleBar Then
  56:         lStyles = lStyles And Not (uwsHasMaxButton Or uwsHasMinButton Or uwsHasIcon)
  57:     End If
  58:  
  59:     ‘获取正常的窗口样式位
  60:     lStyle = GetWindowLong(hwnd, GWL_STYLE)
  61:  
  62:     ‘适当地更新正常的样式位
  63:     ‘如果要图标或者最大化、最小化或关闭按钮,则必须有系统菜单
  64:     ModifyStyles lStyle, lStyles, uwsHasIcon Or uwsHasMaxButton Or uwsHasMinButton Or uwsHasCloseButton, WS_SYSMENU
  65:  
  66:     ‘大多数情况下需要标题栏!
  67:     ModifyStyles lStyle, lStyles, uwsHasIcon Or uwsHasMaxButton Or uwsHasMinButton Or uwsHasCloseButton Or uwsHasTitleBar Or uwsHasSmallTitleBar, WS_CAPTION
  68:  
  69:     ModifyStyles lStyle, lStyles, uwsHasMaxButton, WS_MAXIMIZEBOX
  70:     ModifyStyles lStyle, lStyles, uwsHasMinButton, WS_MINIMIZEBOX
  71:     ModifyStyles lStyle, lStyles, uwsCanResize, WS_THICKFRAME
  72:  
  73:     ‘使用正常样式位更新窗口
  74:     SetWindowLong hwnd, GWL_STYLE, lStyle
  75:  
  76:     ‘获取扩展的样式位
  77:     lStyle = GetWindowLong(hwnd, GWL_EXSTYLE)
  78:  
  79:     ‘适当地修改
  80:     ModifyStyles lStyle, lStyles, uwsHasSmallTitleBar, WS_EX_TOOLWINDOW
  81:  
  82:     If lStyles And uwsHasIcon Then
  83:         lStyle = lStyle And Not WS_EX_DLGMODALFRAME
  84:         
  85:         ‘设置图标,如果有
  86:         SetIcon hwnd, sIconPath
  87:     Else
  88:         lStyle = lStyle Or WS_EX_DLGMODALFRAME
  89:         
  90:         ‘设置图标,如果有
  91:         SetIcon hwnd, “”
  92:     End If
  93:  
  94:     ‘使用扩展样式位更新窗口
  95:     SetWindowLong hwnd, GWL_EXSTYLE, lStyle
  96:  
  97:     ‘通过从控制菜单移除处理关闭按钮而不是通过窗口样式位
  98:     If lStyles And uwsHasCloseButton Then
  99:         ‘需要则重置控制菜单
 100:         hMenu = GetSystemMenu(hwnd, 1)
 101:     Else
 102:         ‘不需要则将其从控制菜单中删除
 103:         hMenu = GetSystemMenu(hwnd, 0)
 104:         DeleteMenu hMenu, SC_CLOSE, 0&
 105:     End If
 106:  
 107:     ‘刷新变化后的窗口
 108:     DrawMenuBar hwnd
 109:  
 110: End Sub
 111:  
 112: ‘ 说明: 检查是否样式位被设置和设置/清除了相应的窗口样式位
 113: 
 114: Private Sub ModifyStyles(ByRef lFormStyle As Long, ByVal lStyleSet As Long, ByVal lChoice As UserformWindowStyles, ByVal lWS_Style As Long)
 115:  
 116:     If lStyleSet And lChoice Then
 117:         lFormStyle = lFormStyle Or lWS_Style
 118:     Else
 119:         lFormStyle = lFormStyle And Not lWS_Style
 120:     End If
 121:  
 122: End Sub

再插入一个标准模块,并输入下面的代码:

   1: Option Explicit
   2: Option Private Module
   3:  
   4: ‘ 为ApphWnd和FindOurWindow示例函数的声明
   5: ‘ 获取桌面窗口的句柄
   6: Private Declare Function GetDesktopWindow Lib “user32″ () As Long
   7:  
   8: ‘查找具有指定类名和标题的子窗口
   9: Private Declare Function FindWindowEx Lib “user32″ Alias “FindWindowExA” (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
  10:  
  11: ‘获取当前Excel实例的ID
  12: Private Declare Function GetCurrentProcessId Lib “kernel32″ () As Long
  13:  
  14: ‘获取正处理的窗口的ID
  15: Private Declare Function GetWindowThreadProcessId Lib “user32″ (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long
  16:  
  17: ‘ 为WorkbookWindowhWnd示例函数的声明
  18: ‘ WorkbookWindowhWnd过程使用上面定义的FindWindowEx
  19: ‘ 为SetNameDropdownWidth示例函数的声明
  20: ‘ 在SendMessage调用中使用的常量
  21:  
  22: Private Const CB_SETDROPPEDWIDTH As Long = &H160&     ‘winuser.h
  23:  
  24: ‘ 函数声明
  25: ‘ SetNameDropdownWidth过程也使用上面定义的FindWindowEx
  26: ‘ 发送给窗口的消息
  27: Private Declare Function SendMessage Lib “user32″ Alias “SendMessageA” (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  28:  
  29: ‘ 为SetIcon示例过程的声明
  30: ‘ 用于SendMessage调用的常量
  31: Private Const WM_SETICON As Long = &H80
  32:  
  33: ‘ 函数声明
  34: ‘ SetIcon过程也使用上面定义的SendMessage
  35: ‘ 获取文件图标的句柄
  36: Private Declare Function ExtractIcon Lib “shell32.dll” Alias “ExtractIconA” (ByVal hInst As Long, ByVal lpszExeFileName As String, ByVal nIconIndex As Long) As Long
  37:  
  38: ‘ 查找Excel主窗口句柄
  39: Function ApphWnd() As Long
  40:  
  41:     If Val(Application.Version) >= 10 Then
  42:         ApphWnd = Application.hwnd
  43:     Else
  44:         ApphWnd = FindOurWindow(“XLMAIN”, Application.Caption)
  45:     End If
  46:  
  47: End Function
  48:  
  49: ‘ 查找属于当前Excel实例的指定类和标题的顶层窗口
  50: ‘ 参数:    sClass     要查找的窗口类名
  51: ‘          sCaption   要查找的窗口标题
  52: Function FindOurWindow(Optional ByVal sClass As String = vbNullString, Optional ByVal sCaption As String = vbNullString)
  53:  
  54:     Dim hWndDesktop As Long
  55:     Dim hwnd As Long
  56:     Dim hProcThis As Long
  57:     Dim hProcWindow As Long
  58:  
  59:     ‘所有顶层窗口都是桌面的子窗口,因此首先获取句柄
  60:     hWndDesktop = GetDesktopWindow
  61:  
  62:     ‘获取与Excel实例匹配的ID
  63:     hProcThis = GetCurrentProcessId
  64:  
  65:     Do
  66:         ‘查找与指定窗口类和/或标题匹配的桌面的下一个子窗口
  67:         ‘开始时hWnd是零,因此将获取第一个匹配窗口
  68:         ‘每次调用将传递上次找到的窗口句柄,从而获得下一个
  69:         hwnd = FindWindowEx(hWndDesktop, hwnd, sClass, sCaption)
  70:  
  71:         ‘获得拥有查找窗口的处理过程ID
  72:         GetWindowThreadProcessId hwnd, hProcWindow
  73:  
  74:         ‘循环直到窗口的处理过程与该过程匹配或者没有找到窗口
  75:     Loop Until hProcWindow = hProcThis Or hwnd = 0
  76:  
  77:     ‘返回找到的句柄
  78:     FindOurWindow = hwnd
  79:  
  80: End Function
  81:  
  82: ‘ 设置窗口的图标
  83: ‘ 参数:    hwnd    要修改图标的窗口的句柄
  84: ‘          sIcon   图标文件的路径
  85: Sub SetIcon(ByVal hwnd As Long, ByVal sIcon As String)
  86:  
  87:     Dim hIcon As Long
  88:  
  89:     ‘获取图标句柄
  90:     hIcon = ExtractIcon(0, sIcon, 0)
  91:  
  92:     ‘设置大(32×32)和小(16×16)图标
  93:     SendMessage hwnd, WM_SETICON, True, hIcon
  94:     SendMessage hwnd, WM_SETICON, False, hIcon
  95:  
  96: End Sub

在用户窗体模块的Initialize事件中,调用上面的SetUserformAppearance过程,同时在QueryClose事件中,放置下列代码以阻止使用Alt+F4组合键关闭用户窗体:

   1: Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
   2:  
   3:     Cancel = (CloseMode = vbFormControlMenu)
   4:  
   5: End Sub
标签: 没有标签

探讨如何限制文本框中的输入字符

为工作方便,自已利用Excel应用程序开发了一个简易的考勤管理系统。其中,一个小小的功能着实让我费了一番功夫。即:如何能够限制在文本框中只能输入数字?
对于这个问题,自已搜索了很多资料,也试验了多种方法和代码。因此,引出了本文的标题,即如何限制文本框中的字符输入。
先准备一个简单的用户窗体界面,以便于代码测试,如下图。
TextBoxSamplepic
一、简单的只能输入数字的代码
Private Sub