The DrawText API by a real example
The drawText APi have some explanations in this MSDN link
https://msdn.microsoft.com/en-us/library/windows/desktop/dd162498%28v=vs.85%29.aspx
its very usefull when you want to format a text (ANSI orR Unicode) in a given area.
The DrawText function draws formatted text in the specified rectangle.
It formats the text according to the specified method (expanding tabs, justifying characters,
breaking lines, and so forth).
the code below shows how to use this API to draw formatted text on a form.The form used is top level for the transparency condition here.
1-it depends of the real HWND of the form (its diffrent way for a top level form (showWindow=2) and forms (showWindow=0,1).
the code shows how to obtain the hwnd whose desserves the devive context hdc calculation.
2-Calculate the appropriate hdc
3-create a font with the Createfont API
the structure of this API (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183499%28v=vs.85%29.aspx)
HFONT CreateFont(
int nHeight, // height of font
int nWidth, // average character width
int nEscapement, // angle of escapement
int nOrientation, // base-line orientation angle
int fnWeight, // font weight
DWORD fdwItalic, // italic attribute option
DWORD fdwUnderline, // underline attribute option
DWORD fdwStrikeOut, // strikeout attribute option
DWORD fdwCharSet, // character set identifier
DWORD fdwOutputPrecision, // output precision
DWORD fdwClipPrecision, // clipping precision
DWORD fdwQuality, // output quality
DWORD fdwPitchAndFamily, // pitch and family
LPCTSTR lpszFace // typeface name
);
4-must select this choosen font with API selectObject to make it working with drawtext API.
5-select the rectangle initial area where plan to draw the text.the left and right top corner are mandatory.
the bottom corner can float in function of the len of text to draw.
the API can do that with the constant DT_CALCRECT
Determines the width and height of the rectangle. If there are multiple lines of text,
DrawText uses the width of the rectangle pointed to by the lpRect parameter and extends the base
of the rectangle to bound the last line of text. If the largest word is wider than the rectangle, the width is expanded. If the text is less than the width of the rectangle, the width is reduced.
If there is only one line of text, DrawText modifies the right side of the rectangle so that it bounds the last character in the line.
In either case, DrawText returns the height of the formatted text but does not draw the text (this is important).
To format the text , drawText uses many constants described in the link above as DT_WORDBREAK,DT_LEFT ,DT_RIGHT,DT_CENTER,DT_RTLREADING ,DT_END_ELLIPSIS...
this API is used in winapi tooltips to format the tooltip text to live inside the tooltip area (see a previous post of winapi tooltips).
the API is not well documented relative to DT_CALRECT constant and we have not real example how to use that constant. If the constant is inside the function it draws anything.it calculates the rectangle height bounding the text only.
Must redraw with drawtext API without this constant to see the effect.
It's simple but it should to be found.
the code below uses many tested texts in a cursor.A navigation button can show each text drawn on the form.see the photo below of the form and what does each button.
the left small red shape can move the form (mousedown)
-can change the fontname/fontsize dynamically, rightclick on the shape to change form shape backcolor
-can change the form opacity(0-255 but a vlaue>100 is better to see visually the text).
-can change the form text forecolor by rightclick also.
-can paste any unicode text (as sample arabix here) on notepad and save as unicode option (mandatory).the unicode text is converted by code toa string using the great function strconv().
The drawTextW is the API working with unicode texts.drawTextA or drawText for ANSI texts.
Before begining copy this arabic unicode text and paste into notepad+save as arabic.txt mandatory with the option "UNICODE".its used in the cursor inside the code.
The drawTextW API preserves the right to left of the text (insert the constant DT_RTLREADING and the DT_RIGHT in code).
- -the constant DT_WORDBREAK Breaks words.
- Lines are automatically broken between words if a word would extend past the edge of the rectangle specified by the lpRect parameter. A carriage return-line feed sequence also breaks the line.
- If this is not specified, output is on one line.
تمكن القطري ناصر الخليفي، بفضل الإمكانات المالية الضخمة التي سخّرها عند تقلده
منصب الرئيس المدير العام لفريق العاصمة الباريسية، في نوفمبر 2011،
من فرض الـ”بي.أس.جي”
في الساحة الكروية الفرنسية. والأكثر من هذا، أصبح النادي الفرنسي يزاحم أكبر
وأعرق النوادي العالمية في انتداب النجوم، بدليل أن تشكيلة قائد الديكة
سابقا لوران بلان تضم في صفوفها لاعبين من الوزن الثقيل،
لا يمكن للفرنسيين حتى من الحلم في رؤيتهم في الملاعب الفرنسية من أمثال
السويدي زلاتان إيبراهاموفيتش والبرازيليين
دافيد لويز و تياغو سيلفا ولوكاس والايطالي فيراتي والأوروغواياني كافاني وآخرين ممن لم يقدروا
على مقاومة العرض المالي الذي قدمه الخليفي صاحب مؤسسة قطر للاستثمارات الرياضية.
ناصر الخليفي صاحب الـ42 عاما (من مواليد 1973 بقطر)، تمكن بفضل تسييره
الراشد من قيادة باريس سانت جيرمان إلى هرم البطولة الفرنسية، لاسيما خلال
هذا الموسم الذي انتزع فيه الفريق الرباعية التاريخية (كأس وبطولة فرنسا)
وكأس الرابطة و كأس السوبر.. وهي كلها ألقاب جعلت من ناصر الخليفي، رئيس المؤسسة
الإعلامية الكبيرة بيين سبور القطرية، من كسب قلوب الفرنسيين الذين يكنون
له كل الاحترام والتقدير،
وهو ما وقفت عليه “الخبر” ميدانيا في ملعب فرنسا، على هامش نهائي كأس فرنسا الذي
عادت فيه الكلمة الأخيرة لـ”بي.أس.جي” بعد هدف كافاني في مرمى نادي أوكسير.
Click on code to select [then copy] -click outside to deselect
Publi oform
oform=Newobject("ydrawText")
oform.Show
Read Events
Retu
*
Define Class ydrawText As Form
BorderStyle = 0
Top = 17
Left = 188
Height = 150
Width = 493
ShowWindow = 2
ShowTips = .T.
Caption = ""
FontBold = .T.
FontSize = 20
MinHeight = 50
TitleBar = 1
ForeColor = Rgb(113,0,56)
BackColor = Rgb(0,255,0)
BorderStyle=0
realhwnd = 0
alpha = 210
hfont = 0
Add Object shape1 As Shape With ;
Top = 8, ;
Left = 9, ;
Height = 132, ;
Width = 476, ;
Anchor = 15, ;
BackStyle = 1, ;
BorderWidth = 6, ;
Curvature = 30, ;
BackColor = Rgb(128,255,255), ;
BorderColor = Rgb(255,0,0), ;
Name = "Shape1"
Add Object shape2 As Shape With ;
Top = -1, ;
Left = 0, ;
Height = 24, ;
Width = 24, ;
Curvature = 99, ;
MousePointer = 15, ;
ToolTipText = "Move by mousedown", ;
BackColor = Rgb(255,0,0), ;
Name = "Shape2"
Add Object image1 As Image With ;
Picture = Home(1)+"samples\solution\toledo\showcode.bmp", ;
Stretch = 2, ;
BackStyle = 0, ;
Height = 32, ;
Left = 445, ;
MousePointer = 15, ;
Top = 16, ;
Width = 32, ;
ToolTipText = "close", ;
Name = "Image1"
Add Object label1 As Label With ;
FontBold = .T., ;
FontSize = 12, ;
Anchor = 0, ;
BackStyle = 0, ;
Caption = "This is the infobulle title", ;
Height = 22, ;
Left = 36, ;
Top = 24, ;
Width = 336, ;
ForeColor = Rgb(255,0,0), ;
Name = "Label1"
Add Object shape3 As Shape With ;
Top = 21, ;
Left = 425, ;
Height = 18, ;
Width = 18, ;
Curvature = 99, ;
MousePointer = 15, ;
ToolTipText = "Fonts*Backcolor", ;
BackColor = Rgb(255,155,205), ;
Name = "Shape3"
Add Object label2 As Label With ;
AutoSize = .T., ;
FontName = "Webdings", ;
FontSize = 22, ;
BackStyle = 0, ;
Caption = "4", ;
Height = 32, ;
Left = 367, ;
MousePointer = 15, ;
Top = 18, ;
Width = 31, ;
ToolTipText = "Navigate cursor", ;
Name = "Label2"
Add Object timer1 As Timer With ;
Top = 120, ;
Left = 12, ;
Height = 25, ;
Width = 37, ;
Enabled = .F., ;
Interval = 200, ;
Name = "Timer1"
Add Object shape4 As Shape With ;
Top = 22, ;
Left = 405, ;
Height = 18, ;
Width = 18, ;
Curvature = 99, ;
MousePointer = 15, ;
ToolTipText = "Forecolor", ;
BackColor = Rgb(128,0,255), ;
Name = "Shape4"
Procedure ydraw
Lparameters lctext,lcTitle,lctype
Sele ycurs
Thisform.label1.Caption=ytitle
#Define TRANSPARENT 1
#Define OPAQUE 2
#Define DT_LEFT 0
#Define DT_CENTER 1
#Define DT_TOP 0
#Define DT_RIGHT 2
#Define DT_WORDBREAK 16
#Define DT_CALCRECT 1024
***************************
#Define FW_NORMAL 400
#Define FW_BOLD 700
#Define OUT_DEVICE_PRECIS 5
#Define OUT_OUTLINE_PRECIS 8
#Define CLIP_STROKE_PRECIS 2
#Define ANSI_CHARSET 0
#Define PROOF_QUALITY 2
#Define DEFAULT_PITCH 0
#Define DT_RTLREADING 0x00020000
If Thisform.hfont <> 0
= DeleteObject(Thisform.hfont)
Thisform.hfont=0
Endif
xfontName=Thisform.FontName &&"English157 BT" &&"Comic sans MS"
xfontsize=Thisform.FontSize
If Thisform.FontBold=.T.
bb=FW_BOLD
Else
bb=FW_NORMAL
Endi
m.italic=0
If Thisform.FontItalic=.T.
m.italic=1
Else
m.italic=0
Endi
Thisform.hfont = CreateFont(xfontsize, 0, 0, 0,;
m.bb, m.italic,0,0,;
ANSI_CHARSET, OUT_DEVICE_PRECIS, CLIP_STROKE_PRECIS,;
PROOF_QUALITY, DEFAULT_PITCH, xfontName)
***************************************
Local hWindow, hDC, lcRect, lctext
hWindow = Thisform.realhwnd
hDC = GetWindowDC(hWindow)
= SelectObject(hDC, Thisform.hfont)
With Thisform
x=30
Y=45
x1=x+.Width-2*30
y1=Y+.Height-2*30
Endwith
sleep(200)
lcRect = Thisform.n2dw(x) + Thisform.n2dw(Y) + Thisform.n2dw(x1) + Thisform.n2dw(Y)
= SetTextColor (hDC, Thisform.ForeColor) &&rgb(255*rand(),255*rand(),255*rand()) ) &&
= SetBkMode (hDC, TRANSPARENT)
sleep(200)
*****
Do Case
Case Upper(lctype)=="A"
h= DrawText (hDC, lctext, Len(lctext),@lcRect, DT_WORDBREAK+DT_LEFT+DT_CALCRECT)
Thisform.Height=h+2*30
sleep(500)
lcRect = Thisform.n2dw(x) + Thisform.n2dw(Y) + Thisform.n2dw(x1) + Thisform.n2dw(Y+h)
DrawText (hDC, lctext, Len(lctext),@lcRect, DT_WORDBREAK+DT_LEFT)
Case Upper(lctype)=="W"
h=DrawTextW (hDC, lctext, Len(lctext)/2,@lcRect, DT_WORDBREAK+DT_RIGHT+DT_RTLREADING+DT_CALCRECT) &&DT_RIGHT if RTL len(lcText)/2 solves pb
Thisform.Height=h+2*30
sleep(500)
lcRect = Thisform.n2dw(x) + Thisform.n2dw(Y) + Thisform.n2dw(x1) + Thisform.n2dw(Y+h)
DrawTextW (hDC, lctext, Len(lctext)/2,@lcRect, DT_WORDBREAK+DT_RIGHT+DT_RTLREADING)
Otherwise
h=DrawText (hDC, lctext, Len(lctext),@lcRect, DT_WORDBREAK+DT_LEFT+DT_CALCRECT)
Thisform.Height=h+2*30
sleep(500)
lcRect = Thisform.n2dw(x) + Thisform.n2dw(Y) + Thisform.n2dw(x1) + Thisform.n2dw(Y+h)
DrawText (hDC, lctext, Len(lctext),@lcRect, DT_WORDBREAK+DT_LEFT)
Endcase
= ReleaseDC(hWindow, hDC)
*https://msdn.microsoft.com/en-us/library/windows/desktop/dd162498%28v=vs.85%29.aspx
*DT_CALCRECT
*Determines the width and height of the rectangle. If there are multiple lines of text,
*DrawText uses the width of the rectangle pointed to by the lpRect parameter and extends
*the base of the rectangle to bound the last line of text. If the largest word is wider
*than the rectangle, the width is expanded. If the text is less than the width of the
*rectangle, the width is reduced. If there is only one line of text, DrawText modifies
*the right side of the rectangle so that it bounds the last character in the line.
*In either case, DrawText returns the height of the formatted text but does not draw the text.
Endproc
Procedure n2dw
Lparameters lnValue
#Define m0 256
#Define m1 65536
#Define m2 16777216
Local b0, b1, b2, b3
b3 = Int(lnValue/m2)
b2 = Int((lnValue - b3*m2)/m1)
b1 = Int((lnValue - b3*m2 - b2*m1)/m0)
b0 = Mod(lnValue, m0)
Return Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)
Endproc
Procedure buf2dword
Lparameters lcbuffer
Return Asc(Substr(lcbuffer, 1,1)) + ;
Asc(Substr(lcbuffer, 2,1)) * 256 +;
Asc(Substr(lcbuffer, 3,1)) * 65536 +;
Asc(Substr(lcbuffer, 4,1)) * 16777216
Endproc
Procedure ytranspa
Lparameters alpha
#Define LWA_COLORKEY 1
#Define LWA_ALPHA 2
#Define GWL_EXSTYLE -20
#Define WS_EX_LAYERED 0x80000
Local nExStyle, nRgb, nAlpha, nFlags
nExStyle = GetWindowLong(Thisform.HWnd, GWL_EXSTYLE)
nExStyle = Bitor(nExStyle, WS_EX_LAYERED)
= SetWindowLong(Thisform.HWnd, GWL_EXSTYLE, nExStyle)
= SetLayeredWindowAttributes(Thisform.HWnd, Thisform.BackColor, alpha,LWA_COLORKEY+LWA_ALPHA)
Endproc
Procedure KeyPress
Lparameters nKeyCode, nShiftAltCtrl
If nKeyCode=27
Thisform.Release
Endi
Endproc
Procedure MouseDown
Lparameters nButton, nShift, nXCoord, nYCoord
lnHandle = Thisform.HWnd
param1 = 274
param2 = 0xF012
Declare Integer ReleaseCapture In WIN32API
Declare Integer SendMessage In WIN32API Integer, Integer, Integer, Integer
bb=ReleaseCapture()
bb=SendMessage(lnHandle, param1, param2,0)
Endproc
Procedure Load
Declare Integer GetWindowLong In user32;
INTEGER HWnd, Integer nIndex
Declare Integer SetWindowLong In user32;
INTEGER HWnd, Integer nIndex, Integer dwNewLong
Declare Integer SetLayeredWindowAttributes In user32;
INTEGER HWnd, Integer crKey,;
SHORT bAlpha, Integer dwFlags
Declare Integer DeleteObject In gdi32 Integer hObject
Declare Integer GetActiveWindow In user32
Declare Integer GetWindowDC In user32 Integer HWnd
Declare Integer ReleaseDC In user32 Integer HWnd, Integer hDC
Declare Integer SetBkMode In gdi32 Integer hdc, Integer iBkMode
Declare Integer SetTextColor In gdi32 Integer hdc, Integer crColor
Declare Integer DrawText In user32;
INTEGER hDC, String lpString, Integer nCount,;
STRING @lpRect, Integer uFormat
Declare Integer DrawTextW In user32;
INTEGER hDC, String lpString, Integer nCount,;
STRING @lpRect, Integer uFormat
Declare Integer Sleep In kernel32 Integer
Declare Integer SelectObject In gdi32 Integer hdc, Integer hObject
Declare Integer SetTextColor In gdi32 Integer hdc, Integer crColor
Declare Integer GetDC In user32 Integer hWindow
Declare Integer ReleaseDC In user32 Integer hWindow, Integer hdc
Declare Integer CreateWindowEx In user32;
INTEGER dwExStyle, String lpClassName, String lpWindowName,;
INTEGER dwStyle, Integer x, Integer Y,;
INTEGER nWidth, Integer nHeight, Integer hWndParent,;
INTEGER hMenu, Integer hInstance, Integer lpParam
Declare Integer SetLayeredWindowAttributes In user32;
INTEGER HWnd, Integer crKey,;
SHORT bAlpha, Integer dwFlags
Declare Integer CreateFont In gdi32;
INTEGER nHeight, Integer nWidth, Integer nEscapement,;
INTEGER nOrientation, Integer fnWeight, Integer fdwItalic,;
INTEGER fdwUnderline, Integer fdwStrikeOut, Integer fdwCharSet,;
INTEGER fdwOutputPrec, Integer fdwClipPrec, Integer fdwQuality,;
INTEGER fdwPitchAndFamily, String lpszFace
Declare Integer SetBkMode In gdi32;
INTEGER hdc, Integer iBkMode
Create Cursor ycurs (ystring m,ytitle c(100),xtype c(1))
********
TEXT to x noshow
The visualization code I'm writing using Processing.js
needs a tooltip to display some information depending on where your mouse is in the canvas. Although there are on where your mouse is in the canvas. Although there are
on where your mouse is in the canvas. Although there are
many tooltip options for webpage elements, I didn't find
any that I could easily use with Processing.js to generate
tooltips dependent on the mouse position in the canvas.
After a few frustrating attempts with various libraries I
finally just took this rounded corners demo by F1LT3R.
*
The DrawText function draws formatted text in the specified
rectangle. It formats the text
according to the specified method (expanding tabs,justifying
characters, breaking lines, and so forth).
The visualization code I'm writing using Processing.js needs a tooltip
to display some information depending
fin
ENDTEXT
Y="This is a big text to work with drawtext API"
Insert Into ycurs Values ( x,Y,"A")
***************
TEXT to x noshow
The visualization code I'm writing using Processing.js
needs a tooltip to display some information depending on where your mouse is in the canvas. Although there are on where your mouse is in the canvas. Although there are
on where your mouse is in the canvas. Although there are
many tooltip options for webpage elements, I didn't find
any that I could easily use with Processing.js to generate
tooltips dependent on the mouse position in the canvas.
After a few frustrating attempts with various libraries I
finally just took this rounded corners demo by F1LT3R.
fin
ENDTEXT
Y="This is a average text to work with drawtext API"
Insert Into ycurs Values ( x,Y,"A")
***************
*unicode
Local cexp
x=Filetostr("arabic.txt") +Chr(0) &&arabic.txt saved as unicode txt in notepad
Y="This is an Arabic unicode text stired in txt file"
Insert Into ycurs Values (x,Y,"W")
************************
TEXT to x noshow
Needs a tooltip to display some information depending on where your mouse is in the canvas. Although there are on where your mouse is in the canvas. Although there are
ENDTEXT
Y="This is a mono line text to work with drawtext API"
Insert Into ycurs Values ( x,Y,"A")
************
*brow
Endproc
Procedure Init
With This
.TitleBar=0
.shape1.Anchor=15
.shape1.BorderColor=Rgb(255*Rand(),255*Rand(),255*Rand())
.realhwnd = Iif(.ShowWindow = 2, Sys(2327, Sys(2325, Sys(2326, .HWnd))), .HWnd)
.alpha=210
Endwith
Thisform.ytranspa(Thisform.alpha)
Thisform.timer1.Enabled=.T.
Endproc
Procedure Activate
Sele ycurs
Thisform.ydraw(ystring,ytitle,xtype)
Endproc
Procedure Destroy
Clea Events
Endproc
Procedure shape1.RightClick
Local m.x
m.x=Getcolor()
If !m.x=-1
This.BackColor=m.x
Endi
Sele ycurs
Thisform.ydraw(ystring,ytitle,xtype)
Endproc
Procedure shape2.MouseDown
Lparameters nButton, nShift, nXCoord, nYCoord
lnHandle = Thisform.HWnd &&getFocus()
param1 = 274
param2 = 0xF012
Declare Integer ReleaseCapture In WIN32API
Declare Integer SendMessage In WIN32API Integer, Integer, Integer, Integer
bb=ReleaseCapture()
bb=SendMessage(lnHandle, param1, param2,0)
Endproc
Procedure image1.Click
Thisform.Release
Endproc
Procedure shape3.Click
Local m.x
m.x=Getfont()
If ! Empty(m.x)
With Thisform
.FontName= Getwordnum(x,1,',')
.FontSize=Int(Val(Getwordnum(x,2,',')))
Endwith
Sele ycurs
Thisform.ydraw(ystring,ytitle,xtype)
Endi
Endproc
Procedure shape3.MouseDown
Lparameters nButton, nShift, nXCoord, nYCoord
Endproc
Procedure shape3.RightClick
local m.x
m.x=getcolor()
if !m.x=-1
with thisform
.shape1.backcolor= m.x
endwith
endi
sele ycurs
thisform.ydraw(ystring,ytitle,xtype)
endproc
Procedure label2.Click
Sele ycurs
Try
Skip
Catch
Locate
Endtry
If ! Empty(ystring)
Thisform.ydraw(ystring,ytitle,xtype)
Endi
Endproc
Procedure timer1.Timer
Sele ycurs
Locate
Thisform.ydraw(ystring,ytitle,xtype)
This.Enabled=.F.
Endproc
Procedure shape4.Click
Local m.x
m.x=Getcolor()
If !m.x=-1
With Thisform
.ForeColor= m.x
Endwith
Endi
Sele ycurs
Thisform.ydraw(ystring,ytitle,xtype)
Endproc
Procedure shape4.RightClick
Local m.x
m.x=Int(Val(Inputbox("Transparency (0---> 100-255)","","210")))
If m.x<=100
Return .F.
Endi
Thisform.alpha=m.x
Thisform.ytranspa(Thisform.alpha)
Sele ycurs
Thisform.ydraw(ystring,ytitle,xtype)
Endproc
Enddefine
*
*-- EndDefine: ydrawtext
Remarks:
1-The text height calculation should be done with vfp by
-using the function memlines (string): number of text lines
-Input a line height (depending on fontname/size used ) and loop to calculate the total text height.
-Draw the text with the specidied rectangle (4 points:left top coner, right bottom corner) with drawText API.
this VFP method is more fast the API but all problem resides in the line height.
2-VFP uses Print method to draw text on the surface form at a specified position (x,y).
form .Print [(cText, iCurrentX, iCurrentY)]
this method dont format the text as well and dont clip the text (a background color stays).(its works with Bitmap=on ).the drawing text can be erased with form.cls.
3-I guess the gdiplusX measureString() function calculates with a similar method the rectangle bounding a text to draw it: loGfx.MeasureString(string, loFont)
its uses the GdipMeasureString API IN GDIPLUS.DLL .
DECLARE Long GdipMeasureString IN GDIPLUS.DLL AS xfcGdipMeasureString Long graphics, String str, Long length, Long thefont, String @layoutRect, Long StringFormat, String @boundingBox, Long @codepointsFitted, Long @linesFilled
-Its the same similar method with html5 canvas:
measureText() Returns an object that contains the width of the specified text
4-Can choose a picture form background and draw a formatted text over it and capture the result as image....
In the next post i plan to make custom VFP tooltips with this idea. A top level form appears as a tooltip when mouseEnter event is fired on any control and disappears when the mouseLeave event is fired on same control
Ref:
http://yousfi.over-blog.com/2015/02/winapi-tooltips.html
http://www.atoutfox.org/articles.asp?ACTION=FCONSULTER&ID=0000000589 (must be member)
http://www.foxite.com/downloads/default.aspx?id=191&keyword=tooltips&category=
http://www.news2news.com/vfp/index.php?example=303