A problem with GradientBrush()

User avatar
Enrico Maria Giordano
Posts: 8756
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Has thanked: 1 time
Been thanked: 4 times
Contact:

Re: A problem with GradientBrush()

Post by Enrico Maria Giordano »

Antonio Linares wrote:

Code: Select all | Expand

oDlg:oBrush:End()

MsgInfo( oDlg:oBrush:nCount )


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
User avatar
Antonio Linares
Site Admin
Posts: 42551
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 31 times
Been thanked: 78 times
Contact:

Re: A problem with GradientBrush()

Post 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.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Enrico Maria Giordano
Posts: 8756
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Has thanked: 1 time
Been thanked: 4 times
Contact:

Re: A problem with GradientBrush()

Post 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
User avatar
nageswaragunupudi
Posts: 10721
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 8 times
Contact:

Re: A problem with GradientBrush()

Post 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()
 
Regards

G. N. Rao.
Hyderabad, India
User avatar
Enrico Maria Giordano
Posts: 8756
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Has thanked: 1 time
Been thanked: 4 times
Contact:

Re: A problem with GradientBrush()

Post by Enrico Maria Giordano »

Ok, thank you. Maybe it's slightly unexpected that SetBrush() increments the brush counter, isn't it?

EMG
User avatar
Antonio Linares
Site Admin
Posts: 42551
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 31 times
Been thanked: 78 times
Contact:

Re: A problem with GradientBrush()

Post 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.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
nageswaragunupudi
Posts: 10721
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 8 times
Contact:

Re: A problem with GradientBrush()

Post 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.
Regards

G. N. Rao.
Hyderabad, India
User avatar
Antonio Linares
Site Admin
Posts: 42551
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 31 times
Been thanked: 78 times
Contact:

Re: A problem with GradientBrush()

Post by Antonio Linares »

Dear Rao,

We learned this technique from Windows itself. It does it the same way :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Enrico Maria Giordano
Posts: 8756
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Has thanked: 1 time
Been thanked: 4 times
Contact:

Re: A problem with GradientBrush()

Post 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
User avatar
Antonio Linares
Site Admin
Posts: 42551
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 31 times
Been thanked: 78 times
Contact:

Re: A problem with GradientBrush()

Post 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.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
nageswaragunupudi
Posts: 10721
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 8 times
Contact:

Re: A problem with GradientBrush()

Post 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.
Regards

G. N. Rao.
Hyderabad, India
User avatar
Enrico Maria Giordano
Posts: 8756
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Has thanked: 1 time
Been thanked: 4 times
Contact:

Re: A problem with GradientBrush()

Post 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
User avatar
Antonio Linares
Site Admin
Posts: 42551
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 31 times
Been thanked: 78 times
Contact:

Re: A problem with GradientBrush()

Post 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 :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Enrico Maria Giordano
Posts: 8756
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Has thanked: 1 time
Been thanked: 4 times
Contact:

Re: A problem with GradientBrush()

Post 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
User avatar
Antonio Linares
Site Admin
Posts: 42551
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 31 times
Been thanked: 78 times
Contact:

Re: A problem with GradientBrush()

Post by Antonio Linares »

Enrico,

It seems as the source code for function Test() is missing in your example
regards, saludos

Antonio Linares
www.fivetechsoft.com
Post Reply