Draw overlay

Intrebari legate de programarea cu biblioteci precum MFC, ATL, WTL si GDI+.
mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 23 Oct 2012, 15:29

Cum merge acum: device-context-ul se salveaza intr-o variabila membru m_MemDC doar la initializare si la schimbarea zoom-ului, iar in momentul desenarii, se transfera continutul memory-device-context-ului in device-context-ul real:

Code: Select all

void CTestDrawView::OnDraw(CDC* pDC)
{
	pDC->BitBlt(rectVisible.left, rectVisible.top, rectVisible.Width(), rectVisible.Height(), 
		&m_MemDC, rectVisible.left, rectVisible.top, SRCCOPY);
}
astfel, desenarea este extrem de rapida, si ramane timp destul pentru alte overlay-uri ... acum merge OK.

Ar mai fi totusi ceva ... in memory-device-context se pune bitmap-ul de dimensiunea zoom-ului ... iar cand zoom-ul devine mare, de la 7 in sus (4 in cazul aplicatiei reale), bitmap-ul din memory-device-context devine huge, si la momentul desenarii in OnDraw, view-ul devine negru (nu se mai redeseneaza in cazul aplicatiei reale). Nu mai pun la socoteala faptul ca la zoom-uri mari, aceasta tehnica cam consuma RAM ... Am incercat sa pun in memory-device-context doar bitmap-ul original (cu zoom 1) si la momentul desenarii sa "intind" memory-device-context-ul in device-context-ul real, in functie de zoom, nu cu CDC::BitBlt, ci cu CDC::StretchBlt ... dar n-am reusit inca ... poate ce vreau eu nu se poate ...



mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 24 Oct 2012, 09:07

1. Foloseste HALFTONE si nu COLORONCOLOR.
Intradevar, view-ul are calitate mai buna cu HALFTONE, cel mai bine se vede asta cand zoom-ul este mare: cu COLORONCOLOR imaginea parca este facuta din "patratele", cu HALFTONE nu. Clasa CDib am luat-o de-a gata, cum a venit asa am folosit-o.
2. Nu arunca CException* ci CUserException*.
Am vazut asta cand am incercat sa compilez proiectul cu un mediu mai nou ...
3. Odata ce folosest MM_TEXT peste tot, cred ca nu-si mai au rost DPtoLP si LPtoDP-urile care ti-au ramas prin cod.
Intradevar nu isi mai au rostul decat atunci cand desenez overlay-ul, pentru a ramane fixa acel text+linii.
4. IDC_HAND este deja definit in SDK, pentru WINVER >= 0x0500. Sigur, VS6.0 defineste by default WINVER 0x0400 insa pentru a preveni orice conflicte ulterioare, e bine sa-l denumesti altfel, de exemplu IDC_HANDX.
Buna idee, ca sa scap de warning-uri la compilare ...
5. De ce nu folosesti GDI+? Ai putea sa incarci mai multe formate (BMP, JPEG, GIF, TIFF, PNG, ICO) fara mare bataie de cap.
In plus, la zoom ai avea de ales intre metode de interpolare care sa dea o calitate mult mai buna decat StretchBlt cu HALFTONE.
Nu vine la pachet cu VS6.0 insa din cate stiu eu, se gaseste in ...
Proiectul real are fisiere custom care transforma datele in bitmap-uri, de aceea pentru test e suficient GDI ... m-am gandit si eu ca pot dezvolta un pic aplicatia test, cine stie ...
Totusi iata cateva observatii si recomandari:
Pentru mine, sant intotdeauna binevenite !!!
Last edited by mesajflaviu on 24 Oct 2012, 13:09, edited 1 time in total.

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 24 Oct 2012, 09:43

Acum desenez in OnDraw cu CDC::StretchBlt, si intind memory-device-context-ul in momentul desenarii ... acum merge bine.
Attachments
TestDraw6.zip
(184.9 KiB) Downloaded 202 times

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Draw overlay

Post by Ovidiu Cucu » 25 Oct 2012, 13:45

Am atasat un mic proiect demo care, cu mici exceptii face ceea ce face si al tau. In schimb e ceva mai bine organizat, si unele lucruri sunt facute mai simplu si mai clar. Daca vrei, putem discuta la fiecare, de ce asa si nu altfel.
L-am scris in scopul de a ajuta sa prinzi cate o idee, eventual comparandu-l cu al tau.
Este inca departe de a fi un "image viewer" profesional... ;)
Demo_Draw.zip
(21.74 KiB) Downloaded 206 times
Din start ideea de a scrie un text fix intr-un scroll view nu-i asa grozava pentru ca tot ce se castiga datorita scroll-ului implementat nativ in Windows se pierde cu faptul ca tot timpul esti obligat sa invalidezi (deci sa repictezi) intreaga zona client, doar ca sa-ti refreseze nenorocitul ala de text.
In plus, CScrollView are oaresce limitari la dimensiunea totala a view-ului. In cazul proiectului tau sar imediat in ochi, daca vrei sa afisezi bitmapuri mari si/sau sa faci zoom-uri bengoase.

Daca vrei sa scoti mai mult, ai urmatoarele posibilitati:
  1. Renunti sa scrii acel text direct in zona client si pastrezi CScrollView. Ai putea de exemplu sa suprapui un tooltip sau o fereastra layered, si-or mai fi si alte solutii.
  2. Ramai la ideea de a scrie textul in zona client si derivezi din CScrollView, dar atunci suprascrii si adaptezi exact la ce-ti trebuie oaresce metode virtuale.
  3. Renunti la CScrollView si derivezi direct din CView. In cazul asta in care ar trebui sa implementezi scroll-ul si alte chestii. Avantajul este ca poti trece de limitarile lui CScrollView si ca poti regandi desenarea cum vrea muschii tai.
  4. Continui pe codul care-l ai ai si aplici deviza programatorului marxist: "Din carpeala in carpeala, spre victoria finala". :)
Eu as prefera #1 sau #3. Prima daca timpul frige, a doua daca as vrea sa fac ceva mai pe asezate.

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 26 Oct 2012, 09:07

In primul rand multumesc pentru aplicatia test, merge la fel cu ce am facut eu, doar ca intr-o realizare mai simpla ... imi place cum e implementata clasa CMemDC, simpla si eficienta.

Ca solutii mi se pare buna ideea unor ferestre layered, trebuie s-o incerc ... nu prea stiu inca cum, dar sper sa iasa ...
La solutia 2 nu imi dau seama ce anume ar trebui sa virtualizez ca sa desenez overlay-uri peste bitmap ...
Solutia 3 e prea complicata (pentru mine).

Solutia 4 n-am aplicat-o niciodata (decat cand n-am avut incotro poate), si sper sa n-o aplic niciodata ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Draw overlay

Post by Ovidiu Cucu » 26 Oct 2012, 14:07

Se putea si fara acel CMemDC, insa prinde bine pentru ca-l "obliga" pe cel care-o foloseste sa aplice RAII (Resource Acquisition Is Initialization), chiar si fara sa stie ce-i aia :), scutindu-l astfel de leaks si alte surprize.

Sa faci o fereastra layered pentru acel "overlay text", nu-i mare lucru. Derivezi o clasa din CWnd. La creare ii pui stilul WS_EX_LAYERED ca sa-i poti seta o culoare transparenta si eventual sa o faci sa aiba un anumit grad de transparenta (vezi SetLayeredWindowAttributes). O faci owned de view-ul cu imaginea (ca sa sa stea tot timpul in fata ei) iar pe WM_MOVE-ul ownerului ai grija sa o muti in coltul ei. Mai ramane sa-i handluiesti WM_PAINT si sa umpli fundalul cu culoarea transparenta plus sa scrii textul si ce mai vrea muschii tai sa apara.
E mai greu de povestit decat de facut. :)
Trebuie totusi facuta mentiunea ca layered windows sunt suportate de la Windows 2000 in sus. Daca musa-i si musa-i sa mearga si pe sisteme mai vechi (desi nu stiu care darcu le mai foloseste azi) se poate un pic mai greu, cu regiuni. Dar chiar si asa, cred ca daca vreun mos care nu vrea sa renunte la NT4.0 ar vedea textul ala pe fond opac, n-ar fi asa mare catastrofa. ;)

In cele din urma, daca vrei sa elimini limitarile lui CScrollView ar trebui sau sa handluiesti WM_HSCROLL si WM_VSCROLL (sau sa suprascrii functiile virtuale care fac scroll) si sa implementezi tu singur. Nici asta nu-i chiar un capat de lume.
Despre limitarile lui WM_HSCROLL si WM_VSCROLL, si cam ce-ar trebui sa faci ca sa treci de ele, vezi sectiunea "Remarks" in documentatie: http://msdn.microsoft.com/en-us/library ... s.85).aspx

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 26 Oct 2012, 14:52

Pentru prima solutie, cea cu ferestre layered, ar mai fi ceva: sa presupunem ca pun un layer cat jumatate din view ... ce se intampla daca user-ul vrea sa "mute" imaginea cu drag&drop si incepe (pune mouse-ul jos) pe jumatatea cu layer ? Mai poate face drag&drop ?

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Draw overlay

Post by Ovidiu Cucu » 26 Oct 2012, 15:25

Poti s-o pui si pe tot ecranul daca vrei. Daca-i setezi stilul WS_EX_TRANSPARENT, trece mausul prin ea ca prin branza... :)

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Draw overlay

Post by Ovidiu Cucu » 26 Oct 2012, 20:53

Iata si un exemplu cu layered windows.
Se misca mult mai "smooth" pentru ca nu se mai invalideaza tot pe WM_HSCROLL si WM_VSCROLL iar acel overlay text nici nu flickare nici nu-i saltaret.
Of course, inca se mai pot aduce imbunatatiri. Discutam... ;)
Attachments
Demo_Draw2.zip
(23.98 KiB) Downloaded 191 times

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 26 Oct 2012, 21:32

Am testat aplicatia ... ce sa zic, decat ca nu stiti cat bine faceti cu acest forum ... :whorship:

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 29 Oct 2012, 12:29

Ovidiu Cucu wrote: Iata si un exemplu cu layered windows.
Se misca mult mai "smooth" pentru ca nu se mai invalideaza tot pe WM_HSCROLL si WM_VSCROLL iar acel overlay text nici nu flickare nici nu-i saltaret.
Of course, inca se mai pot aduce imbunatatiri. Discutam... ;)
As avea o mica intrebare: de ce SetLayeredWindowAttributes este apelata prin

Code: Select all

::GetProcAddress(hModule, "SetLayeredWindowAttributes");
si nu simplu, cu SetLayeredWindowAttributes(...) ? Am vazut ca acea metoda, _SetLayeredWindowAttributes se apleleaza o singura data ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Draw overlay

Post by Ovidiu Cucu » 29 Oct 2012, 12:40

Ba da, daca ai SetLayeredWindowAttributes in SDK atunci no problem.
Ne exista in SDK-ul care vine cu VS6.0 si de aceea am facut cu GetModuleHandle/GetProcAddress.
BTW, la versiuni mai noi, exista si in MFC CWnd::SetLayeredWindowAttributes.

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 29 Oct 2012, 13:29

Mi-am dat seama de asta dar n-am mai apucat sa corectez pentru ca a cazut codexprt-ul pentru cateva minute ...

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Draw overlay

Post by mesajflaviu » 30 Oct 2012, 14:38

Folosind aceasta clasa intr-o aplicatie MDI am observat ceva: fiecare overlay se vede deasupra tuturor view-urilor (daca am deschise 3 view-uri, se vad 3 overlay-uri pe orice view deschis) ... am incercat sa iau afara SWP_NOZORDER din SetWindowPos si sa pun view-ul ca pWndInsertAfter, fara efect ... s-ar putea rezolva aceasta problema ?
Attachments
TestDraw7.zip
(200.06 KiB) Downloaded 156 times

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Draw overlay

Post by Ovidiu Cucu » 30 Oct 2012, 18:52

E normal sa apara textul deasupra din moment ce scriu acel text intr-o fereastra top-level. Nu poti face layered (cu WS_EX_LAYERED) o fereastra child (cu WS_CHILD). De fapt ownerul acelei ferestre cu textul nu este un view (care la randul ei este child) ci fereastra top-level a aplicatiei tale, si anume main frame. Sper ca-i destul de clar, daca nu ia-l pe Spy++ si-ti spune el ce si cum.

Am implementat clasa CTextLayeredWnd la modul cel mai simplu, pentru a afisa un text single-line intr-un SDI, fara alte brizbriz-uri.
De aceea am lasat portite de scapare in caz ca cineva vrea sa faca ceva mai complicat: doua functii virtuale CTextLayeredWnd::_Draw si CTextLayeredWnd::_ResizeWindowToFit. N-am scris acolo "virtual" nici ca sa le stergi, nici ca sa ma dau "architect" care stie ce-i aia o functie virtuala... :)

Deci, lasa-l pe CTextLayeredWnd exact asa cum l-am scris eu, deriveaza si suprascrie cele doua metode de care am vorbit.
In CTextLayeredWnd::_ResizeWindowToFit ai grija sa nu iasa din zona client a view-ului si in plus sa tai zonele obturate de celelalte ferestre MDI child. E un pic de transpirat dar nu foarte-foarte greu.

Post Reply