Accuracy of GetTextWidth()

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Accuracy of GetTextWidth()

Post by esgici »

Hi All

I have some doubts about accuracy of GetTextWidth() function :(

Code: Select all

/*
   Test for accuracy of GetTextWidth() function.
   
   2014-08-18
   
*/


#include <hmg.ch>

PROCEDURE Main()                               
   
   DEFINE WINDOW frmGTWTest ;
      AT     0,0 ;
      WIDTH  250 ;
      HEIGHT 200 ;
      MAIN       ;
      TITLE  "GTW Accuracy"  ;
      ON INIT { || MsgDebug( GetTextWidth( , "size10" ), GetTextWidth( , "size20" ) ) }
      
      ON KEY ESCAPE ACTION ThisWindow.Release
      
      @  50, 50 LABEL lblSize10 HEIGHT 20 VALUE "Size10" FONT "Verdana" SIZE 10
      @ 100, 50 LABEL lblSize20 HEIGHT 30 VALUE "Size20" FONT "Verdana" SIZE 20
      
   END WINDOW // frmGTWTest

   frmGTWTest.Center()
   frmGTWTest.Activate()
  
RETU // Main()

*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.
Metrics added result of test program
Metrics added result of test program
GTW_Accuracy.PNG (14.89 KiB) Viewed 4021 times
I know this is an "undocumented-internal" function so require careful usage.

Anyway I need know exact length in pixel of any string.

And IMHO for this info requires font size in addition to font name and not requires window / control name specified.

We have same samples for interesting usages by experts :

Code: Select all

   gettextwidth(Nil,cString,fontname)*0.072/72*25.4*fontsize
If this formula ( 0.072/72*25.4*fontsize ) is secure ( under every circumstance ) there isn 't a problem to make it another ( but accurate ) function, I think.

Any opinion ?
Viva INTERNATIONAL HMG :D
User avatar
Pablo César
Posts: 4059
Joined: Wed Sep 08, 2010 1:18 pm
Location: Curitiba - Brasil

Re: Accuracy of GetTextWidth()

Post by Pablo César »

Very nteresting matter Esgici, please go ahead with your research.
HMGing a better world
"Matter tells space how to curve, space tells matter how to move."
Albert Einstein
User avatar
Pablo César
Posts: 4059
Joined: Wed Sep 08, 2010 1:18 pm
Location: Curitiba - Brasil

Re: Accuracy of GetTextWidth()

Post by Pablo César »

Hi Esgici,

I appreciate this matter so much and thanks for sharing.

Just now I have done some tests about your code:

Code: Select all

/*
   Test for accuracy of GetTextWidth() function.
   
   2014-08-18
   
*/


#include <hmg.ch>

Function Main
   
   DEFINE WINDOW frmGTWTest ;
      AT     0,0 ;
      WIDTH  250 ;
      HEIGHT 200 ;
      MAIN       ;
      TITLE  "GTW Accuracy"  ;
      ON INIT { || MsgDebug( GetTextWidth( NIL, "size10", _HMG_SYSDATA [ 36 ][2] ), GetTextWidth( NIL, "size20", _HMG_SYSDATA [ 36 ][3] ) ) }
      
      ON KEY ESCAPE ACTION ThisWindow.Release
      
      @  50, 50 LABEL lblSize10 HEIGHT 20 VALUE "Size10" FONT "Verdana" SIZE 10
      @ 100, 50 LABEL lblSize20 HEIGHT 30 VALUE "Size20" FONT "Verdana" SIZE 20
      
   END WINDOW

   frmGTWTest.Center()
   msgdebug(_HMG_SYSDATA [ 36 ] )
   frmGTWTest.Activate()
  
Return Nil
Note, seems something with this _HMG_SYSDATA [ 36 ] value by index.
HMGing a better world
"Matter tells space how to curve, space tells matter how to move."
Albert Einstein
User avatar
Pablo César
Posts: 4059
Joined: Wed Sep 08, 2010 1:18 pm
Location: Curitiba - Brasil

Re: Accuracy of GetTextWidth()

Post by Pablo César »

Getting more results with:

Code: Select all

/*
   Test for accuracy of GetTextWidth() function and Height
   
   2014-08-18
   
*/


#include <hmg.ch>

Function Main
   
   DEFINE WINDOW frmGTWTest ;
      AT     0,0 ;
      WIDTH  250 ;
      HEIGHT 200 ;
      MAIN       ;
      TITLE  "GTW Accuracy"  ;
      ON INIT { || MsgInfo( "Width (lblSize10):"+hb_ValToStr(GetTextWidth( NIL, "size10", _HMG_SYSDATA [ 36 ][2] ))+CRLF+"Width (lblSize20):"+hb_ValToStr(GetTextWidth( NIL, "size20", _HMG_SYSDATA [ 36 ][3] ))+CRLF+CRLF+"Height (lblSize10):"+hb_ValToStr(_HMG_SYSDATA [ 28 ][2] )+CRLF+"Height (lblSize20):"+hb_ValToStr(_HMG_SYSDATA [ 28 ][3] ),"Width and Height") }
      
      ON KEY ESCAPE ACTION ThisWindow.Release
      
      @  50, 50 LABEL lblSize10 HEIGHT 20 VALUE "Size10" FONT "Verdana" SIZE 10
      @ 100, 50 LABEL lblSize20 HEIGHT 30 VALUE "Size20" FONT "Verdana" SIZE 20
      
   END WINDOW

   frmGTWTest.Center()
   // msgdebug(_HMG_SYSDATA [ 36 ] )
   // msgdebug(_HMG_SYSDATA [ 28 ] )
   frmGTWTest.Activate()
  
Return Nil
Here testing Height too.
Tela1.PNG
Tela1.PNG (9.18 KiB) Viewed 3975 times
Message re-edited. Correcting for height in pixels.
HMGing a better world
"Matter tells space how to curve, space tells matter how to move."
Albert Einstein
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: Accuracy of GetTextWidth()

Post by esgici »

OK Sr. Cesar,

It seems, it's enough for correct result, sending font handle of control as third parameter to the function.

For this we need
- defined (and activated) form and control
- know index of control

Well, it's time to learn ( if possible ) width in pixel of any string without own any control :?

TIA
Viva INTERNATIONAL HMG :D
User avatar
mol
Posts: 3720
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Contact:

Re: Accuracy of GetTextWidth()

Post by mol »

I found differences in strings:

Image

By the way, this function doesn't calculate exact string length, besides, when you use bold feature, calculation is very bad.
User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: Accuracy of GetTextWidth()

Post by Rathinagiri »

GetTextWidth() function requires more importantly the DeviceContext and the font handle. Because, the text width might be different in various devices (monitor, printer etc). So, it is better and accurate if we give the exact device on which we want to show the text.
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: Accuracy of GetTextWidth()

Post by esgici »

mol wrote:I found differences in strings:
...
By the way, this function doesn't calculate exact string length, besides, when you use bold feature, calculation is very bad.
I'm not sure, which width returned; width of given string as parameter or caption / value string of control :?: :?
Rathinagiri wrote: GetTextWidth() function requires more importantly the DeviceContext and the font handle. Because, the text width might be different in various devices (monitor, printer etc). So, it is better and accurate if we give the exact device on which we want to show the text.
Beside font handle, we ( at least I ) need more clarification: how can be specified DeviceContext :?

May be first parameter ( always omitted, sent NIL ) ?

And what are codes / names etc of that info ?

Regards
Viva INTERNATIONAL HMG :D
User avatar
Pablo César
Posts: 4059
Joined: Wed Sep 08, 2010 1:18 pm
Location: Curitiba - Brasil

Accuracy of GetTextWidth()

Post by Pablo César »

mol wrote:I found differences in strings:

Image
Yeah, you are right. Thanks Marek to advise this detail. I passed many hours looking for differance in my new function.
mol wrote:By the way, this function doesn't calculate exact string length, besides, when you use bold feature, calculation is very bad.
For bold size differs so few (around 2 pixels) and width sizes came with small differances but I not sure if is considered part o character of empty pixels. As showing in picture below (yellow color):
char.jpg
char.jpg (13.2 KiB) Viewed 3863 times
I have done another sample and I noted when is changed any font property the GetTextWidth function does not takes the right result. :(

Code: Select all

/*
   Test for accuracy of GetTextWidth() function and Height
   
   2014-08-19
   
*/

#include <hmg.ch>

Function Main(cFont,cBold)
Local nFnt, cFontName
Private aFonts:={"Verdana","Arial","Courier New"}, lBold

If cFont=NIL
   cFont:="2"
Endif
nFnt := Val(cFont)
If nFnt>0 .and. nFnt<4
   cFontName := aFonts[nFnt]
Else
   MsgStop("Upto 3 fonts declared")
   Quit
Endif
If cBold=NIL
   lBold := .F.
Else
   lBold := .T.
Endif

DEFINE WINDOW frmGTWTest ;
    AT     0,0 ;
    WIDTH  380 ;
    HEIGHT 280 ;
    MAIN       ;
    TITLE  "Accuracy in pixels" ;
	ON INIT Test()
   
    ON KEY ESCAPE ACTION ThisWindow.Release
    
	DEFINE LABEL lblSize10
	    ROW    50
	    COL    20
	    HEIGHT 20
	    VALUE "Size10"
	    FONTNAME cFontName
	    FONTSIZE 10
	    FONTBOLD lBold
	    BACKCOLOR GREEN
	    FONTCOLOR RED
	END LABEL
	
	DEFINE LABEL lblSize20
	    ROW    100
	    COL    20
	    HEIGHT 30
	    VALUE "Size20"
	    FONTNAME cFontName
	    FONTSIZE 20
	    FONTBOLD lBold
	    BACKCOLOR GREEN
	    FONTCOLOR RED
	END LABEL
	
	@ 50,180 LABEL lblText HEIGHT 80 WIDTH 124 VALUE "" SIZE 11

	DEFINE COMBOBOX Combo_1
	    ROW    180
	    COL    20
	    WIDTH  120
	    HEIGHT 100
	    ITEMS  {aFonts[1],aFonts[2],aFonts[3]}
	    VALUE nFnt
	    FONTNAME "Arial"
	    FONTSIZE 9
	    ONCHANGE ChngFntLbls(This.Value)
	END COMBOBOX
	
	DEFINE CHECKBOX Check_1
	    ROW    180
	    COL    160
	    WIDTH  60
	    HEIGHT 28
	    CAPTION " Bold"
	    VALUE lBold
	    FONTNAME "Arial"
	    FONTSIZE 9
	    ONCHANGE ChngBoldFntLbl(This.Value)
	END CHECKBOX
	
	DEFINE BUTTON Button_1
        ROW    180
        COL    220
        WIDTH  120
        HEIGHT 28
        ACTION Test()
        CAPTION "Get Labels sizes"
        FONTNAME "Arial"
        FONTSIZE 9
        TOOLTIP ""
    END BUTTON

END WINDOW
frmGTWTest.Center()
frmGTWTest.Activate()
Return Nil

Function ChngBoldFntLbl(lValue)
lBold:=!lBold
SetProperty("frmGTWTest","lblSize10","FONTBOLD",lBold)
SetProperty("frmGTWTest","lblSize20","FONTBOLD",lBold)
Test()
Return Nil

Function ChngFntLbls(nValue)
Local cFont := aFonts[nValue]

SetProperty("frmGTWTest","lblSize10","FONTNAME",cFont)
SetProperty("frmGTWTest","lblSize20","FONTNAME",cFont)
Test()
Return Nil

Function Test()
Local aSizes:={}, cText:=""

aSizes := GetPixelSizes ("frmGTWTest","lblSize10","Size10")
cText := "Width (lblSize10): "+AllTrim(Str(aSizes[1]))+CRLF+"Height (lblSize10): "+AllTrim(Str(aSizes[2]))+CRLF+CRLF
aSizes := GetPixelSizes ("frmGTWTest","lblSize20","Size20")
cText := cText + "Width (lblSize20): "+AllTrim(Str(aSizes[1]))+CRLF+"Height (lblSize20): "+AllTrim(Str(aSizes[2]))
SetProperty("frmGTWTest","lblText","Value",cText)
Return Nil

Function GetPixelSizes (cForm,cControl,cString)
Local hWnd := GetFormHandle(cForm)
Local hDC := GetDC( hWnd )
Local idx := GetControlIndex (cControl,cForm)
Local nHndFnt := _HMG_SYSDATA [ 36 ][ idx ]
Local nHeight := _HMG_SYSDATA [ 28 ][ idx ]
Local nWidth

DEFAULT cString := GetProperty(cForm,cControl,"Value")

nWidth := GetTextWidth( hDC, cString, nHndFnt )
// msgdebug(nwidth)
ReleaseDC (hWnd, hDC)
Return {nWidth,nHeight}
This code allow also to receive optional parameters at prompt of line command. Then you can test 3 fonts and bold cases.
Test made by prompt line command with parameters: 3 Bold
Test made by prompt line command with parameters: 3 Bold
Screen_02.PNG (12.96 KiB) Viewed 3856 times
It seems that GetTextWidth is based on when the control is being defined and is not changeable it properties even being forced thru SetProperty... :?
HMGing a better world
"Matter tells space how to curve, space tells matter how to move."
Albert Einstein
User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: Accuracy of GetTextWidth()

Post by Rathinagiri »

In source\c_controlmisc.c around line no 360 you can find out what happens when you pass nil in the place of hDC (handle of device context). When you omit the device context, the device context of the active window is taken as the default device context. If you try to use the same for printing it won't show the accurate width.

Code: Select all

   if( ! hDC )
   {
      bDestroyDC = TRUE;
      hWnd = GetActiveWindow();
      hDC = GetDC( hWnd );
   }
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
Post Reply