Ekran powitalny w wątku.

0

Chciał bym prosić o pomoc bo jeszcze bardzo mało siedziałem w wątkach. Problem wygląda następująco: mam aplikację która przy starcie ładuje dużo danych i robi jeszcze kilka dziwnych rzeczy które wykraczają poza granice mojej wyobraźni, w efekcie odpala się około sekundy. Chciał bym wyświetlić ekran powitalny na czas gdy aplikacja będzie sobie czarowała w tle. Potrzebuje tzw. kopa na rozpęd bo srednio wiem jak zacząc. Czy był by ktoś tak miły i napisał mi coś pomocnego? :D

czy w ogóle potrzebuje tutaj wątków? czy wystarczy jak wyświetle forme powitalna OnTop a aplikacja się przemieli pod
spodem?

0

Wątpię czy ktokolwiek się domyśla o co Ci chodzi... tytuł "Ekran powitalny w wątku" można wiedzieć po co w wątku? Na starcie to znaczy kiedy? W OnCreate formy głównej czy może jeszcze przed jej utworzeniem w pliku DPR? To co ładuje robi w kilku wątkach na raz czy w jednym wątku po kolei a może w ogóle bez wątku?

2

O ile dobrze zrozumiałem co chcesz osiągnąć, to potrzebujesz zrobić tak zwany Splash Screen. Poszukaj informacji o nim. Jest ich mnóstwo wraz z przykładami do znalezienia w Google, także pod Delphi.

0
m_Lesiu napisał(a):

mam aplikację która przy starcie ładuje dużo danych i robi jeszcze kilka dziwnych rzeczy które wykraczają poza granice mojej wyobraźni, w efekcie odpala się około sekundy. Chciał bym wyświetlić ekran powitalny na czas gdy aplikacja będzie sobie czarowała w tle.

Jaki jest sens wyświetlania ekranu powitalnego przez około sekundę?

1

@pelsta dobrze prawi - na sekundę nie ma sensu; Jeśli już koniecznie chcesz to ustal sobie jakiś mały time out przed i po wykonaniu długotrwałego kodu, np. 500ms; No i przede wszystkim tak jak pisze @olesio - poszukaj informacji o tworzeniu SplashScreen; Tutaj na forum także powinien być o tym artykuł, bo sam z niego dawno temu korzystałem (ale szukanie pozostawiam Tobie); I tak jak wspomniał @kAzek - staraj się pisać jasno i podawaj zawsze jak najwięcej informacji - nie będzie się trzeba pewnych rzeczy domyślać.

2

Hej,
nie potrzebujesz wątków.
Potrzebujesz 2 formy i potrzebujesz odpowiednio zmodyfikować program uruchamiający te formy (menu -> project -> viewsource).
Dane utworzone w formie 2 (startowej) możesz przekazać do formy 1 (głównej) zmieniając procedurę execute na funkcję.
Powodzenia. Ciekawy przykład (tyle że z oknem modalnym -> w twoim przypadku nie możesz go użyć znajdziesz tutaj: http://delphi.about.com/od/windowsshellapi/a/password_login.htm
mój przykład poniżej (wygenerowany w delphi xe2):


unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, unit3, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

end.
 
unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, unit3;

type
  TForm2 = class(TForm)
    ProgressBar1: TProgressBar;
    class procedure execute;
  private

    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

{ TForm2 }

class procedure TForm2.execute;
var
  licznik: integer;
begin
  with TForm2.Create(nil) do
    begin
      Show;
      ProgressBar1.Max:= 5;
      ProgressBar1.Min:= 1;
      for licznik := Progressbar1.Min to ProgressBar1.max do
        begin
          ProgressBar1.Position:= licznik;
          Sleep(500);
          Application.ProcessMessages;
        end;
      Free;
    end;
end;

end.
program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2},
  Unit3 in 'Unit3.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  TForm2.execute;
  Application.Run;
end.

Aaaa - zapomniałem dodać -> powyższy programik działa w następujący sposób:
wyświetla się forma2 (tam leci progressbar od 1 do 5 co 0.5 sekundy) - w tym czasie forma 1 jest ukryta.
Jak forma2 się zamknie odpali się dopiero 1. Tutaj musiałbyś przekazać dane z formy2 do 1.

Jeżeli natomiast chcesz mieć 2 formy w jednym czasie to sprawa jest banalna.
Po prostu dodaj formę, ustaw jej właściwość visible na true, zamknij ją lub ukryj po upływie czasu lub po wywołaniu
funkcji z formy 1-rwszej.

1

Widzę, że dalej nikt nie poszukał artykułu, o którym wspomniałem wyżej; Tutaj link: Ekran powitalny - Splash Screen [#]_

SplashScreen dobrze jest obsługiwać z głównego pliku projektu, nie z modułów forularzy; Wszelkie operacje podczas których ekran powitalny powinien wisieć także powinno się wykonywać w module głównym aplikacji; Jeśli taki kod jest upchany gdzieś w module formularza to IMHO jest to błąd projektowy;

@grzesiekyogi - zapominasz, że Twój sposób sprawdzi się tylko wtedy, gdy formularze tworzone są automatycznie przy starcie programu, co jest poważnym uniedogodnieniem i wpływa na zajętość pamięci; Jeśli ktoś tworzy formularze dynamicznie dbając o efektywność i minimalizację zasobożerności aplikacji - nie będzie angażował do tego formularzy, tylko zaimplementuje ten mechanizm gdzie indziej, niż w module formularza; Te dwa mechanizmy powinny być oddzielone i działać niezależnie.

Ciekawy przykład (tyle że z oknem modalnym -> w twoim przypadku nie możesz go użyć znajdziesz tutaj: http://delphi.about.com/od/windowsshellapi/a/password_login.htm

Ciekawy, owszem, tyle że nie związany zbytnio z tematem; Ale po części jest dobry poniważ pokazuje, że tego typu operacje robi się bez użycia formularza głównego aplikacji w głównym module aplikacji.

.. [#] W artykule z podanego linku jest dość nędzne formatowanie kodu i brak odpowiednich bloków zabezpieczających przed wyciekami pamięci w razie jakiegokolwiek błędu; Trzeba je więc samemu dodać.

1

Witam ponownie,
zwykle nie wdaję się w polemikę, gdy problem jest już rozwiązany, ale w tym wypadku muszę wyrazić swoje zdanie :p

furious programming napisał(a):

SplashScreen dobrze jest obsługiwać z głównego pliku projektu, nie z modułów forularzy; Wszelkie operacje podczas których ekran powitalny powinien wisieć także powinno się wykonywać w module głównym aplikacji; Jeśli taki kod jest upchany gdzieś w module formularza to IMHO jest to błąd projektowy;

W przypadku małych programów zgadzam się. Przy dużych projektach stanowczo odradzam.
Moduł główny ma ważniejsze zadania. Kiedy będziesz chciał zrobić drugą wersję programu i zmodyfikować głupią graficzkę w Splash-u
zgodnie z Twoim podejściem będziesz szukał tego w prawdopodobnie dużym module głównym. Jeżeli jednak masz go w osobnym module - żaden problem otwierasz moduł wraz z formą (np. o nazwie Splash) i w 5 minut załatwiasz to co chcesz - taka przecież była idea wprowadzenia modułów.

furious programming napisał(a):

@grzesiekyogi - zapominasz, że Twój sposób sprawdzi się tylko wtedy, gdy formularze tworzone są automatycznie przy starcie programu, co jest poważnym uniedogodnieniem

No popatrz Furious, znowu się nie zgadzam :p.
Dodaj sobie przycisk na formie1 i pod jego zdarzeniem OnClick wpisz:

 TForm2.Execute

oczywiście nie zapomnij o uses unit2.
Jedno polecenie i splash mojego autorstwa jest dostępny gdziekolwiek byś nie chciał
(nie tylko z projektu) :p

furious programming napisał(a):

...i wpływa na zajętość pamięci;

Spójrz raz jeszcze na budowę metody typu class o nazwie execute. Na końcu znajduje się magiczne słówko FREE. Po zakończeniu metody execute cały obiekt zostanie zwolniony. Powiem Ci więcej - możesz nawet usunąć:

var
Form2: TForm2;

Jedynie co zostanie w pamięci to sama metoda execute (gdyż jest to metoda typu class). Jednakże nie ma problemu możesz zaprojektować klasę w ten sposób, że
metoda execute będzie zawierała tylko tworzenie obiektu wraz z wywołaniem konstruktora oraz wywołanie wspomnianej i nieocenionej metody Free. Całą resztą
może zając się sam obiekt - który w końcu i tak jest przez execute zwalniany z pamięci...

aaa i jeszcze jedno ;) Dobrze, że przytoczyłeś przykład z artykułem odnośnie S.Screen. Spróbuj go przystosować, aby S.Screen przekazał jakąś informację (dowolną) do głównego modułu. Oczywiście jest to możliwe, ale wymaga większych zmian. W moim przykładzie zrobisz to bez problemu. Jak już
pisałem wcześniej metodę class procedure execute zmieniasz na class function execute i zwracasz co byś nie chciał. W ten prosty sposób możesz przekazać wyniki drobnych obliczeń (S. Screen wcale nie musi tracić czasu. Przykład? - proszę bardzo: program partition magic. Wyświetla się S.Screen z graficzką - w tym samym czasie program analizuje strukturę danych na dysku by na końcu przekazać ją do modułu głównego zajmującego się obsługą użytkownika).

0

Moduł główny ma ważniejsze zadania. Kiedy będziesz chciał zrobić drugą wersję programu i zmodyfikować głupią graficzkę w Splash-u zgodnie z Twoim podejściem będziesz szukał tego w prawdopodobnie dużym module głównym.

Tak, jeśli z modułu głównego aplikacji zrobi się "spaghetti-code";

Kilka razy wykorzystywałem w swoich aplikacjach ekrany powitalne, które musiały wisieć do czasu ukończenia początkowych operacji (jak sprawdzanie istnienia najważniejszych plików, tworzenie brakujących mało ważnych plików, ładowanie grafiki itd.) i zawsze robiłem tak:

  • formularz z ekranem powitalnym - wiadome - osobny moduł jedynie z formularzem;
  • wszelkie operacje wykonywujące się podczas "wiszenia" ekranu powitalnego były elegancko opakowane w klasę, gdzie jej deklaracja i definicja była zaimplementowana także w osobnym module, dzięki czemu zyskiwałem na czytelności,
  • całość sterowana z modułu głównego;
    Dzięki temu moduł główny miał nie więcej, niż 200 LoC (z różnymi rzeczami prócz operacji początkowych) i wszystko było na swoim miejscu - kod elegancko rozdzielony; Więc nie ma mowy o błądzeniu w kodzie/modułach/wtf by cokolwiek znaleźć i poprawić, jak wynika z Twoich słów dotyczących "idei modułowości"; Oczywiście nie twierdzę, że Twój sposób jest jakiś dziwny/nielogiczny - po prostu dla mnie bardziej logiczne jest rozdzielenie tych dwóch warstw - formularza i klasy do przeprowadzania początkowych operacji; W module z formularzem obsługuje tylko i wyłącznie rzeczy związane z ekranem powitalnym (interfejsem), a ww. klasa ma swój moduł;

Wszystko oczywiście zależy od tego do czego służy ekran powitalny - czy tylko do pokazania jakiegoś loga (ogólnie grafiki i nic więcej), czy bardziej skomplikowany - do pokazania postępu rozruchu np. na ProgressBarze + etykiety z wczytywanymi plikami;

Jedno polecenie i splash mojego autorstwa jest dostępny gdziekolwiek byś nie chciał (nie tylko z projektu)

Tylko po co? Skoro jego przeznaczeniem jest wyświetlanie przy starcie aplikacji i nigdzie indziej; Poza tym jeśli nawet chciałbyś go tylko wyświetlić, to po co w niej Execute, skoro i tak się go nie wykorzysta? No chyba, że znów chcesz wykonać Execute to się zgodzę;

Spójrz raz jeszcze na budowę metody typu class o nazwie execute. [...] Jedynie co zostanie w pamięci to sama metoda execute (gdyż jest to metoda typu class).

Tak, spojrzałem i ujrzałem, że z wczorajszej analizy nic nie zrozumiałem... :]
Przeoczyłem, że jest to metoda statyczna (nazywajmy rzeczy po imieniu) - zwracam honor i przepraszam za wprowadzenie w błąd;

Spróbuj go przystosować, aby S.Screen przekazał jakąś informację (dowolną) do głównego modułu. Oczywiście jest to możliwe, ale wymaga większych zmian.

Tutaj się nie zgodzę - żadne zmiany, bo jak napisałem wyżej nie formularz steruje operacjami rozruchu, a klasa za to odpowiedzialna; Poza tym ta klasa współpracuje z silnikiem aplikacji, który jest odpowiedzialny za aktualizowanie interfejsu i innych elementów programu, przechowywanie bieżącej konfiguracji itd. przez cały czas działania aplikacji (silnik także jest osobną klasą niepowiązaną z żadnym formularzem, więc z każdego miejsca aplikacji mam do niego dostęp, a tworzony w pamięci jest w swoim osobnym module w sekcji initialization i finalization); Z resztą każdy formularz, jaki jest dynamicznie tworzony w mioch programach, w swoim konstruktorze pobiera odpowiednie informacje z silnika, a w destruktorze doń zapisuje, dzięki temu po raz kolejny wiadome jest wszystko - porządek jest - warstwy są oddzielone;

Podsumowując - lubię mieć kod poukładany, elementy służące do różnych rzeczy lubię mieć porozdzielane, stąd preferuję swoje rozwiązanie, które nigdy mnie nie zawiodło i jest na tyle elastyczne, że dużych przeróbek spowodowanych złym dzieleniem kodu nie miewam; Z racji tej, że ekran powitalny głównie wykorzystuję jedynie do informowania użytkownika o tym, iż aplikacja się obecnie uruchamia - nic więcej nie dodaję do formularza; Dzięki temu warstwy interfejsu i kodu działają niezależnie.

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