Traduzione di Antonio Campagna - Marzo 2000

(c) 1995 A.A.Katz, All Rights Reserved

 FORMVARS.HOW

di A.A.Katz

 Ultima modifica 28-10-1995

 



Introduzione

lo scopo principale di questo documento, è aiutare il programmatore di Visual dBASE a gestire i dati che vuole inviare o condividere tra le schede. Suppongo che la via più facile e più veloce per aiutarti, sarebbe quella elencare una serie di regole piuttosto che trattare molta teoria. Ma, se non comprendi l'interazione tra variabili, parametri, proprietà ed oggetti, sei destinato prima o poi "sbattere contro il muro".

Probabilmente prima!

Presumo che hai un minimo di esperienza, sia con Visual dBASE sia con un linguaggio  di programmazione procedurale. Ma, anche se sei un programmatore esperto in linguaggi orientati agli oggetti, non saltare le "parti teoriche" all'inizio di questo How To. L'implementazione dell'OOP di Visual dBASE, può essere molto diversa da altri linguaggi OOP che hai usato nel passato.


Il Problema con le Variabili

Le variabili e OOP non coesistono particolarmente bene. Le variabili sono dichiarate nelle procedure, le quali ne definiscono sia la visibilità sia il tempo di vita.

Considera una variabile privata:

Visibilità e durata di una variabile privata, sono interamente dipendenti dalle relazioni tra le procedure. In OOP, le suddette relazioni non esistono, perché gli oggetti non sono procedure. Gli oggetti sono entità indipendenti, "galleggianti" nello schermo del tuo utente o appostati in memoria ad attendere una chiamata ad i loro metodi. Gli oggetti non sono sottoprogrammi. Non puoi fare in modo che gli oggetti "ritornino" alle procedure dove sono stati creati.

In verità, gli oggetti non fanno "chiamate" a nessuno. Essi sono "Istanziati", creati al volo da una Classe "modello". Ogni oggetto definito, è detto essere una "istanza" di una Classe.

Puoi creare un qualsiasi numero di oggetti da una singola Classe: dieci diversi Entryfields dalla Classe Entryfield, dieci schede diverse dalla classe Form - ciascuno con attributi e comportamenti diversi. Ed è questo potenziale di istanze multiple di una Classe, che pone il più grande problema usando le variabili con le schede. Se immetti un dato nell' Entryfield1, certamente non vuoi che il dato venga visualizzato nell'Entryfield6. Se cambi il valore di CustNo nella scheda 1, certamente non vuoi che cambi il valore di CustNo nella scheda 2.

Per proteggere un oggetto dalla sovrascrittura da parte di un altro oggetto,  esso viene "incapsulato"- cioè isolato e protetto da tutti altri oggetti. Il risultato è che incapsulando gli oggetti "proteggi" le variabili da essere viste o cambiate da qualche altro oggetto.

Una variabile dichiarata in un metodo di Pushbutton1, non è visibile al Pushbutton2. Non è cioè "alla portata." Una variabile dichiarata nell'evento OnOpen di una scheda è totalmente invisibile ad ogni altro oggetto nella stessa scheda.

Suggerimento

Quando si sta studiando la programmazione Object-Oriented, c'è la tendenza a ricorrere alle tecniche procedurali per cercare di superare queste nuove sfide. Non è insolito per un nuovo programmatore OO cercare di usare variabili Pubbliche per superare le restrizioni imposte dalla incapsulazione.  Non farlo!!! Le variabili pubbliche hanno i loro particolari problemi in OOP. Possono essere referenziate o sovrascritte da qualsiasi parte nel tuo programma. Una nuova istanza di un oggetto può facilmente sovrascrivere una variabile dichiarata in un'istanza precedente.Evita l'uso di variabili Pubbliche con le schede ed altri oggetti.

 


 

Quando Usare Variabili

Usare o non usare le variabili non è un "religioso" problema. le variabili non sono ancora passate alla storia. Hanno ancora una grande importanza nei metodi degli oggetti. I "Metodi" sono procedure e funzioni incapsulate in un oggetto. Essi si occupano del "comportamento" dell'oggetto. Malgrado il nuovo nome ed il collegamento al loro oggetto genitore, i metodi sono ancora procedure e funzioni.

variabili in metodi:

Procedure Pushbutton1_OnClick

Local cVar

cVar = substr(Form.Combobox1.Value+space(35),1,35)

Sele MyTable

Seek cVar

O in macro:

Procedure PushButton1_OnClick

Private n,cNum

For n = 1 to 3

cNum = str(n,1)

Sele table

Repl Field&CNum. with Form.Entryfield1.value

EndFor


Il Problema con i Parametri

I parametri sono dati inviati direttamente tra processi (in Visual dBase, i processi sono procedure, oggetti e funzioni). Diversamente dalle variabili, il  "parametro" è inviato esplicitamente. L'oggetto o la procedura, alla quale passiamo un parametro deve avere una struttura predefinita per riceverlo ed usarlo. Alcuni processi(procedure o funzioni) hanno già queste strutture predefinite. Space(), ha come parametro una espressione numerica che restituirà tanti spazi quanti indicati, cosi come Keymatch(), Recno() e tutte le altre funzioni predefinite. Non puoi aggiungere un parametro alle funzioni predefinite. Lo stesso discorso vale per la Classi Standard Predefinite. I soli parametri che puoi inviare ad un oggetto, istanziato da una classe Standard di Visual dBASE (come Form, Menu, Pushbuttons ed Entryfields) sono quelli predefiniti stabiliti da Borland.

In breve, non puoi passare "i tuoi" parametri ad una Classe predefinita o ad un evento per una classe derivata da una predefinita.

Suggerimento

Le Classi Custom sono un'eccezione degna di nota. Queste Classi, simili alle UDFs, non hanno parametri predefiniti. I Parametri sono specificati ed usati da te, il programmatore. Puoi inviare come parametri qualunque dato tu desideri ad una classe custom con la sintassi seguente:

Class MyClass (Var1, Var2, Var3)

Ma non puoi inviare i tuoi dati come parametri tanti ad una Classe Custom derivata da un'altra

Class MyButton(f,n) of Pushbutton(f,n)

L'esempio sopra ha due parametri predefiniti: (f) cioè una scheda - così la Classe Custom sa quale Scheda è suo genitore, e (n) cioè un nome - così che un oggetto derivato dalla Classe può essere referenziato tramite il nome.  Non puoi aggiungere parametri addizionali alla Classe MyBbutton.Essi non saranno accettati.

Lo stesso discorso vale se passi un parametro ad una Scheda, non servirebbe a nessun scopo. Una volta che un parametro è passato, diviene una variabile. Come abbiamo evidenziato precedentemente, l'incapsulazione renderà la tua variabile inutile. non sarebbe visibile dovunque ne avresti bisogno.


Quando puoi Usare Parametri

Puoi usare i parametri liberamente, come le variabili, nei metodi delle schede. I metodi ricevono i parametri nel medesimo modo delle procedure o funzioni non OOP.

Class::SetFields(.t.)                         && chiama un metodo della scheda

Procedure SetFields(lSwitchOn)  && Parametro ricevuto attraverso un metodo

Form.Entryfield1.Enabled = lSwitchOn

Form.Entryfield2.Enabled = lSwitchOn

Form.Entryfield3.Enabled = lSwitchOn

Form.Combobox1.Enabled = lSwitchOn

Puoi passare parametri da qualsiasi oggetto su una scheda a qualsiasi altro metodo, procedura o funzione.

Puoi passare variabili, calcoli, o proprietà dei tuoi oggetti  per riferimento o per valore.

Procedure Pushbutton1_OnClick

        Form.Entryfield1.Value = Upper(Form.Entryfield1.Value) && Proprietà inviata ad una funzione predefinita

        MyFunc(Form.Entryfield1.value - Form.Entryfield2.Value) && Calcolo inviato ad una UDF

        CLASS::Recalc(Form.Entryfield1.Value)                         && Proprietà inviata ad un metodo della classe


Il Problema con i files .WFM

Una cosa che non puoi fare, è passare parametri ad una scheda quando chiami un file .WFM con il comando:

Do My.WFM with .f.,MyData     && non passerà parametri!

Il .WFM è un nuovo tipo di file la sua prima apparizione é stata con dBASE 5 for Windows. E' un tipo di file ibrido - infatti  é sia eseguibile sia "contenitore" per le definizioni di Classe. Questo file multi-scopo può generare  confusione quando cerchi di immaginare il flusso dei tuoi dati.

La tabella seguente può aiutarti nel comprendere i contenuti del .WFM ed il flusso di codice che verrà eseguito quando immetti il comando: 

Do My.WFM.

Il file .WFM è composto da cinque sezioni:

Sezione

Scopo

1. La Testata - tutto il codice al di sopra della linea:

 ** END HEADER Do Not Remove this line

Qualsiasi codice immesso in questa sezione sarà eseguito per primo quando il .WFM è chiamato.

Il codice in questa sezione non sarà sovrascritto da "Impostazione scheda"

2. Codice di Istanza:

Local f 

    f = new Myform()

    if bModal  

        f.MDI = .f. 

        f.ReadModal() 

    Else 

        f.Open()

    Endif 

Questo codice sarà eseguito per secondo quando il .WFM è chiamato. crea un oggetto dalla definizione della Classe nel .WFMe memorizza il suo indirizzo in una variabile locale (f).

Il codice in questa area sarà sovrascritto da Impostazione scheda

3. Codice Costruttore della Classe

Classe Myform of Form() 

Define...

Define...

Define...

Questo codice non verrà eseguito quando il .WFM è chiamato

Questo è la "copia" che sarà usata quando un oggetto è  creato usando "New Myform()".

Puoi aggiungere oggetti (DEFINE), cambiare i valori delle proprietà (Heigth 1.06), aggiungere chiamate a funzioni puntatori (Classe:: Form_onOpen). non puoi aggiungere proprietà custom o codice eseguibile in questa area.

Questi saranno sovrascritte da Impostazione scheda.

4. Metodi - tutto dopo l'ultimo DEFINE: 

Procedure FORM_OnOpen 

....................

Procedure Pushbutton1_OnClick 

.........................

EndClass 

Questo codice non é ESEGUITO quando il .WFM è chiamato. Questa area contiene le procedure e le funzioni che descrivono il comportamento dell'oggetto. (Metodi) Questo codice non sarà soprascritto da Impostazione Scheda a meno che tu non lo cambi con l'editor di procedure

5. Generale 

Questo codice non è eseguito quando il .WFM è chiamato.

Questa sezione è utile per memorizzare le UDFs o le procedure che non sono metodi della tua Classe, ma che possono essere chiamate dall'interno della Classe. Il Codice in questa area non sarà sovrascritto da Impostazione Scheda.

  

Come avrai notato dalla tabella il codice tra Class...Endclass non é mai eseguito.

Esso é letto da Visual dBASE ogni volta che un oggetto è creato da questa Classe, ma è ignorato completamente quando il .WFM é in esecuzione.

Un oggetto viene in essere solo quando è istanziato - creato dalla Classe "Modello".

Perciò le Variabili dichiarate nei files .WFMs o parametri passati ai files .WFMs non hanno effetto con la scheda attuale.

La scheda non esiste ancora.

 

Suggerimento: 

Non c'è ragione perché una definizione di Classe debba essere fatta in un .WFM. essa può essere fatta in qualsiasi files su disco è caricata in memoria con SET PROCEDURE. Il formato .WFM esiste per convenienza per rendere più facile la ricerca dei files di scheda sia per te sia per Navigator. Infatti le sezioni seguenti dimostreranno che puoi inserire il codice di istanza in altri oggetti. E'  comune convenzione in Visual dBASE istanziare una scheda figlia dall'interno della sua scheda genitore senza mai il chiamare il file .WFM.

 


La Soluzione: Le Proprietà

I linguaggi orientati agli oggetti hanno una nuova struttura dati chiamata "Proprietà." Le Proprietà sono contenitori di dati simili alle variabili. Ma, diversamente dalle variabili, esse sono associate (attaccate) ad un oggetto. Le Proprietà sono i dati dell'oggetto, definiscono cioè gli attributi degli oggetto:

This.Height=27
This.ColorNormal="B/W"
This.StartingNum=1
This.MDI=.f.

Dovresti pensare alle proprietà come variabili che sono visibili a loro oggetto genitore e indirizzate direttamente tramite il loro "albero genealogico."

Proprietà:Height(numerico)

Genitore:Pushbutton1
Nonno:Form
Form.Pushbutton1.Height
Proprietà:Height
(numerico)
Genitore:Form
Form.Height



Questo stile di indirizzamento ad albero genealogico è chiamato "Notazione-Punto."

Utilizzando la Notazione Punto, ogni oggetto può essere referenziato o modificato da qualsiasi parte del programma - da ogni altro oggetto, procedura o funzione- tramite la conoscenza dell' "albero genealogico" dell'oggetto. Visual dBASE fornisce un generico "riferimento predefinito" da sostituire per gli oggetti di cui il "lignaggio" non è conosciuto durante la progettazione della scheda.

 This  é  il "riferimento predefinito" che sostituisce l'indirizzo del corrente oggetto in esecuzione:

Procedure FORM_OnOpen

    This.Height = 20 && "This" si riferisce alla scheda (Form)

Procedure Pushbutton1_OnClick

    This.Height = 2 && "This" si riferisce al Pushbutton1

Form è il riferimento generico che si riferisce  sempre alla scheda genitore dell'oggetto corrente:

Procedure FORM_OnOpen

    Form.Height = 20 && Riferimento alla scheda (Form)

Procedure Pushbutton1_OnClick

    Form.Height = 20 && Ancora riferimento alla scheda

 

Suggerimento

Dovunque puoi usa le proprietà invece delle variabili.

Puoi emulare anche variabili Pubbliche per attaccare proprietà custom all'oggetto applicazione (_app) predefinito di Visual dBASE.

"_app.MyCustomProperty" 

è visibile da ogni procedura, funzione ed oggetto nel programma.

Ma usa queste proprietà globali con attenzione - puoi sovrascrivere una proprietà che hai attaccato all'oggetto applicazione ( _app ) così facilmente come sovrascrivere il valore di una variabile pubblica.

 

Visual dBASE supporta le "proprietà dinamiche." Molti OO linguaggi ne sono sprovvisti. Le "Proprietà dinamiche" sono proprietà aggiunte al volo, dopo un che oggetto è stato creato. Questa capacità è estremamente preziosa per le "comunicazioni tra processi,".

Suggerimento 

Non puoi creare proprietà dinamiche nella sezione del codice Costruttore (Define) della Classe. Hai due luoghi possibili dove puoi aggiungere proprietà dinamiche (qualche volta chiamate custom):

  1.  Nell'evento OnOpen della tua scheda; 

  2.  Dopo l'istanza ma prima dell'apertura (open()) della tua scheda.

Per ragioni estetiche é quasi sempre meglio aggiungere una proprietà dinamica

prima dell'apertura (Open()) della scheda. Se usi l'evento OnOpen, la scheda può appena "sedersi sullo schermo" non facendo niente, mentre le nuove proprietà sono create. Se le proprietà dinamiche sono relative ad oggetti da visualizzare sul monitor, potrai vedere un addizionale refresh prima che la  scheda si stabilizzi.

Creando le proprietà prima che la scheda venga aperta (Open()), ogni cosa é impostata prima che la scheda sia visualizzata sul video.  

Cosa fare per una visualizzazione "pulita" della scheda.

1. Proprietà dinamiche  nell'evento OnOpen di una scheda

Procedure Form_OnOpen

     This.Firstname = 'Alan'                     && Crea una proprietà dinamica  nel  metodo OnOpen di una scheda

Form.Pushbutton1.MyData = 'Alan'   && Crea una proprietà dinamica di un oggetto su una scheda.

2. Proprietà dinamiche create  prima che la scheda sia aperta (open())

Procedure CallNewFormButton_OnClick

      Set Proc to New.Wfm Additive

      Form.oChild = New NewForm()

      Form.oChild.FirstName = 'Alan' && Crea una proprietà dinamica di una scheda prima della sua apertura

     Form.oChild.Pusbutton1.MyData = 'Alan' &&  prop. dinamica di un ogg. su una scheda prima della apertura

      Form.oChild.Open()  && apertura della scheda

 

 


 

Il riferimento oggetto (Istanza)

Già abbiamo stabilito che puoi fare riferimento alle  proprietà di ogni oggetto, se conosci il suo "albero genealogico". Le variabili predefinite "This" e "Form" facilitano l'identificazione dell'oggetto corrente e della scheda che lo contiene. Comunque, se stai guardando un oggetto "dall'esterno" del suo contesto non è facile identificarlo. E' tutta una questione di prospettiva.

Se ti trovi nella mia cucina e vuoi conoscerne il colore, devi solo domandare:

Di che colore é questa stanza?

Ma, se ti trovi nel mio ufficio e vuoi conoscere il colore della mia cucina, dovrai chiedere più informazioni per capire a quale cucina in particolare ti riferisci:

Di che colore é la cucina a casa di Alan ?

L'informazione richiesta per riferirsi al colore della mia cucina varia in funzione del luogo ove "ti trovi". Lo stesso discorso vale  per riferirsi alle proprietà di una scheda.

Per riferirsi ad una scheda o ad un suo oggetto, dall'interno di essa, usa "This" o "Form,".

Per riferirsi ad una scheda dall'esterno di essa, devi conoscere l'unico identificatore di quella particolare istanza della scheda.

In sintesi hai bisogno di conoscere l' "indirizzo" dell'oggetto come per  "la cucina di Alan nella sua casa di New York"

In Visual dBASE ogni oggetto ha un unico indirizzo chiamato Riferimento Oggetto. Ciascun pulsante ha il suo proprio riferimento, distinto da ogni altro pulsante.Ciascuna istanza di una scheda ha il suo proprio riferimento, distinto da ogni altra istanza della stessa scheda e di ogni altra scheda.

Suggerimento

Quando si parla di "riferimento oggetto", oppure di  "istanza di riferimento",  in entrambi i casi si parla esattamente della stessa cosa.

Il riferimento oggetto è restituito automaticamente da Visual dBASE ogni qualvolta un oggetto è istanziato.

oMy = New MyForm()  && Crea un nuovo oggetto, memorizza l'indirizzo nella variabile di riferimento oggetto "oMy"

Il Riferimento Oggetto, é un nuovo tipo di dato (tipo "O"), può essere passato, copiato e gestito in modo simile alle stringhe, alle date, ai valori logici ed ai valori numerici. Può essere memorizzato in modo simile agli altri tipi di dati: tramite variabile. Puoi memorizzare il riferimento oggetto di una scheda in una variabile, ed in questo caso è chiamata variabile di riferimento oggetto.

Private oMy

oMy = New MyForm() && Riferimento memorizzato nella variabile "f"

oMy.Open()

Proprietà:  puoi memorizzare il tuo riferimento oggetto in una proprietà di un altro oggetto:

Form.oChild.oMy = New MyForm() &&Riferimento memorizzato in una proprietà della scheda

Form.oChild.oMy.Open()

Proprietà globale: puoi memorizzarlo in una proprietà dinamica dell'applicazione stessa:

_app.oMy = New MyForm() &&Riferimento memorizzato nella proprietà _app

_app.oMy.Open()

Elemento di array:  puoi memorizzarlo in un elemento di un array:

aForms[1] = New MyForm() && Riferimento memorizzato in un array

aForms[1].Open()

  Suggerimento

 In casi speciali il riferimento può essere memorizzato usando il nome della proprietà dell'oggetto piuttosto che un riferimento oggetto esterno ma solo quando l'oggetto è "contenuto" in una scheda:

Define Pushbutton Pushbutton1 Of  This     && il riferimento é adesso   Pushbutton1

Il comando NEW restituisce sempre un riferimento oggetto esterno. Il comando DEFINE usa il nome della proprietà come riferimento oggetto.

Per leggere una proprietà di una scheda dall'esterno di essa, usa il riferimento oggetto per stabilire l' "albero genealogico":

Prospettiva: esterna alla scheda:

oMyForm.Myvar = 'Hello'

oMyForm.Pushbutton1.Height = 2

Prospettiva: Interna alla scheda:

Form.MyVar = "Hello'

Form.Pushbutton1.Height = 2

Il riferimento oggetto può anche essere usato per determinare lo "status" di una scheda. Per valutare (test) se una variabile è un riferimento oggetto:

? Type('form.oMyForm')   && restituisce "O" se l'oggetto esiste

Per valutare se un oggetto è istanziato:

? Empty(Form.oMyForm)   && Se Empty() restituisce .t., l'oggetto non é istanziato

Valutare se una scheda è aperta:

? Form.oMyform.wHnd   && se "handle" è > 0, la scheda é aperta

Suggerimento 

Type() restituisce "O" su un riferimento oggetto anche quando é stato rilasciato.

Il riferimento oggetto è ancora un riferimento oggetto sebbene esso non contenga un oggetto valido.

Per rendere più agevole il test sullo status di una scheda, ti devi sbarazzare completamente del riferimento quando rilasci un oggetto, cambiando il il valore della variabile, della proprietà o dell'array :

Form.oMyForm = '' oppure

Form.oMyForm = .f. oppure

_app.aForms[1] = ''

 


Dove memorizzare il riferimento oggetto

La risposta a questa domanda è un buon argomento per un lungo libro. Le strutture che usi per memorizzare i riferimenti oggetto, dipendono interamente dalle necessità della tua applicazione.Selezionare e gestire queste strutture dovrebbe divenire un passo integrante di tutti i tuoi futuri progetti di applicazioni. Alcuni programmatori di Visual dBase, creano le loro Classi custom per gestire i riferimenti alle schede. Se crei o no classi custom, devi stabilire una strategia, così  conoscerai sempre come accedere ad ogni scheda nel tuo programma. E' imperativo memorizzare, i tuoi riferimenti in strutture dati accessibili. Se non puoi trovare una variabile , una proprietà, o un array contenente gli indirizzi delle tue schede, non puoi accedere alle tue schede dall'esterno. Il tuo riferimento oggetto DEVE ESSERE ALLA PORTATA!

Ecco alcuni suggerimenti. Sono appena suggerimenti, non regole. La tua struttura dati finale deve essere determinata dalla tua applicazione.

Considera i suggerimenti seguenti come linee guida:

 Istanza singola

Se stai creando una scheda SDI - Schede delle quali ci sarà solo una singola istanza - puoi usare una proprietà dell'oggetto applicazione (_app) per memorizzare i tuoi riferimenti:

_app.oCust = New CustomerForm() && Istanza .

_app.oCust.Pushbutton1.height = 2 && Riferimento.

_app.oCust.Open() && Apertura.

Questo è simile alla memorizzazione del tuo riferimento oggetto in una variabile Pubblica.

Istanze Multiple

Se stai scrivendo un programma MDI - dove ci possono essere istanze multiple di una scheda, ti suggerisco fortemente di memorizzare i riferimenti oggetto della scheda in un array. Non hai modo di conoscere durante la fase di  progettazione, quante istanze alla scheda l'utente avrà contemporaneamente sullo schermo. Un array è una struttura, che può "crescere" per memorizzare ciascun nuovo Riferimento Oggetto, quando l'utente lancia una nuova scheda.

_app.aForms = New Array()                            && Dichiara un array.

_app.aForms.Grow(1)                                       && aggiunge un elemento per ciascuna istanza

_app.aForms[1] = New CustomerForm()       && Istanza...

_app.aForms[1].Pushbutton1.Height = 2       && Riferimento...

_app.aForms.Open()                                         && Apertura.

Quando chiamare una finestra di dialogo modale

Se stai "chiamando" un finestra di dialogo, ti suggerisco di memorizzare il Riferimento Oggetto in una proprietà custom della scheda genitore.

Form.oChild = New CustomerForm()           && Istanziata dentro una proprietà Custom.

Form.oChild.Pushbutton1.height = 2          && riferimento.

Form.oChild.ReadModal()                            && Apertura


Dove Instanziare la tua scheda

 Se chiami le tue schede con "Do My.WFM," usi probabilmente il codice di istanza di default generato da Impostazione Scheda per creare ed aprire la tua scheda:

Local f

Param bModal

f = New MyForm()

If (bModal)

f.MDI = .f.

f.ReadModal()

Else

f.Open()

Endif

 

Questo codice è meraviglioso per il collaudo del programma, esso incapsula l'oggetto creato e lo  protegge da tutte le altre schede o istanze.

Ma, ciò ha "un costo" enorme. La sua variabile di riferimento oggetto , "f," è Locale!

Come sai una variabile locale, non può essere indirizzata da nessun altra scheda, oggetto, procedura o funzione nel tuo programma.

Suggerimento

Dovresti prendere l'abitudine sin dall'inizio della scrittura del tuo codice di istanza di lasciare che Impostazione Scheda usi il suo codice di default nelle fasi di progettazione visuale.Ma di non farne affidamento per lanciare le tue schede dall'interno del tuo programma.

 

Così se non puoi usare il codice default di impostazione scheda, come devi fare ?

Ci sono due opzioni:

1. Instanziare le tue schede dall'interno del file .WFM

Utilizzare l'area della testata del file .WFM (Header) cioè quella che si trova al di sopra della linea:

**End Header Do not Remove This Line

Questa area è disponibile per il tuo codice di istanza. Impostazione scheda non sovrascriverà il codice header. Usa quest'area per istanziare la tua scheda e ricorda di aggiungere un "return" nell'ultima linea. Se non fai così , il file .WFM continuerà ad essere eseguito istanziando così la tua scheda due volte:

My.wfm:

Set Procedure to Program(1)       && carica esplicitamente questa procedura in memoria per assicurarsi che My.WFM sarà disponibile dopo il comando return

_app.oMy = New MyForm()       && Istanza alla scheda

_app.oMy.Open()                         && apertura della scheda

Return                                            && torna indietro.

Per lanciare una scheda usando il codice di testata (header) ,utilizza il comando: DO My.WFM

2. Instanziare le tue schede dall'esterno dei file .WFM.

Ci sono molti luoghi dai quali puoi istanziare direttamente le tue schede senza il chiamare il .WFM:

Quando l'istanza ad un oggetto é diretta, assicurati che hai esplicitamente caricato il file .WFM che contiene la Definizione di  Classe per la tua scheda:

Procedure MyMenu_Run_Form_OnClick

    Set Proc to C:\Mydir\My.WFM Additive                  && carico il file contenente la definizione di Classe

    Form.oChild.MyForm = New MyForm()                     && Istanza all'oggetto da dentro una proprietà dell'oggetto corrente

    Form.oChild.Open()                                                      && Apro la scheda usando il riferimento oggetto

Controversia. C'è un accanito dibattito, se il codice di istanza di una scheda debba essere messo all'inizio di ciascun file .WFM o "distribuito" ove necessita il tuo programma. I " Difensori dei .WFM" sostengono che inserire il codice di istanza nello stesso file della definizione di Classe (.WFM), offre un certo tipo di logica di incapsulazione, ma, la cosa più importante é che non devi andare a cercare il codice di istanza, sai sempre dove si trova!

Comunque, io sono un grande sostenitore per l'istanza delle schede dall'esterno dei .WFM per una serie di ragioni:

1. Il codice di istanza non è una parte del tuo oggetto.

2. L'istanza all'inizio (header) del .WFM crea difficoltà, circa la riusabilità. Se hai bisogno di modificare le proprietà di una scheda prima dell'apertura - come title o color o datalinks, devi inviare l'informazione al .WFM come parametro e convertirlo in proprietà nella sezione iniziale  (HEADER) del programma:

Impostazione delle Proprietà in una istanza diretta:

Set Procedure to My.WFM Additive

Form.oChild = New MyForm()

Form.oChild.Titletext = 'Hello'

Form.oChild.Open()

per compiere la stessa istanza nell'area della Testata del .WFM:

Do My.WFM with .f., 'Hello'

My.Prg:

Param bModal,cTitle                       && Istruzione Param

_app.oChild = New Myform()        && Istanza

If type('cTitle') = 'C'                          && Se questo parametro é inviato

        _app.oChild.titletext.text = cTitle  && imposta la proprietà text

Endif

_app.oChild.Open()          && Apre la scheda

Return                     && Return

Come visto sopra devi esaminare, ciascun parametro inviato al .WFM. In più, chiamando il .WFM é più difficile "attaccare" il tuo riferimento Oggetto della scheda per chiamare l'oggetto.

Per fare ciò, devi  passare il riferimento Oggetto della scheda genitore ancora come un altro parametro.

Per le ragioni sopra, raccomando di non istanziare le tue schede usando l'area di HEADER del .WFM.

Comunque, questa è appena un'opinione. Dovresti usare qualsiasi modo vada bene per la tua applicazione e ad il tuo stile di programmazione.


Riuscire a fare "parlare" le schede tra loro

Abbiamo definito precedentemente le comunicazioni tra processi come: l'invio o la restituzione di dati tra oggetti, procedure e funzioni.

In Visual dBASE (e nella maggior parte dei linguaggi OOP), comunicherai tra le schede e/ o procedure tramite l'impostazione o la lettura dei valori delle proprietà di una scheda dall'esterno di essa. C'è un virtualmente numero illimitato di possibili "modi" di comunicare tra processi.

I tre più comuni nella programmazione in Visual dBASE sono:

Da Genitore a figlio.

Questo è il modello più facile perché tutta la comunicazione è fatta dalla scheda genitore, la quale già conosce il proprio riferimento oggetto e quello del figlio.

Procedure ChildButton_OnClick

Set proc to Child.Wfm Additive        && Carica la procedura.

Form.oChild = New ChildForm()    && istanza alla scheda figlia  tramite una proprietà custom della scheda genitore.(dall'interno del genitore)

Form.oChild.Pushbutton1.height = 2  && Imposta una proprietà della scheda figlia.

Form.oChild.CustTotal = Form.Entryfield1.value  && Crea una proprietà dinamica del figlio per "Inviare" il dato.

Form.oChild.ReadModal()   && Apre la scheda figlia

Form.Entryfield1.Value = Form.oChild.CustTotal  && Legge dalla scheda figlia

Close Proc Child.Wfm             && chiude la Procedura.



Dalla scheda Figlia alla scheda genitore

Questa maniera è diversa dalla precedente in quanto la scheda figlia non conosce il riferimento oggetto del genitore.

Devi "inviare" il riferimento oggetto del genitore al figlio in una proprietà dinamica:

Nella scheda Genitore:

Form.oChild = New CustomerForm()
Form.oChild.oParent = Form              && Crea una proprietà dinamica nella scheda figlia la quale memorizza il Riferimento Oggetto del genitore (Form) 

Nella Scheda Figlia:

Form.oParent.Pushbutton1.Height = 2   && Imposta una proprietà della scheda genitore dall'interno della scheda figlia.
Form.oParent.CustTotal = Form.Entryfield1.value && Creare una proprietà dinamica della scheda genitore con un valore fornito dalla scheda figlia

Schede e Procedure/Funzioni

Qualche volta potresti volere che una procedura esterna o funzione, cambi una proprietà di una Scheda.

Questo è effettuato, come nell'esempio da figlio a Genitore, tramite l'invio come "parametro" del riferimento oggetto di una scheda:

Nella scheda:

Procedure ProcessButton_OnClick

    Do Process with Form   &&Invia come parametro una scheda

Nella procedura:

Procedure Process(oForm)     && Riceve il riferimento ad una scheda come parametro

    oForm.Text1.Text = 'Processing item # 1'  && Aggiorna l'oggetto testo tramite la procedura esterna

 

Suggerimento

Ricorda la discussione sulla "prospettiva". Puoi usare "Form" e "This" invece di una variabile di Riferimento Oggetto quando stai chiamando una procedura( o funzione) esterna dall'interno di una scheda. Come abbiamo fatto nell'esempio precedente.

E una volta che hai accesso al riferimento oggetto, puoi cambiare ogni proprietà da dovunque, lanciare qualsiasi metodo da dovunque.

Hai il completo controllo delle tue schede.

Suggerimento 

Ricorderai che all'inizio del documento abbiamo affermato che  "gli oggetti non ritornano" alle procedure che li hanno creati. confermiamo quanto affermato.

Comunque, c'è uno caso importante nel quale gli oggetti emulano il comportamento suddetto - una scheda aperta con ReadModal ().

ReadModal() causa l'arresto del programma lasciando il controllo alla finestra di dialogo modale. Quando la scheda aperta con il metodo readmodal() viene chiusa, il controllo ritorna all'istruzione successiva al metodo readmodal(). Questo da l'effetto del "ritorno" da una scheda figlia ad una scheda genitore

Se hai bisogno di associare schede  multiple tutte le schede  figlia devono essere aperte con ReadModal () piuttosto che con Open().

 


 

************************************************************************

Codice di Esempio 1 - Genitore legge Entryfield nella Scheda figlia

************************************************************************

Il seguente esempio consiste di due semplici schede che usano Customer.Dbf

nella directory esempi di Visual dBASE. La scheda genitore chiama la scheda figlia

ed allora legge il valore del CustomerNoField del figlio quando il figlio

è chiuso- ma prima il figlio è rilasciato.

************************************************************************

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

* Copia questo codice in un file chiamato FormDemo.prg

* Questo breve programma configura l'ambiente

* ed poi chiama la prima scheda: CustomerForm

* Per lanciare questo programma dimostrativo digita "Do Formdemo"

* dalla Finestra Comandi.

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

SET TALK OFF && Configura l'ambiente

SET BELL OFF

SET CUAENTER ON

Set Procedure to Customer.Wfm Additive && Carica in memoria

_app.Cust = New CustomerForm() && Istanza

_app.Cust.Open() && Apre la scheda

*--------------------------------------------Customer Form-----------

* Copia questo codice in un file chiamato CUSTOMER.WFM

* Questa scheda richiede la tabella Customer.dbf nella directory esempi di Visual dBASE 

* Change the View property of the form to the appropriate drive and

* directory to access Customer.DBF

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

** END HEADER -- do not remove this line*

* Generated on 09/25/95

parameter bModal && This code never runs because

local f                     && .WFM is never executed

f = new CUSTOMERForm()

if (bModal)

        f.mdi = .F. && ensure not MDI

        f.ReadModal()

else

        f.Open()

endif

Class CUSTOMERForm OF Form &&Customer Class "blueprint"

        this.Left = 23

        this.Top = 0

        this.Width = 60

        this.View = "C:\VISUALDB\SAMPLES\CUSTOMER.DBF"

        this.Text = "Parent Form"

        this.Height = 10.8232

DEFINE RECTANGLE RECTANGLE1 OF THIS;

        PROPERTY;

Left 2.333,;

Top 1.0586,;

Width 55.5,;

Text "",;

BorderStyle 2,;

Height 8.2939

DEFINE ENTRYFIELD CUSTOMERNOFIELD OF THIS;

        PROPERTY;

Left 26.833,;

Top 4.1758,;

Width 11.667,;

Value " ",;

Height 1

DEFINE TEXT TEXT1 OF THIS;

        PROPERTY;

Left 12.833,;

Top 4.2344,;

Width 12.5,;

Text "Customer No.",;

Height 0.7656

DEFINE PUSHBUTTON LOOKUPBUTTON OF THIS;

        PROPERTY;

Left 40.166,;

Top 4.1172,;

Width 12.167,;

ColorNormal "R/W",;

Text "&Look Up",;

Group .T.,;

OnClick Class::LOOKUPBUTTON_ONCLICK,;

Height 1.1172

DEFINE PUSHBUTTON CLOSEBUTTON OF THIS;

        PROPERTY;

Left 40.166,;

Top 6.0586,;

Width 12.167,;

ColorNormal "B/W",;

Text "&Close",;

Group .T.,;

OnClick Class::CLOSEBUTTON_ONCLICK,;

Height 1.1172

Procedure CLOSEBUTTON_OnClick

    Form.Close()

    Form.Release()

Procedure LOOKUPBUTTON_OnClick

    Set Procedure to CustLook.Wfm Additive           && Load Procedure.

    Form.oChild = New CustLookForm()                  && Instantiate.

    Form.oChild.Mdi = .f.                                            && Make sure it's not MDI.

    Form.oChild.ReadModal()                                    && Open the lookup Modal.

    If Form.oChild.OKButtonPressed                       && See if OK was pressed in child

            Form.Customernofield.Value = Form.oChild.Entryfield1.value

    Endif               && If so, read child entryfield value into this Form's entryfield value.                        

    Form.oChild.Release()                        && Release child here, not in child form

    Close Proc CustLook.Wfm               && Unload Procedure File.

ENDCLASS

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

* Copy this code into Custlook.Wfm

*

* This Form is the child lookup Form for Customer.Wfm

* It has a Browse and a disabled Entryfield tor display

* of the currently selected Customer No.

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

** END HEADER -- do not remove this line*

* Generated on 10/14/95

*

parameter bModal

local f

f = new CUSTLOOKForm()

if (bModal)

f.mdi = .F. && ensure not MDI

f.ReadModal()

else

f.Open()

endif

CLASS CUSTLOOKForm OF FORM

this.Top = 1.5879

this.Width = 60

this.OnOpen = CLASS::FORM_OnOpen

this.Height = 10.0586

this.Text = "Child Lookup Form"

this.MDI = .F.

this.Left = 33.833

DEFINE RECTANGLE RECTANGLE1 OF THIS;

    PROPERTY;

Top 0.5879,;

Width 57,;

Height 7.1172,;

BorderStyle 1,;

Text "Rectangle1",;

Left 0.833

DEFINE BROWSE BROWSE1 OF THIS;

    PROPERTY;

Top 1.3516,;

Alias "CUSTOMER",;

Width 52.6689,;

Fields 'CUSTOMER->CUSTOMER_N\H="Cust No.",;

CUSTOMER->NAME\H="Cust Name"',;

CUATab .T.,;

Height 5.2354,;

FontBold .T.,;

Left 3.3311

DEFINE PUSHBUTTON OKBUTTON OF THIS;

    PROPERTY;

Top 8.293,;

Width 11.002,;

Height 1.1172,;

Text "&OK",;

OnClick CLASS::OKBUTTON_ONCLICK,;

ColorNormal "B/W",;

Group .T.,;

Left 33.8311

DEFINE PUSHBUTTON CANCELBUTTON OF THIS;

    PROPERTY;

Top 8.293,;

Width 11,;

Height 1.1172,;

Text "&Cancel",;

ColorNormal "B/W",;

Group .T.,;

Left 46.5

DEFINE ENTRYFIELD ENTRYFIELD1 OF THIS;

    PROPERTY;

Top 8.4111,;

Width 13,;

DataLink "CUSTOMER->CUSTOMER_N",;

Height 1,;

When {;Return .f.},;

ColorNormal "N/W",;

Left 16.833

DEFINE TEXT TEXT1 OF THIS;

    PROPERTY;

Top 8.5293,;

Width 13.166,;

Height 1,;

Text "Customer No.",;

Left 2

Procedure OKBUTTON_OnClick

Form.OkButtonPressed = .t. && Set property if button

Form.Close() && is pressed.

 

Procedure FORM_OnOpen

Form.OKButtonPressed = .f. && Set up dynamic property

&& to determine later if

&& OK Button has been clicked.

ENDCLASS

************************************************************************

Codice di Esempio 2  - Oggetto figlio aggiorna Entryfield nella scheda Genitore

************************************************************************

The following sample has two simple Forms using Customer.Dbf from the

Visual dBASE samples directory. These are the same Forms as the previous

code sample. Only this time, the parent sends its Object Reference to

the child Form so that the Child Form can directly change the value

of the parent's CustomerNoField.

************************************************************************

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

* Copy this code into FormDemo.prg

* This short program sets up the environment

* and then calls the first form: CustomerForm()

*

* To start this demo program type "Do Formdemo"

* from the Command Window.

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

 

SET TALK OFF && Set up environment

SET BELL OFF

SET CUAENTER ON

Set Procedure to Customer.Wfm Additive && Load into memory

_app.Cust = New CustomerForm() && Instantiate

_app.Cust.Open() && Open Form.

*--------------------------------------------Customer Form-----------

* Copy this code into a file called CUSTOMER.WFM

*

* This Form requires Customer.dbf from the Visual dBASE Samples

* Change the View property of the form to the appropriate

* drive and directory to access Customer.DBF

*

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

** END HEADER -- do not remove this line*

* Generated on 09/25/95

parameter bModal && This code never runs because

local f && this .WFM is never "called"

f = new CUSTOMERForm()

if (bModal)

f.mdi = .F. && ensure not MDI

f.ReadModal()

else

f.Open()

endif

Class CUSTOMERForm OF Form &&Customer Class "blueprint"

this.Left = 23

this.Top = 0

this.Width = 60

this.View = "C:\VISUALDB\SAMPLES\CUSTOMER.DBF"

this.Text = "Parent Form"

this.Height = 10.8232

DEFINE RECTANGLE RECTANGLE1 OF THIS;

    PROPERTY;

Left 2.333,;

Top 1.0586,;

Width 55.5,;

Text "",;

BorderStyle 2,;

Height 8.2939

DEFINE ENTRYFIELD CUSTOMERNOFIELD OF THIS;

    PROPERTY;

Left 26.833,;

Top 4.1758,;

Width 11.667,;

Value " ",;

Height 1

DEFINE TEXT TEXT1 OF THIS;

    PROPERTY;

Left 12.833,;

Top 4.2344,;

Width 12.5,;

Text "Customer No.",;

Height 0.7656

DEFINE PUSHBUTTON LOOKUPBUTTON OF THIS;

    PROPERTY;

Left 40.166,;

Top 4.1172,;

Width 12.167,;

ColorNormal "R/W",;

Text "&Look Up",;

Group .T.,;

OnClick Class::LOOKUPBUTTON_ONCLICK,;

Height 1.1172

DEFINE PUSHBUTTON CLOSEBUTTON OF THIS;

    PROPERTY;

Left 40.166,;

Top 6.0586,;

Width 12.167,;

ColorNormal "B/W",;

Text "&Close",;

Group .T.,;

OnClick Class::CLOSEBUTTON_ONCLICK,;

Height 1.1172

Procedure CLOSEBUTTON_OnClick

Form.Close()

Form.Release()

Procedure LOOKUPBUTTON_OnClick

Set Procedure to CustLook.Wfm Additive && Load Procedure

Form.oChild = New CustLookForm() && Instantiate

Form.oChild.oParent = Form && Add new property to child

&& with this parent's Reference

Form.oChild.Mdi = .f. && Make sure it's not MDI

Form.oChild.ReadModal() && Open the lookup Modal

Close Proc CustLook.Wfm && Unload Procedure File.

ENDCLASS

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

* Copy this code into Custlook.Wfm

*

* This Form is the child lookup Form for Customer.Wfm

* It has a Browse and a disabled Entryfield tor display

* of the currently selected customer

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

** END HEADER -- do not remove this line*

* Generated on 10/14/95

*

parameter bModal

local f

f = new CUSTLOOKForm()

if (bModal)

f.mdi = .F. && ensure not MDI

f.ReadModal()

else

f.Open()

endif

CLASS CUSTLOOKForm OF FORM

this.Top = 1.5879

this.Width = 60

this.OnClose = CLASS::FORM_ONCLOSE

this.Height = 10.0586

this.Text = "Child Lookup Form"

this.MDI = .F.

this.Left = 33.833

DEFINE RECTANGLE RECTANGLE1 OF THIS;

    PROPERTY;

Top 0.5879,;

Width 57,;

Height 7.1172,;

BorderStyle 1,;

Text "Rectangle1",;

Left 0.833

DEFINE BROWSE BROWSE1 OF THIS;

    PROPERTY;

Top 1.3516,;

Alias "CUSTOMER",;

Width 52.6689,;

Fields 'CUSTOMER->CUSTOMER_N\H="Cust No.",;

,CUSTOMER->NAME\H="Cust Name"',;

CUATab .T.,;

Height 5.2354,;

FontBold .T.,;

Left 3.3311

DEFINE PUSHBUTTON OKBUTTON OF THIS;

    PROPERTY;

Top 8.293,;

Width 11.002,;

Height 1.1172,;

Text "&OK",;

OnClick CLASS::OKBUTTON_ONCLICK,;

ColorNormal "B/W",;

Group .T.,;

Left 33.8311

DEFINE PUSHBUTTON CANCELBUTTON OF THIS;

    PROPERTY;

Top 8.293,;

Width 11,;

Height 1.1172,;

Text "&Cancel",;

ColorNormal "B/W",;

Group .T.,;

Left 46.5

DEFINE ENTRYFIELD ENTRYFIELD1 OF THIS;

    PROPERTY;

Top 8.4111,;

Width 13,;

DataLink "CUSTOMER->CUSTOMER_N",;

Height 1,;

When {;Return .f.},;

ColorNormal "N/W",;

Left 16.833

DEFINE TEXT TEXT1 OF THIS;

    PROPERTY;

Top 8.5293,;

Width 13.166,;

Height 1,;

Text "Customer No.",;

Left 2

Procedure OKBUTTON_OnClick

&& Update parent Form's Custnofield

&& using the parent Form's Object Reference,

&& which is stored in the oParent property

&& of this Form.

Form.oParent.CustomerNoField.Value = Form.Entryfield1.Value

Form.Close()

 

Procedure FORM_OnClose

Form.Release() && This Form may be released here as

&& it will not be addressed again in

&& the parent Form.

 

ENDCLASS