An Application
With its Own Desktop
In Visual dBASE 7.01
by Robert Bravery



 

Introduzione

Visual dBASE è un magnifico linguaggio di programmazione con il quale è possibile fare molte cose. Trattare dati, presentare i dati e recuperare informazioni in molti modi. Nelle mie applicazioni ho spesso dimenticato la presentazione grafica per cui le ho costruite in maniera molto semplice. Ho sempre pensato che la cosa importante fosse che cosa vedere e non come vederla. Purtroppo non tutti la pensano così per cui ci sono persone che giudicano l’applicazione da come si presenta piuttosto che dalle sue prestazioni. Per questo ho iniziato a fare qualche cosa di più carino ma rimaneva sempre lo sfondo grigio del desktop or _app.framewin. Per superare questo problema ho pensato a qualche soluzione per creare un desktop personalizzato per le mie applicazioni.

Dovevo creare delle form con sfondi differenti dato che la form contiene al suo interno altre form, (come succede per la shell VdB, o framewin). L’unico problema è che le form sono figlie dell’oggetto framewin, rendendo impossibile per una form essere contenuta in un altra. Dobbiamo in qualche nodo cambiare il padre della form principale. La nostra form Desktop deve diventare la form padre.L’unica strada che consente di farlo passa attraverso le API di Windows API (Application Program Interface).

SetParent

Per determinare la finestra padre esiste la funzione SetParent().

From the Win32 Programmers Reference:

La funzione SetParent cambia il riferimento alla finestra padre di una finestra figlio.

La funzione SetParent function può essere usata in una applicazione per settare la finestra padre di un pop-up, sovrapposto o di una finestra figlio. La nuova finestra padre e la finestra figlio devono appartenere alla stessa applicazione.

Se la finestra, identificata dal parametro hWndChild è visibile, Windows la ridisegna e la ridipinge.

La funzione richiede due argomenti, uno per l’handle della finestra figlio e l’altro per l’handel della finestra padre.

La funzione SetParent cambia il riferimento alla finestra padre di una finestra figlio.

HWND SetParent(
HWND hWndChild,     // handle della finestra della quale viene cambiato il padre
HWND hWndNewParent  // handle della nuova finestra padre)

Per altre informazioni leggere l’help in linea.

La form Desktop

E’ una normale form con la proprietà maximize posta a true. Il settaggio a true avviene all’inizio; tutte le altre form saranno contenute in essa. Create la form ed inserite qualche pulsante ( si può usare anche un a menu, e / o una tool bar o una combinazione dei tre). Create uno sfondo o usatene uno fornito con VdB. Io uso "shore.jpg" e lo modifico leggermente.  Usate questo file come sfondo del vostro Desktop, e assicuratevi che la proprietà MDI della form sia settata a false.

Dobbiamo ora creare l’applicazione figlio o la form figlio. Queste possono essere qualsiasi form che esegue qualsiasi funzione. Ricordate che queste form devono avere la proprietà MDI settata a false.  Osservate anche che queste form NON devono avere attaccato ne’ menu ne’ toolbars. Qualcuno può pensare che mescolo MDI e SDI.  Invece tutte le forms sono SDI.  Quello che devo fare è una applicazione simile ad una applicazione MDI.  Osservate che le caratteristiche della form MDI non saranno applicate alle vostre forms ma saranno applicate solo le caratteristiche della form SDI .  Non ho cercato di confondere le due o di combinarle entrambe. Per capire bene quello che state facendo leggete la sessione delle form del VdB help file.

Dopo aver creato la form, dobbiamo fare alcuni cambiamenti. Quando viene aperta o eseguita la form, viene eseguito il bootstrap della form che definisce la form e tutte le sue proprietà oltre che aprire e visualizzarla.

parameter bModal
local f
f = new backgroundForm()
if (bModal)
  f.mdi = false // ensure not MDI
  f.readModal()
else
  f.open()
endif

Quello che dobbiamo fare, è prevenire il bootstrap e fare eseguire al suo posto il nostro codice. Per evitare che questo codice sia cancellato quando viene editata la form con il Designer dobbiamo inserirlo prima della linea: "** END HEADER -- do not remove this line ".

La prima riga è un parametro che determina come aprire la form ( in modalità modale o non) e quindi dobbiamo dichrarare la funzione esterna API SetParent function.

EXTERN CHANDLE SetParent(CHANDLE,CHANDLE) User32

Dichiariamo quindi una variabile _app.FoParent   alla quale faranno riferimento tutte le form e quindi dichiariamo ed apriamo la form come al solito.

_app.FoParent= new backgroundForm()
if (bModal)
  _app.FoParent.mdi = false  // ensure not MDI
  _app.FoParent.ReadModal()
else
   _app.FoParent.Open()
endif
return

NOTA IMPORTANTE:Non dimenticare il return alla fine

Vediamo ora la form figlio

La Form Figlio

Questa form viene creata normalmente con l’unica differenza che quando si apre con l’evento onOpen dobbiamo cambiare il riferimento alla form padre. Più precisamente vogliamo che il padre sia il nostro Desktop. Dato che abbiamo dichiarato come externed la funzione SetParent della form Desktop, dobbiamo usare questa funzione per cambiare nella form figlio il riferimento al padre.
Per prima cosa dobbiamo controllare se la form viene effettivamente chiamata dalla form che vogliamo sia il genitore oppure viene chiamata da un’altra form o viene chiamata da se stessa. Il fattore determinante (non il solo ma quello che io uso) è la variabile _app.FoParent. Naturalmente, se questa variabile è presente in memoria dobbiamo usarla come riferimento della form genitore. Per fare questo usiamo la funzione type().
 

if type("_app.FoParent") # "U"

Dall’help VdB:

TYPE() restituisce una stringa di uno o due caratteri che indicano il tipo di dato. I valori restituisi possono essere.
 
Expression type TYPE()
Array object A
DBF or Paradox binary field (BLOB) B
Bookmark BM
Character field or string value, Paradox alphanumeric field C
Codeblock CB
Date field or value, Paradox date field D
Float field, Paradox numeric or currency field F
Function pointer FP
OLE (general) field G
Logical field or value L
DBF or Paradox memo field M
DBF numeric field or value N
Object reference (other than Array) O
Undefined variable, field, invalid expression, or null U

Usare TYPE() per verificare quale function, class, o method risultano caricati in memoria. Se TYPE() restituisce "FP" (per function pointer), come si vede nel seguente statements, IF che verifica se la funzione indicata non è caricata (questo viene fatto per determinare se caricarla o meno in memoria)

In altre parole, se la variabile NON è definita, viene caricata in memoria e possiamo quindi cambiare il riferimento al genitore di questa form. Dobbiamo farlo dato che abbiamo un riferimento al genitore. Lo possiamo fare chiamando la funzione setparent con i due parametri l’handle della form figlio e della form genitore.

setparent(form.hwnd, _app.FoParent.hwnd)

In questo modo cambiamo il genitore della nostra form con la form Desktop definita precedentemente.

Eseguendo la form Desktop, osserverete che è simile ad una applicazione. Se l’applicazione viene minimizzata osserverete che è una porzione della Task Bar, il che significa che è una applicazione stand alone.

Cambiano l’evento onClick di un pulsante del Desktop per aprire una form figlio, ci aspettiamo che la form venga aperta all’interno del Desktop e che possa essere mossa solo entro il margini del Desktop.

Ora l’applicazione principale è la form Desktop. Le altre form figlio sono una parte dell’applicazione principale e sono contenute all’interno di essa. Se si deve minimizzare la form figlio ci si aspetta che ciò avvenga nell’angolo in basso a destra del Desktop, come avviane quando si minimizzano le finestre del Navigator e di Command di VdB.

Minimizzando l’intera applicazione, abbiamo solamente un riferimento nella Taskbar, dell’applicazione principale Desktop mentre le form figlio non compariranno minimizzate nella Taskbar.

Nota: se la proprietà MDI della form figlio viene settata a true essa scompare quando viene minimizzata. Perché ? Poiché si tratta di una applicazione MDI che ha , perciò, un altro genitore. (il suo genitore è l’oggetto framewin di VDB. Leggete questa sezione nell’help in linea.) Assicuratevi anche che la proprietà topmost sia settata a true in modo che se viene minimizzata sia visibile nella parte alta del Desktop.

Analogamente, se viene ingrandita, si troverà al di sotto della form genitore:

Dato che si possono aprire molte finestre figlio, ingrandirle minimizzarle, si può inserire del codice per gestire queste finestre in modo da renderle con un aspetto ordinato. Il codice si trova nelle utility dUFLP (dUFLP = dBASE Users' Function Library Project) che si trovano sul sito web di Ken Mayer's web site.

Talking Forms

Perché le forms lavorino correttamente, è necessario che dialoghino fra di loro. In altre parole si deve poter settare qualche proprietà della form figlio senza modificare la form genitore e viceversa.  Per esempio si può voler disabilitare il pulsante della form genitore che chiama la form figlio e quando questa è chiusa, rendere di nuovo attivo il pulsante. Ci sono centinaia di altre cose che si possono fare. Questo articolo non intende affrontare questo argomento che viene trattato in maniera diffusa nel files "HOW.TO" disponibili nei siti Web. In modo particolare l’ "HOW.TO" scritto per VdB5.6, chiamato "FormVars.how".

La prima cosa da fare è creare una reference all’oggetto fra la form padre e figlio. Ogni oggetto contenuto in una form ha un riferimento ad essa (es, un pulsante ha come reference "form.pushbutton"), e con questo si può fare riferimento a qualsiasi proprietà del pulsante nominando la form nella quale è contenuto.  Per cui la proprietà enabled sarà "form. pushbutton1.enabled = true".  Allo stesso modo un riferimento al figlio (es., "ochild"), sarà creato come "form.ochild". Usando il riferimento "this", ci si riferirà ovviamente all’oggetto attuale, in questo caso sarà il pushbutton.

this.ochild = new childForm()

Nella proprietà parent delle form figlio dobbiamo inserire un riferimento a qualche cosa della form genitore. Si comprende che "this" fa riferimento al pushbutton. Per cui "child.parent" equivale a.

this.ochild.parent=this

Quello che abbiamo detto qui si riferisce alla proprietà "child.parent", dato che l’abbiamo assegnata al pushbutton, ma possiamo usare questo riferimento per qualsiasi altra proprietà del pushbutton genitore. Es. Se nella form figlio incontriamo , "form.parent.pushbutton1.enabled" ci riferiremo a "pushbutton1.enabled" della form genitore.

Possiamo aprire la form e vederla. Possiamo chiamare l’evento onOpend della form figlio dall’interno della form genitore dato che abbiamo stabilito un riferimento ad essa.

this.ochild.open()

Una volta aperta, possiamo usare la form in maniera normale. Possiamo minimizzarla e, se l’applicazione lo consente, possiamo aprire un’altra form. In altre parole possiamo avere molte form aperte contemporaneamente (se l’applicazione è stata disegnata per farlo).

Quando si chiude una form, viene chiamato l’evento onClose. Nel codice onClose dobbiamo disabilitare il pulsante del genitore con la proprietà parent creata in precedenza. Dobbiamo per primo controllare se esiste veramente questo riferimento controllando se la variabile "_app.FoParent", che abbiamo creato in precedenza, esiste in memoria. Con questo riferimento all’indietro possiamo accedere a qualsiasi oggetto contenuto o attaccato alla form genitore o all’oggetto genitore. ES., se abbiamo un riferimento alla form, possiamo riferirci ad ogni oggetto menu, toolbar o activeX, ecc.

if type("_app.FoParent") # "U"
  this.parent.enabled = true
endif

Conclusion

La strada che ho indicato non è l’unica e può non essere la migliore, ma è quella che uso nelle mie applicazioni. Il bello di Visual dBASE è che molte persone possono fare la stessa cosa in modo differente. Questa vuole essere solo un’idea da espandere o da cambiare completamente.  Deve aiutare a fare esperimenti e serve anche come apprendimento. La pratica rende le cose perfette o almeno le migliora dato che un programma non è mai perfetto. In fin dei conti dovete fare qualche cosa che funziona e renda felici gli utilizzatori.

Enjoy!!

Robert Bravery