hello Paul :-)
found the following code at https://www.freebasic.net/forum/viewtopic.php?p=138367#p138367
made a new project with one button and placed the code in the Form1_Button1_Click function.
everything seems to work OK but I would like your opinion, is the code kosher?
are there any memory leaks?
is there a better way?
[I changed hWndForm to Form1.hWindow]
Function Form1_Button1_Click( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
'by BasicScience
Dim As Integer xleft, ytop, wd, ht
xleft = 50
ytop = 50
wd = 400
ht = 200
Dim hDC As HDC
' Dim hPen As hpen
hDC = GetDC( Form1.hWindow )
Rectangle hDC, xleft, ytop, xleft+wd, ytop+ht
Dim As HPEN greenPen=CreatePen(PS_solid, 3, &h0000ff00)
Dim As HPEN BluePen=CreatePen(PS_solid, 3, &h00ff0000)
SelectObject (hDC, greenPen)
MoveToEx hDC, xleft, ytop+ht/2, Null
For i As Integer = 0 To wd-1
If i = wd/2 Then SelectObject (hDC, BluePen)
LineTo hDC, xleft+i, ytop + (ht/2)*(1+ Sin(6.28*i/20)*Exp(-i/70))
Next i
ReleaseDC Form1.hWindow, hDC
DeleteObject(GreenPen)
DeleteObject(BluePen)
Function = 0
End Function
Hi Johan,
I would do it a little different. :)
You should put all of the drawing in WM_PAINT because you never know when a portion of the form will need to repainted. I am doing all of the form background painting in WM_PAINT (the form background and the graphic itself). I am also suppressing WM_ERASEBKGND so there isn't double painting of the background causing flicker.
I am also SaveDC and RestoreDC in order to preserve the DC stack preventing deleting GDI objects while they are still selected in the DC.
Take a look at this:
dim shared gShowGraphic as Boolean = false
''
''
Function Form1_AllEvents( ByRef sender As wfxForm, ByRef e As EventArgs ) As LRESULT
select case e.Message
case WM_PAINT
Dim hDC As HDC
dim as RECT rc
Dim As HPEN greenPen, BluePen
Dim As long xleft, ytop, wd, ht, stateDC
xleft = 50
ytop = 50
wd = 400
ht = 200
hDC = GetDC( Form1.hWindow )
stateDC = SaveDC(hDC)
' Paint the Form background
dim as HBRUSH hBackBrush = CreateSolidBrush(Form1.BackColor)
GetClientRect( Form1.hWindow, @rc)
FillRect( hDC, @rc, hBackBrush)
' Paint the graphic
if gShowGraphic then
Rectangle hDC, xleft, ytop, xleft+wd, ytop+ht
greenPen = CreatePen(PS_solid, 3, &h0000ff00)
BluePen = CreatePen(PS_solid, 3, &h00ff0000)
SelectObject (hDC, greenPen)
MoveToEx hDC, xleft, ytop+ht/2, Null
For i As Integer = 0 To wd-1
If i = wd/2 Then SelectObject (hDC, BluePen)
LineTo hDC, xleft+i, ytop + (ht/2)*(1+ Sin(6.28*i/20)*Exp(-i/70))
Next i
end if
RestoreDC(hDC, stateDC)
ReleaseDC Form1.hWindow, hDC
DeleteObject(GreenPen)
DeleteObject(BluePen)
DeleteObject(hBackBrush)
case WM_ERASEBKGND
' We will handle all of the form background painting in WM_PAINT
' This will help avoid flicker.
e.Handled = true
end select
Function = 0
End Function
''
''
Function Form1_Button1_Click( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
' Toggle displaying the graphic
gShowGraphic = not gShowGraphic
Form1.Refresh
Function = 0
End Function
''
'' Remove the following Application.Run code if it used elsewhere in your application.
Application.Run(Form1)
You could also use the BeginPaint and EndPaint api functions to get the hDC and release it when finished in WM_PAINT. In my code, I used GetDC and ReleaseDC. I don't think that it really makes any difference other than that BeginPaint will automatically send an WM_ERASEBKGND message so you could redraw the client area in that message before drawing your graphic. In my code, I decided to do it all in the WM_PAINT handler.
Also, before I forget, this code you used is dangerous because INTEGER is 32 bits on Win32 and 64 bits on Win64 thereby causing problems when compiling 64 bit EXE's. The Windows API expects 32 bit values for just about everything. I always use LONG rather than INTEGER.
Dim As Integer xleft, ytop, wd, ht
Rectangle hDC, xleft, ytop, xleft+wd, ytop+ht
thanks a million, Paul :-)
your advice and code are very much appreciated.