Jump to content

Recommended Posts

Posted

Thinking of this from a UDF perspective (GUIDarkTheme), I don't have access to the GUI font size if the user has something different set with GUISetFont. My goal is to obtain the font size for the GUI (eg. 8.5, 10, 12, etc.) which can then automatically set the font size for the menubar (in GUIDarkMenu UDF) so that the font size matches.

I do have access to the GUI handle since that is passed on to GUIDarkTheme. So we do have a GUI handle to work with. I could technically get the user to pass on the font size as well, but my goal is to keep everything as simple and automatic as possible for whoever uses the UDF.

I did spend some time searching the forum and did not find much, unfortunately. It's understandable because we would typically know the font size. But from the perspective of a UDF, I don't have that. I did find something interesting from @Yashied in this post.

#Include <Array.au3>
#Include <FontConstants.au3>
#Include <WinAPI.au3>
#Include <WindowsConstants.au3>

$hGUI = GUICreate('MyGUI', 300, 200)
GUISetFont(12)
$Label = GUICtrlCreateLabel('Simple Text', 20, 40, 100, 22)
;GUICtrlSetFont(-1, 12, 700, 2 + 4, 'Tahoma')
GUISetState(@SW_SHOW)

;$aFont = GUIGetFont($hGUI)
$aFont = GUICtrlGetFont($Label)

_ArrayDisplay($aFont)

Do
Until GUIGetMsg() = -3

#cs

[0] - Size
[1] - Weight
[2] - Attribute
[3] - Name
[4] - Quality

#ce

Func GUIGetFont($hWnd)
    Local $Ret, $hDC, $hFont, $tFont
    Local $aFont = 0
    $hDC = _WinAPI_GetDC($hWnd)
    $hFont = _SendMessage($hWnd, $WM_GETFONT)
    $tFont = DllStructCreate($tagLOGFONT)
    $Ret = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFont, 'int', DllStructGetSize($tFont), 'ptr', DllStructGetPtr($tFont))
    If (Not @error) And ($Ret[0]) Then
        ConsoleWrite("past error" & @CRLF)
        Dim $aFont[5] = [0]
        $aFont[0] = -Round(DllStructGetData($tFont, 'Height') / _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) * 72, 1)
        $aFont[1] = DllStructGetData($tFont, 'Weight')
        $aFont[2] = BitOR(2 * (DllStructGetData($tFont, 'Italic') <> 0), 4 * (DllStructGetData($tFont, 'Underline') <> 0), 8 * (DllStructGetData($tFont, 'Strikeout') <> 0))
        $aFont[3] = DllStructGetData($tFont, 'FaceName')
        $aFont[4] = DllStructGetData($tFont, 'Quality')
    EndIf
    _WinAPI_ReleaseDC($hWnd, $hDC)
    Return $aFont
EndFunc   ;==>GUIGetFont

Func GUICtrlGetFont($CtrlID)

    Local $hWnd = GUICtrlGetHandle($CtrlID)

    If Not $hWnd Then
        Return 0
    EndIf

    Local $Ret, $hDC, $hFont, $tFont
    Local $aFont = 0

    $hDC = _WinAPI_GetDC($hWnd)
    $hFont = _SendMessage($hWnd, $WM_GETFONT)
    $tFont = DllStructCreate($tagLOGFONT)
    $Ret = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFont, 'int', DllStructGetSize($tFont), 'ptr', DllStructGetPtr($tFont))
    If (Not @error) And ($Ret[0]) Then
        Dim $aFont[5] = [0]
        $aFont[0] = -Round(DllStructGetData($tFont, 'Height') / _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) * 72, 1)
        $aFont[1] = DllStructGetData($tFont, 'Weight')
        $aFont[2] = BitOR(2 * (DllStructGetData($tFont, 'Italic') <> 0), 4 * (DllStructGetData($tFont, 'Underline') <> 0), 8 * (DllStructGetData($tFont, 'Strikeout') <> 0))
        $aFont[3] = DllStructGetData($tFont, 'FaceName')
        $aFont[4] = DllStructGetData($tFont, 'Quality')
    EndIf
    _WinAPI_ReleaseDC($hWnd, $hDC)
    Return $aFont
EndFunc   ;==>GUICtrlGetFont

 

The only problem is that it only works with controls. It works very well though. I tried my best to modify his function so I could send the GUI handle (since I do have that) in hopes to get the font details, but it fails. My added function is GUIGetFont($hWnd).

Does anyone know of a way to get the GUI font size in this scenario?

Thank you for your time. :)

Posted

Adding:

$hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0)
If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT)
Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)

Gives me something but of course, that is just giving the default font size in the end.

Posted

Try this :

; From Nine
#include <GUIConstants.au3>
#include <SendMessage.au3>
#include <WinAPI.au3>
#include <Array.au3>

Opt("MustDeclareVars", True)

Example()

Func Example()
  Local $hGUI = GUICreate("Example")
  Local $idEdit = GUICtrlCreateEdit("Test", 10, 10, 200, 20)
  GUICtrlSetFont(-1, 10, 0, 0, "Consolas")
  GUISetState()

  _ArrayDisplay(GUICtrlGetFont($idEdit))

  While True
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd
EndFunc   ;==>Example

Func GUICtrlGetFont($hWnd)
  If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
  Local $aFont[5], $hDC = _WinAPI_GetDC($hWnd)
  Local $hFont = _SendMessage($hWnd, $WM_GETFONT), $tFont = DllStructCreate($tagLOGFONT)

  _WinAPI_GetObject($hFont, DllStructGetSize($tFont), $tFont)

  $aFont[0] = Abs(Round($tFont.Height / _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) * 72, 1))
  $aFont[1] = $tFont.Weight
  $aFont[2] = BitOR(2 * ($tFont.Italic <> 0), 4 * ($tFont.Underline <> 0), 8 * ($tFont.Strikeout) <> 0)
  $aFont[3] = $tFont.FaceName
  $aFont[4] = $tFont.Quality

  _WinAPI_ReleaseDC($hWnd, $hDC)
  Return $aFont
EndFunc   ;==>_GetFont

 

Posted
7 minutes ago, Nine said:

Try this :

Thanks. It does work well but it is not getting the font size for the GUI itself. For example, if you add GUISetFont(14) before the edit control is created and changing to _ArrayDisplay(GUICtrlGetFont($hGUI)) it fails to get the GUI font.

I've ran into this issue before as well but never bothered to look too deep into it.

  • Solution
Posted

It does says GUICtrlGetFont ;)

; From Nine
#include <GUIConstants.au3>
#include <SendMessage.au3>
#include <WinAPI.au3>
#include <Array.au3>

Opt("MustDeclareVars", True)

Example()

Func Example()
  Local $hGUI = GUICreate("Example")
  GUISetFont(14)
  Local $idEdit = GUICtrlCreateEdit("Test", 10, 10, 200, 20)
  GUICtrlSetFont(-1, 10, 0, 0, "Consolas")
  GUISetState()

  _ArrayDisplay(GUICtrlGetFont($idEdit))
  ConsoleWrite(GUIGetFontSize($hGUI) & @CRLF)

  While True
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd
EndFunc   ;==>Example

Func GUICtrlGetFont($hWnd)
  If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
  Local $aFont[5], $hDC = _WinAPI_GetDC($hWnd)
  Local $hFont = _SendMessage($hWnd, $WM_GETFONT), $tFont = DllStructCreate($tagLOGFONT)

  _WinAPI_GetObject($hFont, DllStructGetSize($tFont), $tFont)

  $aFont[0] = Abs(Round($tFont.Height / _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) * 72, 1))
  $aFont[1] = $tFont.Weight
  $aFont[2] = BitOR(2 * ($tFont.Italic <> 0), 4 * ($tFont.Underline <> 0), 8 * ($tFont.Strikeout) <> 0)
  $aFont[3] = $tFont.FaceName
  $aFont[4] = $tFont.Quality

  _WinAPI_ReleaseDC($hWnd, $hDC)
  Return $aFont
EndFunc   ;==>GUICtrlGetFont

Func GUIGetFontSize($hWnd)
  Local $idTest = GUICtrlCreateLabel("Test", -100, -100, 150, 30)
  Local $aTest = GUICtrlGetFont($idTest)
  GUICtrlDelete($idTest)
  Return $aTest[0]
EndFunc   ;==>GUIGetFontSize

 

Posted
2 minutes ago, Nine said:

It does says GUICtrlGetFont ;)

Indeed, of course. :)

Your new method of creating a hidden label that would technically pull in the GUI font size and then getting the size from that label is a brilliant and creative idea. That works really well. Nice technique.

It looks like you are rounding the returned value to the nearest .5 which is also smart. That was going to be my next question. :)

Thank you for this. I haven't tried it within the UDF yet, but from the perspective of the UDF this should work.

Posted
11 minutes ago, WildByDesign said:

It looks like you are rounding the returned value to the nearest .5 which is also smart. That was going to be my next question. :)

Actually, maybe I was wrong on this. It doesn't appear to be rounding to the nearest .5 value. The reason why I noticed that is because the value is slightly different depending on the DPI scaling set. The return value is different whether DPI is set or not, and also when changing the DPI scaling level. That makes sense, of course. It is adapting to those changes which is a really good thing from a measurement perspective.

With that being said, could you please help with rounding to the nearest .5?

It can be a separate function or built into the main function, either way. Thank you so much. :)

Posted (edited)
9 minutes ago, MattyD said:

Just a small nitpick..

Small but mighty! That fixed the return values on the different DPI levels perfectly. Thank you! :)
 

EDIT: Also negates the need for any rounding.

Edited by WildByDesign
Posted (edited)
-(($tFont.Height * 72)/_WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY))

I think this is as good as we're getting.  The system rounds going the other way so there's a limit.

It  gives a bit more granularity as $tFont.Height changes, which is a signed int. The amount it changes might change depending on the DC/font.

Edited by MattyD
Posted

You guys are fantastic. This community wins… always.

I can confirm that this method does work wonderfully in the UDF and does set the menubar text at the font size matching the GUI as set by the user.

Thank you both for your time on this. Have a great weekend.

Posted

I've updated the script by adding the font handle ($hFont) to the array because we can use that for the menubar text measurement as well.

@UEZ This technique that Nine has come up with should be beneficial for you as well because I use your menubar subclassing code. From your code:

Local $hDC = _WinAPI_GetDC($hWnd)
Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0)
If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT)

That is used in your WM_MEASUREITEM and WM_DRAWITEM and possibly elsewhere. The initial Local $hFont fails 100% of the time. Therefore it always falls back to the stock GUI font. With the technique from Nine, you get the font handle (and other details) and also the DPI precision thanks to Matty.

Anyway, here is my updated script which returns the font handle in the array as well.

DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

; From Nine
#include <GUIConstants.au3>
#include <SendMessage.au3>
#include <WinAPI.au3>
#include <Array.au3>

Opt("MustDeclareVars", True)

Example()

Func Example()
    Local $hGUI = GUICreate("Example")
    GUISetFont(12)
    Local $idEdit = GUICtrlCreateEdit("Test", 10, 10, 200, 20)
    GUICtrlSetFont(-1, 10, 0, 0, "Consolas")

    Local $aFont = GUIGetFontSize($hGUI)
    ConsoleWrite("Font Size: " & @TAB & @TAB & @TAB & $aFont[0] & @CRLF)
    ConsoleWrite("Font Weight: " & @TAB & @TAB & $aFont[1] & @CRLF)
    ConsoleWrite("Font Attributes: " & @TAB & $aFont[2] & @CRLF)
    ConsoleWrite("Font Name: " & @TAB & @TAB & @TAB & $aFont[3] & @CRLF)
    ConsoleWrite("Font Quality: " & @TAB & @TAB & $aFont[4] & @CRLF)
    ConsoleWrite("Font Handle: " & @TAB & @TAB & $aFont[5] & @CRLF)

    GUISetState()

    While True
        Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func GUICtrlGetFont($hWnd)
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local $aFont[6], $hDC = _WinAPI_GetDC($hWnd)
    Local $hFont = _SendMessage($hWnd, $WM_GETFONT), $tFont = DllStructCreate($tagLOGFONT)

    _WinAPI_GetObject($hFont, DllStructGetSize($tFont), $tFont)

    $aFont[0] = Round(-(($tFont.Height * 72)/_WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)) / 0.5) * 0.5
    $aFont[1] = $tFont.Weight
    $aFont[2] = BitOR(2 * ($tFont.Italic <> 0), 4 * ($tFont.Underline <> 0), 8 * ($tFont.Strikeout) <> 0)
    $aFont[3] = $tFont.FaceName
    $aFont[4] = $tFont.Quality
    $aFont[5] = $hFont

    _WinAPI_ReleaseDC($hWnd, $hDC)
    Return $aFont
EndFunc   ;==>GUICtrlGetFont

Func GUIGetFontSize($hWnd)
    Local $idTest = GUICtrlCreateLabel("Test", -100, -100, 150, 30)
    Local $aFont = GUICtrlGetFont($idTest)
    GUICtrlDelete($idTest)
    ;Return Round($aTest[0] / 0.5) * 0.5
    Return $aFont
EndFunc   ;==>GUIGetFontSize

 

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
×
×
  • Create New...