Newsgroup: it.comp.lang.delphi
Titolo: Frame Codice-Descrizione legato ai dati

Ciao a tutti,
Non so voi...
Ma a me capita spesso di dover gestire dati nella forma codice-
descrizione.
Spesso esiste una form in cui l'utente puo' inserire un codice e il
campo descrizione (legata a quel codice) deve essere presentato.
Oppure puo' effettuare una ricerca in una form di ricerca il cui
risultato e' selezionare un codice (e la descrizione collegata).
Volevo crearmi un frame in cui mettere due caselle (codice e
descrizione) e legarle in qualche modo ai dati tramite datasource.
In questo modo vorrei creare un frame "universale" per tutte quelle
tabelle codice-descrizione da riusare in tutte le form di un
gestionale.
Secondo voi e' fattibile?
Come procedereste?
Non mi piace l'idea di avere una tendina (lookupcombobox) perche'
implica caricare ogni volta tutti i record della tabella codice-
descrizione...e credo sia poco performante.
JH

 Come procedereste?
Cerca per internet partendo da google, lookup fields, db lookup, 
incremental searching, ecc..
un link utile:
http://delphi.about.com/od/database/l/aa121499a.htm
adattalo alla tua situazione.
Ciao
-- 
Morde

 Come procedereste?
Certo che è fattibile. Costruisci un Frame o un Form con le 
caratteristiche (dal punto di vista dell'aspetto e del comportamento) 
che possano adattarsi a tutte le esigenze; se poi avrai necessità di 
personalizzarlo, puoi sempre creare un Frame/Form discendente, 
sfruttando la VFI (Visual Form Inheritance) di Delphi.
E' un approccio che personalmente adotto quasi allo sfinimento, perché è 
molto comodo ed efficace.
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

 molto comodo ed efficace.
Infatti sono partito proprio cosi'.
Io ho scelto la via del frame perche' vorrei poter "piazzare" il nuovo
pseudo-componente (domani...magari potrei farlo diventare un
componente vero e proprio)
nelle varie form.
Faccio un esempio perche', in effetti , nel primo post mi ero spiegato
molto male.
Supponiamo di voler fare un programmino banale di inserimento fatture.
Chiaro che, l'uente, deve poter scegliere il cliente.
Supponiamo che la tabella fatture testata (lasciamo perdere le righe)
sia caricata in un clientdataset.
E' chiaro che li' ci sara' il campo "codicecliente".
(supponiamo che non ci sia la ragionesociale...anche se, in effetti,
potremmo anche metterla direttamente
nella tabella delle fatture...ma supponiamo che ci sia solo il codice
del cliente, senza la ragionesociale)
Visivamente e' piu' utile mostrare all'utente sia il codice che la
ragionesociale
anche se poi...nella tabella fatture, mettero' solo il campo
codicecliente.
A questo punto io volevo creare questo frame che , come property
avesse il fieldname del "codice"
Che avesse inoltre una property "datasource" per poterlo collegare
alla tabella fatture (al clientdataset...in questo caso)
E poi ...magari una property "SQL" , in modo tale da indicare la query
per reperire la descrizione ogni qualvolta il codice cambia.
Quindi il frame dovrebbe intercettare i cambiamenti del campo
"codice" (collegato al clientdataset) e , allo scattare dell'evento
, andare ad eseguire la query lato server in modo da mostare la
descrizione collegata a quel codice.
Quindi...
Io procedrei cosi':
creerei nel frame delle "property" nuove (in modo tale da poterle
vedere come proprieta' del frame quando lo aggiungo ad un form)
queste property dovranno servire
1) a collegare il frame ad una tabella (clientdataset) ...per poter
leggere/scrivere il campo codice
2) ad eseguire la query sql per ottenere, a partire dal codice, la
descrizione
suggerimenti utili?
ci sono scorciatoie?
JH

Primo problema:
ho costruito il frame cosi':
1) componente tdbedit per il codice
2) componente tedit per la descrizione
3) datasource collegato al tdbedit
ho messo il codice per caricare la descrizione associata al codice
nell'evento ondatachange del datasource.
procedure TfrCodiceDescrizione.dsCodiceDataChange(Sender: TObject;
  Field: TField);
begin
	if edCodice.Text = '' then
   	begin
      	edDescrizione.Text := '';
         Exit;
      end;
   if qyDes.Active then
    qyDes.Close;
   qyDes.ParamByName('codice').asinteger := edCodice.Field.AsInteger;
   qyDes.Open;
	if qydes.eof then
   	begin
         //edcodice.setfocus;
         //edDescrizione.text := '';
         if not (dscodice.State in [dsedit,dsinsert]) then
         	begin
               eddescrizione.text := '*** SCONOSCIUTO ***';
            end
         else
         	begin
            	showmessage('il codice digitato ('+edcodice.text+') non
esiste');
            	edcodice.Undo;
               edcodice.setfocus;
					abort;
            end;
      end
   else
   	begin
	   	edDescrizione.text := qydes.fieldbyname('risultato').asstring;
      end
end;
se l'utente si sposta in una tabella...tutto ok
(la descrizione viene aggiornata)
se l'utente inserisce nel dbedit un codice che non esiste
volevo bloccare l'inserimento con messaggio "il codice non esiste"
la cosa funziona, ma se col mouse sposto il focus
su una griglia...il db mi fa il post dei dati errati
quindi il blocco non funziona.
dove e' meglio mettere questo controllo?
JH

 nell'evento ondatachange del datasource.
NB: (IMHO)
Il codice che hai scritto nell'evento OnDataChange non fa altro che 
abbattere le prestazioni dell'applicazione almeno metti qualche 
controllo, un assigned field un try finally
Goblin

 controllo, un assigned field un try finally
Il codice che ho scritto (a parte rallentare le prestazioni) dovrebbe
caricare nel tedit "edDescrizione" la descrizione collegata al codice.
Sono d'accordo con te che vada ottimizzato e sistemato, ma il problema
non è li'...
Il mio problema e' nel validare il codice inserito (nel caso in cui
l'utente
lo inserisse manualmente).
Nel frattempo ho scoperto che sollevare un'eccezione con la Abort
nell'evento
OnDataChange non funziona bene. (talvolta , smanettando col mouse, si
riesce
a fare il post dei dati anche se questi non sono corretti).
Ho cosi' trovato un'altra soluzione.
A runtime, assegno un evento onValidate del campo collegato al codice.
Spostando nell'onvalidate la logica del controllo sui dati inseriti.
Cosi' funziona bene.
Ovvero: cosi' l'utente non riesce in nessun modo a inserire nel campo
codice
un codice che non esiste nella tabella collegata.
(tradotto: non riesce ad inserire nella fattura un codice cliente che
non esiste
in anagrafica clienti).
Per ora quindi ho risolto.
Vorrei poi mettere a disposizione di tutti il codice cosi' ottenuto
per avere
consigli e/o miglioramenti.
JH

 non è li'...
Forse nel mex precedente mi sono spiegato male (a dire il vero non mi 
sono spiegato per niente :) ) cmq secondo me bastavano poche modifiche 
al tuo codice per farlo funzionare anche nell'evento OnDataChange. Poi 
... forse mi sbaglio in quanto il pezzo di codice sotto non l'ho testato.
var lLoop: Boolean; //(variabile privata) mi serve per evitare la 
ricorsione nel datachange
procedure TfrCodiceDescrizione.dsCodiceDataChange(Sender: TObject; 
Field: TField);
begin
   If Assigned(Field) then
     if (UpperCase(Field.FieldName) = 'CODICE') and (Not lLoop) Then
     begin
       lLoop := True;
       Try
         if edCodice.Text = '' then
         begin
           edDescrizione.Text := '';
           lLoop := False; // non mi ricordo se exit passa nel finally
           Exit;
         end;
         if qyDes.Active then
           qyDes.Close;
         qyDes.ParamByName('codice').asinteger := edCodice.Field.AsInteger;
         qyDes.Open;
         Try
           if Not qydes.eof then
             edDescrizione.text := qydes.fieldbyname('risultato').asstring
           else
           begin
             showmessage('il codice digitato ('+edcodice.text+') 
nonesiste');
             edcodice.Clear; //(se è un dbedit)
           end;
         finally
           qyDes.Close;
         end;
       finally
         lLoop := False;
       end;
     end;
end;
Ciao
Goblin
-- 
Ibis et redibis non morieris in bello
http://goblinland.myminicity.com/

           if Not qydes.eof then
Errata corrige :)
  - if Not (qydes.bof and qydes.eof) then
