A problem with GradientBrush()

Re: A problem with GradientBrush()

Postby Enrico Maria Giordano » Tue Feb 02, 2010 7:53 am

Antonio Linares wrote:
Code: Select all  Expand view
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
Enrico Maria Giordano
 
Posts: 8370
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: A problem with GradientBrush()

Postby Antonio Linares » Tue Feb 02, 2010 10:53 am

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
Antonio Linares
Site Admin
 
Posts: 41393
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A problem with GradientBrush()

Postby Enrico Maria Giordano » Tue Feb 02, 2010 11:30 am

Ok. And what do you say about

Code: Select all  Expand view
oDlg:oBrush:End()
oDlg:SetBrush( TBrush():New( ,,,, hBmp ) )


Do we need to release the brush here?

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8370
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: A problem with GradientBrush()

Postby nageswaragunupudi » Tue Feb 02, 2010 11:40 am

>>
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 view
  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
nageswaragunupudi
 
Posts: 10306
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: A problem with GradientBrush()

Postby Enrico Maria Giordano » Tue Feb 02, 2010 11:48 am

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

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8370
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: A problem with GradientBrush()

Postby Antonio Linares » Tue Feb 02, 2010 12:05 pm

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
Antonio Linares
Site Admin
 
Posts: 41393
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A problem with GradientBrush()

Postby nageswaragunupudi » Tue Feb 02, 2010 12:06 pm

>>
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
nageswaragunupudi
 
Posts: 10306
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: A problem with GradientBrush()

Postby Antonio Linares » Tue Feb 02, 2010 12:08 pm

Dear Rao,

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

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41393
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A problem with GradientBrush()

Postby Enrico Maria Giordano » Tue Feb 02, 2010 12:31 pm

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
Enrico Maria Giordano
 
Posts: 8370
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: A problem with GradientBrush()

Postby Antonio Linares » Tue Feb 02, 2010 1:31 pm

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
Antonio Linares
Site Admin
 
Posts: 41393
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A problem with GradientBrush()

Postby nageswaragunupudi » Tue Feb 02, 2010 1:58 pm

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
nageswaragunupudi
 
Posts: 10306
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: A problem with GradientBrush()

Postby Enrico Maria Giordano » Tue Feb 02, 2010 2:27 pm

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 view
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
Enrico Maria Giordano
 
Posts: 8370
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: A problem with GradientBrush()

Postby Antonio Linares » Wed Feb 03, 2010 10:10 am

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
Antonio Linares
Site Admin
 
Posts: 41393
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A problem with GradientBrush()

Postby Enrico Maria Giordano » Wed Feb 03, 2010 10:26 am

Ok, please review this revised version:

Code: Select all  Expand view
#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
Enrico Maria Giordano
 
Posts: 8370
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: A problem with GradientBrush()

Postby Antonio Linares » Wed Feb 03, 2010 10:31 am

Enrico,

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

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41393
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

PreviousNext

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Horizon, MarcoBoschi and 50 guests