Newsgroup: it.comp.lang.delphi
Titolo: D7E : errore "control has no parnet window" utilizzando frame ereditati

>         WndParent := TWinControl(Owner).Handle
ed è come se non riuscisse a leggere correttamente il dfm del frame
che mi serve.
Ma quello che mi fa ...zzzare è che il primo lo crea senza alcun
problema.
Poi, ho fatto un altro test...
In TFrameBaseEdit era presente un pagecontrol, che dovrebbe poi essere
popolato dai discendenti.
L'ho rimosso e ho ricompilato il tutto e magicamente va...
Allora l'ho messo nel discendente che devo istanziare e andava cmq in
errore.
Alla fine l'ho lasciato, rimuvendo l'unico tabsheet che aveva e
funziona.
Allora ho rimesso il pagecontrol su TFrameBaseEdit senza nessun
tabsheet.
Poi nel discendente ho messo dei componenti visuali creati da me
ereditati da alcuni dei developer express e tutto funziona alla grande.
Giusto x concludere, tengo a sottolineare che:
1) non ho fumato niente di strano (io non ho mai fumato nulla in vita
mia...)
2) non ho bevuto
Prima che finisca alla neuro qualcuno mi sa dare una dritta?
Intanto ovviamente cerco ancora con google e vedo se trovo qualcosa...
Pax vobiscum.
A.

Ho messo da parte il problema per tutto il giorno e l'ho riaffrontato
poco fa, risolvendolo.
Posto qui un workaround in modo da evitare ad altri il seccarsi la
lingua a causa delle numerose parolacce..
Praticamente, il casino si scatena se un frame contiene dei componenti
che contengono a loro volta altri componenti, come il pagecontrol, ma
anche un tpanel nel quale si mette qualsiasi cosa.
Il tutto è dovuto al fatto che il frame non ha il parent e puo averlo
solo dopo che è stato creato.
Ma ovviamente alla creazione lui tenta di usare i costruttori dei
componenti che contiene e non avendo il parent questi costruttori vanno
in crash.
Ovviamente, anche utilizzando un costruttore proprio la cosa non cambia
visto che x ovvi motivi nel 99% dei casi la prima riga è inherited
Create(AOwner)...
Il workaoround consiste nel creare un override del metodo CreateWnd da
dichiarare nella sezione protected per non incorrere nel warning di
diverso livello di visibilita.
Il codice è semplicissimo:
protected
  procedure CreateWnd; override;
...
implementation
procedure TframeBaseEdit.CreateWnd;
begin
  x := TWinControl(Owner);
  if Assigned(Owner) then
    Self.Parent := TWinControl(Owner);
  inherited;
end;
Ribadisco che si tratta di un workaround...
Se qlc ha una soluzione migliore e la pubblica qui (davanti alla quale
la mia sembra molto lassativa e cinofallica...) ovviamente la butto
via.
Pax vobiscum.
A.
"Mentre 'a mmare e' 'nfosa, l'acqua..."

 anche un tpanel nel quale si mette qualsiasi cosa. [...]
Ma questo problema è sistematico, oppure è legato anche a qualche 
condizione particolare?
Lo dico perché sulle versioni successive alla 7 non si verifica, ma 
anche nella versione 7 mi pare di non aver mai incontrato nulla del 
genere. :-|
Hai una serie di step riproducibili che conducano al problema, partendo 
da un progetto vuoto? Basta prendere un Frame, inserire un PageControl 
ed ereditarlo per ottenere l'eccezione quando il discendente viene creato?
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)
     Non hai la possibilità di scaricare Turbo Delphi Explorer?
     Te lo spedisco io!! [
http://www.marco.breveglieri.name/?p=48
]

 ed ereditarlo per ottenere l'eccezione quando il discendente viene creato?
Giusto Marco!
Azz, ho trascurato un dettaglio molto importante.
Chiedo venia ma sono talmente preso da questa fottuta scadenza che ho
che non ho avuto tempo di fare un test ulteriore.. ok, l'ho appena
fatto.
Ho simulato una situazione analoga in un progetto normale (exe win32) e
la cosa non si verifica.
Il problema io l'ho avuto in un com...
Tiro a indovinare...
Se sei in un exe normale, forse la cosa viene risolta tramite la
TApplication...
Ma se sei in una dll e non esiste una TApplication, si incazza..
Bye
A.

 Ma se sei in una dll e non esiste una TApplication, si incazza..
Se includi la unit /Forms/ in una DLL, anche in quel caso hai un oggetto 
di *TApplication* a disposizione, ma è diversa da quella dell'eseguibile.
Se si tratta di un oggetto COM (controllo ActiveX?), è possibile che 
qualcosa tenti di aggiornare o passare il focus ad un controllo non pronto.
Ad ogni modo, se non parliamo di una classica "VCL Application", ci sono 
già molte più variabili del problema da prendere in considerazione e 
dovresti descrivere accuratamente l'architettura dell'applicazione per 
capirne qualcosa di più e poter fare prove autonomamente. :-|


Adesso ho qualche minuto e cerco di esporre meglio la cosa.
Ho un activex library che contiene alcuni com (automation object) un
form e alcuni frames.
Questo form ha 2 pannelli nei quali vengono visualizzati i frames.
Questi frames sono polimorfici...ho un frame "radice" dal quale
ereditano 2 diversi frame:
1) lista, che contiene una griglia
2) edit, che contiene un pagecontrol con dentro dei componenti visuali
non dbaware.
Nota, questi controlli li ho creati io ereditando da alcuni editor dei
developer express.
Sul form ho un treeview.
Ad ogni nodo è associato un oggettino che contiene le info necessarie
a visualizzare (ed istanziare ove necessario) i frames da creare, una
cosa simile a questa;
  TFrameItem = class
  private
    FListFrameClass: TframeBaseListClass;
    FEditFrameClass: TframeBaseEditClass;
    FDataManager: IDataManager;
    FSender: TComponent;
    FId: integer;
    FListFrame: TframeBaseList;
    FEditFrame: TframeBaseEdit;
    function Disable(): integer;
  protected
  public
    constructor Create(
      const AID: integer;
      ASender: TComponent;
      ADataManager: IDataManager;
      AListFrameClass: TframeBaseListClass;
      AEditFrameClass: TframeBaseEditClass);
    destructor Destroy; override;
    function Enable(AForm: TForm; AGridPanel, AEditPanel: Tpanel):
integer;
  published
    property ID: integer read FId;
  end;
Esiste poi una classe collection che contiene questi items:
  TFrameManager = class
  private
  public
    constructor Create(
      AForm: TForm;
      AGridPanel: TPanel; AEditPanel: TPanel);
    destructor Destroy; override;
    function SwithcTo(const AId: integer): integer;
    function AddFrameItem(
      const AID: integer;
      ASender: TComponent;
      ACollectionManager: IBaseCollectionManager;
      AListFrameClass: TframeBaseListClass;
      AEditFrameClass: TframeBaseEditClass): integer;
  end;
Quando clicco su un ramo, leggo un ID e lo passo al metodo switch:
var
  NewItem: TFrameItem;
begin
  Result := -1;
  if Assigned(FActiveItem) and (FActiveItem.Id = AId) then
    exit;
  NewItem := FList.FindById(AId);
  if Assigned(NewItem) then
  begin
    if Assigned(FActiveItem) then
      FActiveItem.Disable;
    NewItem.Enable(FForm, FGridPanel, FEditPanel);
    FActiveItem := NewItem;
    Result := 0;
  end;
end;
Il metodo enable per prima cosa istanzia i frames qualora non lo
fossero gia e poi li associa ai corrispondenti pannelli:
function TFrameItem.Enable(
  AForm: TForm;
  AGridPanel, AEditPanel: Tpanel): integer;
  Result := -1;
  if Not Assigned(Self.FListFrame) then
  begin
    Self.FEditFrame := FEditFrameClass.Create(AEditPanel);
 
Self.FEditFrame.Name
 := '';
    Self.FEditFrame.Visible := False;
    Self.FEditFrame.Align := alClient;
    Self.FListFrame := FListFrameClass.Create(AGridPanel);
 
Self.FListFrame.Name
 := '';
    AGridPanel.Width := Self.FListFrame.Width + 10;
    Self.FListFrame.editFrame := Self.FEditFrame;
    Self.FListFrame.Align := alClient;
  end;
  Self.FEditFrame.Parent := AEditPanel;
  Self.FListFrame.Parent := AgridPanel;
  Result := 0;
Sintetizzando:
in un exe, funziona tutto.
Nella mia activex library, invece se il frame contiene uno dei seguenti
controlli standard:
pagecontrol
tabcontrol
combobox
listbox
radiogroup
se questi non ha items, tutto ok ma basta che almeno uno di essi abbia
un solo item che viene fuori l'errore.
Altro test...
Ho aggiunto alla libreria un form vuoto e ho provato a metterci il
frame incriminato a design time dopo aver aggiunto un item al
pagecontrol. Nessun problema.
Tutto questo facendo un test con le cose gia pronte fatte da me.
Ho provato a vedere quale è l'ancestor + "basso" in comune tra questi
controlli ma è sempre TWinControl.
Da li in la gerarchia si ramifica.
appena ho 2 secondi faccio un test con un progetto creato apposta.
Sono sotto rilascio e ho a stento il tempo di respirare.
A.