Autor Téma: Rozdiel medzi Invalidate, Refresh a Repaint u vizualnych VCL komponent  (Přečteno 971 krát)

Offline Daniel_Andrascik

  • Hrdina
  • ****
  • Příspěvků: 459
  • Karma: 19
    • Verze Delphi: D2007, XE3
Excellent
Rated 1 time
Zdravim.

Mohol by mi prosim vas niekto polopatisticky vysvetlit aky je rozdiel medzi nasledujucimi metodami u vizualnych VCL komponent:

1. Invalidate
2. Refresh
3. Repaint

Konkretne ma to zaujima hlavne u trosku komplikovanejsej komponentny TChart (TeeChart). Vykreslujem asi 5 fastline serii a celkom do toho grafu palim. Pridavam cca 5 bodov za sekundu pre kazdu seriu. Neviem ale pri tejto kadencii sa mi z nejakeho dovodu prestal graf sam prekreslovat. Musim cez neho prebiehat aspon myskou aby sa prekreslil. Volanie metody Refresh to vyriesilo, ale neviem ci som zvolil zrovna tu najoptimalnejsiu cestu.

Offline Delfin

  • Padawan
  • ******
  • Příspěvků: 1724
  • Karma: 66
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Mohol by mi prosim vas niekto polopatisticky vysvetlit aky je rozdiel medzi nasledujucimi metodami u vizualnych VCL komponent:

1. Invalidate
2. Refresh
3. Repaint

1. Invalidate - pouze oznaci cely klientsky region komponenty za neplatny; s nasledujicim prichodem zpravy WM_PAINT od operacniho systemu se tento region prekresli.
2. Refresh - vola pro tridu TControl interne pouze Repaint. Jsou tedy v TControl zamenitelne.
3. Repaint - pokud komponenta obsahuje styl csOpaque, pak se vynuti prime vykresleni (bez vyuziti operacniho systemu); pokud ne, pak se invaliduje klientsky region a vyvola odeslani zpravy WM_PAINT pomoci funkce UpdateWindow.

Dalo by se tedy rict, ze metoda Invalidate je "mene invazivni". Pouze se oznaci invalidni region a ten se pak s naslednym prichodem kreslici zpravy od operacniho systemu prekresli. Repaint je "vice invazivni" v tom, ze se vykresleni vynuti (bud primou injekci kreslici zpravy do pumpy, nebo jeji vyvolani operacnim systemem).

Jeste dodam, ze zprava WM_PAINT ma nizsi prioritu nez napr. zpravy uzivatelskeho vstupu (zpravy vstupu jako klavesnice nebo mysi).
« Poslední změna: 16-12-2018, 18:19:56 od Delfin »
I'm a soldier, so don't panic! I know the underground! I like WTFPL license! No more Google, go duck, go!

Offline Delfin

  • Padawan
  • ******
  • Příspěvků: 1724
  • Karma: 66
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Konkretne ma to zaujima hlavne u trosku komplikovanejsej komponentny TChart (TeeChart). Vykreslujem asi 5 fastline serii a celkom do toho grafu palim. Pridavam cca 5 bodov za sekundu pre kazdu seriu. Neviem ale pri tejto kadencii sa mi z nejakeho dovodu prestal graf sam prekreslovat. Musim cez neho prebiehat aspon myskou aby sa prekreslil. Volanie metody Refresh to vyriesilo, ale neviem ci som zvolil zrovna tu najoptimalnejsiu cestu.

Nee, 5 hodnot za sekundu je zivacka. Jaka je to verze TeeChart? Da se takove chovani zreprodukovat i na cistem projektu? A deje se to od nejakeho poctu hodnot nebo porad? P.S. videl jsem zdrojak TeeChart a neni to pekny pohled... Ale co si budeme povidat, i spousta JavaScriptovych grafu je z pohledu UX mnohem dal nez Steema.
« Poslední změna: 16-12-2018, 18:27:17 od Delfin »
I'm a soldier, so don't panic! I know the underground! I like WTFPL license! No more Google, go duck, go!

Offline Daniel_Andrascik

  • Hrdina
  • ****
  • Příspěvků: 459
  • Karma: 19
    • Verze Delphi: D2007, XE3
TeeChart v D10.2 je tusim 2016ka. Mozem skusit cisty projekt ze preco sa mi prestali same prekreslovat grafy, ale momentalne nestiham, zajtra potrebujem zakaznikovy nieco predviest. Ucesavat to budem neskor, zatial nech to ide, hodim tam to invalidate, i s nim mi to fungovalo.

Mozno som zvolil zly postup pri pridavani hodnot do serii. Vzdy pristupujem k jednotlivym seriam priamo pomocou ich premennej a nie pomocou kolekcie cez TChart kontajner. Najprv vsetkym seriam zavolam metody BeginUpdate. Potom do nich nasukam hodnoty a potom vsetkym zavolam EndUpdate. Toto by som mozno mohol zmenit a volat BeginUpdate a EndUpdate len raz pre samotny TChart. Neviem jak je to vo vnutry poprepajane a zmenezovane.

V kazdom pripade diky za vycerpavajuce vysvetlenie o sposobe fungovania metod Invalidate, Refresh a Repaint. Nie som zrovna moc "vizualne komponentovy". Riesim u nich len nevyhnutne zlo... A tak nejak sa mi mari ze zvycajne sa odporucalo pouzivat Invalidate...

Offline Delfin

  • Padawan
  • ******
  • Příspěvků: 1724
  • Karma: 66
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Mozno som zvolil zly postup pri pridavani hodnot do serii. Vzdy pristupujem k jednotlivym seriam priamo pomocou ich premennej a nie pomocou kolekcie cez TChart kontajner. Najprv vsetkym seriam zavolam metody BeginUpdate. Potom do nich nasukam hodnoty a potom vsetkym zavolam EndUpdate. Toto by som mozno mohol zmenit a volat BeginUpdate a EndUpdate len raz pre samotny TChart. Neviem jak je to vo vnutry poprepajane a zmenezovane.

TChart nema metody BeginUpdate a EndUpdate. Nicmene ten postup se zamykanim serii je mozna i zbytecny, protoze pridavas do dane serie jen 1 hodnotu. Ten zamek serii je pro hromadne pridavani hodnot. Co je vsak divne je, proc se graf prestane vykreslovat. Nechybi Ti nekde odemceni toho zamku (do paru chybejici EndUpdate)?

Jinak obecne se pro zamceni vykreslovani komponent da pouzit zprava WM_SETREDRAW. Myslenka je takova, ze pomoci ni grafu zamknes vykreslovani, nasypes vsechny hodnoty, vykreslovani odemknes a vyvolas prekresleni.

A tak nejak sa mi mari ze zvycajne sa odporucalo pouzivat Invalidate...

Ano, to je spravny zpusob pro situace kdy nepotrebujes okamzite kresleni vystupu. Zprava WM_PAINT ma vsak (stejne jako napr. WM_TIMER) snizenou prioritu a muze se stat, ze napr. drzis stisknute tlacitko mysi a tim drzenim se pres frontu mysich zprav k WM_PAINT jen tak nedostanes. Proto se pouziva bypass v podobe Repaint (nebo Refresh), pripadne Update (jenz narozdil od Repaint neinvaliduje zadny region, hodi se tedy pro okamzite kresleni mensich oblasti).

Samotny princip kresleni ve Windows je jednoduchy. Invaliduji se regiony okna a Windows za to posila (se snizenou prioritou) zpravu WM_PAINT. No a ty pak v aplikaci cekas na tu WM_PAINT, pomoci BeginPaint si vyzvednes ten invalidovany region a do nej kreslis co potrebujes.

Z toho take plyne, ze pokud chces vyvolat prekresleni jen urcite oblasti komponenty, nevolas k tomu VCL Invalidate, ale WinAPI InvalidateRect, prip. InvalidateRgn s regionem jenz se ma obcerstvit.
« Poslední změna: 17-12-2018, 07:39:07 od Delfin »
I'm a soldier, so don't panic! I know the underground! I like WTFPL license! No more Google, go duck, go!

Offline Faltynek

  • Plnoletý
  • ***
  • Příspěvků: 162
  • Karma: 2
    • Verze Delphi: D5 Enterprise, D2009
A nestačí náhodou přidat hodnotu do série před AddXY?
Dalibor (D2009 Enterprise, dřív D5Enterprise)

Offline Daniel_Andrascik

  • Hrdina
  • ****
  • Příspěvků: 459
  • Karma: 19
    • Verze Delphi: D2007, XE3
Ano, hodnoty pridavam cez AddXY.

BeginUpdate a EndUpdate pouzivam preto, lebo hned po tom co pridam hodnotu, tak minimalne jednu alebo viac hodnot zo zaciatku serie este umazavam a az tak volam EndUpdate. Cize tych bodov je preca len upravenych viac, ale uznavam ze koli dvom trom bodom sa to mozno fakt neoplati, vyskusam to aj bez toho. Ale bral som to tak ze umazanie paru pociatocnych bodov moze ale aj nemusi vyvolat "masivnejsie" prekreslenia. Ale kedze zdrojak nepoznam, povedal som si ze Begin a EndUpdate by nemalo nicomu ublizit tak to tam radsej dam.  Begin a EndUpdate mam pekne cisto spravene v ramci bloku try, finally, Takze sa nema ako stat aby som tie serie neodomkol. A teraz ma prave asi napadlo preco mi to prestava vykreslovat. Hned ako pridam nejake hodnoty a umazem aj nejake tie pociatocne hodnoty tak nastavim este zobrazovanu oblast pomocou volania metody BottomAxis.SetMinMax... ci tak nejako, ale toto volam v case ked su este vsetky serie zamknute. Je dost mozne ze sa to tam niekde zamota a uz sa to po zavolani EndUpdate neprekresli.

Problem je ze to teraz neviem uplne jednoducho vyskusat, pretoze aplikacia je zavisla na externom hardveri ktory teraz nemam a moc sa mi to simulovat nechce. Ale urcite to najneskor po novom roku vyskusam, pripadne medzi sviatkami a dam vediet.

Offline František

  • Hrdina
  • ****
  • Příspěvků: 473
  • Karma: 6
    • Verze Delphi: primárne v XE5, občas 10.2.3 comunity
ja vykreslujem bod kazdu milisekundu (teda 100 bodov raz za 100 ms v timery) + dalsie prepocitane hodnoty (spolu 4 serie), a splape ako vino (XE5)

Offline Daniel_Andrascik

  • Hrdina
  • ****
  • Příspěvků: 459
  • Karma: 19
    • Verze Delphi: D2007, XE3
fiha pekne. a aky dlhy takyto zaznam zobrazujes?

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4118
  • Karma: 36
    • Verze Delphi: XE7 professional
Veď nech tu hodí obrázok.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline František

  • Hrdina
  • ****
  • Příspěvků: 473
  • Karma: 6
    • Verze Delphi: primárne v XE5, občas 10.2.3 comunity
30000 ms