HMG4 release method

Moderator: Rathinagiri

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

Re: HMG4 release method

Post by Carlos Britos » Sat Jul 23, 2011 12:09 am

Hi mrduck
Carlos, I still have some problems trying to focus on this problem. I "feel" there is something not really clear...

You want to be able to delete a HMG4 object and automatically delete the underlaying hbQt and expecially Qt objects. In every message/thread/sample I find on the web, this is NOT POSSIBLE in Qt. Memory management is done by Qt with its own rules.
In fact I'm just a bit worry seeing how the number of handles is increased each
time a window in open or each time the mouse is over a menu and do not decrease. Memory leak ?
The only way to ask Qt to delete the object is using the Qt::WA_DeleteOnClose. And you are just asking Qt to "please, can you delete the object when you want to do it..., really thanks...."
So if we implement it and if Qt wants to do it is ok.

That said, your sample code looks strange to me..... let me explain
I know that, this code was intended (not too much) to see how release method works with parents
A) Parenting
I don't understand why you are setting the parents in this way.... are these parenting useful in a application ?

:parent has good code, for examply it correctly handles the removal from the parent both as DATA member and in ::aControls array, something :release() in the various forms doesn't do correctly.
What :parent() doesn't do is Qt parenting !!!!!
Have a look at Label:New(). Creating the QLabel we set a Qt parenting. ::parent() doesn't update this parenting.
So after the line
LBL3:Parent := LBL2
the HMG parenting is one, the Qt parenting is another one and LBL3 is still a child of the window....

You may change the code to
Code:
With Object LBL3 := label():New( "LBL3", LBL2 )

but the label won't show... a label inside a label ?!?!?!?
I found time ago some code (HMGEE) that uses a label (in fact is a window without title. C code) as container and child objects are inside this container. Row and col a related to the container. If this is useful or not, well this is another story. QT has a different way to do the things.


B) why qt object doesn't get deleted
C) main and child windows
D) how to close a window
....
When window type is WND_STANDARD it doesn't stop the eventloop....
Since WND_MAIN is the only window type run in a different way (we should check all the windows types) I changed the if in:

Code:
IF ::nType != WND_MAIN
::oEventLoop:Exit( 0 )
ENDIF

and now everything works, the window is closed, the msginfo shown and when oStd goes out of scope used memory (hmg/hbQt/Qt) should be correctly recovered.
Thanks for the explanation.
Do you will commit this ?
Regards/Saludos, Carlos (bcd12a)

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

Post by Carlos Britos » Sat Jul 23, 2011 12:43 pm

mrduck wrote:
Carlos Britos wrote:

Code: Select all

#include "hmg.ch"
FUNCTION Main

Please add here a hbqt_errorsys() call and you will see some harbour errors...
Can you show me what and where are the errors because with or without hbqt_errorsys() I can't see them.
Regards/Saludos, Carlos (bcd12a)

mrduck
Posts: 497
Joined: Fri Sep 10, 2010 5:22 pm

Post by mrduck » Sat Jul 23, 2011 4:50 pm

Please add here a hbqt_errorsys() call and you will see some harbour errors...
Can you show me what and where are the errors because with or without hbqt_errorsys() I can't see them.

the first menu item:

Code: Select all

Item "Release LBL1"   Action { || Win_1:LBL1 := NIL,;
                                       WIN_1:LBL1:Show(),;
                                       WIN_1:LBL1:Value( '********' ) }
After this it will correctly report that NIL has no Show() method. There is also another error in other cases but I can't test now.

mrduck
Posts: 497
Joined: Fri Sep 10, 2010 5:22 pm

Post by mrduck » Thu Jul 28, 2011 10:00 pm

About using qt_wa_deleteonclose....

quotation 1:
Anyways, unless its unavoidable, I personally don’t think it is a good way to manage memory. I have worked on a document editor like MS-Word in Qt and not used the Qt::WA_DeleteOnClose anywhere in the >10000 lines of code. Use the QObject parent/child relationship and use Aggregation and a sound design to delete objects when they are no longer needed.
quotation 2:
Qt::WA_DeleteOnClose eventually causes a call to deleteLater(). The objects are actually deleted once the event loop runs. [...]

Anyways, Qt::WA_DeleteOnClose should be used for parent less QObjects only (e.g. stand alone toplevel widgets like a QMainWindow or a QDialog based UI). Everything else is deleted by the parent-child object relationship.

Carlos, could you test for memory leaking after updating the test source code with my proposals ?

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

Post by Carlos Britos » Fri Jul 29, 2011 7:29 pm

mrduck wrote: Carlos, could you test for memory leaking after updating the test source code with my proposals ?
Hi Francesco
Today I've made some test based on your proposals.

Checking handles seem to be better.
At the begining values are:
Handles = 74
GDI handles = 34
User handles = 15
After open 10 standart windows values are:
Handles = 92
GDI handles = 113
User handles = 25
After close the 10 standart windows values are:
Handles = 92
GDI handles = 38
User handles = 15

Remarks:
- It was not deeply tested.

- With :DelData() I have problems because cName is always == Self:cName and
IF __objHasMsg( Self, LOWER( cName ) ) never is .T.
I can't find the way with this.

- Standart windows are released with button in form, NOT with X button in title; We have to connect X button QEvent_Close with ::Release()

Below are the sources changed based on release 672

I'll try with :destroy()
form Qt docs: Frees up window system resources. Destroys the widget window if destroyWindow is true. destroy() calls itself recursively for all the child widgets
Attachments
testrelease.zip
(15.03 KiB) Downloaded 67 times
Regards/Saludos, Carlos (bcd12a)

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

Post by Carlos Britos » Fri Jul 29, 2011 7:29 pm

mrduck wrote: Carlos, could you test for memory leaking after updating the test source code with my proposals ?
Hi Francesco
Today I've made some test based on your proposals.

Checking handles seem to be better.
At the begining values are:
Handles = 74
GDI handles = 34
User handles = 15
After open 10 standart windows values are:
Handles = 92
GDI handles = 113
User handles = 25
After close the 10 standart windows values are:
Handles = 92
GDI handles = 38
User handles = 15

Remarks:
- It was not deeply tested.

- With : DelData() I have problems
IF __objHasMsg( Self, LOWER( cName ) ) never is .T.
I can't find the way with this. Any hint ?

- Standart windows are released with button in form, NOT with X button in title; We have to connect X button QEvent_Close with ::Release()

Below are the sources changed based on release 672

I'll try with :destroy()
form Qt docs: Frees up window system resources. Destroys the widget window if destroyWindow is true. destroy() calls itself recursively for all the child widgets
Attachments
testrelease.zip
(15.03 KiB) Downloaded 65 times
Regards/Saludos, Carlos (bcd12a)

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

Post by Carlos Britos » Sat Jul 30, 2011 12:01 pm

Carlos Britos wrote: - With : DelData() I have problems
IF __objHasMsg( Self, LOWER( cName ) ) never is .T.
I can't find the way with this. Any hint ?
Replacing code with this one, now Deldata() is ok

Code: Select all

METHOD Release() CLASS BASIC

   // 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
      IF ! hb_IsNil( ::oQTObject )
         ::oQTObject:close()
      ENDIF

      IF ::oParent:cClass != "HMGAPP"
         ::oParent:DelData( ::cName )
      ENDIF

      ::oQTObject := NIL

   ENDIF

   RETURN NIL
The values of the test are the same.
Regards/Saludos, Carlos (bcd12a)

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

Post by l3whmg » Sat Jul 30, 2011 12:28 pm

Hi Carlos
IMHO this
Carlos Britos wrote: IF ::oParent:cClass != "HMGAPP"
::oParent:DelData( ::cName )
ENDIF
is wrong.

You must remove form from HMGAPP stack: isn't it?
If HmgApp don't have deldata, I think you must copy "DelData" source code within HMGAPP.
HMGAPP must be aligned with HMG4 parental system ( or logic ) and functions or methods.
If HMGAPP had a release method, you can "release" all forms: isn't it?
Is a little hidden future.

Cheers

update
p.s. You can create a command WINDOWS RELEASE ALL like HMGAPP():Release(). Isn't it?
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 » Sun Jul 31, 2011 4:14 pm

Hi
l3whmg wrote: You must remove form from HMGAPP stack: isn't it?
If HmgApp don't have deldata, I think you must copy "DelData" source code within HMGAPP.
HMGAPP must be aligned with HMG4 parental system ( or logic ) and functions or methods.
Below are the files with Luigi proposal. (file source1.zip)
Should I commit it ?
If HMGAPP had a release method, you can "release" all forms: isn't it?
Is a little hidden future.
Cheers

update
p.s. You can create a command WINDOWS RELEASE ALL like HMGAPP():Release(). Isn't it?
Maybe, but first we have to check for each window the:
command Set InteractiveClose On|Off|Query|Main Query, bOnRelease, bOnInteractiveClose, NoAutoRelease

I think we need something like ::aControls for windows to check each window before release it.

I'm trying to implement in release method:
command Set InteractiveClose On|Off|Query|Main Query, bOnRelease, bOnInteractiveClose, AutoRelease
but I can't intercept the QT closeEvent, I've tried with QCloseEvent():ignore() but with no luck; Any idea how we can do it?

the idea is something like this:

Code: Select all

::oQTObject:connect( QEvent_Close, {|| ::Release() } )

/*----------------------------------------------------------------------*/

METHOD Release() CLASS VIRTUALWINDOW

   LOCAL i

   /* command SET INTERACTIVECLOSE  On|Off|Query|Main Query */
   IF ::nSetInteractiveClose == 0         // OFF
      MsgStop ( 'Close not allowed', 'Close Window' )
      RETURN NIL
   ELSEIF ::nSetInteractiveClose == 1     // ON
      // nothing to do. default
   ELSEIF ::nSetInteractiveClose == 2     // QUERY
      IF ! MsgYesNo ( 'Are you sure ?', 'Close Window' )
         RETURN NIL
      ENDIF
   ELSEIF ::nSetInteractiveClose == 3     // QUERY MAIN
      IF ::nType == WND_MAIN
         IF ! MsgYesNo ( 'Are you sure ?', 'Close Window' )
            RETURN NIL
         ENDIF
      ENDIF
   ENDIF

   /* Eval bOnInteractiveClose */
   IF hb_IsBlock( ::bOnInteractiveClose )
      IF ! EVAL( ::bOnInteractiveClose )
         RETURN NIL
      ENDIF
   ENDIF

   /* Eval bOnRelease */
   IF hb_IsBlock( ::bOnRelease )
      IF ! EVAL( ::bOnRelease )
         RETURN NIL
      ENDIF
   ENDIF

   /* AutoRelease */
   IF ! ::lAutoRelease
      ::hide()
      RETURN NIL
   ENDIF

   IF ::nType != WND_MAIN
      ::oEventLoop:Exit( 0 )
   ENDIF

   // Remove each control of the window
   FOR i := 1 TO len(::aControls)
      IF ! hb_IsNil( ::aControls[ i ] )
         ::aControls[ i ]:Release()  // it calls :close()
      ENDIF
   NEXT i

   Super:Release()  // it calls :close()
   ::oQTObject := NIL

   IF ::nType == WND_MAIN
      HMGAPP():Quit()
   ENDIF

   RETURN NIL
Attachments
source1.zip
(17.79 KiB) Downloaded 66 times
Regards/Saludos, Carlos (bcd12a)

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

Post by Carlos Britos » Sun Jul 31, 2011 9:35 pm

Hi
I've made this commit please check it.
2011-07-30 18:35 UTC-0300 Carlos Britos ( <bcd12a(a_t)yahoo.com.ar> )
+ samples/window.close
+ samples/window.close/demo_1.prg
+ samples/window.close/demo_2.prg
+ samples/window.close/build.bat
+ samples/window.close/hbmk.hbm
+ samples/window.close/qt.conf
* Added: Samples to test:
Set InterActiveClose ON | OFF | QUERY | QUERY MAIN

* source/window.prg
* source/hmgapp.prg
* source/virtualwindow.prg
* source/control.prg
* source/basic.prg
* Changed Release methods
; Please review it, test it !!
I have some doubts (tagged bcd), see METHOD Release() CLASS VIRTUALWINDOW
If necessary I can revert changes to previous commit.

* include/hmg.ch
+ Added commands Set InterActiveClose ON | OFF | QUERY | QUERY MAIN.
I've commit it to test it in a better way
TODO: How check each window before the release of main window, QUIT or RELEASE WINDOW ALL
Regards/Saludos, Carlos (bcd12a)

Post Reply