Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Createobject
Message
From
26/12/2002 09:46:57
Cetin Basoz
Engineerica Inc.
Izmir, Turkey
 
 
To
26/12/2002 04:45:39
Victor Verheij
International Film Festival Rotterdam
Rotterdam, Netherlands
General information
Forum:
Visual FoxPro
Category:
Coding, syntax & commands
Title:
Miscellaneous
Thread ID:
00735703
Message ID:
00735819
Views:
8
>Maybe I'm going about this the wrong way.
>
>I'm trying to figure out the best way to make an application wich makes use of toolbars. My problem was how to disable/enable certain buttons on certain bars. The only way I could think of is by making the bar een object off my custom class goapp, that way I could refence it like: goapp.oMyTbr.cmdSave.enabled = .t. I now know this wasn't very bright of me as i could also reference it if i created this object with createobject()
>
>However, I have a releted problem. How do i reference another form, if i have a modal form from wich i want to pass a value to the main form.
>These forms are not instantiated classes.
>
>Thanks, Victor.

Toolbars management has always been complex for me too :( Any form might need more than one toolbar, any 2 or more forms might need the same toolbar and any form might need different enabled/disabled state for the buttons. To make it worse a toolbar doesn't only have buttons to enable/disable but many other controls like dropdowns that should be updated per form maybe.
Tastrade sample has an application object with some toolbar management code - though it needs to control only one type of toolbar might give idea. _systoolbars of _app.vcx foundation class is another one managing toolbars.
goApp class sounds to be the best place for the management. I support goApp with toolbar custom methods which are fired with its properties' assign methods (or directly assign code does that). ie: A navigator toolbar.EditMode property assign calls its parent method to enable/disable, change picture/caption of related buttons.
Baseform class has a property called cToolbarLst keeping a comma separated name list of toolbars for a form. In init form simply sets its custom property uniqueID to sys(2015). UniqueID_assign method calls goApp.ShowToolbars(this.cToolbarLSt,vNewVal) and in form.destroy goApp.ReleaseToolbars(this.cToolbarLst,this.UniqueID) is called. goApp has arrays keeping track of form.UniqueID, toolbars list and also another array for the state of toolbars. If a form is coming into view and one or more of its toolbars is not in toolbars array, add to array creating the toolbar and shows. If a form calls ReleaseToolbars, its UniqueID is removed from forms array, its toolbar list is checked and only toolbars not used by any other form are released clearing their references from toolbars array.
Form.Activate calls goApp.UpdateToolbars('Editmode',this.Editmode,this.cToolBarLst), goApp simply walks through its toolbars making a setall('Editmode',passedValue) and also uses list to hide/show toolbars.
With VFP8's new collection class I think all these management will be more easier to control.


Referencing to another form could be made by either name or passing form obj.ref. as a parameter (and some other methods that's not reliable all the time). ie:

do form Form1 name frm1
do form Form2 && Modal

Since scope is reserved till modal form returns you could reference Form1 as frm1. I wouldn't suggest this as it's related to variable's scope.

do form Form2 with thisform

OTOH is a reliable method. Called form might be modal or not.

*Called form.init - has custom property oCaller
lparameters toCaller
this.oCaller = toCaller

* Any method/event of called form could do this
with this.oCaller
 .AnyProperty = 'SomeValue'
 .AnyObject.Value = 'SomeValue'
 AValue = .AnyObject.AnyProperty
 .AnyMethod(ParamList)
endwith
One another unreliable method is to use caller form's scx name as reference. ie: If form1's scx is myform.scx :

myForm.Somethod()
myForm.AnyObject.AnyProperty = 'SomeValue'

This is not reliable because only first instance of form1 could be referenced this way and behaviour might change between versions.

_screen.forms collection could be used too but hard since multiple instances of a form has same name (if not explicitly changed) and forms collection changes as the order of forms show sequence changes (ie: forms[1] is not always the same form if user activates forms in irregular sequence - forms[1] is always the last form shown, though with a modal form coming up this wouldn't be a problem and caller is forms[2]).

One question should be asked here. Do you need to reference of the caller for the task you need. Modal forms could pass back a parameter in unload event and it's just one parameter. What if you need to pass multiple values back ? Need to pass caller ref. in this case ? Well you might but not necessary. You can pass back just one thing, right but that could be a string wrapping multiple values, an object or you could be messaging with an array. For these scenarios you'd design in such a way that both the caller anmd called forms know what to pass and what to expect to get back. Suppose we have a modal form related with reporting where you ask the user destination (printer,screen,cursor,graph as 1,2,3,4), filter on field 1 - 4 values, startdate, enddate (field1 char, field2 int, field3 date, field4 datetime).

-String wrapping multiple values
*Modal form.Unload
return ;
 trans(this.Destination.value)+chr(13)+;
 this.field1filter.value+chr(13)+;
 trans(this.field2filter.value)+chr(13)+;
 dtoc(this.field3filter.value,1)+chr(13)+;
 ttoc(this.field4filter.value,1)+chr(13)+;
 ttoc(this.StartDate.value,1)+chr(13)+;
 ttoc(this.EndDate.value,1)

*Caller form
local lcRetStr, lnDestination, ;
  lcFilter1, lnFilter2, ldFilter3, ltFilter4, ldStartDate, ldEndDate
do form GetRepParams to lcRetStr && Calls the modal form
* Parses on return
local array arrRetVals[1]
if alines(arrRetVals,lcRetVAl) = 7 && Expecting back 7 values wrapped
  lnDestination = val(arrRetVals[1])
  lcFilter1     = arrRetVals[2]
  lnFilter2     = val(arrRetVals[3])
  ldFilter3     = ctod(trans(arrRetVals[4],'@R ^9999/99/99'))
  ltFilter4     = ctot(trans(arrRetVals[5],'@R ^9999/99/99 99:99:99'))
  ldStartDate   = ctod(trans(arrRetVals[6],'@R ^9999/99/99'))
  ldEndDate     = ctod(trans(arrRetVals[7],'@R ^9999/99/99'))
else && error handling - only development phase should need this if block
endif
-Array
*Modal form.Unload or might be OKbutton click, release etc whereever you like
arrRetVals[1] = this.Destination.value
arrRetVals[2] = this.field1filter.value
arrRetVals[3] = this.field2filter.value
arrRetVals[4] = this.field3filter.value
arrRetVals[5] = this.field4filter.value
arrRetVals[6] = this.StartDate.value
arrRetVals[7] = this.EndDate.value

*Caller form
dimension arrRetVals[7]
do form GetRepParams && Calls the modal form - array is in scope
* On return 
local lnDestination, lcFilter1, ;
  lnFilter2, ldFilter3, ltFilter4, ldStartDate, ldEndDate
lnDestination = arrRetVals[1]
lcFilter1     = arrRetVals[2]
lnFilter2     = arrRetVals[3]
ldFilter3     = arrRetVals[4]
ltFilter4     = arrRetVals[5]
ldStartDate   = arrRetVals[6]
ldEndDate     = arrRetVals[7]
-Object (this is my favourite if I want to pass and get values)
*Modal form.init
lparameters toCargo
this.oCargo = toCargo && To keep in scope

*Modal form assigns controlsources such as
* could do in init code or directly using PEM sheet
with this
  .Destination.controlsource  = "this.oCargo.Destination" 
  .field1filter.controlsource = "this.oCargo.Filter1"
  .field2filter.controlsource = "this.oCargo.Filter2"
  .field3filter.controlsource = "this.oCargo.Filter3"
  .field4filter.controlsource = "this.oCargo.Filter4"
  .StartDate.controlsource    = "this.oCargo.StartDate"
  .EndDate.controlsource      = "this.oCargo.EndDate"
endwith

*Caller form
local loCargo
create cursor dummy (Destination i,Filter1 c(10),Filter2 i,;
  Filter3 d,Filter4 t,StartDate d,EndDate d)
scatter name loCargo blank
use in 'dummy'
do form GetRepParams with loCargo && Calls the modal form
* On return has all the values in loCargo as property values.
* ie: loCargo.Destination
Yet another and effective way is not to return params but query from modal form objects. ie: Given the above report parameters modal form sample :
*Modal form is designed with no special code
* other than OK and Cancel button
*OK button code
thisform.hide()

*Cancel button code
thisform.tag = 'User Cancelled'
thisform.hide()

*Caller form
local loRepParams
do form GetRepParams name loRepParams && Calls the modal form
* Returns here as modal form is hidden - but it still exists
* On return query modal form's object values
* ie: 
if loRepParams.Tag = 'User Cancelled' && Take action for cancel
*...
else
 lnDestination = loRepParams.Destination.Value
 *...
 ldStartDate   = loRepParams.StartDate.Value
endif
loRepParams.release() && Release the modal form
PS: Sergey is right to avoid macro substitution. On an average 600-800 Mhz computer, if you create around 50K objects you get approximately one second performance penalty. Use store instead.
Cetin
Çetin Basöz

The way to Go
Flutter - For mobile, web and desktop.
World's most advanced open source relational database.
.Net for foxheads - Blog (main)
FoxSharp - Blog (mirror)
Welcome to FoxyClasses

LinqPad - C#,VB,F#,SQL,eSQL ... scratchpad
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform