Kilka kopii tego samego formularza

0

Cześć,
Problem pewnie był już poruszany, ale nie umiem znaleźć odpowiedniego posta, dlatego zapytam.

Mam problem z otwieraniem kilku kopii tego samego formularza, a właściwie istota problemu polega na odpowiedniej deklaracji procedury w tej formatce.
Przykładowo:

procedure Address2Enable(Enable : Boolean);
begin
   CDataForm.CAddress2StreetTBox.Enabled:=Enable;
  CDataForm.CAddress2BNumberTBox.Enabled:=Enable;
  CDataForm.CAddress2AnumberTBox.Enabled:=Enable;
  CDataForm.CAddress2TownTBox.Enabled:=Enable;
  CDataForm.CAddress2PostalTBox.Enabled:=Enable;
  CDataForm.CAddress2DistrTBox.Enabled:=Enable;
  CDataForm.CAddress2VoiTBox.Enabled:=Enable;
  CDataForm.CAddress2CountryTBox.Enabled:=Enable;
end;

Procedura ma za zadanie umożliwienia/uniemożliwienia edycji danych teleadresowych po kliknięciu przycisku.
Więc problem polega na tym, że gdy nie wpiszę "CDataForm"(nazwa formularza), to kompilator wyrzuca, że EditBoxy są niezdefiniowane.
Gdy utworzę dynamicznie kopię tego formularza procedura (na przykład dla innego klienta) działa tylko na jej oryginalnej wersji z wiadomych przyczyn.
Jak napisać kod procedury, żeby obsługiwał aktualnie otwartą formatkę? Kombinowałem z Self, ale doszedłem do tego, że nie działa to w ten sposób.
Z Delphi jestem zielony i dopiero się uczę. Proszę o wyrozumiałość.

Pozdrawiam.

0

Ja tu widzę miejsce na aplikację MDI i dynamiczne tworzenie okien potomnych.
Aplikacje takie mają zastosowanie gdy źródłem danych jest baza. Tworząc takie okno edycyjne, przekazuję do niego także id rekordu którego dane są w nim edytowane. Na koniec zatwierdzając dane w oknie potomnym korzystam właśnie z tego id rekordu.
Inna sprawa to wielodostęp do tych samych danych, ale chyba tym się na razie nie przejmujesz. W każdym razie stwarza to jednak pewne problemy.

0

Cześć, dzięki za odpowiedź, ale niestety MDI tutaj nie wchodzi w grę, formularz będzie otwierany w innym miejscu i do innego celu, niż ten oryginalny.

Poza tym mam wrażenie, że MDI i tak nie rozwiąże mojego problemu. Nie ma sposobu na napisanie procedury, czy funkcji w taki sposób jak opisałem wyżej? Bez konieczności podawania nazwy formularza/lub przekazania tej nazwy w inny sposób? Chodzi o to, żeby procedura korzystała z tej kopii formy, która aktualnie jest otwarta?

Formatka ma za zadanie wyświetlenie danych klienta, edycję ich lub dodanie nowego klienta, w zależności od trybu, jaki będzie potrzebny. Bezpośrednio z tego formularza będzie można przejść do dodawania pojazdów, których klient jest właścicielem i tutaj potrzebuję drugi formularz, gdyż z formularza dodawania pojazdu można dodać osobę, która będzie współwłaścicielem. Nie chcę tworzyć dwóch identycznych formularzy, tylko chciałbym operować na dwóch kopiach tego samego.

Edit:
Przyszło mi teraz do głowy, żeby przekazać do procedury wskaźnik do formy, którą obsługuję. Czy to dobry pomysł?

0
uses
  Unit2;

procedure Tmain.btnnowyClick(Sender: TObject);
var
  mojaForma: TTestCzas;
begin
  mojaForma := TTestCzas.Create(main);
  mojaForma.Show;
  mojaForma.edtczas.Text := DateTimeToStr(Now);
end;

takie utworzenie formy mojaForma := TTestCzas.Create(main) z argumentem o nazwie formy wywołującej powoduje że zamknięcie formy main zwalnia zasoby po formie tworzonej dynamicznie.

1
danijel napisał(a):

Poza tym mam wrażenie, że MDI i tak nie rozwiąże mojego problemu. Nie ma sposobu na napisanie procedury, czy funkcji w taki sposób jak opisałem wyżej? Bez konieczności podawania nazwy formularza/lub przekazania tej nazwy w inny sposób? Chodzi o to, żeby procedura korzystała z tej kopii formy, która aktualnie jest otwarta?

Więc w jaki sposób magicznie metoda ma wiedzieć do jakiego okna się odnieść? Jakoś musisz ją przekazać ;) Można użyć metody FindWindow. Jednak ani to eleganckie, ani sensowne. Naturalnym wydaje się być przekazanie do metody wskaźnika do okna na którym ma ona pracować.

danijel napisał(a):

Edit:
Przyszło mi teraz do głowy, żeby przekazać do procedury wskaźnik do formy, którą obsługuję. Czy to dobry pomysł?

Tak to jest rozwiązanie najlepsze.

0
Mr.YaHooo napisał(a):
danijel napisał(a):

Edit:
Przyszło mi teraz do głowy, żeby przekazać do procedury wskaźnik do formy, którą obsługuję. Czy to dobry pomysł?

Tak to jest rozwiązanie najlepsze.

Mógłbyś mi jeszcze podpowiedzieć jak wyciągnąć wskaźnik z aktualnie otwartej formy? Czy trzeba go jakoś przekazać np w konstruktorze?
Apropos konstruktora, gdy stworzę własny konstruktor z parametrami to nie jest wykonywany konstruktor główny (bezparametrowy). Czy jest możliwość odpalenia najpierw konstruktora głównego, a potem mojego? Wiem, że w C# jest taka możliwość przy przeciążaniu konstruktorów, ale w Delphi jeszcze do tego nie doszedłem.

0
MyForm:=TMyForm.create(..);
MyProcedure(MyForm);



0

To się wydaje oczywiste, ale MyForm znajduje się w innym formularzu niż MyProcedure. MyForm musiałby być zmienną globalną w takim wypadku. Dlatego pytałem o przekazanie wskaźnika przez kreator lub wyciągnięcia wskaźnika z aktualnie otwartej formy.

1
danijel napisał(a):

Kombinowałem z Self, ale doszedłem do tego, że nie działa to w ten sposób.

Self to pierwsza rzecz jaka mi przyszła do głowy. Dlaczego nie zadziałało?

Poza tym Address2Enable umieść jako procedure w klasie formularza i wtedy będziesz mógł ją wywołać po utworzeniu nowego formularza właśnie z Self.

NowyFormularz.Address2Enable(true);
0

Bo źle go używałem, nie widzi Self w napisanych przeze mnie procedurach (undeclarated idnetifier), ale rozgryzłem chyba to, gdybyś mógł ocenić to rozwiązanie i powiedzieć, czy nie zabije mi później programu ;)
Teraz procedurę wywołuję tak:

 Address2Enable(Mode, Self);
procedure Address2Enable(Enable : Boolean; Form :TCDataForm);
begin
Form.CAddress2StreetTBox.Enabled:=Enable;
....
end;

Wygląda na to, że od początku miałem dobre rozwiązanie gdzieś z tyłu głowy, ale źle go używałem.

3

Wygląda spoko i pewnie będzie działać.

Ja raczej bym zrobił w klasie formularza dodatkową procedurę i ustawił ją jako public. Wtedy nie musisz mieć jakieś dodatkowej z kosmosu tylko odnosisz się bezpośrednio do formularza.

procedure TCDataForm.Address2Enable(Enable : Boolean);
begin
Self.CAddress2StreetTBox.Enabled:=Enable;
end;

i potem tylko

var
okno:TCDataForm;
begin
(...)
okno.Address2Enable(true);

Ale Twoje rozwiązanie pewnie też będzie działać. Nie wiem, które rozwiązanie byłoby lepsze i zgodne z dobrymi praktykami ;) Musiałby się wypowiedzieć ktoś bardziej doświadczony.

0

Dzięki :) Popróbuję też Twoim sposobem.

Póki co Delphi jest dla mnie bardzo nieintuicyjne i jeszcze się gubię. Cóż, trzeba się rozwijać ;)

0
karpov napisał(a):

Ale Twoje rozwiązanie pewnie też będzie działać. Nie wiem, które rozwiązanie byłoby lepsze i zgodne z dobrymi praktykami ;) Musiałby się wypowiedzieć ktoś bardziej doświadczony.

Oczywiście, że wystawienie procedury w sekcji public formularza będzie lepszą praktyką niż bezpośrednie odnoszenie się do kontrolek na formatce. Załóżmy, że w paru miejscach będziemy chcieli ukrywać/pokazywać kontrolki adresu. Wtedy będzie trzeba w paru miejscach duplikować kod, a jak wiadomo to jest zuo :)

0

Niby dlaczego? Za każdym razem odpalam procedurę wywołując ją normalnie, bez duplikowania kodu. Nie robię tego "z zewnątrz", jeśli o to chodzi, bo nie ma takiej potrzeby.

0

@danijel, ale jakbyś chciał ukrywać/pokazywać kontrolki z paru miejsc to byś musiał duplikować kod. Co więcej, ubranie tego w nową funkcję skraca kod i poprawia jego czytelność. Łatwiej się czyta wywołania funkcji niż ukrywanie czy pokazywanie 10 editów.

0

Albo jestem niewyobrażalnie tępy i nie potrafię zrozumieć o co Ci chodzi, albo ciągle mówimy o tym samym. Procedura jest napisana raz. Nie korzystam z niej poza formularzem, a wywoływana jest kilka razy w zależności od potrzeby, m.in. w zdarzeniu onCreate, po kliknięciu checkboxa, a nawet przy działaniu innej funkcji. Za każdym razem wywoływana jedną komendą, a nie duplikowaniem kodu.
Aż tak kiepski nie jestem, żeby za każdym razem pisać 10 linijek kodu, żeby aktywować kilka editów :D

0

Nie mniej jednak wydaje się, że umieszczenie tego w klasie formularza jest lepszym rozwiązaniem ;)

2

@karpov, @danijel
jeśli procedura działa wyłącznie na polach klasy to najsensowniejsze jest umieszczenie jej w kodzie klasy

0

Dziękuję wszystkim za podpowiedzi :) Pozdrawiam

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