我需要一个能够扫描我的数组并在ColumnWidths
中为我的ListBox
返回UserForm
的函数。过了一会儿,我找到了This StackOverflow topic。我修复并使用了代码时出现了一些错误。工作得很好!
但是我注意到当我打开和关闭UserForm几次(10-20x)时,开口越来越长。而Excel的内存使用量也越来越大。每次运行大约1MB。
所以我认为这是这个模块。有没有人能够看到那里是否有内存泄漏?
我使用的代码是:
Option Explicit
' ==========================================================================
' SOURCE for this module, slightly modified code from TravelinGuy
' https://stackoverflow.com/questions/5012465/vb-macro-string-width-in-pixel
'
' Adds functions:
' GetStringPixelHeight(text:Str, fontName:Str, fontSize:Single, _
' [isBold:Bool=False], [isItalics:Bool=False])
' GetStringPixelWidth(text:Str, fontName:Str, fontSize:Single, _
' [isBold:Bool=False], [isItalics:Bool=False]))
' GetLabelPixelHeight(label:Str)
' GetLabelPixelWidth(label:Str)
' ==========================================================================
'API Declares
Private Declare Function CreateDC Lib "gdi32.dll" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, lpInitData As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32.dll" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateFontIndirect Lib "gdi32.dll" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function GetTextExtentPoint32 Lib "gdi32.dll" Alias "GetTextExtentPoint32A" (ByVal hdc As Long, ByVal lpsz As String, ByVal cbString As Long, lpSize As FNTSIZE) As Long
Private Declare Function MulDiv Lib "kernel32.dll" (ByVal nNumber As Long, ByVal nNumerator As Long, ByVal nDenominator As Long) As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32.dll" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hdc As Long) As Long
Private Const LOGPIXELSY As Long = 90
Private Type LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName As String * 32
End Type
Private Type FNTSIZE
cx As Long
cy As Long
End Type
Public Function GetLabelPixelWidth(label As String) As Integer
Dim font As New StdFont
Dim sz As FNTSIZE
font.Name = "Arial Narrow"
font.size = 9.5
sz = GetLabelSize(label, font)
GetLabelPixelWidth = sz.cx
End Function
Public Function GetStringPixelHeight(text As String, fontName As String, fontSize As Single, Optional isBold As Boolean = False, Optional isItalics As Boolean = False) As Integer
Dim font As New StdFont
Dim sz As FNTSIZE
font.Name = fontName
font.size = fontSize
font.Bold = isBold
font.Italic = isItalics
sz = GetLabelSize(text, font)
GetStringPixelHeight = sz.cy
End Function
Public Function GetStringPixelWidth(text As String, fontName As String, fontSize As Single, Optional isBold As Boolean = False, Optional isItalics As Boolean = False) As Integer
Dim font As New StdFont
Dim sz As FNTSIZE
font.Name = fontName
font.size = fontSize
font.Bold = isBold
font.Italic = isItalics
sz = GetLabelSize(text, font)
GetStringPixelWidth = sz.cx
End Function
Private Function GetLabelSize(text As String, font As StdFont) As FNTSIZE
Dim tempDC As Long
Dim tempBMP As Long
Dim f As Long
Dim lf As LOGFONT
Dim textSize As FNTSIZE
' Create a device context and a bitmap that can be used to store a
' temporary font object
tempDC = CreateDC("DISPLAY", vbNullString, vbNullString, ByVal 0)
tempBMP = CreateCompatibleBitmap(tempDC, 1, 1)
' Assign the bitmap to the device context
DeleteObject SelectObject(tempDC, tempBMP)
' Set up the LOGFONT structure and create the font
lf.lfFaceName = font.Name & Chr$(0)
lf.lfHeight = -MulDiv(font.size, GetDeviceCaps(GetDC(0), 90), 72) 'LOGPIXELSY
lf.lfItalic = font.Italic
lf.lfStrikeOut = font.Strikethrough
lf.lfUnderline = font.Underline
If font.Bold Then lf.lfWeight = 800 Else lf.lfWeight = 400
f = CreateFontIndirect(lf)
' Assign the font to the device context
DeleteObject SelectObject(tempDC, f)
' Measure the text, and return it into the textSize SIZE structure
GetTextExtentPoint32 tempDC, text, Len(text), textSize
' Clean up (very important to avoid memory leaks!)
DeleteObject f
DeleteObject tempBMP
DeleteDC tempDC
' Return the measurements
GetLabelSize = textSize
End Function
用于构造ListBox.ColumnWidths
字符串的函数是:
' Return string with column widths from entered myarray values for lstbox.ColumnWidths
' Example: "80;40;49;65;30;21;19;65"
'---------------------------------------------------------------------------------------
Public Function getLstColumnWidths(ByVal myarray As Variant, _
Optional multiplier As Single = 1) As String
Dim currentVal As Long
Dim longestVal As Long
' Get Column Widths from the largest string in column
getLstColumnWidths = ""
Dim i As Long
Dim j As Long
For i = LBound(myarray, 1) To UBound(myarray, 1)
longestVal = 0
For j = LBound(myarray, 2) To UBound(myarray, 2)
Dim strText As String
strText = myarray(i, j)
' MEMORY LEAKS?
currentVal = GetStringPixelWidth(strText, "Tahoma", 8 ' <-- USED HERE
longestVal = IIf(currentVal > longestVal, currentVal, longestVal)
Next j
getLstColumnWidths = getLstColumnWidths & _
CStr(Round(longestVal * multiplier, 1)) & ";"
Next i
getLstColumnWidths = Left(getLstColumnWidths, Len(getLstColumnWidths) - 1)
End Function