@ DCBROWSE ....RECORDOBJECT <oRecord>

Announcements about new features or events.
Post Reply
Message
Author
User avatar
unixkd
Posts: 576
Joined: Thu Feb 11, 2010 1:39 pm

@ DCBROWSE ....RECORDOBJECT <oRecord>

#1 Post by unixkd »

Hi All

How can the numerous dynamic class instances created by DC_DbRecord():new() be removed from memory when the function terminates. Alaska made it clear in their documentation that Dynamically created objects must be explicitly destroyed by executing Classdestroy(oRecord) function otherwise they will remain in memory

Thanks

Joe

Code: Select all

/*
This sample program shows how to browse an array of objects
using the OBJECTVAR clause of DCBROWSECOL.
*/

#include "dcdialog.ch"
#INCLUDE "appevent.CH"

FUNCTION Main()

LOCAL oData, aData1[0], aData2[0], GetList[0], oBrowse1, oBrowse2, ;
      GetOptions, oRecord, i, nRecNo, lStatus, nPointer := 1

DC_LoadRdds()

USE ..\..\data\customer VIA 'FOXCDX'

oRecord := CUSTOMER->(DC_DbRecord():new())

DO WHILE !CUSTOMER->(Eof())
  oRecord := CUSTOMER->(DC_DbRecord():new())
  CUSTOMER->(DC_DbScatter(oRecord))
  AAdd(aData1,{oRecord,CUSTOMER->(RecNo())})
  AAdd(aData2,oRecord)
  CUSTOMER->(dbSkip())
ENDDO

wtf aData1, aData2


// Browsing a multi-dimensional array with objects
@ 0,0 DCSAY 'This is a \i\ubrowse\c of a \bmulti-dimensional\c array of objects:\n' FORMATTED ;
      SAYSIZE 0 FONT '10.Lucida Console' ;
      RESIZE DCGUI_RESIZE_REPOSONLY_Y

@ 1,0 DCBROWSE oBrowse1 DATA aData1 SIZE 20,10 FIT ;
      FILTER {|a|Left(a[1]:bill_city,1)$'ASWBGH'} ;
      POINTER nPointer ;
      RESIZE DCGUI_RESIZE_RESIZEONLY ;
      ;// EDIT xbeBRW_ItemSelected ;
      ITEMSELECTED {||EditRecord(aData1[nPointer,1]),oBrowse1:refreshCurrent()}

DCBROWSECOL OBJECTVAR cust_nmbr ELEMENT 1  HEADER 'ID'       WIDTH  5 PARENT oBrowse1
DCBROWSECOL OBJECTVAR bill_name ELEMENT 1  HEADER 'Name'     WIDTH 15 PARENT oBrowse1
DCBROWSECOL OBJECTVAR bill_strt ELEMENT 1  HEADER 'Address'  WIDTH 15 PARENT oBrowse1
DCBROWSECOL OBJECTVAR bill_city ELEMENT 1  HEADER 'City'     WIDTH 10 PARENT oBrowse1
DCBROWSECOL OBJECTVAR bill_zip  ELEMENT 1  HEADER 'Zip'      WIDTH  4 PARENT oBrowse1
DCBROWSECOL ELEMENT 2 HEADER 'Record' WIDTH 3 PICTURE '999' PARENT oBrowse1

// Browsing a single-dimensional array with objects
@ 12,0 DCSAY 'This is a \i\ubrowse\c of a \bsingle-dimensional\c array of objects:\n' FORMATTED ;
   SAYSIZE 0 FONT '10.Lucida Console'

@ 13,0 DCBROWSE oBrowse2 DATA aData2 SIZE 20,10 FIT ;
       RESIZE DCGUI_RESIZE_RESIZEONLY_X

DCBROWSECOL OBJECTVAR cust_nmbr HEADER 'ID'       WIDTH  5 PARENT oBrowse2
DCBROWSECOL OBJECTVAR bill_name HEADER 'Name'     WIDTH 15 PARENT oBrowse2
DCBROWSECOL OBJECTVAR {|o|Upper(Trim(o:bill_strt))} HEADER 'Address'  WIDTH 15 PARENT oBrowse2
DCBROWSECOL OBJECTVAR {|o|Trim(o:bill_city)} HEADER 'City'     WIDTH 10 PARENT oBrowse2
DCBROWSECOL OBJECTVAR bill_zip  HEADER 'Zip'      WIDTH  4 PARENT oBrowse2

@ 24,0 DCPUSHBUTTON CAPTION 'Browse Objects in GetList' SIZE 20 ;
       ACTION {||BrowseGetListObjects(GetList)}

DCGETOPTIONS RESIZE

DCREAD GUI FIT ADDBUTTONS TITLE 'Browse array of objects' TO lStatus ;
   SETAPPWINDOW OPTIONS GetOptions

IF lStatus
  FOR i := 1 TO Len(aData1)
    oRecord := aData1[i,1]
    nRecno := aData1[i,2]
    CUSTOMER->(dbGoTo(nRecno))
    CUSTOMER->(DC_DbGather(oRecord))
  NEXT
ENDIF

RETURN nil

PROC appsys; return

* -----------

STATIC FUNCTION BrowseGetListObjects( aGetList )

LOCAL GetList[0], oBrowse

@ 0,0 DCBROWSE oBrowse DATA aGetList SIZE 20,20 FIT

DCBROWSECOL DATA {||oBrowse:arrayElement} HEADER 'Nmbr' WIDTH 3 PICTURE '9999' PARENT oBrowse

DCBROWSECOL DATA {||DC_GetListType(aGetList[oBrowse:arrayElement,nGETLIST_TYPE])} ;
   HEADER 'Type' WIDTH 15 PARENT oBrowse

DCBROWSECOL DATA {||aGetList[oBrowse:arrayElement,cGETLIST_CAPTION]} ;
   HEADER 'Caption' WIDTH 15 PARENT oBrowse

DCBROWSECOL OBJECTVAR className() ELEMENT oGETLIST_OBJECT ;
   HEADER 'Class Name' WIDTH 10 PARENT oBrowse

DCBROWSECOL OBJECTVAR setParent() ELEMENT oGETLIST_OBJECT ;
   HEADER 'Parent' WIDTH 10 PARENT oBrowse

DCBROWSECOL OBJECTVAR currentSize()[1] ELEMENT oGETLIST_OBJECT ;
   HEADER 'Width' WIDTH 3 PARENT oBrowse PICTURE '9999'

DCBROWSECOL OBJECTVAR currentSize()[2] ELEMENT oGETLIST_OBJECT ;
   HEADER 'Height' WIDTH 3 PARENT oBrowse PICTURE '9999'

DCBROWSECOL OBJECTVAR currentPos()[1] ELEMENT oGETLIST_OBJECT ;
   HEADER 'Col' WIDTH 3 PARENT oBrowse PICTURE '9999'

DCBROWSECOL OBJECTVAR currentPos()[2] ELEMENT oGETLIST_OBJECT ;
   HEADER 'Row' WIDTH 3 PARENT oBrowse PICTURE '9999'

DCBROWSECOL OBJECTVAR setFontCompoundName() ELEMENT oGETLIST_OBJECT ;
   HEADER 'Font' WIDTH 15 PARENT oBrowse



DCREAD GUI FIT TITLE 'Browsing GetList' MODAL

RETURN nil

* ------------

FUNCTION EditRecord( oRecord )

LOCAL getList[0]

@ 0,0 DCSAY 'Billing Name' GET oRecord:bill_name
@ 1,0 DCSAY 'Billing Street' GET oRecord:bill_strt

DCREAD GUI FIT TITLE 'Editing Data' ADDBUTTONS ENTEREXIT TO lStatus

IF lStatus
  CUSTOMER->(DC_DbGather(oRecord))
ENDIF

RETURN nil


User avatar
rdonnay
Site Admin
Posts: 4802
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: @ DCBROWSE ....RECORDOBJECT <oRecord>

#2 Post by rdonnay »

This is true. All classes in Xbase++ are dynamically created, but those created by ClassCreate() can be destroyed.

If you intend to use the same alias name for different databases, then you should ClassDestroy() on the class created by DC_DbRecord() before calling DC_DbRecord() again with a different data structure but the same alias. This is true even if you have databases opened in different threads, because dynamically created classes are not thread-safe.

You can pass the name of the class to be created and give it any name you want, but by default it will be DATA_ + Alias().

It is not problematic to fail to destroy a class created by DC_DbRecord(). It really is not necessary. In fact, it is best that the class NOT be destroyed because DC_DbRecord() will likely be used with the same database later in the program. If the class already exists, it will not be created. You could write a wrapper function that calls DC_DbRecord() and saves away the record object onto a stack (an array), end then call a function that destroys all the classes when closing the databases.
The eXpress train is coming - and it has more cars.

Post Reply