Toon posts:

[VC++/GDI] Raar gedrag binnen CDC

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hoi,

Ik loop al een tijdje tegen een vage bug aan waarvan ik de oorzaak maar niet kan achterhalen. De situatie:

Voor de weergave van een grafiek, die veranderlijk is door met de muis over het dingetje te slepen, trigger ik in een bepaald geval voor iedere OnMouseMove event voor een venstertje een repaint aan met
code:
1
InvalidateRect(NULL,false);


Vervolgens wordt in OnDraw de volgende code uitgevoerd:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
void CCdcView::OnDraw(CDC* pDC)
{
    CCdcDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    CPen *oldPen;

try {    // gekunstelde try catch om te checken dat er geen ontoelaatbare dingen gebeuren
    CRect clientArea;
    GetClientRect(&clientArea);
    int height = clientArea.Height();
    int width  = clientArea.Width();

    if(resize) { // resize is true via OnSize event en bij eerste aanroep
        background.CreateCompatibleBitmap(pDC, width, height);
        pDC->FillRect(clientArea, &CBrush(RGB(0,0,0)));
        resize = false;
    }

    try {
        calculate();
    } catch(...) {      // alle mogelijke fouten (divide by zero... etc)
        exit(0);
    };
    
    CDC dc;
    dc.CreateCompatibleDC(pDC);
    dc.SelectObject(background);

    dc.BitBlt(0,0, width, height, NULL, 0,0, BLACKNESS); // zwarte achtergrond
    

    CPen pen;
    pen.CreatePen(PS_SOLID, 1, RGB(80,80,200)); // binnen dc nog niets geselecteerd dus hoef de oude cpen ook niet op te slaan, right?
    dc.SelectObject(pen);
    pen.DeleteObject();   // kan ook aan het einde van de functie, maakt niet uit

    // bereken verschaling
    float schaal_x = (float) (clientArea.Width() / 117);
    float schaal_y = (float) (clientArea.Height() / 45);

    
    
    // bell filter
    CPen pen2;
    pen2.CreatePen(PS_SOLID, 1, RGB(255,0,0));
    dc.SelectObject(pen2);
    pen2.DeleteObject();

    dc.MoveTo( 0,
        (int)((height-calc_results[1] * schaal_y) - height/2) // calc_result is een array dat wordt gevuld door calculate(), waarden voor x en y vallen gegarandeerd binnen mn client area
        );


    for(int i=2; i<129; i++) {    // tekent de grafiek
        dc.LineTo(
        (int)(i*schaal_x), 
        (int)(height-calc_results[i] * schaal_y) - height/2);
        }

    top = CPoint((int)(fc * schaal_x),  // en een mooi groen vakje aan de top
        (int) ((height-calc_results[fc] * schaal_y) - height/2) );

    CPen pen3;
    pen3.CreatePen(PS_SOLID, 2, RGB(0,255,0));
    dc.SelectObject(pen3);
    pen3.DeleteObject();

    dc.Rectangle(top.x-2, top.y-2, top.x+2, top.y+2);

    if( ((height-calc_results[fc] * schaal_y) - height/2) < height/2)
        pDC->ExcludeClipRect(0,(int)(height/2)+height/5, width, height);
    else
        pDC->ExcludeClipRect(0, 0, width, (int)(height/2)-height/5);

    pDC->BitBlt(0,0, width, height, &dc, 0,0, SRCCOPY); // kopieeren dc naar huidige context

    dc.DeleteDC();
    }
catch(...) { 
        exit(0);   // knalt er noooit uit
    };
}


Ik weet dat ik niet al te gratieus codeer, ben dan ook geen programmeur maar elektrotechnicus van beroep. Sorry

Het vage is nu dat na deze functie een keer of wat is aangeroepen (niet te debuggen waar precies, geen aanwijzbare directe oorzaak) de kleuren van mijn cpen's zwart worden. Zelf zat ik te denken aan een onopgeruimd opbject ergens, maar die kan ik nergens vinden, ook niet buiten deze functie. Bovendien blijft het geheugengebruik erg bescheiden.

Iemand enig idee?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

MFC is niet m'n sterkste kant, maar waarom alloceer je pen3, select je 'm in de DC en delete je 'm vervolgens direct *terwijl hij nog erin selected zit*? :?

En wist dat je in Task Manager in het View menu een 'Show columns...' optie hebt waardoor je realtime GDI Object count kunt bekijken van je proces? *hint* :Y)

Professionele website nodig?


  • The End
  • Registratie: Maart 2000
  • Laatst online: 21:38

The End

!Beginning

De nette methode om objecten te selecteren is dit:

code:
1
2
3
4
5
6
7
CPen BluePen(PS_SOLID,1,RGB(0,0,255));
CPen *OldPen = CurDC.SelectObject(&BluePen);

//Doe wat

CurDC.SelectObject(OldPen);
BluePen.DeleteObject();

Verwijderd

Topicstarter
curry684 schreef op 01 december 2003 @ 12:16:
MFC is niet m'n sterkste kant, maar waarom alloceer je pen3, select je 'm in de DC en delete je 'm vervolgens direct *terwijl hij nog erin selected zit*? :?

En wist dat je in Task Manager in het View menu een 'Show columns...' optie hebt waardoor je realtime GDI Object count kunt bekijken van je proces? *hint* :Y)
Het lijkt niet uit te maken waneer ik pen1,2 of 3 opruim, als ze eenmaal geselect zijn kun je er mee tekenen; hij kopieert slecht de eigenschappen van de pen, niet het object als zodanig. Opruimen aan het einde van de functie geeft het zelfde effect en daarom heb ik tijdens het opruimen van de procedure ze maar even zo dicht mogelijk bij elkaar gezet, om overzicht te houden.

Wat betreft de tweede tip: Thx, maar ik programmeer onder win98. (ik realiseer me dat je nu in lachen uitbarst maar ik als stagiar wordt een ouwe pc toebedeeld en de mogelijkheid dat de baas even een extra pakketje windows 2000 aanschaft blijkt binnen dit bedrijf niet aanwezig |:( ) Er zit dus niet zo'n optie in mijn taskmanager...

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

The End schreef op 01 december 2003 @ 12:30:
De nette methode om objecten te selecteren is dit:

code:
1
2
3
4
5
6
7
CPen BluePen(PS_SOLID,1,RGB(0,0,255));
CPen *OldPen = CurDC.SelectObject(&BluePen);

//Doe wat

CurDC.SelectObject(OldPen);
BluePen.DeleteObject();
Zoals ik al zei, MFC is niet m'n sterkste kant en ik heb er soms nog wel eens hoop op dat ie dingen slimmer aanpakt, maar blijkbaar moet je het met MFC dus ook nog op de klassieke algemene Win32 manier doen zoals je hier correct demonstreert :)

Professionele website nodig?


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Je doet bij alle pennen een Create , Select , Delete

Het is de bedoeling dat je
Create

oldObject = SelectObject( ..... )

Draw(.......)

SelectObject ( oldobject )

DeleteObject ( ..... )

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Verwijderd schreef op 01 december 2003 @ 12:31:
[...]
Het lijkt niet uit te maken waneer ik pen1,2 of 3 opruim, als ze eenmaal geselect zijn kun je er mee tekenen; hij kopieert slecht de eigenschappen van de pen, niet het object als zodanig. Opruimen aan het einde van de functie geeft het zelfde effect en daarom heb ik tijdens het opruimen van de procedure ze maar even zo dicht mogelijk bij elkaar gezet, om overzicht te houden.

Wat betreft de tweede tip: Thx, maar ik programmeer onder win98. (ik realiseer me dat je nu in lachen uitbarst maar ik als stagiar wordt een ouwe pc toebedeeld en de mogelijkheid dat de baas even een extra pakketje windows 2000 aanschaft blijkt binnen dit bedrijf niet aanwezig |:( ) Er zit dus niet zo'n optie in mijn taskmanager...
Dat je onder Win98 ontwikkelt maakt het echter wel verschrikkelijk veel relevanter. Je hoort zoals The End aangeeft je objecten uit de DC te 'unselecten' voordat je ze delete, anders raak je ze kwijt, en onder Win98 is er volgens mij een GDI object limit van 16384 per proces, oftewel ik gok dat je na 16384 paints ineens geen pens meer kunt gebruiken.

Hint: koop de bijbel, hij is z'n geld waard :)

[ Voor 12% gewijzigd door curry684 op 01-12-2003 12:38 ]

Professionele website nodig?


Verwijderd

Topicstarter
Als ik een nieuwe DC aanmaak staat er toch nog geen object in geselecteerd? Hoe kan ik dan het oude object opslaan?

ik doe:
code:
1
2
CDC dc;
    dc.CreateCompatibleDC(pDC);


en selecteer dan een pen, voor een nieuw dc bestaat er toch geen geselecteerd item? Wat retouneert het beestje dan?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Verwijderd schreef op 01 december 2003 @ 12:42:
Als ik een nieuwe DC aanmaak staat er toch nog geen object in geselecteerd? Hoe kan ik dan het oude object opslaan?

ik doe:
code:
1
2
CDC dc;
    dc.CreateCompatibleDC(pDC);


en selecteer dan een pen, voor een nieuw dc bestaat er toch geen geselecteerd item? Wat retouneert het beestje dan?
Er zit op dat moment een stock object (hint: een zwarte pen) in geselecteerd, dat is ook het probleem niet. Het probleem is wel dat je die bij het destroyen van de DC er terug in moet douwen, en dat je op dat moment de door jouzelf aangemaakte pen netjes vernietigt.

Professionele website nodig?


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 17:13

BoAC

Memento mori

Een BOOL als het goed gaat ongelijk aan FALSE ;) (Zie msdn Library)
Help bij select object
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CDC::SelectObject  
CPen* SelectObject( CPen* pPen );

CBrush* SelectObject( CBrush* pBrush );

virtual CFont* SelectObject( CFont* pFont );

CBitmap* SelectObject( CBitmap* pBitmap );

int SelectObject( CRgn* pRgn );

Return Value

A pointer to the object being replaced. 
This is a pointer to an object of one of the classes derived from CGdiObject, 
such as CPen, depending on which version of the function is used. 
The return value is NULL if there is an error. 
This function may return a pointer to a temporary object. 
This temporary object is only valid during the processing of one Windows message. 
For more information, see CGdiObject::FromHandle.

Het is dus altijd handig(raadzaam) om de oude terug te zetten ;) anders krijg je dus zwarte(invalid) teken acties

[ Voor 1% gewijzigd door BoAC op 01-12-2003 12:51 . Reden: Vanwege layout ]


Verwijderd

Topicstarter
Ok, heb het geprobeerd maar krijg:

C:\cpp\cdctest\cdc\cdcView.cpp(106) : error C2440: '=' : cannot convert from 'void *' to 'class CPen *'

voor:
code:
1
2
3
4
Cpen *oldPen;
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(80,80,200));
oldPen = dc.SelectObject(pen);   // retouneert void*??


Toch moet het zo volgens bovenstaande voorbeelden...

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Ik zou CPen met een hoofdletter P schrijven, C++ is case-sensitive. De compiler zal als het goed is eerst een error geven op de declaratie van oldPen, en daarna verder proberen te compileren als void*.

Daarnaast vergeet je de address-of operator in de SelectObject parameter (zoals in bovenstaande voorbeelden aangegeven).

Professionele website nodig?


Verwijderd

Topicstarter
Thanx... het werkt... _/-\o_
Pagina: 1