Newsgroup: it.comp.lang.delphi
Titolo: Liberare Buffer tastiera x Distruzine Form

Mi sono accorto di questo:
 
se creo un form non modale ed associo un'evento per la distruzione ad un 
pulsante del form figlio, non ci sono problemi, al click sul pulsante, 
esegue Libera e distrugge il form figlio
 
-- Form2 chiamante : frm_Unit : TForm3
...
frm_unit3 := TForm3.Create(nil);
frm_unit3.Parent := Panel1;
frm_unit3.Align := alClient;
frm_unit3.act_Chiude.OnExecute := Libera;
frm_unit3.Show;
 
procedure TForm2.Libera(Sender: TObject);
begin
   FreeAndNil(frm_Unit3);
end;
 
-- Form3 figlio contiene un TButton ed un TEdit
procedure TForm3.act_ChiudeExecute(Sender: TObject);
begin
//
end;
 
se invece faccio la stessa operazione dal TEdit, esegue il FreeAndNil
ma torna sempre sul controllo TEdit generando eccezione, il form e' 
ormai distrutto, credo sia il Buffer di Tastiera da vuotare.
 
procedure TForm3.Edit1KeyPress(Sender: TObject; var Key: Char);
var Msg: TMsg;
begin
   if Key = #13 then
     begin
      Key := #0;
      // non da effetti di svuotamento, come se non ci fosse
      while PeekMessage(Msg, 0, WM_KEYFIRST, WM_KEYLAST,
         PM_REMOVE or PM_NOYIELD) do;
 
      //simula pressione Button
      Button1.Click;
     end;
---> torna qui <---
end;
 
Maurizio

 ormai distrutto, credo sia il Buffer di Tastiera da vuotare.
 
Le tue deduzioni sono corrette: stai distruggendo il padre di un 
controllo, dall'interno di un event handler del controllo stesso, per 
questo motivo hai l'access violation.
tuttaiva il buffer di tastiera non c'entra: quando invochi il 
button1.click, la CPU salta alla zona di memoria dove c'è il codice di 
gestione del click, lì dentro tu liberi le risorse stesse che hanno 
chiamato quella zona di memoria, di conseguenza, quando la CPU torna ad 
eseguire il codice che ha chiamato il click, si accorge che quella zona 
di memoria non è più allocata e chiaramente va in access violation.
 
 
La soluzione per mantenere l'"autodistruzione" consiste, invece di 
chiamare il button.click, di mandarti un messaggio a te stesso (cioè, il 
form figlio manda a sè stesso un messaggio di autodistruzione).
In questo modo la CPU finisce di eseguire il gestore di evento del tedit 
correttamente, poi il gestore di messaggi della finestra si accorge che 
c'è un messaggio da processare (quello di autodistruzione) e libera sè 
stesso dalla memoria.
 
Ho cercato di non usare termini tecnici e spero di averti dato una mano.
Per realizzare la tua soluzione documentati sul sendmessage.
 
 
 
-- 
morde
Android
QT 4.7
Delphi (5,6,7.. expired)
Firebird Database
 

Maurizio ha scritto:

Detto in maniera brutale:
se hai queste esigenze (svuotare il buffer della tastiera? peekmessage?), 
stai completamente sbagliando a progettare l'interfaccia utente. 
 
Riconsidera tutto prima di infognarti in simili rogne.
 
ACSH
 
 
-- 
 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it
 
 
 


la soluzione e' PostMessage, da inviare per distruggere il controllo attivo;
nel mio caso , quando viene premuto Enter, invio il Postmessage e dopo
posso attivare l'evento act_Chiude che sara' intercettato dal Form chiamate.
Cosi' non ho piu' access violation.
 
Maurizio
 
const
   WM_KILLCONTROL = WM_USER + 1;
 
type
   TForm3 = class(TForm)
     Edit1: TEdit;
     ActionList1: TActionList;
     act_Chiude: TAction;
     procedure Edit1KeyPress(Sender: TObject; var Key: Char);
     procedure act_ChiudeExecute(Sender: TObject);
 
   private
     { Private declarations }
     procedure KillControl(var message: TMessage); message WM_KILLCONTROL;
 
   public
     { Public declarations }
   end;
 
var
   Form3: TForm3;
 
implementation
 
{$R *.dfm}
 
procedure TForm3.act_ChiudeExecute(Sender: TObject);
begin
//
end;
 
procedure TForm3.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
   if Key = #13 then PostMessage(self.Handle, WM_KILLCONTROL, 0, 
integer(Edit1));
end;
 
procedure TForm3.KillControl(var message: TMessage);
var
   control: TControl;
begin
   control := TObject(message.LParam) as TControl;
   assert(control.Owner = self);
   control.Free;
   act_Chiude.Execute;
end;
 

 end;
 
Va bene, ma hai praticamente reimplementato il metodo release che esiste 
(credo) da delphi 1.