Newsgroup: it.comp.lang.delphi
Titolo: Access Violation anomalo in scambio dati tra Form e Frame

Ciao a tutti,
ho un problemino di access violation che non mi so spiegare anche
perchè appare all'esecuzione di un codice banale.
In pratica da una form devo passare un valore stringa a un frame
caricato nella form principale del programma.
Il codice è questo:
BeeperAdvPageFrame.EditDirectoryScan.Text :=
DirectoryListBox2.Directory;
Dove
BeeperAdvPageFrame.EditDirectoryScan.Text è il campo che si trova nel
frame (che si chiama appunto "BeeperAdvPageFrame") e
DirectoryListBox2.Directory è la stringa che prelevo e che devo
passare da form a frame.
Da cosa può dipendere?
Grazie mille

 Da cosa può dipendere?
In quale punto del programma (evento) avviene l'esecuzione del codice 
problematico? Siamo effettivamente sicuri che il Frame sia 
inizializzato? L'identificatore utilizzato per accedere al Frame dove si 
trova (dov'è dichiarato)?
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)


Ciao Alka,
dal frame contenuto nella form principale, all'evento OnClick di un
bottone viene eseguito questo codice:
  Form4 := TForm4.Create(nil);
  Form4.Visible := true;
  Form4.DirectoryListBox2.Directory := EditDirectoryScan.Text;
  MainForm.Enabled := false;
  MainForm.AlphaBlend := true;
  MainForm.AlphaBlendValue := 180;
Form4 è la form che contiene il componente DirectoryListBox2 con
l'elenco delle presenti in una cartella predefinita. Come vedi il
frame non viene modificato nè chiuso, semplicemente blocco il form
principale con enabled := false;
Può essere qui il problema? Cioè, se il form viene disabilitato non è
possibile accedere alle proprietà? Mi sembra strano.
Selezionando da Form4 la directory desiderata, si attiva un bottone
nel form che se cliccato esegue il codice:
procedure TForm4.ButtonOKClick(Sender: TObject);
begin
  BeeperAdvPageFrame.EditDirectoryScan.Text :=
DirectoryListBox2.Directory;
  Close();
end;
procedure TForm4.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MainForm.Enabled := true;
  MainForm.AlphaBlend := false;
end;
Grazie

Dimenticavo:
dal form principale, al Click di un bottone del menu viene eseguito
questo codice per creare il frame:
    // Carica il frame "Beeper"
    LoadPage(TBeeperPageFrame);
    FrameLoaded := 'TBeeperPageFrame';
    // Imposta a true la selezione del bottone cliccato
    remote.Down := false;
    race.Down := false;
    beeper.Down := true;
    settings.Down := false;
Mentre questa è la funzione LoadPage
procedure TMainForm.LoadPage(APageClass: TPageFrameClass);
begin
   // Verifica che il riferimento alla "metaclasse" sia valido
  if APageClass = nil then
    Exit;
  // Verifica che la pagina richiesta sia differente da quella attuale
  if FCurrentPage <> nil then
    if FCurrentPage.ClassType = APageClass then
      Exit;
  // Distrugge l'istanza della pagina esistente
  if FCurrentPage <> nil then
    FreeAndNil(FCurrentPage);
  // Crea un'istanza della pagina richiesta
  FCurrentPage := APageClass.Create(Self);
  try
    // Dispone la pagina all'interno del pannello contenitore
    FCurrentPage.Parent := PagePanel;
    // Forza la pagina ad occupare lo spazio disponibile
    FCurrentPage.Align := alClient;
  except
    // Distrugge la pagina in caso di errore imprevisto
    FreeAndNil(FCurrentPage);
    // Risolleva l'eccezione per consentire al gestore predefinito
    // di visualizzare il "classico" messaggio
    raise;
  end;
end;
Questo codice fa parte di un tuo progetto demo che avevo scaricato
tempo fa e che uso come base di partenza per alcune applicazioni.

 tempo fa e che uso come base di partenza per alcune applicazioni.
Sì, ma in questo caso non penso c'entri nulla, visto che da nessuna 
parte si fa riferimento all'identificatore "BeeperAdvPageFrame" con cui 
accedi al Frame.


 [...]
Ti ho fatto delle domande precise perché mi sono sorti sospetti ben 
precisi su quale potrebbe essere il problema.
E' ovvio che se tu segui la strada dei tuoi ragionamenti ed eviti di 
rispondere in modo preciso e puntuale alle domande che ti pongo, non ci 
salteremo mai fuori. :-)
Se ti chiedo come inizializzi una variabile, è inutile che tu mi 
fornisca la locazione del tuo progetto su disco fisso, no? ;-)


L'identificatore utilizzato per accedere al Frame dove si
trova (dov'è dichiarato)?
Se non ho capito male quello che mi chiedi, ho inserito il nome della
unit del frame BeeperPageFrame nelle uses del form Form4 in modo da
poterci accedere e avere uno scambio dati. Ho anche inserito la
CustomPageFrame nelle uses pensando che magari non aveva qualche
riferimento ma non è cambiato nulla.
Credo che alle altre domande ti abbia già risposto ma in caso
negativo, riformulami la domanda. Porta pazienza plz.

 riferimento ma non č cambiato nulla.
Capisco l'origine dei tuoi problemi (e l'avevo compresa bene a suo 
tempo, in altri luoghi): tu vai a caso. ;-)
Quale ragionamento logico ti ha portato ad inserire quel riferimento 
alla *uses*? Sai da cosa č determinato l'errore che ottieni?
Non puoi eludere il comprendere la causa del problema e andare per 
tentativi inserendo riferimento a questa o quell'altra unit sperando che 
l'applicazione vada a posto da sola.
Se a fronte di un problema non ti documenti su quale possa essere la 
causa *vera* e vaghi in preda ad intuizioni sbagliate, che sono tali 
proprio perché non conosci la causa del problema, non riuscirai mai ad 
uscirne vivo.
Riepilogando, tu hai appoggiato un Frame sul Form, quindi hai creato un 
oggetto di quel Frame e Delphi si č preoccupato di aggiungere un campo 
nella dichiarazione del Form, come avviene per qualsiasi altro 
componente, attraverso il quale puoi accedere dal Form al suddetto Frame 
e a tutti i controlli in esso contenuti. Usa quell'identificatore per 
manipolare le proprietŕ e i controlli del Frame.


Ciao Marco,
dalle tue parole mi era parso di capire che l'errore stava nel fatto
di aver copiato un frame e di averlo modificato con nuovi componenti
per cui l'access violation si riferiva al fatto che l'oggetto a cui
facevo riferimento in realtà era relativo a un altro frame che non era
inizializzato. Ho rifatto così il frame partendo da quello base e ho
ricreato tutti gli oggetti con relativi eventi. Fatto partire il debug
e il risultato è identico, sempre access violation. Suppongo di non
aver capito una mazza di quello che volevi dirmi. La procedura che ho
fatto è sempre la solita che uso e che non mi ha mai dato problemi per
cui..sono ancora più confuso.

 [...]
Non ho mai detto una cosa del genere.
La domanda che ti ho fatto inizialmente č semplice: dove č dichiarata la 
variabile che utilizzi per accedere all'oggetto Frame?


   (
http://www.marco.breveglieri.name
)
E' dichiarata nelle var globali della unit BeeperAdvanced
type
  TBeeperAdvancedPageFrame = class(TCustomPageFrame)
var
  BeeperAdvancedPageFrame: TBeeperAdvancedPageFrame; <----- Var
globale
Mentre nella form ho messo il nome della unit nelle uses in modo da
avere accesso all'oggetto.
E' questo che volevi sapere?

 E' questo che volevi sapere?
Sě. Quella variabile non va utilizzata in questo contesto: Delphi ne 
aggiunge una alla dichiarazione del Form quando inserisci il Frame al 
suo interno, selezionadolo dalla Palette dei Componenti (icone "Frame"): 
quella č la variabile da utilizzare, che fa riferimento all'istanza 
attiva sul Form.


   (
http://www.marco.breveglieri.name
)
Non ho capito. Come devo modificare il mio frame per renderlo corretto?

 Non ho capito. Come devo modificare il mio frame per renderlo corretto?
Ma il Frame a cui fai riferimento tramite la "famosa variabile" come 
viene inserito nel Form? Lo crei dinamicamente, tramite codice? Oppure 
lo hai appoggiato sul Form ospitante selezionandolo dalla Palette dei 
Componenti?



Lo creo dinamicamente tramite:



In pratica creo un frame sulla base di quello Customizzato, gli
inserisco i vari componenti visuali e poi lo carico da codice nel form
principale quando viene richiesto.

 principale quando viene richiesto.
In tal caso, è il campo "FCurrentPage" che contiene il riferimento al 
Frame visualizzato, assegnato con l'istruzione
   //...
   // Crea un'istanza della pagina richiesta
   FCurrentPage := APageClass.Create(Self);
   //...
ed è quella la variabile da utilizzare per fare riferimento all'oggetto, 
il Frame, che è stato mostrato sul Form.
Chiaramente, siccome la variabile non appartiene alla classe specifica 
del Frame ma ad una classe base, è necessario effettuare un "casting" 
quando ci si trova ad operare con il Frame in questione.
   if (FCurrentPage is TMySpecificFrame)
     TMySpecificFrame(FCurrentPage).SpecificProperty := ...;
In effetti, non conosco la problematica specifica ma, in genere, io 
evito di introdurre delle simili specializzazioni in un contenitore 
generico come il Form, rendendolo possibilmente agnostico per quanto 
riguarda le funzionalità peculiari delle pagine che vi carico all'interno.
Ciao,
   Marco.


MARCO SEI IL MIO EROE.
Era proprio quello l'errore, ora funziona alla perfezione!
GRAZIE!!!!!