Moderators Melba23 Posted February 23, 2010 Moderators Share Posted February 23, 2010 anixon,If you need to know the size of any piece of text, then please use my StringSize UDF:expandcollapse popup#include-once ; #INDEX# ============================================================================================================ ; Title .........: _StringSize ; AutoIt Version : v3.2.12.1 or higher ; Language ......: English ; Description ...: Returns size of rectangle required to display string - width can be chosen ; Remarks .......: ; Note ..........: ; Author(s) .....: Melba23 ; ==================================================================================================================== ;#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 ; #INCLUDES# ========================================================================================================= #include <SendMessage.au3> #include <WinAPI.au3> ; #CURRENT# ========================================================================================================== ; _StringSize: Returns size of rectangle required to display string - width can be chosen ; ==================================================================================================================== ; #INTERNAL_USE_ONLY#================================================================================================= ; _StringSize_Error: Returns from error condition after DC and GUI clear up ; ==================================================================================================================== ; #FUNCTION# ========================================================================================================= ; Name...........: _StringSize ; Description ...: Returns size of rectangle required to display string - maximum permitted width can be chosen ; Syntax ........: _StringSize($sText[, $iSize[, $iWeight[, $iAttrib[, $sName[, $iWidth]]]]]) ; Parameters ....: $sText - String to display ; $iSize - [optional] Font size in points - default AutoIt GUI default ; $iWeight - [optional] Font weight (400 = normal) - default AutoIt GUI default ; $iAttrib - [optional] Font attribute (0-Normal, 2-Italic, 4-Underline, 8 Strike - default AutoIt ; $sName - [optional] Font name - default AutoIt GUI default ; $iWidth - [optional] Width of rectangle - default is unwrapped width of string ; Requirement(s) : v3.2.12.1 or higher ; Return values .: Success - Returns array with details of rectangle required for text: ; |$array[0] = String formatted with @CRLF at required wrap points ; |$array[1] = Height of single line in selected font ; |$array[2] = Width of rectangle required to hold formatted string ; |$array[3] = Height of rectangle required to hold formatted string ; Failure - Returns 0 and sets @error: ; |1 - Incorrect parameter type (@extended = parameter index) ; |2 - Failure to create GUI to test label size ; |3 - DLL call error - extended set to indicate which ; |4 - Font too large for chosen width - longest word will not fit ; Author ........: Melba23 ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: Yes ;===================================================================================================================== Func _StringSize($sText, $iSize = Default, $iWeight = Default, $iAttrib = Default, $sName = Default, $iWidth = 0) Local $avSize_Info[4], $iLine_Width = 0, $iLast_Word, $iWrap_Count Local $hLabel_Handle, $hFont, $hDC, $oFont, $tSize ; Check parameters are correct type If Not IsString($sText) Then Return SetError(1, 1, 0) If Not IsNumber($iSize) And $iSize <> Default Then Return SetError(1, 2, 0) If Not IsInt($iWeight) And $iWeight <> Default Then Return SetError(1, 3, 0) If Not IsInt($iAttrib) And $iAttrib <> Default Then Return SetError(1, 4, 0) If Not IsString($sName) And $sName <> Default Then Return SetError(1, 5, 0) If Not IsNumber($iWidth) Then Return SetError(1, 6, 0) ; Create GUI to contain test labels, set to passed font parameters Local $hGUI = GUICreate("", 1200, 500, @DesktopWidth + 10, @DesktopHeight + 10) If $hGUI = 0 Then Return SetError(2, 0, 0) GUISetFont($iSize, $iWeight, $iAttrib, $sName) ; Store unwrapped text $avSize_Info[0] = $sText ; Ensure EoL is @CRLF and break text into lines If StringInStr($sText, @CRLF) = 0 Then StringRegExpReplace($sText, "[\x0a|\x0d]", @CRLF) Local $asLines = StringSplit($sText, @CRLF, 1) ; Draw label with unwrapped lines to check on max width Local $hText_Label = GUICtrlCreateLabel($sText, 10, 10) Local $aiPos = ControlGetPos($hGUI, "", $hText_Label) GUISetState(@SW_HIDE) GUICtrlDelete($hText_Label) ; Store line height for this font size after removing label padding (always 8) $avSize_Info[1] = ($aiPos[3] - 8)/ $asLines[0] ; Store width and height of this label $avSize_Info[2] = $aiPos[2] $avSize_Info[3] = $aiPos[3] - 4 ; Reduce margin ; Check if wrapping is required If $aiPos[2] > $iWidth And $iWidth > 0 Then ; Set returned text element to null $avSize_Info[0] = "" ; Set width element to max allowed $avSize_Info[2] = $iWidth ; Set line count to zero Local $iLine_Count = 0 ; Take each line in turn For $j = 1 To $asLines[0] ; Size this line unwrapped $hText_Label = GUICtrlCreateLabel($asLines[$j], 10, 10) $aiPos = ControlGetPos($hGUI, "", $hText_Label) GUICtrlDelete($hText_Label) ; Check wrap status If $aiPos[2] < $iWidth Then ; No wrap needed so count line and store $iLine_Count += 1 $avSize_Info[0] &= $asLines[$j] & @CRLF Else ; Wrap needed so need to count wrapped lines ; Create label to hold line as it grows $hText_Label = GUICtrlCreateLabel("", 0, 0) ; Initialise Point32 method $hLabel_Handle = ControlGetHandle($hGui, "", $hText_Label) $hDC = _WinAPI_GetDC($hLabel_Handle) If @error Then _StringSize_Error(3, 1, $hLabel_Handle, 0, $hGUI) $hFont = _SendMessage($hLabel_Handle, 0x0031) ; $WM_GETFONT If @error Then _StringSize_Error(3, 2, $hLabel_Handle, $hDC, $hGUI) $oFont = _WinAPI_SelectObject($hDC, $hFont) If @error Then _StringSize_Error(3, 3, $hLabel_Handle, $hDC, $hGUI) If $oFont = 0 Then _StringSize_Error(3, 4, $hLabel_Handle, $hDC, $hGUI) ; Zero counter $iWrap_Count = 0 While 1 ; Set line width to 0 $iLine_Width = 0 ; Initialise pointer for end of word $iLast_Word = 0 For $i = 1 To StringLen($asLines[$j]) ; Is this just past a word ending? If StringMid($asLines[$j], $i, 1) = " " Then $iLast_Word = $i - 1 ; Increase line by one character Local $sTest_Line = StringMid($asLines[$j], 1, $i) ; Place line in label GUICtrlSetData($hText_Label, $sTest_Line) ; Get line length $tSize = _WinAPI_GetTextExtentPoint32($hDC, $sTest_Line) If @error Then _StringSize_Error(3, 5, $hLabel_Handle, $hDC, $hGUI) $iLine_Width = DllStructGetData($tSize, "X") ; If too long exit the loop If $iLine_Width >= $iWidth - Int($iSize / 2) Then ExitLoop Next ; End of the line of text? If $i > StringLen($asLines[$j]) Then ; Yes, so add final line to count $iWrap_Count += 1 ; Store line $avSize_Info[0] &= $sTest_Line & @CRLF ExitLoop Else ; No, but add line just completed to count $iWrap_Count += 1 ; Check at least 1 word completed or return error If $iLast_Word = 0 Then _StringSize_Error(4, 0, $hLabel_Handle, $hDC, $hGUI) EndIf ; Store line up to end of last word $avSize_Info[0] &= StringLeft($sTest_Line, $iLast_Word) & @CRLF ; Strip string to point reached $asLines[$j] = StringTrimLeft($asLines[$j], $iLast_Word) ; Trim leading whitespace $asLines[$j] = StringStripWS($asLines[$j], 1) ; Repeat with remaining characters in line EndIf WEnd ; Add the number of wrapped lines to the count $iLine_Count += $iWrap_Count ; Clean up _WinAPI_ReleaseDC($hLabel_Handle, $hDC) GUICtrlDelete($hText_Label) EndIf Next ; Convert lines to pixels and add reduced margin $avSize_Info[3] = ($iLine_Count * $avSize_Info[1]) + 4 EndIf ; Clean up GUIDelete($hGUI) ; Return array Return $avSize_Info EndFunc ; => _StringSize ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _StringSize_Error ; Description ...: Returns from error condition after DC and GUI clear up ; Syntax ........: _StringSize_Error($iError, $iExtended, $hLabel_Handle, $hDC, $hGUI) ; Parameters ....: $iError - required error value to return ; $iExtended - required extended value to return ; $hLabel_Handle, $hDC, $hGUI - variables as set in _StringSize function ; Author ........: Melba23 ; Modified.......: ; Remarks .......: This function is used internally by _StringSize ; =============================================================================================================================== Func _StringSize_Error($iError, $iExtended, $hLabel_Handle, $hDC, $hGUI) ; Release DC if created DllCall("User32.dll", "int", "ReleaseDC", "hwnd", $hLabel_Handle, "hwnd", $hDC) ; Delete GUI GUIDelete($hGUI) ; Return with extended set Return SetError($iError, $iExtended, 0) EndFunc ; => _StringSize_ErrorI think the header is self-explanatory, but please ask if anything is unclear. M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
anixon Posted February 23, 2010 Author Share Posted February 23, 2010 anixon, If you need to know the size of any piece of text, then please use my StringSize UDF: expandcollapse popup#include-once ; #INDEX# ============================================================================================================ ; Title .........: _StringSize ; AutoIt Version : v3.2.12.1 or higher ; Language ......: English ; Description ...: Returns size of rectangle required to display string - width can be chosen ; Remarks .......: ; Note ..........: ; Author(s) .....: Melba23 ; ==================================================================================================================== ;#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 ; #INCLUDES# ========================================================================================================= #include <SendMessage.au3> #include <WinAPI.au3> ; #CURRENT# ========================================================================================================== ; _StringSize: Returns size of rectangle required to display string - width can be chosen ; ==================================================================================================================== ; #INTERNAL_USE_ONLY#================================================================================================= ; _StringSize_Error: Returns from error condition after DC and GUI clear up ; ==================================================================================================================== ; #FUNCTION# ========================================================================================================= ; Name...........: _StringSize ; Description ...: Returns size of rectangle required to display string - maximum permitted width can be chosen ; Syntax ........: _StringSize($sText[, $iSize[, $iWeight[, $iAttrib[, $sName[, $iWidth]]]]]) ; Parameters ....: $sText - String to display ; $iSize - [optional] Font size in points - default AutoIt GUI default ; $iWeight - [optional] Font weight (400 = normal) - default AutoIt GUI default ; $iAttrib - [optional] Font attribute (0-Normal, 2-Italic, 4-Underline, 8 Strike - default AutoIt ; $sName - [optional] Font name - default AutoIt GUI default ; $iWidth - [optional] Width of rectangle - default is unwrapped width of string ; Requirement(s) : v3.2.12.1 or higher ; Return values .: Success - Returns array with details of rectangle required for text: ; |$array[0] = String formatted with @CRLF at required wrap points ; |$array[1] = Height of single line in selected font ; |$array[2] = Width of rectangle required to hold formatted string ; |$array[3] = Height of rectangle required to hold formatted string ; Failure - Returns 0 and sets @error: ; |1 - Incorrect parameter type (@extended = parameter index) ; |2 - Failure to create GUI to test label size ; |3 - DLL call error - extended set to indicate which ; |4 - Font too large for chosen width - longest word will not fit ; Author ........: Melba23 ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: Yes ;===================================================================================================================== Func _StringSize($sText, $iSize = Default, $iWeight = Default, $iAttrib = Default, $sName = Default, $iWidth = 0) Local $avSize_Info[4], $iLine_Width = 0, $iLast_Word, $iWrap_Count Local $hLabel_Handle, $hFont, $hDC, $oFont, $tSize ; Check parameters are correct type If Not IsString($sText) Then Return SetError(1, 1, 0) If Not IsNumber($iSize) And $iSize <> Default Then Return SetError(1, 2, 0) If Not IsInt($iWeight) And $iWeight <> Default Then Return SetError(1, 3, 0) If Not IsInt($iAttrib) And $iAttrib <> Default Then Return SetError(1, 4, 0) If Not IsString($sName) And $sName <> Default Then Return SetError(1, 5, 0) If Not IsNumber($iWidth) Then Return SetError(1, 6, 0) ; Create GUI to contain test labels, set to passed font parameters Local $hGUI = GUICreate("", 1200, 500, @DesktopWidth + 10, @DesktopHeight + 10) If $hGUI = 0 Then Return SetError(2, 0, 0) GUISetFont($iSize, $iWeight, $iAttrib, $sName) ; Store unwrapped text $avSize_Info[0] = $sText ; Ensure EoL is @CRLF and break text into lines If StringInStr($sText, @CRLF) = 0 Then StringRegExpReplace($sText, "[\x0a|\x0d]", @CRLF) Local $asLines = StringSplit($sText, @CRLF, 1) ; Draw label with unwrapped lines to check on max width Local $hText_Label = GUICtrlCreateLabel($sText, 10, 10) Local $aiPos = ControlGetPos($hGUI, "", $hText_Label) GUISetState(@SW_HIDE) GUICtrlDelete($hText_Label) ; Store line height for this font size after removing label padding (always 8) $avSize_Info[1] = ($aiPos[3] - 8)/ $asLines[0] ; Store width and height of this label $avSize_Info[2] = $aiPos[2] $avSize_Info[3] = $aiPos[3] - 4 ; Reduce margin ; Check if wrapping is required If $aiPos[2] > $iWidth And $iWidth > 0 Then ; Set returned text element to null $avSize_Info[0] = "" ; Set width element to max allowed $avSize_Info[2] = $iWidth ; Set line count to zero Local $iLine_Count = 0 ; Take each line in turn For $j = 1 To $asLines[0] ; Size this line unwrapped $hText_Label = GUICtrlCreateLabel($asLines[$j], 10, 10) $aiPos = ControlGetPos($hGUI, "", $hText_Label) GUICtrlDelete($hText_Label) ; Check wrap status If $aiPos[2] < $iWidth Then ; No wrap needed so count line and store $iLine_Count += 1 $avSize_Info[0] &= $asLines[$j] & @CRLF Else ; Wrap needed so need to count wrapped lines ; Create label to hold line as it grows $hText_Label = GUICtrlCreateLabel("", 0, 0) ; Initialise Point32 method $hLabel_Handle = ControlGetHandle($hGui, "", $hText_Label) $hDC = _WinAPI_GetDC($hLabel_Handle) If @error Then _StringSize_Error(3, 1, $hLabel_Handle, 0, $hGUI) $hFont = _SendMessage($hLabel_Handle, 0x0031) ; $WM_GETFONT If @error Then _StringSize_Error(3, 2, $hLabel_Handle, $hDC, $hGUI) $oFont = _WinAPI_SelectObject($hDC, $hFont) If @error Then _StringSize_Error(3, 3, $hLabel_Handle, $hDC, $hGUI) If $oFont = 0 Then _StringSize_Error(3, 4, $hLabel_Handle, $hDC, $hGUI) ; Zero counter $iWrap_Count = 0 While 1 ; Set line width to 0 $iLine_Width = 0 ; Initialise pointer for end of word $iLast_Word = 0 For $i = 1 To StringLen($asLines[$j]) ; Is this just past a word ending? If StringMid($asLines[$j], $i, 1) = " " Then $iLast_Word = $i - 1 ; Increase line by one character Local $sTest_Line = StringMid($asLines[$j], 1, $i) ; Place line in label GUICtrlSetData($hText_Label, $sTest_Line) ; Get line length $tSize = _WinAPI_GetTextExtentPoint32($hDC, $sTest_Line) If @error Then _StringSize_Error(3, 5, $hLabel_Handle, $hDC, $hGUI) $iLine_Width = DllStructGetData($tSize, "X") ; If too long exit the loop If $iLine_Width >= $iWidth - Int($iSize / 2) Then ExitLoop Next ; End of the line of text? If $i > StringLen($asLines[$j]) Then ; Yes, so add final line to count $iWrap_Count += 1 ; Store line $avSize_Info[0] &= $sTest_Line & @CRLF ExitLoop Else ; No, but add line just completed to count $iWrap_Count += 1 ; Check at least 1 word completed or return error If $iLast_Word = 0 Then _StringSize_Error(4, 0, $hLabel_Handle, $hDC, $hGUI) EndIf ; Store line up to end of last word $avSize_Info[0] &= StringLeft($sTest_Line, $iLast_Word) & @CRLF ; Strip string to point reached $asLines[$j] = StringTrimLeft($asLines[$j], $iLast_Word) ; Trim leading whitespace $asLines[$j] = StringStripWS($asLines[$j], 1) ; Repeat with remaining characters in line EndIf WEnd ; Add the number of wrapped lines to the count $iLine_Count += $iWrap_Count ; Clean up _WinAPI_ReleaseDC($hLabel_Handle, $hDC) GUICtrlDelete($hText_Label) EndIf Next ; Convert lines to pixels and add reduced margin $avSize_Info[3] = ($iLine_Count * $avSize_Info[1]) + 4 EndIf ; Clean up GUIDelete($hGUI) ; Return array Return $avSize_Info EndFunc ; => _StringSize ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _StringSize_Error ; Description ...: Returns from error condition after DC and GUI clear up ; Syntax ........: _StringSize_Error($iError, $iExtended, $hLabel_Handle, $hDC, $hGUI) ; Parameters ....: $iError - required error value to return ; $iExtended - required extended value to return ; $hLabel_Handle, $hDC, $hGUI - variables as set in _StringSize function ; Author ........: Melba23 ; Modified.......: ; Remarks .......: This function is used internally by _StringSize ; =============================================================================================================================== Func _StringSize_Error($iError, $iExtended, $hLabel_Handle, $hDC, $hGUI) ; Release DC if created DllCall("User32.dll", "int", "ReleaseDC", "hwnd", $hLabel_Handle, "hwnd", $hDC) ; Delete GUI GUIDelete($hGUI) ; Return with extended set Return SetError($iError, $iExtended, 0) EndFunc ; => _StringSize_Error I think the header is self-explanatory, but please ask if anything is unclear. M23 Thanks for that I will run the code later today cause I need a break from coding so off to see 'Hurt Locker' Ant.. Link to comment Share on other sites More sharing options...
anixon Posted February 24, 2010 Author Share Posted February 24, 2010 (edited) Thanks for the fantastic help Melba23. Calculating width based on font has been an issue that I have struggled with for a long time. A post some time ago did not produce a methodology and your solution is most elegant. Given that I am only every accommodating a single line of fixed text of various lengths I have modified your code for my own purpose Thanks again Ant.. #include <GUIConstantsEx.au3> Opt('MustDeclareVars', 1) Global $iSize = 12, $iWeight = 400, $iAttrib = 0, $sName = "sans-serif", $sText = "This is a test and another test", $iWidth, $iMargin = 4 ;//Call the PopUp Box Width Calculator _PopUpBoxWidth() ;//Display the result MsgBox(0, "", $iWidth) Func _PopUpBoxWidth() ;//Create a dialog box Local $hGUI = GUICreate("") ;//Set the font for text within the dialog box GUISetFont($iSize, $iWeight, $iAttrib, $sName) ;//Create the Label Local $hText_Label = GUICtrlCreateLabel($sText, 10, 20) ;//Read the Pixel Width of the Label Local $aiPos = ControlGetPos($hGUI, $sText, $hText_Label) ;//Save the Width plus a margin $iWidth = $aiPos[2] + $iMargin ;//Hide the dialog box GUISetState(@SW_Hide) ;//Delete the dialogbox GUIDelete($hGUI) EndFunc ;==>Example Edited February 24, 2010 by anixon Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted February 24, 2010 Moderators Share Posted February 24, 2010 anixon, Just what you need for a single line! Short and sweet! M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now