F.A.Q.

 

Egregi lettori

le vostre domande sono meritevoli della nostra attenzione. Altresì mi delizio per i complimenti ricevuti. In fin dei conti, chi scrive articoli, su internet o altre piattaforme orientate ai godimenti di un pubblico eterogeneo, trastulla l’ispirata verve sulle accondiscendenze dei propri lettori. Il successo dei miei articoli è così dimostrato dall’interesse di un vasto pubblico e dal continuo flusso di domande che mi vengono poste in merito ai database. Chiaramente non sempre è possibile rispondere, o rientrare in tempi accettabili: chiedo scusa ai lettori, ma, come ebbi già modo di partecipare in altre occasioni, il tempo, per chi accudisce il nostro mestiere, è un despota inflessibile. Mi compiaccio comunque e sempre della vostra cortese attenzione, che onora il mio lavoro e spinge il nostro staff ad essere sempre a disposizione del pubblico. Come ricambiare le vostre attenzioni? Rispondendo alle domande, che sono un diritto di chi legge ed impongono dovere a rispondere per chi scrive! Al vostro servizio dunque, umile servitore del mio vasto ed appassionato pubblico. Premesso ciò passiamo alle risposte.

 

Ho un applicativo di tipo gestionale fatto in delphi 6 ed uso delle tabelle paradox. Se volessi portare in rete il programma cosa mi consiglieresti fare???? 
Sono un po' in confusione su cosa fare nel senso che non so prendere una decisione alla fine l'applicativo dovrà girare su tre pc con windows xp in rete a 100... 
Alcuni mi hanno detto che devo mappare il percorso del server altri che non c'è ne sta bisogno perchè i file paradox gestiscono la rete ma io ho provato e sinceramente va molto piano non so cosa fare... poi ho letto il tuo manuale sui database mi ha incuriosito molto quello che tu chiami "il mio sistema" si possono avere ulteriori chiarimenti a proposito ?

Purtroppo le informazioni da lei indugiate a riguardo del problema sono davvero poche. La lentezza cagionata nel suo programma può giustificarsi in svariati modi. Generalmente, un errore consueto, nei programmi di tipo Client – Servere, soprattutto se non si ha la necessaria esperienza, è dovuto alla connessione di una tabella oppure una query ad un controllo di tipo DBGrid. Infatti le operazioni di scansione all’indietro di suddetta tabella risultano essere esageratamente lente. Nel caso di database locali, le tabelle sono dei file sequenziali il cui ordine è di natura fisica oppure subordinato ad un indice. I server SQL, invece, operano con insiemi di dati logici che non sono assolutamente relazionati ad un ordinamento strutturale di tipo fisico. Un server per database relazionali manipola i dati in base al modello relazionale, che è ricavato da un modello matematico appartenente alla teoria degli insiemi. E’ importante capire che i tuple o record di  una tabella vengono identificati in modo univoco non dalla posizione ma da una chiave primaria basata su uno o più campi. Quando il server ottiene un insieme di record, aggiunge, ad ognuno di essi, un riferimento che punta al successivo: ciò rende molto veloce lo spostamento in avanti, ma di una lentezza esasperante quello all’indietro. Questa è la ragione per cui diciamo che un RDBMS utilizza cursori monodirezionali. Il BDE risolve questo problema ospitando in una cache locale i record preventivamente caricati nella tabella. In questo modo i record successivi vengono richiesti al server, mentre il BDE si cura di quelli già esaminati, rendendo in tal modo, i cursori sopra citati, totalmente bidirezionali.

Ripeto, le cause possono essere davvero tante, generalmente, quanto sopra descritto, è uno degli errori più frequenti, ma non l’unico!

Per quanto riguarda il "Mio sistema", è il parto di una decina d’anni di studio in merito allo sviluppo di applicazioni database. Affronta tutta una serie di problematiche dovute al concetto di memorizzazione, visualizzazione, manipolazione dei dati. Ho deciso di renderne pubblica una piccola parte, poiché convinto assertore del concetto "è bene che la gente sia erudita!". Esporrò, comunque, nel proseguo delle mie lezioni, altre astrazioni riguardanti il "Mio sistema", affinché, chi vuole, possa utilizzare con successo queste mie teorie!
Mariano.

Mi interessa sapere la differenza che passa tra una procedura e una funzione ed eventualmente come faccio a realizzare si la prima che la seconda e soprattutto come inizializzarle.

La differenza sostanziale tra la procedura e la funzione e che la seconda ritorna un risultato ( può tornare un integer, un float, una string, un boolean dipende da quello che deve fare la nostra funzione), mentre la procedura esegue la parte di codice in essa scritta senza ritornare nulla.
Ecco un piccolo esempio di Funzione che raddoppia il numero inserito nella edit1 mostrando il risultato nella edit 2:

unit Raddoppia;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
X :integer;
implementation

{$R *.dfm}
function Raddoppia_X (X: Integer): Integer;
 begin
  X := X * 2;
  Result := X;
 end;
procedure TForm1.Button1Click(Sender: TObject);
 begin
  edit2.Text := inttostr (Raddoppia_X(Strtoint(edit1.Text)));
 end;
end.

L'help in lin
ea di delphi alla voce :Procedure declarations e Function declarations mi sembra comunque molto esaustivo oltre a mettere a disposizione alcuni chiari esempi, buon lavoro
DelphiRuby (Mauro).

Ho utilizzato il seguente codice per far in modo che mi restituisse un determinata quantità di numeri casuali,servendomi naturalmente di una form, di un pulsante e di un listbox:

procedure TForm1.Button1Click(Sender: TObject);
var

 I: Integer;
  begin
   ListBox1.Items.Clear;
    Randomize;
    I := 0;
   while I <= 1000 do
    begin
     I := I + Random (100);
     Listbox1.Items.Add ('Numero Casuale: ' + IntToStr (I));
   end;

Il motivo della mia domanda sta nel fatto che ricevo un quantità di numeri superiore a quella che mi aspettavo e soprattutto un taglio di numeri superiore alla centinaia. Detto questo, come posso calibrare il codice in esame per permettere all'applicazione di restituirmi solo una certa quantità di numeri e solo i numeri che vanno da 50 a 100 per esempio? Certo di una sua pronta risposta invio cordiali saluti.

Non so quanti numeri si aspettasse di ricevere. ma leggendo le righe di codice mi salta subito all'occhio che con il comando:
while I <= 1000 do
  begin 
  ....
 end;

il compilatore continuerà a generare numeri random fino a che non ci sarà un numero maggiore o uguale a 1000 (quindi non si puo prevedere quante generazioni verranno fatte, per avere un numero preciso dobbiamo impostare noi una routine come per es. for I := 1 to 10 do begin....end; in tal modo verranno generati 10 numeri).
Invece per il taglio di numeri generati basta ricorrere alla funzione "RandomRange" che ci permette di decidere il range in cui verranno generati i numeri.
Ecco un piccolo esempio che genera 10 numeri compresi tra 100 e 250.

procedure TForm1.Button1Click(Sender: TObject);
 var

 I, Num: Integer;
  begin
   ListBox1.Items.Clear;
   Randomize;
    for I := 1 to 10 do
     begin  
      Num := RandomRange(100,250);
      Listbox1.Items.Add ('Numero Casuale: ' + IntToStr (Num));
     end;
  end;
Buon lavoro DelphiRuby (Mauro).

Sono interessato allo studio di SQL come del resto Lei menziona nella sua guida database, ma non so da dove iniziare. Potrebbe darmi un consiglio? In libreria ho dato un'occhiata ed esistono vari tipi di sql ma non so quale acquistare. Cosa devo chiedere al rivenditore? quale tipo di sql devo compare per delphi?
P.S.
Esiste una guida on-line?

Su Internet si trova praticamente di tutto, mancano solo il fagiolo magico e la bacchetta del buon Merlino. Figuriamoci i trattati su SQL. Egregi Paolo e Roberto, consiglio due esposizioni veramente efficaci: “Il manuale SQL” scritto da Stephen Cannon e Gerard Otten. Cinquecentoottanta pagine da gustare in solitudine, preferibilmente davanti al computer. Un libro davvero notevole, che vi introdurrà nel mondo SQL gradatamente, ricorrendo ad egli esempi molto validi. Da non perdere. Se poi questo testo non fiaccherà la vostra perspicacia ad erudirvi in questo campo, comperate senza indugio “Il manuale SQL” scritto da Ryan K. Stephens, Ronald R. Plew, Bryan Morgan e Jeff Perkins: basato su un’impostazione didattica ferrea ed una conduzione spartana, ricca di esempi, esercizi e tutto il resto. Apporterà, al vostro bagaglio tecnico, dei benefici notevoli. Un ottimo libro! Personalmente li ho studiati entrambi, a fondo, e non solo per motivi squisitamente culturali. Se sopravvivere te all’ardua prova, scrivetemi ancora, oltre che complimentarmi per lo spirito di abnegazione, vi introdurrò a dei trattati che potranno completare la vostra preparazione in materia.
Mariano.

Nella terza lezione sui database Lei menziona il componente TScreen che funziona, come mi insegna, per adattare l'applicativo a qualsivoglia risoluzione video mantenendo anche adeguate proporzioni, font ecc. Vorrei sapere se il suddetto componente è nativo in delphi o si tratta di un componete aggiuntivo? Potrei ricevere informazioni in merito e soprattutto come configurarlo e da dove eventualmente scaricarlo ?
Nella stessa lezione ci evidenzia la potenzialità del componente ActionListEditor: potrei sapere come utilizzarlo?

Il componente TScreen nasce con Delphi, è parte del suo patrimonio genetico. Viene creato, come ho spiegato in una lezione pubblicata sul sito, all’avvio di ogni applicazione. Contiene, tra tante altre cose, le informazioni relative alle dimensioni dello schermo tramite le proprietà Whidth e Size. Vediamo un esempio: una form denominata FrmChiama posiziona una form denominata FrmProva.

procedure FrmChiama.FormCreate(Sender: TObject);
 var
 WM: Integer;
  begin
   WM := FrmProva.Width;
   if Screen.Width >= 2 * WM then
    Left := WM
    else
    Left := Screen.Width-WM;
     ….
end;
Nelle applicazioni che girano in sistemi operativi come quelli attuali, esistono svariati modi per impartire dei comandi, come ad esempio una voce di menu, un pulsante ed altro. Al fine di poter attribuire una specifica propria ad ognuno di questi comandi, soprattutto per quanto concerne l’interattività uomo - macchina, Delphi, dalla versione 4, ha introdotto il concetto di “Azione”, stupendamente magnificato dalla versione 6. In pratica è possibile creare un’interfaccia utente la cui attività basata su Action risulti totalmente visuale. Altresì è possibile demandare all’utilizzatore finale il compito di modificare l’interfaccia dell’applicativo a proprio piacimento. Delphi vanta un’architettura degli eventi piuttosto aperta, questo consente di scrivere un singolo gestore e collegarlo agli eventi OnClick, ad esempio, di una barra pulsanti inglobata in un menu. Il medesimo evento può essere altresì gestito da diversi pulsanti o voci di menu, semplicemente ricorrendo al parametro Sender. Diviene invece più difficile gestire la sincronizzazione tra pulsanti e voci di menu: se abbiamo infatti un pulsante ed una voce di menu che gestiscono il medesimo evento, ogni qualvolta questi sarà richiamato, è necessario aggiungere un segno di spunta alla voce di menu e modificare lo stato del pulsante in modo che venga indicato che è stato premuto. Per ovviare a questo problema è nato il componente ActionList, o Lista di azioni, cioè di comandi. Un’azione o comando, indica quindi l’operazione in corso quando si ricorre agli eventi OnClick, determinando lo stato operativo di tutti gli elementi (pulsanti e voci di menu) ad essi collegati. Ho realizzato un esempio che ritengo sufficientemente istruttivo nel programma Alice, collocando il componente relativo nel modulo centrale del programma. Il componente gestisce le azioni relative alla navigazione dei record in una tabella database, ma può essere predisposto, come appena spiegato, alla gestione egli eventi OnClick relativi alle azioni necessarie a sovrintendere i comandi di pulsanti e voci di menu tra esse logicamente correlate.
Mariano.

Nelle lezioni sui database, ho letto che lei fa riferimento ed uso del componente 'Query'. Potrei sapere l'utilizzo specifico e i relativi benefici apportati da questo componente?

Semplicemente dico che, senza l’utilizzo di SQL non è possibile realizzare applicativi database di un certo livello. Nel caso specifico, il componente Query è il tramite verso questo linguaggio. Ho descritto con dovizia di particolari le funzioni del componente Query ed i benefici che questo linguaggio comporta nel corso delle lezioni pubblicate sul sito. Pertanto, rispettosamente, vi rimando alla lezione menzionata. Ad ogni modo, la realizzazione di applicativi di tipo gestionale, quindi preposti alla manipolazione di grandi quantità di dati, debbono obbligatoriamente servirsi di questo linguaggio, poiché specifici problemi possono essere risolti esclusivamente ricorrendo ad SQL. Il componente Query, nel nostro caso, assolve, per citarne alcuni, compiti legati alla visualizzazione, contabilità, aggiornamento e modifica dei dati. Silenziosamente, dietro le quinte. Lavoratore indefesso, col suo operato, grava su di sé gran parte del lavoro occulto che consente il buon funzionamento di un applicativo interfacciato con motori database!
Mariano.


Vorrei tanto sapere se in delphi 7 esiste una funzione che mi permette di verificare se il codice da me stilato presenta imperfezioni.

Non mi risulta che esita una funzione del genere anche se la domanda lascia spazio a molteplici interpretazioni, ma diciamo che come sicuramente sarà già capitato a ognuno di noi se ci sono degli errori di sintassi nel codice il compilatore non ci permette la compilazione segnalandoci a che riga del .PAS si trova l'errore, se per esempio nel nostro codice vogliamo utilizzare una variabile ma non è stata preventivamente dichiarata (ad es. variabile_A):
procedure TForm1.Button1Click(Sender: TObject);
 var
  a :integer;
   begin
    A := variabile_A;
   end;

il compilatore ci ritorna il seguente messaggio:
[Error] Unit1.pas(31): Undeclared identifier: 'variabile_A'
[Fatal Error] Project1.dpr(5): Could not compile used unit 'Unit1.pas'
in questo caso siamo avvisati che nel programma abbiamo cercato di utilizzare una variabile (alla riga N°31) senza averla preventivamente dichiarata.
Oltre alla segnalazione degli errori veri e propri possiamo ci possono essere degli avvisi dati dal compilatore, ad Es :

procedure TForm1.Button1Click(Sender: TObject);
 var
  A, variabile_A :integer;
   begin
    A := variabile_A;
    inc(A);
   end;
in questo caso l'avviso è il seguente:
[Hint] Unit1.pas(32): Value assigned to 'A' never used
[Hint] Unit1.pas(31): Value assigned to 'A' never used

la compilazione viene effettuata regolarmente ma ci viene segnalato che il valore assegnato alla variabile A non viene utilizzato nel nostro programma.
Potremmo anche trovarci degli avvertimenti (warning), la compilazione come nel caso precedente viene effettuata, ma al confronto di un (Hint) in nosto Delphi ci chiede di prestare maggiore attenzione. Nel manuale in linea alla voce Delphi compiler error messages sono elencati tutti i messaggi che possiamo incontrare.
Esistono poi, delle regole di bella sintassi che possono essere quella di andare a capo dopo un punto e virgola, nei loop annidati spostarci di almeno uno spazio per ogni ciclo di for - next o while - do ecc. utilizzare dei colori differenti per i commenti, parti in assembler, stringhe ecc. e usare un colore che salti all'occhio per le reseved word, insomma un pochino d'ordine non fa mai male.
Per concludere ci tengo a precisare che questi sono solo dei consigli non regole ma negli anni a me personalmente hanno dato dei riscontri positivi, soprattutto in caso di manutenzione o modifiche del codice e sicuramente aiuta a leggere il listato in modo più scorrevole.
Buon lavoro DelphiRuby (Mauro).


Potresti dirmi come convertire una stringa esadecimale in decimale?

Approfittando della domanda e considerato che altri lettori hanno fatto domande sulla conversione da HEX a DEC ho pensato di creare una funzione che possa risolvere il problema e la si può trovare nella pagina dei TIPS (converte da esadecimale a decimale)    VAI 
oppure nei TRUCCHI \ MISCELLANEA c'è un esempio con il progetto completo.
Buon lavoro DelphiRuby (Mauro).

Sono curioso di sapere se per installare il BDE Administrator nel computer destinatario (utente finale dell'applicativo) si deve solo ricorrere al software "InstallShiel" o ci sono in merito dei trucchi o delle tecniche che permettono di omettere le potenzialità di questo programma.
Potrei sapere ancora, se esistono altri software simili a InstallShied e che quindi permettono l'installazione e la configurazione dell'Alias nel p.c. destinatario ed eventulamente dove reperirli? Grazie

Qualsiasi programma può essere installato manualmente, anche il BDE Administrator. E’ necessaria una buona conoscenza del registro di Windows e dei file di configurazione che accompagnano il prodotto. Però è un problema che non ha motivo d’essere, poiché il programma InstallShield in dotazione con Delphi è veramente un ottimo prodotto. Esistono tanti altri applicativi similari (visitare il sito www.pcwdirect.it), più o meno validi, alcuni costosi altri meno. Altresì è possibile creare un programma d’installazione personalizzato, ma è necessario avere una grande preparazione. Tutto sommato, InstallShield offre il necessario per creare un setup degno di questo nome. E poi, a caval donato..!

  
Nella domanda che io ho fatto : "Esiste un sistema per rendere un'applicazione utilizzabile solo per un determinato periodo di tempo, scaduto il quale l'applicazione non sarà più utilizzabile, se non con l'uso di un codice seriale che serva da sblocco?" in cui Lei mi risponde che "Di sistemi ne esistono diversi, più o meno efficaci. Potrebbe impostare il suo Applicativo con un contatore che tenga conto del lancio del programma. Altresì, se l'applicativo s'interfaccia con motori database, può impostare, ad esempio, per una determinata tabella, un certo numero di record, raggiunto il quale, il programma giunga ad un blocco.In base a quanto da lei gentilmente consigliatomi nelle FAQ desidererei sapere come implementare un codice che monitorizzi il numero di volte in cui il software viene lanciato ? oppure, come fare affinché la mia applicazione contenente tabelle (database) potrà contenere solo un certo numero di record.

Nella fase di apertura del programma, quindi nella form principale, è necessario implementare un contatore che incrementi di uno il proprio valore ad ogni esplosione dell’eseguibile. Una variabile di tipo Integer si adopera meravigliosamente allo scopo.Suddetto valore dovrà essere occultato nella system di windows, oppure se preferisce, in una stringa del registro, o ancora dove lei ritenga sia al riparo dall’accanimento mal celato dei predatori di software! Per realizzare questa alchimia può utilizzare il componente Memo, che, tra le sue opulenze, pone in bella mostra due funzioni assai toste: SaveToFile e LoadFromFile. Detto ciò dovrà aver cura di trasferire il valore dal contatore all’interno del componente memo e viceversa (le funzioni StrToInt e IntToStr, di cui abbiamo già parlato, si prestano che di più non si può), per ricorrere quindi alla funzione SaveToFile in precedenza citata. Andrà perciò ad occultare, la prima volta in cui il programma verrà esploso, il valore del contatore dove più riterrà opportuno. Esempio:
memo1.Lines.SaveToFile('C:.Dat);

Se poi ha dimestichezza con delle tecniche di criptazione dei file, ancora meglio.
Fatto ciò è necessario predisporre il codice che andrà a richiamare il valore del contatore e, ad ogni esploso dell’applicativo, lo importerà nel componente Memo. Esempio:

memo1.Lines.LoadFromFile('C:.Dat);

Questo valore verrà ora confrontato con una procedura da lei predisposta e che determinerà quando il programma dovrà estinguere. Se i valori coincidono l’applicativo, al prossimo riavvio, visualizzerà il triste messaggio. Tenga presente che questa è una buona tecnica, ma deve essere implementata con degli accorgimenti piuttosto elaborati, affinché i nemici non abbiano di che portar via la bandiera!
Per quanto riguarda le tabelle database, le procedure concernenti la sicurezza si fanno un tantino più delicate. Ma è altrettanto vero che si può ricorrere a degli stratagemmi che danno tanto filo da torcere alle quelle zucche illuminate dai fulmini di Giove che tanto godimento traggono nel penetrare furtivamente gli altrui sistemi. Una volta predisposta la procedura di comparazione (questa potrebbe pescare i dati da qualche file ben celato ed alimentato da ogni evento di memorizzazione Post che dovrà stabilire il numero di record necessari affinché l’applicativo debba cessare di funzionare, ricorrerà alla funzione RecordCount, che restituisce, all’interno di una variabile intera, il numero di record presenti in una tabella. Esempio:

var
I: Integer;
begin
 I:= Miatabella.Recordcount;
 If I = 30 then
  begin
   //confronto con procedura
   //se il confronto è positivo allora...... 
   Showmessage(‘Il programma è scaduto!’);
     ……
    ……
 end;
end;

Nel caso specifico ho supposto un massimo di 30 record. Rammenti che, chiunque abbia una copia del Paradox è in grado di modificare i valori di una tabella. Senza chiamare in causa quei programmi di tipo disassembler che, in mano a persone esperte, riconducono alla procedura di comparazione e addirittura ne modificano le risultanze. Ecco perché le procedure di comparazione dovrebbero risiedere, in piccole porzioni, all’interno di più DLL preposte a tal compito, anch’esse ben occultate. Se lei riesce a fondere insieme le due tecniche appena esposte, può ottenere dei buoni risultati. Tenga conto che, impostando un contatore di comparazione con i record di un database, è necessario predisporre almeno una decina di tabelle civetta, con il più alto numero di campi possibile, tutti operativi, che svolgano in apparenza la funzione di contatore, in modo tale che, chi dovrà aggredire le sue alchimie informatiche, abbia a che divertirsi! Non è mica tanto semplice, in un mare di cento e passa campi capire quello che svolge il compito base. In questi casi è molto importante la fantasia ed il saper predisporre codice fantasma, cioè apparentemente inutile! Termino consigliandole di sperimentare con passione quanto sopra esposto, soprattutto se ha intenzione di produrre programmi di un certo livello!

NEXT PAGE

Ritorna alla pagina principale