Sign in to follow this  
Followers 0
ppat

Autosize label ?

12 posts in this topic

Is there a way to create a label that autosizes ?

And then to adjust its size so that all the text can be seen?

Here is my code:

GuiCreate("Countdown", 100, 50)
WinMove("Countdown", "", 0,0)
$mylabel = GUICtrlCreateLabel ( "This is a very long text, very very very long, extremely long.", 9, 20,  89, 20 )
GUISetState(@SW_SHOW) 
msgbox(0,"Close this", "Look at the window at the upper left part of your screen. " & Chr(13) & Chr(13) & "Close this to exit the program")

If you run this and look at the window at the upper left part of your screen, you can see that the label is auto-wrapped (see screenshot below). So the height is bigger than expected, and part of the second line and the 3rd, 4th lines are hidden. I would like the label to autosize. Then I would measure the size of the label and increase the height of the GUI accordingly so as to be able to see the whole label.

Posted Image

I know that this is something very standard in VB or VBA, how can it be done in Autoscript? Ideally, I'd prefer to avoid using Windows APIs, but if this is the only solution, then it's OK.

Share this post


Link to post
Share on other sites



#include <GUIConstantsEx.au3>

Dim $str = "Expanding Label", $fntSize = 14

$GUI = GUICreate("Expanding Label", 229, 160)
$lblText = GUICtrlCreateLabel($str, 40, 56, StringLen($str) * $fntSize)
GUICtrlSetFont(-1, $fntSize)
GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
WEnd

I think :hmm:

Share this post


Link to post
Share on other sites

Search on forum about _StringSize() by Melba I think.


When the words fail... music speaks

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

ppat,

The attached is a UDF I wrote to do just what you want.

The returned array includes a formatted string and the size of the label to hold it. You can set the font using the same parameters as GUISetFont. The width for the label can be specified - if you do not set a width, the UDF returns the unwrapped width of the string:

#include-once

#include <WindowsConstants.au3>
#include <SendMessage.au3>
#include <WinAPI.au3>

; #FUNCTION# =======================================================================================
;
; Name...........: _StringSize
; Description ...: Returns size of rectangle required to display string - width can be chosen
; Syntax ........: _StringSize($sText[, $iSize[, $iWeight[, $iAttrib[, $sName[, $iWidth]]]]])
; Parameters ....: $sText   - String to display
;                 $iSize   - Font size in points - default AutoIt GUI default
;                 $iWeight - Font weight (400 = normal) - default AutoIt GUI default
;                 $iAttrib - Font attribute (0-Normal, 2-Italic, 4-Underline, 8 Strike - default AutoIt
;                 $sName   - 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 - Failure of _WinAPI_SelectObject
;                 |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 $hWnd, $hFont, $hDC, $oFont, $tSize, $hGUI, $hText_Label, $sTest_Line
    Local $iLine_Count, $iLine_Width, $iWrap_Count, $iLast_Word
    Local $asLines[1], $avSize_Info[4], $aiPos[4]
    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)
    $hGUI = GUICreate("", 1200, 500, 10, 10)
    If $hGUI = 0 Then Return SetError(2, 0, 0)
    GUISetFont($iSize, $iWeight, $iAttrib, $sName)
    $avSize_Info[0] = $sText
    If StringInStr($sText, @CRLF) = 0 Then StringRegExpReplace($sText, "[x0a|x0d]", @CRLF)
    $asLines = StringSplit($sText, @CRLF, 1)
    $hText_Label = GUICtrlCreateLabel($sText, 10, 10)
    $aiPos = ControlGetPos($hGUI, "", $hText_Label)
    GUICtrlDelete($hText_Label)
    $avSize_Info[1] = ($aiPos[3] - 8) / $asLines[0]
    $avSize_Info[2] = $aiPos[2]
    $avSize_Info[3] = $aiPos[3] - 4
    If $aiPos[2] > $iWidth And $iWidth > 0 Then
        $avSize_Info[0] = ""
        $avSize_Info[2] = $iWidth
        $iLine_Count = 0
        For $j = 1 To $asLines[0]
            $hText_Label = GUICtrlCreateLabel($asLines[$j], 10, 10)
            $aiPos = ControlGetPos($hGUI, "", $hText_Label)
            GUICtrlDelete($hText_Label)
            If $aiPos[2] < $iWidth Then
                $iLine_Count += 1
                $avSize_Info[0] &= $asLines[$j] & @CRLF
            Else
                $hText_Label = GUICtrlCreateLabel("", 0, 0)
                $hWnd = ControlGetHandle($hGUI, "", $hText_Label)
                $hFont = _SendMessage($hWnd, $WM_GETFONT)
                $hDC = _WinAPI_GetDC($hWnd)
                $oFont = _WinAPI_SelectObject($hDC, $hFont)
                If $oFont = 0 Then Return SetError(3, 0, 0)
                $iWrap_Count = 0
                While 1
                    $iLine_Width = 0
                    $iLast_Word = 0
                    For $i = 1 To StringLen($asLines[$j])
                        If StringMid($asLines[$j], $i, 1) = " " Then $iLast_Word = $i - 1
                        $sTest_Line = StringMid($asLines[$j], 1, $i)
                        GUICtrlSetData($hText_Label, $sTest_Line)
                        $tSize = _WinAPI_GetTextExtentPoint32($hDC, $sTest_Line)
                        $iLine_Width = DllStructGetData($tSize, "X")
                        If $iLine_Width >= $iWidth - Int($iSize / 2) Then ExitLoop
                    Next
                    If $i > StringLen($asLines[$j]) Then
                        $iWrap_Count += 1
                        $avSize_Info[0] &= $sTest_Line & @CRLF
                        ExitLoop
                    Else
                        $iWrap_Count += 1
                        If $iLast_Word = 0 Then
                            GUIDelete($hGUI)
                            Return SetError(4, 0, 0)
                        EndIf
                        $avSize_Info[0] &= StringLeft($sTest_Line, $iLast_Word) & @CRLF
                        $asLines[$j] = StringTrimLeft($asLines[$j], $iLast_Word)
                        $asLines[$j] = StringStripWS($asLines[$j], 1)
                    EndIf
                WEnd
                $iLine_Count += $iWrap_Count
                _WinAPI_ReleaseDC($hWnd, $hDC)
                GUICtrlDelete($hText_Label)
            EndIf
        Next
        $avSize_Info[3] = ($iLine_Count * $avSize_Info[1]) + 4
    EndIf
    GUIDelete($hGUI)
    Return $avSize_Info
EndFunc ;==>_StringSize
Edited by Melba23

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______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

 

Share this post


Link to post
Share on other sites

He asked for no WinAPI :unsure:

Ideally :P

When the words fail... music speaks

Share this post


Link to post
Share on other sites

ppat,

The only other alternative method I ever developed which was anywhere near as successful measured the width of each character in the specified font and then used that to sum the line length instead of the WinAPI call. It did work pretty well, but was not very elegant. ;-(

I could try and find it (or rewrite it) but why do you not want to use the API call? They are there precisely to do things which AutoIt finds difficult to do in native code.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______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

 

Share this post


Link to post
Share on other sites

$hGUI = GuiCreate("Countdown", 50, 50)
WinMove("Countdown", "", 0,0)
$mylabel = GUICtrlCreateLabel ( "This is a very long text, very very very long, extremely long.", 9, 20)
$LabelPos = WinGetPos(GUICtrlGetHandle($mylabel))
$GUIPos = WinGetPos($hGUI)
WinMove($hGUI, '', 0, 0, $GUIPos[2]+$LabelPos[0]+$LabelPos[2], $GUIPos[3]+$LabelPos[1]+$LabelPos[3])

GUISetState(@SW_SHOW)
msgbox(0,"Close this", "Look at the window at the upper left part of your screen. " & @LF & @LF  & "Close this to exit the program")

?

Share this post


Link to post
Share on other sites

Authenticity,

But if you do not have a pre-formatted string and you want to wrap it to a certain size (to fit into a GUI for example), you need to calculate the line length at some point so you know when to wrap. That is what the _WinAPI_GetTextExtentPoint32 call (or the count of character width in the earlier version) does for you.

The "Create a label without size parameters" method is fine as far as it goes, but will only produce a label to fit the string as formatted - not adjust the string formatting to fit a given size.

If you try displaying ever increasing strings in a MsgBox, you will see that Windows uses the same trick. The MsgBox will increase to a certain width and then the string wraps to maintain that width:

$sString = "A pretty longish line to display in a message Box"

For $i = 1 To 5
    $sDisplay = ""
    For $j = 1 To $i
        $sDisplay &= $sString
    Next
    ConsoleWrite("Here" & @CRLF)
    MsgBox(0, $i, $sDisplay)
Next

Exit

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______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

 

Share this post


Link to post
Share on other sites

Thanks for this exchange between experts. To be more specific about my need, I should be adding that:

- I do not need to set a specific font to the text. Default font is fine with me

- I would like to *ideally* find a solution without windows API because simpler is better

Authenticity: passing no width / height argument to GUICtrlCreateLabel()does in effect autosize the label. The problem is that for very looooong text, the width will increase too much. I tried to pass only a fixed width argument hoping that the height would autosize, but this is not what happens. The help file says "default is the previously used height".

Besides, I am a bit sceptical about using WinGetPos() to get the position of the label control, wherease WinGetPos() retieves the position of a window. I looked for a function called GUICtrlGetPos() but this function does not exist. When I try your code with a longer text, the label is cut and goes beyond the GUI. This is probably the limit of WinGetPos(GUICtrlGetHandle($mylabel)) .

$hGUI = GuiCreate("Countdown", 50, 50)
WinMove("Countdown", "", 0,0)
$mylabel = GUICtrlCreateLabel ( "This is a very long text, very very very long, extremely long. Event longer than you think.", 9, 20)
$LabelPos = WinGetPos(GUICtrlGetHandle($mylabel))
$GUIPos = WinGetPos($hGUI)
WinMove($hGUI, '', 0, 0, $GUIPos[2]+$LabelPos[0]+$LabelPos[2], $GUIPos[3]+$LabelPos[1]+$LabelPos[3])

GUISetState(@SW_SHOW)
msgbox(0,"Close this", "Look at the window at the upper left part of your screen. " & @LF & @LF  & "Close this to exit the program")

I will later try the UDF proposed by Melba23.

Share this post


Link to post
Share on other sites

ppat,

If you do not want to change the font, just set the font parameters when you call the UDF to Default. The Width parameter should be set to the width you want for your label. Here is a short example which uses the UDF as an include. It shows the difference between setting a width (for the label) and not (for the button):

#include <GUIConstantsEx.au3>
#include <StringSize.au3>

$iGUI_Width = 220
$sBut_Txt = "Press to Exit"
$sLabel_Txt  = "This line is long enough to need wrapping if it is to fit within the required GUI width."

$aiBut_Ret = _StringSize($sBut_Txt)
$avLabel_Ret = _StringSize($sLabel_Txt, Default, Default, Default, Default, $iGUI_Width - 20)
$iError = @error
            
If IsArray($avLabel_Ret) Then
    GUICreate("String Sizing", $iGUI_Width, $avLabel_Ret[3] + 65)
    $hLabel = GUICtrlCreateLabel($avLabel_Ret[0], ($iGUI_Width - $avLabel_Ret[2]) / 2, 15, $avLabel_Ret[2], $avLabel_Ret[3], 1)
        GUICtrlSetBkColor(-1, 0xBBFF88); Just to show label size
    $hExit = GUICtrlCreateButton($sBut_Txt, ($iGUI_Width - ($aiBut_Ret[2] + 20)) / 2, $avLabel_Ret[3] + 25, $aiBut_Ret[2] + 20, 30)
    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE, $hExit
                Exit
        EndSwitch   
    WEnd
Else
    MsgBox(0, "Error", "Code = " & $iError)
EndIf

Exit

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______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

 

Share this post


Link to post
Share on other sites

Perfect :P exactly what I need. Thank-you Melba23 for providing the code

Share this post


Link to post
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
Sign in to follow this  
Followers 0