System Logistics è oggi “partner di impresa“ per il cliente. Grazie all’ampia gamma di prodotti e al patrimonio d` esperienza acquisito con le oltre 650 installazioni sul mercato mondiale, System è in grado di predisporre l` offerta più idonea all` esigenza del cliente.
L’obbiettivo primario è
quello di convertire la fornitura di “prodotti tecnologici” in fornitura di
“prodotti di servizio”, ponendosi come costante supporto del cliente
nell’ambito del material handling, sia per i semilavorati e componenti per la
produzione, sia per i prodotti finiti destinati alla distribuzione.
Avvalendosi di qualificati
servizi interni in grado di studiare attentamente i flussi delle merci per
ridurne i cicli di movimentazione, System Logistics offre “soluzioni complete”
nei sistemi avanzati ed automatici di magazzinaggio: impianti e software
gestionale.
I programmi di gestione
degli impianti forniti, sono sviluppati su piattaforma WINDOWS NT : fino ad
oggi questi “pacchetti” software supervisione sono stati applicati per la
gestione di oltre 350000 UDC (unità di carico).
Questa modalità di
intervento è in grado di promuovere una gestione avanzata della logistica di
fabbrica controllando i flussi delle merci da e per il magazzino.
Il risultato finale delle
soluzioni presentate da System Logistics, assicura una migliore gestione
dell’approvvigionamento e della consegna dei materiali, permettendo il recupero
di produttività; la gestione dei materiali cessa così di essere una
problematica per l’impresa, e diviene un fattore determinante per il
miglioramento della competitività.
La propensione al servizio e
al supporto consulenziale e tecnico di System SpA emerge anche dalla sua
organizzazione. I dipendenti di System sono circa 300, di questi, 90 sono
impiegati nella divisione Logistics.
Le più recenti tendenze
della cultura manageriale pongono il concetto di logistica, inteso come
organizzazione e movimentazione delle risorse in azienda, al centro delle
scelte strategiche aziendali. In corrispondenza delle nuove tecniche di “lean
production” e delle richieste di estrema flessibilità e dinamismo, la logistica
è divenuta disciplina vitale nell’attività d’impresa.
Il punto di forza di System
Logistics è proprio la sua capacità di gestire interamente progetti complessi:
basti pensare che in Texas è stata in grado di realizzare una commessa
pluriennale per impianti di movimentazione e magazzinaggio per un valore oltre
i 60 milioni di dollari.
System Logistics offre infatti, ai diversi settori
industriali e aziendali, “soluzioni complete” per fare fronte alla
competizione, che oggi si gioca specialmente a livello di servizio, oltre che
di prezzo e di tecnologia.
Per questo la sua attività
non è limitata alla fornitura di macchinari, ma ha il suo fulcro nell’offerta
di vere e proprie “soluzioni complete” per la gestione integrata dei magazzini
automatici, affiancata dall’analisi svolta da personale specializzato con il
supporto di sistemi di simulazione.
Una qualificata e continua
assistenza post vendita è garantita da una struttura interna dedicata che opera
in tutto il mondo, anche in teleassistenza, in collaborazione con le società
estere appartenenti a System SPA : System Espana, System France, System
Southeast, System Bohemia e System Brasil in grado di garantire un servizio
tempestivo e qualificato, attraverso personale specializzato che interviene
direttamente in caso di guasto o di problemi nell’utilizzo dei macchinari.
- magazzini
verticali automatici Modula
-
trasloelevatori
Miniload
-
trasloelevatori
Robostore e/o sterzanti
2. Impianti
handling
-
sistemi
di convogliamento e trasporto
-
palletizzatori
robottizzanti
-
veicoli
laser guidati LGV
INQUADRAMENTO
DELLA TESI
Obiettivo specifico della tesi
La mia tesi in sostanza si occupa della quotazione del magazzino, quindi dell’inserimento in una tabella di un Database delle coordinate X, Y e Z delle posizioni e profondità delle celle di una parte, di più parti o dell’intero magazzino per una o più macchine; dovrà poi permettere all’operatore di modificare queste coordinate sommandogli un numero costante o variabile, quindi oltre all’eliminazione di uno o più record dalla tabella dovrà consentire anche di creare in tabella una copia di una definizione macchina evitando così l’inserimento manuale di tutti i dati.
Interessante sottolineare che il progetto generale pensato da System Logistics è totalmente innovativo, infatti mai in precedenza è stato provata un operazione del genere usando un Personal Computer, questi rilievi sono sempre stati fatti attraverso l'uso di PLC.
Il mio progetto si può sostanzialmente dividere in cinque fasi:
2.
Calcolo
quote di una o più parti dello scaffale
3.
Modifica
quote di una o più parti dello scaffale
4.
Creazione
di uno scaffale per una macchina copiandone uno già esistente in tabella.
5.
Eliminazione
di uno scaffale, di uno o di tutti i record presenti in tabella.
Nella prima fase viene
definito lo scaffale per una determinata macchina e quindi le celle in cui
quella macchina può andare a depositare un’unità di carico; verrà inoltre
definita la tipologia della cella, quindi il numero posizioni ed il numero
profondità che essa può assumere. La definizione da noi creata per una data
macchina sarà inserita in una tabella all’interno della quale il numero
macchina sarà univoco, infatti non potranno esistere in tabella due definizioni
scaffale per la stessa macchina.
Nella seconda fase il
progetto permette ad un operatore di calcolare ed inserire in tabella le quote
di una parte, di più parti o dell’intero scaffale ora presente in tabella dopo
averlo inserito nella prima fase. Le quote saranno calcolate partendo dalle
coordinate di una cella iniziale in base a passo piani e passo colonne dati
inseriti sempre in questa fase.
Nella terza fase il progetto
si occupa della modifica delle quote celle. Per modifica delle quote si intende
poter sommare a queste una costante o una variabile incrementale. La modifica
si riferisce alle coordinate X, Y in prima e seconda profondità; il tutto
sempre riferito ad una parte o all’intero scaffale definito in prima fase.
La quarta fase si occupa
della creazione di uno scaffale per una determinata macchina copiandone uno già esistente in tabella. È
possibile inoltre creare per la stessa macchina lo scaffale di sinistra
copiandone quello di destra già esistente in tabella e viceversa. Questa fase
mi permette di creare uno scaffale saltando la fase uno e la fase due quindi
l’inserimento manuale di tutti i dati.
La quinta fase permette
l’eliminazione di un record, di tutti i
record riferiti alla macchina o di tutti i record presenti in tabella.
Il modello RoboStore RS 50 è utilizzato nella movimentazione di scatole o cassette del peso massimo di 50 kg. La struttura è monocolonna in alluminio con doppio gruppo di traslazione, inferiore e superiore; il quadro elettrico è posizionato a terra. Il dispositivo di prelievo può essere previsto con catena, pinze laterali, piattaforma telescopica o gruppo speciale per prelievo / deposito contemporaneo.Le motorizzazioni con servomotori ed il sistema di controllo garantiscono i massimi livelli di prestazione.
I modelli RoboStore RS 100,
RS 200 e RS 300 sono utilizzati nella movimentazione di scatole o cassette per
la con peso massimo di 300 kg. Sono la versione monocolonna in acciaio e
bicolonna in acciaio per carichi multipli. Il dispositivo di prelievo può
essere previsto con catena, pinze laterali, piattaforma telescopica o gruppo
speciale per prelievo/deposito contemporaneo. Il sistema a due ruote motrici,
le motorizzazioni con servomotori ed il
sistema di controllo garantiscono i massimi livelli di prestazione.
I modelli RoboStore RS 350,
RS 500 e RS 650 sono utilizzati nelle movimentazioni di carichi pallettizzanti
fino 650 kg o di contenitori. La struttura è monocolonna in acciaio con
sollevamento a catena.Il dispositivo di prelievo è normalmente realizzato con
forche telescopiche a singola e multipla profondità o con gruppi di estrazione
a strisciamento. Le motorizzazioni con servomotori ed il sistema di controllo
garantiscono i massimi livelli di prestazione. Tutti i modelli sono forniti
anche in allestimento “sterzante” per operare su un singolo trasloelevatore su
più corsie.
I modelli RoboStore RS 750,
RS 1000 e RS 1250 sono i più frequentemente utilizzati nella movimentazione di
carichi pallettizzanti con peso massimo di 1250 kg. La struttura è monocolonna
in acciaio con sollevamento a catena. Il dispositivo di prelievo è normalmente
realizzato con forche telescopiche con singola e multipla profondità. Le
motorizzazioni con servomotori ed il sistema di controllo garantiscono i
massimi livelli di prestazione. Tutti i modelli sono forniti anche in
allestimento “sterzante” per operare su un singolo trasloelevatore su più
corsie di magazzino fino ad una altezza di 22 m.
I modelli RoboStore RS 1500
e RS 2000 sono utilizzati nella movimentazione di pallet o contenitori
metallici con peso massimo di 2000 kg. La struttura è monocolonna in acciaio
con sollevamento a catena. Il dispositivo di prelievo è normalmente realizzato
con forche telescopiche con singola e multipla profondità. Le motorizzazioni
con servomotori ed il sistema di controllo garantiscono i massimi livelli di
prestazione. I modelli sono forniti anche in allestimento “sterzante” per
operare su un singolo trasloelevatore su più corsie di magazzino fino ad una
altezza di 22 m.
I trasloelevatori vanno a lavorare su magazzini che appaiono come scaffali costituiti da piani e colonne che vanno a definire un certo numero di celle. Questi scaffali possono raggiungere una altezza di 30 m ed una lunghezza di 185, fino ad avere un numero di 5000 celle. All’interno di ogni cella si possono avere fino a tre posizioni e due profondità e quindi spazio per 6 UDC unità di carico.
Le macchine sono in grado, scorrendoci in mezzo, di lavorare contemporaneamente su due scaffali uno di destra e uno di sinistra.
Quindi un utilizzatore di questo magazzino può arrivare a gestire un numero che si aggira sulle 30000 UDC esclusivamente attraverso l’uso di macchine.
Per facilitarne
la comprensione il problema è stato presentato attraverso le immagini di tutti
i controlli usati all’interno del progetto e alla spiegazione della loro
utilità e del loro funzionamento.
Questo capitolo
è molto utile per poter fare il primo vero passo all’interno del progetto e
capire il modo in cui questo va a risolvere le varie funzioni che permetteranno
all’operatore di definire, quotare e modificare le coordinate del magazzino.
1.1 DEFINIZIONE DELLO SCAFFALE
Per definizione dello
scaffale si intende fornire i dati che mi permetteranno di calcolare il numero
di celle, di posizioni e profondità che lo determineranno; questa definizione
sarà sempre riferita ad una macchina e ad uno scaffale anch’essi specificati
dall’utente.
Si parla di scaffale per
riferirsi ad un enorme contenitore di celle dove una o più macchine
depositeranno una o più unità di carico U.D.C, questo sarà definito da un
numero colonne ed un numero piani, in più per ogni colonna noi possiamo avere
più di una cella, quindi in totale avremo un numero celle uguale ai piani per
le colonne per il numero celle per colonna; ogni cella avrà anche la
possibilità di contenere fino a sei UDC avendo a disposizione tre posti in
prima e volendo anche in seconda profondità.
La definizione avviene nella
prima pagina della form contenuta all’interno di un pageframe, che contiene
altre quattro pagine per ulteriori funzioni, cliccando sul comando Calcola
unico comando attivo, come si vede sotto in figura, che lancerà la procedura
Calcolacelle contenuta nelle procedure della Form.
Come si vede tutte le
Caselle di testo sono inizializzate a 1 per indicare il valore minimo
accettato, se infatti venisse inserito uno zero non sarebbe accettato
attraverso un apposito controllo che mi vigilerà anche sul valore massimo
inserito, che si differenzierà per ogni Casella di testo a seconda della
propria funzione.
In questa videata non è
visibile la Casella di testo per la prima cella di sinistra perché non è stata
selezionato il lato sinistro nella apposita Casella di riepilogo. Una volta
selezionato il lato S la Casella di testo per la prima cella di sinistra mi
apparirà nello spazio “Selezione lato” a fianco della Casella di riepilogo,
quindi potrò inserire il numero del codice cella dal quale inizierà lo scaffale
di sinistra.
Il primo dato che viene inserito nella prima pagina è il numero
macchina.
Il numero macchina mi
permette di specificare per quale trasloelevatore è riferita la definizione che io sto calcolando, le macchine da
noi considerate possono arrivare fino 99 quindi per questa Casella di testo
saranno accettati valori che vanno da 1 a 99.
Se si è inserito un numero
macchina già presente in tabella al momento del calcolo nella procedura
Calcolacelle l’operatore verrà posto davanti a due strade :
1.Rinunciare alla
definizione
2.Sostituire la nuova
definizione a quella vecchia
In caso si rinunci alla
definizione l’operatore verrà riportato a pagina uno per permettergli una nuova
definizione, mentre se decidesse di proseguire la procedura eliminerà tutti i
record riferiti alla macchina in questione presenti in tabella e quindi
inserirà i nuovi. Tutto questo viene fatto perché il numero macchina deve
rimanere sempre univoco all’interno della tabella
Una volta inserito il numero
macchina bisogna specificare a che scaffale è associata. La macchina può
lavorare su un magazzino a due scaffali, quindi può essere associata a due
scaffali uno di destra e uno di sinistra.
Per la selezione dello
scaffale in prima pagina è stato pensato un apposito spazio “Selezione lato”
all’interno del quale io posso appunto selezionare lo scaffale attraverso una
Casella di riepilogo che mi permette di scegliere tra due voci “D” o “S” che
definiscono rispettivamente lo scaffale di destra e lo scaffale di sinistra.
All’avvio della Form questa
casella di riepilogo sarà inizializzata a D; per il motivo che se il primo lato
è considerato quello di destra, infatti la sua prima cella sarà sempre la
numero uno, a differenza dello scaffale di sinistra dove la prima cella sarà
decisa dall’operatore.
Lo scaffale di sinistra è
praticamente il continuo dello scaffale di destra, infatti se ad esempio
l’ultima cella dello scaffale di destra è la numero 999 la prima di sinistra
sarà la numero 1000.
L’inserimento della prima
cella dello scaffale di sinistra sarà possibile solo se viene selezionato “S”
nell’apposita Caselle di riepilogo, infatti quando la selezione avviene sulla
casella “D” una disabilitazione del comando Visible non permetterà di vedere la
Casella di testo riservata alla prima cella dello scaffale di sinistra, mentre
verrà abilitata quando nella Casella di riepilogo verrà selezionato “S”, come
si vede dalla figura sotto. Alla selezione di “S” tramite la procedura
InteractiveChance della casella di riepilogo verrà reso attiva la Casella di
testo per la prima cella dello scaffale di sinistra.
Il valore della Casella di
testo della prima cella di sinistra sarà sempre inizializzata, attraverso un
controllo, alla prima cella dello scaffale di sinistra della macchina
attualmente esistente in pagina uno, trovata in tabella, altrimenti se non
venisse trovata sarà inizializzata a zero. In figura 1261 sarà il codice cella
della prima cella di sinistra trovata in tabella riferita alla macchina
attualmente presente in pagina uno.
All’interno della prima
pagina compare un secondo spazio “Dati per la definizione” dove inserire i dati
per la definizione e quindi il calcolo dei codici, posizioni e profondità delle
celle componenti lo scaffale.
I primi valori ad essere
inseriti in questo spazio sono il numero colonne, il numero piani e il numero
celle per colonna. I dati di sinistra mi permetteranno di capire le dimensioni
del mio magazzino per questi valori è previsto un numero che va da 1 a n,
quindi questi valori vengono inizializzati a 1 e su questi il programma non
prevede particolari controlli
Se l’operatore provasse ad
inserire il numero zero non gli verrebbe permesso da un controllo inserito
nella procedura InteractiveChance delle Caselle di testo.
Ogni cella di uno scaffale
può avere 1, 2 o 3 posizioni ed 1 o 2 profondità, avendo quindi la possibilità
di contenere fino a 6 U.D.C.
Particolare da non
dimenticare e’ che le tre posizioni in seconda profondità, quindi dietro a
quelle in prima profondità, potrebbero essere sfasate in altezza, mantenendo
sempre la stessa X, ma variando di conseguenza la Y altezza e la Z profondità.
Per numero posizioni di una
cella si intende un numero posti dove poter depositare unità di carico. Se il
numero posizioni è uguale a uno significa che all` interno di quella cella è prevista la presenza di un'unica unità di
carico al centro, mentre per numero posizioni uguale a due le unità di carico
previste saranno due, una di sinistra e una di destra, ed infine per numero
posizioni uguale a tre le unità di carico possibili all’interno della cella
saranno tre, in ordine secondo l` indice usato nel progetto, una di centro, una
di sinistra e una di destra.
Il numero profondità uguale
a uno indicherà che per quelle celle sono previste solo le posizioni anteriori,
mentre per numero profondità uguale a due significherebbe che è possibile
inserire due unità di carico nella stessa posizione all` interno della stessa
cella una davanti e una dietro.
Se il numero profondità ha
valore uguale a due il programma andrà ad abilitare, come si vede sotto, le
coordinate in seconda profondità che si trovano in pagina due inizialmente
disabilitate essendo tutti i valori in prima pagina inizializzati a uno.
Quindi con Numero profondità
uguale a due significa che il magazzino è previsto per ospitare U.D.C. anche in
seconda profondità; queste coordinate prevedono solo Y e Z infatti la X sarà la
stessa dell’unità di carico in prima profondità.
La procedura Calcolacelle con la quale si fa il calcolo e l’inserimento in tabella dei codici, posizione e profondità delle celle verrà lanciata tramite un bottone di comando posto all’interno di un contenitore di pulsanti rappresentato da una calcolatrice, abilitato appositamente in questa pagina per questa funzione.
1.2
QUOTAZIONE SCAFFALE
La quotazione di una parte, di più parti o dell’intero scaffale è possibile attuarla in pagina due. Nella seconda pagina è possibile inserire i dati attraverso i quali la procedura Coordinate mi calcolerà tutte le quote X, Y e Z delle posizioni e profondità delle celle appartenenti alla parte di scaffale definita sempre in seconda pagina.
Importante sapere è che la parte di scaffale considerata farà riferimento alla definizione avvenuta in pagina uno e quindi alla macchina al momento presente in prima pagina.
L’accesso a questa pagina sarà quindi permesso solo se viene riscontrata in tabella una situazione macchina uguale a quella in prima pagina.
Questo controllo verrà fatto prima sul numero celle poi sulla situazione posizioni e profondità ed alla prima discordanza verrà vietato l’accesso per evitare di lavorare sulla macchina errata.
La quotazione avviene nella
seconda pagina della form contenuta all’interno di un pageframe, che contiene
altre quattro pagine per ulteriori funzioni, cliccando sul comando Calcola
unico comando attivo, come si vede in figura, che lancerà la procedura
Coordinate contenuta nelle procedure della Form.
La seconda pagina è suddivisa in tre spazi all’interno dei quali inserire i dati per le diverse funzioni.
Nel primo spazio verranno inseriti i dati per la definizione della parte di scaffale per la quale si vuole inserire in tabella le quote delle posizioni e profondità delle celle ed i dati che mi permetteranno di avere il passo col quale calcolarle, in sostanza qui l’utente selezionerà la parte di tabella su cui fare la quotazione.
Colonna inizio mi indicherà la colonna dello scaffale da dove iniziare la quotazione della definizione al momento presente in prima pagina e Numero colonne mi dirà per quante colonne questa quotazione deve proseguire; il passo colonne invece mi indicherà il passo della colonna e quindi, a seconda del numero celle per colonna in prima pagina, mi darà il riferimento per il calcolo delle coordinate X.
Su questi valori andranno fatti vari controlli al fine di evitare che l’operatore possa cadere il diversi malfunzionamenti. Il primo controllo verrà fatto sulla colonna inizio infatti questa non dovrà mai essere maggiore del Numero colonne dello scaffale come non dovrà mai superare questo valore anche il Numero colonne sommato alla Colonna inizio, altrimenti la quotazione inizierà o continuerà per colonne che in realtà non esistono. Per il passo colonne non ci sono particolari limitazioni.
La parte di destra di questo spazio è riservata al piano da dove iniziare la mia quotazione ed il numero piani per i quali questa deve proseguire ed un passo piani che mi indica appunto l’altezza di un piano e quindi mi permettere di calcolare le coordinate Y Per questi valori vale naturalmente il discorso fatto in precedenza per le colonne e quindi i loro valori non dovranno superare il reale valore del numero piani dello scaffale definito in pagina uno.
Un secondo spazio è dedicato alle coordinate della prima cella da cui inizierà il calcolo delle quote eseguito grazie al passo colonne ed al passo piani
La prima cella da cui partire con la quotazione è già stata trovata prima grazie ai dati inseriti nel primo spazio, ora grazie a queste coordinate la procedura Coordinate saprà da che valori iniziare il calcolo delle quote e quindi sarà in grado una volta determinati i giusti valori di inserire in tabella le coordinate X, Y e Z fino a questo momento uguali a zero..
Le coordinate della prima cella si riferiranno precisamente alla prima posizione all’interno della prima cella che sarà uguale a quella centrale se il numero posizioni fosse uguale a 1 o a 3; se invece il numero posizioni fosse uguale a 2 la prima sarebbe quella di sinistra
Il terzo spazio è riservato alle coordinate in seconda profondità come già trattato nel paragrafo precedente saranno utilizzabili dall’utente solo se in prime pagina è stato inserito un numero profondità uguale a 2 in caso contrario queste rimarranno allo stato iniziale vale a dire disabilitate.
Queste coordinate saranno riferite alla prima posizione della prima cella in seconda profondità quindi manterranno sempre la stessa X della posizione più avanzata, ma potranno essere sfasate in altezza e in profondità
La procedura Coordinate con la quale si fa il calcolo e l’inserimento in tabella delle quote, verrà lanciata tramite un bottone di comando posto all’interno di un contenitore di pulsanti rappresentato da una calcolatrice, abilitato appositamente in questa pagina per questa funzione.
1.3
MODIFICA QUOTE
La modifica di una parte, di più parti o dell’intero scaffale è possibile attuarla in pagina tre.
Per modifica si intende poter andar a sommare alle coordinate X e Y in precedenza inserite in tabella una costante o una variabile incrementale, inserita in una apposita Casella di testo dall’utente che sempre in terza pagina avrà inserito anche i dati necessari per la selezione delle celle su cui andare a fare l’operazione.
Nella terza pagina è quindi possibile inserire i dati attraverso i quali la procedura Modificacelle mi calcolerà tutte le nuove quote delle posizioni e profondità delle celle appartenenti alla parte di scaffale definita all’interno della stessa pagina.
Importante è il fatto che la parte di scaffale considerata sarà riferita alla definizione avvenuta in pagina uno e quindi alla macchina al momento presente in prima pagina. L’accesso a questa pagina sarà quindi permesso solo se viene riscontrata in tabella una situazione macchina uguale a quella in prima pagina.
Questo controllo verrà fatto prima sul numero celle poi sulla situazione posizioni e profondità ed alla prima discordanza verrà vietato l’accesso per evitare di andare a lavorare sulla macchina errata.
La modifica avviene come
detto nella terza pagina della Form contenuta all’interno di un pageframe, che
contiene altre quattro pagine per ulteriori funzioni, cliccando sul comando
Modifica unico comando attivo, come si vede in figura, che lancerà la procedura
Modificaquote contenuta nelle procedure della Form.
La pagina è divisa in tre spazi “Dati per la modifica delle celle” , “Somma costante” e “Somma incrementale” ognuno caratterizzato da specifiche funzioni.
Il primo spazio sarà riservato ai dati per la definizione della parte di scaffale per la quale si vuole andare a modificare le quote delle posizioni e profondità delle celle, qui noi in sostanza andiamo a selezionare la parte di tabella su cui fare la modifica.
Colonna inizio mi indicherà la colonna dello scaffale da dove iniziare la modifica della definizione al momento presente in prima pagina, mentre il Numero colonne mi dirà per quante colonne questa modifica deve proseguire. Su questi valori andranno fatti vari controlli al fine di evitare che l’operatore possa cadere il diversi malfunzionamenti. Il primo controllo verrà fatto sulla colonna inizio infatti questa non dovrà mai essere maggiore del Numero colonne dello scaffale come non dovrà mai superare questo valore anche il Numero colonne sommato alla Colonna inizio altrimenti la modifica inizierà o continuerà per colonne che in realtà non esistono.
La parte di destra di questo spazio è riservata al piano da dove iniziare la mia modifica ed il numero piani per i quali questa deve proseguire. Per questi valori vale naturalmente il discorso fatto in precedenza per le colonne e quindi i loro valori non dovranno superare il reale valore del numero piani dello scaffale definito in pagina uno.
Un secondo spazio è dedicato alle “Somma costante” con la quale ci si propone di sommare a tutte le coordinate delle posizioni e profondità delle celle selezionate prima una costante; questa somma è possibile farla contemporaneamente sulla variabile X e Y come si vede dalla figura dove nel caso specifico verrà sommato 100 contemporaneamente alle X e alle Y.
Un terzo spazio è dedicato alla “Somma incrementale” con la quale è possibile sommare a tutte le coordinate delle posizioni e profondità delle celle selezionate prima, una variabile che verrà moltiplicata da un numero che incrementerà di uno di cella in cella, questo numero si rinizializzerà tutte le volte che si passerà ad una cella del piano superiore; come prima anche questa somma è possibile farla contemporaneamente sulla variabile X e Y; cosa che non è possibile è di fare il calcolo di questa somma contemporaneamente alla somma costante della stessa variabile, infatti, come si vede dalla figura, se una Casella di testo di una variabile per la somma costante risulta essere diversa da zero un controllo disabiliterà immediatamente la Casella di testo della stessa variabile per la somma incrementale, e viceversa, impedendo quindi che tutte e due siano diverse da zero per evitare malfunzionamenti del programma; regola che vale anche per la somma costante infatti anche questa non potrà mai essere fatta contemporaneamente ad una somma incrementale della stessa variabile.
La procedura Modificaquote con la quale si fa il calcolo delle nuove quote, verrà lanciata tramite un bottone di comando posto all’interno di un contenitore di pulsanti rappresentato da una matita e un righello, abilitato appositamente in questa pagina per questa funzione.
1.4 COPIA
DI UNA DEFINIZIONE
Per copia di una definizione intendiamo la creazione di una definizione di uno scaffale per una macchina copiandone una già esistente in tabella; questa operazione, eseguibile in quinta pagina, risulterà molto utile perché permetterà di evitare l’inserimento dato per dato e quindi la fase uno e la fase due. Nella quinta pagina è possibile inserire i dati attraverso i quali il programma contenuto all’interno della sua procedura Click mi creerà ed inserirà in tabella la nuova definizione.
Per creare la copia della definizione la procedura avrà bisogno di sapere il numero macchina da cui copiarla e il numero macchina per quale crearla e i rispettivi scaffali e se necessario la prima cella degli scaffali di sinistra
La copia avviene nella
quinta pagina della form contenuta all’interno di un pageframe, che contiene
altre quattro pagine per ulteriori funzioni, cliccando sul comando Copia unico
comando attivo, come si vede in figura, che eseguirà il programma contenuto
all’interno della sua procedura Click.
Questa pagina è divisa in due spazi “Crea una definizione scaffale per una macchina copiandone una già esistente” e “Elimina solo una parte della tabella”. Nel primo è possibile creare una definizione scaffale per una macchina nuova semplicemente copiandone una già presente in tabella. Questa operazione sarà possibile inserendo nella Casella “Sorgente” il numero macchina da cui si vuole copiare la definizione ed nella Casella “Lato sorgente” il suo scaffale; poi andando ad inserire sotto gli stessi dati per la nuova macchina.
Il lato è stato inizializzato a “D”, ma se venisse selezionato il lato sorgente “S”, come in figura, verrebbe resa visibile la Casella di testo “Prima cella sinistra sorgente” fino a quel momento non visibile e quindi reso possibile l’inserimento del giusto valore senza li quale il programma non sarebbe in grado di trovare la prima cella dello scaffale di sinistra in tabella riferita a quella macchina; questo valore andrà inserito anche quando il lato sorgente è ”D”, perché il programma dovrà essere sempre in grado di sapere dove termina questo lato per non fare la copia di celle che appartengono al lato sinistro. Nell’esempio in figura sopra il programma andrà a fare la copia dello scaffale di sinistra della macchina uno per lo scaffale di destra della macchina due; andrà quindi in tabella e partendo dalla cella numero 1261 della definizione scelta farà la copia
E’ possibile anche creare, come in figura sopra, una definizione dello scaffale di sinistra per una macchina copiandone la sua definizione dello scaffale di destra già esistente in tabella; in questo esempio non è stato inserito il valore della prima cella sinistra sorgente perché in tabella il programma troverà solo celle del lato destro.
Un errore che può essere fatto è voler fare una copia del lato di destra quando in tabella sono presenti entrambi i lati e non inserire il valore della prima cella del lato di sinistra, infatti a questo punto il programma quando va a fare la copia non si limiterà al lato destro, ma non potendo distinguerli continuerà facendo la copia di entrambi.
Nel secondo spazio l’operatore sarà in grado di poter eliminare dalla tabella tutte i record riferiti ad una macchina da lui voluta. Per usufruire di questa possibiltà bisognerà selezionare la Casella di controllo “Elimina solo una macchina” così che venga abilitato, come si vede in figura, il comando Cancella fino a quel momento disabilitato. Questo comando mi permetterà l’eliminazione dei record della macchina inserita nella Casella di testo “Macchina” grazie ad un programma nella sua procedura Click.
CAPITOLO 2
La Form del mio progetto è composto essenzialmente da due oggetti: un Pageframe ed un contenitore di comandi. Questo oggetto mi permette di avere sempre ben in vista la situazione comandi e una semplice e veloce consultazione delle varie situazioni grazie alle cinque pagine componenti il Pageframe. È stato usato un form di tipo Formmodal per adeguarsi alle esigenze del programma WINSTORE 3.00 utilizzato per la progettazione e descritto dettagliatamente nel capitolo seguente.
La proprietà principale utilizzata dalla Form è stata DataSession impostata a
due che indica una sessione dati privata. Ho utilizzato la procedura Init per
innanzitutto rendere attiva all’inizializzazione della Form la pagina 4 e
quindi dare una idea generale della situazione attuale all’operatore attraverso
la consultazione della tabella, poi per inizializzare la Casella di testo della
prima cella dello scaffale di sinistra mettendola uguale al giusto valore
trovato in tabella per la macchina attualmente in prima pagina o a zero se in
tabella risultasse non presente uno scaffale di sinistra per quella macchina.
Poi ho creato altre tre procedure per la Form che mi permetteranno di eseguire
le principali funzioni del progetto. La prima procedura creata si chiama
Calcolacelle, questa procedura calcola le posizioni e profondità delle celle di
uno scaffale e le inserisce in tabella con coordinate tutte a zero. Coordinate
è la seconda procedura creata e mi permette di fare il calcolo delle quote
della parte dello scaffale da me desiderata. L’ultima procedura inserita è
Modificacelle, questa mi permette di sommare alle celle in tabella un numero
che può essere costante o incrementale.
La procedura si occupa della creazione delle posizioni e profondità delle celle di uno scaffale e le mette in tabella tutte a coordinate azzerate. Questa procedura svolge la funzione più importante per il mio progetto, infatti prima di questa nessuna delle altre due procedure Coordinate e Modificaquote potrà essere eseguita.
Come prima cosa la procedura va a selezionare la tabella all’interno del database sulla quale lavorare, attraverso il comando Select, poi fà il calcolo del numero celle grazie ai dati inseriti nel secondo spazio “Dati per la definizione” di pagina uno.
Ora Calcolacelle tenta il blocco della tabella per impedire che venga usata da più utenti. Secondo controllo che viene fatto è se il numero celle calcolato per lo scaffale di destra comprende celle di sinistra, in questo caso l’utente verrà informato tramite un messaggio mostrato dalla figura sotto e gli verrà permesso di rinunciare o continuare l’operazione attraverso il clic su “ANNULLA” o su “OK”.
Terzo ed ultimo controllo viene fatto sul numero macchina; infatti la procedura vede se esiste già in tabella la macchina che è stata scelta, se la macchina è presente l’utente verrà posto davanti a due strade, rinunciare o continuare; nel caso l’utente voglia continuare sarà messo al corrente che la definizione attuale andrebbe a sostituire quella già presente in tabella.
Questa sostituzione avviene prima eliminando tutti i record in tabella riferiti alla macchina, poi inserendo i nuovi. L’eliminazione dei record non avviene in senso fisico, ma mettendo il numero macchina a zero e selezionando il record con Delete; in questo modo i record selezionati verranno messi all’inizio della tabella da un apposito indice e potranno poi essere recuperati al momento opportuno, grazie alla selezione non saranno visibili in tabella.
Quindi ora la procedura inizia l’inserimento dei valori nei campi dei record usando il comando Replace.
Il primo valore inserito è il numero macchina, poi la procedura per inserire il codice cella deve controllare se lo scaffale è di destra o di sinistra, quindi se la prima cella è uno o uguale alla Casella di riepilogo numero prima cella di sinistra.
A questo punto vengono definiti i valori dei campi posizione e profondità grazie alle apposite Caselle di testo in pagina uno. Sono state previste tre posizioni: centrale, sinistra e destra per queste posizioni in tabella verranno inseriti rispettivamente “00””01”e”02”, mentre per le due profondità anteriore e posteriore “00” e “01”. Gli ultimi valori inseriti sono le coordinate che questa procedura metterà tutte a zero.
Infine Calcolacelle sblocca la tabella e fa un Refresh sulla tabella aggiornandola e attiva pagina due per permettermi l’inserimento delle quote. Il lancio della procedura sarà possibile al clic del comando Calcola, infatti all’interno della procedura Click di questo comando vi è un richiamo alla procedura Calcolacelle.
A questo punto dopo avere fatto il clic del comando Calcola avremo in tabella tutta la definizione riguardante la macchina e solo ora potrò inserire o modificare le quote.
2.1.2 La
procedura Coordinate
Coordinate permette di
calcolare ed inserire in tabella le quote delle celle di una parte, di più
parti o dell’intero scaffale.
Importante sapere di questa
procedura è che il calcolo si basa sui dati di pagina due, ma considerando le
celle riferite alla definizione scaffale per la macchina inserita in pagina
uno, anche per questo a scanso di errori sono stati pensati diversi controlli
tutte le volte che viene richiesto l’accesso alla pagina due, quindi l’uso
della pagina sarà concesso solo se esiste una definizione in tabella
corrispondente ai dati di pagina uno; questo controllo verrà fatto prima sul
numero celle, poi sullo stato delle posizione e delle profondità. Nel caso
venga impedito l’accesso vorrebbe significare che l’operatore inavvertitamente
ha cambiato il valore numero macchina, e quindi la definizione non risulta più
essere quella per la macchina inserita in tabella, o chiede di entrare in
pagina due senza avere prima lanciato Calcolacelle e quindi inserito i dati in
tabella; a questo punto verrà attivata pagina uno per permettergli di inserire
un numero macchina corretto o di cliccare su Cmd1 ed inserire la definizione in
tabella. Questo controllo evita di quotare o modificare celle differenti alle
quali l’operatore sia realmente interessato.
Il calcolo delle quote verrà
fatto, partendo da una coordinata iniziale ed in base al passo colonne digitati
in pagina due e al numero colonne e numero celle per colonna di pagina uno per
le X, mentre per le Y in base al passo piani e al numero piani.
Se in pagina1 sono state
inserite due profondità, Coordinate è in grado di calcolare anche le quote in
seconda profondità, quindi all’attivazione della seconda pagina un controllo
abiliterà Y2 e Z2 per permetterne l’uso. Per queste celle risulterà una
variazione di Y e Z, mentre X rimarrà invariata, quindi le celle in seconda
profondità saranno sfasate anche in altezza.
Questa procedura sarà lanciata grazie al clic di Cmd1 il comando Calcola, rappresentato da una calcolatrice, che verrà abilitato all’attivazione di pagina due per il suo lancio.
Come prima cosa, dopo avere selezionato attraverso Select la tabella all’interno del database su cui lavorare e inizializzato tutte le variabili utili alla procedura Coordinate, calcolerà il passocelle; questo valore risulterà molto importante infatti è il valore che mi permette di sapere il passo effettivo di una cella avendo prima solo il passo delle colonne, quindi se il passo colonne sarà dieci e le celle per colonna due il passocella sarà uguale al primo diviso il secondo quindi cinque.
Ora la procedura trova la posizione della prima cella della parte scaffale in base ai dati inseriti in pagina due e da questa partirà con la quotazione, se lo scaffale considerato è quello di sinistra allora si sommerà a questo numero il numero della prima cella di sinistra.
Dopo avere imposto di considerare solo i record non selezionati da Deleted con un Set deleted on e ordinato la tabella secondo un indice creato in precedenza, tenta di bloccarla per evitare che più utenti lavorino contemporaneamente su di essa. Se il blocco tabella non ha avuto successo l’operatore ne verrà messo al corrente attraverso un messaggio, mentre in caso contrario la procedura continuerà con il calcolo vero e proprio e l’inserimento dei dati nei record in tabella.
Attraverso cinque cicli For con una Seek la procedura Coordinate seleziona la giusta posizione e profondità della cella considerata e inserisce nel record selezionato le quote X, Y e Z calcolate in base al valore delle Caselle di testo delle coordinate della prima cella e del passocella che viene calcolato alla fine del ciclo delle posizioni cella. Dopo avere inserito i dati ci sarà un aggiornamento della posizione della cella da selezionare.
Alla fine del ciclo delle profondità con una Skip si selezionerà il record successivo, mentre alla fine del ciclo delle colonne la procedura farà il calcolo della X e della Y da inserire nella prossima cella al piano superiore.
2.1.3 La
procedura Modificaquote
Modificaquote fa la somma di una costante o una variabile
incrementale alle quote delle celle della parte di scaffale determinata da
colonna e piano iniziale, numero colonne e numero piani inseriti in pagina tre.
Questo calcolo lo fa sempre riferendosi alle celle della macchina in prima
pagina, quindi come in Coordinate verrà concesso l’accesso in pagina tre solo
se in tabella è rilevata una situazione macchina uguale a quella risultante in
pagina uno; questo controllo verrà fatto prima sul numero celle, poi sullo
stato delle posizione e delle profondità, in caso contrario all’operatore sarà
impedito l’accesso. In questi casi vorrebbe dire che l’operatore
inavvertitamente ha cambiato il valore numero macchina, e quindi la definizione
non risulta più essere quella per la macchina inserita in tabella o chiede di
entrare in pagina tre senza avere prima lanciato Calcolacelle e quindi inserito
i dati in tabella; a questo punto la procedura attiverà pagina uno per
permettergli di inserire il numero macchina esatto o di cliccare su Cmd1 ed inserire la definizione in
tabella. Questo controllo evita di quotare o modificare celle differenti alle
quali l’operatore sia realmente interessato. La somma alle quote può essere
costante o incrementale e può essere effettuata alle X o alle Y.
Per somma costante si
intende semplicemente prendere le quote delle celle in una determinata
posizione e profondità e sommargli una costante, mentre la una somma
incrementale consiste nel sommare una variabile che verrà moltiplicata per un
numero che incrementerà di uno di cella in cella fino a tornare al numero
iniziale passando ad un piano superiore.
La somma costante escluderà
la somma incrementale per la stessa coordinata, infatti un controllo all’uso di
una disabiliterà l’altra. L’utilizzazione di questa procedura è permessa dal
clic su cmd2 il comando Modifica, rappresentato da una matita e un righello,
che verrà abilitato all’attivazione di pagina tre.
Come prima cosa Modificaquote selezionerà con Select la tabella all’interno del database su cui lavorare e dopo avere inizializzato tutte le variabili utili alla procedura calcolerà la posizione della prima cella della parte scaffale in base ai dati inseriti dall’operatore nel primo spazio di pagina tre e da questa partirà con la somma, se lo scaffale considerato è quello di sinistra allora si sommerà al codice cella trovato il numero della prima cella di sinistra.
Dopo avere imposto di considerare solo i record non selezionati da Delete con un Set deleted on e ordinato la tabella secondo un indice creato in precedenza tenta di bloccarla per evitare che più utenti lavorino contemporaneamente su di essa. Se il blocco tabella non ha avuto successo l’operatore ne verrà messo al corrente attraverso un messaggio, mentre in caso contrario la procedura continuerà con il calcolo vero e proprio e l’inserimento dei dati nei record in tabella.
Attraverso cinque cicli For con una Seek la procedura Modificaquote selezionerà la giusta posizione e profondità della cella considerata e inserirà nel record selezionato le somme di X e Y calcolate in base al valore delle apposite Caselle di testo in pagina tre
Dopo avere inserito i dati ci sarà un aggiornamento della posizione della cella da selezionare.
Alla fine del ciclo delle profondità con una Skip si selezionerà il record successivo, mentre alla fine del ciclo delle colonne la procedura calcolerà il contatorey, col quale eseguirà il calcolo della somma incrementale alle Y, mi azzererà il contatorex per la somma incrementale delle X.
Infine viene sbloccata la tabella e chiusa la transizione.
Questo oggetto mi permette di raccogliere in modo ordinato e quindi mi permette una semplice consultazione di tutte le informazioni contenute all’interno del progetto suddividendole in cinque pagine caratterizzate ognuna da una specifica funzione.
Non sono state usate procedure di questo oggetto ed in particolare è stata usata una proprietà, che determina il suo numero di pagine, Page Count impostata naturalmente a cinque.
2.2.1 Prima Pagina
La prima pagina è sicuramente la più importante nell’esecuzione del progetto, qui infatti vengono inseriti i dati grazie ai quali la procedura Calcolacelle creerà ed inserirà i record in tabella.
Di questa oggetto è stata
usata solo la sua procedura Refresh() per rinfrescare il valore della Casella
di testo della prima cella di sinistra in modo d’avere sempre all’accesso in
pagina il valore riferito alla macchina giusta.
Cmalabel1: Etichetta Nmac “Macchina”
Nmac: Casella di testo attraverso la quale viene definito il numero macchina
Procedure utilizzate: Lostfocus
Proprietà utilizzate: Name,
Tablndex, Value
Shape1: Spazio riservato ai dati per il lato
Proprietà utilizzati: SpecialEffect
Cmalabel2: Etichetta Shape1 “Selezione lato :”
Cmalabel3: Etichetta Combo1 “Lato :”
Cmalabel4: Etichetta Npce “Numero prima cella lato SX :”
Proprietà utilizzate: Visible
Npce: Casella
di testo che definisce il numero prima cella di sinistra
Proprietà utilizzate : Name,
Tablndex, Value, Visible
Combo1: Casella
di riepilogo che definisce il lato scaffale
Procedure utilizzate: Init, Interactivechace, Lostfocus
Proprietà utilizzate: Name, Rowsource, RowsourceType, Tablndex
Shape2: Spazio riservato ai dati per la definizione
Cmalabel5: Etichetta Shape2 “Dati per la definizione:”
Cmalabel6: Etichetta Ncol “Numero colonne:”
Cmalabel7: Etichetta Npia “Numero piani:”
Cmalabel8: Etichetta Ncco “Numero celle per colonna”:
Cmalabel9: Etichetta Npos “Numero posizioni”
Cmalabel10: Etichetta Npro “Numero profondità”
Ncol: Casella di testo che mi definisce il numero di colonne
Npia: Casella di testo che mi definisce il numero di piani
Ncco: Casella di testo che mi definisce il numero di celle per colonna
Npos: Casella di testo che mi definisce il numero di posizioni
Procedure utilizzate: LostFocus
Npro: Casella di testo che mi definisce il numero di profondità
Procedure utilizzate: LostFocus
Funzionamento delle principali procedure e proprietà
utilizzate dai vari oggetti contenuti in pagina uno.
Ho inserito nel metodo Active di pagina1 un Refresh della form che permetta l’attivazione dei comandi utili alla pagina. La proprietà Caption mi permette di rappresentare la pagina con “ Definizione scaffale”. Per le etichette Cmalabel è stata usata un’unica proprietà significativa Caption con la quale si definito il suo testo. Nella prima pagina ho inserito un insieme di CmaText che permetteranno all`operatore di inserire con Nmac il numero di macchina, Ncol il numero colonne, Npia il numero piani, Ncco il numero celle per colonne ed inoltre con Npos ed Npro il numero posizioni e numero profondità previste all’interno di una singola cella; una semplice Combo invece mi guiderà alla selezione del lato dello scaffale destro o sinistro. Ogni dato inserito avrà delle limitazioni e controlli che eviteranno errori all’interno del progetto. Per il numero macchina è stato previsto un numero che va da 1 a 99; questo all’interno della tabella deve essere univoco, quindi se viene inserita una definizione scaffale con un numero macchina già presente nella tabella il programma permetterà due strade:
1.
Annullare
la definizione
2.
Proseguire
la definizione andando a sostituire quella già esistente.
La scelta del
lato dello scaffale è stata facilitata da Combo1 nella quale andare a
selezionare il lato “D “ o il lato “S “, nella sua procedura Interactivechace
ho inserito un controllo che renderà visibile Cmalabel4 e Ncpe se e solo se il
lato risulterà essere quello di sinistra, se venisse inserito un valore diverso
dai due detti in precedenza un controllo all’interno della procedura Lostfocus
me lo farà notare e metterà il valore uguale a ”D “, infatti ogni altro valore
non sarà permesso perché potrebbe portare a diversi errori. Nella procedura
Init inizializzo la Combo1 mettendo il suo valore uguale a “D “. Le proprietà
Rowsource e RowsourceType mi definiscono i valori delle caselle della Combo.
In Npce verrà
riportato il numero della prima cella del lato sinistro dello scaffale , questo
dovrà essere inserito sempre anche se la definizione non interessa
apparentemente questo lato, perché la
procedura Calcolacelle ne avrà bisogno, infatti sarà fondamentale sapere dove
inizia e dove termina il lato destro.
Inizialmente
Npce non sarà visibile grazie all` impostazione a false della sua proprietà
Visible, sarà possibile vederlo solo se sarà selezionato il lato sinistro. Il
suo valore sarà uguale a quello della prima cella di sinistra, relativa al
numero macchina corrente, presente in tabella; se non venisse trovato nessun
valore Npce risulterà uguale a zero. Per il numero colonne non ci sono ne’
limitazioni ne’ controlli come per il numero di piani ed il numero celle per
colonna.
Il numero
posizioni all’interno della cella dovrà essere 1 2 o 3, mentre il numero
profondità potrà essere 1 o 2. In base
a questo valore verranno abilitate le coordinate in seconda profondità situate
in seconda pagina, mettendo le loro proprietà Enabled, proprietà che determina
se un controllo è attivo o meno, uguale a true. I controlli di Npos e Npro
verranno fatti usando Lostfocus, così rilasciando la Casella di testo il programma attraverso un
messaggio informerà dell’errore l’operatore e lo correggerà automaticamente
forzando il valore a uno.
Una volta
inseriti tutti questi dati l’operatore e’ in grado di poter calcolare e quindi
definire il numero di celle dello scaffale, con coordinate tutte a 0,
attraverso l` apposito pulsante Cmd1 rappresentato da una calcolatrice. Se
tutto va bene verranno così inserite tutte le celle con relativa macchina,
posizione, profondità e coordinate tutte a zero in una tabella QUOTE e tramite
Activepage, attivazione di una macchina, si salta a pagina due, ma se il
programma tramite un controllo Refresh, rinfresco comandi, di pagina due non
trovasse in tabella una definizione rappresentante la situazione in pagina uno
bloccherà il passaggio e la pagina
attivata rimarrà la numero uno.
2.2.2 Seconda Pagina
La seconda pagina è la parte del progetto che mi permette di quotare una parte della tabella, qui infatti vengono inseriti i dati grazie ai quali la procedura Coordinate calcolerà ed inserirà in tabella le coordinate fino a quel momento uguali a zero.
Di questa pagina è stata
usata solo la sua procedura Refresh per controllare che in tabella esista una
definizione che rispecchi la situazione in pagina uno e per abilitare o meno le
coordinate in seconda profondità a seconda del numero profondità inserito in
pagina uno; in più è stata usata la procedura Active che all’attivazione della
pagina abilita i comandi.
Shape1: Spazio riservato ai dati per la quotazione scaffale
Proprietà utilizzate: SpecialEffect
Cmalabel1: Etichetta Shape1 “Selezione lato”
Cmalabel2: Etichetta Colini “Colonna Inizio”
Cmalabel3: Etichetta Ncol “Numero colonne :”
Cmalabel4: Etichetta PasCol “Passo colonne“
Cmalabel5: Etichetta PiaIni “Piano inizio”
Cmalabel6: Etichetta
Npia “Numero piani“
Cmalabel7: Etichetta PasPia “Passo piani”
Colini: Casella di testo che definisce la colonna di inizio
Procedure utilizzate: LostFocus
Ncol: Casella
di testo che definisce il numero colonne
Procedure utilizzate: LostFocus
PasCol: Casella di testo che definisce il passo colonna
PiaIni: Casella
di testo che definisce il piano di inizio
Procedure utilizzate: LostFocus
Npia: Casella
di testo che definisce il numero piani
Procedure utilizzate: LostFocus
Paspia: Casella
di testo che definisce il passo piani
Shape2: Spazio riservato alle coordinate della prima cella in prima profondità
Proprietà utilizzate: SpecialEffect
Cmalabel8: Etichetta Shape2 “Coordinate prima cella”
Cmalabel9: Etichetta X “X”
Cmalabel10: Etichetta
Y “Y”
Cmalabel11: Etichetta Z “Z”
X: Casella di testo che definisce la coordinata x prima cella
Y: Casella
di testo che definisce la coordinata y prima cella
Z: Casella
di testo che definisce la coordinata z prima cella
Shape3: Spazio riservato alle coordinate della prima cella in seconda profondità
Proprietà utilizzate: SpecialEffect
Cmalabel12: Etichetta Shape3 “Coordinate prima cella in seconda profondità :”
Proprietà utilizzate: Enabled
Cmalabel13: Etichetta Y “Y”
Proprietà utilizzate: Enabled
Cmalabel14: Etichetta Z “Z”
Proprietà utilizzate: Enabled
Y2: Casella
di testo che definisce la coordinata y in seconda profondità
Proprietà utilizzate: Enabled
Z2: Casella
di testo che definisce la coordinata z in seconda profondità
Proprietà utilizzate: Enabled
Funzionamento delle principali procedure e proprietà
utilizzate dai vari oggetti contenuti in pagina due
Con un RefreshForm inserito in Active di pagina due rinfresco la situazione pulsanti andando ad abilitare solo quelli utili alla pagina.
Nella procedura Refresh della pagina ho inserito un controllo che mi
permette di lavorare sulla pagina solo se è stata rilevata in tabella una
situazione macchina uguale a quella riscontrata in Page1, questo per evitare
che l’operatore vada a quotare una scaffale per una macchina diversa da quella
realmente voluta. Il programma andrà prima a fare un controllo sul numero celle
poi sulle posizioni e profondità; trovata una discordanza l’operatore verrà
informato tramite un messaggio e verrà impedito l’accesso alla pagina venendo
riportati a pagina uno.
Sempre nel Refresh sono state inserite delle istruzioni che mi permetteranno di andare ad abilitare le coordinate in seconda profondità, in partenza disabilitate, se in pagina uno il numero profondità inserito è uguale a due.
Per gli spazi Shape è stata usata la proprietà SpecialEffect con la quale si ottiene un effetto tridimensionale dei bordi che delimitano lo spazio all’interno del quale andare ad inserire i dati.
Per le etichette Cmalabel è stata usata un’unica proprietà significativa
Caption con la quale si è definito il suo testo; in alcune attraverso la
proprietà Enable è stata prevista l’abilitazione solo in particolari
situazioni.
Nella seconda
pagina l’operatore inserirà il numero della prima colonna e del primo piano
dello scaffale da cui si vuole partire con la quotazione ed il numero delle
colonne e dei piani per i quali questa deve proseguire.
Verranno poi
inseriti il passo delle colonne ed il passo dei piani, infine verranno inserite
le coordinate delle prima cella in prima, ed
eventualmente in seconda profondità. Come nella pagina precedente con l`
apposito comando verrà quotata la parte di scaffale in base alle coordinate
iniziali e al passo colonne e passo piani.
Nel metodo
LostFocus del numero prima colonna Colini e primo piano PiaIni sarà’ inserito
un controllo che impedirà l’inserimento di un numero uguale a 0 o maggiore di
quello inserito in pagina1, mentre nel numero colonne Ncol e numero piani Npia
questo controllo si assicurerà che la somma del numero di inizio e del numero
di scansione non superi il numero totale di piani o colonne in pagina uno.
Per il
CmaText passo colonne e passo piani non
sono state previste limitazioni, così come per le coordinate in prima e seconda
profondità’.
Per tutti i
CmaText è stata usata la proprietà Value per inizializzarne il valore: per le
coordinate uguale a zero e per gli altri uguale a uno.
2.2.3 Terza Pagina
La terza pagina è la parte del progetto che mi consente di modificare le quote di una parte della tabella, qui infatti vengono inseriti i dati grazie ai quali la procedura Modificaquote calcolerà ed inserirà in tabella le nuove coordinate.
In questa pagina è stata
usata la procedura Refresh, come nella pagina precedente, per controllare che
in tabella esista una definizione che rispecchi la situazione in pagina uno, in
più è stata usata la procedura Active per permettere l’abilitazione dei
pulsanti.
Shape1: Spazio riservato ai dati per la modifica delle celle
Proprietà utilizzate: SpecialEffect
Cmalabel1: Etichetta Shape1 “Dati per la modifica delle celle :”
Cmalabel2: Etichetta Colini “Colonna Inizio :”
Cmalabel3: Etichetta Ncol “Numero colonne :”
Cmalabel4: Etichetta PiaIni “Piano inizio”
Cmalabel5: Etichetta Npia “Numero piani “
Colini: Casella di testo che
definisce la colonna inizio
Procedure utilizzate: LostFocus
Ncol: Casella di testo che
definisce il numero colonne
Procedure utilizzate: LostFocus
PiaIni: Casella di testo che
definisce il numero piani
Procedure utilizzate: LostFocus
Npia: Casella di testo che
definisce il numero piani
Procedure utilizzate: LostFocus
Shape2: Spazio riservato alle costanti da sommare alle quote delle celle selezionate
Proprietà utilizzate: SpecialEffect
Cmalabel6: Etichetta Shape2 “Somma costante”
Cmalabel7: Etichetta X cost “X”
Cmalabel8: Etichetta
Y cost “Y”
Xcost: Casella di testo che
definisce la somma costante x
Procedure utilizzate: InteractiveChange
Proprietà utilizzate : Enabled
Ycost: Casella di testo che
definisce la somma costante y
Procedure utilizzate: InteractiveChange
Proprietà utilizzate : Enabled
Shape3: Spazio riservato alle variabili da sommare alle quote delle celle selezionate
Proprietà utilizzate: SpecialEffect
Cmalabel9: Etichetta Shape3 “Somma incrementale”
Cmalabel10: Etichetta X inc “X”
Cmalabel11: Etichetta
Y inc “Y”
Xinc: Casella di testo che
definisce la somma incrementale x
Procedure utilizzate: InteractiveChange
Proprietà utilizzate : Visible
Yinc: Casella di testo che
definisce la somma incrementale y
Procedure utilizzate: InteractiveChange
Proprietà utilizzate : Visible
Funzionamento delle principali procedure e proprietà
utilizzate dai vari oggetti contenuti in pagina tre
Con un RefreshForm inserito in Active di pagina due rinfresco la situazione pulsanti abilitando solo quelli utili alla pagina.
Nella procedura Refresh della pagina ho inserito un controllo che mi permette di entrare solo se è stata rilevata in tabella una situazione macchina uguale a quella riscontrata in pagina uno, questo per evitare che l’operatore vada a quotare una scaffale per una macchina diversa da quella realmente voluta. Il programma andrà prima a fare un controllo sul numero celle poi sulle posizioni e profondità; trovata una discordanza l’operatore verrà informato tramite un messaggio e verrà impedito l’accesso alla pagina venendo riportati a pagina uno.
Per gli spazi Shape è stata usata la proprietà SpecialEffect con la quale
si ottiene un effetto tridimensionale dei bordi che delimitano lo spazio
all’interno del quale inserire i dati. Per le etichette Cmalabel è stata usata
un’unica proprietà significativa Caption con la quale si è definito il suo
testo.
La terza pagina
permette all’operatore di sommare una costante o una variabile incrementale
alle coordinate X, X1,Y1 e Y2 delle celle di una parte dello scaffale. Questa
pagina prevederà l’inserimento del numero
della prima colonna e primo piano, del numero colonne e numero piani, per stabilire la parte di scaffale, poi
naturalmente la variabile per la somma costante o incrementale di X o Y. La
somma costante ad una coordinata escluderà la
somma incrementale grazie ad un controllo inserito nel InteractiveChance
di Xcos, Ycos e Xinc, Yinc attraverso il quale si varia la proprietà Enabled
che abilita o meno la Casella di testo.
Nel metodo
LostFocus del numero prima colonna Colini e primo piano PiaIni sarà’ inserito
un controllo che impedirà l’inserimento di un numero uguale a 0 o maggiore di
quello inserito in pagina uno, mentre nel numero colonne Ncol e numero piani
Npia questo controllo si assicurerà che la somma del numero di inizio e del
numero di scansione non superi il numero totale di piani o colonne in pagina
uno.
2.2.4 Quarta Pagina
La quarta pagina è la parte del progetto che mi permette di consultare la situazione celle attraverso una griglia che mi rappresenta la tabella sulla quale il progetto va a lavorare. La Griglia descriverà la situazione celle grazie a numero macchina, codice cella, posizione, profondità, quota x, quota y e quota z divisi da sette colonne.
Di questa pagina è stata
usata solo la procedura Active che consente l’abilitazione dei pulsanti utili
alla pagina..
Grid1: Griglia che rappresenta la
tabella
Procedure utilizzate: Refresh
Proprietà utilizzate: ColumnCount, RecordSource
Funzionamento delle principali procedure e proprietà
utilizzate dai vari oggetti contenuti in pagina tre
Nella quarta
pagina sarà possibile controllare la situazione aggiornata dello scaffale
attraverso una tabella che mi fotograferà la situazione attuale di ogni cella.
La tabella e’
rappresentata attraverso un controllo Grid; con la proprietà Column si
definisce il numero colonne di questo controllo uguale a sette rappresentanti:
numero macchina, codice cella, posizione, profondità, coordinata x, coordinata
y e coordinata z. La proprietà RecordSource indicherà dove prelevare i dati da
inserire all’interno della griglia
A questa tabella
e’ associato un indice che attraverso la procedura Refresh la ordina per numero macchina, codice cella, posizione
e profondità .
2.2.5 Quinta Pagina
Attraverso la quinta pagina l’operatore è in grado di creare una copia di una definizione già presente in tabella per una macchina da lui inserita in più selezionando la Casella di controllo potrà anche eliminare tutti i record presenti in tabella riferiti ad una macchina .
In questa pagina è stata
usata la procedura Active per permettere l’abilitazione delle Caselle delle
prime celle di sinistra, della macchina da eliminare e dei comandi utili alla
pagina.
Shape1: Spazio riservato ai dati per la copia di una macchina
Proprietà utilizzate: SpecialEffect
Cmalabel1: Etichetta Shape1 “Crea definizione scaffale per una macchina copiandone una esistente”
Cmalabel2: Etichetta Nmaces “Sorgente:”
Cmalabel3: Etichetta Nmacin “Destinazione :”
Cmalabel4: Etichetta Combo1 “Lato macchina esistente”
Cmalabel5: Etichetta Combo2 “Lato macchina da inserire“
Cmalabel9: Etichetta Npces “Prima cella sinistra sorgente”
Cmalabel10: Etichetta Npced “Prima cella sinistra destinazione”
Npces: Casella di testo che definisce il numero cella di sinistra sorgente
Npced: Casella di testo che definisce il numero cella di sinistra destinazione
Nmaces: Casella di testo che
definisce la macchina sorgente
Procedure utilizzate: LostFocus
Nmacis: Casella di testo che
definisce la macchina destinazione
Procedure utilizzate: LostFocus
Combo1: Casella di riepilogo
che definisce il lato sorgente
Procedure utilizzate: Init, InteractivreChange, LostFocus
Proprietà utilizzate: RowSource,
RowSource Type
Combo2: Casella di riepilogo
che definisce il lato destinazione
Procedure utilizzate: Init, InteractivreChange, LostFocus
Proprietà utilizzate: RowSource, RowSource Type
Shape2: Spazio riservato alle macchina da eliminare
Proprietà utilizzate: SpecialEffect
Cmalabel6: Etichetta Shape2 “Elimina solo una parte della tabella”
Cmalabel7: Etichetta Nmaccan “Numero macchina:”
Cmacheck1: Casella di
controllo che abilita Nmaccan e Cmd5
Procedure utilizzate: InteractiveChange
Nmaccan: Casella di testo che
definisce i record macchina da eliminare
Proprietà utilizzate: Enabled
Funzionamento delle principali procedure e proprietà
utilizzate dai vari oggetti contenuti in pagina cinque
Per gli spazi Shape è stata usata la proprietà SpecialEffect con la quale si ottiene un effetto tridimensionale dei bordi che delimitano lo spazio all’interno del quale inserire i dati.
Per le etichette Cmalabel è stata usata un’unica proprietà significativa
Caption con la quale si è definito il suo testo.
Attraverso la procedura
LostFocus di Nmacin e Nmaces vengono controllati che i dati inseriti siano
corretti, quindi compresi tra 1 e 99.
Per Combo1 e Combo2 sono
state utilizzate le procedure Init, InteractiveChange e LostFocus; con la prima
si è andato ad inizializzare la Combo con “D”, con la seconda, se necessario,
si rendono visibili le Caselle di testo per la prima cella di sinistra e con la
terza si controlla che i caratteri inseriti siano corretti, mentre con le
proprietà RowSource e RowSource Type si definiscono i valori delle Caselle di
testo delle Combo.
Poi per la Casella di controllo Cmacheck1 è stata usata la procedura InteractiveChange con la quale si abilita il comando per la cancellazione dei record di una macchina.
I pulsanti hanno la funzione di eseguire tutte le procedure fondamentali del progetto; quindi l’utente grazie a questi sarà in grado in ogni momento di eseguire le varie funzioni aiutato anche da immagini e indicazioni che caratterizzeranno ogni pulsante in base alla propria funzionalità.
Attraverso il semplice clic su un pulsante è
possibile lanciare ad esempio le procedure Calcolacelle, Coordinate e
Modificaquote contenute nelle procedure della Form oppure cancellare record
dalla tabella o copiare definizioni di scaffale.
Ogni pulsante sarà abilitato solo in precise
pagine, questo per evitare che si vadano ad eseguire funzioni in pagine non
previste per esse.
Ogni pulsante può anche essere in grado di eseguire
più di una funzione a seconda della pagina in quel momento attiva; il pulsante
calcola se attiva la pagina uno lancia Calcolacelle se attiva pagina due lancia
Coordinate se al contrario è attiva qualsiasi altra pagina il pulsante
risulterà disabilitato.
L’uso di questo comando è possibile solo se ci si trova in pagina tre per tutte le altre pagine sarà disabilitato.
L’eliminazione dei record non avviene fisicamente, ma selezionandoli con l’istruzione Delete e mettendo il numero macchina uguale a zero così da essere posti ad inizio tabella dall’indice e pronti per essere recuperati dall’istruzione Recall; prima di fare qualsiasi operazione la tabella sarà stata prontamente bloccata.
L’uso di questo comando è possibile solo se ci si trova in pagina quattro, la pagina dove è consultabile la tabella, per tutte le altre pagine sarà disabilitato.
È possibile anche fare la copia dello scaffale di destra sullo scaffale di sinistra di una stessa macchina e viceversa.
Se viene preso in
considerazione lo scaffale di sinistra la procedura per proseguire avrà bisogno
di sapere sempre la prima cella dello scaffale di sinistra altrimenti non sarà
possibile proseguire; la procedura verrà interrotta anche se la macchina da
copiare non è stata trovata, mentre se la macchina da inserire è già presente
l’operatore potrà o rinunciare all’operazione o sostituire tutti i record
riferiti alla macchina in tabella coi nuovi creati dalla procedura.
Passati tutti i controlli
iniziali vengono selezionati i record da copiare e viene calcolato i codici
cella dei nuovi basandosi sullo scaffale e sulla prima cella di sinistra. Il
codice cella è l’unico campo che cambia infatti posizione, profondità e
coordinate rimarranno uguali al record presente in tabella. Se lo scaffale da
copiare è quello di destra un controllo
alla fine della procedura mi impedirà di continuare il ciclo nel caso venisse
trovata la prima cella dello scaffale di sinistra, consentendomi di fare la
copia solo ed esclusivamente delle celle di destra.
L’uso di questo comando è possibile solo se ci si trova in pagina cinque, per tutte le altre pagine sarà disabilitato.
L’eliminazione dei record non avviene fisicamente, ma selezionandoli con l’istruzione Delete e mettendo il numero macchina uguale a zero così da essere posti ad inizio tabella dall’indice e pronti per essere recuperati dall’istruzione Recall; prima di fare qualsiasi operazione la tabella è stata prontamente bloccata.
DOCUMENTAZIONE
La prima parte di questo
capitolo ha l’obbiettivo di fornire dettagli sull’uso delle classi e sulla
strutturazione dei progetti per il programma di gestione dei magazzini WINSTORE
creato ed utilizzato da System Logistics in un ambiente di sviluppo
rappresentato da VISUAL FOX.
La seconda parte è dedicata
alla documentazione del codice più significativo sviluppato all’interno del mio
progetto.
Dopo aver installato il
VISUAL FOX PRO ed essere entrati nell’ambiente di sviluppo, alla voce “OPZIONI”
del menu “TOOLS” occorre effettuare le seguenti impostazioni:
La seguente finestra di
configurazione contiene tutti i percorsi significativi del sistema FOX.
Si lasceranno tutti
invariati, ad eccezione di PATH (come si vede, i files verranno cercati
dapprima nelle directories del sottoprogetto della commessa, poi, in assenza di
essi, nelle directories comuni.
Il flag di “DEFAULT
DIRECTORY” sara’ deselezionato, in modo da assumere, per ogni sottoprogetto,
l’opportuna “ROOT DIRECTORY”; questo sara’ ottenuto realizzando, in WINDOWS,
dei Links all’eseguibile VFP.EXE (eseguibile di FOX), con ambiente di lavoro
uguale alla directory del sottoprogetto.
nel caso lo sviluppatore sia
client di un SERVER VISUAL SOURCE SAFE, e’ possibile integrare l’ambiente FOX
con il SOURCE SAFE stesso con la seguente impostazione:
I settaggi relativi alla
valuta, alla data e ora etc. potranno essere presi da quelli impostati in
ambiente WINDOWS (Pannello di Controllo) con il seguente settaggio:
Tutti i valori non
menzionati nelle surriportate finestre potranno essere lasciati ai valori di
default.
Per ogni commessa, il nome
consigliato per la directory ROOT del progetto e’:
-
WINSTORE_<nomeCommessa>.
Le sottodirectory fisse
(contenenti form, classi e reports comuni ai vari sottoprogetti che formeranno
la commessa) sono:
-
code
(contenente i forms di uso piu’ comune);
-
lib
(contenente le classi di uso piu’ comune);
-
lib\bmp
(contenente le immagini e le icone di uso piu’ comune);
-
report
(contenente i reports di stampa di uso piu’ comune).
Saranno poi create tante
directories quanti sono i sottoprogetti che costituiscono la commessa. Ognuna
di esse potra’ avere il proprio “code”, “lib”, “lib\bmp”, “report”, in cui
saranno collocati i files specifici del sottoprogetto (peraltro “prioritari”, a
parita’ di nome, rispetto a quelli comuni, in virtu’ della sopracitata
configurazione del PATH di RICERCA).
Nella ROOT del sottoprogetto
sara’ creato il file di progetto (.pjx, abbinato al suo indice.pjt), che
rappresenta il collettore dei files che costituiscono il sottoprogetto.
Nota per utilizzatori del SOURCE SAFE:
In ambiente integrato con
VISUAL SOURCE SAFE, esiste (oltre ai files.pjx e.pjt) anche un terzo file
(prodotto automaticamente dal SOURCE SAFE all’atto dell’inserimento del
progetto stesso nel SOURCE SAFE), con estensione.pjm.
Si tratta di un file di
testo, contenente tutti i nomi dei files (coi loro percorsi relativi rispetto
alla posizione del progetto) contenuti nel progetto. Esso e’ l’unico file (tra
i tre suddetti) che viene realmente posto sotto SOURCE SAFE. Quando un
operatore deve aggiornare la struttura di un progetto, deve effettuare
l’operazione di “Join Source Control Project” (menu’ File), specificando il
progetto corretto; questo garantisce l’aggiornamento dei due files locali.pjx
e.pjt.
A questo punto, l’operatore
puo’ aggiornare la struttura ed effettuare la “Update Project List” (menu’
“Project \ Source Control”), riportando, cosi’, le modifiche locali al.pjm, di
cui, per terminare,.dovra’ essere fatto il Check In direttamente dall’ambiente
Source Safe, per renderlo disponibile anche ad altri utenti.
Le classi gia’ realizzate
contengono la maggior parte delle proprieta’ e dei metodi che possono occorrere
al programmatore per realizzare progetti WINSTORE (ed anche non correlati a
WINSTORE).
Preme ricordare che tutte le istanze delle classi, i forms ed eventuali
nuove classi (ereditate o meno da quelle gia’ esistenti) vanno legate
all’opportuno file di costanti (normalmente WS_BASE.H), agiendo sul menu’: FORM
/ Include File.. o: CLASS / Include File…
Esistono alcuni files di
classi di utilita’ generale che conviene sempre linkare al progetto:
-
CMAGEN.VCX: contiene la maggior parte
delle classi visuali e di utilita’ generale utilizzate per la realizzazione dei
progetti. Eventuali personalizzazioni non dovranno essere effettuate su queste
classi, ma su classi ereditate da queste, normalmente poste nel file USER.VCX, posto nella directory.
Le
classi principali contenute in CMAGEN.VCX sono:
· Classe Application: viene utilizzata come classe da cui ereditare la
classe USER (contenuta nel file USER.VCX) e contiene tutte le proprieta’ di uso
generale per tutti i progetti, non le relative inizializzaioni (il metodo
ReadIni, invocato dall’evento Init, provvede a leggere dal file init.ini, nella
stessa directory dell’eseguibile, e dai files indSock.ini e inicom.ini, nella
stessa directory del DataBase principale, i parametri di configurazione, da
riportare su altrettante proprieta’).
Nella classe USER (specifica
del progetto), potranno essere create ed inizializzate altre proprieta’ (oltre
che implementati altri metodi).
Il file main.prg (contenente
il codice con cui il programma parte) provvede a inizializzare una variabile
globale (unica di tutto il progetto), detta “oApp”, ponendovi il puntatore ad
una istanza della classe USER.
Viene di seguito riportato
un tipico main.prg:
* Inclusione file di costanti (esso include, a sua volta, il link ai
files di costanti generali)
#INCLUDE WS_BASE.H
* Apertura files di classi
utilizzate nel programma:
SET CLASSLIB TO CMAGEN,
USER, UT_LOG, UT_MENU………..
* Eventuali settaggi
relativi allo SCREEN (icona, titolo, etc.)
_SCREEN.icon =
"cma2.ico"
_SCREEN.caption =
"Titolo Applicativo"
…..
* Eliminazione menu
principale (verra’ ricostruito in base all’utente loggato)
SET SYSMENU OFF
* Testa che sia andata a
buon fine la creazione;
* Chiama il metodo di
creazione delle istanze delle classi di utilita’ linkate ad oApp (iniUti);
* Abilita la costruzione dei
menu’ personalizzati per gli utenti;
* Invoca il metodo
principale (DO), in cui viene richiesto il Login, costruito il menu’
personalizzato per l’utente loggato (se necessario). In programmi Mono-Form (un
unico form modale, in cui si svolge tutta la gestione) il form stesso viene
lanciato direttamente dal metodo DO, senza costruzione del menu’.
PUBLIC oApp
oApp = CREATEOBJECT("User")
if TYPE('oApp') = "O"
if oApp.iniuti() =.T.
oApp.NoAddToMenu =.F. &&
-- &&
oApp.Do() &&
-- &&
endif
endif
* Liberazione memoria e
conclusione programma
CLOSE
DATA ALL && -- &&
CLEAR
ALL && -- &&
RELEASE
ALL EXTENDED && -- &&
N.B.
E’ possibile, semplicemente eliminando, dal main.prg, le righe di codice
denotate con “&& -- &&”, ottenere un semplice programma
(normalmente chiamato oApp.prg), linkato al progetto ma marcabile come
“ESCLUSO” (perche’ non sara’ impiegato nell’eseguibile finale, ma solo in fase
di DEBUG). Lanciando preventivamente tale.prg, sara’ possibile lanciare e
provare i singoli forms, che si troveranno tutte le proprieta’ generali gia’
inizializzate.
Naturalmente, occorrera’, al termine del DEBUG, deallocare la memoria e chiudere tutti i databases e le tabelle.
Questo e’ possibile semplicemente costruendo un.prg (normalmente chiamato release.prg), linkato al progetto ma escluso da esso, contenente le seguenti righe di codice:
CLOSE
DATA ALL
CLEAR
ALL
RELEASE ALL EXTENDED
Durante il corso del
programma, potra’ essere referenziata una qualunque proprieta’ generale di USER
(o APPLICATION) tramite la notazione:
oApp.proprieta’.
ESEMPI SIGNIFICATIVI:
oApp.fileIni = file.ini locale per parametri
di configurazione;
oApp.fileIniCom = file.ini comune per parametri
configurazione generali;
oApp.pathFiles = Path in cui e’ contenuto il dataBase principale e le relative tabelle;
oApp.pathWork = Path in cui sono contenute eventuali tabelle di appoggio per l’applicativo (di default, coincide con la directory dell’eseguibile);
oApp.lingua = Codice della lingua (IT, SP,
FR, IN,..);
oApp.help =
File di help (Path completo);
oApp.terminale = Numero terminale (01 – 99);
oApp.tipoApp = Tipo applicazione (AN per
Anagrafiche, LS per liste, CO per configuratore, etc.);
oApp.chiaviTab(n,3)=
Array di tre colonne, inizializzato nell’evento init di USER, in cui:
oApp.chiaviTab(n, 1) = “Nome
tabella”;
oApp.chiaviTab(n, 2) =
“Campi da visualizzare nel log delle modifiche (USER_LOG), per identificare
univocamente il record modificato”;
oApp.chiaviTab(n, 3) =
“Campo indice qualunque che verra’ utilizzato dal metodo di rinfresco degli
indici prima di una ricerca in una tabella (uti.seek)”;
· Classe FormModal: rappresenta la classe immediatamente ereditata dalla
classe FORM, corredata di diverse funzionalita’:
Ø Scrittura su file init.ini
della posizione della finestra sulla chiusura (metodo WriteWindowPos) con
recupero posizione sull’apertura (metodo RestoreWindowPos);
Ø Traduzione automatica dei
testi sull’apertura della finestra (se richiesta) (metodo formTrad).
Ø Possibilita’ di implementare
la barra di scorrimento nei LOOPs:
thisform.barra(BAR_CREA, TitoloBarra,
Val.minimo, Val. massimo, Val. di incremento, Possibilita’ di uscita con CTRL +
F12 (.t. o.f.)) à crea barra;
thisform.barra(BAR_INCREM) à incrementa contatore;
thisform.barra(BAR_DELETE) à distrugge barra.
La classe si linka,
sull’inizializzazione, le istanze delle due classi UT_FORM (nome istanza: UTI) e USER_LOG (nome istanza: LOG), particolarmente utili, in quanto
contenenti metodi fondamentali per la gestione (vedi di seguito).
A tali metodi potro’
riferirmi, in qualunque momento, con:
thisform.uti.<nomeMetodo>(elenco
parametri)
o con:
thisform.log.<nomeMetodo>(elenco
parametri)
N.B.
Per creare un form derivandolo non dalla classe base FORM, ma da una classe
ereditata da FORM (come la FormModal), occorre, nel menu’ Tools / Opzions,
effettuare la seguente configurazione:
N.B.
Una volta creato un form (derivato da una qualunque classe ereditata dalla
classe FORM) sara’ possibile creare proprieta’ e metodi personalizzati
semplicemente usando le voci di menu’:
form / New Property;
form / New Method.
· Classe FormBase: ereditata da FormModal e corredata della seguente
funzionalita’ aggiuntiva:
Ø Aggiunta e rimozione al/dal
menu (menu’ Finestre) del titolo del form (metodi AddToMenu e RemoveFromMenu,
invocati rispettivamente all’inizializzazione ed alla distruzione del form);
· Classe FormTabella: ereditata da FormBase, e’ dotata delle funzionalita’
di base per gestire una tabella (barra degli strumenti, istanza della classe DBButtonArray). L’ambiente dati e’
PRIVATO (proprieta’ DataSession = 2), il che evita interferenze con dati di
altri form concorrenti.
E’ necessario, per gestire
una tabella anagraficamente, legare la tabella all’ambiente dati del form
(DataEnvironment), settare la proprieta’ del DataEnvironment
InitialSelectedAlias = Alias della Tabella e creare, sul form, la griglia
(meglio se istanziata dalla classe GRIDFILT,
in quanto gia’ corredata di diverse funzionalita’, che verranno di seguito
descritte), che sara’ legata all’Alias della Tabella (campo RecordSource) e le
cui colonne saranno legate ai campi opportuni (campo ControlSource delle
colonne).
N.B. Allo scopo di consentire, RUNTIME, una collocazione del / dei
Databases diversa da quella dell’ambiente di sviluppo, e’ assolutamente
necessario collocare, nell’evento BeforeOpenTables del DataEnvironment, per
ogni Alias (Cursor) presente, la seguente riga di codice:
this.cursorN.DataBase = <DataBase con Path completo>
(Esempio: this.cursor1.DataBase = oApp.pathFiles + “WSTOREDB.DBC”).
Questo provvede, prima dell’apertura del DataBase e delle Tabelle, a
settarne opportunamente il DataBase.
Inoltre, e’ necessario
ricordare, per gestire correttamente le tabelle in modo “Ottimistico per
Record”, di settare, per ogni Alias, le seguente proprieta’:
BufferModeOverride = 3.
E’, per finire, corretto
(anche se non indispensabile, in quanto puo’ essere fatto anche da codice, non
appena occorre) inizializzare il campo Order (Indice) dell’Alias.
N.B. E’ estremamente utile, ai fini di evitare interferenze tra i dati
presentati sul form (per esempio sulla griglia) ed i dati trattati nel codice,
utilizzare, nel DataEnvironment, Alias diversi per la stessa tabella (uno di
essi verra’ agganciato agli strumenti di visualizzazione, l’altro, o gli altri,
utilizzato/i per gestire controlli o modifiche sulla tabella).
Non attenersi a questo approccio rende la programmazione piu’ complessa
e porta quasi certamente ad errori (sfasamenti di indici, spuntamento del
record, etc.)
Nella DbButton appaiono i
pulsanti di spostamento e di modifica (gia’ funzionanti), un testo per digitare
il campo da cercare secondo l’indice corrente (o i campi dell’indice composto,
separati da “;”), una combo per la
selezione degli indici possibili ed una combo per impostare Nuovi filtri o
filtri gia’ preimpostati.
Il caricamento della combo
degli indici, si effettua inserendo, per ogni indice da presentare, nella init
della dbButton, la seguente riga di codice (dopo l’invocazione del codice base
della classe, con DODEFAULT()):
this.addIndice(“Descrizione
indice”, “nome indice”, "Tipo indice»(“C” o “N”))
La possibilita’ di
utilizzare la combo per il caricamento di filtri si ottiene nel modo seguente:
v Inizializzare la proprieta’
“Filtro_TipoTabw” con il tipo di dati di TABWORK (3 caratteri alfanumerici,
costituenti un tipo non gia’ utilizzato (vedi elenco voci TabWork nel documento
allegato)) che il programma impieghera’ per bufferizzare i futuri filtri
impostati;
v Inizializzare la proprieta’
Filtro_Tabelle, che comprende l’elenco, separato da “,”, delle tabelle su cui
potranno essere impostati filtri (i cui campi, con le descrizioni in chiaro,
potranno essere caricati nella tabella FILTRI con l’opportuno FORM di
utilita’);
v Inizializzare la proprieta’
Filtro_Alias, che comprende l’elenco, separato da “,”, degli alias delle
tabelle di cui al punto precedente (stesso ordine);
v Inizializzare la proprieta’
Filtro_Desc, che rappresenta l’elenco, separato da “,”, delle descrizioni in
chiaro delle suddette tabelle (stesso ordine).
E’ possibile personalizzare
i metodi di modifica/cancellazione/inserimento (abilitrazione/disabilitazione
oggetti, controlli aggiuntivi, etc.) inserendo il codice personalizzato nei
metodi:
v SAVE, invocato dal pulsante:
v
RESTORE, invocato dal
pulsante:
v OKDELETE, invocato dal
pulsante (che chiama il metodo DELETE e, dopo conferma da parte dell’utente, il
metodo OKDELETE):
v AZZCAMPIINDICE, in cui il
flusso di codice passa, dopo aver bloccato il record da cancellare, subito
prima della cancellazione: qui il programmatore puo’ inserire le REPLACE necessarie
per portare il record al TOP della tabella, secondo l’indice che sara’ usato
per il recupero (vedi metodo RECURECORD della classe UT_FORM);
v ADDNEW, invocato dal
pulsante:
(Si tenga presente che il
metodo ADDNEW crea/recupera il record e lo lascia bloccato, in attesa che
vengano operate le modifiche da parte dell’utente e chiamato il metodo SAVE,
che effettua lo sblocco e la registrazione sullo USER_LOG della transazione).
La classe FORMTABELLA e’
anche dotata di una istanza della classe PRINTEXPIMP:
Questa classe mette a
disposizione 3 funzionalita’:
v Stampa: la pressione del
primo tasto produce l’apertura di un form, derivato dalla classe FRMREPORTS,
che consente di selezionare il form di stampa e se effettuare un PREVIEW, una
stampa su stampante o su file.
I forms di stampa devono,
naturalmente, essere preparati a priori; possono essere linkati al progetto
(essere inglobati nell’eseguibile) o essere esterni all’eseguibile.
Occorre creare, in TABWORK,
un tipo dati (che poi sara’ indicato nella proprieta’ Stampe_Tipo di
PRINTEXPIMP), in cui, per ogni Codice, oltre che la descrizione del report di
stampa, dovranno essere riportati, nel campo Valore, il nome del report ed il
titolo di default (modificabile RUNTIME dal form di stampa), nel formato:
|Nome report|Titolo di
default|
v Import: la pressione del
secondo tasto produce la chiamata del metodo IMPORT, che va, naturalmente,
personalizzato.
v Export: la pressione del
terzo tasto produce la chiamata del metodo EXPORT, che va, naturalmente,
personalizzato.
· Classe FormPageTabella: ereditata da FormTabella. Un’istanza di questa
classe, al cui DataEnvironment sia stato legato (con gli accorgimenti suddetti)
l’Alias di una Tabella e la cui GRIDFILT sia stata agganciata all’Alias, e’ un
form di gestione di una Tabella gia’ funzionante e completo.
Per la gestione filtri ed
indici sulla DBButton, vale quanto detto al punto precedente.
La seconda pagina della
finestra e’ riservata ai campi della tabella che possono essere modificati
(basta porre nella seconda pagina dei text, agganciati, tramite la proprieta’
ControlSource, ai campi opportuni dell’Alias).
· Classe GRIDFILT: rappresenta una classe ereditata dalla classe base GRID,
dotata, in particolare, delle seguenti caratteristiche:
v Se la caption dell’Header di
una colonna non viene modificata (rimane settata al valore “Header”), la colonna non verra’ resa visibile.
v Se la proprieta’ Tag del
TEXT di una colonna viene posto = al campo della tabella agganciato alla
colonna (ALIAS.nomeCampo) à l’Header della colonna, RUNTIME,
verra’ sottolineato e l’utente,
con un doppio click sopra di esso,
potra’ ottenere un filtro immediato (anche composto con altre colonne)
sulla condizione: ALIAS.nomeCampo = <valore del campo del record attualmente
selezionato>
· Classe ARRCOMBO: ereditata dalla classe COMBOBOX, e’ corredata di una
proprieta’ – array, denominata ArrDati(), che puo’ essere ridimensionata
(istruzione DIMENSION) mano a mano che la combo viene caricata (con
this.addItem(..)), ponendo in ogni elemento dell’array una o piu’
caratteristiche corrispondenti ad ogni voce caricata.
· Classe COMBOTAB: ereditata dalla classe COMBOBOX, viene impiegata per
contenere le descrizioni (selezionabili a tendina) ed i codici corrispondenti
di un certo tipo, tratte dalla tabella TABWORK (vedi tabulato allegato al
documento, contenente le informazioni depositate in tale tabella). Una volta
incollata al form una istanza di tale classe, basta settare le seguenti
proprieta’:
v
Alias : alias usato, nel form, per TABWORK
(normalmente, TABWORK);
v
TipoDati : 3 caratteri alfanumerici, che rappresentano
il tipo dati di TabWork;
v
AliasDest : Eventuale alias per uno dei cui campi viene
usata la COMBOTAB; settando questa proprieta’, se per tale alias eof() risulta
vera, la COMBOTAB viene automaticamente disabilitata.
· Classe UT_FORM: si tratta di una classe non visuale, ereditata dalla
classe CUSTOM (normalmente, la sua istanza viene chiamata “UTI” e si trova
sicuramente su tutte le forms derivati dalla classe FORMMODAL o dalle classi da
essa ereditate). Contiene la maggior parte dei metodi di utilita’ normalmente
utilizzati, sia nella gestione dei DataBases e delle tabelle, sia per altre
funzionalita’.
Alcuni
di essi sono:
v
CloseOpen(Exclusive) : Chiude l’alias corrente e lo riapre (se
passato.t. come parametro, in esclusiva). Se l’alias e’ l’unico aperto per la
tabella, questa operazione puo’ essere impiegata per forzare il sistema
operativo a liberare memoria.
v
GetCampiStr(stringa,
separatore, @array) :
pone nell’array (opportunamente ridimensionato) tutti i campi estrapolati dalla
stringa e separati da “separatore”. La stringa puo’ iniziare e/o terminare con
“separatore”, oppore no. Restituisce il numero di campi trovati (0 se stringa
vuota).
v
InsLogErr(Codice,
Metodo, Descrizione) : Inserisce nella
tabella LOGERR la registrazione dell’errore, avente quella descrizione (max.
100 caratteri), il riferimento al metodo in cui si e’ verificato ed il codice.
I possibili codici sono i seguenti (estratto del file: CMA.H):
Ø
#DEFINE SEEK_ERR "AA" && Seek fallita
Ø
#DEFINE
LOCK_ERR "AB" && Blocco
del Record fallito
Ø
#DEFINE
FBLK_ERR "AC" && Blocco
del File fallito
Ø
#DEFINE
ABBINA_ERR "AD" && Abbinamento
tra Udc e Cella non trovato
Ø
#DEFINE
TIPO_ERR "AE" && Tipologia
missione non Prevista
Ø
#DEFINE
HEAD_ERR "AF" && Intestazione
Msg ricevuto da Liv1 sconosciuto
Ø
#DEFINE
ERROPENTAB "AG" && Errore
durante l'apertura di una tabella
Ø
#DEFINE
BUFFERERR "AH" && Errore
rilevato durante la save dei dati dal buffering
Ø
#DEFINE
NOTHANDERROR "AI" && Errori
non gestiti
Ø
#DEFINE
LISTINCOMERR "AJ" && Lista
incompleta
Ø
#DEFINE
IMMEINCOMERR "AK" && Immediato
incompleto
Ø
#DEFINE
NUMRIMPMAXERR "AL" && Numero
rimpiazzi eccessivo
Ø
#DEFINE ABORT_ERR "AM" && Abortita
Ø
#DEFINE
ANNULLATA_ERR "AN" && Annullata
Ø
#DEFINE
PESO_SAG_ERR "AO" && Errore
di peso o di sagoma
Ø
#DEFINE
TIMEOUT_ERR "AP" && Errore
di timeout
Ø
#DEFINE
MISSDUPL_ERR "AQ" && Missione
duplicata
Ø
#DEFINE
RIMP_IMP_ERR "AR" && Rimpiazzo
impossibile
Ø
#DEFINE
VUOTO_VUOTO_ERR "AS" && Errore
di vuoto su vuoto
Ø
#DEFINE
PIENO_PIENO_ERR "AT" && Errore
di pieno su pieno
Ø
#DEFINE
SORG_INES_ERR "AU" && Errore
di sorgente inesistente
Ø
#DEFINE
DEST_INES_ERR "AV" && Errore
di destinazione inesistente
Ø
#DEFINE
SORG_INIB_ERR "AW" && Errore
di sorgente inibita
Ø
#DEFINE
DEST_INIB_ERR "AY" && Errore
di destinazione inibita
Ø
#DEFINE
NUMMACERR_ERR "AZ" && Numero
macchina errato
Ø
#DEFINE
TIPMISSERR_ERR "BA" && Tipologia
missione errata
Ø
#DEFINE
DIMUDCERR_ERR "BB" && Dimensioni
Udc errate
Ø
#DEFINE
BUFL1PIENO_ERR "BC" && Buffer
Livello1 pieno
Ø
#DEFINE
MISSSCONOSC_ERR "BD" && Missione
Sconosciuta
Ø
#DEFINE
STAMIS_ERR "BE" && Stato
missione incongruente
Ø
#DEFINE
MISINCOURSE_ERR "BF" && Missione
in Corso
v
SaveAlias(@OldAlias,
@OldOrder, @OldRecord) :
Pone nelle tre variabili passate per indirizzo l’Alias corrente, il tag indice
corrente ed il puntatore al record corrente. Questo consente, alla fine delle
operazioni, chiamando il metodo RestAlias, di ripristinare la situazione dati
originaria.
v
RestAlias(OldAlias,
OldOrder, OldRecord) :
Seleziona l’alias corrente, settandone il tag indice passato ed andando al
numero di record indicato.
v
Trad(testo) : Rende la traduzione del testo passato
(max. 100 caratteri), in base alla lingua codificata in oApp.lingua, legata
all’operatore corrente o letta dal file init.ini (sezione [CONFIG], parametro
DEFLINGUA=).
OApp.lingua
puo’ valere:
Ø
IT :
Italiano (testo viene reso identico);
Ø
FR :
francese;
Ø
SP :
spagnolo;
Ø
IN :
inglese;
Ø
…….
La ricerca della traduzione viene fatta nella tabella LINGUA. Se il
testo italiano non viene trovato (nel gruppo delle traduzioni di quella
specifica lingua), il metodo provvede ad aggiungere un record, con il campo
della traduzione vuoto, e rende il testo da tradurre preceduto da “_”.
v
Seek(Valore
da Trovare) :
Effettua la ricerca del valore da trovare nella tabella e secondo il tag indice
correnti, dopo aver forzato il rinfresco degli indici della tabella da parte
del sistema.
In ambienti multiutenza,
questo metodo va sempre utilizzato, per evitare mancati ritrovamenti di records
(inseriti da altri utenti o applicativi) legati al mancato rinfresco del
contesto di memoria dell’applicativo.
v
Rec_Lock(numero,
tipo) :
Effettua il lock (blocco) del record corrente.
Ø
Tipo
puo’ assumere i seguenti valori (estratto del file CMA.H):
Ø
#DEFINE
LOC_NUMERO "N" && Tenta di bloccare il record per
n Volte
Ø
#DEFINE
LOC_SECONDI "S" && Tenta di bloccare il record per
n Secondi
Ø
#DEFINE
LOC_AUTO "A" && Aspetta fino a che non ha
bloccato il record (indefinitivamente)
Quindi:
Ø
Tipo
= LOC_NUMERO : Numero rappresenta il
numero di tentativi di lock (se falliscono tutti, il metodo rende.f.,
altrimenti.t.);
Ø
Tipo
= LOC_SECONDI : Numero rappresenta
il tempo (in secondi) per cui e’ necessario tentare il lock (al termine, in
caso negativo, il metodo rende.f., altrimenti rende.t. appene riesce nel
blocco);
Ø
Tipo
= LOC_AUTO : In questo caso, Numero deve
essere posto a 0. Il metodo esce solo quando il record e’ stato bloccato
(valore di ritorno =.f.).
N.B. Naturalmente, se mi trovo all’ eof(), il metodo restituisce,
comunque,.f..
v
RecuRecord() : Effettua l’inserimento di un nuovo record
nella tabella corrente, od il recupero di un record cancellato in precedenza
(che viene sbiancato). All’uscita dal metodo, il record e’ bloccato.
E’
necessario, affinche’ il recupero venga fatto in modo corretto, selezionare,
prima di invocare la funzione, il tag indice opportuno, che garantisca di
trovare al TOP della tabella tutti i records deletati.
Cio’
si ottiene inserendo in un campo indice, all’atto della cancellazione del
record, un valore sicuramente inferiore rispetto a quelli assunti di norma da
quel campo.
Qualche
esempio:
Ø
Tabella
UDC: Sulla cancellazione, porre
UDC_COD = -1 e, sul recupero, utilizzare l’indice XUDC_ID1 (su UDC_COD);
Ø
Tabella
SCOMPART: Sulla cancellazione, porre
SCO_ART = chr(13) e, sul recupero, utilizzare l’indice XSCO_ID14 (su SCO_ART);
Ø
Tabella
ARTICOLI: Sulla cancellazione,
porre ART_COD = chr(13) e, sul recupero, utilizzare l’indice XART_ID1 (su
ART_COD);
Ø
…..
-
UT_LOG.VCX: contiene, in particolare,
una classe particolarmente utile:
· USER_LOG: questa classe (la cui istanza viene normalmente denominata LOG ed e’
sempre presente sulle Forms derivati dalla classe FORMMODAL o dalle sue
ereditate) contiene, in particolare, il seguente metodo:
Ø
RegUnlock(nuovoRecord) : effettua lo sblocco del record
precedentemente bloccato, dopo aver fatto la registrazione della transazione
sulla tabella USER_LOG.
Sono
di seguito riportati i diversi casi di modifica o cancellazione o inserimento
di records:
ü
Inserimento
(recupero) (su USER_LOG vengono riportati tutti i nuovi valori dei campi):
SELECT <ALIAS>
SET ORDER TO <TAGINDICE per RECUPERO>
Thisform.uti.recuRecord()
REPLACE <CAMPO1> WITH <Valore1>,;
<CAMPO2>
WITH <Valore2>,;
….
Thisform.log.regUnlock(.t.)
ü
Modifica
(su USER_LOG vengono riportati tutti i valori vecchi e nuovi dei campi
modificati):
SELECT <ALIAS>
SET ORDER TO <TAGINDICE per RICERCA>
Thisform.uti.Seek(<Valore
da Ricercare>)
If found()
If
thisform.uti.rec_lock(2, LOC_NUMERO)
REPLACE <CAMPO1> WITH <Valore1>,;
<CAMPO2>
WITH <Valore2>,;
….
Thisform.log.regUnlock(.f.)
Else
* Registrazione errore di lock
thisform.uti.insLogErr(LOCK_ERR, “Metodo”,
thisform.uti.trad(“No Blocco”))
Endif
Else
* Registrazione errore di seek
thisform.uti.insLogErr(SEEK_ERR, “Metodo”,
thisform.uti.trad(“No Trovato”))
Endif
ü
Cancellazione
(su USER_LOG vengono riportati tutti i valori vecchi dei campi):
SELECT <ALIAS>
SET ORDER TO <TAGINDICE per RICERCA>
Thisform.uti.Seek(<Valore
da Ricercare>)
If found()
If
thisform.uti.rec_lock(2, LOC_NUMERO)
REPLACE <CAMPO per
RECUPERO> WITH <Valore “Basso”>
DELETE
Thisform.log.regUnlock(.f.)
Else
* Registrazione errore di lock
thisform.uti.insLogErr(LOCK_ERR, “Metodo”,
thisform.uti.trad(“No Blocco”))
Endif
Else
* Registrazione errore di seek
thisform.uti.insLogErr(SEEK_ERR, “Metodo”,
thisform.uti.trad(“No Trovato”))
Endif
-
UT_MENU.VCX: contiene le classi
necessarie per la crezione del menu’ e per la gestione delle funzioni dei
diversi utenti.
E’ opportuno riassumere come
e’ possibile personalizzare il menu’ di una applicazione e le diverse funzioni
sui diversi forms.
Occorre agire su 2 tabelle:
v CONFMENU: questa tabella
contiene l’elenco delle voci di menu e sottomenu per ogni utente. Volendo
aggiungere o togliere una voce di menu’ (o sottomenu), si agisca solo
sull’utente WINSTORE (per gli altri utenti, provvedera’ la form OPERATORI a
duplicare opportunamente le voci, abilitandole o disabilitandole).
Occorre notare che il campo
MNU_OPE e’ costituito dal nome utente (15 caratteri) e da due caratteri
alfanumerici che identificano il tipo dell’applicazione (proprieta’
oApp.tipoApp). In questo modo, e’ possibile avere menu’ diversi, per ogni
utente, per ogni applicazione.
Esaminiamo gli altri campi:
MNU_POS : il primo carattere
identifica il menu’ principale, il secondo i diversi sottomenu’;
MNU_MNU : nome menu’ principale
(uguale per tutti i sottomenu’);
MNU_SUBM : nome sottomenu’;
MNU_SHRT : eventuale SHORTCUT (per
esempio: ALT + F);
MNU_SYS : eventuale chiamata a
funzioni del sistema operativo (per esempio, per il COPY di un testo
selezionato, _MED_COPY);
MNU_FUNZ : condizione di
disabilitazione;
MNU_DO : azione compiuta dal
sottomenu’ (per esempio: DO FORM <nomeForm> LINKED per lanciare un form);
MNU_ABI : codice di
abilitazione: settarlo a MA per i menu’ principali, a SA per i sottomenu’
(provvedera’ la form di gestione degli utenti a cambiare quei valori, per
inibire, eventualmente, per un utente, quelle voci);
MNU_FORM : form cui e’ agganciato
il sottomenu’ (blank per menu’ principali e per sottomenu’ non agganciati a
form).
v FUNZIONI: questa tabella
contiene l’elenco delle funzioni previste per ogni form.
Elenco e decrizione campi:
FNZ_FORM : form cui e’ riferita
la funzione;
FNZ_FNZ : elenco codici
funzione (separati da, posto anche all’inizio ed alla fine dell’elenco); questi
codici alfanumerici (arbitrari) sono, ognuno, agganciati ad una funzione
specifica della form, cui l’operatore puo’ essere o non puo’ essere abilitato.
In questo ruolo, FNZ_COD e’ blank e FNZ_NOME assume il nome della form.
FNZ_FNZ
puo’ altresi’ essere impiegato per contenere la descrizione di dettaglio di un
singolo codice (in tal caso, FNZ_COD contiene quel codice e FNZ_NOME e’ blank).
FNZ_ABI : va’ inizializzato
a “A” (abilitato). Sara’, poi, la form di gestione operatori a disabilitare,
per un particolare utente, quella funzione.
N.B. I codici delle funzionalita’ della form possono
essere utilizzati liberamente, da codice, per testare se un utente puo’ o non
puo’ effettuare quella particolare funzione. Questo si ottiene ponendo,
sull’evento LOAD della form, la seguente riga di codice:
Thisform.StrAbiButton
= oApp.access.GetstrAbiButton(Thisform.Name)
Nella
proprieta’ (gia’ presente a livello di classe FORMMODAL) strAbiButton, in tal
modo, mi trovero’ il valore estrapolato dal campo FNZ_FNZ (elenco funzioni,
separate da “_”). Il test di abilitazione o meno alla funzione sara’, quindi:
If (“_” + <Codice funzione> + “_”) $
thisform.strAbiButton or ;
empty(thisform.strAbiButton) or empty(<Codice funzione>) then
* Utente abilitato
…..
Else
*
Utente disabilitato
…..
Endif
(Si noti che strAbiButton vuota o <codice
funzione> vuoto sono sinonimo di funzioni / funzione sempre abilitate /
abilitata).
Molte
funzioni utente, tuttavia, essendo gia’ gestite a livello di classe, non
debbono essere gestite da codice, ma e’ sufficiente settare le opportune
proprieta’. Per esempio, sulla barra degli strumenti della form, basta settare,
sui pulsanti, la proprieta’ buttonCode (se vuota à funzione sempre abilitata) e, a livello di DBButton, le proprieta’:
filtroCode (abilitazione all’uso dei filtri), indexCode (abilitazione all’uso
degli indici) e cercaCode (abilitazione all’uso del cerca).
3.2
CODICE SVILUPPATO
3.2.1 Principali procedure
3.2.1.1 CALCOLACELLE
SELECT quote
N=((thisform.pageframe1.page1.ncco.value
*thisform.pageframe1.page1.ncol.value)*thisform.pageframe1.page1.npia.value)
BEGIN transaction
*--------------------Tenta il blocco della tebella
IF !Flock()
=MessageBox(ThisForm.Uti.trad("Tentativo di bloccare la tabella
fallito"),;
MB_ICONSTOP,ThisForm.Uti.trad("ERRORE"))
RETURN .F.
ENDIF
pos=thisform.pageframe1.page1.npos.value
pro=thisform.pageframe1.page1.npro.value
nummacchina=thisform.pageframe1.page1.nmac.value
numprimacelscafsx=thisform.pageframe1.page1.npce.value
IF
thisform.pageframe1.page1.combo1.value='D '
IF n>=thisform.pageframe1.page1.npce.value
msg=ThisForm.Uti.trad("Il numero calcolato di
celle comprende celle del lato di sinistra !!!" )+CHR(13)
msg=msg+thisform.Uti.trad("Vuoi continuare ?")
IF messagebox(msg,65,ThisForm.Uti.trad("ATTENZIONE"))=2
RETURN
END transaction
UNLOCK
ENDIF
ENDIF
ENDIF
SET
deleted off
SET
order to xquo_id1
SEEK str(nummacchina,2)
*--------------------Controlla che non vengano
inserite due macchine uguali per lo stesso scaffale
*--------------------Se vuole inserire una macchina
gia'presente provvede ad eliminare i suoi record
IF !eof()
msg=ThisForm.Uti.trad("Questa macchina e'gia' presente nella
tabella !!!" )+CHR(13)
msg=msg+ThisForm.Uti.trad(' Vuoi sostituirla ?' )
IF
messagebox(msg,65,ThisForm.Uti.trad("ATTENZIONE"))=1
DO while !eof()
REPLACE quo_mac with 0
Delete
SEEK
str(nummacchina,2)
ENDDO
ELSE
END transaction
UNLOCK
RETURN
ENDIF
ENDIF
FOR
i=1 to n
FOR k=1 to pos
FOR y=1 to pro
*-------------------Sfrutta se ci sono i record
cancellati
SEEK str(0,2)
IF !eof()
RECALL
ELSE
APPEND blank
ENDIF
*-------------------Inizia inserimento dei dati
REPLACE quo_mac with nummacchina
*-Inserisce codcella,scaffale e si assicura che la
prima cella dello scaffale di destra sia 1 e quella di sinistra
numprimacelscafsx
IF (thisform.pageframe1.page1.combo1.value='D ') and
(i<numprimacelscafsx)
REPLACE quo_cel with i
ELSE
IF thisform.pageframe1.page1.combo1.value='S
'
REPLACE quo_cel with
(i+numprimacelscafsx-1)
ELSE
REPLACE quo_cel with i
ENDIF
ENDIF
*------------------Inserisce posizione,profondita'e
coordinate
DO case
CASE (k=1) and (y=1) and (pos<>2)
REPLACE quo_pos with cel_centro
REPLACE quo_pro with cel_ant
CASE (k=1) and (y=2) and (pos<>2)
REPLACE quo_pos with cel_centro
REPLACE quo_pro with cel_post
CASE ((k=2) and (y=1) and
(pos<>2)) or((k=1) and (y=1) and (pos=2))
REPLACE quo_pos with cel_soccsx
REPLACE quo_pro with cel_ant
CASE ((k=2) and (y=2)and (pos<>2))
or ((k=1) and (y=2) and (pos=2))
REPLACE quo_pos with cel_soccsx
REPLACE quo_pro with cel_post
CASE ((k=3) and (y=1) and
(pos<>2)) or ((k=2) and (y=1) and
(pos=2))
REPLACE quo_pos with cel_soccdx
REPLACE quo_pro with cel_ant
CASE ((k=3) and (y=2) and
(pos<>2)) or ((k=2) and (y=2) and (pos=2))
REPLACE quo_pos with cel_soccdx
REPLACE quo_pro with cel_post
ENDCASE
REPLACE quo_x with 0
REPLACE quo_y with 0
REPLACE quo_z with 0
NEXT
NEXT
NEXT
SET
deleted on
thisform.pageframe1.page4.grid1.refresh()
UNLOCK
END
transaction
thisform.pageframe1.activepage=2
SELECT quote
nx =thisform.pageframe1.page2.x.value
ny =thisform.pageframe1.page2.y.value
ny2=thisform.pageframe1.page2.y2.value
nz1 =thisform.pageframe1.page2.Z.value
xiniziale=thisform.pageframe1.page2.x.value
passocolonne=thisform.pageframe1.page2.PasCol.value
passopiani=thisform.pageframe1.page2.PasPia.value
numcolonne=(thisform.pageframe1.page2.Ncol.value)
numpiani=(thisform.pageframe1.page2.Npia.value)
numcellepercolonna=(thisform.pageframe1.page1.ncco.value)
nmac=thisform.pageframe1.page1.nmac.value
npos=thisform.pageframe1.page1.npos.value
npro=thisform.pageframe1.page1.npro.value
profonditacella=thisform.pageframe1.page2.z2.value
IF thisform.pageframe1.page1.ncco.value=1
passocelle=(passocolonne)
ELSE
passocelle=(passocolonne/thisform.pageframe1.page1.ncco.value)
ENDIF
*-------------------------Calcolo posizione prima cella
pos=(((thisform.pageframe1.page2.PiaIni.value-1)* thisform.pageframe1.page1.Ncol.value)*thisform.pageframe1.page1.ncco.value)+;
(((thisform.pageframe1.page2.Colini.value-1)*thisform.pageframe1.page1.ncco.value)+1)
IF thisform.pageframe1.page1.combo1.value='S '
pos=pos+thisform.pageframe1.page1.npce.value-1
ENDIF
BEGIN transaction
SET deleted on
SET order to xquo_id1
*---------------------Tenta il blocco della tabella
IF !Flock()
=MessageBox(ThisForm.Uti.trad("Tentativo di bloccare la tabella fallito"),;
MB_ICONSTOP,ThisForm.Uti.trad("ERRORE"))
RETURN
.F.
ENDIF
FOR p=1 to numpiani
FOR i= 1 to numcolonne
FOR k=1 to numcellepercolonna
*--------------------Si posiziona sulla cella corretta
SEEK
str(nmac,2)+bintoc(pos)
FOR r=1 to npos
FOR w=1 to npro
IF w=1
*--------------------Inserisce coordinate in prima o seconda profondita'
REPLACE
quo_y with ny
nz=nz1
ELSE
REPLACE quo_y with ny2
nz=profonditacella
ENDIF
REPLACE quo_x with nx
REPLACE quo_z with nz
*------------------Calcola la posizione della cella seguente
IF
r<npos or w<npro
ELSE
IF (numcolonne>i) or (numcellepercolonna>k)
pos=pos+1
ELSE
pos=pos+((thisform.pageframe1.page1.Ncol.value-(thisform.pageframe1.page2.Colini.value+thisform.pageframe1.page2.Ncol.value-1))*numcellepercolonna)
IF numpiani>p
pos=pos+(((thisform.pageframe1.page2.Colini.value-1)*numcellepercolonna)+1)
ENDIF
ENDIF
ENDIF
*-------------------Va al record successivo
Skip
ENDFOR
*-------------------Calcola coordinata x per il prossimo record
DO case
CASE npos =1
nx=nx+passocelle
CASE npos=2
nx=nx+(passocelle/2)
CASE r=1 and npos=3
nx=nx-((passocelle/6)*2)
CASE (r=2 or r=3) and npos=3
nx=nx+((passocelle/6)*4)
ENDCASE
nz=0
ENDFOR
ENDFOR
ENDFOR
*-------------------Calcola coordinate y,x per il prossimo record al piano superiore
ny=(ny+passopiani)
ny2=(ny2+passopiani)
nx=xiniziale
ENDFOR
UNLOCK
thisform.pageframe1.page4.grid1.refresh()
END transaction
SELECT quote
contatorex=0
contatorey=thisform.pageframe1.page3.Yinc.value
numcolonne=(thisform.pageframe1.page3.Ncol.value)
numpiani=(thisform.pageframe1.page3.Npia.value)
numcellepercolonna=thisform.pageframe1.page1.ncco.value
nmac=thisform.pageframe1.page1.nmac.value
npos=thisform.pageframe1.page1.npos.value
npro=thisform.pageframe1.page1.npro.value
costantex=thisform.pageframe1.page3.Xcost.value
costantey=thisform.pageframe1.page3.Ycost.value
incrementalex=thisform.pageframe1.page3.Xinc.value
incrementaley=thisform.pageframe1.page3.Yinc.value
nz=0
nx=0
*-------------------------Calcolo posizione prima cella
pos=(((thisform.pageframe1.page3.PiaIni.value-1)* thisform.pageframe1.page1.Ncol.value)*thisform.pageframe1.page1.ncco.value)+;
(((thisform.pageframe1.page3.ColIni.value-1)*thisform.pageframe1.page1.ncco.value)+1)
IF thisform.pageframe1.page1.combo1.value='S '
pos=pos+thisform.pageframe1.page1.npce.value-1
ENDIF
*-------------------------Tenta il blocco della tabella
IF !Flock()
=MessageBox(ThisForm.Uti.trad("Tentativo di bloccare la tabella fallito"),;
MB_ICONSTOP,ThisForm.Uti.trad("ERRORE"))
RETURN
.F.
ENDIF
BEGIN transaction
SET order to xquo_id1
SET deleted on
FOR p=1 to numpiani
FOR i= 1 to numcolonne
FOR k=1 to numcellepercolonna
*------------------Si posiziona sulla cella corretta
SEEK
str(nmac,2)+bintoc(pos)
FOR r=1 to npos
FOR w=1 to npro
*-------------------Calcola la somma coordinate x e y ,se incrementale,usando un contatore
IF costantex>0
nx =(quo_x+costantex)
ELSE
IF incrementalex>0
IF (r=1) and (w=1)
contatorex=contatorex + incrementalex
ENDIF
nx=quo_x
nx =(nx+contatorex )
ELSE
nx=quo_x
ENDIF
ENDIF
IF costantey>0
ny=(quo_y+costantey)
ELSE
IF incrementaley>0
ny=(quo_y+contatorey)
ELSE
ny=quo_y
ENDIF
ENDIF
nz=quo_z
REPLACE quo_x with nx
REPLACE quo_y with ny
REPLACE quo_z with nz
*-----------------Calcola la posizione della cella seguente
IF
(r<npos) or (w<npro)
ELSE
IF (numcolonne>i) or
(numcellepercolonna>k)
pos=pos+1
ELSE
pos=pos+((thisform.pageframe1.page1.Ncol.value-(thisform.pageframe1.page3.ColIni.value+thisform.pageframe1.page3.Ncol.value-1))*numcellepercolonna)
IF numpiani>p
pos=pos+(((thisform.pageframe1.page3.ColIni.value-1)*numcellepercolonna)+1)
ENDIF
ENDIF
ENDIF
*------------------Va al record seguente
Skip
ENDFOR
ENDFOR
ENDFOR
ENDFOR
contatorey=contatorey+incrementaley
contatorex=0
nx=quo_x
ENDFOR
UNLOCK
END transaction
SELECT quote
SET order to xquo_id1
scafs=thisform.pageframe1.page5.combo1.value
scafd=thisform.pageframe1.page5.combo4.value
nmac=thisform.pageframe1.page5.Nmaces.value
nmac2=thisform.pageframe1.page5.Nmacin.value
npsx1=thisform.pageframe1.page5.npces.value
npsx2=thisform.pageframe1.page5.npced.value
i=1
k=2
q=.f.
v=.f.
*--------------------Tenta il blocco della tebella
IF !Flock()
=MessageBox(ThisForm.Uti.trad("Tentativo di bloccare la tabella fallito"),;
MB_ICONSTOP,ThisForm.Uti.trad("ERRORE"))
RETURN .F.
ENDIF
*-----------------Controlla se esiste la macchina da cui copiare
IF
npsx1=0 and scafs='S '
msg=ThisForm.Uti.trad("La prima cella dello scaffale di sinistra della macchina sorgente non è stata inserita !!!" )+CHR(13)
msg=msg+ThisForm.Uti.trad("Impossibile fare il calcolo " )
messagebox(msg,49,ThisForm.Uti.trad("ATTENZIONE"))
UNLOCK
RETURN
ENDIF
IF npsx2=0 and scafd='S '
msg=ThisForm.Uti.trad("La prima cella dello scaffale di sinistra della macchina destinazione non è stata inserita !!!" )+CHR(13)
msg=msg+ThisForm.Uti.trad("Impossibile fare il calcolo " )
messagebox(msg,49,ThisForm.Uti.trad("ATTENZIONE"))
UNLOCK
RETURN
ENDIF
if
scafs='D '
SEEK str(nmac,2)+bintoc(1)
else
SEEK str(nmac,2)+bintoc(npsx1)
endif
IF eof() or (scafs='D 'and quo_cel<>1) or
(scafs='S ' and quo_cel<>npsx1)
msg=ThisForm.Uti.trad("Macchina da copiare non esistente in tabella!!!" )+CHR(13)
MESSAGEBOX(msg,48,ThisForm.Uti.trad("ATTENZIONE"))
thisform.pageframe1.page5.Nmaces.value=1
thisform.pageframe1.page5.combo1.value='D '
unlock
RETURN
ENDIF
*!* *----------------Controlla se esiste già la macchina da inserire e permette la sua ridefinizione
if scafd='D '
SEEK str(nmac2,2)+bintoc(1)
else
SEEK str(nmac2,2)+bintoc(npsx2)
endif
IF
(scafd='D ' and quo_cel=1) or (scafd='S ' and quo_cel=npsx2)
msg=ThisForm.Uti.trad("Macchina e scaffale da inserire già esistente !!!" )+CHR(13)
msg=msg+ThisForm.Uti.trad("Vuoi sostituirla ?" )
IF
messagebox(msg,49,ThisForm.Uti.trad("ATTENZIONE"))=2
unlock
RETURN
else
DO
while quo_mac=nmac2 and !eof()
REPLACE quo_mac with 0
Delete
SEEK
str(nmac2,2)
ENDDO
ENDIF
ENDIF
*-------------------Esamina le varie combinazione di scaffali per inserire i codici cella corretti
if scafs='D '
SEEK str(nmac,2)+bintoc(1)
else
SEEK str(nmac,2)+bintoc(npsx1)
endif
DO while (quo_mac=nmac) and (!eof()) and (!V)
*------------------Calcola il nuovo numero cella basandosi sul numero cella già esistente in tabella
DO case
CASE
scafs='D 'and scafd='S '
cell=(quo_cel+npsx2-1)
CASE scafs='S
'and scafd='D '
cell=(quo_cel-npsx1+1)
CASE scafs='D
'and scafd='D '
cell=quo_cel
CASE
scafs='S 'and scafd='S '
cell=quo_cel-npsx1+npsx2
ENDCASE
pos=quo_pos
pro=quo_pro
x=quo_x
Y=quo_y
z=quo_z
*-------------------Recupera i record eliminati,se possibile,ed inserisce i nuovi dati
SEEK str(0,2)
IF
!eof()
RECALL
ELSE
APPEND blank
ENDIF
REPLACE quo_mac with nmac2
REPLACE quo_cel with cell
REPLACE quo_pos with pos
REPLACE quo_pro with pro
REPLACE quo_x with x
REPLACE quo_y with y
REPLACE quo_z with z
if
scafs='D '
SEEK str(nmac,2)+bintoc(1)
else
SEEK str(nmac,2)+bintoc(npsx1)
endif
Skip i
*-------------------Variabile che indica se si è arrivati alla prima cella dello scaffale di sinistra
if (scafs='D ' and
quo_cel=npsx1) or (nmac=nmac2 and quo_cel=npsx2)
v=.t.
endif
i=i+1
ENDDO
Unlock
3.2.2 Principali controlli
Controllo per
l’accesso a pagina due e pagina tre inserito nelle procedure refresh delle
pagine.
SELECT quote
SET order to xquo_id1
nummac=thisform.pageframe1.page1.nmac.value
npos=thisform.pageframe1.page1.npos.value
npro=thisform.pageframe1.page1.npro.value
SEEK str(nummac,2)
N=((((thisform.pageframe1.page1.ncco.value
*thisform.pageframe1.page1.ncol.value)*;
thisform.pageframe1.page1.npia.value)*npos)*npro)
*-----------------Controlla che la quotazione avvenga sullo scaffale corretto
num=0
DO while (quo_mac=nummac) and (!eof())
Skip
num=num+1
ENDDO
*------------------Controlla caso per caso la situazione posizione_profondità all'interno della cella
*------------------Se trova una discordanza mette c=0
SEEK str(nummac,2)
c=1
IF npos=1 and npro=1
IF
quo_pos='00' and quo_pro='00'
ELSE
c=0
ENDIF
ENDIF
IF npos=1 and npro=2
IF
quo_pos='00' and quo_pro='00'
Skip
IF
quo_pos='00' and quo_pro='01'
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ENDIF
IF npos=2 and npro=1
IF
quo_pos='01' and quo_pro='00'
Skip
IF
quo_pos='02' and quo_pro='00'
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ENDIF
IF
npos=2 and npro=2
IF
quo_pos='01' and quo_pro='00'
Skip
IF quo_pos='01' and quo_pro='01'
Skip
IF
quo_pos='02' and quo_pro='00'
Skip
IF quo_pos='02' and quo_pro='01'
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ENDIF
IF npos=3 and npro=1
IF
quo_pos='00' and quo_pro='00'
Skip
IF
quo_pos='01' and quo_pro='00'
Skip
IF
quo_pos='02' and quo_pro='00'
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ENDIF
IF npos=3 and npro=2
IF
quo_pos='00' and quo_pro='00'
Skip
IF
quo_pos='00' and quo_pro='01'
Skip
IF
quo_pos='01' and quo_pro='00'
Skip
IF quo_pos='01' and quo_pro='01'
Skip
IF quo_pos='02' and
quo_pro='00'
Skip
IF quo_pos='02' and quo_pro='01'
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ELSE
c=0
ENDIF
ENDIF
IF num<>n or c=0
msg=ThisForm.Uti.trad("La definizione dello scaffale in prima pagina non e' presente in tabella !!!" )+CHR(13)
msg=msg+ThisForm.Uti.trad('Impossibile modificare quote.' )
MESSAGEBOX(msg,64,ThisForm.Uti.trad("ERRORE"))
thisform.pageframe1.activepage=1
ENDIF
Procedura
inserita nel Refresh di pagina uno e nel LostFocus di Nmac che inizializza la
prima cella di sinistra
*--------Inizializza numero prima cella sx con il corrispondente in tabella se c'e altrimenti con 0
SELECT celle
SET order to xcel_id1
nmac=thisform.pageframe1.page1.nmac.value
vera=.f.
SEEK str(nmac,2)
DO while !vera and !eof() and cel_mac=nmac
IF
cel_lato='S '
primacella=cel_cod
vera=.t.
ENDIF
Skip
ENDDO
IF vera
thisform.pageframe1.page1.npce.value=primacella
ELSE
thisform.pageframe1.page1.npce.value=0
ENDIF
*----Controlla che il numero di posizoni all'interno della cella non sia maggiore di 3
IF this.value>3
MESSAGEBOX(thisform.uti.trad("Il numero posizioni non puo'essere maggiore di 3 !"), 64, thisform.uti.trad("ERRORE"))
this.value=1
ENDIF
IF this.value=0
this.value=1
ENDIF
if this.value<>'D 'and
this.value<>'S '
msg=ThisForm.Uti.trad("Il valore inserito non é corretto !!!" )+CHR(13)
msg=msg+thisform.Uti.trad("Per selezionare il lato sinistro S per il lato destro D ?")
messagebox(msg,65,ThisForm.Uti.trad("ATTENZIONE"))
this.value='D
'
endif
Procedura
inserita nel LostFocus di Colini e PiaIni che controlla valore inserito.
IF
this.value>thisform.pageframe1.page1.ncol.value
MESSAGEBOX(thisform.uti.trad("Il numero della colonna iniziale non puo'essere maggiore del numero max di colonne !"), 64, thisform.uti.trad("ERRORE"))
this.value=1
ENDIF
IF ((this.value+thisform.pageframe1.page2.ncol.value)-1)>thisform.pageframe1.page1.ncol.value
msg=thisform.uti.trad("La somma delle colonne e' maggiore del numero max di colonne !")+CHR(13)
msg=msg+thisform.uti.trad("Rinserire Colonna inizio e Numero colonne")
MESSAGEBOX(msg, 64,
thisform.uti.trad("ERRORE"))
this.value=1
thisform.pageframe1.page2.ncol.value=1
ENDIF
IF this.value=0
this.value=1
ENDIF
Procedura
inserita nel LostFocus di Ncol e Npia che controlla il valore inserito.
IF ((this.value+thisform.pageframe1.page2.Colini.value)-1)>thisform.pageframe1.page1.ncol.value
msg=thisform.uti.trad("La somma delle colonne e' maggiore del numero max di colonne !")+CHR(13)
msg=msg+thisform.uti.trad("Rinserire Colonna inizio e Numero colonne")
MESSAGEBOX(msg, 64,
thisform.uti.trad("ERRORE"))
this.value=1
thisform.pageframe1.page2.ncol.value=1
ENDIF
IF this.value=0
this.value=1
ENDIF
Case che
inserito nella procedura clic dei comandi lancia Calcolacelle, Coordinate o
Modificaquote.
DO case
CASE ThisForm.Pageframe1.ActivePage = 1
thisform.calcolacelle
CASE ThisForm.Pageframe1.ActivePage = 2
thisform.Coordinate
ENDCASE
DO case
CASE ThisForm.Pageframe1.ActivePage = 1
this.enabled = .t.
this.ToolTipText = "Avvia la procedura di calcolocelle "
CASE ThisForm.Pageframe1.ActivePage = 2
this.enabled = .t.
this.ToolTipText = "Avvia la procedura di quotazione celle"
CASE ThisForm.Pageframe1.ActivePage = 3
this.enabled = .f.
this.ToolTipText = ""
CASE ThisForm.Pageframe1.ActivePage = 4
this.enabled = .f.
this.ToolTipText = ""
CASE ThisForm.Pageframe1.ActivePage = 5
this.enabled = .f.
this.ToolTipText = ""
ENDCASE
Procedura inserita
nel Click di Cmd5 che elimina o il record selezionato o i record macchina
SELECT quote
SET order to xquo_id1
IF !Flock()
=MessageBox(ThisForm.Uti.trad("Tentativo di bloccare la tabella fallito"),;
MB_ICONSTOP,ThisForm.Uti.trad("ERRORE"))
RETURN .F.
ENDIF
*-------------------Cancella tutti i record della macchina
IF
thisform.pageframe1.page5.cmacheck1.value=.t. and
thisform.pageframe1.activepage=5
msg=ThisForm.Uti.trad("Questa
operazione eliminera' tutti i record relativi alla macchina !!!" )+CHR(13)
msg=msg+thisForm.Uti.trad("Sei sicuro !")
IF messagebox(msg,68,ThisForm.Uti.trad("ATTENZIONE"))=6
macc=thisform.pageframe1.page5.Nmaccan.value
SEEK str(macc,2)
IF eof()
msg=ThisForm.Uti.trad("Macchina non esistente !!!" )+CHR(13)
MESSAGEBOX(msg,49,ThisForm.Uti.trad("ATTENZIONE"))
RETURN
UNLOCK
ENDIF
DO
while quo_mac=macc and !eof()
REPLACE quo_mac with 0
Delete
SEEK str(macc,2)
ENDDO
ENDIF
ELSE
*-------------------Elimina il record selezionato
IF
thisform.pageframe1.activepage=4
REPLACE quo_mac with 0
Delete
GO
recno()
ENDIF
thisform.pageframe1.page4.grid1.refresh()
ENDIF
UNLOCK
UN ESEMPIO
APPLICATIVO
In questo capitolo viene
descritto un esempio applicativo col quale ci si propone di mostrare il vero
funzionamento delle fasi del progetto rendendone il più semplice possibile la
comprensione da parte del lettore.
In questo esempio supponiamo
che l’operatore voglia definire lo scaffale di destra di un magazzino per la
macchina uno e che voglia poi quotarne solo una parte andando in un secondo
tempo a modificarne le quote, infine copia la definizione dello scaffale di
destra creata per la macchina uno sullo scaffale di sinistra della macchina
due.
L’operatore andrà poi ad
eliminare prima un record selezionato in tabella poi tutti i record riferiti
alla macchina uno inizialmente calcolati ed inseriti in tabella.
La prima operazione da
fare è definire lo scaffale inserendo i dati in prima pagina, in questo
esempio, come si vede dalla Form qui sotto, l’utente creerà la definizione per
la macchina uno di uno scaffale di destra di dieci colonne e dieci piani con due celle per colonna e
tre posizioni e due profondità per ogni cella
Inseriti i dati ora siamo in
grado di calcolare ed inserire le celle in tabella cliccando sul pulsante
Calcola, unico attivo con pagina uno; al clic del comando se tutto va bene
avremo in tabella 200.
Come si vede in tabella le
celle per la macchina numero uno sono come previsto 200 con tre posizioni e due
profondità a coordinate tutte a zero. Dopo l’ultima cella non compaiono più
record perché quella inserita è l’unica definizione in tabella.
Ora l’operatore va a quotare una parte dello scaffale considerando
solo le celle comprese tra la terza e la settima colonna e tra il secondo e il
quarto piano, quindi avremo una situazione in pagina due uguale a quella in
figura qui sotto.
La quotazione partirà dalla
posizione centrale anteriore della cella numero venticinque terza colonna
secondo piano, questa posizione avrà coordinate uguali a zero per la prima
profondità e Y e X in seconda profondità uguali a 500.
Terminerà alla posizione
destra posteriore della novantaduesima cella quinto piano settima colonna
Ora in tabella avremo una
situazione del genere
Come previsto il calcolo
delle quote parte dalla posizione centrale anteriore della venticinquesima
cella prima al secondo piano terza colonna con coordinate a zero e finirà alla
novantaduesima seconda al quinto piano settima colonna.
Dalla tabella si può notare
come le coordinate siano state calcolate in base al passo colonne e al numero
celle per colonna.
Dopo avere inserito le
coordinate si vuole modificarle. Grazie a pagina tre l’operatore sarà in grado
di definire una parte dello scaffale per la modifica e sommare alle quote delle
posizioni e profondità delle sue celle una costante o una variabile.
Nell’esempio qui sotto
verranno considerate le celle comprese tra la prima e la quinta colonna e tra
il primo e il quinto piano; alle quote X di tutte queste verrà sommato 100,
mentre alle quote Y verrà fatta una somma incrementale, quindi alle celle del
primo piano 100 a quelle del secondo 200 a quelle del terzo 300 a quelle del
quarto 400 e a quelle del quinto 500.
Dalla Form qui sopra si nota
la disabilitazione di X incrementale e di Y costante dovute ai valori
rispettivamente di X costante e Y incrementale diversi da zero.
Quindi la tabella risulterà
essere uguale a quella qui sotto, come si vede la coordinata X della cella 24
prima a zero ora è uguale alla costante sommata 100, come anche la posizione
centrale della 25, mentre la posizione di sinistra prima uguale a –167 ora è
uguale a –67.
La quota Y della cella 24
essendo al secondo piano è uguale a 200, mentre la Y in seconda profondità
della 25 prima a 500 ora è uguale a 700; infatti la somma incrementale Y al
primo piano sarà 100,al secondo piano sarà uguale a 200, al terzo 300 e così
via.
Ora l’utente fa la copia
della definizione sullo scaffale di sinistra della macchina due.
Come si vede dalla figura
qui sotto il programma attraverso il clic del comando Copia creerà in tabella
una definizione uguale a quella inserita in precedenza per lo scaffale di
sinistra con prima cella 1000 per la macchina due
In figura si nota anche che
il secondo spazio è disattivato, infatti non è stata selezionata la Casella di
controllo attraverso la quale sarà possibile usufruire dei dati all’interno
dello spazio.
In questo caso non è stata
inserita la prima cella di sinistra della macchina sorgente perché in tabella
non è presente per questa macchina uno scaffale di sinistra, altrimenti il
programma non avendo la possibilità di distinguere tra scaffale di destra o di
sinistra avrebbe fatto la copia di entrambi gli scaffali.
In figura qui sotto possiamo
vedere come appare la tabella dopo aver fatto la copia, infatti possiamo notare
che la definizione dello scaffale per la macchina due inizia dalla cella 1000,
come voluto , con una tipologia di cella uguale a quella della macchina uno e
stesse coordinate X, Y e Z.
La prima cella risulta
essere la 1000 come abbiamo desiderato inserendo in prima cella dello scaffale
di sinistra 1000, l’ultima rispecchiando la definizione della macchina uno sarà
uguale a 1200
Ora vediamo come è possibile
eliminare dalla tabella tutti i record riferiti ad una macchina. Per poter
disporre di questa funzione prima di tutto bisognerà selezionare la Casella di
controllo “Elimina solo una macchina” che abiliterà la Casella di testo per la
macchina e il Comando Cancella, quindi inserendo in macchina uno e cliccando su
Cancella il programma eliminerà dalla tabella tutti i record riferiti alla
macchina uno.
Notiamo come alla selezione
della Casella di controllo “Elimina solo una macchina” vengano abilitati la
Casella di testo “Macchina” e il comando Cancella consentendo così questa
funzione.
Prima della eliminazione
l’operatore sarà informato della operazione in corso da un messaggio come
quello sotto e sarà in grado di continuare o rinunciare alla operazione
Come si vede dalla tabella
l’operazione è stata eseguita infatti sono stati eliminati tutti i record della
macchina uno.