- Da lontanissimi ricordi del pascal so che era possibile testare il valore di una sottostringa così : Stringa[2:3] = 'ABC'. Mi da errore in fase di compilazione. Esiste in maniera diversa da quella che ricordo o me lo sono inventato per facilitarmi la vita ? ;D
- Questa è un po più tosta. Ho parecchie form che sostanzialmente contengono gli stessi componenti e anzichè scrivere lo stesso codice di gestione per ognuna ho implementato un sistema generico sugli eventi e fin qui tutto bene. Il problema è che in alcuni casi vorrei che fosse eseguito anche del codice specifico (in sostanza una specie di eredietarietà a runtime). Sono riuscito a farlo sul componente Application e ho visto che c'è qualcosa anche per gli altri componenti su alcune proprietà / eventi ma non su tutti. C'è un sistema ?
Allengo parte del codice (con un minimo di commento) per rendere meglio l'idea :
// Richiamato dall'evento OnCreate di ogni form
procedure TFormMain.GenericCatchSettings(Sender: TObject);
var
N: Integer;
begin
with (TForm(Sender)) do
for N := $0 to Pred(ComponentCount) do
case (Components[N].ClassName) of
'TTrackBar': begin
TTrackBar(Components[N]).OnChange := @GenericTBChange;
end;
'TStaticText': begin
TStaticText(Components[N]).OnMouseDown := @GenericSTMouseDown;
TStaticText(Components[N]).OnMouseMove := @GenericSTMouseMove;
end;
end;
end;
// Per ogni componente static text cerco il rispettivo trackbar
procedure TFormMain.GenericSTMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
N, Delta: Integer;
MNewPos: TPoint;
TBName: string;
begin
if (Shift = [ssLeft]) then
begin
GetCursorPos(MNewPos);
Delta := (MNewPos.X - MOldPos.X) + (MNewPos.Y - MOldPos.Y);
MOldPos := MNewPos;
TBName := 'TB' + Copy(TStaticText(Sender).Name, $3, Length(TStaticText(Sender).Name) - $2);
with (TForm(TStaticText(Sender).Owner)) do
for N := $0 to Pred(ComponentCount) do
if (Components[N].Name = TBName) then
TTrackBar(Components[N]).Position := TTrackBar(Components[N]).Position + Delta;
end;
end;
procedure TFormMain.GenericSTMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
GetCursorPos(MOldPos);
end;
// Qui vorrei che fosse eseguito questo codice + quello eventualmente presente nel componente
procedure TFormMain.GenericTBChange(Sender: TObject);
var
STName: string;
N: Integer;
begin
STName := 'ST' + Copy(TTrackBar(Sender).Name, $3, Length(TTrackBar(Sender).Name) - $2);
with (TForm(TTrackBar(Sender).Owner)) do
for N := $0 to Pred(ComponentCount) do
if (Components[N].Name = STName) then
TStaticText(Components[N]).Caption := IntToStr(TTrackBar(Sender).Position);
end;
// Il codice da eseguire associato al componente TBProva
procedure TFormMain.TBProvaChange(Sender: TObject);
begin
ShowMessage('Prova');
end;
In pratica anzichè assegnare l'evento con Evento := @NomeProc non c'è una specie di AddHandleOn qualcosa ?
Per quanto riguarda il punto 1 puoi usare questo codice:
function EstraiStringa(StringaIn: string; Da: integer; A: integer): string;
var
i: integer;
ret: string;
begin
ret:='';
for i:=Da to A
ret:=ret + StringaIn[i];
EstraiStringa:=ret;
end;
Per il secondo problema devo fare delle ricerche!
Ho trovato come fare...cercando altro per giunta...vabbè (fortuna che lazarus è open source e si può spulciare nei sorgenti) :P
Il metodo più semplice è :
var
ExecShow: procedure of object;
TMethod(ExecShow).Data := TForm(Sender);
TMethod(ExecShow).Code := TForm(Sender).MethodAddress('FormShow');
if not (TMethod(ExecShow).Code = nil) then
ExecShow;
Questa è il codice da inserire nella parte generica. In questo caso l'evento è l'OnShow e la procedure che contiene il codice specifico si chiama FormShow (e deve chiamarsi allo stesso modo in tutti gli oggetti). Se non esiste semplicemente ritorna null e va oltre.
P.S.
Aggiungo che funziona solo con le procedure dichiarate published (probabilmente per le altre non viene salvato il nome e quindi ritorna null).
E' lo stesso metodo che utilizza l'IDE per importare le varie opzioni della schermata dell'ispettore degli oggetti ma dovrebbe anche essere il metodo di base con cui il free pascal richiama gli oggetti dato che è una proprietà della classe TObject (praticamente la prima classe da cui tutti ereditano qualcosa) quindi funziona su qualsiasi piattaforma e difficilmente può subire modifiche (è praticamente un pilastro della struttura). L'unico appunto è dichiarare la variabile con lo stesso prototipo della procedure, quindi nell'esempio ho sbagliato (apparentemente non da errore in realtà si brucia lentamente lo stack).
var
ExecShow: procedure (Sender: TObject) of object;
Questo è quello corretto e rispecchia l'evento OnShow.
Certo, è un modo a basso livello di utilizzare un linguaggio ad alto livello ma ha i vuoi vantaggi. Io l'ho trovato perchè stavo cercando un sistema per far eseguire il codice contenuto nell'OnShow anche quando la form era già visibile. Utilizzando Show o settando visibile a true non funzionava visto che non cambiava lo stato ed era una bella menata.