Click here to Skip to main content
15,888,527 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
For some time now I have been trying to resolve the WM_PAINT code or my application. Every advise I have ever been given on this issue, I have applied.

Someone said I should carry out all the DC operations in WM_PAINT. I did that.

Someone said I should display output calculatedly. I have already tried a trillion o different calculations.

Although my apps documents consist of one or more several pages, each page consists of different graphics that are rendered arbitrarily.

When I render directly to the window dc, the display is usually perfect except for flickering during scrolling.

In order to solve the flickering problem, I decided to use double line buffering which works well only on the first page, after which display goes haywire.

The relevant codes are shown below:
C++
case WM_CREATE:

 SetAppScrollInfo(hWnd, iPageWidth, iPageHeight);
        HDC hDC = GetDC(hWnd);
        tuple Tuple = GetAppDocumentSize(hWnd, hDC, iPageWidth, iPageHeight, eResultActionType);
       
        hMemDC = CreateCompatibleDC(hDC);

        iScreenWidth = GetSystemMetrics(SM_CXSCREEN);
        iScreenHeight = GetSystemMetrics(SM_CYSCREEN);

        hBitmap = CreateCompatibleBitmap(hDC, iScreenWidth, iScreenHeight);
        hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);

        PrepareMemDC(hMemDC);
        RECT rc;
        rc.left = 0;
        rc.top = 0;
        rc.right = iScreenWidth;
        rc.bottom = iScreenHeight;

        HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
        FillRect(hMemDC, &rc, hBrush);
        
        ReleaseDC(hWnd, hDC);

C++
case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code that uses hdc here...
        tuple Tuple = GetAppDocumentSize(hWnd, hdc, iPageWidth, iPageHeight, eResultActionType);
        double dOneMMX = get<0>(Tuple);
        double dOneMMY = get<1>(Tuple);
        int iOffsetX = get<2>(Tuple);
        int iOffsetY = get<3>(Tuple);
        int iHPos = get<4>(Tuple);
        int iVPos = get<5>(Tuple);
        PrepareMemDC(hMemDC, iHPos, iVPos);
         
        WriteForWindowDC(hWnd, hMemDC, vClassResult, classResult, dOneMMX, dOneMMY, iOffsetX, iOffsetY, iOffsetX, iOffsetY, iPageWidth, iPageHeight, iResultTerm, eWriteType, eResultActionType, eBroadSheetActionType, eBroadSheetType, eResultsType, eResultSheetActionType);


//There is a BltBit line here that writes from memory to window dc that I mistakenly fixed. As soon as I get to my laptop I will add it 
        
        EndPaint(hWnd, &ps);
    }

C++
void PrepareMemDC(HDC hDC, int iScrollPosX, int iScrollPosY)
{
    int iWindowExtX = static_cast<int>(GetDeviceCaps(hDC, HORZSIZE));
    int iWindowExtY = static_cast<int>(GetDeviceCaps(hDC, VERTSIZE));

    int iViewPortX = static_cast<int>(0.3 * GetDeviceCaps(hDC, HORZRES));
    int iViewPortY = static_cast<int>(0.3 * GetDeviceCaps(hDC, VERTRES));

    SetMapMode(hDC, MM_ISOTROPIC);
    SetWindowExtEx(hDC, iWindowExtX, iWindowExtY, nullptr);
    SetViewportExtEx(hDC, iViewPortX, iViewPortY, nullptr);

    SetWindowOrgEx(hDC, iScrollPosX, iScrollPosY, nullptr);
}

C++
void WriteForWindowDC(HWND hWnd, HDC hMemDC, vector<ClassResult>& vClassResult, ClassResult& classResult, double dOneMMX, double dOneMMY, int iLeft, int iTop, int iOffsetX, int iOffsetY, int iPageWidth, int iPageHeight, int iTerm, WriteType eWriteType, ResultActionType eResultActionType, BroadSheetActionType eBroadSheetActionType, BroadSheetTypes eBroadSheetType, ResultsType eResultsType, ResultSheetActionType eResultSheetActionType)
{
	RECT rcFillRect;
	HBRUSH hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);

	if (eResultActionType == ResultActionType::RAT_VIEW_BROADSHEET)
	{
		if (vClassResult.size())
		{
			for (int iPage = 0; iPage < static_cast<int>(vClassResult.size()); iPage++)
			{
				int iPageTop = iTop + iPage * (iPageHeight + iOffsetY);

				classResult = vClassResult[iPage];//Each page buffer contains coordinates of all graphics in the page as if that page page is the only existing page.

				rcFillRect.left = iLeft;
				rcFillRect.top = iPageTop;
				rcFillRect.right = rcFillRect.left + iPageWidth;
				rcFillRect.bottom = rcFillRect.top + iPageHeight;

				FillRect(hMemDC, &rcFillRect, hBrush);

				WriteBroadSheet(hWnd, hMemDC, dOneMMX, dOneMMY, iLeft, iPageTop, iOffsetX, iOffsetY, iPageWidth, iPageHeight, iTerm, eWriteType, eResultActionType, eBroadSheetActionType, eBroadSheetType, classResult);
			}
		}
	}

//some missing codes
}

C++
void SetAppScrollInfo(HWND hWnd, int iPageWidth, int iPageHeight, int iOffsetX, int iOffsetY, int iNumPages,int iPosX, int iPosY)
{
    RECT rc;
    GetClientRect(hWnd, &rc);

    SCROLLINFO scrollInfo;
    scrollInfo.cbSize = sizeof(SCROLLINFO);

    scrollInfo.fMask = scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    scrollInfo.nPos = iPosX;
    scrollInfo.nMin = 0;
    scrollInfo.nMax = std::max(iPageWidth + 2 * iOffsetX, (int)rc.right);
    scrollInfo.nPage = std::max(iPageWidth + 2 * iOffsetX, (int)rc.right);
    SetScrollInfo(hWnd, SB_HORZ, &scrollInfo, TRUE);

    scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    scrollInfo.nPos = iPosY;
    scrollInfo.nMin = 0;
    scrollInfo.nMax = std::max(iNumPages * (iPageHeight + iOffsetY), (int)rc.bottom);
    scrollInfo.nPage = std::max(iPageHeight + iOffsetY, (int)rc.bottom);
    SetScrollInfo(hWnd, SB_VERT, &scrollInfo, TRUE);
}

C++
case WM_VSCROLL:
    {
        SCROLLINFO scrollInfo;
        scrollInfo.fMask = SIF_ALL;
        
        GetScrollInfo(hWnd, SB_VERT, &scrollInfo);
        int yScrollPos = scrollInfo.nPos;

        int iPosition = HIWORD(wParam);
        switch (LOWORD(wParam))
        {
        case SB_TOP:
            yScrollPos = 0;
            break;
        case SB_BOTTOM:
            yScrollPos = scrollInfo.nMax - scrollInfo.nPage + 1;
            break;
        case SB_LINEUP:
            yScrollPos -= LINE_HEIGHT;
            break;
        case SB_LINEDOWN:
            yScrollPos += LINE_HEIGHT;
            break;
        case SB_PAGEUP:
            yScrollPos -= scrollInfo.nPage;
            break;
        case SB_PAGEDOWN:
            yScrollPos += scrollInfo.nPage;
            break;
        case SB_THUMBPOSITION:
            yScrollPos = scrollInfo.nTrackPos;
            break;
        case SB_THUMBTRACK:
            yScrollPos = iPosition;
            break;

        }

        yScrollPos = max(yScrollPos, 0);
        yScrollPos = min(yScrollPos, static_cast<int>(scrollInfo.nMax) - static_cast<int>(scrollInfo.nPage) + 1);

        if (yScrollPos != scrollInfo.nPos)
        {
            SIZE szDistance(0, scrollInfo.nPos - yScrollPos);

            scrollInfo.fMask = SIF_POS;

            scrollInfo.nPos = yScrollPos;
            SetScrollInfo(hWnd, SB_VERT, &scrollInfo, TRUE);

            //InvalidateRect(hWnd, nullptr, FALSE);
            ScrollWindow(hWnd, 0, szDistance.cy, nullptr, nullptr);
            UpdateWindow(hWnd);
        }
    }
    break;

C++
case WM_HSCROLL:
   {
       SCROLLINFO scrollInfo;
       scrollInfo.fMask = SIF_ALL;

       GetScrollInfo(hWnd, SB_HORZ, &scrollInfo);
       int xScrollPos = scrollInfo.nPos;

       int iPosition = HIWORD(wParam);
       switch (LOWORD(wParam))
       {
       case SB_LEFT:
           xScrollPos = 0;
           break;
       case SB_RIGHT:
           xScrollPos = scrollInfo.nMax + 1;
           break;
       case SB_LINELEFT:
           xScrollPos -= LINE_WIDTH;
           break;
       case SB_LINERIGHT:
           xScrollPos += LINE_WIDTH;
           break;
       case SB_PAGELEFT:
           xScrollPos -= scrollInfo.nPage;
           break;
       case SB_PAGERIGHT:
           xScrollPos += scrollInfo.nPage;
           break;
       case SB_THUMBPOSITION:
           xScrollPos = scrollInfo.nTrackPos;
           break;
       case SB_THUMBTRACK:
           xScrollPos = iPosition;
           break;
       }

       xScrollPos = max(xScrollPos, 0);
       xScrollPos = min(xScrollPos, static_cast<int>(scrollInfo.nMax) - static_cast<int>(scrollInfo.nPage) + 1);

       if (xScrollPos != scrollInfo.nPos)
       {
           SIZE szDistance(scrollInfo.nPos - xScrollPos, 0);

           scrollInfo.fMask = SIF_POS;
           scrollInfo.nPos = xScrollPos;
           SetScrollInfo(hWnd, SB_HORZ, &scrollInfo, TRUE);

           //InvalidateRect(hWnd, nullptr, FALSE);
           ScrollWindow(hWnd, szDistance.cx, 0, nullptr, nullptr);
           UpdateWindow(hWnd);
       }
   }

C++
std::tuple<double,double,int,int,int,int> GetAppDocumentSize(HWND hWnd, HDC hDC, int& iWidth, int& iHeight, ResultActionType eResultActionType)
{
    int iWindowExtX = static_cast<int>(GetDeviceCaps(hDC,HORZSIZE));
    int iWindowExtY = static_cast<int>(GetDeviceCaps(hDC, VERTSIZE));

    int iViewPortX = static_cast<int>(0.3 * GetDeviceCaps(hDC, HORZRES));
    int iViewPortY = static_cast<int>(0.3 * GetDeviceCaps(hDC, VERTRES));

    SetMapMode(hDC, MM_ISOTROPIC);
    SetWindowExtEx(hDC, iWindowExtX, iWindowExtY, nullptr);
    SetViewportExtEx(hDC, iViewPortX, iViewPortY, nullptr);

    int iDeviceSizePixelsX = GetDeviceCaps(hDC, HORZRES);
    int iDeviceSizePixelsY = GetDeviceCaps(hDC, VERTRES);

    int iDeviceSizeMMX = GetDeviceCaps(hDC, HORZSIZE);
    int iDeviceSizeMMY = GetDeviceCaps(hDC, VERTSIZE);

    double dOneMMX = (double)iDeviceSizePixelsX/ (double)iDeviceSizeMMX;
    double dOneMMY =  (double)iDeviceSizePixelsY/ (double)iDeviceSizeMMY;

    if (eResultActionType == ResultActionType::RAT_VIEW_RESULTSHEET)
    {
        iWidth = static_cast<int>(dOneMMX * 210);
        iHeight = static_cast<int>(dOneMMY * 297);
    }
    else
    {
        iHeight = static_cast<int>(dOneMMX * 210);
        iWidth = static_cast<int>(dOneMMY * 297);
    }

    int iOffsetX = (int)Approximate(10 * dOneMMX,0);
    int iOffsetY = (int)Approximate(10 * dOneMMY,0);

    SCROLLINFO scrollInfo;
    scrollInfo.cbSize = sizeof(SCROLLINFO);
    
    scrollInfo.fMask = SIF_POS;
    GetScrollInfo(hWnd,SB_HORZ, &scrollInfo);
    int xOrg = scrollInfo.nPos;
    
    scrollInfo.fMask = SIF_POS;
    GetScrollInfo(hWnd,SB_VERT, &scrollInfo);
    int yOrg = scrollInfo.nPos;
    SetWindowOrgEx(hDC,xOrg, yOrg,nullptr);

    return std::tuple(dOneMMX, dOneMMY, iOffsetX, iOffsetY,xOrg,yOrg);
}


What I have tried:

I have been debugging and googling for a reasonably long period now.
Posted
Updated 5-Apr-24 6:41am
v6

I see no easy fix but you may debug it via double buffering. At first you paint a complete image into some memory dc and than make a BitBlt to the screen.
Read this Guide to DC to improve your knowledge.

Best is to optimize the code via stripping out all constants to some data members or struct and TRACE the variable like scroll offset.
Use a more simpler approach with only vertical scrolling to find the bugs.

Last but complicate: write all hdc to bitmaps with counter or timestamp.
 
Share this answer
 
Comments
Gbenbam 5-Apr-24 12:36pm    
Please, how can one do this: "Last but complicate: write all hdc to bitmaps with counter or timestamp". Do you mind expantiating?
KarstenK 8-Apr-24 3:51am    
See this code. I didnt find some better, but it will work this way:
https://www.daniweb.com/programming/software-development/threads/481786/saving-an-hdc-as-a-bmp-file
You need to draw to memory DC before you call BeginPaint. Your BeginPaint should have only 2 more lines after it - BitBlt and EndPaint. All drawing must be done prior to these lines. And perhaps use Direct2D API. This way you'll take care of hardware acceleration
 
Share this answer
 
v2
Comments
Gbenbam 22-Apr-24 18:23pm    
If use Direct2D API will I have to replace GDI functions like ellipse and rectangle with Direct2D versions. I am asking because my code uses GDI functions heavily.
steveb 3 days ago    
Direcr2D has all the drawing code of the GDI

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900