dovresti fare in modo che, per tutti gli edit, il nome sia formato da un prefisso + un contatore, ad esempio:
Edit1, Edit2, Edit3, ec...
poi puoi cercare l'edit come suggerito nella funzione sotto
function EnumControls(const aControl:TWinControl; const StartSpace :string=''):String;
var
Res : string;
begin
for Cnt := 0 to aControl.ControlCount -1 do
begin
WriteStr(Res,StartSpace + aControl.Controls[Cnt].Name);
Result:= Result + Res + LineEnding;
if aControl.Controls[Cnt] is TWinControl then
EnumControls(TwinControl(aControl.Controls[Cnt]), StartSpace+' ')
end;
end;
in alternativa ti puoi salvare i puntatori dentro ad un array in modo da accedere tipo:
dovresti fare in modo che, per tutti gli edit, il nome sia formato da un prefisso + un contatore, ad esempio:
Edit1, Edit2, Edit3, ec...
poi puoi cercare l'edit come suggerito nella funzione sotto
function EnumControls(const aControl:TWinControl; const StartSpace :string=''):String;
var
Res : string;
begin
for Cnt := 0 to aControl.ControlCount -1 do
begin
WriteStr(Res,StartSpace + aControl.Controls[Cnt].Name);
Result:= Result + Res + LineEnding;
if aControl.Controls[Cnt] is TWinControl then
EnumControls(TwinControl(aControl.Controls[Cnt]), StartSpace+' ')
end;
end;
Ti ringrazio moltissimo per il suggerimento e sto cercando di capire bene il primo dei due esempi che mi hai gentilmente fornito. Purtroppo ho alcuni vuoti di comprensione nel tuo codice:
- StartSpace, aControl sono costanti.
- EnumControls è una funzione tua che visualizza in qualche modo i controlli con lo stesso prefisso nel nome? (Error: Identifier not found "EnumControls")
Te lo chiedo perchè ho ricevuto errori in compilazione e, in particolare:
procedure TForm411.FormCreate(Sender: TObject);
const
aControl:TWinControl; // Fatal: Syntax error, "=" expected but ";" found
puoi semplificare
for i := 1 to 9 do
begin
x := FindComponent('Label' + IntToStr(i)).ComponentIndex;
TEdit(Components[x]).Text := IntToStr(i);
end;
EnumControls non è una mia funzione, è solo un esempio che ho trovato che mostra come accedere ai controlli figli tramite la proprietà controls
molto più semplicemente Controls contiene tutti i controlli di un container (form, pannello, ec...)
quindi
ti restituisce il puntatore al primo controllo della form
con un semplice loop da 0 (zero) a ControlCount -1 puoi avere una lista di tutti i controlli tra i quali cercare i tuoi TEdit
Benissimo!
In questa fase di studio sto cercando di capire come procedere per trattare le mie 9 TEdit (EmioNum1,EmioNum2ì, ..., EmioNum9), come un array "grafico".
Per arrivare a questo però mi pare di capire che col metodo che mi hai suggerito potrei costruire un array di puntatori alle suddette TEdit.
Se fin qui ho capito bene, dovrei estrarre il valore indirizzo di ciascuna TEdit e caricarlo in un array di tipo indirizzo (es.: Puntatore), in modo da potere accedere alle TEdit tramite il valori indirizzo contenuti nell'array Puntatore.
Mi mancano perciò le conoscenze corrette per ottenere i due risultati suddetti.
Per creare la struttura di aggancio necessaria, ho cominciato a scrivere, con l'aiuto della funzione da te suggeritami, alcune istruzioni nella seguente procedura:
procedure TForm411.FormCreate(Sender: TObject);
const
aControl:TWinControl;
StartSpace: String= '';
var
i: Integer;
Res, aControl: String;
begin
for i := 0 to aControl.ControlCount -1 do
begin
WriteStr(Res,StartSpace + aControl.Controls[i].Name);
Result:= Result + Res + LineEnding;
if aControl.Controls[i] is TWinControl then
EnumControls(TWinControl(aControl.Controls[i]), StartSpace+' ')
end;
{ for i:= 1 to 9 do
begin
tbSist[1,1]:= ;
TWinControl;
end;}
end;
Purtroppo la prova è finita prima di cominciare, perchè il compilatore, come ho indicato nel mio post precedente, mi ha segnalato l'errore già alla definizione di const
aControl:TWinControl; // Fatal: Syntax error, "=" expected but ";" found
Quindi, intanto dovrei capire come uscire da detta segnalazione di errore, in modo da potere arrivare ad ottenere i famosi valori indirizzo a tutte e 9 la mie TEdit.
Spero di essermi spiegato meglio e di potere ancora ricevere l'aiuto che mi porterà a proseguire nella prova studio corrente.
Grazie!
Purtroppo la prova è finita prima di cominciare, perchè il compilatore, come ho indicato nel mio post precedente, mi ha segnalato l'errore già alla definizione di const
aControl:TWinControl; // Fatal: Syntax error, "=" expected but ";" found
Quindi, intanto dovrei capire come uscire da detta segnalazione di errore, in modo da potere arrivare ad ottenere i famosi valori indirizzo a tutte e 9 la mie TEdit.
Spero di essermi spiegato meglio e di potere ancora ricevere l'aiuto che mi porterà a proseguire nella prova studio corrente.
Grazie!
nella sezione const devi definire le costanti e quindi l'operatore che ci si aspetta è '=' (da quì l'errore)
probabilmente volevi scrivere:
type
aControl:TWinControl;
sono alquanto inguaiato. Pur scrivendo:
type
aControl: TWinControl;
il compilatore segnala un errore di sintassi:
carnumgioca.pas(65,11) Fatal: Syntax error, "=" expected but ":" found
Mi dispiace, ma non so proprio andare avanti.
Si ho provato, anche se non so cosa scrivere dopo l'uguale.
Riporto il codice della unit, fino alla procedura incriminata:
unit carNumGioca;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons,
LCLType, ExtCtrls;
type
{ TForm411 }
TForm411 = class(TForm)
EdigNum: TEdit;
EmioNum1: TEdit;
EmioNum6: TEdit;
EmioNum7: TEdit;
EmioNum8: TEdit;
EmioNum9: TEdit;
EmioNum2: TEdit;
EmioNum3: TEdit;
EmioNum4: TEdit;
EmioNum5: TEdit;
GroupBox1: TGroupBox;
Label1: TLabel;
pulsAnnullFrm411: TButton;
procedure EdigNumChange(Sender: TObject);
procedure EdigNumKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
);
procedure FormCreate(Sender: TObject);
procedure pulsAnnullFrm411Click(Sender: TObject);
private
public
end;
var
Form411: TForm411;
implementation
{$R *.lfm}
{ TForm411 }
type
TtbSist = array[0..8] of Integer;
var
tbSist: TtbSist;
procedure TForm411.pulsAnnullFrm411Click(Sender: TObject);
begin
Close
end;
procedure TForm411.FormCreate(Sender: TObject);
type
TWinControl= ^String;
const
StartSpace: String= '';
var
aControl: TWinControl;
i: Integer;
Res: String;
begin
Label1.Caption:= 'Digita un numero' + System.lineending + '(da 1 a 90)';
for i := 0 to aControl.ControlCount -1 do
begin
WriteStr(Res,StartSpace + aControl.Controls[i].Name);
Result:= Result + Res + LineEnding;
if aControl.Controls[i] is TWinControl then
EnumControls(TWinControl(aControl.Controls[i]), StartSpace+' ')
end;
end;
Ora ricevo due errori:
carnumgioca.pas(77,26) Error: Illegal qualifier
carnumgioca.pas(77,26) Fatal: Syntax error, "DO" expected but "identifier CONTROLCOUNT" found
for i := 0 to aControl.ControlCount -1 do f
Ciao.
Come il solito cambio approccio.
Nelle ultime versioni di FPC esistono le enumerazioni (for x in insieme do).
type
{ TComponentEnumerator }
TComponentEnumerator = class
private
FTarget: TWinControl;
FIdx: integer;
function getCurrent: TComponent;
public
constructor Create(aTarger: TWinControl);
destructor Destroy; override;
function MoveNext: boolean;
published
property Current: TComponent read getCurrent;
end;
function TComponentEnumerator.getCurrent: TComponent;
begin
Result := FTarget.Components[FIdx];
end;
constructor TComponentEnumerator.Create(aTarger: TWinControl);
begin
FTarget := aTarger;
FIdx := -1;
end;
destructor TComponentEnumerator.Destroy;
begin
inherited Destroy;
end;
function TComponentEnumerator.MoveNext: boolean;
begin
Inc(FIdx);
Result := FIdx < FTarget.ComponentCount - 1;
end;
operator enumerator(target: TWinControl): TComponentEnumerator;
begin
Result := TComponentEnumerator.Create(target);
end;
questo codice produce la classe che FPC necessita per poter "viaggiare" automaticamente su tipi custom.
In questo caso i component di una classe visuale.
var
c: TComponent;
begin
for c in self do
begin
if (c is TEdit) and (c.Tag = 1) then
begin
ShowMessage((C as TEdit).Text);
end;
end;
end;
Questo è un esempio stupido di utilizzo (come vedi diventa quasi banale).
Per discriminare il tipo di component che ti interessa puoi usare la logica che meglio ti è più congeniale.
Spero di averti dato uno spunto, non so nemmeno se va (scritto di getto).
Stilgar.
[/code]
al di la delle varie strategie per scansionare tutti i componenti del progetto penso che il metodo che ti avevo suggerito sia il più semplice
con x := FindComponent('EmioNum1').ComponentIndex;
ricavi l'indice al componente da utilizzare poi con TEdit(Components[x]).Text := 'Prova';
puoi variare il valore o con stringa := TEdit(Components[x]).Text ;
leggerne il contenuto
Per grandi linee ho capito. La prova prtaica però non ha prodooto il risultato iniziale che speravo.
Riporto il contenuto della unit fino alla procedure .FormCreate:
unit carNumGioca;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons,
LCLType, ExtCtrls;
type
{ TForm411 }
TForm411 = class(TForm)
EdigNum: TEdit;
EmioNum1: TEdit;
EmioNum6: TEdit;
EmioNum7: TEdit;
EmioNum8: TEdit;
EmioNum9: TEdit;
EmioNum2: TEdit;
EmioNum3: TEdit;
EmioNum4: TEdit;
EmioNum5: TEdit;
GroupBox1: TGroupBox;
Label1: TLabel;
pulsAnnullFrm411: TButton;
procedure EdigNumChange(Sender: TObject);
procedure EdigNumKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
);
procedure FormCreate(Sender: TObject);
procedure pulsAnnullFrm411Click(Sender: TObject);
private
public
end;
var
Form411: TForm411;
implementation
{$R *.lfm}
type
{ TComponentEnumerator }
TComponentEnumerator = class
private
FTarget: TWinControl;
FIdx: integer;
function getCurrent: TComponent;
public
constructor Create(aTarger: TWinControl);
destructor Destroy; override;
function MoveNext: boolean;
published
property Current: TComponent read getCurrent;
end;
{ TForm411 }
TtbSist = array[1..9] of Integer; // contiene l'indice di puntamento al componente EmioNum1, EmioNum2, ..., EmioNum9
var
tbSist: TtbSist;
function TComponentEnumerator.getCurrent: TComponent;
begin
Result := FTarget.Components[FIdx];
end;
constructor TComponentEnumerator.Create(aTarger: TWinControl);
begin
FTarget := aTarger;
FIdx := -1;
end;
destructor TComponentEnumerator.Destroy;
begin
inherited Destroy;
end;
function TComponentEnumerator.MoveNext: boolean;
begin
Inc(FIdx);
Result := FIdx < FTarget.ComponentCount - 1; // Result contiene sempre $1008b8fe0
end;
operator enumerator(target: TWinControl): TComponentEnumerator;
begin
Result := TComponentEnumerator.Create(target);
end;
procedure TForm411.pulsAnnullFrm411Click(Sender: TObject);
begin
Close
end;
procedure TForm411.FormCreate(Sender: TObject);
var
indx: TComponent;
i: Integer;
nomeSerie: String = 'EmioNum';
begin
Label1.Caption:= 'Digita un numero' + System.lineending + '(da 1 a 90)';
for indx in self do
begin
if (indx is TEdit) and (indx.Tag = 1) then // indx.Tag è sempre 0
begin
ShowMessage((indx as TEdit).Text); // non viene eseguita mai
end;
end;
end;.
Come puoi riscontrare dalle mie note a fianco alle istruzioni che ho riportato dal codice che mi hai suggerito, l'istruzione SHoeMessage non viene mai eseguita
Ho cercato di seguire la sequenza esecutiva delle procedure e funzioni. Ecco la pseudo trac e che ho ricavato:
procedure TForm411.FormCreate
operator enumerator
function TComponentEnumerator.Create
function TComponentEnumerator.MoveNext
function TComponentEnumerator.getCurrent
function TComponentEnumerator.MoveNext
..................................................................... le tre funzioni elencate sopra sono eseguito in ciclo per 8 volte
function TComponentEnumerator.Destroy
La procedura TForm411.FormCreate Il programma termina senza errori.
Bene.
Modificando il tag di ciascuna TEdit, ho potuto portare a termine il passo di programmazione di prova.
Tuttavia, visto che non devo eseguire, nell'ordinario, una sola volta la scansione di tutte e 9 le TEdit, ho spostato le istruzioni di scansione, portandole dentro la funzione carSist, che richiamo di volta in volta, a fine di digitazione di un nuovo numero. Adesso il codice già provato non funziona più e ricevo Errore già dal compilatore.
Riporto la funzione carSist e la sua chiamante:
function carSist(numDig: String): Integer;
var
indx: TComponent;
i, numCorr: Integer;
cambio: String;
begin
for indx in self do
begin
if (indx is TEdit) and (indx.Tag = 1) then // indx.Tag è sstato impostato a 1 in tutta la serie durante il disegno nella Form
begin
case Length(indx.Text) of
0:
begin
indx.Text:= numDig;
EdigNum.text:= '';
end;
else:
begin
if (indx.Text = numDig) then
begin
ShowMessage('valore digitato = DUPLICATO');
break;
end
else
begin
if (indx.Text > numDig) then
begin
cambio:= indx.Text;
indx.Text:= numDig;
EdigNum.Text:= '';
end;
end;
end;
end;
end;
end;
end;
procedure TForm411.EdigNumKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
esito, i, num: Integer;
msgInfo: String;
begin
if (Key = VK_RETURN) then
begin
num:= StrToInt(EdigNum.Text);
if (num < 1) or (num > 90) then
begin
ShowMessage('valore digitato NON ammesso');
EdigNum.Text:= '';
end
else
begin
esito:= carSist(EdigNum.Text); { carSist restituisce: 0 -se il numero digitato è nuovo nella serie
1,...,9 -se il numero già presente nella serie}
case esito of
0:
begin
for i:= 1 to 9 do
begin
if (tbSist[i] = 0) then
begin
EdigNum.Text:= '';
Break;
end;
end;
EdigNum.ReadOnly:= True;
// INSERIRE QUI la visualizzazione della riga "Sommatoria"
end
else
begin
msgInfo:= 'Numero immesso già presente' +
system.lineending + '-------- CORREGGI --------';
// ShowMessage('E R R O R E', msgInfo, mtCustom, [mrYes, 'SI', mrNo, 'NO', 'IsDefault'], '');
EdigNum.Text:= '';
end;
end;
end;
end;
end;
Il compilatore fornisce il seguente 1° messaggio di errore:
carnumgioca.pas(167,15) Error: Identifier not found "self"
No, la Tedit dalla quale prelevo il dato immesso non è un componente della serie di TEdit della Form411 (http://www.lazaruspascal.it/index.php?action=dlattach;topic=2389.0;attach=945)
Quelle si trovano dentro la frame GroupBox1 e sono quelle da valorizzzare di volta in volta con ciascun numero immesso, teoricamente, in maniera disordinata.
Quindi la mia istruzione di chiamata della function carSist:
esito:= carSist(EdigNum.Text);
non lavora sulla serie di Tedit, ma affida alla carSist di caricare il valore passato in detta serie.
Allora è opportuno che sia tale function a potere scansionare e valorizzare la Tedit corretta fra tutte le 9 TEdit della serie.
Ecco, ho appena indicato ciò che dovrei realizzare, ma, purtroppo, è proprio quello che non ho capito come fare per metterlo in pratica.
Spero di essere stato più chiaro questa volta.
Penso di avere risolto.
Ho spostato le mie istruzioni di caricamento nella serie di Tedit dentro un evento dell'oggetto TGroupBox contenente la serie, ed esattamente dentro l'evento OnDblClick, impostando anche un valore nella proprietà TGroupBax.GroupBox1.Tag, alla pressione del tasto |INVIO|. Ciò mi permette di riconoscere la natura della schedulazione dell'evento OnDblClick e non eseguire alcuna istruzione al suo interno, nel caso in cui venisse dato un doppio click sul mouse.
In questa maniera
l'istruzione
funziona benissimo e tutto il successivo lavoro di scansione della serie per il caricamento ordinato, nella serie, dei numeri immessi in successione disordinata funziona a meraviglia.
Riporto qui sotto per chiarezza le istruzioni interne alle procedure TForm411.EdigNumKeyDown, :TForm411.GroupBox1DblClick:
procedure TForm411.EdigNumKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
esito, i, num: Integer;
msgInfo: String;
begin
writeln('procedure TForm411.EdigNumKeyDown');
if (Key = VK_RETURN) then
begin
num:= StrToInt(EdigNum.Text);
if (num < 1) or (num > 90) then
begin
ShowMessage('valore digitato NON ammesso');
EdigNum.Text:= '';
end
else
begin
GroupBox1.Tag:= 13; // corrispondente al tasto |INVIO|-(CARRIAGE RETURN);
GroupBox1DblClick(GroupBox1);
GroupBox1.Tag:= 0;
if (EdigNum.Text <> '') then
ShowMessage('aggiornamento "Numeri delSistema"' +
System.lineending + 'NON RIUSCITO');
end;
end;
end;
procedure TForm411.GroupBox1DblClick(Sender: TObject);
var
indx: TComponent;
i, numCorr: Integer;
cambio, digit: String;
begin
writeln('procedure TForm411.GroupBox1DblClick');
digit:= EdigNum.Text;
for indx in self do
begin
if (indx is TEdit) and (indx.Tag = 1) then // indx.Tag è sstato impostato a 1 in tutta la serie durante il disegno nella Form
begin
case Length((indx as TEdit).Text) of
0:
begin
(indx as TEdit).Text:= digit;
EdigNum.Text:= '';
break;
end
else
begin
if ((indx as TEdit).Text = EdigNum.Text) then
begin
ShowMessage('valore digitato = DUPLICATO');
break;
end
else
begin
if ((indx as TEdit).Text > EdigNum.Text) then
begin
cambio:= (indx as TEdit).Text;
(indx as TEdit).Text:= digit;
digit:= cambio;
end;
end;
end;
end;
end;
end;
end;
Il codice non è ancora del tutto completo, ma già rende l'idea del risultato.
Grazie a tutti per l'aiuto.