Utworzenie informacji że program się uruchamia

Odpowiedz Nowy wątek
2019-06-12 19:58
0

Witam.
W moim programie jest dużo danych przygotowywanych i przetwarzanych w trakcie uruchamiania. Umieściłem je w sekcji FormCreate. Wszystko działa bardzo bobrze, jednakże pomimo iż mam raczej dobry sprzęt (i7 4GHz), to po uruchomieniu programu przez około 15 sekund wygląda jakby nic się nie działo. Próbowałem też umieścić te procedury w sekcji FormShow, lecz nic to nie zmieniło. Jeśli nie wywołuję tych procedur, to okno aplikacji pojawia się natychmiast po uruchomieniu.
Chodziło by mi o to, aby po uruchomieniu programu pokazywało się okno aplikacji, na którym mógłbym umieścić informację o uruchamianiu np. typu Label, a potem uruchomić te czasochłonne procedury. Zależy mi aby były one wywoływane tylko raz, a nie np OnActivate. Niestety nie udało mi się tego zrobić.
Proszę o pomoc.

Pozostało 580 znaków

2019-06-12 20:54
4

To tak tylko podpowiem (bo nie programuje nic w Delphi), że może by tak ładowanie danych puścić w innym wątku i użytkownikowi wyświetlać info, że dane już załadowanie, a do tego czasu niech się kręci jakiś spinner czy jakieś splash logo? Ma to sens?

Link raczej stary, ale może sam coś lepszego znajdziesz

https://www.experts-exchange.[...]-to-a-delphi-application.html

edytowany 1x, ostatnio: axelbest, 2019-06-12 20:55

Pozostało 580 znaków

2019-06-12 20:58
5
Klakierus napisał(a):

Witam.
W moim programie jest dużo danych przygotowywanych i przetwarzanych w trakcie uruchamiania. Umieściłem je w sekcji FormCreate.

No to już zrobiłeś błąd – nie powinieneś takich rzeczy umieszczać w kodzie formularza. Klasy służące do zarządzania danymi powinny być od nich niezależne i być tworzone na zewnątrz nich.

Wszystko działa bardzo bobrze, jednakże pomimo iż mam raczej dobry sprzęt (i7 4GHz), to po uruchomieniu programu przez około 15 sekund wygląda jakby nic się nie działo.

Czyli na moim komputerze trwało by to z minutę. :]

Nie marnując czasu na buzzwordy, wszystkie klasy służące do przechowywania i zarządzania danymi oddziel od formularzy i zapisz w osobnych modułach. Natomiast wszystkie instrukcje łądujące dane czy je obrabiające (te, które zjadają te piętnaście sekund) wywołaj przed wywołaniem metod tworzących instancje formularzy (czyli pośrednio lub bezpośrednio w głównym pliku projektu).

Po drugie, zrób okno splash, które będzie widoczne na ekranie podczas ładowania danych. Utwórz je dynamicznie, przekazując Application jako Owner. Natomiast aby takie okienko reagowało na komunikaty, cały proces ładowania danych wydziel do wątku pobocznego (albo do kilku).

To tak z grubsza.


edytowany 2x, ostatnio: furious programming, 2019-06-12 21:01

Pozostało 580 znaków

2019-06-12 22:12
0

a ja jestem ciekaw (wiem, wiem, ciekawość to pierwszy stopień ...) cóż to za dane są generowane że aż tyle czasu zajmują? Nie jest to przypadkiem coś dociągane z netu?

Pozostało 580 znaków

2019-06-13 10:23
2

a ja dam prostszy sposób. FormCreate i FormShow wywołuje sie tak na prawde przed wyrysowaniem okna, dlatego najlepszym rozwiązaniem jest stworzenie własnej symulującej coś na krztałt OnAfterShow

const
  WM_AFTER_SHOW = WM_USER + 300; 
type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    procedure OnAfterShow(var Msg: TMessage); message WM_AFTER_SHOW;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.OnAfterShow(var Msg: TMessage);
begin
  // tutaj wywołaj swoje metody
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  PostMessage(Self.Handle, WM_AFTER_SHOW, 0, 0);
end;

Pozostało 580 znaków

2019-06-13 15:48
0

Dziękuję za rady. Na razie skorzystam z porady kolegi flasher86. To co napisał furious programming muszę w wolnym czasie przemyśleć i zrozumieć, jestem na dużo niższym poziomie, piszę właściwie tylko pomoce dla siebie.
Co do pytania robertz68, to nie dane z netu, to wczytywanie i obróbka grafik w wysokiej rozdzielczości, wstępne przygotowanie kolorów, miejsc pod inne grafiki i napisy itp.
Dziękuję za pomoc.
Pozdrawiam.

edytowany 1x, ostatnio: Klakierus, 2019-06-13 16:35

Pozostało 580 znaków

2019-06-13 17:15
0
flasher86 napisał(a):

FormCreate i FormShow wywołuje sie tak na prawde przed wyrysowaniem okna, dlatego najlepszym rozwiązaniem jest stworzenie własnej symulującej coś na krztałt OnAfterShow

No i w czym to niby pomoże? Nadal okno będzie zamrożone i do czasu przetrawienia danych nie będzie odpowiadało na komunikaty. Bo tutaj problemem nie jest moment przetwarzania danych, a wydzielenie tego procesu z głównego wątku, tak aby interfejs nie ”wisiał”.

Poza tym sterowanie interfejsem i zarządzanie oknami z poziomu zdarzeń konkretnego okna (np. głównego okna) to zła praktyka i nie powinno się tego robić. Okna mają żyć własnym życiem, a aplikacja powinna być zarządzana przez mechanizmy niezależne od formularzy.


edytowany 3x, ostatnio: furious programming, 2019-06-13 17:17

Pozostało 580 znaków

2019-06-13 18:47
0

Pewnie chodzi o to, by pojawiło sie okno/splash z info, że coś się dzieje, a po 30 sekundach ożyło. Bo teraz z tego co rozumiem to odpalasz program i bez znaków życia on przez 30 sekund odpala się nie daje znać, że żyje - w ten sposób ,możesz włączyć go drugi raz i zaraz masz całą kolekcje nowych procesów co wiszą i co jakiś czas będą się odpalać ;) Niemniej masz racje - ładowanie danych powinno być asynchroniczne.

Pozostało 580 znaków

2019-06-13 18:55
0

somedev - dokładnie tak. Zrobiłem zgodnie z radą flasher-a i działa poprawnie.
Niestety dotychczas pisałem tylko proceduralnie i właśnie czytam o klasach/wątkach - próbuję nauczyć się tego, o czym napisał furious programming.

Pozostało 580 znaków

2019-06-14 06:59
0

Gdy czytam co pisze kolega furious programming wszystko wydaje się jasne i logiczne. Poczytałem o tworzeniu wątków, troszkę to jest dla mnie zagmatwane, dlaczego nie można wprost uruchomić danej procedury w nowym wątku, należy tworzyć nowe klasy, ale nie ma co narzekać, tylko się nauczyć tego.
Zacząłem więc od przerzucenia procedur i funkcji przygotowujących i obrabiających dane do nowego modułu. Było trochę zamieszania, gdyż stale używane obrazy miałem jako zmienne globalne i użycie ich było niejawne, a tymczasowo używane obrazy były jako zmienne lokalne przekazywane jawnie. Udało się wszystko zrobić bez problemów, wszystkie przekazania zmiennych są teraz jawne.
Jednakże przy próbie tworzenia wątków zgłupiałem i mam kilka pytań. Abym to zrozumiał posłużę się przykładami, a nie moimi procedurami. Jeśli przykładowo mam taki program (piszę naprędce z głowy, nie kopiuję z kompilatora,więc możliwe są błędy):

var 
     obraz, wzor : TBitmap;
     kolor1, kolor2 : TColor;

procedure TForm1.obrobka(var obraz:TBitmap; wzor:TBitmap; kolor1, kolor2:TColor);
begin
   ...
end;

begin
   obraz:=TBitmap.Create;
   wzor.Picture.LoadFromFile('plik1.bmp');
   obrobka(obraz,wzór,kolor1,kolor2);
   ...
   obraz.Free;
end.

Następnie przerzucam procedurę "obrobka" do nowego modułu i przerabiam, aby później mogła być wywoływana w wątku

unit procedury;
...
type 
TprocZrobObraz=procedure(obj:TObject; obraz, wzor:TBitmap; kolor1, kolor2:TColor) of object;

procedure obrobka(obj:TObject; procZrobObraz:TprocZrobObraz);

implementation

procedure obrobka(obj:TObject; procZrobObraz:TprocZrobObraz);
var 
   obraz : TBitmap;
begin
   obraz:=TBitmap.Create;
   ...
   procZrobObraz(obj, obraz, wzor, kolor1, kolor2);
   obraz.Free;
end;

Jak w takim przypadku przekazać w programie głównym zmienne do danej procedury?
U mnie kompilator stale wywala że jest niezgodność danych, niemożna przypisać TBitmap do mojego nowego typu danych.
W jaki sposób powinienem deklarować dane które mają być zmienione - odpowiednik "var" (obraz) oraz te które są tylko do odczytu (wzór)?

Pozostało 580 znaków

2019-06-14 07:50

Ależ można używać tego prościej od razu w innym wątku. To że @furious programming mówił o wątkach to sądzę, ze albo jest skrótem myślowym, albo po prostu nadal z tego korzysta, niemniej tutaj nie używał bym wątków, jako takich ale samego konceptu. Wątki jak zauważyłeś są nieco skomplikowane w użyciu, dlatego opakowano je w wyższa abstrakcje. Obecnie można wzorem C#, w prosty sposób tworzyć taski, które w dowolnym momencie mogą zostać utworzone i uruchomią kod do przetwarzania współbieżnego. Taski mają szereg zalet - są prostsze w użyciu, lepiej się synchronizują i prościej poczekać na zakończenie jakiegoś zadania, oraz co najważniejsze - task poprzez PPL (Parallel Programming Library , z kolei w C# jest TPL - Task Parallel Library), jest korelowany z wątkiem i to PPL zarządza osobnym wątkiem i dba, żeby było ok, do tego stopnia, że nie trzeba martwić się o ilość wątków, jakieś thread poolery etc. gdyż to wszystko robi za nas PPL- dla przykładu tworząc ręcznie wątki można stworzyć ich tyle, że program nie będzie nic robił tylko zmieniał konteksty na procesorze, natomiast używając PPL - wątków jest mniej niż tasków, niemniej to PPL tym zarządza by wszystko wykonywało się równolegle. Uważam, że do Twojego problemu lepszy będzie TTask niż twardy wątek, no i bardziej nowocześnie i łatwo.

Masz sznurek: http://docwiki.embarcadero.co[...]_Parallel_Programming_Library

Przepiszę przykład

procedure TForm1.Button1Click(Sender: TObject);
var
 aTask: ITask;
begin
 aTask := TTask.Create (procedure ()
   begin
     sleep (3000); // 3 seconds
     ShowMessage ('Hello');
   end);
 aTask.Start;
end;

Tutaj po kliknięciu przycisku metoda szybko się skończy i program będzie odblokowany, a po 3 sekundach nagle wyskoczy messagebox. Tutaj definiujesz podczas założenia taska procedurę, która się wykona. Coś takiego samego możesz osadzić w ShowForm, żeby asynchronicznie zacząć wczytywać pewne dane.

edytowany 1x, ostatnio: furious programming, 2019-06-14 14:02

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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