vykreslení obrázků v poli-velice velké množství
Dobrý den,
Řeším problém s překreslením obrázků v poli.
Na uvod krátký popis problematiky. Jedná se jen o základní popis, nikoliv odborný, učelem je vysvětlení funkce.
Na železnici je spousta typů zabezpečovacího zařízení. To které popisuji se nazývá releové. Je tvořeno panelem s mnoha prvky, nejdůležitější jsou však žárovky a tlačítka, která jsou vidět. Svícení/nesvícení žároviček dává obsluze stanice informace o stavu v kolejišti a podobně. Na panelu je největší množství takzvaných průsvitek. Jsou tvořeny šedou usečkou, za kterou jsou dvě žárovky. Bílá a červená. Existují 3 základní stavy.
Šedá-zařízení v základním stavu, kolej je volná a v pořádku.
Bílá-Přes danou kolej je proveden závěr jízdní cesty. Tzn. pojede tam vlak.
Červená-Daná kolej je obsazena vlakem, nebo je v poruše.
Vedle těchto základních stavů, jsou i další, ale ty nejsou z hlediska dotazu důležité, protože se jedná o kombinace svícení/kmitání žárovek bílá/červená.
To by byl základní popis na pochopení jak to funguje.
Obsluha však potřebuje v případě potřeby znát polohu výhybek. Výhybky jsou tvořeny popsanými průsvitkami, sestavenými do podoby písmene Y. Mají tedy větve a rozlišujeme větve přímé a odbočující. Pokud však na panelu nesvítí průsvitky, neví obsluha do které větve směřuje která výhybka. Aby to bylo obsluze umožněno, má na panelu tlačítko s popisem Kontrola polohy výměn. Po jeho stlačení, dojde k prosvětlení průsvitek bílou barvou (pokud není některá obsazená) a obsluha tak vidí v jaké poloze je ta která výhybka.
Po stlačení se však tyto průsvitky rozsvítí všechny najednou, protože se jedná o sepnutí kontaktu a uzavření okruhu. Ono to není uplně seriové spojení, ale to bych zacházel až moc do detailu.
V jazyku Delphi, mám tedy nakreslený takový panel a jednotlivé průsvitky jsou tvořeny za běhu, jako jednorozměrné pole.
Problém je v tom, že je jich veliké množství, více než 1024, protože ten zdrojový kód je univerzální a není jen jeden panel.
Jde mi o to aby při tomto množství došlo k rozsvícení všech průsvitek najednou.
Zdrojový kod je navržen tak, že projde celé pole (smyčka FOR) a všechny obrázky změní a na konci je zobrazí. Jenže dochází tím prodlevě 1sec až 1,5sec od stlačení tlačítka do zobrazení, což je už moc dlouhá doba a simulátor se pak nechová jako ve skutečnosti.
Věděl by někdo jak upravit algoritmus, tak aby se průsvitky překreslily najednou? Nebo alespon tak rychle že se to bude chovat jako že najednou?
Na formuláři se pak nachází 3 tlačítka, jedno provede vykreslení a 2 zbývající pak překreslení na bílo nebo červeno.Dále 2 editboxy, do kterých se zadává počet řádků a sloupců a 3 obrázky image, které jsou ony průsvitky šedé, bílé a červené.
procedure TForm1.btn3Click(Sender: TObject); //kliknutí na tlačítko, přemění všechny na červené a ponechá
begin
for i:=1 to strtoint(Form1.Caption) do begin //délka smyčky je High(prusvitky), tedy největší index ze všech prvků
prusvitky[i].Picture:=img3.Picture; //překreslujeme obrázek, bereme si jej z hotového na formuláři.
end;
end;
Předem děkuji za případné rady a pomoc.
Síce som to celé akosi "nepobral", ale z kúska nekompletného kódu mi vychádza, že zbytočne naplňuješ pole obrázkami - tu vidím asi to najväčšie zdržanie...
Však ak máš hotové 3 obrázky, potom Ti stačí pole, kde budeš uchovávať hodnotu farby....napr: 0 = šedá, 1 = červená, 2 = biela.... potom si vykreslíš na formulár taký obrázok, aký číselný kód je v poli na konkrétnej pozícii.
Ale možno je to celé inak.
Snažím se to pochopit. Je to popsáno s velkou snahou, ale i tak to nechápu.
Popiš to blíž, protože tohle není zřejmá věc.
Nemůžeš si nějak v tom běžícím programu ukládat časy jednotlivých činností a logovat je? Něco jako v JS console.log().
Problém může být i třeba s tím "překreslujeme obrázek, bereme si jej z hotového na formuláři" - možná je ta operace pomalá a bylo by lepší ten obrázek brát ze souboru (resources...), ale to jen hádám.
Podľa zdrojového kódu, prusvitky[i].Picture:=img3.Picture volá metódu TImage.SetPicture, ktorá volá metódu TPicture.Assign, ktorá volá TBitmap.Assign, ktorá kopíruje dáta obrázku (GetMem, Move). Zdrojový kód je síce z LLCL, ale predpokladám, že VCL to bude mať veľmi podobné, ak nie rovnaké.
Aby si to zrýchlil, stačí sa zbaviť tohto zbytočného kopírovania. Najjednoduchšie je spraviť komponent, ktorý bude mať 3 bitmapy a zobrazovať podľa stavu len ten aktuálny. Prípadne môžeš spraviť komponent, ktorý sa bude starať o vykreslenie celého poľa naraz. Komponent bude mať vlastnú OnPaint metódu, kde cez Canvas.Draw vykreslíš, čo potrebuješ.
Ak potrebuješ len farbu a nie obrázok, tak namiesto Canvas.Draw vykreslíš obdĺžnik pomocou Canvas.Rectangle (a predtým nastavíš farbu podľa potreby).
Předem děkuji za cenné rady a doplním to obrázky pro lepší názornost. Toto je jen malá stanice, šířka panelu je asi 6m. Ovšem existují i panely o délkách až ke 20metrům. Proto se snažím psát ten kod univerzálně, protože do budoucna nechci mít jen jednu stanici.
Na prvním obrázku je pohled na celkový panel. Černé čáry se šedými usečkami, jsou koleje a ty šedé jsou právě průsvitky o které jde především.
Druhý obrázek ukazuje stav, kdy se po stlačení tlačítka kontroly polohy výměn, rozsvítí celý panel a obsluha (výpravčí) tak ví, ve které poloze (kam směřuje), ta která výhybka. (Po stlačení se však tyto průsvitky rozsvítí všechny najednou, protože se jedná o sepnutí kontaktu a uzavření okruhu. Ono to není uplně seriové spojení, ale to bych zacházel až moc do detailu.)
Třetí obrázek je detail průsvitek, zde vidíme šedé (nesvítí) průsvitky, bílé (tedy považujeme je za bílé, ačkoliv odstín je do žluta) a nakonec červené (tam je kolej obsazena vlakem).
Postupoval jsem tak že jsem si vytvořil základní detaily průsvitek, tedy pohled přímo na ně. To je onen zmíněný img3.picture, vytvořený na formuláři. Přesněji řečeno oni jsou celkem 3, jeden je šedý, druhý bílý a třetí je červený.
Dále jsem vytvořil jednorozměrné pole prusvitky[index] jako array of TImage. Během programování, jsem ale přišel na to, že je lepší ty useky(shodné části v kolejích, seskupit dohromady a ušetřit tak velikost pole, byť na úkor velikosti obrázku. Např. staniční koleje, to jest 2. a 3.sekce panelu (počítáno zleva a panel je složen z více čelních stěn), jsou shodně dlouhé (16 průsvitek v 5 řadách kolejí). A protože jsou shodně dlouhé, tak mi přišlo zbytečné dělat každou tu průsvitku jako buňku pole, ale seskupit do jedné buňky o velikosti 16 průsvitek. Protože když vypočtu 16x5=80 prvků v poli, nebo použít 5 prvků v poli, je ten rozdíl zásadní.
Jak jsem psal už výše, existují mnohem větší panely a s tím pochopitelně i nárust průsvitek.
A ted jde právě o to, že na počátku je stav podle prvního obrázku (celý šedý panel, nesvítí žádná) a já jej chci změnit na druhý obrázek (celý panel svítí bíle).
V reálu se o to stará tlačítko, které po zmáčknutí spojí obvody relé a všechny žárovky v průsvitkách se rozsvítí najednou. Podobně jako vánoční stromeček v letadlech, kdy piloti zkouší, zda je vadná žárovka v indikaci, nebo je chyba jinde. Případně některá moderní auta, rozsvítí před startem celou palubní desku.
A zde máme kod, bohužel je dlouhý a nejde vložit klasickou cestou, tak jej dávám jako soubor unit1.txt
A zároveň náhled na formulář a výsledek vykreslení ve všech barvách.
A celé se to točí u rychlosti kreslení. Od stlačení tlačítko do konečného vykreslení, uběhne více než 1 sekunda a to zpoždění je již velké a simulátor tak ztrácí to co má dělat, jako v reálu. V reálu se to děje ihned, protože se v podstatě jedná o uzavření elektrického okruhu.
Cyklus nie je problém. Problém je to, čo sa deje v ňom - veľa kopírovania. Keď som spravil to isté, čo ty, iba v JavaScripte, tak samotná obsluha trvala cca 50 ms a vnímaná zmena stavu bola okamžitá. Keď nebudeš nič kopírovať, iba zmeníš vykresľovanie, tak to budeš mať podobne.
Osobne by som takéto niečo robil v JavaScripte - nie je potrebná inštalácia, ladenie je oveľa jednoduchšie, renderovanie je optimalizované, atď. Viem, že je to mimo témy, ale zvažoval si možnosť implementovať to ako webovú stránku? Ak áno, čo bola prekážka?
Je vic možností.
Asi bych sáhnul po TStringGrid případně TDrawGrid + pole, kde budeš držet stav.
Obrázky bych naházel do TImageList - všechny možnosti, případně základní obrázky + průsvitky, které se budou kreslit následně s průhledným pozadím.
V OnDraw gridu bych obrázek do buňky vykreslil přes ImageList.Draw() - tam zadáš jen kam a index obrázku. V případě, kde bude průsvitka zvlášť vykreslíš základ a přes to ještě jednou jen průsvitku.
Grid ti umožní panel rozdělit na čtverce a poskládat, jak potřebuješ, pak jen potřebuješ držet obsah jednotlivých čtverců.
O vlastní vykreslování se pak starat nebudeš, grid bude vědět, který index má pro buňku použít a jestli tam má navíc nakreslit průsvitku.
Ty jen nastavíš podmínky pro vykreslení - v cyklu nastavíš příznak a zavoláš grid.update
Tvůj současný problém je vytváření obrázků a ještě do nich pak láduješ obrázky - tohle je hodně pomalé.
P.S.
To už je hodně dávno, kdy jsme se učili releové zabezpečovací zařízení, adjustovali kontakty relátek a hledali v úvazech problém...