HDC global... GetDC überschreibt alles?


  • Mod

    zu 1. selbst wenn es hilft ist es mieses Design und in meinen Augen falsch.
    zu 2. Du kannst kein Objekt selektieren und den DC danach freigeben. Das leaked ohne Ende. Punkt... Ganz egal was Du meinst.
    zu 3. Das macht Scribble (MFC) auch. D.h. Du zeichnest Due Bewegungen in einer Liste auf, und malst in WM_APINT. Was denkst Du denn, was passiert, wen Du mal den Explorer vor Deine Anwendung bringst und dann wieder minimierst. Wo sind dann Deine netten Zeichnungen?



  • Momentan geht alles bei einem Rechtsklick verloren(absicht)[Das wird wohl erst ein wenig später eingebaut, da ich um 15:45 feierabend mache ;-)].

    Wenn ich aber eine Liste mache mit den Bewegungen der Maus, dann kommt doch eine Zeitverzögerung in das Programm oder?

    zu 1. Könntest du dass begründen, evtl einen Lösungsweg dazu geben(man lernt ja nie aus) ?
    zu 2. Dass ist schon raus...

    Ahso: was ist denn das Standard-Objekt? Denn momentan wähle ich nur ein anderes(was im Pointer gespeichert ist) und benutze es



  • Beim ersten Aufruf von SelectObject() bekommst du ein Handle zurück. Das ist das Standardobjekt. Sichern und nachher wieder selektieren. Fertig.

    Und was die Liste mit den Bewegungen angeht: Die Zeitverzögerung wirst du nicht merken.



  • Danke.
    Habe es jetzt so eingestellt.

    Jetzt werde ich mal überlegen wie ich dass mit dem PAINT malen fertig kriege.


  • Mod

    1. Ein HDC ist eine temporäres Handle, SOlch ein Handle holt man sich seltenst sondern man bekomt es geliefert (WM_PAINT)
    2. Ein DC verliert seine GTültigkeit mit dem ReleaseDC. Wieso sollte man also ein HDC speichern, dass sowieso ungültig ist.. und wenn DU den DC nicht frei gibst, dann ist dies eine Ressourcenverschwendung ohne Ende und es würde mich nicht wundern wenn Dein programm innerhalb eines gewissen Zeitarumes aus dem Ruder läuft.

    BTW: Du hast auf meinen Einwurf /3.) nicht geantwortet.
    Was passiert, wenn der User Alt+Tab macht. Dann ist ales gemalte weg oder wie?



  • Erstaunlicher weise nicht...
    Da ich allerddings gelesen hatte, das es passieren sollte habe ich probiert... Es verschwindet alles wenn man das Fenster neu Skalliert(was nicht möglich ist) oder es unter die Startleiste schiebt(also aus dem Bildschirm raus)...

    Zumindest unter Vista...

    ReleasDC ist doch zur freigabe von DC oder?

    1. verstehe ich nicht, entweder ist dein Satz falsch (unverständlich) oder ich habe ein falsches WM_PAINT...
    Auch in WM_PAINT muss ich ein HDC deklarieren...



  • lippoliv schrieb:

    Erstaunlicher weise nicht...
    Da ich allerddings gelesen hatte, das es passieren sollte habe ich probiert... Es verschwindet alles wenn man das Fenster neu Skalliert(was nicht möglich ist) oder es unter die Startleiste schiebt(also aus dem Bildschirm raus)...

    Eben. Immer, wenn Du irgendwas mit dem Fenster machst, sendet Windows eine WM_PAINT. In der Standardbearbeitung (DefWindowProc) wird einfach das Fenster samt Hintergrund neu gezeichnet. Alles, was dann nicht in WM_PAINT gezeichnet wurde, verschwindet.

    1. verstehe ich nicht, entweder ist dein Satz falsch (unverständlich) oder ich habe ein falsches WM_PAINT...
    Auch in WM_PAINT muss ich ein HDC deklarieren...

    Unter WM_PAINT ist der hDC der Rückgabewert von BeginPaint(). Alles das muß dann mit EndPaint() abgeschlossen werden.



  • Ok dass verstehe ich.
    Habe ich doch bis jetzt auch gemacht (in WM_PAINT)...

    Ne frage zu dem Array... Muss ich alles drin speichern oder nur den letzten schritt?

    Ich meine WM_PAINT überschreibt deralles was vorher war, oder behält er dass von davor in sich?

    [EDIT]

    //glob.vars
    HPEN *aktPen;
    [...]
    COORD myPoint,
          mouseKoord;
    HDC myHdc;
    HWND myWnd;
    [...]
        case WM_PAINT:
            //zum Zeichnen anmelden
            myHdc = BeginPaint( myWnd, &myPaint );
            {
                stdForm( myPaint, myRect, myWnd, myHdc );
                if( myPoint.x != -1 )
                {
                    printf( "." );
                    backUp = SelectObject( myHdc, *aktPen );
                    MoveToEx(
                        myHdc,		//Zeichenfläche
                        myPoint.x,	//X-Koordinate
                        myPoint.y,	//Y-Koordinate
                        NULL		  //old-Koordinate
                    );
                    LineTo(
                        myHdc,//Zeichenfläche
                        mouseKoord.X,	//X-Koordinate
                        mouseKoord.Y	 //Y-Koordinate
                    );
                    SelectObject( myHdc, backUp );
                }
            }
        EndPaint( myWnd, &myPaint );
        break;
        [...]
        case WM_MOUSEMOVE:
            if( myPoint.x != -1 )
            {
                SendMessage( myAppWnd, WM_PAINT, 0, 0 );//send WM_PAINT so that the painting is just standing, if the window will be resized
                myPoint.x = LOWORD(lParam);//set new coordinates
                myPoint.y = HIWORD(lParam);
            }
            else
            {
                myPoint.x = LOWORD(lParam);//The first coordinates
                myPoint.y = HIWORD(lParam);
            }
        break;
    [...]
    

    Das funktioniert nicht... er macht punkte( Z: 16 ) aber... naja... er malt nicht.



  • Was übergibst Du denn da an BeginPaint()? Ist &myPaint der Zeiger auf die PaintStruct?
    Normalerweise sollte das so aussehen:

    case WM_PAINT:
          {
             PAINTSTRUCT    myPaint;
             HDC            hDC;
    
             hDC = BeginPaint(hWnd, &myPaint);
    

    Dies nur, weil Du die Deklaration unterschlagen hast. 😉
    zum Spechern der Punkte solltest du eine POINT-Variable anlegen, die sind schon vordefiniert:

    The POINT structure defines the x- and y- coordinates of a point. 
    
    typedef struct tagPOINT { // pt  
        LONG x; 
        LONG y; 
    } POINT; 
    
    Members
    
    x
    Specifies the x-coordinate of the point. 
    
    y
    Specifies the y-coordinate of the point.
    

    COORD benutzt man eigentlich nur für Consolen-Ausgaben.

    Jetzt zu Deinem Problem: Natürlich mußt Du deine gezeichneten Punkte zwischenspeichern und unter WM_PAINT ausgeben. Du hast aber nur eine Variable dafür angelegt. Wenn Du nur jeweils einen Punkt speicherst, wird auch nur der ausgegeben. Du kannst die Punkte in einem Array speichern (muß evtl. redimensioniert werden, wenn Du die Zeichnung erweiterst) und dann unter WM_PAINT zeichnen lassen.



  • Naja die idee ist:
    Ich speichere den aktuellen Punkt.

    Wenn es schon einen Punkt gibt(zwischengespeichert), dann ziehe ich erst eine Linie zwischen den beiden Punkten und speichere den aktuellen zwischen.
    got Naja die idee ist;
    😉

    So brauche ich nicht ein array für das gesamte Bild oder!?

    PS: myPaint ist ein PAINTSTRUCT sry... vergessen



  • Dann bräuchtest Du zwei POINT-Variablen, hast aber unter WM_MOUSEMOVE nur eine angelegt. WM_PAINT liefert keine Mauskoordinaten.
    Der Effekt ist halt, wenn Du alles vorherige nicht gespeichert hast, wird das durch die WM_PAINT erstmal gelöscht. Dann zeichnet BeginPaint Deine Linie, hat aber nur den aktuellen Punkt dafür, die vorherigen nicht. Du mußt also die vorherigen Aktionen zwischenspeichern und bei WM_PAINT neu ausführen.

    Übrigens bewirkt man das Aktualisieren des Fensters nicht mit SendMessage(...WM_PAINT...), sondern mit InvalidateRect().



  • Ja das Tue ich doch...

    LRESULT CALLBACK WndProc( HWND myWnd, UINT givenMessage, WPARAM wParam, LPARAM lParam )
    /*
    	This function recieves the Messages, wich are given from MS-Windows to the program.
    	So the program can do message specific actions, if this message is incoming.
    */
    {
    	PAINTSTRUCT myPaint;
    	//Handle für Gerätekontext(gültiger Zeichenbereich)
    	BOOL visitMsg = FALSE;
    
    	static POINT myPoint;
    
    	static RECT myRect;
    
    	static BOOL isPainting;
    
    	static COORD mouseKoord;
    
    	HANDLE backUp;
    
    	if( LOWORD(lParam) != 0 || HIWORD(lParam) != 0)
    	{
    		mouseKoord.X = LOWORD(lParam);	//took the mouse-coordinates into a COORD variable (perfomance)
    		mouseKoord.Y = HIWORD(lParam);
    	}
    
    	switch( givenMessage )
    	{
    		case WM_PAINT:
    			//zum Zeichnen anmelden
    			myHdc = BeginPaint( myWnd, &myPaint );
    			{
    				stdForm( myPaint, myRect, myWnd, myHdc );
    				if( myPoint.x != -1 )
    				{
    					backUp = SelectObject( myHdc, *aktPen );
    					MoveToEx(
    							myHdc,		//Zeichenfläche
    							myPoint.x,	//X-Koordinate
    							myPoint.y,	//Y-Koordinate
    							NULL		//old-Koordinate
    					);
    					LineTo(
    						myHdc,			//Zeichenfläche
    						mouseKoord.X,	//X-Koordinate
    						mouseKoord.Y	//Y-Koordinate
    					);
    					SelectObject( myHdc, backUp );
    				}
    			}
    			EndPaint( myWnd, &myPaint );
    			visitMsg = TRUE;
    		break;
    		case WM_MOUSEMOVE:
    			myHdc = GetDC( myWnd );			//open device-context (paintplace)
    			{
    				if( !isPainting )			//Wenn der 
    				{
    					if( inRect( mouseKoord, blackColor ) )
    					{
    						aktPen = &blackPen;								//slect black pen
    
    						R = 0;
    						G = 0;
    						B = 0;
    					}
    					else if( inRect( mouseKoord, whiteColor ) )
    					{
    						aktPen = &whitePen;								//select white pen
    
    						R = 255;
    						G = 255;
    						B = 255;
    					}
    					else if( inRect( mouseKoord, smallSize ) )
    					{
    						DeleteObject( aktPen );
    						*aktPen = CreatePen( PS_SOLID, 1, RGB( R, G, B ) );
    					}
    					else if( inRect( mouseKoord, middleSize ) )
    					{
    						DeleteObject( aktPen );
    						*aktPen = CreatePen( PS_SOLID, 3, RGB( R, G, B ) );
    					}
    					else if( inRect( mouseKoord, bigSize ) )
    					{
    						DeleteObject( aktPen );
    						*aktPen = CreatePen( PS_SOLID, 4, RGB( R, G, B ) );
    					}
    				}
    				else
    				{
    					if( myPoint.x != -1 )
    					{
    						SendMessage( myAppWnd, WM_PAINT, 0, 0 );	//send WM_PAINT so that the painting is just standing, if the window will be resized
    						myPoint.x = mouseKoord.X;					//set new coordinates
    						myPoint.y = mouseKoord.Y;
    					}
    					else
    					{
    						myPoint.x = mouseKoord.X;//The first coordinates
    						myPoint.y = mouseKoord.Y;
    					}
    				}
    			}
    			ReleaseDC( myWnd, myHdc );
                visitMsg = TRUE;
    		break;
    		case WM_LBUTTONDOWN:
    			isPainting = TRUE;
    			visitMsg = TRUE;
    		break;
    		case WM_LBUTTONUP:
    			isPainting = FALSE;
    
    			myPoint.x = -1;
    			myPoint.y = -1;
    
    			visitMsg = TRUE;
    		break;
    		case WM_RBUTTONDOWN:
    			DeleteObject( whitePen );
    			DeleteObject( blackPen );
    			setGlobalVars();
    			InvalidateRect(
    							myWnd,
    							NULL,
    							TRUE
    			);
    
    			visitMsg = TRUE;
    		break;
    		default:
    		break;
    	}
    
    	if( visitMsg )
    		return 0;
    	else
    		return DefWindowProc( myWnd, givenMessage, wParam, lParam );
    }
    

    Min invalidate rect, hackts ur wenn ich das Fenster erneuere... also beim malen zuckt mein "Form" total zusammen



  • Na endlich mal ein bißchen mehr Code... :p
    Unter WM_MOUSEMOVE fragst Du keine Koordinaten ab, sondern ordnest nur MouseKoord an MyPoint zu. Das bringt nichts.
    Dieser Abschnitt

    if( LOWORD(lParam) != 0 || HIWORD(lParam) != 0)
        {
            mouseKoord.X = LOWORD(lParam);    //took the mouse-coordinates into a COORD variable (perfomance)
            mouseKoord.Y = HIWORD(lParam);
        }
    

    gehört auch unter WM_MOUSEMOVE. Sonst werden die aktuellen Koordinaten nicht aus der WM_MOUSEMOVE-Message genommen.
    Danach verschiebst Du die Maus und speicherst die neuen Koordinaten in myPoint. Damit hast Du zwei Punkte, die unter WM_PAINT abgefragt werden können.



  • Elektronix schrieb:

    Sonst werden die aktuellen Koordinaten nicht aus der WM_MOUSEMOVE-Message genommen.

    Diese Koordinaten sollen immer aktuell sein, ob mousemove oder nicht... sie werden überall wieder verwednet, damit ich nicht immer auf LO und HIWORD zurückgreife...

    Ob sie da stehen oder in Mousemove... macht dass einen Unterschied?



  • lippoliv schrieb:

    Elektronix schrieb:

    Sonst werden die aktuellen Koordinaten nicht aus der WM_MOUSEMOVE-Message genommen.

    Diese Koordinaten sollen immer aktuell sein, ob mousemove oder nicht... sie werden überall wieder verwednet, damit ich nicht immer auf LO und HIWORD zurückgreife...

    Wieso, das tust Du doch ohnehin. Nur eben permanent und ohne Zusammenhang.

    Ob sie da stehen oder in Mousemove... macht dass einen Unterschied?

    Ja. Das Fenster wird noch mit einem Haufen anderer WM-Nachrichten bombardiert, die in lParam immer andere (oder auch gar keine) Werte enthalten. Damit kannst Du beim Zeichnen nichts anfangen. Die aktuellen Koordinaten bekommst Du nur mit den Mouse- oder Button-Nachrichten (oben aufgezählt), dazu sind die da!



  • Ja ist ja kein Problem oder?
    Ich nehme ja nur welche an wo HO oder LO != 0 ist/sind.
    Und fürs Zeichnen bekomme ich dann ja immer die Aktuellsten Koordinaten...

    Ich habe es jetzt umgebaut, und selbst da funktioniert es nicht.

    1. Ich kriege keine striche,
    2. es zuckt...



  • Programmier doch mal ein Textfeld, wo Du Dir die angeblichen Koordinaten anzeigen läßt. Dann wirste es ja sehen.



  • Ich soll, weil mein Form zuckt und keine Striche erscheinen, ein Textfeld Programmieren?

    Ich bin -glaube ich- auf dem so ziemlich untesten Level der Fensterprogrammierung.. ein Textfeld ist da noch weit weg glaube ich.



  • Nö, ein Textfeld ist genau auf dem untersten Level 😃

    http://msdn2.microsoft.com/en-us/library/ms632679.aspx
    mit EDIT als lpClassName. Ganz einfach, oder?



  • Trotzdem, was sollte mir das Helfen? Das Problem vergeht nicht, während ich ein anderes Programm schreibe.


Anmelden zum Antworten