Working on my hexdump application, which draws a page of hex data using a fixed font (Courier New), I wanted to ignore clicks on the whitespace between the columns. The character spacing is fixed, so asking Windows for the horizontal size, rather than using a number which seemed to fit my console, seemed like a good idea. However, the character size returned by GetTextMetrics is too small, and GetTextCharacterExtra returns zero.
my question is: is there a reliable way of predicting the pixel position of fixed-font text, and if so, what is it?
here's a compileable example, click on the data part of the display and metrics appear in the dialog caption.
my question is: is there a reliable way of predicting the pixel position of fixed-font text, and if so, what is it?
here's a compileable example, click on the data part of the display and metrics appear in the dialog caption.
Code:
' Does GetTextMetrics lie? ' to investigate mapping pixel positions to characters displayed in a LABEL ' Chris Holbrook Sep 2008 ' #COMPILE EXE #DIM ALL #INCLUDE "WIN32API.INC" %IDD_DIALOG1 = 101 %IDC_LABEL1 = 1001 '---------------------------------------------------------------------- FUNCTION MakeFont(BYVAL fName AS STRING, BYVAL ptSize AS LONG, _ OPT BYVAL attr AS STRING) AS DWORD '-------------------------------------------------------------------- ' Create a desired font and return its handle. ' attr = "biu" for bold, italic, and underlined (any order) '-------------------------------------------------------------------- LOCAL hDC AS DWORD, CharSet AS LONG, CyPixels AS LONG LOCAL BOLD, italic, uLine AS LONG LOCAL tm AS TEXTMETRIC IF LEN(attr) THEN IF INSTR(LCASE$(attr), "b") THEN BOLD = %FW_BOLD IF INSTR(LCASE$(attr), "i") THEN italic = 1 IF INSTR(LCASE$(attr), "u") THEN uLine = 1 END IF hDC = GetDC(%HWND_DESKTOP) CyPixels = GetDeviceCaps(hDC, %LOGPIXELSY) ReleaseDC %HWND_DESKTOP, hDC PtSize = 0 - (ptSize * CyPixels) \ 72 FUNCTION = CreateFont(ptSize, 0, 0, 0, BOLD, italic, uLine, _ %FALSE, CharSet, %OUT_TT_PRECIS, _ %CLIP_DEFAULT_PRECIS, %DEFAULT_QUALITY, _ %FF_MODERN , BYCOPY fName) END FUNCTION '------------------------------------------------------------------------- CALLBACK FUNCTION ShowDIALOG1Proc() LOCAL s, stopline AS STRING LOCAL i, j, l, x, y, row, col AS LONG LOCAL ppage AS DWORD LOCAL q AS BYTE PTR LOCAL buffer AS STRING LOCAL pt AS POINTAPI LOCAL hFont, lcolor AS DWORD LOCAL tm AS TEXTMETRIC STATIC charwidth, rowheight AS LONG LOCAL hdc AS DWORD LOCAL m AS LONG SELECT CASE AS LONG CBMSG CASE %WM_INITDIALOG FOR i = 1 TO 256 buffer = buffer + CHR$(i) NEXT ppage = STRPTR(buffer) hDC = getDC(getdlgitem(CBHNDL,%IDC_LABEL1)) GetTextmetrics hDc, tm rowheight = tm.tmheight LOCAL intercharspace AS LONG intercharspace = GetTextCharacterExtra ( hdc) charwidth = tm.tmAveCharWidth + intercharspace'its a fixed font, so all chars should have the same width GOSUB drawlabel CASE %WM_LBUTTONDOWN pt.X = LO(WORD,CBLPARAM): pt.Y = HI(WORD,CBLPARAM) X = pt.X - (11*charwidth) ' 11 characters precede the data block but this only gets us to char 10! ' try to work out if click was on whitespace or on a value m = x MOD (3*charwidth) col = x \ 3*charwidth ' assume first char width in 3-char column is a space IF m > charwidth THEN DIALOG SET TEXT CBHNDL, "charwidth =" + STR$(charwidth) + _ " pos in row =" + STR$(x) + _ " pos in block =" + STR$(m) + _ " column = " + STR$(col) ELSE DIALOG SET TEXT CBHNDL, SPACE$(100) END IF row = (pt.Y - (2*rowheight)) \ rowheight END SELECT EXIT FUNCTION drawlabel: s = STRING$(80 * 16, $SPC) FOR i = 0 TO 15 FOR j = 0 TO 15 q = ppage + (i*16) + j MID$(s, (i * 80) + (j*3)+ 10, 2) = HEX$(@q,2) IF INSTR ( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"" £$%^&*()_+{}[]:@~;'#,./\<>?`¬",CHR$(@q)) <> 0 THEN MID$(s, (i * 80) + 59 + j, 1) = CHR$(@q) ELSE MID$(s, (i * 80) + 59 + j, 1) = "." END IF NEXT MID$(s, ((i) * 80) + 1, 11) = HEX$(ppage + i*16, 8) MID$(s, ((i + 1) * 80) -2, 2) = $CRLF NEXT stopline = SPACE$(11) FOR i = 0 TO 15 stopline = stopline + HEX$(((ppage AND &HF) + i ) AND &HF)+ " " NEXT s = stopline + _ $CRLF + STRING$(57,"-") + " " + STRING$(16,"-") + $CRLF + " " + s CONTROL SET TEXT CBHNDL, %idc_label1, s RETURN END FUNCTION '------------------------------------------------------------------------------- FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG LOCAL lRslt AS LONG LOCAL hDlg AS DWORD LOCAL hFont1 AS DWORD DIALOG NEW hParent, "character and pixel positioning Chris Holbrook Sep 2008", _ 70, 70, 430, 207, _ %WS_POPUP OR %WS_BORDER OR _ %WS_DLGFRAME OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _ %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _ %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg CONTROL ADD LABEL, hDlg, %IDC_LABEL1, "", _ 5, 5, 420, 200, _ %WS_CHILD OR %WS_VISIBLE 'OR %SS_NOWORDWRAP hFont1 = makefont("Courier New",10) CONTROL SEND hDlg, %IDC_LABEL1, %WM_SETFONT, hFont1, 0 DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt DeleteObject hFont1 FUNCTION = lRslt END FUNCTION '------------------------------------------------------------ FUNCTION PBMAIN() ShowDIALOG1 %HWND_DESKTOP END FUNCTION
Comment