problem z dynamicznym buttonem

0

Witam!

Mam komponent mniej wiecej taki :

type
TLog = class(TButton)
constructor Create(i : byte); virtual;
destructor Destroy; override;
end;

W ciele konstruktora zawieram kod, który ma tworzyć dynamicznie button:

Constructor TLog.Create(i : byte);
begin
inherited create(owner);
SetBounds(282,66,193,25);
Caption:='buton'+i;
case i of
1:
begin
Parent:=FormaGlowna;
end;
2:
Parent:=Forma2;
end;

Jak widać wywołanie konstruktora z parametrem 1 stworzy button na FormieGlownej, a z parametrem 2 na drugiej formie.
Problem w tym, że tworzy mi button tylko na FormieGlownej, a na drugiej nie chce. Sprawdzalem wartosc Visible ale to nie to. Może ktoś wie czemu nie działa?

pzodrawiam

0

oczywiście wywołuję w OnCreate FormyGlownej i Form2 :
TLog.Create(1); oraz TLog.Create(2);

0

Coś robisz nie tak, u mnie bez problemów działa, bo skoro kod jest prawidlowy
oraz jak należy użyty, to dlaczego by miało coś nie działać? Zobacz sam. Unit1:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, Unit3;

type
  TFormaGlowna = class(TForm)
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
  public
  end;

var
  FormaGlowna: TFormaGlowna;

implementation

uses
  Unit2;

{$R *.dfm}

procedure TFormaGlowna.FormCreate(Sender: TObject);
var
  A : TLog;
begin
  A := TLog.Create(1);
end;

procedure TFormaGlowna.BitBtn1Click(Sender: TObject);
begin
  Forma2.ShowModal;
end;

end.

Unit2:

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Unit3;

type
  TForma2 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
  public
  end;

var
  Forma2: TForma2;

implementation

{$R *.dfm}

procedure TForma2.FormCreate(Sender: TObject);
var
  A : TLog;
begin
  A := TLog.Create(2);
end;

end.

Unit3:

unit Unit3;

interface

uses
  StdCtrls, Classes;

type
  TLog = class(TButton)
    constructor Create(I : Byte); virtual;
  end;

implementation

uses
  Unit1, Unit2;

Constructor TLog.Create(I : Byte);
begin
  inherited create(Owner);
  SetBounds(282,66,193,25);
  Caption := 'Buton1';
  case I of
  1:
    Parent := FormaGlowna;
  2:
    Parent:=Forma2;
  end;
end;

end.
0

moim zdaniem powinno sie najpierw ustawic parenta a dopiero pozniej przypisywac wielkosc i pozycje...
a swoja droga... jakies dziwne rozwiazanie zeby na sztywno laczyc z formami... czy takich rzeczy jak forma nie powinno sie przekazywac do konstruktora jako parametr...?

0

dzięki za zainteresowanie - tylko, że jest małe "ale", otóż forma druga jest ładowana dynamicznie (w project options wyrzucilem ja z autocreate'a).
W kodzie FormyGlownej mam procedurke, ktora wywoluje Forme2(frmPrezentacja):

procedure TfrmOknoGlowne.btnPrezentacjaClick(Sender: TObject);
begin
PokazPrezentacje(Self); //odwolanie do funkcji w formie 2
end;

Natomiast w Formie 2 (frmPrezentacja) mam takie coś:

(...)

function PokazPrezentacje(AOwner: TComponent): TModalResult;

implementation

{$R *.dfm}

function PokazPrezentacje(AOwner: TComponent): TModalResult;
var
frmPrezentacja : TfrmPrezentacja;
begin
frmPrezentacja := TfrmPrezentacja.Create(AOwner);
try
with frmPrezentacja do begin
{w linijce poniżej odwoluje sie do komponentu}
TLog.Create(2)
Result := ShowModal;
end;
finally
FreeAndNil(frmPrezentacja);
end;
end;

no i lipa czy to coś zmienia, że frmPrezentacja jest ładowana dynamicznie? może coś z właścicielami się wtedy miesza, skoro button pokazuje mi się tylko w FormieGlownej (?)

pzodrawiam

0

ustawienie parenta najpierw nic nie zmienia - sprawdzalem

0

Nie wiem w czym masz problem. Tak tworzę dynamicznie przycisk na dynamicznej formatce i jest ok.

var
  Frm : TForm;
  Btn : TButton;
begin
  Frm := TForm.Create(Self);
  Btn := TButton.Create(Frm);
  Btn.Parent := Frm;
  Frm.ShowModal;
end;
0

no tym sposobem co napisałeś to też mi działa, tylko że moim mi nie działa, chociaż teoretycznie wszystko robie ok. kompilator nie zgłasza błędów, na głównej formie tworzy sie przyscisk OnShow, i jest tez na niej przycisk, ktory pokazuje Forme2. Klikam nań i button nie chce się pokazać moim sposobem. Zastanawia mnie, czy jakimś sposobem nie tworzy się jeszcze raz na formie głównej podczas pokazywania Formy2, albo gdzieś indziej ginie, bo program się kompiluje

0

chodzi o to, że chce użyć mojego kodu, ponieważ mam dużo dynamicznych form i chcę żeby na każdej z nich pojawiał się button. Pisanie kodu w zdarzeniu OnCreate kazdej formy byloby chyba malo profesjonalne wiec chce pisać tylko odnośnik do mojego komponentu(z parametrem), ktory by sie tym zajmował.

0

Witam,

Widzę tu dwa błędy:

  1. Konstruktor powinien wyglądać tak:
constructor Create(AOwner: TComponent; i : byte); overload;

...

constructor TLog.Create(AOwner: TComponent; i: byte);
begin
  inherited Create(AOwner);
  // cos dalej
end;

Twoje wywolanie inherited Create(Owner) nie ma sensu, gdyz odwlujesz sie do wlasciwosci Owner samego komponentu, ktora nie jest ustawiona i wynosi nil

  1. W konstruktorze odwloujesz sie do globalnych zmiennych zdefiniowanych w unitach. To jest bardzo powazny blad i dlatego, prawdopodobnie nie dziala Ci drugi przypadek.

Powinienes konstruktor przepisac nastepująco:

constructor Create(AOwner: TComponent; AParent: TWinControl; ACaption: TCaption); overload;

constructor TLog.Create(AOwner: TComponent; AParent: TWinControl;
  ACaption: TCaption);
begin
  inherited Create(AOwner);
  Parent := AParent;
  Caption := ACaption;
  SetBounds(282,66,193,25);
end;

Jak widzisz pozbylismy sie niepotrzebnego case'a. Za AParent podstawiasz obiekt ktory ma byc rodzicem Twojego przycisku, czyli np dowolna forme.

Obowiązkowa lektura: google -> decoupling

pozdrawiam.

0

Dzięki! Teraz działa jak trzeba.

Wywołuję w OnCreate tak:

(..)
var
cc: TLog;
begin
cc := TLog.Create(owner,Forma2,'JakisCaption');

lub (też działa):

cc := TLog.Create(nil,Forma2,'JakisCaption');

Mam jeszcze jedno małe pytanko - czy zwalnianiem tego zajmuje się Forma, do której jest przypisany button? Nie trzba już pisać: cc.Free; ?

pozdrawiam

0
neptune napisał(a)

Dzięki! Teraz działa jak trzeba.

Wywołuję w OnCreate tak:

(..)
var
cc: TLog;
begin
cc := TLog.Create(owner,Forma2,'JakisCaption');

lub (też działa):

cc := TLog.Create(nil,Forma2,'JakisCaption');

Mam jeszcze jedno małe pytanko - czy zwalnianiem tego zajmuje się Forma, do której jest przypisany button? Nie trzba już pisać: cc.Free; ?

pozdrawiam

Jesli wywlolasz pierwszym sposobem to przycisk zostanie zwolniony razem z obiektem Owner.
JEzeli wstawisz NIL to musisz napisac cc.free

Zeby przycisk byl zwolniony razm z forma2 to powinno byc wywolane tak:

cc := TLog.Create(Forma2,Forma2,<font color="blue">'JakisCaption'</font>);
0

Jeżeli dobrze rozumiem, z tego co napisałeś to metoda:

cc := TLog.Create(Forma2,Forma2,'JakisCaption');

..pozwoli na zwolnienie komponentu wraz z Forma2. To czy w takim wypadku nie potrzebny jest destructor komponentu??

1 użytkowników online, w tym zalogowanych: 0, gości: 1