Announcement

Collapse
No announcement yet.

How to calculate text in pixels or dialog units in advance?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to calculate text in pixels or dialog units in advance?

    Hello,
    I want for definition of the size of the message to calculate text in pixels or dialog units before make the dialog/message.
    How does it work?

    For example:

    variable
    txt$ = "the text string ..." will be in font "Tahoma", 9, normal

    How is the text width in pixels or dialog units?

    Thanks
    Yours sincerely

  • #2
    Use the API functions GetExtentPoint32 and GetDialogBaseUnits

    Example:

    Code:
    ' [You must create a device context (hDC) first and select your required font]
    Local szl as SIZEL
    GetExtentPoint32 hDC, "test", 4, szl
    dialogunitX = (szl.cx * 4) / LOWRD(GetDialogBaseUnits)
    dialogunitY = (szl.cy * 8) / HIWRD(GetDialogBaseUnits)
    kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

    Comment


    • #3
      I need text size before make the dialog/message !!!
      Yours sincerely

      Comment


      • #4
        GetDC(%HWND_DESKTOP)

        kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

        Comment


        • #5
          How to be with FONT changing?

          one "Tahoma", 9 , 0
          In other case "Courier", 10, 1

          Thanks
          Yours sincerely

          Comment


          • #6
            Pardon poor understanding of your request but Windows need to know where you are putting the text before calculating the sizes, then all information about the font is given with GetTextMetrics
            Last edited by John Petty; 21 Mar 2008, 11:24 AM. Reason: spelling

            Comment


            • #7
              Kev
              Seems to be an interesting omission from PB that it provides standard Text Size functions for printers (XPrint) and Graphics but not Dialogs or Controls
              John

              Comment


              • #8
                Maybe?

                Something to work from?

                Code:
                FUNCTION GetTextWidthInPixels(BYVAL hWnd AS LONG, BYVAL txt AS STRING) AS LONG
                  LOCAL hDc AS LONG, hFont AS LONG, lpSize AS SIZEL
                  hDc = GetDc(hWnd)                               'get handle for proper device context
                    hFont = SendMessage(hWnd, %WM_GETFONT, 0, 0)  'must select hWnd's font into DC,
                    hFont = SelectObject(hDC, hFont)              'otherwise System font is used..
                    CALL GetTextExtentPoint32(hDc, BYVAL STRPTR(txt), LEN(txt), lpSize)
                    SelectObject hDC, hFont                       'select original font back
                  ReleaseDC hWnd, hDc                             'and release DC
                  'FUNCTION = lpSize.cy                           '<- for textheight..
                  FUNCTION = lpSize.cx                            '<- function returns the textwidth
                END FUNCTION

                Comment


                • #9
                  Be sure it will fit: set pixel mode prior to call

                  Code:
                  SUB GetTextDimensions(BYVAL hWnd AS DWORD, BYVAL sText AS STRING, cx AS LONG, cy AS LONG)
                    LOCAL hDC AS DWORD, hFnt AS DWORD, hOldFt AS DWORD
                    LOCAL siz AS SIZEL
                  
                    sText = sText & "W"                            '  extra width to be sure text will fit
                    hDC = GetDC(hWnd)
                    hFnt   = SendMessage (hWnd, %WM_GETFONT, 0, 0)
                    hOldFt = SelectObject(hDC, hFnt)
                    IF SetMapMode (hDC, %MM_TEXT) THEN                   '  set pixelmode
                      GetTextExtentPoint32 hDC, BYVAL STRPTR(sText), LEN(sText), siz
                    END IF
                    SelectObject hDC, hOldFt
                    ReleaseDC hWnd, hDC
                    cx = siz.cx
                    cy = siz.cy
                  END SUB

                  Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                  http://zijlema.basicguru.eu
                  *** Opinions expressed here are not necessarily untrue ***

                  Comment


                  • #10
                    Thanks Tonny and Egbert,
                    but it is necessary to correct code..., I make so:
                    Code:
                    ...
                    lResult = SendMessage ([B][COLOR="Red"]GetDlgItem(hDlg, %IDC_LABEL_TEXT)[/COLOR][/B], %WM_GETFONT, 0, 0) 
                    ...
                    then all works

                    and
                    Code:
                    DIALOG PIXELS hDlg, sz.cx, sz.cy TO UNITS xx, yy
                    Last edited by Alexander Holzer; 21 Mar 2008, 03:54 PM.
                    Yours sincerely

                    Comment


                    • #11
                      Originally posted by Alexander Holzer View Post
                      Code:
                      ...
                      lResult = SendMessage ([B][COLOR="Red"]GetDlgItem(hDlg, %IDC_LABEL_TEXT)[/COLOR][/B], %WM_GETFONT, 0, 0) 
                      ...
                      OK, no problem if you do it this way!
                      It works because you want the size of a control. In my (humble) opinion, though, it's more straight to retrieve the control's handle before calling the function. Like this:
                      Code:
                      hCtrl =  GetDlgItem(hDlg, %IDC_LABEL_TEXT)
                      GetTextDimensions hCtrl, sText, cx, cy
                      
                      ' In case you prefer DDT to retrieve the handle, you may replace 
                      ' GetDlgItem() with: 
                      CONTROL HANDLE hDlg, %IDC_LABEL_TEXT TO hCtrl
                      Last edited by Egbert Zijlema; 22 Mar 2008, 11:40 AM. Reason: set identical names for same var

                      Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                      http://zijlema.basicguru.eu
                      *** Opinions expressed here are not necessarily untrue ***

                      Comment


                      • #12
                        Seems to be an interesting omission from PB that it provides standard Text Size functions for printers (XPrint) and Graphics but not Dialogs or Controls
                        So send in a New Feature Suggestion to [email protected]

                        Or, you could pray and hope your request is forwarded to Florida with a recommendation..
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          Thanks Michael, I do that on improvements that are important to me. this was just interesting, don't want to distract them from more important improvements

                          Comment


                          • #14
                            Sample Code

                            Here follows a sample of how to calculate control sizes in advance.
                            Also try this without adding the extra "W" to the text (see: SUB GetTextDimensions) and see what happens.
                            Code:
                            #COMPILE EXE
                            #DIM ALL
                            
                            %IDC_LABEL = 1001
                            
                            #INCLUDE "WIN32API.INC"
                              
                            SUB CenterMainDialog(BYVAL hDlg AS DWORD)
                                 ' centers a dialog on the desktop
                              LOCAL xScr AS LONG, yScr AS LONG, xDlg AS LONG, yDlg AS LONG
                              xScr = GetSystemMetrics(%SM_CXSCREEN)
                              yScr = GetSystemMetrics(%SM_CYSCREEN)
                              DIALOG GET SIZE hDlg TO xDlg, yDlg
                              DIALOG SET LOC hDlg, (xScr - xDlg) / 2, (yScr - yDlg) / 2
                            END SUB
                            
                            SUB GetTextDimensions(BYVAL hWnd AS DWORD, BYVAL sText AS STRING, cx AS LONG, cy AS LONG)
                              LOCAL hDC AS DWORD, hFnt AS DWORD, hOldFt AS DWORD
                              LOCAL siz AS SIZEL
                            
                              sText = sText & "W"
                              hDC = GetDC(hWnd)
                              hFnt   = SendMessage (hWnd, %WM_GETFONT, 0, 0)
                              hOldFt = SelectObject(hDC, hFnt)
                              IF SetMapMode (hDC, %MM_TEXT) THEN
                                GetTextExtentPoint32 hDC, BYVAL STRPTR(sText), LEN(sText), siz
                              END IF
                              SelectObject hDC, hOldFt
                              ReleaseDC hWnd, hDC
                              cx = siz.cx
                              cy = siz.cy
                            END SUB
                            
                            FUNCTION MakeFont(fWeight AS LONG, fItalic AS BYTE, fUnderline AS BYTE, fStrikeOut AS BYTE, _
                                                                              fFaceName AS STRING, fPtSize AS SINGLE) AS DWORD
                              LOCAL lf  AS LOGFONT
                              LOCAL hDC AS DWORD
                              hDC = GetDC(%HWND_DESKTOP)
                              lf.lfFaceName = fFaceName & CHR$(0)
                              lf.lfWeight = fWeight
                              lf.lfUnderline = fUnderline
                              lf.lfItalic = fItalic
                              lf.lfStrikeOut = fStrikeOut
                              lf.lfHeight = -(fPtSize * GetDeviceCaps(hDC, %LOGPIXELSY)) \ 72
                              FUNCTION = CreateFontIndirect(lf)
                              ReleaseDC 0, hDC
                            END FUNCTION
                            
                            CALLBACK FUNCTION MainDlgProc()
                              STATIC hFnt AS DWORD
                              LOCAL hCtrl AS DWORD
                              
                              SELECT CASE AS LONG CBMSG
                                CASE %WM_INITDIALOG
                                  LOCAL sText AS STRING
                                  LOCAL xLbl AS LONG, yLbl AS LONG
                                  LOCAL xDlg AS LONG, yDlg AS LONG
                                  
                                  sText = " This is a test"
                                  
                                  ' initially set a font for the label:
                                  hFnt = MakeFont(%FW_BOLD, 0, 0, 0, "Arial", 14)
                                  CONTROL SEND CBHNDL, %IDC_LABEL, %WM_SETFONT, hFnt, 0
                                  
                                  ' now the font is set, calculate the control's dimensions 
                                  CONTROL HANDLE CBHNDL, %IDC_LABEL TO hCtrl
                                  GetTextDimensions hCtrl, sText, xLbl, yLbl
                                  CONTROL SET SIZE CBHNDL, %IDC_LABEL, xLbl, yLbl * 3   ' height = 3 lines
                                  CONTROL SET TEXT CBHNDL, %IDC_LABEL, $CRLF & sText
                                  CONTROL SET LOC CBHNDL, %IDC_LABEL, 10, 10            ' margins 10 pixels
                                  
                                  ' now the size of the control is known, calculate and set the dialog's size
                                  xDlg = xLbl + _                                       ' width of control
                                         (2 * 10) + _                                   ' left and right margin
                                         (GetSystemMetrics(%SM_CXDLGFRAME) * 2)         ' left and right frame
                                  yDlg = (3 * yLbl) + _
                                         (2 * 10) + _
                                         (GetSystemMetrics(%SM_CYDLGFRAME) * 2) + _
                                         GetSystemMetrics(%SM_CYCAPTION)
                                  DIALOG SET SIZE CBHNDL, xDlg, yDlg
                                  
                                  ' finally center the dialog
                                  CenterMainDialog CBHNDL
                                
                                CASE %WM_DESTROY
                                  DeleteObject hFnt                                     ' delete the font on exit
                                
                              END SELECT
                            END FUNCTION
                            
                            FUNCTION PBMain () AS LONG
                              LOCAL hDlg AS DWORD
                              DIALOG NEW PIXELS, %HWND_DESKTOP, " Testing text dimensions...", , , 0, 0, _
                                                                %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU TO hDlg
                              ' ad a static control, unknown size and location, with a sunken border to see how the text fits in
                              CONTROL ADD LABEL, hDlg, %IDC_LABEL, "", 0, 0, 0, 0, %SS_SUNKEN
                              CONTROL SET COLOR hDlg, %IDC_LABEL, %BLUE, %WHITE
                              DIALOG SHOW MODAL hDlg, CALL MainDlgProc
                            END FUNCTION

                            Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                            http://zijlema.basicguru.eu
                            *** Opinions expressed here are not necessarily untrue ***

                            Comment


                            • #15
                              Interesting code Egbert.

                              I had asked in an earlier post about fractional fonts and your code showed me an example of how to do it. I'd always assumed they had to be integer because of sample code I've been using for a long time.

                              Pays to read every post, never know when you'll pick up good code. Thanks!

                              Bob Mechler

                              Comment


                              • #16
                                I make this:

                                Code:
                                #COMPILE EXE
                                
                                #INCLUDE "Win32Api.Inc"
                                #INCLUDE "PBForms.INC"
                                
                                %IDC_LABEL_TEXT = 1000
                                
                                FUNCTION PBMAIN()
                                
                                  LOCAL hDlg, hDC     AS DWORD
                                  LOCAL Txt           AS STRING
                                  LOCAL sz            AS SIZEL
                                  LOCAL hFont         AS DWORD
                                  LOCAL x1,y1,xx1,yy1 AS LONG
                                  LOCAL dialogunitY   AS LONG
                                  LOCAL xx,yy         AS LONG
                                  LOCAL lResult       AS LONG
                                  LOCAL Rct           AS RECT
                                
                                SystemParametersInfo %SPI_GETWORKAREA, 0, BYVAL VARPTR(Rct), 0
                                
                                Txt   = "That is not long text"
                                
                                hFont = PBFormsMakeFont("Tahoma", 9, 400, %FALSE, %FALSE, %FALSE, %ANSI_CHARSET) ' from PBForms, otherwise - CreateFont()
                                x1 = 20  ' offset x in pixel
                                y1 = 15  ' offset y in pixel
                                IF LEN(Txt) < 30 THEN x1 = 50 - LEN(Txt) 'if text is too short
                                
                                DIALOG NEW 0, "TEST",,, 1, 1, %WS_SYSMENU, TO hDlg
                                CONTROL ADD LABEL, hDlg, %IDC_LABEL_TEXT, Txt,  0, 0, 0, 0
                                CONTROL SEND hDlg, %IDC_LABEL_TEXT, %WM_SETFONT, hFont, 0
                                
                                  hDc = GetDc (hDlg)
                                  lResult = SendMessage (GetDlgItem(hDlg, %IDC_LABEL_TEXT), %WM_GETFONT, 0, 0)
                                  lResult = SelectObject(hDc, lResult)
                                  GetTextExtentPoint32 hDc, BYVAL STRPTR(Txt), LEN(Txt), sz
                                  lResult = SelectObject(hDc, lResult)
                                  ReleaseDC hDlg, hDc
                                
                                DIALOG PIXELS hDlg, sz.cx, sz.cy TO UNITS xx, yy
                                DIALOG PIXELS hDlg, x1, y1 TO UNITS xx1, yy1
                                
                                CONTROL SET SIZE  hDlg, %IDC_LABEL_TEXT, xx, yy
                                CONTROL SET COLOR hDlg, %IDC_LABEL_TEXT, RGB(10,20,120), RGB(230,230,230)
                                DIALOG SET COLOR hDlg, -1, RGB(230,230,230)
                                CONTROL SET LOC hDlg, %IDC_LABEL_TEXT, xx1, yy1
                                
                                DIALOG  SET SIZE hDlg, xx + 2*xx1 + 4, yy + 2*yy1 + 20' x/y offsets, 4 - widh 2 x border lines, 20 - caption (?)
                                
                                DIALOG PIXELS hDlg, Rct.nLeft,  Rct.nTop    TO UNITS Rct.nLeft,  Rct.nTop
                                DIALOG PIXELS hDlg, Rct.nRight, Rct.nBottom TO UNITS Rct.nRight, Rct.nBottom
                                DIALOG SET LOC hDlg, (Rct.nRight - Rct.nLeft - (xx + 2*xx1)) / 2, (Rct.nBottom - Rct.nTop - (yy + 2*yy1 + 20))/2
                                
                                DIALOG SHOW MODAL hDlg
                                
                                END FUNCTION
                                I always look for a short way of the decision and a small code.

                                All helped - many thanks.
                                Last edited by Alexander Holzer; 23 Mar 2008, 06:15 AM.
                                Yours sincerely

                                Comment


                                • #17
                                  Originally posted by Egbert Zijlema View Post
                                  OK, no problem if you do it this way!
                                  It works because you want the size of a control. In my (humble) opinion, though, it's more straight to retrieve the control's handle before calling the function. Like this:
                                  Code:
                                  hCtrl =  GetDlgItem(hDlg, %IDC_LABEL_TEXT)
                                  [B][COLOR="Red"]GetTextDimensions[/COLOR][/B] hCtrl, sText, cx, cy
                                  
                                  ' In case you prefer DDT to retrieve the handle, you may replace 
                                  ' GetDlgItem() with: 
                                  CONTROL HANDLE hDlg, %IDC_LABEL_TEXT TO hCtrl
                                  GetTextDimensions - ?
                                  What is the function?
                                  Yours sincerely

                                  Comment


                                  • #18
                                    Alexander asks: what is the function?

                                    GetTextDimensions is a function written by myself. That's all.

                                    Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                                    http://zijlema.basicguru.eu
                                    *** Opinions expressed here are not necessarily untrue ***

                                    Comment


                                    • #19
                                      I apologize,
                                      Nonsense has asked..
                                      Yours sincerely

                                      Comment


                                      • #20
                                        Extra W does not really satisfy

                                        Although I'm using the here presented code (see previous page) for a couple of years now, I'm not really satisfied with the fact that I need to insert an extra character "W" in order to get a sufficient cx-value (= width) in return. If you omit that extra "W" a control in many cases will not be wide enough to accommodate the text string. In my opinion GetTextExtentPoint32 should return correct values, provided we use it correctly, but without the necessity to pass a "dirty trick". So what am I (are we) doing wrong here? :headache:

                                        Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                                        http://zijlema.basicguru.eu
                                        *** Opinions expressed here are not necessarily untrue ***

                                        Comment

                                        Working...
                                        X