一个人的朝圣深度感悟

What Started It All

是什么开始了

I had an instance recently where I needed to take text from a textbox on a VBA form and split the text into separate lines to send to a zebra printer.  The catch was that I needed the text to break at the same line points as the VBA textbox.  The textbox was configured with multiline and wordwrap enabled.  Searching all over the internet for a function or idea to accomplish this task, I found plenty of examples of wrapping text based on already included carriage returns or just of a space and character count, but not what I needed.  A VBA textbox may or may not have carriage returns and it splits text on more than just spaces.

最近我有一个实例,我需要从VBA表单上的文本框中获取文本并将文本拆分成单独的行以发送到Zebra打印机。 问题是我需要文本在与VBA文本框相同的行点处中断。 文本框已配置为启用多行和自动换行。 在Internet上搜索用于完成此任务的功能或构想,我发现了很多基于已经包含回车符或仅包含空格和字符数来包装文本的示例,但不是我所需要的。 VBA文本框可能有回车符,也可能没有回车符,它会在多个空格上分割文本。

This led me on a quest to build a word wrap function mimicking the wrapping of a textbox.  Working through coding and testing, I ended up creating a few different versions.  The earlier versions were better than what I had found, but not good enough for my needs.  They are posted here in case they are good enough for you.  The original function returned data in a string array, but it was easy to adjust it to return as single string with carriage returns to break apart each line.  That code is also included.

这使我开始寻求构建模仿文字框自动换行的自动换行功能。 通过编码和测试,我最终创建了几个不同的版本。 较早的版本比我发现的要好,但不足以满足我的需求。 如果它们对您足够好,则会在此处发布。 原始函数以字符串数组的形式返回数据,但是很容易将其调整为带有回车符的单个字符串以将每一行分开。 该代码也包括在内。

Breakdown of the basic code:

基本代码明细:

A textbox has a variety of rules on how it separates text.  The first step is to take the text and split it into an array based on already defined line feeds.  Use the line feed (vbLf) as this will catch user entered returns from both Enter Key (If EnterKeyBehavior = True) and Cntrl-Enter (if EnterKey Behavior=False).

文本框对于如何分隔文本具有多种规则。 第一步是获取文本并将其根据已定义的换行符拆分为一个数组。 使用换行符(vbLf),因为它将捕获用户从Enter键(如果EnterKeyBehavior = True)和Cntrl-Enter(如果EnterKey Behavior = False)输入的返回值。

strLineData = Split(TextToWrap, vbLf)
' This is the RegEx List for Characters that should be grouped with the text that follows them
' ${(<[\ - Have to use escape character "\" for ] and \
strStartGroup = "${(<\[\\"
' This is the RegEx List for Characters that should be grouped with the text the preceeds them
' !)}%>?-] - Have to use escape character "\" for - and ]
strEndGroup = "!)}%>?\-\]"
' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instances
strRegPattern = "[" & strStartGroup & "]?"
' Now grab all characters that are not part of special list and no spaces \s
' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.
' Equates to finding whole words including some special characters (those not in list since negative comparison)
strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"
' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instances
strRegPattern = strRegPattern & "[" & strEndGroup & "]?"
objRegExp.Pattern = strRegPattern
Set objWordList = objRegExp.Execute(strLine)

The first function I created calculated the width of each line by the number of characters per line.  These can work well for you if you are using a fixed width font.  They are simplier and will run slightly faster.

我创建的第一个函数通过每行的字符数来计算每行的宽度。 如果您使用的是固定宽度的字体,则这些字体对您来说效果很好。 它们比较简单,运行速度会稍快。

I have included a VBScript version using late binding.

我已经包括了使用后期绑定的VBScript版本。

WordWrapByCharacterToArray Function:

WordWrapByCharacterToArray 功能:

Here is the first function.  To use this function, send it the text that you want word wrapped and the maximum number of characters per line.  It will return a string array with each line as a separate element in the array.

这是第一个功能。 要使用此功能,请向其发送您要自动换行的文本以及每行最大字符数。 它将返回一个字符串数组,其中每一行作为数组中的单独元素。

Example Usage:

用法示例:

Dim strLines() As String
strLines = WordWrapByCharacterToArray(TextToWrap:=TextBox1.Text, LengthOfLine:=20)
For i = 0 To UBound(strLines)Debug.Print strLines(i)
Next
'---------------------------------------------------------------------------------------
' Function  : WordWrapByCharacterToArray
' Date      : 03/21/2012
' Purpose   : Will Return a String array of line data wrapped at proper break points
'               for a given line length as determined by the number of characters.
'               It uses the same rules as a VBA text box
'
' Usage     : Set a string array = to WordWrapByCharacterToArray sending WordWrapByCharacterToArray
'               your text and maximum length for each line
'               Example:
'               Dim strLines() as string
'               strLines = WordWrapByCharacterToArray("This is my text I want to wrap around something", 15)
'               This will break the string into multiple lines with a maximum length of 15 characters per line
'---------------------------------------------------------------------------------------
'
Public Function WordWrapByCharacterToArray(ByVal TextToWrap As String, _ByVal LengthOfLine As Long) As String()On Error GoTo WordWrapByCharacterToArray_Error:Dim objRegExp As VBScript_RegExp_55.RegExpDim objWordList As VBScript_RegExp_55.MatchCollectionDim objWord As VBScript_RegExp_55.MatchDim strStartGroup As StringDim strEndGroup As StringDim strRegPattern As StringDim intLineNum As Integer: intLineNum = 0Dim intLinePos As IntegerDim strReturn() As StringDim strLineData() As StringDim strLine As VariantDim intNumCharUsed As Integer' Instantiate RegExSet objRegExp = New VBScript_RegExp_55.RegExp' ------------------------------------' Set Set Font Settings' ------------------------------------' Make sure we were sent a good line widthIf LengthOfLine < 1 Then' Return an ErrorErr.Raise Number:=vbObjectError + 605, Description:="Requested Length of Line must be greater than 0"End If' ------------------------------------' Set RegEx Settings' ------------------------------------objRegExp.MultiLine = FalseobjRegExp.Global = True' ------------------------------------' Set the Search Pattern' ------------------------------------' This is the RegEx List for Characters that should be grouped with the text that follows them' ${(<[\ - Have to use escape character "\" for ] and \strStartGroup = "${(<\[\\"' This is the RegEx List for Characters that should be grouped with the text the preceeds them' !)}%>?-] - Have to use escape character "\" for - and ]strEndGroup = "!)}%>?\-\]"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = "[" & strStartGroup & "]?"' Now grab all characters that are not part of special list and no spaces \s' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.' Equates to finding whole words including some special characters (those not in list since negative comparison)strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = strRegPattern & "[" & strEndGroup & "]?"objRegExp.Pattern = strRegPattern' ------------------------------------' Break up Original String into already defined lines' ------------------------------------strLineData = Split(TextToWrap, vbLf)' ------------------------------------' Set Original Size of Return Array to just one line.  Can Expand Later' ------------------------------------ReDim Preserve strReturn(0)' ------------------------------------' Loop through each line to wrap text if needed' ------------------------------------For Each strLine In strLineData' Reset the Line Position for this set of textintLinePos = 0' Make sure the line is long enough to need to be wrappedIf Len(strLine) > LengthOfLine Then' ------------------------------------' Get the list of words defined by the Pattern' ------------------------------------Set objWordList = objRegExp.Execute(strLine)' ------------------------------------' Build the Return Array' ------------------------------------For Each objWord In objWordList' See if this word is too big to FitIf objWord.Length > LengthOfLine Then' Word is too big for the line, have to break it appart' Reset the Number of Characters used in this word to 1intNumCharUsed = 1' First see if we have any remaining words that should be added to the previous lineIf objWord.FirstIndex - intLinePos > 0 Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Save Previous LinestrReturn(intLineNum) = Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfDo While intNumCharUsed < objWord.Length' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Get as many characters as will fit on the linestrReturn(intLineNum) = Mid(objWord.Value, intNumCharUsed, LengthOfLine)' Increase the Number used counterintNumCharUsed = intNumCharUsed + Len(strReturn(intLineNum))' Reset the Line PositionintLinePos = intLinePos + Len(strReturn(intLineNum))' Increment our line CounterintLineNum = intLineNum + 1LoopElseIf objWord.FirstIndex - intLinePos + objWord.Length > LengthOfLine Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' This word will not fit on current Line.  Save Current LinestrReturn(intLineNum) = Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfEnd If 'objWord.Length > LengthOfLineNext' ------------------------------------' See if there is any text yet to add' ------------------------------------If (Len(strLine) - intLinePos) > 0 Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Save of the Last bits of DatastrReturn(intLineNum) = Right(strLine, Len(strLine) - intLinePos)' Increment our line CounterintLineNum = intLineNum + 1End IfElse' ------------------------------------' The entire line fits.  Add it now' ------------------------------------' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End IfstrReturn(intLineNum) = strLine' Increment our line CounterintLineNum = intLineNum + 1End IfNext' Return our ArrayWordWrapByCharacterToArray = strReturnRelease:On Error Resume NextErase strReturnSet objWordList = NothingSet objWord = NothingSet objRegExp = NothingExit FunctionWordWrapByCharacterToArray_Error:MsgBox "Procedure = WordWrapByCharacterToArray" & vbCrLf & _"Error Number = " & Err.Number & vbCrLf & _"Error Message = " & Err.Description & vbCrLf, _vbCritical Or vbSystemModal, "Word Wrap Error"Resume Release:
End Function

VBScript Version:

'---------------------------------------------------------------------------------------
' Function  : WordWrapByCharacterToArray
' Date      : 03/21/2012
' Purpose   : Will Return a String array of line data wrapped at proper break points
'               for a given line length as determined by the number of characters.
'               It uses the same rules as a VBA text box
'
' Usage     : Set a string array = to WordWrapByCharacterToArray sending WordWrapByCharacterToArray
'               your text and maximum length for each line
'               Example:
'               Dim strLines
'               strLines = WordWrapByCharacterToArray("This is my text I want to wrap around something", 15)
'               This will break the string into multiple lines with a maximum length of 15 characters per line
'---------------------------------------------------------------------------------------
'
Public Function WordWrapByCharacterToArray(TextToWrap, LengthOfLine)Dim objRegExp, objWordList, objWordDim strStartGroup, strEndGroup, strRegPatternDim intLineNum, intLinePos, intNumCharUsedDim strReturn(), strLineData, strLine' Instantiate RegExSet objRegExp = CreateObject("VBScript.RegExp")intLineNum = 0' ------------------------------------' Set Set Font Settings' ------------------------------------' Make sure we were sent a good line widthIf LengthOfLine < 1 Then' Return an ErrorErr.Raise vbObjectError + 605, "Requested Length of Line must be greater than 0"End If' ------------------------------------' Set RegEx Settings' ------------------------------------objRegExp.MultiLine = FalseobjRegExp.Global = True' ------------------------------------' Set the Search Pattern' ------------------------------------' This is the RegEx List for Characters that should be grouped with the text that follows them' ${(<[\ - Have to use escape character "\" for ] and \strStartGroup = "${(<\[\\"' This is the RegEx List for Characters that should be grouped with the text the preceeds them' !)}%>?-] - Have to use escape character "\" for - and ]strEndGroup = "!)}%>?\-\]"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = "[" & strStartGroup & "]?"' Now grab all characters that are not part of special list and no spaces \s' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.' Equates to finding whole words including some special characters (those not in list since negative comparison)strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = strRegPattern & "[" & strEndGroup & "]?"objRegExp.Pattern = strRegPattern' ------------------------------------' Break up Original String into already defined lines' ------------------------------------strLineData = Split(TextToWrap, vbLf)' ------------------------------------' Set Original Size of Return Array to just one line.  Can Expand Later' ------------------------------------ReDim strReturn(0)' ------------------------------------' Loop through each line to wrap text if needed' ------------------------------------For Each strLine In strLineData' Reset the Line Position for this set of textintLinePos = 0' Make sure the line is long enough to need to be wrappedIf Len(strLine) > LengthOfLine Then' ------------------------------------' Get the list of words defined by the Pattern' ------------------------------------Set objWordList = objRegExp.Execute(strLine)' ------------------------------------' Build the Return Array' ------------------------------------For Each objWord In objWordList' See if this word is too big to FitIf objWord.Length > LengthOfLine Then' Word is too big for the line, have to break it appart' Reset the Number of Characters used in this word to 1intNumCharUsed = 1' First see if we have any remaining words that should be added to the previous lineIf objWord.FirstIndex - intLinePos > 0 Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Save Previous LinestrReturn(intLineNum) = Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfDo While intNumCharUsed < objWord.Length' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Get as many characters as will fit on the linestrReturn(intLineNum) = Mid(objWord.Value, intNumCharUsed, LengthOfLine)' Increase the Number used counterintNumCharUsed = intNumCharUsed + Len(strReturn(intLineNum))' Reset the Line PositionintLinePos = intLinePos + Len(strReturn(intLineNum))' Increment our line CounterintLineNum = intLineNum + 1LoopElseIf objWord.FirstIndex - intLinePos + objWord.Length > LengthOfLine Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' This word will not fit on current Line.  Save Current LinestrReturn(intLineNum) = Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfEnd If 'objWord.Length > LengthOfLineNext' ------------------------------------' See if there is any text yet to add' ------------------------------------If (Len(strLine) - intLinePos) > 0 Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Save of the Last bits of DatastrReturn(intLineNum) = Right(strLine, Len(strLine) - intLinePos)' Increment our line CounterintLineNum = intLineNum + 1End IfElse' ------------------------------------' The entire line fits.  Add it now' ------------------------------------' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End IfstrReturn(intLineNum) = strLine' Increment our line CounterintLineNum = intLineNum + 1End IfNext' Return our ArrayWordWrapByCharacterToArray = strReturn' Release the ObjectsOn Error Resume NextSet objWordList = NothingSet objWord = NothingSet objRegExp = Nothing
End Function

WordWrapByCharacterToSstring Function:

WordWrapByCharacterToSstri ng功能:

Here is the Next function.  To use this function, send it the text that you want word wrapped and the maximum number of characters per line.  It will return a single string with each line in the string separated by a carriage return.

这是Next函数。 要使用此功能,请向其发送您要自动换行的文本以及每行最大字符数。 它将返回单个字符串,字符串中的每一行都用回车符分隔。

Example Usage:

用法示例:

Dim strWrappedLines As String
strWrappedLines = WordWrapByPointToString(TextToWrap:=TextBox1.Text, LengthOfLine:=20)
Debug.Print strWrappedLines
'---------------------------------------------------------------------------------------
' Procedure : WordWrapByCharacterToString
' Date      : 03/23/2012
' Purpose   : Will Return a String array of line data wrapped at proper break points
'               for a given line length as determined by the number of characters.
'               It uses the same rules as a VBA text box
'               *** MUST have a REFERENCE set for MICROSOFT VBSCRIPT REGULAR EXPRESSION 5.5
'
' Usage     : Set a string array = to WordWrapByCharacterToString sending WordWrapByCharacterToString
'               your text and maximum length for each line
'               Example:
'               Dim strWrappedLines as string
'               strWrappedLines = WordWrapByCharacterToString("This is my text I want to wrap around something", 15)
'               This will break the string into multiple lines with a maximum length of 15 characters per line
'---------------------------------------------------------------------------------------
'
Public Function WordWrapByCharacterToString(ByVal TextToWrap As String, _ByVal LengthOfLine As Long) As StringOn Error GoTo WordWrapByCharacterToString_Error:Dim objRegExp As VBScript_RegExp_55.RegExpDim objWordList As VBScript_RegExp_55.MatchCollectionDim objWord As VBScript_RegExp_55.MatchDim strStartGroup As StringDim strEndGroup As StringDim strRegPattern As StringDim intLineNum As Integer: intLineNum = 0Dim intLinePos As IntegerDim strReturn As StringDim strLineData() As StringDim strLine As VariantDim intNumCharUsed As Integer' Instantiate RegExSet objRegExp = New VBScript_RegExp_55.RegExp' ------------------------------------' Set Set Font Settings' ------------------------------------' Make sure we were sent a good line widthIf LengthOfLine < 1 Then' Return an ErrorErr.Raise Number:=vbObjectError + 605, Description:="Requested Length of Line must be greater than 0"End If' ------------------------------------' Set RegEx Settings' ------------------------------------objRegExp.MultiLine = FalseobjRegExp.Global = True' ------------------------------------' Set the Search Pattern' ------------------------------------' This is the RegEx List for Characters that should be grouped with the text that follows them' ${(<[\ - Have to use escape character "\" for ] and \strStartGroup = "${(<\[\\"' This is the RegEx List for Characters that should be grouped with the text the preceeds them' !)}%>?-] - Have to use escape character "\" for - and ]strEndGroup = "!)}%>?\-\]"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = "[" & strStartGroup & "]?"' Now grab all characters that are not part of special list and no spaces \s' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.' Equates to finding whole words including some special characters (those not in list since negative comparison)strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = strRegPattern & "[" & strEndGroup & "]?"objRegExp.Pattern = strRegPattern' ------------------------------------' Break up Original String into already defined lines' ------------------------------------strLineData = Split(TextToWrap, vbLf)' ------------------------------------' Loop through each line to wrap text if needed' ------------------------------------For Each strLine In strLineData' Reset the Line Position for this set of textintLinePos = 0' Make sure the line is long enough to need to be wrappedIf Len(strLine) > LengthOfLine Then' ------------------------------------' Get the list of words defined by the Pattern' ------------------------------------Set objWordList = objRegExp.Execute(strLine)' ------------------------------------' Build the Return Array' ------------------------------------For Each objWord In objWordList' See if this word is too big to FitIf objWord.Length > LengthOfLine Then' Word is too big for the line, have to break it appart' Reset the Number of Characters used in this word to 1intNumCharUsed = 1' First see if we have any remaining words that should be added to the previous lineIf objWord.FirstIndex - intLinePos > 0 Then' Save Previous LinestrReturn = strReturn & (Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfDo While intNumCharUsed < objWord.Length' Get as many characters as will fit on the linestrReturn = strReturn & (Mid(objWord.Value, intNumCharUsed, LengthOfLine) & vbNewLine)' Reset the Line PositionintLinePos = intLinePos + Len(Mid(objWord.Value, intNumCharUsed, LengthOfLine))' Increase the Number used counterintNumCharUsed = intNumCharUsed + Len(Mid(objWord.Value, intNumCharUsed, LengthOfLine))' Increment our line CounterintLineNum = intLineNum + 1LoopElseIf objWord.FirstIndex - intLinePos + objWord.Length > LengthOfLine Then' This word will not fit on current Line.  Save Current LinestrReturn = strReturn & (Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfEnd If 'objWord.Length > LengthOfLineNext' ------------------------------------' See if there is any text yet to add' ------------------------------------If (Len(strLine) - intLinePos) > 0 Then' Save of the Last bits of DatastrReturn = strReturn & (Right(strLine, Len(strLine) - intLinePos) & vbNewLine)' Increment our line CounterintLineNum = intLineNum + 1End IfElse' ------------------------------------' The entire line fits.  Add it now' ------------------------------------strReturn = strReturn & (strLine & vbNewLine)' Increment our line CounterintLineNum = intLineNum + 1End IfNext' Return our ArrayWordWrapByCharacterToString = strReturnRelease:On Error Resume NextSet objWordList = NothingSet objWord = NothingSet objRegExp = NothingExit FunctionWordWrapByCharacterToString_Error:MsgBox "Procedure = WordWrapByCharacterToString" & vbCrLf & _"Error Number = " & Err.Number & vbCrLf & _"Error Message = " & Err.Description & vbCrLf, _vbCritical Or vbSystemModal, "Word Wrap Error"Resume Release:
End Function

VBScript Version:

'---------------------------------------------------------------------------------------
' Procedure : WordWrapByCharacterToString
' Date      : 03/23/2012
' Purpose   : Will Return a String array of line data wrapped at proper break points
'               for a given line length as determined by the number of characters.
'               It uses the same rules as a VBA text box
'
' Usage     : Set a string array = to WordWrapByCharacterToString sending WordWrapByCharacterToString
'               your text and maximum length for each line
'               Example:
'               Dim strWrappedLines
'               strWrappedLines = WordWrapByCharacterToString("This is my text I want to wrap around something", 15)
'               This will break the string into multiple lines with a maximum length of 15 characters per line
'---------------------------------------------------------------------------------------
'
Public Function WordWrapByCharacterToString(TextToWrap, LengthOfLine)Dim objRegExp, objWordList, objWordDim strStartGroup, strEndGroup, strRegPatternDim intLineNum, intLinePos, intNumCharUsedDim strReturn, strLineData, strLine' Instantiate RegExSet objRegExp = CreateObject("VBScript.RegExp")intLineNum = 0' ------------------------------------' Set Set Font Settings' ------------------------------------' Make sure we were sent a good line widthIf LengthOfLine < 1 Then' Return an ErrorErr.Raise vbObjectError + 605, "Requested Length of Line must be greater than 0"End If' ------------------------------------' Set RegEx Settings' ------------------------------------objRegExp.MultiLine = FalseobjRegExp.Global = True' ------------------------------------' Set the Search Pattern' ------------------------------------' This is the RegEx List for Characters that should be grouped with the text that follows them' ${(<[\ - Have to use escape character "\" for ] and \strStartGroup = "${(<\[\\"' This is the RegEx List for Characters that should be grouped with the text the preceeds them' !)}%>?-] - Have to use escape character "\" for - and ]strEndGroup = "!)}%>?\-\]"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = "[" & strStartGroup & "]?"' Now grab all characters that are not part of special list and no spaces \s' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.' Equates to finding whole words including some special characters (those not in list since negative comparison)strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = strRegPattern & "[" & strEndGroup & "]?"objRegExp.Pattern = strRegPattern' ------------------------------------' Break up Original String into already defined lines' ------------------------------------strLineData = Split(TextToWrap, vbLf)' ------------------------------------' Loop through each line to wrap text if needed' ------------------------------------For Each strLine In strLineData' Reset the Line Position for this set of textintLinePos = 0' Make sure the line is long enough to need to be wrappedIf Len(strLine) > LengthOfLine Then' ------------------------------------' Get the list of words defined by the Pattern' ------------------------------------Set objWordList = objRegExp.Execute(strLine)' ------------------------------------' Build the Return Array' ------------------------------------For Each objWord In objWordList' See if this word is too big to FitIf objWord.Length > LengthOfLine Then' Word is too big for the line, have to break it appart' Reset the Number of Characters used in this word to 1intNumCharUsed = 1' First see if we have any remaining words that should be added to the previous lineIf objWord.FirstIndex - intLinePos > 0 Then' Save Previous LinestrReturn = strReturn & (Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfDo While intNumCharUsed < objWord.Length' Get as many characters as will fit on the linestrReturn = strReturn & (Mid(objWord.Value, intNumCharUsed, LengthOfLine) & vbNewLine)' Reset the Line PositionintLinePos = intLinePos + Len(Mid(objWord.Value, intNumCharUsed, LengthOfLine))' Increase the Number used counterintNumCharUsed = intNumCharUsed + Len(Mid(objWord.Value, intNumCharUsed, LengthOfLine))' Increment our line CounterintLineNum = intLineNum + 1LoopElseIf objWord.FirstIndex - intLinePos + objWord.Length > LengthOfLine Then' This word will not fit on current Line.  Save Current LinestrReturn = strReturn & (Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfEnd If 'objWord.Length > LengthOfLineNext' ------------------------------------' See if there is any text yet to add' ------------------------------------If (Len(strLine) - intLinePos) > 0 Then' Save of the Last bits of DatastrReturn = strReturn & (Right(strLine, Len(strLine) - intLinePos) & vbNewLine)' Increment our line CounterintLineNum = intLineNum + 1End IfElse' ------------------------------------' The entire line fits.  Add it now' ------------------------------------strReturn = strReturn & (strLine & vbNewLine)' Increment our line CounterintLineNum = intLineNum + 1End IfNext' Return our ArrayWordWrapByCharacterToString = strReturn' Release the ObjectsOn Error Resume NextSet objWordList = NothingSet objWord = NothingSet objRegExp = Nothing
End Function

Stage Two:

第二阶段:

As I mentioned, the problem with both of the above functions is that they still break based on a character count.  With propotionalized fonts, though, a line of "iiiiiiiiii" will break differently than a line of "WWWWWWWWWW" in a textbox.  Since the width of a text box is based on points, the code needed to determine the size of the text in points before it could split the lines.  There are examples on the internet of using Windows APIs to determine the pixel size of a section of text.  If you know the DPI of a monitor, which can be had via the APIs, you can determine the point size.  Adapting those ideas, a class to determine text size was created.

正如我提到的,上述两个函数的问题在于它们仍然基于字符计数而中断。 但是,对于带比例的字体,文本框中的“ iiiiiiiiii”行与“ WWWWWWWWWW”行的折断方式不同。 由于文本框的宽度基于点,因此需要使用代码来确定文本的大小(以点为单位),然后才能分割线。 互联网上有使用Windows API确定一段文字的像素大小的示例。 如果您知道可以通过API获得的显示器的DPI,则可以确定点的大小。 为适应这些想法,创建了一个确定文本大小的类。

This class is used to measure the point size of each word, to compare that with the targeted line width in points, and to see if the word fits that line.  Pleaset note that the defined width of a text box is not exactly the size needed for your total line width.  The textbox has margins built into the display.  I could not find this documented anywhere, but it appears that the margin is 3 points per side (Selection Margin is another 3 if set to true and a displayed scroll bar appears to take up 14).  Therefore when wrapping text, you need to take the width of the text box and subtract the correct amount (like 6 for just a basic box) to find the width in points that can display text.

此类用于测量每个单词的点大小,将其与目标行宽(以磅为单位)进行比较,并查看单词是否适合该行。 请注意,文本框的定义宽度与总线宽所需的大小不完全相同。 文本框在显示屏中内置了页边距。 我在任何地方都找不到此文档,但是看来边距是每边3个点(如果设置为true,则“选择边距”是另外3个点,并且显示的滚动条似乎占用14个点)。 因此,在自动换行时,需要采用文本框的宽度并减去正确的数量(例如对于基本框来说为6)以找到可以显示文本的点的宽度。

Since this code requires access to Windows API, VBA must be used.  Therefore, they have been coded using early binding for regular expressions.  Please make sure to add a reference in your project to MICROSOFT VBSCRIPT REGULAR EXPRESSION 5.5 to use these functions.

由于此代码需要访问Windows API,因此必须使用VBA。 因此,已使用早期绑定对正则表达式进行编码。 请确保在项目中添加对MICROSOFT VBSCRIPT REGULAR EXPRESSION 5.5的引用,以使用这些功能。

WordWrapByPointToArray Function:

WordWrapByPointToArray函数:

Here is the third attempt at a function.  To use this function, send it the text that you want word wrapped, the font used, and how wide the line should be in points.  It will return a string array with each line as a separate element in the array.

这是函数的第三次尝试。 要使用此功能,请向其发送要自动换行的文本,使用的字体以及线的宽度(以磅为单位)。 它将返回一个字符串数组,其中每一行作为数组中的单独元素。

Example:

例:

Dim strLines() As String
strLines = WordWrapByPointToArray(TextToWrap:=TextBox1.Text, TextFont:=TextBox1.Font, LineWidthInPoints:=TextBox1.Width - 6)
For i = 0 To UBound(strLines)Debug.Print strLines(i)
Next
'---------------------------------------------------------------------------------------
' Function  : WordWrapByPointToArray
' Date      : 03/20/2012
' Purpose   : Will Return a String array of line data that has been sepearated into lines
'               based on Width in Points and split according to textbox word wrap rules.
'               *** MUST have a REFERENCE set for Microsoft VBScript Regular Expression 5.5
'               *** Must also have the DetermineTextSize Class added to the project***
'
' Usage     : Set a string array = to WordWrapByPointToArray sending WordWrapByPointToArray
'               your text, Font and Line Width (Point Size) for each line
'               Example:
'               Dim strLines() as string
'               strLines = WordWrapByPointToArray(TextToWrap:=TextBox1.Text, TextFont:=TextBox1.Font, LineWidthInPoints:=TextBox1.Width - 6)
'               This will break the string into multiple lines at the same point as the text box
'
'               Please note in the example I take 6 away form TextBox1.Width as this appears to be
'                the margin size of a text box.  I found this through trial and error and have not
'                been able to verify that value.
'---------------------------------------------------------------------------------------
'
Public Function WordWrapByPointToArray(ByVal TextToWrap As String, _ByVal TextFont As StdFont, ByVal LineWidthInPoints As Single) As String()On Error GoTo WordWrapByPointToArray_Error:Dim objRegExp As VBScript_RegExp_55.RegExpDim objWordList As VBScript_RegExp_55.MatchCollectionDim objWord As VBScript_RegExp_55.MatchDim udtTextSize As DetermineTextSizeDim strStartGroup As StringDim strEndGroup As StringDim strRegPattern As StringDim intLineNum As Integer: intLineNum = 0Dim intLinePos As IntegerDim intEndPosition As IntegerDim strReturn() As StringDim strLineData() As StringDim strLine As VariantDim lngPointSize As LongDim lngWordSize As LongDim intNumCharUsed As Integer' Instantiate RegExSet objRegExp = New VBScript_RegExp_55.RegExpSet udtTextSize = New DetermineTextSize' ------------------------------------' Set Set Font Settings' ------------------------------------' Make sure we were sent a good line widthIf LineWidthInPoints < 1 Then' Return an ErrorErr.Raise Number:=vbObjectError + 605, Description:="Requested Line Width in Points must be greater than 0"End If' ------------------------------------' Set Set Font Settings' ------------------------------------udtTextSize.Font = TextFont' ------------------------------------' Set RegEx Settings' ------------------------------------objRegExp.MultiLine = FalseobjRegExp.Global = True' ------------------------------------' Set the Search Pattern' ------------------------------------' This is the RegEx List for Characters that should be grouped with the text that follows them' ${(<[\ - Have to use escape character "\" for ] and \strStartGroup = "${(<\[\\"' This is the RegEx List for Characters that should be grouped with the text the preceeds them' !)}%>?-] - Have to use escape character "\" for - and ]strEndGroup = "!)}%>?\-\]"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = "[" & strStartGroup & "]?"' Now grab all characters that are not part of special list and no spaces \s' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.' Equates to finding whole words including some special characters (those not in list since negative comparison)strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = strRegPattern & "[" & strEndGroup & "]?"objRegExp.Pattern = strRegPattern' ------------------------------------' Break up Original String into already defined lines' ------------------------------------strLineData = Split(TextToWrap, vbLf)' ------------------------------------' Set Original Size of Return Array to just one line.  Can Expand Later' ------------------------------------ReDim Preserve strReturn(0)' ------------------------------------' Loop through each line to wrap text if needed' ------------------------------------For Each strLine In strLineData' Reset the Line Position for this set of textintLinePos = 0' Make sure the line is long enough to need to be wrappedIf udtTextSize.TextWidthinPoints(strLine) > LineWidthInPoints Then' ------------------------------------' Get the list of words defined by the Pattern' ------------------------------------Set objWordList = objRegExp.Execute(strLine)' ------------------------------------' Build the Return Array' ------------------------------------For Each objWord In objWordListlngWordSize = udtTextSize.TextWidthinPoints(objWord.Value)' See if this word is too big to FitIf lngWordSize > LineWidthInPoints Then' Word is too big for the line, have to break it appart' Reset the Number of Characters used in this word to 0intNumCharUsed = 0' First see if we have any remaining words that should be added to the previous lineIf objWord.FirstIndex - intLinePos > 0 Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Save Previous LinestrReturn(intLineNum) = Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IflngPointSize = lngWordSize' Keep Looping until remaining text will fit on a line by itselfDo While lngPointSize > LineWidthInPoints' Calculate the new end Length (Try to get close to needed end so it does not loop too long)If (objWord.Length - intNumCharUsed) > 10 Then' Set our attempted end position.  Figure out how much of the word we have left' and then take the percentage of that.  The precantage being how far over' the line width we areintEndPosition = intLinePos + ((objWord.Length - intNumCharUsed) / CInt(lngPointSize / LineWidthInPoints))Else' We don't have too many characters Left so just go at them one at a timeintEndPosition = intLinePos + (objWord.Length - intNumCharUsed)End If' Recalculate the lengthlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, intEndPosition - intLinePos))If lngPointSize <= LineWidthInPoints Then' Keep Looping until we are one past it fitting on the lineDo While lngPointSize <= LineWidthInPoints' This character would still fit, add one more characterintEndPosition = intEndPosition + 1' Recalculate the lengthlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, intEndPosition - intLinePos))Loop' Take away the one extra character to go back to the last one that fitintEndPosition = intEndPosition - 1Else' Still too big' Keep removing one character until it fitsDo While lngPointSize > LineWidthInPoints' Did not fit, go back one characterintEndPosition = intEndPosition - 1' Recalculate the lengthlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, intEndPosition - intLinePos))LoopEnd If' Calculate how many characters were addedintNumCharUsed = intNumCharUsed + (intEndPosition - intLinePos)' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Since we made it this far, we know this text fits.  Add it nowstrReturn(intLineNum) = Mid(strLine, intLinePos + 1, intEndPosition - intLinePos)' Reset the Line PositionintLinePos = intEndPosition' Increment our line CounterintLineNum = intLineNum + 1' Now Calculate how big the next line is when we add the remaining text and try againlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos + objWord.Length))LoopElse' This word is smaller than the line width.  Check the width if we add itlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos + objWord.Length))If lngPointSize > LineWidthInPoints Then' It did not fit.  Add previous text to array' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' This word will not fit on current Line.  Save Current LinestrReturn(intLineNum) = Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfEnd IfNext' ------------------------------------' See if there is any text yet to add' ------------------------------------If (Len(strLine) - intLinePos) > 0 Then' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End If' Save of the Last bits of DatastrReturn(intLineNum) = Right(strLine, Len(strLine) - intLinePos)' Increment our line CounterintLineNum = intLineNum + 1End IfElse' ------------------------------------' The entire line fits.  Add it now' ------------------------------------' See if we need to expand the arrayIf UBound(strReturn) < intLineNum Then' ReDim the ArrayReDim Preserve strReturn(intLineNum)End IfstrReturn(intLineNum) = strLine' Increment our line CounterintLineNum = intLineNum + 1End IfNext' Return our ArrayWordWrapByPointToArray = strReturnRelease:On Error Resume NextErase strReturnSet udtTextSize = NothingSet objWordList = NothingSet objWord = NothingSet objRegExp = NothingExit FunctionWordWrapByPointToArray_Error:MsgBox "Procedure = WordWrapByPointToArray" & vbCrLf & _"Error Number = " & Err.Number & vbCrLf & _"Error Message = " & Err.Description & vbCrLf, _vbCritical Or vbSystemModal, "Word Wrap Error"Resume Release:
End Function

WordWrapByPointToString Function

WordWrapByPointToString函数

Here is the fourth attempt at a function.  To use this function, send it the text that you want word wrapped, the font used, and how wide the line should be in points.  It will return a single string with each line in the string separated by a carriage return.

这是功能的第四次尝试。 要使用此功能,请向其发送要自动换行的文本,使用的字体以及线的宽度(以磅为单位)。 它将返回单个字符串,字符串中的每一行都用回车符分隔。

Example:

例:

Dim strWrappedLines As String
strWrappedLines = WordWrapByPointToString(TextToWrap:=TextBox1.Text, TextFont:=TextBox1.Font, LineWidthInPoints:=TextBox1.Width - 6)
Debug.Print strWrappedLines
'---------------------------------------------------------------------------------------
' Function  : WordWrapByPointToString
' Date      : 03/20/2012
' By        : Barry Versaw
' Purpose   : Will Return a String of data that has been sepearated into lines
'               based on Width in Points and split according to textbox word wrap rules.
'               Each line is separated by a carriage return & line feed
'               *** MUST have a REFERENCE set for Microsoft VBScript Regular Expression 5.5
'               *** Must also have the DetermineTextSize Class added to the project***
'
' Usage     : Set a string array = to WordWrapByPointToString sending WordWrapByPointToString
'               your text, Font and Line Width (Point Size) for each line
'               Example:
'               Dim strWrappedLines as string
'               strWrappedLines = WordWrapByPointToString(TextToWrap:=TextBox1.Text, TextFont:=TextBox1.Font, LineWidthInPoints:=TextBox1.Width - 6)
'               This will break the string into multiple lines at the same point as the text box
'
'               Please note in the example I take 6 away form TextBox1.Width as this appears to be
'                the margin size of a text box.  I found this through trial and error and have not
'                been able to verify that value.
'---------------------------------------------------------------------------------------
'
Public Function WordWrapByPointToString(ByVal TextToWrap As String, _ByVal TextFont As StdFont, ByVal LineWidthInPoints As Single) As StringOn Error GoTo WordWrapByPointToString_Error:Dim objRegExp As VBScript_RegExp_55.RegExpDim objWordList As VBScript_RegExp_55.MatchCollectionDim objWord As VBScript_RegExp_55.MatchDim udtTextSize As DetermineTextSizeDim strStartGroup As StringDim strEndGroup As StringDim strRegPattern As StringDim intLineNum As Integer: intLineNum = 0Dim intLinePos As IntegerDim intEndPosition As IntegerDim strReturn As StringDim strLineData() As StringDim strLine As VariantDim lngPointSize As LongDim lngWordSize As LongDim intNumCharUsed As Integer' Instantiate RegExSet objRegExp = New VBScript_RegExp_55.RegExpSet udtTextSize = New DetermineTextSize' ------------------------------------' Set Set Font Settings' ------------------------------------' Make sure we were sent a good line widthIf LineWidthInPoints < 1 Then' Return an ErrorErr.Raise Number:=vbObjectError + 605, Description:="Requested Line Width in Points must be greater than 0"End If' ------------------------------------' Set Set Font Settings' ------------------------------------udtTextSize.Font = TextFont' ------------------------------------' Set RegEx Settings' ------------------------------------objRegExp.MultiLine = FalseobjRegExp.Global = True' ------------------------------------' Set the Search Pattern' ------------------------------------' This is the RegEx List for Characters that should be grouped with the text that follows them' ${(<[\ - Have to use escape character "\" for ] and \strStartGroup = "${(<\[\\"' This is the RegEx List for Characters that should be grouped with the text the preceeds them' !)}%>?-] - Have to use escape character "\" for - and ]strEndGroup = "!)}%>?\-\]"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = "[" & strStartGroup & "]?"' Now grab all characters that are not part of special list and no spaces \s' [] = Group.  Find Anything listed in this group.  + = Find 1 to many instances.' Equates to finding whole words including some special characters (those not in list since negative comparison)strRegPattern = strRegPattern & "[^\s" & strStartGroup & strEndGroup & "]+"' [] = Group.  Find Anything listed in this group.  ? = Find 0 to 1 instancesstrRegPattern = strRegPattern & "[" & strEndGroup & "]?"objRegExp.Pattern = strRegPattern' ------------------------------------' Break up Original String into already defined lines' ------------------------------------strLineData = Split(TextToWrap, vbLf)' ------------------------------------' Loop through each line to wrap text if needed' ------------------------------------For Each strLine In strLineData' Reset the Line Position for this set of textintLinePos = 0' Make sure the line is long enough to need to be wrappedIf udtTextSize.TextWidthinPoints(strLine) > LineWidthInPoints Then' ------------------------------------' Get the list of words defined by the Pattern' ------------------------------------Set objWordList = objRegExp.Execute(strLine)' ------------------------------------' Build the Return Array' ------------------------------------For Each objWord In objWordListlngWordSize = udtTextSize.TextWidthinPoints(objWord.Value)' See if this word is too big to FitIf lngWordSize > LineWidthInPoints Then' Word is too big for the line, have to break it appart' Reset the Number of Characters used in this word to 0intNumCharUsed = 0' First see if we have any remaining words that should be added to the previous lineIf objWord.FirstIndex - intLinePos > 0 Then' Save Previous LinestrReturn = strReturn & (Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IflngPointSize = lngWordSize' Keep Looping until remaining text will fit on a line by itselfDo While lngPointSize > LineWidthInPoints' Calculate the new end Length (Try to get close to needed end so it does not loop too long)If (objWord.Length - intNumCharUsed) > 10 Then' Set our attempted end position.  Figure out how much of the word we have left' and then take the percentage of that.  The precantage being how far over' the line width we areintEndPosition = intLinePos + ((objWord.Length - intNumCharUsed) / CInt(lngPointSize / LineWidthInPoints))Else' We don't have too many characters Left so just go at them one at a timeintEndPosition = intLinePos + (objWord.Length - intNumCharUsed)End If' Recalculate the lengthlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, intEndPosition - intLinePos))If lngPointSize <= LineWidthInPoints Then' Keep Looping until we are one past it fitting on the lineDo While lngPointSize <= LineWidthInPoints' This character would still fit, add one more characterintEndPosition = intEndPosition + 1' Recalculate the lengthlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, intEndPosition - intLinePos))Loop' Take away the one extra character to go back to the last one that fitintEndPosition = intEndPosition - 1Else' Still too big' Keep removing one character until it fitsDo While lngPointSize > LineWidthInPoints' Did not fit, go back one characterintEndPosition = intEndPosition - 1' Recalculate the lengthlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, intEndPosition - intLinePos))LoopEnd If' Calculate how many characters were addedintNumCharUsed = intNumCharUsed + (intEndPosition - intLinePos)' Since we made it this far, we know this text fits.  Add it nowstrReturn = strReturn & (Mid(strLine, intLinePos + 1, intEndPosition - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = intEndPosition' Increment our line CounterintLineNum = intLineNum + 1' Now Calculate how big the next line is when we add the remaining text and try againlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos + objWord.Length))LoopElse' This word is smaller than the line width.  Check the width if we add itlngPointSize = udtTextSize.TextWidthinPoints(Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos + objWord.Length))If lngPointSize > LineWidthInPoints Then' It did not fit.  Add previous text to array' This word will not fit on current Line.  Save Current LinestrReturn = strReturn & (Mid(strLine, intLinePos + 1, objWord.FirstIndex - intLinePos) & vbNewLine)' Reset the Line PositionintLinePos = objWord.FirstIndex' Increment our line CounterintLineNum = intLineNum + 1End IfEnd IfNext' ------------------------------------' See if there is any text yet to add' ------------------------------------If (Len(strLine) - intLinePos) > 0 Then' Save of the Last bits of DatastrReturn = strReturn & (Right(strLine, Len(strLine) - intLinePos) & vbNewLine)' Increment our line CounterintLineNum = intLineNum + 1End IfElse' ------------------------------------' The entire line fits.  Add it now' ------------------------------------strReturn = strReturn & (strLine & vbNewLine)' Increment our line CounterintLineNum = intLineNum + 1End IfNext' Return our StringWordWrapByPointToString = strReturnRelease:On Error Resume NextSet udtTextSize = NothingSet objWordList = NothingSet objWord = NothingSet objRegExp = NothingExit FunctionWordWrapByPointToString_Error:MsgBox "Procedure = WordWrapByPointToString" & vbCrLf & _"Error Number = " & Err.Number & vbCrLf & _"Error Message = " & Err.Description & vbCrLf, _vbCritical Or vbSystemModal, "Word Wrap Error"Resume Release:
End Function

DetermineTextSize Class

确定文本大小类

Both of the above functions require the following code to be added as a class to your project.  Please name the class DetermineTextSize.  To add a class, on the menu click Insert >> Class Module.  Then in the properties change the name to DetermineTextSize.  Then in the code window paste the following code:

以上两个功能都需要将以下代码作为类添加到您的项目中。 请将该类命名为DefineTextSize。 要添加类,请在菜单上单击插入>>类模块。 然后在属性中将名称更改为确定文本大小。 然后在代码窗口中粘贴以下代码:

'---------------------------------------------------------------------------------------
' Class   : DetermineTextSize
' PURPOSE : This class accepts a font and the determines the size of the passed text.
'           It can return the Text Height or Width in Pixels or
'           The Text Height or Width in Points
'
'           This code is adapted from several posts on the web
'-----------------------Option Explicit' Declare all Needed Windows Constants
Private Const LF_FACESIZE = 32
Private Const LOGPIXELSY = 90
Private Const LOGPIXELSX = 88
Private Const DT_CALCRECT = &H400' See - http://msdn.microsoft.com/en-us/library/dd145037%28v=vs.85%29.aspx
Private Type udtLogFontlfHeight As LonglfWidth As LonglfEscapement As LonglfOrientation As LonglfWeight As LonglfItalic As BytelfUnderline As BytelfStrikeOut As BytelfCharSet As BytelfOutPrecision As BytelfClipPrecision As BytelfQuality As BytelfPitchAndFamily As BytelfFaceName(LF_FACESIZE) As Byte
End TypePrivate Type udtTextSizeWidth As LongHeight As Long
End TypePrivate Declare Function GetTextExtentPoint Lib "gdi32" _Alias "GetTextExtentPointA" (ByVal hDC As Long, _ByVal lpszString As String, ByVal cbString As Long, _lpSIZE32 As udtTextSize) As LongPrivate Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" _(ByRef lpudtLogFont As udtLogFont) As LongPrivate Declare Function GetDC Lib "user32.dll" _(ByVal hWnd As Long) As LongPrivate Declare Function ReleaseDC Lib "user32.dll" _(ByVal hWnd As Long, ByVal hDC As Long) As LongPrivate Declare Function MulDiv Lib "kernel32" ( _ByVal nNumber As Long, ByVal nNumerator As Long, _ByVal nDenominator As Long) As LongPrivate Declare Function DeleteObject Lib "gdi32" _(ByVal hObject As Long) As LongPrivate Declare Function GetDeviceCaps Lib "gdi32" _(ByVal hDC As Long, ByVal nIndex As Long) As LongPrivate Declare Function SelectObject Lib "gdi32" _(ByVal hDC As Long, ByVal hObject As Long) As LongPrivate m_objFont As StdFont        ' Store Font Settings to be used for calculations
Private m_hDeviceContext As Long    ' Store the handler for the Device Context
Private m_intDPIWidth As Integer    ' Store the DPI Width - just calculate once
Private m_intDPIHeight As Integer   ' Store the DPI Height - just calculate once'---------------------------------------------------------------------------------------
' Procedure : Class_Initialize
' Purpose   : Class has been Declared.  Set Default Values
'---------------------------------------------------------------------------------------
'
Private Sub Class_Initialize()' Instantiate the Font ObjectSet m_objFont = New StdFont' Get Access to A Device Context for the general screenm_hDeviceContext = GetDC(0)' Grab the Screen DPI Settingsm_intDPIWidth = GetDeviceCaps(m_hDeviceContext, LOGPIXELSX)m_intDPIHeight = GetDeviceCaps(m_hDeviceContext, LOGPIXELSY)
End Sub'---------------------------------------------------------------------------------------
' Procedure : Class_Terminate
' Purpose   : Class is being Destroyed.  Release objects
'---------------------------------------------------------------------------------------
'
Private Sub Class_Terminate()Set m_objFont = NothingEnd Sub'---------------------------------------------------------------------------------------
' Property  : Font
' Purpose   : Gets & Lets the Font to be used in sizing the text
'---------------------------------------------------------------------------------------
'
Public Property Get Font() As StdFontFont = m_objFontReleaseDC 0, m_hDeviceContextEnd PropertyPublic Property Let Font(ByVal FontValue As StdFont)Set m_objFont = FontValueEnd Property'---------------------------------------------------------------------------------------
' Procedure : TextHeightInPixels
' Purpose   : Returns the Height of sent text in pixels
'---------------------------------------------------------------------------------------
Public Function TextHeightInPixels(ByVal TextToEvaluate As String) As LongDim udtSize As udtTextSize' Get the Size of the Text in Height & WidthudtSize = GetSizeOfText(TextToEvaluate)' .Bottom Returns how high the rectangle is in pixelsTextHeightInPixels = udtSize.Height
End Function'---------------------------------------------------------------------------------------
' Procedure : TextHeightInPoints
' Purpose   : Returns the Height of sent text in Points
'---------------------------------------------------------------------------------------
Public Function TextHeightInPoints(ByVal TextToEvaluate As String) As LongDim udtSize As udtTextSize' Get the Size of the Text in Height & WidthudtSize = GetSizeOfText(TextToEvaluate)' .Bottom Returns how high the rectangle is in pixels' Pionts = Pixels *  72 / DPI : 72 Points Per Inch' Use MulDiv to avoid potential overflow errorTextHeightInPoints = MulDiv(udtSize.Height, 72, m_intDPIHeight)End Function'---------------------------------------------------------------------------------------
' Procedure : TextWidthInPixels
' Purpose   : Returns the width of sent text in pixels.  If the text has
'               multiple lines, it returns the width of the widest line.
'---------------------------------------------------------------------------------------
Public Function TextWidthInPixels(ByVal TextToEvaluate As String) As LongDim udtSize As udtTextSize' Get the Size of the Text in Height & WidthudtSize = GetSizeOfText(TextToEvaluate)' Width is the Right Dimension of the RectangleTextWidthInPixels = udtSize.WidthEnd Function'---------------------------------------------------------------------------------------
' Procedure : TextWidthInPoints
' Purpose   : Returns the width of sent text in Points.  If the text has
'               multiple lines, it returns the width of the widest line.
'---------------------------------------------------------------------------------------
Public Function TextWidthinPoints(ByVal TextToEvaluate As String) As LongDim udtSize As udtTextSize' Get the Size of the Text in Height & WidthudtSize = GetSizeOfText(TextToEvaluate)' Width is the Right Dimension of the Rectangle' Pionts = Pixels *  72 / DPI : 72 Points Per Inch' Use MulDiv to avoid potential overflow errorTextWidthinPoints = MulDiv(udtSize.Width, 72, m_intDPIWidth)End Function'---------------------------------------------------------------------------------------
' Procedure : GetudtTextSize
' Purpose   : Gets udtLogFont size of a string and returns it as
'               Width ane Length Dimension
'---------------------------------------------------------------------------------------
'
Private Function GetSizeOfText(ByVal TextToSize As String) As udtTextSizeDim udtFont As udtLogFontDim hFont As Long           ' Handle to a Logical FontDim hOldFont As Long        ' Handle to a Logcial FontDim udtReturnDims As udtTextSize' Convert the stdFont to a udtLogFont for use in drawing the RectangleudtFont = OLEFontToLogFont(m_objFont)' Create a temporary Font to draw the RectanglehFont = CreateFontIndirect(udtFont)' Store the Current Font to put back when donehOldFont = SelectObject(m_hDeviceContext, hFont)' Draw the RectangleGetTextExtentPoint m_hDeviceContext, TextToSize, Len(TextToSize), udtReturnDims' Put the Original Font Back in PlaceSelectObject m_hDeviceContext, hOldFont' Delete our Temporary FontDeleteObject hFont' Return the DimensionsGetSizeOfText = udtReturnDimsEnd Function'---------------------------------------------------------------------------------------
' Procedure : OLEFontToLogFont
' Purpose   : Converts an OLE stdFont to a udtLogFont
'---------------------------------------------------------------------------------------
Private Function OLEFontToLogFont(ByVal FontToConvert As StdFont) As udtLogFontDim strFont As StringDim intChar As IntegerDim bytFont() As ByteWith OLEFontToLogFontstrFont = FontToConvert.NamebytFont = StrConv(strFont, vbFromUnicode)For intChar = 0 To Len(strFont) - 1.lfFaceName(intChar) = bytFont(intChar)Next intChar' Convert Height from Points to Pixels' Use MulDiv to avoid potential overflow error.lfHeight = -MulDiv(FontToConvert.Size, m_intDPIHeight, 72).lfItalic = FontToConvert.Italic.lfWeight = FontToConvert.Weight.lfUnderline = FontToConvert.Underline.lfStrikeOut = FontToConvert.Strikethrough.lfCharSet = FontToConvert.CharsetEnd WithEnd Function

翻译自: https://www.experts-exchange.com/articles/10064/The-end-of-a-pilgrimage-to-find-a-more-robust-WordWrap-function.html

一个人的朝圣深度感悟

一个人的朝圣深度感悟_朝圣之末找到更强大的WordWrap函数相关推荐

  1. dll文件用什么语言编写_为什么Unix不用功能更强大的C++而是用C编写

    有人总会说C++不是要比C的作用大很多,功能也更多.那为什么Unix不用功能更强大的C++而是用C编写?关于Unix为什么用C而不是C ++编写的显而易见的答案是C ++是在C之后诞生的.另一个原因是 ...

  2. 深度学习:在图像上找到手势_使用深度学习的人类情绪和手势检测器:第2部分

    深度学习:在图像上找到手势 情感手势检测 (Emotion Gesture Detection) Hello everyone! Welcome back to the part-2 of human ...

  3. lime 深度学习_用LIME解释机器学习预测并建立信任

    lime 深度学习 It's needless to say: machine learning is powerful. 不用说:机器学习功能强大. At the most basic level, ...

  4. 深度学习:在图像上找到手势_使用深度学习的人类情绪和手势检测器:第1部分

    深度学习:在图像上找到手势 情感手势检测 (Emotion Gesture Detection) Has anyone ever wondered looking at someone and tri ...

  5. python课程结课感悟_科学网—《互联网+引论与Python》课堂感想(七) - 张忆文的博文...

    课程感想 文/2018级社会学 方向阳 在本学期的课程中,我受益良多,这种收获不仅只是课程的知识,更多的是关于学习的态度.下面我将从三个方面讲述对课程的感想感悟. 一.课堂模式 互联网+课程的模式是让 ...

  6. 证券行业信息化_感悟_我遇到了哪些系统故障?系统故障如何避免?如何看待系统故障?

    转自 https://stanleyyan.wordpress.com/2010/10/06/%E8%AF%81%E5%88%B8%E8%A1%8C%E4%B8%9A%E4%BF%A1%E6%81%A ...

  7. 双卡双待支持双电池 夏新N808深度评测_夏新手机评测-泡泡网

    双卡双待支持双电池 夏新N808深度评测_夏新手机评测-泡泡网 双卡双待支持双电池 夏新N808深度评测_夏新手机评测-泡泡网 双卡双待支持双电池 夏新N808深度评测 posted on 2013- ...

  8. octave深度学习_【深度学习笔记】(一)Octave

    [深度学习笔记](一)Octave Octave是一种面向科学数学运算的原型语言,内置了强大的数学函数及图形展示工具.原型prototyping设计的意思是使用ovtave进行算法设计.实现.验证等过 ...

  9. 奥比中光深度摄像头_苹果收购Primesense后,奥比中光希望用它的深度摄像头填补市场空白...

    提到体感技术和深度摄像头,很多人的第一印象就是微软的Kinect.然而微软的第一代Kinect技术来自Primesense的授权.2005年创建于以色列的 PrimeSense 可谓深度摄像头技术的先 ...

最新文章

  1. Hadoop的存储架构介绍
  2. js中的失误导致的奇怪事
  3. mysql的in查询参数限制,多少数据量会造成性能下降?什么时候创建临时表合适?
  4. 黑马程序员--线程【下】
  5. android bitmap转图片_Android 这些 Drawable 你都会用吗?
  6. CentOS 恢复 rm -rf * 误删数据(转)
  7. 如何查看 mysql 的视图?
  8. 余承东宣布鸿蒙系统视频,余承东宣布鸿蒙系统开源:打造全球的操作系统
  9. CppUnit快速入门
  10. 鸿蒙 HarmonyOS 3.0,终于来了!
  11. 数据抓取的艺术(二)
  12. 20个PCB快捷键操作,提升绘图效率
  13. at+cipstart返回state:tcp close解决方案 SIM868模块使用
  14. 2021-05-23 自学Java第三天 唉 怎么感觉自制力不是很强啊 感觉有些慢了 慢慢来吧
  15. 为赢过老婆打造自动瞄准弓,闭眼也能百发百中,零件电路算法全自制
  16. Spring Cloud限流详解
  17. 基于IAAS和SAAS的运维自动化-张克琛
  18. 内存泄露的检测工具——Valgrind
  19. 一款小巧的kafka测试工具
  20. MySQL中修改密码及访问限制

热门文章

  1. iOS1.0到iOS7,iOS七大版本特性回顾
  2. 河道、地下水位监测方案
  3. ESP32(arduino)和声音传感器数据采集并实现连接WiFi进行MQTT通信
  4. 计算机网络用户名及密码如何查询,用wifi连接电脑的怎么查看宽带账号密码
  5. 苹果双卡双待买哪款合适_iPhone 12/苹果12哪款最值得买?
  6. 2017 ccpc网络预选赛 CaoHaha's staff
  7. 第四套人民币荧光“四大天王”收藏价值分析
  8. 嵌入式LINUX搭建arm环境,手把手教你嵌入式ARM开发环境搭建
  9. win10电脑黑屏,只有鼠标能动,并且只能打开任务管理器
  10. Jfrog:烂泥蛙安装