Page 1 of 1

How to get the current Gui font w/o creating a control?

Posted: 06 Oct 2013, 04:22
by just me
If you want to create owner-drawn controls, you have to process the WM_MEASUREITEM message and set the item height.
MSDN wrote:The system sends the WM_MEASUREITEM message to the owner window of combo boxes and list boxes created with the OWNERDRAWFIXED style before sending the WM_INITDIALOG message. As a result, when the owner receives this message, the system has not yet determined the height and width of the font used in the control; function calls and calculations requiring these values should occur in the main function of the application or library.
Does anybody know a way to get the current Gui control font without creating a control, as this might interfere with relative control positioning? (I've been asking this in 2009 already, but without success).

Re: How to get the current Gui font w/o creating a control?

Posted: 06 Oct 2013, 04:54
by SKAN

Code: Select all

#NoEnv  
#SingleInstance, Force

GuiDefaultFont() {        ; By SKAN www.autohotkey.com/forum/viewtopic.php?p=465438#465438
 hFont := DllCall( "GetStockObject", UInt,17 ) ; DEFAULT_GUI_FONT
 VarSetCapacity( LF, szLF := 60 * ( A_IsUnicode ? 2 : 1 ) )
 DllCall( "GetObject", UInt,hFont, Int,szLF, UInt,&LF )
 hDC := DllCall( "GetDC", UInt,hwnd ),
 DPI := DllCall( "GetDeviceCaps", UInt,hDC, Int,90 )
 DllCall( "ReleaseDC", Int,0, UInt,hDC ), 
 S := Round( ( -NumGet( LF,0,"Int" )*72 ) / DPI )
Return DllCall( "MulDiv",Int,&LF+28, Int,1,Int,1, Str )
     , DllCall( "SetLastError", UInt,S )
}

A_GuiFont     := GuiDefaultFont()
A_GuiFontSize := A_LastError

MsgBox, %A_GuiFont%`t%A_GuiFontSize%
:)

Re: How to get the current Gui font w/o creating a control?

Posted: 06 Oct 2013, 06:00
by just me
THX SKAN, but it seems I have to be more clear:

I want to retrieve the current Gui control font as set with Gui, Font, ..., ....

BTW: Would someone please increase the font size of inline code?

Re: How to get the current Gui font w/o creating a control?

Posted: 06 Oct 2013, 10:31
by SKAN
just me wrote:retrieve the current Gui control font as set with Gui, Font, ..., ....
That is not easy, I guess. Here is an idea:

Fetch a list of all controls in GUI and reverse it so that latest created control is on top.
Find the font used for each control and if none is found use default Gui font.

Code: Select all

#NoEnv  
SetWorkingDir %A_ScriptDir%  
#SingleInstance, Force
#Persistent

Gui, Font, S10, Arial
Gui, Add, Text,, Line1
Gui, Font, S9, Tahoma
Gui, Add, Text,, Line2
Gui, Font, S8, Courier New
Gui, Add, Text,, Line3
Gui, Font, S7, Times New Roman
Gui, Add, Picture, wp hp, C:\NonExistentFile
Gui, Font, S6, NonExistentFont
Gui, Add, Text,, Line4

Gui, Show, w100 

Gui +LastFound
hWnd := WinExist()

WinGet, CHL, ControlListHwnd, ahk_id %hWnd% ; List of all Controls in GUI
Loop, Parse, CHL, `n                        ; Reverse the order of Controls so that
 CH := A_LoopField "`n" CH                  ; the lastest created control is on top    
StringTrimRight, CH, CH, 1


Loop, Parse, CH, `n
 {
  hFont := DllCall( "SendMessage", UInt,A_LoopField, UInt,0x31, UInt,0, UInt,0, UInt )
  If ( hFont )
     MsgBox % GetFontname( hFont ) "`t" A_LastError
 }
Return


GetFontname( hFont ) {
 VarSetCapacity( LF, szLF := 60*( A_IsUnicode ? 2:1 ) )
 DllCall( "GetObject", UInt,hFont, Int,szLF, UInt,&LF )
 hDC := DllCall( "GetDC", UInt,hwnd ), 
 DPI := DllCall( "GetDeviceCaps", UInt,hDC, Int,90 )
 DllCall( "ReleaseDC", Int,0, UInt,hDC ), 
 S := Round( ( -NumGet( LF,0,"Int" )*72 ) / DPI )
Return DllCall( "MulDiv",Int,&LF+28, Int,1,Int,1, Str )
     , DllCall( "SetLastError", UInt,S )
}

Re: How to get the current Gui font w/o creating a control?

Posted: 06 Oct 2013, 10:44
by SKAN
Ahh! This method would not work if Gui,Font was called but no control was created! :(

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Oct 2013, 09:11
by jballi
just me wrote:I want to retrieve the current Gui control font as set with Gui, Font, ..., ....
This information is not available. As SKAN showed, the font information can be derived if a control was created after the font was set and you know which control it was. Otherwise, there is no way to know.

This sounds like something to add to the Wish List forum. I'm thinking a request for a A_LastFont system variable that would return 0 if no fonts have been created, otherwise the handle to the last logical font that was created or referred to via the gui Font command would be returned.

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Oct 2013, 09:47
by HotKeyIt
just me wrote:BTW: Would someone please increase the font size of inline code?
How about that?

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Oct 2013, 10:01
by just me
Much better! ;)

Re: How to get the current Gui font w/o creating a control?

Posted: 13 Jan 2020, 23:19
by DRocks
BUMP,

@just me
Did any one find how to solve OP question?
(How to get a GuiControl current font)

Reason: make it easy to toggle from one font to another for each controls in a Gui.
Example :

Code: Select all

;--------------------------------------------------------------------------------
toggle_row_highlight(boolean) {
;--------------------------------------------------------------------------------
	Global hGuiMain, column_names
	
	row := get_row_under_mouse()
	
	;prev_font := ???
	Gui, font, % (boolean ? " Bold":prev_font)
	For column, variable_name in column_names {
		GuiControl, %hGuiMain%:Font, % variable_name . row
	}
}

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 01:25
by teadrinker
Like this?

Code: Select all

Gui, New, +hwndhGui

Gui, Font,, Verdana
MsgBox, % GetFont(hGui)

Gui, Font,, Calibri
MsgBox, % GetFont(hGui)
ExitApp

GetFont(hWnd) {
   static WM_GETFONT := 0x31
   hFont := DllCall("SendMessage", "Ptr", hWnd, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
   if !hFont {
      Gui, %hWnd%: Add, Text, xp yp wp hp Hidden hwndhText
      hFont := DllCall("SendMessage", "Ptr", hText, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
   }
   size := DllCall("GetObject", "Ptr", hFont, "Int", 0, "Ptr", 0)
   VarSetCapacity(LOGFONT, size, 0)
   DllCall("GetObject", "Ptr", hFont, "Int", size, "Ptr", &LOGFONT)
   fontName := StrGet(&LOGFONT + 28)
   ( hText && DllCall("DestroyWindow", "Ptr", hText) )
   Return fontName
}

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 01:36
by guest3456
teadrinker wrote:
14 Jan 2020, 01:25
Like this?
can you DestroyWindow inside the same if-block after doing WM_GETFONT? or does that destroy the font object too?

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 01:42
by teadrinker
You are right, it could be done like this:

Code: Select all

GetFont(hWnd) {
   static WM_GETFONT := 0x31
   hFont := DllCall("SendMessage", "Ptr", hWnd, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
   if !hFont {
      Gui, %hWnd%: Add, Text, xp yp wp hp Hidden hwndhText
      hFont := DllCall("SendMessage", "Ptr", hText, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
      DllCall("DestroyWindow", "Ptr", hText)
   }
   size := DllCall("GetObject", "Ptr", hFont, "Int", 0, "Ptr", 0)
   VarSetCapacity(LOGFONT, size, 0)
   DllCall("GetObject", "Ptr", hFont, "Int", size, "Ptr", &LOGFONT)
   Return StrGet(&LOGFONT + 28)
}

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 17:29
by DRocks
@teadrinker thanks,
Would this be meant to work with the hwnd of a GuiControl or is it restricted for a top level window?

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 17:50
by teadrinker
Should work for controls too:

Code: Select all

Gui, Font, s24, Comic Sans MS
Gui, Add, Edit, hwndhEdit, Hello
MsgBox, % GetFont(hEdit)
Gui, Show

GetFont(hWnd) {
   static WM_GETFONT := 0x31
   hFont := DllCall("SendMessage", "Ptr", hWnd, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
   if !hFont {
      Gui, %hWnd%: Add, Text, xp yp wp hp Hidden hwndhText
      hFont := DllCall("SendMessage", "Ptr", hText, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
      DllCall("DestroyWindow", "Ptr", hText)
   }
   size := DllCall("GetObject", "Ptr", hFont, "Int", 0, "Ptr", 0)
   VarSetCapacity(LOGFONT, size, 0)
   DllCall("GetObject", "Ptr", hFont, "Int", size, "Ptr", &LOGFONT)
   Return StrGet(&LOGFONT + 28)
}

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 19:14
by DRocks
teadrinker wrote:
14 Jan 2020, 17:50
Should work for controls too:
Hey, thanks! I've tested it and read the content of the function.
It does work for what the function is called "GetFont()"
But I'm afraid I am refering to a more complex "kind of font".
I mean like everything that this GuiControl has relating to its display properties like size, quality, weight, font, etc.
The thing is that it gets messy real quick if you can't store automatically what the GuiControl's display / font properties are.

For now I am trying to store properties manually like so:

Code: Select all

static normal_header_font := "s12 q5 w400"
	, bold_header_font := "s12 q5 w700"
Then I try to toggle from the special font to the original one

Re: How to get the current Gui font w/o creating a control?

Posted: 14 Jan 2020, 20:28
by teadrinker
No problem. :)

Code: Select all

Gui, New, +hwndhGui
Gui, Font, s12 italic bold q4, Comic Sans MS

res := GetFont(hGui), sResult := ""
for k, v in res
   sResult .= (A_Index = 1 ? "" : "`n") . k . ": " . v
Gui, Add, Text,, % sResult

Gui, Font, s14 norm underline q5, Calibri

Gui, Add, Edit, hwndhEdit xp y+10 wp hp r7
res := GetFont(hEdit), sResult := ""
for k, v in res
   sResult .= (A_Index = 1 ? "" : "`n") . k . ": " . v
GuiControl,, Edit1, % sResult

GuiControl, Focus, Static1
Gui, Show
Return

GuiClose:
   ExitApp

GetFont(hWnd) {
   static WM_GETFONT := 0x31
                              
   hFont := DllCall("SendMessage", "Ptr", hWnd, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
   if !hFont {
      Gui, %hWnd%: Add, Text, xp yp wp hp Hidden hwndhText
      hFont := DllCall("SendMessage", "Ptr", hText, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
      DllCall("DestroyWindow", "Ptr", hText)
   }
   sizeLF := DllCall("GetObject", "Ptr", hFont, "Int", 0, "Ptr", 0)
   VarSetCapacity(LOGFONT, sizeLF, 0)
   DllCall("GetObject", "Ptr", hFont, "Int", sizeLF, "Ptr", &LOGFONT)
   
   Size      :=-NumGet(LOGFONT, "Int")*72//A_ScreenDPI
   Weight    := NumGet(LOGFONT, 16, "Int")
   Italic    := NumGet(LOGFONT, 20, "Char")
   Underline := NumGet(LOGFONT, 21, "Char")
   Strike    := NumGet(LOGFONT, 22, "Char")
   Quality   := NumGet(LOGFONT, 26, "Char")
   FaceName  := StrGet(&LOGFONT + 28)
   
   res := {}
   for k, v in ["Size", "Weight", "Italic", "Underline", "Strike", "Quality", "FaceName"]
      res[v] := %v%
   Return res
}