Page 3 of 5
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 7:53 am
by Enrico Maria Giordano
Why we need to explicitly release the brush? The dialog already release it on close. But if this is true then I don't understand why the message shows 1 if I comment out the first line... ?
EMG
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 10:53 am
by Antonio Linares
Enrico,
We need to explicity release it because we have created a new brush.
It is not the original brush that was created by FWH. We have created a new one so we have to End() it. Keep in mind that End()s simply decrease the use counter and if it reaches zero, then it is finally destroyed calling DeleteObject().
This way we can share the same brush to be used from different controls, dialogs, windows.
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 11:30 am
by Enrico Maria Giordano
Ok. And what do you say about
Code: Select all | Expand
oDlg:oBrush:End()
oDlg:SetBrush( TBrush():New( ,,,, hBmp ) )
Do we need to release the brush here?
EMG
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 11:40 am
by nageswaragunupudi
>>
oDlg:SetBrush( TBrush():New( ,,,, hBmp ) )
>>
TBrush():new() creates a brush object and sets the count to 1. oWnd/oDlg:SetBrush( oBrush ) increments count to 2. When the window/dialog is closed, the count of oBrush is decremented to 1. The program that first creates the brush is responsible to finally release the brush. In the above usage the brush is never released.
Therefore it is not desirable to create brush inline while setting brush.
What is to be done is :
Create brush ( count : 1 )
setbrush --> count 2
close window --> count 1
brush:end --> count 0 and released
Examining the code for SetBrush makes it clear:
Code: Select all | Expand
METHOD SetBrush( oBrush ) INLINE If( ::oBrush != nil, ::oBrush:End(),),;
::oBrush := oBrush,;
If( oBrush:nCount == nil, oBrush:nCount := 1, oBrush:nCount++),;
::Refresh()
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 11:48 am
by Enrico Maria Giordano
Ok, thank you. Maybe it's slightly unexpected that SetBrush() increments the brush counter, isn't it?
EMG
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 12:05 pm
by Antonio Linares
Enrico,
Method SetBrush() has to increase the counter. Thats its main utility

We need to increase it when it is assigned to a new object, that will use it, and it will be automatically decreased from Method Destroy() when the container object is destroyed.
Its the same technique that Windows uses internally with LoadLibrary() and FreeLibrary(). It uses counters, to know how many "users" a library has, and only when there is just one which calls FreeLibrary() again, then the library will be really freed.
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 12:06 pm
by nageswaragunupudi
>>
Ok, thank you. Maybe it's slightly unexpected that SetBrush() increments the brush counter, isn't it?
>>
This is Mr. Antonio's well thought of ingenious way of reusing resources like fonts, brushes, etc. Once we understand the architecture, we know what to do.
Simple rule we are asked to remember is that
(1) we create font / brush
(2) use them anywhere in any number of windows and / or inherited classes and finally
(3) release the fonts/brushes we created "after" closing all windows/inherited classes.
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 12:08 pm
by Antonio Linares
Dear Rao,
We learned this technique from Windows itself. It does it the same way

Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 12:31 pm
by Enrico Maria Giordano
Maybe it's a matter of naming. One doesn't expect that a method called SetBrush() creates a brush but merely assigns an existing one. So, why does it have to increase the brush counter as if it's creating one?
EMG
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 1:31 pm
by Antonio Linares
Enrico,
The counter is not to count the created brushes. The counter counts the number of users

When you assign a brush to an object, the number of users of the brush increases.
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 1:58 pm
by nageswaragunupudi
Mr Antonio
Let me put Mr. Enrico's question in a different way.
If the programmer creates a brush/font and uses it in as many windows ( and derivatives ) as he wants and releases the brush/font after all such windows are closed by him, there is no harm even if the FWH library does not keep count of the number of users of the resource. Application still works fine. Only thing is the user should not release the resource while it is still being used by a window ( or derivative ).
Whats wrong with it?
I do agree that the present system of incrementing and decrementing the number of windows using the resource has some additional benefits.
For example:
CREATE BRUSH oBrush FILE cFile // nCount is 1
CREATE WINDOW oWnd BRUSH oBrush // nCount is 2
RELEASE BRUSH oBrush // nCount is 1 and so hBrush is not destroyed
ACTIVATE WINDOW ownd
// here nCount becomes zero and the hBrush is released
return nil
Even this code works well with the present implementation.
Re: A problem with GradientBrush()
Posted: Tue Feb 02, 2010 2:27 pm
by Enrico Maria Giordano
Antonio Linares wrote:Enrico,
The counter is not to count the created brushes. The counter counts the number of users

When you assign a brush to an object, the number of users of the brush increases.
Ok, it is the well known "reference counting" technique. But this still not explains why we have to explicitly release the old brush:
Code: Select all | Expand
oDlg:oBrush:End()
oDlg:SetBrush( TBrush():New( ,,,, hBmp ) )
SetBrush() method already releases the old brush and increments the counter of the new brush. Or am I still missing something?
EMG
Re: A problem with GradientBrush()
Posted: Wed Feb 03, 2010 10:10 am
by Antonio Linares
Enrico,
You are right, Method SetBrush() already End()s (and decreases) the previous used brush counter, so there is no need to call oBrush:End() as I have done in my examle

Re: A problem with GradientBrush()
Posted: Wed Feb 03, 2010 10:26 am
by Enrico Maria Giordano
Ok, please review this revised version:
Code: Select all | Expand
#include "Fivewin.ch"
FUNCTION MAIN()
LOCAL oDlg
LOCAL lVar := .F.
DEFINE DIALOG oDlg;
TRANSPARENT
@ 1, 1 BUTTON "Test";
ACTION TEST()
@ 3, 1 CHECKBOX lVar
ACTIVATE DIALOG oDlg;
ON INIT GRADIENTBRUSH( oDlg, { { 1, RGB( 216, 230, 238 ), RGB( 103, 154, 194 ) } } );
CENTER
RETURN NIL
FUNCTION GRADIENTBRUSH( oDlg, aColors )
LOCAL hDC, hBmp, hBmpOld, oBrush
hDC = CREATECOMPATIBLEDC( oDlg:GetDC() )
hBmp = CREATECOMPATIBLEBITMAP( oDlg:hDC, oDlg:nWidth, oDlg:nHeight )
hBmpOld = SELECTOBJECT( hDC, hBmp )
GRADIENTFILL( hDC, 0, 0, oDlg:nHeight, oDlg:nWidth, aColors )
oBrush = TBrush():New( ,,,, hBmp )
oDlg:SetBrush( oBrush )
AEval( oDlg:aControls, { | o | o:SetBrush( oDlg:oBrush ) } )
RELEASE BRUSH oBrush
SELECTOBJECT( hDC, hBmpOld )
DELETEDC( hDC )
oDlg:ReleaseDC()
RETURN NIL
EMG
Re: A problem with GradientBrush()
Posted: Wed Feb 03, 2010 10:31 am
by Antonio Linares
Enrico,
It seems as the source code for function Test() is missing in your example