Przejście pomiędzy formami w różnych klasach

0

Mam jedną klasę główną i dwie dziedziczące po niej. W konstruktorze klas dziedziczących wywołuję procedurę z głównej klasy tworzącą nową formę i wyświetlam ją jako ShowModal. Po kliknięciu odpowiedniego przycisku forma ta ma się zamknąć, a stworzona ma zostać nowa. Próbowałem to zrobić na dwa sposoby, ale nie udało mi się ani tak ani tak.

  1. Procedurę tworzącą dodatkową formę umieściłem w klasie bazowej. Dzięki temu wywołuję ją jeszcze przed zamknięciem poprzedniej formy i wszystko wygląda płynnie. Niestety w ten sposób nie wiem jak odnieść się do procedur umieszczonych w klasach dziedziczących o ile jest to możliwe.
  2. Procedurę tworzącą dodatkową formę umieściłem w klasach dziedziczących. Dzięki temu mogę się łatwo odnieść do procedur wewnątrz klasy. Problem jest taki, że żeby wywołać tą procedurę, najpierw muszę zamknąć poprzednią formę, przez co jest widoczny przeskok, zanim otworzy się nowa forma. Co więcej kod procedury tworzącej dodatkową formę mimo, że taki sam muszę wstawić do każdej klasy dziedziczącej.
    Bardziej odpowiednie wydaje mi się to pierwsze rozwiązanie. Tyle tylko, że decydując się na nie, nie jestem w stanie uruchomić odpowiednich procedur.

Kod napisałem na szybko, może i nieodpowiednie nazwy, ale to tylko tak poglądowo żeby pokazać o co mi chodzi. Po kliknięciu dalej na czerwonym tle pojawia się przez chwilę główna forma z żółtym tłem, a chciałbym, żeby od razu pokazała się Forma dodatkowa z białym tłem.

 
unit Unit1;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, DateUtils, Math, Variants, Grids, Windows,
  LMessages;

type
  TKlasaBazowa = class(TPersistent)
  private
    FormaBazowa: TForm;
    PrzyciskDalej: TPanel;
    procedure TworzFormeBazowa;
    procedure PrzyciskDalejClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent);
  end;

  TKlasaDodatkowa = class(TKlasaBazowa)
  private
    FNumerProcedury: Integer;
    FormaDodatkowa: TForm;
    PrzyciskDalej: TPanel;
    procedure Procedura1;
    procedure Procedura2;
    procedure Procedura3;
    procedure TworzFormeDodatkowa;
    procedure PrzyciskDalejClick(Sender: TObject);
  public
    constructor CreateB(AOwner: TComponent; Index: Integer);
  end;

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
    Komponent: TKlasaDodatkowa;
    Przycisk: TPanel;
    procedure PrzyciskClick(Sender: TObject);
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  with Form1 do
  begin
    Left := 0;
    Top := 0;
    Width := Screen.Width;
    Height := Screen.Height;
    Hide;
    BorderStyle := bsNone;
    Color := clYellow;
    Caption := 'Forma Glowa';
  end;

  Przycisk := TPanel.Create(Form1);
  with Przycisk do
  begin
    Parent := Form1;
    Left := 0;
    Top := 0;
    Width := 100;
    Height := 50;
    Color := clBlue;
    Caption := 'Przycisk';
    BevelOuter := bvNone;
    Cursor := crHandPoint;
    OnClick := PrzyciskClick;
  end;
end;

procedure TForm1.PrzyciskClick(Sender: TObject);
begin
  Komponent := TKlasaDodatkowa.CreateB(Form1, 10);
end;

constructor TKlasaBazowa.Create(AOwner: TComponent);
begin
  inherited Create;
end;

procedure TKlasaBazowa.TworzFormeBazowa;
begin
  FormaBazowa := TForm.Create(Application);
  with FormaBazowa do
  begin
    Left := 0;
    Top := 0;
    Width := Screen.Width;
    Height := Screen.Height;
    Hide;
    BorderStyle := bsNone;
    Color := clRed;
    Caption := 'Forma Bazowa';
  end;

  PrzyciskDalej := TPanel.Create(FormaBazowa);
  with PrzyciskDalej do
  begin
    Parent := FormaBazowa;
    Left := 0;
    Top := 0;
    Width := 100;
    Height := 50;
    BevelOuter := bvNone;
    Cursor := crHandPoint;
    Caption := 'Dalej';
    onClick := PrzyciskDalejClick;
  end;
end;

procedure TKlasaBazowa.PrzyciskDalejClick(Sender: TObject);
begin
  FormaBazowa.Close;
end;

constructor TKlasaDodatkowa.CreateB(AOwner: TComponent; Index: Integer);
begin
  inherited Create(AOwner);
  TworzFormeBazowa;
  FormaBazowa.ShowModal;
  TworzFormeDodatkowa;
  FormaDodatkowa.Show;

  if Index mod 2 = 1 then
    Procedura1
  else
    Procedura2;
end;

procedure TKlasaDodatkowa.TworzFormeDodatkowa;
begin
  FormaDodatkowa := TForm.Create(Application);
  with FormaDodatkowa do
  begin
    Left := 0;
    Top := 0;
    Width := Screen.Width;
    Height := Screen.Height;
    Hide;
    BorderStyle := bsNone;
    Color := clWhite;
    Caption := 'Forma Dodatkowa';
  end;

  PrzyciskDalej := TPanel.Create(FormaDodatkowa);
  with PrzyciskDalej do
  begin
    Parent := FormaDodatkowa;
    Left := 0;
    Top := 0;
    Width := 100;
    Height := 50;
    BevelOuter := bvNone;
    Cursor := crHandPoint;
    Caption := 'Dalej';
    onClick := PrzyciskDalejClick;
  end;
end;

procedure TKlasaDodatkowa.PrzyciskDalejClick(Sender: TObject);
begin
  if FNumerProcedury = 1 then
    Procedura2
  else
    Procedura3;
end;

procedure TKlasaDodatkowa.Procedura1;
begin
  FNumerProcedury := 1;
end;

procedure TKlasaDodatkowa.Procedura2;
begin
  FNumerProcedury := 2;
  ShowMessage('Procedura 2');
end;

procedure TKlasaDodatkowa.Procedura3;
begin
  FNumerProcedury := 3;
  Application.Terminate;
end;

end.

0

Lepiej by było, gdybyś napisał co potrzebujesz zrobić, zamiast pisać o tym co już masz; Ten kod nie jest dobry i ciężko zrozumieć o co w nim chodzi; Utwórz jakiś prosty projekt, przedstawiający Twój problem i napisz po prostu co jest źle i jak ma to wyglądać, aby było dobrze.

0

Właśnie to jest ten prosty projekt przedstawiający problem. Umieściłem w tym kodzie tylko to co jest potrzebne. Po uruchomieniu programu jest tworzony przycisk. Po jego kliknięciu tworzy się zmienna typu TKlasaDodatkowa. W konstruktorze tej klasy inicjuje procedurę zawarta w klasie bazowej która tworzy nowa formę wraz z przyciskiem. Aby przejść dalej konieczne jest kliknięcie tego przycisku. Wtedy tworzona jest kolejna forma w procedurze zawartej już w odpowiedniej klasie. W sumie na tym można by było zakończyć, problem jest taki ze nir wiem co zrobić żeby jie było teho migniecia między zamknięcie jednej formy a otworzeniem drugiej. Może z kodu to wynika ale pp skomplikowaniu go, zauważysz o co chodzi.

0

Znów zrobiłeś ten sam błąd: opisałeś to co Ty wymyśliłeś, aby rozwiązać swój podstawowy problem, lecz tego podstawowego problemu nie opisałeś.

Z Twoich słów wynika, że chcesz zrobić formę, która po kliknięciu przycisku będzie się natychmiastowo przekształcać w drugą, tak? W takim wypadku wykorzystaj TTabControl (mam nadzieję, że nie pomyliłem nazwy, ale dawno nie wykorzystywałem VCL/LCL :P).

0

I dobrze by było, gdybyś te formy tworzył liniowo, czyli tak:

+ MAIN
  - FIRST SUB
  - SECOND SUB

a nie przez zagnieżdżanie:

+ MAIN
  + FIRST SUB
    - SECOND SUB
0

Chodzi też o to ze konieczne jest użycie showmodal. Żeby dopiero po kliknięciu przycisku pierwszej formy tworzyła się druga. Showmodal dlatego bo są dalsze instrukcje które muszą się wykonać dopiero po zamknięciu. Nie znam innego sposobu żeby zatrzymać wykonywanie instrukcji w procedurze aż do jakiegoś działania w ttm przypadku na nowo utworzonej formie.

A gdzie jest problem to nie wiem. Chciałbym uzyskać taki efekt jak jest po skomplikowaniu teho kodu tyle że bez przeskoku między tworzeniem i zamknięciem odpowiednich form. Pp prostu nie wiem jak to zrovic.

0

No dobrze, ShowModal jest do tego potrzebne, ale nie rozumiem po co te dodatkowe klasy dziedziczące po TPersistent i ogólnie po co tyle tego zagmatwanego kodu;

Wystarczy, że w zdarzeniu OnClick przycisku główneg okna, najpierw utworzysz pierwsze okno i wyświetlisz je za pomocą ShowModal, a następnie utworzysz drugi formularz i wyświetlisz go tuż po (np. za pomocą ShowModal, o ile znów trzeba zablokować główne okno i czekać na zamknięcie tego drugiego okna-dziecka);

Sam zamysł jest jak najbardziej poprawny, jednak wykonanie pozostawia wiele do życzenia; Dlatego też razem z @Patryk27 zasugerowaliśmy, abyś napisał co potrzebujesz zrobić, a nie jak naprawić Twój kod;

Chciałbym uzyskać taki efekt jak jest po skomplikowaniu teho kodu tyle że bez przeskoku między tworzeniem i zamknięciem odpowiednich form.

A jak mamy skompilować ten kod, skoro nie dałeś do niego pełnych źródeł? :]

0

Te klasy są dlatego że to jest wersja uproszczona. Klas dziedziczacych po TKlasaBazowa jest kilka. Tutsj nie ma wszystkich metod które mam w głównym kodzie. A ten uprosiclem tak, żeby po prostu pokazać co chciałbym poprawić.

Jeśli wyświetle pierwsza formę show modal, a później druga w ten sam sposób w tym samym zdarzeniu onClick to będzie tak samo jak jest teraz. Pierwsza forma zniknie, pojawi się na chwilę forma główna i dopiero zostanie utworzona kolejna. Wydaje mi się ze ta kolejna forma powinna zostać wyświetlona, zanim pierwsza zostanie zamknięta. Problem tylko ze procedurę wyświetlająca ta druga formę mam w klasie podrzednej. Oczywiście mogę ją przenieść do klasy bazowej co byłoby korzystne dla mjie, tylko wtedy nie będę mógł się odniesc do procedur umieszczonych w klasie podrzednej. Ale to już pisałem. Cel jest taki: po naciśnięciu przycisku otwiera się forma jako showmodal, pp kliknięciu w przycisk na niej otwiera się kolejna forma, po kliknięciu w przycisk na niej wykonywana jest procedura z klasy podrzednej.

Kod jest napisany tak ze wystarczyło by otworzyć nowy czysty projekt i wkleić kod. Ale jeśli trzeba to wstawię jutro wszysykie pliki.

0

Hmm... tworzony w ten sposób formularz nie otrzymuje uchwytu - taka buła w LCL :]

procedure TMainForm.CShowFormsClick(Sender: TObject);
begin
  FSubForm1 := TForm.Create(MainForm);
  try
    FSubForm1.HandleNeeded(); // tu żebrzemy o uchwyt

    FSubForm1.BoundsRect := Rect(0, 0, 300, 300);
    FSubForm1.Position := poOwnerFormCenter;
    FSubForm1.Caption := 'SubForm1';

    FSubForm1.ShowModal();
  finally
    FSubForm1.Free();
  end;

  FSubForm2 := TForm.Create(MainForm);
  try
    FSubForm2.HandleNeeded();  // tu żebrzemy o uchwyt

    FSubForm2.BoundsRect := Rect(0, 0, 400, 300);
    FSubForm2.Position := poOwnerFormCenter;
    FSubForm2.Caption := 'SubForm2';

    FSubForm2.ShowModal();
  finally
    FSubForm2.Free();
  end;
end;

Tak więc wywołanie metody HandleNeeded[#]_ jest konieczne, bo inaczej ten dynamiczny formularz delikatnie pisząc głupieje i nie potrafi utrzymać fokusa, więc i modalne wywołanie nie działa poprawnie; Nie wiem czy to bug czy feature - w razie czego można to zgłosić lub po prostu zapytać na ichniejszym forum dlaczego trzeba samemu wołać o uchwyt;

Podany wyżej kod pochodzi z testowego projektu, którego źródła wrzucam do załączników; Pobierz sobie je, przekompiluj i uruchom - po kliknięciu w przycisk w głównym oknie wyświetli się pierwsze okno potomne (mniejsze), a dopiero po jego zamknięciu wyświetli się drugie potomne okienko (większe); Czyli tak jak ma to wyglądać - główny formularz czeka aż pierwszy potomny zostanie zamknięty, po to aby utworzyć i wyświetlić drugi potomny;

.. [#] Nie żebym znał LCL na pamięć - po prostu sprawdziłem co robi metoda Application.CreateForm.

0

To może trochę teraz dopowiem po ściągnięciu Twojego kodu. U mnie nie da się zamknąć formy przyciskiem 'x'. Zamknięcie jej następuje po naciśnięciu przycisku umieszczonego na formie. Przy czym u Ciebie również występuję to o czym mówiłem, czyli taki lekki przeskok, że zanim pojawi się druga forma, po zamknięciu tej pierwszej to przez ułamek sekundy jest widoczna tylko główna. Mi chodzi o to aby tworzenie nowej formy było jakby częścią procedury zamykania poprzedniej formy. Tak by została ona stworzona jeszcze zanim poprzednia się zamknie. Chodzi o to, żeby nie było widać tego przeskoku. Utrudnione jest to o tyle, że procedurę tworzącą jedną formę mam w klasie bazowej, a kolejną w klasie dziedziczącej. W załączniku przesyłam mój projekt.

0
Patryk27 napisał(a):

Z Twoich słów wynika, że chcesz zrobić formę, która po kliknięciu przycisku będzie się natychmiastowo przekształcać w drugą, tak? W takim wypadku wykorzystaj TTabControl (mam nadzieję, że nie pomyliłem nazwy, ale dawno nie wykorzystywałem VCL/LCL :P).

0

Okej, TTabControl. Problem w tym, że nigdy z niego nie korzystałem i nie wiem jak nawet miałbym to wykorzystać :/

0

@dani17 - to co podałem wcześniej działa prawidłowo, tak jak ma działać; Pierwszy modalny formularz musi się najpierw zamknąć (i zniknąć z ekranu), aby można było wyświetlić drugi modalny; Jeżeli będziesz kombinował i nadmiernie ingerował w proces tworzenia okien to napytasz sobie biedy, bo interfejs zacznie wariować;


Wiem o czym piszę, bo w swoim dużym projekcie miałem podobny problem (aplikacja prezentacyjna, więc z nietypowym interfejsem - musi być ładna); Najpierw wskakuje na cały ekran specjalny splash screen, ładują się dane - chwilę to trwa; Następnie ten splash znika i pojawia się główny formularz, również na pełny ekran; Wizualnie wygląda to tak, jakby na cały ekran było rozciągnięte tło ze znakiem wodnym, a na środku znajduje się splash; Po jego zniknięciu tło pozostaje nieruchome, a nad nim wyświetla się główne okno;

Problem był z tym, że owe tło nie mogło być osobnym formularzem, bo menedżer okien strasznie głupiał (podbijał tło ponad główne okno) i nie dało się tego nijak rozwiązać; Dlatego też skorzystałem z pewnego triku - okno główne i splash zawsze wyświetlają się na pełny ekran, posiadają tak samo malowany znak wodny, natomiast wizualny obszar okien umieszczony został w panelach (mogę, bo mam całkowicie customowy interfejs); Dzięki temu wszystko wygląda idealnie, a menedżer okien nie ma prawa świrować;

Do czego zmierzam - przejście pomiędzy splashem a głównym oknem musi być płynne; Jeżeli najpierw zwolnię splash, a następnie pokażę główne okno to pomiędzy tymi akcjami, dosłownie przez 50ms widać pulpit (ogólnie to co jest pod spodem); Jest to takie samo mignięcie jak masz w swoim programie; Rozwiązałem to w nietypowy sposób - pokazuję splash, po załadowaniu danych pokazuję główne okno nad widoczną wizytówką, a po 500ms zwalniam z pamięci splash (w timerze); Dzięki temu przejście z jednego okna do drugiego wygląda na płynne;


U Ciebie będzie trudniej, bo po pierwsze, nie wiem co konkretnie chcesz ugrać, a po drugie, korzystasz ze zwykłych formularzy z natywnym schematem; Tak więc niewiele da się zrobić z tym miganiem.

0

Spróbuję więc to obejść inaczej. Stworzę po prostu dodatkową formę, która będzie służyła jako tło i ten przeskok będzie nawet całkiem pasować do całości. Jednak to był plan awaryjny.

Ale mam tu mały problem. Zrobiłem formę a na niej umieściłem komponent TImage. Tyle tylko, że ja muszę go narysować, a nie z automatu wyświetlić. Z tego co widzę da się Canvas.Draw, ale to jest dla BitMap, a co jeśli ja mam zdjęcia w innych formatach?

0

Z tego co widzę da się Canvas.Draw, ale to jest dla BitMap, a co jeśli ja mam zdjęcia w innych formatach?

Nie ma to żadnego znaczenia, bo wszystkie klasy do obsługi najróżniejszych obrazów i tak dziedziczą z tej samej, czyli jak dobrze pamiętam TFPImageBitmap; Format plików graficznych nie ma większego znaczenia dla wewnętrznych mechanizmów - ważny jest jedynie sposób odczytu obrazu z postaci skompresowanej (ogólnie: dyskowej) oraz zapis obrazu natywnego do postaci skompresowanej (docelowej, bo nie każdy format wykorzystuje kompresję);

Natomiast metoda Draw nie przyjmuje w trzecim argumencie konkretnie bitmapy, a obiekt dziedziczący z klasy TGraphic; To pozwala na malowanie dowolnego obrazu, bez względu na jego format;

Możliwe jest to dlatego, że każdy załadowany obraz do pamięci, dekompresowany jest po prostu do bloku pamięci, który składa się z porcji wartości składowych BGR dla każdego piksela (lub ABGR, zależy od głębi); Taki też bufor używają mechanizmy malujące.

0

To teraz kwestia jak pod TGraphic wczytać obraz który normalnie mam na TImage?

0

TGraphic to klasa abstrakcyjna i nie używa się jej bezpośrednio;

Lepiej napisz co potrzebujesz zrobić, bo znów chcesz przekombinować.

0

Muszę narysować obraz, w tym wypadku w formacie .jpg, ale będę też potrzebował .png i tyle. Ostatecznie mogę narysować wszystko inne i zostawić puste miejsce i postawić komponent TImage w tym miejscu. Efekt mnie zadowoli.

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