HMG4 release method

Moderator: Rathinagiri

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Re: HMG4 release method

Post by l3whmg » Thu Jul 21, 2011 1:02 pm

Hi Carlos,
your idea it's good but I have some doubt:
1) about QT objects: when I close (release) a form every child it's released. For this reason, looking to your code: before I close a form and then I have a loop for every child (good), but it's already closed. I repeat: about QT

Attention: it's an idea, I don't test it

1) the release method cant' be in a unique place. Every object must have a release method ( as MrDuck write). I think this for other things, anyway.
2) Well, I change the order: before I execute the loop and then close the object:

Code: Select all

METHOD Release() CLASS WINDOW or BUTTON or ....
   LOCAL i
   LOCAL cCurrentObj := ::cName     //<<---- to clear current object
   // Release all child objects in it.
   // Recursive !
   FOR i := 1 TO Len( ::aControls )
      IF hb_IsObject( ::aControls[ i ] )
         ::aControls[ i ]:Release()
      ENDIF
   NEXT
   // Some QT classes do not have close()
   ::oQTObject:close()      //<=== this must be inserted if the QT object has the close method
                                    // I remember to you: the release method must by overwrite for every object
   ::oParent:&cCurrentObj := NIL     //<=== remove my self Harbour/HMG4
   RETURN NIL
But attention: probably, we have connected a procedure with the form (remember ONRELEASE?). What happen?
In this moment I don't have a clear idea. I'm working to extend ONRELEASE to every object.

On the other hand, I'm working to find a good way to connect and handle events and signals. Thanks to MrDuck for inspiration!
This is a little real example that I'm using on my experimental HMG4, within every object class

Code: Select all

  
   ::oQtObject:connect( QEvent_WindowStateChange,  { |e| ::ZonChangeDo( e ) } )  <=== this only for window
   ::oQtObject:connect( QEvent_Close,              { || ::ZonCloseDo() } )
   ::oQTObject:connect( QEvent_FocusIn,            { || ::ZonFocusInDo() } )
   etc., etc.
If I receive a good return, I want change HMG4!

Cheers
Luigi from Italy
www.L3W.it

Carlos Britos
Posts: 220
Joined: Sat Aug 02, 2008 5:03 pm
Has thanked: 6 times
Been thanked: 2 times

Post by Carlos Britos » Thu Jul 21, 2011 4:06 pm

l3whmg wrote:Hi Carlos,
your idea it's good but I have some doubt:
1) about QT objects: when I close (release) a form every child it's released. For this reason, looking to your code: before I close a form and then I have a loop for every child (good), but it's already closed. I repeat: about QT
In my test the window or parent object is closed at the end.

1) the release method cant' be in a unique place. Every object must have a release method ( as MrDuck write). I think this for other things, anyway.
I don't know about this.

Code: Select all

2) Well, I change the order: before I execute the loop and then close the object:
METHOD Release() CLASS WINDOW or BUTTON or ....
   LOCAL i
   LOCAL cCurrentObj := ::cName     //<<---- to clear current object
   // Release all child objects in it.
   // Recursive !
   FOR i := 1 TO Len( ::aControls )
      IF hb_IsObject( ::aControls[ i ] )
         ::aControls[ i ]:Release()
      ENDIF
   NEXT
   // Some QT classes do not have close()
[code]   ::oQTObject:close()      //<=== this must be inserted if the QT object has the close method
Is closed at the begining.

Code: Select all

                                    // I remember to you: the release method must by overwrite for every object
   ::oParent:&cCurrentObj := NIL     //<=== remove my self Harbour/HMG4
   RETURN NIL 
First we have to clean any refence to the object in the code/lib.

Code: Select all

[b]But attention[/b]: probably, we have connected a procedure with the form (remember ONRELEASE?). What happen?
In this moment I don't have a clear idea. I'm working to extend ONRELEASE to every object.
I don't have it clear too, I try to implement OnInteractiveclose which is realted with this but fail.
Regards/Saludos, Carlos (bcd12a)

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Post by l3whmg » Thu Jul 21, 2011 4:52 pm

Hi Carlos,
Carlos Britos wrote:
l3whmg wrote:
Hi Carlos,
your idea it's good but I have some doubt:
1) about QT objects: when I close (release) a form every child it's released. For this reason, looking to your code: before I close a form and then I have a loop for every child (good), but it's already closed. I repeat: about QT
In my test the window or parent object is closed at the end.
I'm sorry I don't understand: what do you mean with "is closed at the end"? Little example.
With QT object...
QMainWindow:Close() then its childs will be: QLAbel:Close(), QPushButton:Close(), ..... this is the automated QT process
With HMG4 "translation"
MainForm:Release() then its childs will be: Label1:Close(), Button1:Close(), ..... this is the automated QT process
But we have HMG/Harbour objects with related aControls... ok, this is another problem!
Carlos Britos wrote:
Quote:
1) the release method cant' be in a unique place. Every object must have a release method ( as MrDuck write). I think this for other things, anyway.
I don't know about this.
We must pay attention to QT problem. Some object have the same properties and/or method but other object have different properties or methods. Example QAction used by MENUITEM don't has QT close method; for this reason, HMG release method related to MENUITEM can't has ::oQtObject:Close(). To handle this differences, we must overwrite the HMG4 release method within any HMG4 object: to have a clean code and a clear idea about what happen.

About my code:
first I don't test it with current HMG4. I have used this idea sometime ago and work fine.
second IMHO before close current QT object (ie form) you must close childs then you can close current QT object and clean HMG4/Harbour object (ie form). Your function is recursive and explore aControls. Isn't it? For this reason repeat from: close current QT object (ie MAINMENU) you must close childs then...., close current QT object (ie MENU) you must close childs..., close current QT object (ie MENUITEM) you must...
But, related with first, I don't test it and related with second I think this may be the logic.

Cheers
Luigi from Italy
www.L3W.it

Carlos Britos
Posts: 220
Joined: Sat Aug 02, 2008 5:03 pm
Has thanked: 6 times
Been thanked: 2 times

Post by Carlos Britos » Thu Jul 21, 2011 11:16 pm

l3whmg wrote:
I'm sorry I don't understand: what do you mean with "is closed at the end"? Little example.
With QT object...
QMainWindow:Close() then its childs will be: QLAbel:Close(), QPushButton:Close(), ..... this is the automated QT process
With HMG4 "translation"
MainForm:Release() then its childs will be: Label1:Close(), Button1:Close(), ..... this is the automated QT process
But we have HMG/Harbour objects with related aControls... ok, this is another problem!
If we release a window or another parent object, the FOR NEXT, first check for all the child objects and releases them, and at the end release the window
( ::aControls only have child objects of the window or another parent object )
We must pay attention to QT problem. Some object have the same properties and/or method but other object have different properties or methods. Example QAction used by MENUITEM don't has QT close method; for this reason, HMG release method related to MENUITEM can't has ::oQtObject:Close().
To handle this differences, we must overwrite the HMG4 release method within any HMG4 object: to have a clean code and a clear idea about what happen.
Mauricio has done this in the code to check it.
// Some QT classes do not have close()
IF ! ( ::cClass == "MENUITEM" .OR. ;
::cClass == "SOUND" .OR. ;
....

first I don't test it with current HMG4. I have used this idea sometime ago and work fine.
second IMHO before close current QT object (ie form) you must close childs then you can close current QT object and clean HMG4/Harbour object (ie form).
Your function is recursive and explore aControls. Isn't it?
yes, search and replace by NIL.
For this reason repeat from: close current QT object (ie MAINMENU) you must close childs then...., close current QT object (ie MENU) you must close childs..., close current QT object (ie MENUITEM) you must...
But, related with first, I don't test it and related with second I think this may be the logic.
Is the same. the FOR NEXT loop

I've made some tests and the problem is more complex than I thought:
- We have to kill Harbour and QT objects.
- As far as I know and as Apais said the only way to kill a harbour object is with o := NIL, but from outside the class.
::oParent:&cCurrentObj := NIL
After this in the class, the object is still there.

- Checking the number handles (with ProcesExplorer), before and after release, never decrease in fact are increased.
- In QT docs, about close ==> QWidget::close()
The widget is HIDDEN if it accepts the close event. If it ignores the event, nothing happens.
If the widget has the Qt::WA_DeleteOnClose flag, the widget is also deleted. A close events is delivered to the widget no matter if the widget is visible or not.


Qt::WA_DeleteOnClose = 55. Makes Qt delete this widget when the widget has accepted the close event.

But QT core is out of my scope.


- Please, test something like this:
build an object, RELEASE it and SHOW it from a menu

Code: Select all

  With Object lbl1  := label():New( "lbl1" )
     :value := '111'
     :Row   := 40
     :Col   := 10
  End

  MenuItem "Release" Action {|| Win_1:Lbl1:Release() , ;
                            Win_1:Lbl1:Value := '000' , ;
                            Win_1:Lbl1:Show() }
  
If we do Win_1:Lbl1 := nil then harbour object is destroyed (I'm guess) but the Qt object is there.

This stuff and all related to this, like OnInterActiveClose, OnRelease, etc.. must be thinked very carefully.
Regards/Saludos, Carlos (bcd12a)

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Post by l3whmg » Fri Jul 22, 2011 11:17 am

Hi Carlos,
Carlos Britos wrote:If we release a window or another parent object, the FOR NEXT, first check for all the child objects and releases them, and at the end release the window
( ::aControls only have child objects of the window or another parent object )
I think we thinking the same while we writing different :lol:
Our code are very similar: I have only do little change: the order.
First we release childs Qt object
Carlos Britos wrote: // Release all child objects in it.
// Recursive !
FOR i := 1 TO Len( ::aControls )
IF hb_IsObject( ::aControls[ i ] )
::aControls[ i ]:Release()
ENDIF
NEXT
Second we close the current Qt Object
Carlos Britos wrote: // Some QT classes do not have close()
IF ! ( ::cClass == "MENUITEM" .OR. ;
::cClass == "SOUND" .OR. ;
::cClass == "TIMER" .OR. ;
::cClass == "LAYOUTBOX" .OR. ;
::cClass == "LAYOUTFORM" .OR. ;
::cClass == "LAYOUTGRID" )

// release QT object
::oQTObject:close()

ENDIF
Third remove HMG4 object from stack and ampyt current Harbour object
Carlos Britos wrote: // Remove from the parent pool control
FOR i := 1 TO Len( ::oParent:aControls )
IF hb_IsObject( ::oParent:aControls[ i ] )
IF ::oParent:aControls[ i ]:Name == ::Name
::oParent:aControls[ i ] := Nil
ENDIF
ENDIF
NEXT

About release I write: we must have (ie release) a generic method and specialized method for any object when required difference.
For this reason my release method is without test: "IF !( ::cClass...." but this it's IMHO to keep code clean.
I repeat: IMHO and my vision of kernel code.
Carlos Britos wrote:- As far as I know and as Apais said the only way to kill a harbour object is with o := NIL, but from outside the class.
Because someone introduce this mandatory syntax: "with object ObjectName := .... " in program and you must clear ObjectName within your program: not within HMG4. It's out of scope this ability.
I write more time: IMHO this syntax it's not a good way. Anyway.
p.s. update
on the other hand if we clean the internal HMG object we clean the external object
a code can be
LOCAL oObjectName := ::cName
::oParent:&oObjectName := NIL
end of update
With ::oParent:aControls we remove the internal HMG4 object (and work fine) not the external: the programmer must do this like to declare var (IMHO this syntax it's not a good......)

Carlos Britos wrote:- Checking the number handles (with ProcesExplorer), before and after release, never decrease in fact are increased.
- In QT docs, about close ==> QWidget::close()
The widget is HIDDEN if it accepts the close event. If it ignores the event, nothing happens.
If the widget has the Qt::WA_DeleteOnClose flag, the widget is also deleted. A close events is delivered to the widget no matter if the widget is visible or not.

Qt::WA_DeleteOnClose = 55. Makes Qt delete this widget when the widget has accepted the close event.

But QT core is out of my scope.

Mee to. I'm a novice: every day I read about QT, find a solution and try tuo use. IMHO, HMG4 have a good level, but I think we must recheck all the code,
rewrite many parts, and redo test with demo.
For this reason I write my personal HMG. When I find a solution update the kernel and recheck all demo.
The last discovered is about event/signlas in a "standardize" (no more) HMG handling method.
Or a toplayer (before HMG4 basic.prg) with only basic property and method of a Qt widget....
Last edited by l3whmg on Fri Jul 22, 2011 11:48 am, edited 1 time in total.
Luigi from Italy
www.L3W.it

User avatar
concentra
Posts: 256
Joined: Fri Nov 26, 2010 11:31 am
Location: Piracicaba - Brasil

Post by concentra » Fri Jul 22, 2011 11:32 am

Just dropping 2 cents on the table...
l3whmg wrote:About release I write: we must have (ie release) a generic method and specialized method for any object when required difference.
For this reason my release method is without test: "IF !( ::cClass...." but this it's IMHO to keep code clean and manageble in a easy way.
I had an idea while reading this.
In order to avoid code duplication ( multiplication ) maybe its better to write another method exclusively to "close" the QT object and overload this method in the classes ::oQtObject:close() is not applicable.
Something like this:

Code: Select all

Method Release() CLASS BASIC
   code...
   code...
   code...
   
   ::CloseQtObject()
  
   code...
   code...
   code...
   RETURN Self

/*******************/
  Generic
/*******************/
Method CloseQtObject() CLASS BASIC
   ::oQtObject:Close()
   RETURN Self

/*******************/
  No close compliant code
/*******************/
Method CloseQtObject() CLASS NOCLOSECOMPLIANT
   // Do nothing
   RETURN Self
[[]] Mauricio Ventura Faria

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Post by l3whmg » Fri Jul 22, 2011 11:53 am

Hi Mauricio,
you don't have a duplicate code but another method CloseQtObject() and you must manage/update and so on.

With a generalized release method with ::oQtObject:close() when you know that a QT object can't handle this method, you simply add release method (see CloseQtObject) within its class. It's the same

Cheers
Luigi from Italy
www.L3W.it

User avatar
concentra
Posts: 256
Joined: Fri Nov 26, 2010 11:31 am
Location: Piracicaba - Brasil

Post by concentra » Fri Jul 22, 2011 12:54 pm

l3whmg wrote:Hi Mauricio,
you don't have a duplicate code but another method CloseQtObject() and you must manage/update and so on.

With a generalized release method with ::oQtObject:close() when you know that a QT object can't handle this method, you simply add release method (see CloseQtObject) within its class. It's the same

Cheers
But manage duplicate code is way harder.
See this sample situation:
Without auxiliary method:

Code: Select all

/*----------------------------------------------------------------------*/
/* Generic Release
/*----------------------------------------------------------------------*/
METHOD Release() CLASS BASIC

   code 1...
   code 2...
   code 3...

   ::oQTObject:close()

   code 4...
   code 5...
   code 6...

   RETURN Self

/*----------------------------------------------------------------------*/
/* Release for MENUITEM
/*----------------------------------------------------------------------*/

Method Release() CLASS MENUITEM
   code 1...
   code 2...
   code 3...
   code 4...
   code 5...
   code 6...
   RETURN Self

/*----------------------------------------------------------------------*/
/* Release for SOUND
/*----------------------------------------------------------------------*/

Method Release() CLASS SOUND
   code 1...
   code 2...
   code 3...
   code 4...
   code 5...
   code 6...
   RETURN Self

/*----------------------------------------------------------------------*/
/* Release for TIMER
/*----------------------------------------------------------------------*/

Method Release() CLASS TIMER
   code 1...
   code 2...
   code 3...
   code 4...
   code 5...
   code 6...
   RETURN Self

/*----------------------------------------------------------------------*/
/* Release for LAYOUTBOX
/*----------------------------------------------------------------------*/

Method Release() CLASS LAYOUTBOX
   code 1...
   code 2...
   code 3...
   code 4...
   code 5...
   code 6...
   RETURN Self

/*----------------------------------------------------------------------*/
/* Release for LAYOUTFORM
/*----------------------------------------------------------------------*/

Method Release() CLASS LAYOUTFORM
   code 1...
   code 2...
   code 3...
   code 4...
   code 5...
   code 6...
   RETURN Self

/*----------------------------------------------------------------------*/
/* Release for LAYOUTGRID
/*----------------------------------------------------------------------*/

Method Release() CLASS LAYOUTGRID
   code 1...
   code 2...
   code 3...
   code 4...
   code 5...
   code 6...
   RETURN Self
And with the auxiliary method.

Code: Select all

/*----------------------------------------------------------------------*/
/* Release
/*----------------------------------------------------------------------*/
METHOD Release() CLASS BASIC

   code 1...
   code 2...
   code 3...

   ::CloseQtObject()

   code 4...
   code 5...
   code 6...

   RETURN Self

/*----------------------------------------------------------------------*/
/* Generic Close Qt Object
/*----------------------------------------------------------------------*/
Method CloseQtObject() CLASS BASIC

   ::oQtObject:Close()

   RETURN Self

/*----------------------------------------------------------------------*/
/* Close for MENUITEM
/*----------------------------------------------------------------------*/

Method CloseQtObject() CLASS MENUITEM
   // Do nothing
   RETURN Self

/*----------------------------------------------------------------------*/
/* Close for SOUND
/*----------------------------------------------------------------------*/

Method CloseQtObject() CLASS SOUND
   // Do nothing
   RETURN Self

/*----------------------------------------------------------------------*/
/* Close for TIMER
/*----------------------------------------------------------------------*/

Method CloseQtObject() CLASS TIMER
   // Do nothing
   RETURN Self

/*----------------------------------------------------------------------*/
/* Close for LAYOUTBOX
/*----------------------------------------------------------------------*/

Method CloseQtObject() CLASS LAYOUTBOX
   // Do nothing
   RETURN Self

/*----------------------------------------------------------------------*/
/* Close for LAYOUTFORM
/*----------------------------------------------------------------------*/

Method CloseQtObject() CLASS LAYOUTFORM
   // Do nothing
   RETURN Self

/*----------------------------------------------------------------------*/
/* Close for LAYOUTGRID
/*----------------------------------------------------------------------*/

Method CloseQtObject() CLASS LAYOUTGRID
   // Do nothing
   RETURN Self
If, for example, code 1... needs to be changed we have to change it 1 time other than 7 times in the first situation.
Maintain existing code is much harder than writing new one and, if I have to choose, I choose the first because its easier to maintain, smaller and simpler.
Last edited by concentra on Fri Jul 22, 2011 3:39 pm, edited 1 time in total.
[[]] Mauricio Ventura Faria

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Post by l3whmg » Fri Jul 22, 2011 1:16 pm

Hi Mauricio, perhaps I don't understand your code, but I see a lot of release method (I'm referring to the second example) for any object class ???
On the other hand: if "code 1" for MENUITEM is different from "code 1" of TOOLBUTTON you can't have the same BASIC release method or not? I think there are a lot of possibility to have problems/differences.

Anyway, up to you.

Cheers
Luigi from Italy
www.L3W.it

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Post by l3whmg » Fri Jul 22, 2011 2:39 pm

Hi Carlos, I do one test and this doesn't work
l3whmg wrote:p.s. update
on the other hand if we clean the internal HMG object we clean the external object
a code can be
LOCAL oObjectName := ::cName
::oParent:&oObjectName := NIL
end of update
I'm able only to clean the internal object (ie ::oParent:aControls := NIL) but not the external var (ie oMainForm, oLabel, etc.). As I write, the external var must be clean within your program; on the other hand, put a code like this "MEMVAR->&(::cName) := NIL" IMHO it's dangerous.
With new mandatory syntax you must write your program in this way:
"WITH OBJECT oMainForm := WINDOW():New( <name>", the <name> can be omitted but it is irrelevant
Somewhere in your program you must write "oMainForm := NIL" to clean external object.

But thanks to your indication, now the objects of QT are permanently deleted (I refer to my experiment).

Cheers
Luigi from Italy
www.L3W.it

Post Reply