OK Aurel,
Thanks for responding. I will give you my suggestions but you're free to follow them or not, even if for the obvious reasons of language authorship.
1.
my drawing with mouse move is based on FBSL example
You are free to use any piece of FBSL code found in the accompanying documentation or on the FBSL site for any purpose unless the code has an explicit license stated in the respective file. All such code is in the Public Domain and does not require any reference as to its origin. FBSL is freeware, after all. Thanks for the reference though.
2.
the number of GDI objets in Task are still the same 48..no mather what kind of drawing i do
I'm afraid this isn't so. Your FillSolidRect() creates a temporary (local) GDI object
hBr and uses it to fill the rect but never deletes it when no longer needed. You must add
DeleteObject(hBr) otherwise calling FillSolidRect() (or WindowColor() that uses it) in a loop will show you that your app is leaking one GDI object per each iteration.
3.
WM_ERASEBKGND message is not currently part of new window procedure.
If WindowColor() is the only means to change the background color of your graphics window then you wouldn't want Windows to erase it with the graphics window's default color every time your app responds to a WM_PAINT message (every WM_PAINT is always preceded by WM_ERASEBKGND unless the latter is suppressed in your callback). Unsuppressed WM_ERASEBKGND followed by WindowColor() will cause your window to flicker like hell whenever it is resized or dragged from outside the screen bounds back onto your desktop. Add the following code to your callback to suppress WM_ERASEBKGND:
...
Case WM_ERASEBKGND
Return 1
...
4. If your
ww and
wh parameters are the actual width and height of your graphics window's client area (I don't know what your GetSize() really does), then in order to make you graphics window respond to resizing events, add the following code to your callback:
...
Case WM_SIZE
ww = lParam And &HFFFF ' equivalent to LoWord(lParam)
wh = lParam >> 16 ' equivalent to HiWord(lParam)
...
5. If your
ww and
wh parameters are the width and height of your graphics window's non-client area (effectively its outer sizes), then tell me so and I'll show you how to create a window from the very baginning based on the desired size of its client area rather than its outer dimensions.
6. You should create your memory DC's compatible bitmap to the exact size that your app needs rather than ww+1000 and wh+1000 because:
- every platform and piece of hardware has a limit to the size of bitmaps that it can support; and
- speed of BitBlt(), even if hardware assisted, is dependent roughly on the square of the bitmap's side; the smaller the bitmap, the faster the BitBlt() execution speed. The size of compatible bitmap should match exactly the size of graphics window drawing area it is blitted to; everything extra is a waste of system resources.
7. You tactics of blit-copying every single drawing operation into the memory DC is very very wasteful, both speed- and resource-wise. You will be much better off if you draw directly into the memory DC instead and have a new command called, say
Refresh(hdc As Sys) (or Redraw like Peter's code has) that will be supposed to do only one thing, which will be to blit the contents of memory DC into the hDC of your graphics window:
Sub Refresh(hdc As Sys)
BitBlt(hdc, 0, 0, ww, wh, hDCmem, 0, 0, SRCCOPY)
End Sub
Think for yourself: all you wanna do is set just one pixel on the entire canvas but at the same time you accompany that very simple and relatively fast task with an entire canvas blitting operation, and especially when your canvas is
(ww*wh-1)+1000000 pixels larger than what's really needed! Now imagine what happens if you plan to draw a small row of a hundred pixels in a loop!
I'm curious how Ruben can still draw anything at all!
8.
Case WM_PAINT
If win2 <> 0
BitBlt(hDC, 0, 0, ww, hh, hdcMem, 0, 0, SRCCOPY)
End If
This is an absolutely unacceptable solution. The problem is that WM_PAINT uses its own, very special hDC value that
does not generally coincide with the value returned by GetDC() in this particular message handler. You
must use in this handler the value returned by a call to
BeginPaint() and you
must end this handler with a call to
EndPaint(): Return 0 as prescribed by the Win32 Programmer's Reference:
(watch out for line wrap!)...
Case WM_PAINT
Scope
Dim ps[64] As Byte ' this is a fake PAINTSTRUCT; we aren't going to use its members so no need to define it as genuine UDT
Refresh(BeginPaint(hwnd, ps)) ' hwnd is callback's argument, BeginPaint() returns hDC required to call Refresh()
EndPaint(hwnd, ps) ' ditto
End Scope
Return 0 ' as per Win32 SDK specs
...
EpilogueWe can discuss memory canvas resizing in WM_SIZE in further detail similar to what you found in the FBSL samples when and if you have implemented my suggestions. And my final advice would be that you and your users not attempt to draw anything at random places within your/their code (I remember you having been obsessed with this unreasonable idea some years ago) but rather have some well defined procedure (sub) where all drawing operations would be gathered together in order to be able to efficiently repaint the entire picture, if needed, and then blit it all from memory and into the on-screen graphics window in one go with a call to Refresh() as described above. This tactics would be very very handy to quickly restore the picture in case the window needs to be resized or restored from mini-/maximization.