Linien und Schriften verlieren nach kurzer Zeit Formatierung



  • Hallo zusammen,

    ich bin relativer Windows-Programmierungs-Anfänger und nutze Visual C++ Express 2010 und Windows 7.

    Mein Programm erstellt ein Fenster, und in diesem Fenster nochmals ein Fenster, das 100 mal pro Sekunde durch einen Timer per WM_PAINT neu gezeichnet wird.

    In dem inneren Fenster wird eine rote Linie gezeichnet, aber nach 2 Minuten und 34 Sekunden (bzw. wenn das Fenster nur 50 mal pro Sekunde gezeichnet wird nach 5 Minuten und 8 Sekunden, also genau der doppelten Zeit), "vergisst" Windows die Linienfarbe sowie Schriftarten (aus Arial wird in dem Fenster dann die Standardschrift) und es werden auch keine Messageboxes mehr ausgegeben.

    Ich habe den Code mal stark gekürzt, ist aber funktionsfähig und der Fehler tritt auf.

    Lösche ich die evtl. die Objekte nicht richtig?

    Hier der Code, in dem ich den Fehler vermute (ganz unten der komplette Code):

    case WM_PAINT:
                hdc_map = BeginPaint(hwnd, &ps_map); // begin painting
    
                hPaintColorGrey = SelectObject(hdc_map, CreatePen(PS_SOLID, 0, RGB(255, 50, 50)));    // creating a handle for a red color
    
                MoveToEx(hdc_map, 0, 96, NULL);    // move cursor to position, end line of a block
                LineTo(hdc_map, 488, 96);            // draw line
    
                DeleteObject(hPaintColorGrey);        // delete brush and color handles
                DeleteObject(CreatePen(PS_SOLID, 0, RGB(255, 50, 50)));    // delete brush and color handles
                DeleteObject(SelectObject(hdc_map, CreatePen(PS_SOLID, 0, RGB(255, 50, 50))));    // delete brush and color handles
    
                EndPaint(hwnd, &ps_map); // end painting
    
                return(0);
    

    Hier noch der komplette Code:

    #include <windows.h>
    
    // Definition of the functions for window-handling
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);        // declaration of the main window proc function
    LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);    // declaration of the map window proc function
    
    static HWND    hwndChild_map;                                    // handle for the map window
    
    // Hauptfenster
    int WINAPI WinMain(    HINSTANCE    hInstance,
                        HINSTANCE    hPrevInstance,
                        PSTR        szCmdLine,
                        int            iCmdShow)
        {
        static TCHAR    szAppName[] = TEXT("CDROID");        // Name des Hauptfenster
        HWND            hwnd;
        MSG                msg;
        WNDCLASS        wndclass;
    
        // Definition der Fensterklasse für das Hauptfenster
        wndclass.style            = CS_HREDRAW | CS_VREDRAW;                // Bei Größenänderung neuzeichnen
        wndclass.lpfnWndProc    = WndProc;                                // Bezeichner der Fensterklasse, über den festgelegt wird, welche Callback-Funktion welche Klasse benutzt, unabhängig davon, wann die Klasse mit RegisterClass registriert wurde
        wndclass.cbClsExtra        = 0;
        wndclass.cbWndExtra        = 0;                                    // wieviele Byte für das Fenster zusätzlich reserviert werden sollen
        wndclass.hInstance        = hInstance;
        wndclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);        // Es wird kein Fenstericon geladen
        wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);            // Der Standardcursor wird verwendet
        wndclass.hbrBackground    = (HBRUSH) GetStockObject(WHITE_BRUSH);    // Das Fenster wird mit einer weißen Hintergrundfarbe gefüllt
        wndclass.lpszMenuName    = NULL;                                    // Es wird kein Menü verwendet
        wndclass.lpszClassName    = szAppName;                            // Der Name der Fensterklasse
        RegisterClass(&wndclass);
    
        // definition of window class for map window
        wndclass.lpfnWndProc    = ChildWndProc;
        wndclass.cbWndExtra        = sizeof(long);                            // wieviele Byte für das Fenster zusätzlich reserviert werden sollen (in diesem Fall 4)
        wndclass.hIcon            = NULL;
        wndclass.lpszClassName    = TEXT("Map");                        // class name
        RegisterClass(&wndclass);
    
        hwnd = CreateWindow(szAppName,
                            TEXT("CDROID"),                                // Name des Fensters in der Titelleiste
                            WS_DLGFRAME | WS_MINIMIZEBOX,                // ohne Schaltflächen, minimierbar, feste Größe
                            10,                                            // Startposition des Fensters von links
                            10,                                            // Startposition des Fensters von rechts
                            1400,                                        // Breite
                            1000,                                        // Höhe
                            NULL,                                        // Übergeordnetes Fenster
                            NULL,                                        // Instanzname für Rückmeldungen an das übergeordnete Fenster
                            hInstance,
                            NULL);
    
        // Fenster anzeigen
        ShowWindow(hwnd, iCmdShow);
    
        // Inhalt anzeigen
        UpdateWindow(hwnd);
    
        // Nachrichtenverarbeitung
        while(GetMessage(&msg, NULL, 0, 0))
            {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            }
    
        return(0);
        }
    
    HDC            hdc_hwnd;    // Handle auf den Anzeigebereich (Gerätekontext)
    PAINTSTRUCT    ps_hwnd;
    
    // Befehlsverarbeitung für das Hauptfenster
    LRESULT CALLBACK WndProc(    HWND    hwnd,
                                UINT    message,
                                WPARAM    wParam,
                                LPARAM    lParam)
        {
        switch(message)
            {
            case WM_CREATE: // creation of the main window
                hwndChild_map = CreateWindow(                    TEXT("Map"),
                                                                NULL,
                                                                WS_CHILDWINDOW | WS_BORDER,
                                                                10,
                                                                10,
                                                                490,
                                                                490,
                                                                hwnd,
                                                                (HMENU) (13),
                                                                (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
                                                                NULL);
    
                ShowWindow(hwndChild_map, SW_SHOW); // show map window
    
                SetTimer(hwnd, 1, 10, NULL); // set timmer; 100 times per second for calculating the movement
    
            case WM_TIMER:
                switch(wParam)
                    {
                    case 1:
                        InvalidateRect(hwndChild_map, NULL, TRUE);            // invalidate the map window area
    
                        break;
                    }
    
                return(0);
    
            case WM_DESTROY:
                KillTimer(hwnd, 1); // kill timer
    
                PostQuitMessage(0); // Schließen des Hauptfensters
    
                return(0);
            }
    
        return(DefWindowProc(hwnd, message, wParam, lParam));
        }
    
    HDC            hdc_map;
    PAINTSTRUCT    ps_map;
    HGDIOBJ        hPaintColorGrey;
    
    LRESULT CALLBACK ChildWndProc(    HWND    hwnd,
                                    UINT    message,
                                    WPARAM    wParam,
                                    LPARAM    lParam)
        {
        switch(message)
            {
            case WM_CREATE:
                return(0);
    
            case WM_PAINT:
                hdc_map = BeginPaint(hwnd, &ps_map); // begin painting
    
                hPaintColorGrey = SelectObject(hdc_map, CreatePen(PS_SOLID, 0, RGB(255, 50, 50)));    // creating a handle for a red color
    
                MoveToEx(hdc_map, 0, 96, NULL);    // move cursor to position, end line of a block
                LineTo(hdc_map, 488, 96);            // draw line
    
                DeleteObject(hPaintColorGrey);        // delete brush and color handles
                DeleteObject(CreatePen(PS_SOLID, 0, RGB(255, 50, 50)));    // delete brush and color handles
                DeleteObject(SelectObject(hdc_map, CreatePen(PS_SOLID, 0, RGB(255, 50, 50))));    // delete brush and color handles
    
                EndPaint(hwnd, &ps_map); // end painting
    
                return(0);
            }
    
        return(DefWindowProc(hwnd, message, wParam, lParam));
        }
    


  • hdc_map = BeginPaint(hwnd, &ps_map); // begin painting
    hPaintColorGrey = SelectObject(hdc_map, CreatePen(PS_SOLID, 0, RGB(255, 50, 50)));    // SelectObject liefert den alten Pen
    MoveToEx(hdc_map, 0, 96, NULL);    // move cursor to position, end line of a block
    LineTo(hdc_map, 488, 96);            // draw line
    DeleteObject(hPaintColorGrey);        // löscht den alten Pen 
    DeleteObject(CreatePen(PS_SOLID, 0, RGB(255, 50, 50)));    // ??? wozu
    DeleteObject(SelectObject(hdc_map, CreatePen(PS_SOLID, 0, RGB(255, 50, 50))));    // ??? wozu
    EndPaint(hwnd, &ps_map); // end painting
    

    Du wollstest wahrscheinlich Folgendes machen

    hdc_map = BeginPaint(hWnd, &ps_map); // begin painting
    HPEN hPaintColorGrey = CreatePen(PS_SOLID, 0, RGB(255, 50, 50)); // creating a handle for a red color
    HGDIOBJ hpenOld = SelectObject(hdc_map, hPaintColorGrey);    // hPaintColorGrey in den Device-Kontext
    MoveToEx(hdc_map, 0, 96, NULL);    // move cursor to position, end line of a block
    LineTo(hdc_map, 488, 96);            // draw line
    
    DeleteObject(SelectObject(hdc_map,hpenOld)); // alten Pen setzen, hPaintColorGrey löschen
    EndPaint(hWnd, &ps_map); // end painting
    


  • Um das noch einmal klar zu stellen:
    Du erstellst jeweils einen neuen Pen (im ersten Sel.Obj), löschst ihn aber nicht mehr, da du nur den zuvor eingewählten (Default-) Pen zerstörst. Windows stellt diesen zwar immer wieder her, ist aber wahrscheinlich alles andere als glücklich dabei.
    Du solltest einmal im Taskmanager beobachten, wie sich die Anzahl der GDI-Objekte bei jedem Neuzeichnen erhöht. Die letzte beiden DeleteObjects führen natürlich zu nichts (sind aber auch nicht das Problem).



  • Hallo,

    vielen Dank für deine Hilfe!
    Jetzt kapier ich das 🙂

    Viele Grüße!


Anmelden zum Antworten