Jump to content

How to get the font size (width & height) ?


charvi
 Share

Recommended Posts

How can I retrieve the pixel size of a font at a particular size and attribute? This is mainly useful for monospaced fonts.

And for proportional fonts, how can I retrieve the pixel size of a specified character at a specified size and attribute? I need this to calculate automatically the size of the label (GUICtrlCreateLabel).

Link to comment
Share on other sites

How can I retrieve the pixel size of a font at a particular size and attribute? This is mainly useful for monospaced fonts.

And for proportional fonts, how can I retrieve the pixel size of a specified character at a specified size and attribute? I need this to calculate automatically the size of the label (GUICtrlCreateLabel).

It's easier to set the font of the gui to whatever you want then create the label and it will automatiucally be the correct size. You can set the gui font back afterwards if needed.

Here is an example, but there are other ideas in the same thread.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

Yes martin, I agree, it's easier to let the label be created automatically. But knowing the size of a character in a certain font with some attributes set, it can help construct the screen page in advance, and not only for labels. Because nobody else replied to my original question, I must think that there is no way at this time.

So, because of this, I was thinking of a way to get a value anyway. The code below is my solution as I have no (or too few) knowledge about Win API stuff, so I wrote a pure AutoIt method.

If you have comments or ideas to make it better, your welcome. I even don't know if the values returned are correct.

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GuiStatusBar.au3>
#include <GuiEdit.au3>
#include <GuiMenu.au3>
#include <GuiToolBar.au3>
#include <GuiComboBoxEx.au3>
#include <Array.au3>
#include <Constants.au3>
#include <WinAPI.au3>
#include <File.au3>
#include <Misc.au3>
#include <GDIPlus.au3>
#include <Color.au3>

Global $h_Wx, $h_Label, $i_LabelWidth, $i_LabelHeight, $i_Color, $s_FontName, $n_FontSize, $i_FontAttr, $i_FontWeight, $n_FontWidth, $n_FontHeight
Global $s_Char, $i_1, $i_2, $i_we, $i_ws, $i_he, $i_hs, $i_P, $s_Result

; ==============================================================
; Select the Font here
$s_FontName = "Courier"
$n_FontSize = 30
$i_FontWeight = 400 ; 400 (=normal) or 800 (=bold)
$i_FontAttr = 1
$s_Char = "W"
; ==============================================================
; For larger font sizes like 200, set the label width and height
; both to 300 for example
; don't forget: the bigger the label, the longer it will take
$i_LabelWidth = 30
$i_LabelHeight = 30
; ==============================================================

$h_Wx = GUICreate("",$i_LabelWidth,$i_LabelHeight,0,0,$WS_POPUP)
GUISetBkColor(0xc1c1c1, $h_Wx)

$h_Label = GUICtrlCreateLabel($s_Char,0,0,$i_LabelWidth,$i_LabelHeight)
GUIctrlSetFont($h_Label, $n_FontSize, $i_FontWeight, $i_FontAttr, $s_FontName)
GUICtrlSetBkColor($h_Label, 0xc0c0c0)
GUICtrlSetColor($h_Label, 0xc2c2c2)

GUISetState(@SW_SHOW)
; ==============================================================
; Begin measurements
$i_we = 0
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = $i_LabelWidth-1 To 0 Step -1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_we < $i_2 Then
                $i_we = $i_2
            EndIf
        EndIf
    Next
Next
$i_ws = $i_LabelWidth
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = 0 To $i_LabelWidth-1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_ws > $i_2 Then
                $i_ws = $i_2
            EndIf
        EndIf
    Next
Next
$i_he = 0
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = $i_LabelWidth-1 To 0 Step -1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_he < $i_1 Then
                $i_he = $i_1
            EndIf
        EndIf
    Next
Next
$i_hs = $i_LabelHeight
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = 0 To $i_LabelWidth-1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_hs > $i_1 Then
                $i_hs = $i_1
            EndIf
        EndIf
    Next
Next
GUIDelete($h_Wx)
; ==============================================================
; Display results
$s_Result = "Font Name : " & $s_FontName & @CR & "Font Size : " & $n_FontSize & @CR & "Font Weight : " & $i_FontWeight & @CR & "Font Attribute : " & $i_FontAttr & @CR & @CR & @CR
$s_Result &="Tested character : " & $s_Char & @CR & @CR
$s_Result &= "Width = " & $i_we-$i_ws+1 & @CR & "Height = " & $i_he-$i_hs+1
MsgBox(0, "Result", $s_Result)
; ==============================================================            
Exit
Link to comment
Share on other sites

How can I retrieve the pixel size of a font at a particular size and attribute? This is mainly useful for monospaced fonts.

And for proportional fonts, how can I retrieve the pixel size of a specified character at a specified size and attribute? I need this to calculate automatically the size of the label (GUICtrlCreateLabel).

You might want to look at this

http://www.autoitscript.com/forum/index.ph...st&p=550588

and/or this http://www.autoitscript.com/forum/index.ph...st&p=608669

earlier in the same thread martin linked to:

Link to comment
Share on other sites

Yes martin, I agree, it's easier to let the label be created automatically. But knowing the size of a character in a certain font with some attributes set, it can help construct the screen page in advance, and not only for labels. Because nobody else replied to my original question, I must think that there is no way at this time.

So, because of this, I was thinking of a way to get a value anyway. The code below is my solution as I have no (or too few) knowledge about Win API stuff, so I wrote a pure AutoIt method.

If you have comments or ideas to make it better, your welcome. I even don't know if the values returned are correct.

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GuiStatusBar.au3>
#include <GuiEdit.au3>
#include <GuiMenu.au3>
#include <GuiToolBar.au3>
#include <GuiComboBoxEx.au3>
#include <Array.au3>
#include <Constants.au3>
#include <WinAPI.au3>
#include <File.au3>
#include <Misc.au3>
#include <GDIPlus.au3>
#include <Color.au3>

Global $h_Wx, $h_Label, $i_LabelWidth, $i_LabelHeight, $i_Color, $s_FontName, $n_FontSize, $i_FontAttr, $i_FontWeight, $n_FontWidth, $n_FontHeight
Global $s_Char, $i_1, $i_2, $i_we, $i_ws, $i_he, $i_hs, $i_P, $s_Result

; ==============================================================
; Select the Font here
$s_FontName = "Courier"
$n_FontSize = 30
$i_FontWeight = 400 ; 400 (=normal) or 800 (=bold)
$i_FontAttr = 1
$s_Char = "W"
; ==============================================================
; For larger font sizes like 200, set the label width and height
; both to 300 for example
; don't forget: the bigger the label, the longer it will take
$i_LabelWidth = 30
$i_LabelHeight = 30
; ==============================================================

$h_Wx = GUICreate("",$i_LabelWidth,$i_LabelHeight,0,0,$WS_POPUP)
GUISetBkColor(0xc1c1c1, $h_Wx)

$h_Label = GUICtrlCreateLabel($s_Char,0,0,$i_LabelWidth,$i_LabelHeight)
GUIctrlSetFont($h_Label, $n_FontSize, $i_FontWeight, $i_FontAttr, $s_FontName)
GUICtrlSetBkColor($h_Label, 0xc0c0c0)
GUICtrlSetColor($h_Label, 0xc2c2c2)

GUISetState(@SW_SHOW)
; ==============================================================
; Begin measurements
$i_we = 0
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = $i_LabelWidth-1 To 0 Step -1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_we < $i_2 Then
                $i_we = $i_2
            EndIf
        EndIf
    Next
Next
$i_ws = $i_LabelWidth
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = 0 To $i_LabelWidth-1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_ws > $i_2 Then
                $i_ws = $i_2
            EndIf
        EndIf
    Next
Next
$i_he = 0
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = $i_LabelWidth-1 To 0 Step -1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_he < $i_1 Then
                $i_he = $i_1
            EndIf
        EndIf
    Next
Next
$i_hs = $i_LabelHeight
For $i_1 = 0 To $i_LabelHeight-1
    For $i_2 = 0 To $i_LabelWidth-1
        $i_P = PixelGetColor($i_2, $i_1)
        If $i_P <> 0xc0c0c0 Then
            If $i_hs > $i_1 Then
                $i_hs = $i_1
            EndIf
        EndIf
    Next
Next
GUIDelete($h_Wx)
; ==============================================================
; Display results
$s_Result = "Font Name : " & $s_FontName & @CR & "Font Size : " & $n_FontSize & @CR & "Font Weight : " & $i_FontWeight & @CR & "Font Attribute : " & $i_FontAttr & @CR & @CR & @CR
$s_Result &="Tested character : " & $s_Char & @CR & @CR
$s_Result &= "Width = " & $i_we-$i_ws+1 & @CR & "Height = " & $i_he-$i_hs+1
MsgBox(0, "Result", $s_Result)
; ==============================================================            
Exit
That's an interesting ideas but a bit long winded. You could use the same idea but differently. For example, make a label which is a reference like this

GuiCtrlCreateLabel("{",$x,$y);a character which uses all availble height afaik.
$RefSize = controlgetpos(....
RefWid = $RefSize[0]

Then use your idea to measure the real height. The width of any text can easily be worked out by creating a label with the text you want with '{' added to the text. Get the width of the label using ControlGetPos, take away the $RefWid and that's the width of your text.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

  • Moderators

Hi,

I too have been trying to determine the correct size of a label to hold a given text for some time. Although the trick of omitting the width and height parameters works if there is no text wrapping, I wanted something that would allow wrapping within a set width and still give a good height measurement - by which I mean not trimming the text and not adding too much wasted space at the bottom.

So far the best I have come with so far is to use _GDIPlus_GraphicsMeasureString, but even this is not perfect, particularly if a line ends very close to the end of the defined width. Furthermore, I discovered that GDI is not very happy with texts containing multiple @CRLF (try seaching in Google and see how many frustrated coders there are out there!), so I went the line-by-line route.

The code draws each line of the text unwrapped to get its length. Dividing by the width requires then gives the number of lines it takes, although this takes no account of the wasted white-space at the end of lines cause by word breaks.

Another method I tried was to find the height of a GDI character for a given font and size and then GDI draw each line of the text within the required width to see how many lines it takes, but my experiments showed this method is only really useful for monospace (fixed width) fonts where it sometimes gives the correct answer when the dividing method does not.

Once the total number of lines has been determined, simply multiply this by the height of a GUICtrlCreateLabel character for the same font and size (and they are not quite the same!) and then you have the label height required.

The following code is not infallible, but it is best I have produced to date:

CODE

#include-once

#Include <GDIPlus.au3>

#EndRegion

; #FUNCTION# =======================================================================================

; Name............: _Label_Size

; Description ....: Returns the size of label required for a given text, even if wrapped to a width

; Syntax..........: _Label_Size($sText, $iFont_Size, $sFont_Name[, $iWidth])

; Parameters .....: $sText -> The text to display with @CRLF line endings

; $iFont_Size -> The font size in points

; $sFont_Name -> The font name

; $iWidth -> The max width of the label - default is width of desktop

; Requirement(s)..: v3.2.12.1 or higher

; Return values ..: Success: Returns an array giving details of the label needed to hold the text

; $array[0] = Number of unwrapped lines in $sText

; $array[1] = Height of 1 line of text

; $array[2] = Width of label required to hold text

; $array[3] = Height of label required to hold text

; Failure: Returns 0

; - Error 1 - Failure to create GUI to test label size

; - Error 2 - GDI measure string failure

; Author .........: Melba23, based on some original GDI code by Malkey

; Example.........; Yes

;===================================================================================================

Func _Label_Size_Test($sText, $iFont_Size, $sFont_Name, $iWidth = @DesktopWidth)

Local $hGUI, $hLabel, $hWin, $hGraphic, $hFamily, $hGDIFont, $hFormat, $tLayout, $iMessage_Depth

Local $nGDI_Line, $iDiv_Count, $iGDI_Count, $iDiv_Depth, $iGDI_Depth

Local $aLines[1], $aPos[4], $aInfo[3]

; Create GUI

$hGUI = GUICreate("", 800, 1000, 800, 10)

If $hGUI = 0 Then Return SetError(1, 0, 0)

GUISetFont($iFont_Size, 400, 0, $sFont_Name)

; Break text into lines

$aLines = StringSplit($sText, @CRLF, 1)

;Now fill with unwrapped lines to check on max width

$hLabel = GUICtrlCreateLabel($sText, 10, 10)

$aPos = ControlGetPos($hGUI, "", $hLabel)

; Store number of lines and line height for this font size

$aPos[0] = $aLines[0]

; Remove label padding (8)

$aPos[1] = ($aPos[3] - 8)/ $aLines[0]

; Now see if wrapping is required

If $aPos[2] > $iWidth Then

; Set width element to max allowed

$aPos[2] = $iWidth

$hWin = WinGetHandle("[ACTIVE]")

_GDIPlus_Startup()

$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWin)

$hFamily = _GDIPlus_FontFamilyCreate($sFont_Name)

$hGDIFont = _GDIPlus_FontCreate($hFamily, $iFont_Size)

$hFormat = _GDIPlus_StringFormatCreate()

; Get GDI line height

$tLayout = _GDIPlus_RectFCreate(0, 0, @DesktopWidth, @DesktopHeight)

$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, "X", $hGDIFont, $tLayout, $hFormat)

; Remove GDI padding (2)

$nGDI_Line = DllStructGetData($aInfo[0], 4) - 2

; Set line counts to zero

$iDiv_Count = 0

$iGDI_Count = 0

; Take each line in turn

For $j = 1 To $aLines[0]

; Replace blank lines to get valid GDI drawing

If StringLen($aLines[$j]) = 0 Then $aLines[$j] = "X"

; GDI width method

; Reset the GDI width to desktop

$tLayout = _GDIPlus_RectFCreate(0, 0, @DesktopWidth, @DesktopHeight)

; Draw the line unwrapped

$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $aLines[$j], $hGDIFont, $tLayout, $hFormat)

If Not IsArray($aInfo) Then

GUIDelete($hGUI)

Return SetError(2, 0, 0)

EndIf

; Divide GDI width by max width

$nDiv_Lines = DllStructGetData($aInfo[0], 3) / $iWidth

; Make adjustment to allow for lines which end right on the edge

If Mod(DllStructGetData($aInfo[0], 3), $iWidth + 8) > .1 Then $nDiv_Lines += 1

$iDiv_Count += Int($nDiv_Lines)

; GDI Depth method - only used to check mono fonts

If $sFont_Name = "Courier New" Or $sFont_Name = "Lucida Console" Then

; Limit the GDI width to max allowed

$tLayout = _GDIPlus_RectFCreate(0, 0, $iWidth, @DesktopHeight)

; Draw the line which wraps if required

$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $aLines[$j], $hGDIFont, $tLayout, $hFormat)

If Not IsArray($aInfo) Then

GUIDelete($hGUI)

Return SetError(2, 0, 0)

EndIf

; Divide GDI depth by line depth

$iGDI_Count += Int(DllStructGetData($aInfo[0], 4) / $nGDI_Line)

EndIf

Next

_GDIPlus_StringFormatDispose($hFormat)

_GDIPlus_FontDispose($hGDIFont)

_GDIPlus_FontFamilyDispose($hFamily)

_GDIPlus_GraphicsDispose($hGraphic)

_GDIPlus_Shutdown()

; Convert lines to pixels

$iDiv_Depth = 8 + Int($iDiv_Count) * $aPos[1]

$aPos[3] = $iDiv_Depth

$iGDI_Depth = 8 + Round($iGDI_Count) * $nGDI_Line

; Adjust if significant difference between methods for mono fonts

If $iGDI_Depth - $iDiv_Depth > $aPos[1] / 2 Then $aPos[3] += $aPos[1] / 2

; Note: $iGDI_Depth is only 8 if not mono font, so no need to check font type

EndIf

; Clean up

GUIDelete($hGUI)

; Return array

Return $aPos

EndFunc ; => _Label_Size

So that is where I am for the moment. The code works pretty well for font sizes up to about 13 and label width of 350 or more. Bigger fonts or smaller widths mean there is too much wasted white-space at the ends of lines when the line breaks at word endings, leading to trimming.

If anyone has any comments or suggestions for what to try next, I would love to hear them. If you have solution that works all the time, even better! :-D

M23

P.S. Why does the code come out without any formatting when you preview the post? It is fine in the editing box!

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Okay, my first idea was very primitive and unusable because the height and width were calculated at character level at their limits, so the "a" will be lower than a "d" and a "i" narrower than a "w". Martin's idea is better, and ResNullius has a very quick way to determine the width of a character or even a string.

I have not yet tested Melba23 idea, but it is worth a deep study :)

I'm writing to you now because I have taken a look at MSDN for the first time. And I was wondering if GetCharWidth32() at http://msdn.microsoft.com/en-us/library/aa911452.aspx is not the solution we all want? The problem is that I don't know if it is possible to use these functions in AutoIt, and if affirmative, how?

Now I'm going to study Melba23 code :) lol

P.S. Why does the code come out without any formatting when you preview the post? It is fine in the editing box!

Instead of using [ code ] and [ /code ], use [ autoit ] and [ /autoit ] (without the spaces) to format your code in the forum.
Link to comment
Share on other sites

Instead of using [ code ] and [ /code ], use [ autoit ] and [ /autoit ] (without the spaces) to format your code in the forum.

Autoit tags are totally unreliable and cause a lot of hassle beause when you try to reply to a post which has used them there is a good, but unpredictable, chance that the text will will converted into gibberish.

They have irritated me so many times that they feature in my signature. Everyone who uses AutoIt tags should have had every hair below their neck pulled out one at a time, slowly. Better make that only on one side so they can still be punished if they do it again.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

I studied Melba23 script... Looks good, I added a working example.

#include <GDIPlus.au3>
#include <Array.au3>

$hGUI = GUICreate("", 800, 800, 800, 10)
GUISetState()
Global $aArray[4], $sX
; single line example ===========================
$sX = "Thank you Melba23 for the your script!"
$aArray = _Label_Size_Test($sX,12,"Times New Roman")
_ArrayDisplay($aArray)
GUISetFont(12,400,1,"Times New Roman")
GUICtrlCreateLabel($sX,10,10,$aArray[2],$aArray[1])
GUICtrlSetBkColor(-1, 0xff0080)
Sleep(2000)
; multi line example ============================
$sX = "Martin says: Do not use [AutoIt] tag in the forum as it seems to be sometimes problematic, use [code] tag instead." & @CRLF & "A pity, really, because the [code] tag does not display the colours..."
$aArray = _Label_Size_Test($sX,10,"Tahoma",200)
_ArrayDisplay($aArray)
GUISetFont(10,400,1,"Tahoma")
GUICtrlCreateLabel($sX,10,110,$aArray[2],$aArray[3])
GUICtrlSetBkColor(-1, 0xff0080)
Sleep(3000)
Exit

; #FUNCTION# =======================================================================================
; Name............: _Label_Size
; Description ....: Returns the size of label required for a given text, even if wrapped to a width
; Syntax..........: _Label_Size($sText, $iFont_Size, $sFont_Name[, $iWidth])
; Parameters .....: $sText -> The text to display with @CRLF line endings
; $iFont_Size -> The font size in points
; $sFont_Name -> The font name
; $iWidth -> The max width of the label - default is width of desktop
; Requirement(s)..: v3.2.12.1 or higher
; Return values ..: Success: Returns an array giving details of the label needed to hold the text
; $array[0] = Number of unwrapped lines in $sText 
; $array[1] = Height of 1 line of text 
; $array[2] = Width of label required to hold text 
; $array[3] = Height of label required to hold text
; Failure: Returns 0 
; - Error 1 - Failure to create GUI to test label size
; - Error 2 - GDI measure string failure
; Author .........: Melba23, based on some original GDI code by Malkey
; Example.........; Yes
;===================================================================================================




Func _Label_Size_Test($sText, $iFont_Size, $sFont_Name, $iWidth = @DesktopWidth)

Local $hGUI, $hLabel, $hWin, $hGraphic, $hFamily, $hGDIFont, $hFormat, $tLayout, $iMessage_Depth
Local $nGDI_Line, $iDiv_Count, $iGDI_Count, $iDiv_Depth, $iGDI_Depth
Local $aLines[1], $aPos[4], $aInfo[3]

; Create GUI
$hGUI = GUICreate("", 800, 1000, 800, 10)
If $hGUI = 0 Then Return SetError(1, 0, 0)
GUISetFont($iFont_Size, 400, 0, $sFont_Name)

; Break text into lines
$aLines = StringSplit($sText, @CRLF, 1)

;Now fill with unwrapped lines to check on max width
$hLabel = GUICtrlCreateLabel($sText, 10, 10)
$aPos = ControlGetPos($hGUI, "", $hLabel)

; Store number of lines and line height for this font size
$aPos[0] = $aLines[0]
; Remove label padding (8)
$aPos[1] = ($aPos[3] - 8)/ $aLines[0]

; Now see if wrapping is required
If $aPos[2] > $iWidth Then

; Set width element to max allowed
$aPos[2] = $iWidth

$hWin = WinGetHandle("[ACTIVE]")
_GDIPlus_Startup()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWin)
$hFamily = _GDIPlus_FontFamilyCreate($sFont_Name)
$hGDIFont = _GDIPlus_FontCreate($hFamily, $iFont_Size)
$hFormat = _GDIPlus_StringFormatCreate()

; Get GDI line height
$tLayout = _GDIPlus_RectFCreate(0, 0, @DesktopWidth, @DesktopHeight)
$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, "X", $hGDIFont, $tLayout, $hFormat)
; Remove GDI padding (2)
$nGDI_Line = DllStructGetData($aInfo[0], 4) - 2

; Set line counts to zero
$iDiv_Count = 0
$iGDI_Count = 0

; Take each line in turn
For $j = 1 To $aLines[0]

; Replace blank lines to get valid GDI drawing
If StringLen($aLines[$j]) = 0 Then $aLines[$j] = "X"

; GDI width method
; Reset the GDI width to desktop
$tLayout = _GDIPlus_RectFCreate(0, 0, @DesktopWidth, @DesktopHeight)
; Draw the line unwrapped
$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $aLines[$j], $hGDIFont, $tLayout, $hFormat)
If Not IsArray($aInfo) Then
GUIDelete($hGUI)
Return SetError(2, 0, 0)
EndIf
; Divide GDI width by max width
$nDiv_Lines = DllStructGetData($aInfo[0], 3) / $iWidth
; Make adjustment to allow for lines which end right on the edge
If Mod(DllStructGetData($aInfo[0], 3), $iWidth + 8) > .1 Then $nDiv_Lines += 1
$iDiv_Count += Int($nDiv_Lines)

; GDI Depth method - only used to check mono fonts
If $sFont_Name = "Courier New" Or $sFont_Name = "Lucida Console" Then

; Limit the GDI width to max allowed
$tLayout = _GDIPlus_RectFCreate(0, 0, $iWidth, @DesktopHeight)
; Draw the line which wraps if required
$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $aLines[$j], $hGDIFont, $tLayout, $hFormat)
If Not IsArray($aInfo) Then
GUIDelete($hGUI)
Return SetError(2, 0, 0)
EndIf
; Divide GDI depth by line depth
$iGDI_Count += Int(DllStructGetData($aInfo[0], 4) / $nGDI_Line)
EndIf

Next

_GDIPlus_StringFormatDispose($hFormat)
_GDIPlus_FontDispose($hGDIFont)
_GDIPlus_FontFamilyDispose($hFamily)
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_Shutdown()

; Convert lines to pixels
$iDiv_Depth = 8 + Int($iDiv_Count) * $aPos[1]
$aPos[3] = $iDiv_Depth
$iGDI_Depth = 8 + Round($iGDI_Count) * $nGDI_Line

; Adjust if significant difference between methods for mono fonts
If $iGDI_Depth - $iDiv_Depth > $aPos[1] / 2 Then $aPos[3] += $aPos[1] / 2
; Note: $iGDI_Depth is only 8 if not mono font, so no need to check font type

EndIf

; Clean up
GUIDelete($hGUI)

; Return array
Return $aPos

EndFunc; => _Label_Size
Edited by charvi
Link to comment
Share on other sites

  • Moderators

Charvi,

I have a fully working script for label sizing in the Example Scripts area here.

Hope it does what you want.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...