Click here to Skip to main content
15,887,322 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am using the double buffering method in main window of my program to prevent flickering, but I am have been getting entirely black window client area instead. What could be the problem.

The relvant codes are shown below:
Please note that the WriteDatah Function is not an actual part of the actual appliation. I created a new project and brought the problematic code to it in order to figure out was was wrong. The WriteData represent actual code in funinality. With this new test applicaion, I was able to narrow down the problem to be either the double buffering is not properly done or the mapping mode conflicts with it. What do you think.

C++
case WM_CREATE:
    {
        HDC hdc = GetDC(hWnd);

        std::tuple<double, double, int, int> Tuple = GetAppDocumentSize(hWnd, hdc, iPageWidth, iPageHeight);
        iOneMMX = static_cast<int>(Approximate(get<0>(Tuple), 0));
        iOneMMY = static_cast<int>(Approximate(get<1>(Tuple), 0));
        int iWidth = GetSystemMetrics(SM_CXSCREEN);
        int iHeight = GetSystemMetrics(SM_CYSCREEN);
        hMemDC = CreateCompatibleDC(hdc);
        hBitmap = CreateCompatibleBitmap(hdc, iWidth, iHeight);
        hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
        HBRUSH hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
        hOldBrush = (HBRUSH)SelectObject(hMemDC, hBrush);

        ReleaseDC(hWnd,hdc);


        break;
    }




C++
case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            std::tuple<double,double,int,int> Tuple = GetAppDocumentSize(hWnd, hdc, iPageWidth, iPageHeight);
          
            BitBlt(hdc, 0, 0, iPageWidth, iPageHeight, hMemDC, 0, 0, SRCCOPY);

            EndPaint(hWnd, &ps);
        }
        break;



This following code is lunched by the menu item with the ID ID_DRAW_DRAW_TEXT. So, it is handled by WM_COMMAND.
C++
case ID_DRAW_DRAWTEXT:
            {
                Rectangle(hMemDC, 0, 0, iPageWidth, iPageHeight);
                WriteDatah(hMemDC,iOneMMX,iOneMMY,iPageWidth,iPageHeight);

                InvalidateRect(hWnd, NULL, FALSE);

                break;
            }



C++
HFONT CreateAppFont(int cHeight, int cWeight, DWORD bItalic, int cEscapement, DWORD bUnderline, LPCWSTR pszFaceName)
{
    return CreateFont(cHeight, 0, cEscapement, cEscapement, cWeight, bItalic, bUnderline, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
        CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, pszFaceName);


}




C++
double Approximate(double dNumber, int iDecimalPlaces)
{
    int iMultipier = static_cast<int>(pow(10, iDecimalPlaces));
    dNumber *= iMultipier;

    double dInteger = 0.0;
    double dDecimal = modf(dNumber, &dInteger);

    int Integer = static_cast<int>(dInteger);

    if (dDecimal >= 0.5)
    {
        Integer++;
    }

    double dResult = Integer / iMultipier;

    return dResult;
}




C++
void WriteDatah(HDC hdc,int iOneMMX,int iOneMMY,int iPageWidth,int iPageHeight)
{
    UNREFERENCED_PARAMETER(iPageHeight);

    std::wstring wstData = L"Jesus is Lord of the Nations";
    
    int iOneINCHY = GetDeviceCaps(hdc, LOGPIXELSY);
    double dOneFontPOINT = (double)iOneINCHY / 72.0;
    int iOneFontPOINT = static_cast<int>(Approximate(dOneFontPOINT, 0));

    int iFontSize = 10 * iOneFontPOINT;

    HFONT hFont = CreateAppFont(iFontSize, FW_BOLD);
    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);

    int iLeft = 10 * iOneMMX;
    int iTop = 10 * iOneMMY;

    SIZE size;
    GetTextExtentPoint32(hdc, wstData.c_str(), lstrlen(wstData.c_str()), &size);
    TEXTMETRIC tm;
    GetTextMetrics(hdc, &tm);

    for (int i = 0; i < 100; i++)
    {
        TextOut(hdc, iLeft, iTop, wstData.c_str(), lstrlen(wstData.c_str()));

        iTop += tm.tmHeight + tm.tmExternalLeading;

    }
      
       


    SelectObject(hdc, hOldFont);
    
}


What I have tried:

I have been debugging all day. I have quite ab amount of googling too.
Posted
Comments
Richard MacCutchan 19-Jan-24 12:36pm    
I suspect that part of your problem is that you are manipulating device contexts in different parts of the code. Move all the code that deals with display issue into the WM_PAINT handler. That is how I have always done it, and never had any similar issues to this problem.
Gbenbam 19-Jan-24 20:36pm    
How do you handle flickering?

From the first look: you des not specify the pen and brush colors for the drawing.
 
Share this answer
 
Comments
Gbenbam 19-Jan-24 20:33pm    
It uses black pen and white brush.
Maxim Kartavenkov 20-Jan-24 3:59am    
Check what has been draw on your compatible bitmap - you can easy save it to the file - in this case you be sure that you are on the right way. Also you can try to draw on client area first to check the results. After you should check the window styles and validate the GetLastError codes after each operation. To prevent flickering you should disable default erasing background as I already told.
I have used this class : Flicker Free Drawing In MFC[^] for many years and it works really well. I also wrote a non-MFC version of it that I have used a few times. Your code does not appear to use MFC but the principles are the same. It's all about handling messages, primarily WM_PAINT. However, WM_ERASEBACKGND also needs to be handled by just returning true. I recommend that you read the article carefully to see if you are doing something wrong.

Let me know if you want to see the non-MFC version and I will post it here. It's essentially the same as the MFC version except it uses GDI calls instead of CDC methods.
 
Share this answer
 
Comments
Gbenbam 19-Jan-24 20:19pm    
I am very fluent with MFC, but its better if you share the WIN32 version here.
merano99 20-Jan-24 18:42pm    
It may be that the examples under "Flicker Free Drawing In MFC" worked back then. Current compilers can no longer cope with this without major changes.
Whether you are using MFC or WIN32, the correct method to eliminate flickering using double buffing method is as stated below:

1. Get the window's dc.
2. Create a dc that is compartible with window's dc by using CreateCompartibleDC function and stating the window's dc as the dc to be emulated.
3. Get the width and height of the screen by using GetSystemMetrics.
4. Create a bitmap that is compartible with the window's dc of width and height equaling that o the screen's by using CreatecompartibleBitmap function and stating the window's dc as the dc to be emulated.
5. Select the bitmap created into the memory dc created by using SelectObject.
6. Get or create a brush whose colour is the same as the main window's client area background.
7. Select the created or gotten brush into the created memory dc.
8. Make the created bitmap look identical to the window's client area by painting it with the same colour the window's client area has by using PatBlt function and specifying PATCOPY in it as the copy mode.
8. Use BitBlt t transfer the content of the memory dc to the window's dc and secifying SRCCOPY as the copy mode during WM_PAINT.


Alternatively, you can use FillRect to paint the created bitmap to look like the windoW's client area. These would replace steps 6. 7. and 8.

Rather than making the created bitmap equal in size to the screen, you can make it equal in size to the client area, by calling GetClientRect, but thus would mean that you would have to repeat the entire creation process each time the window is resized. Typically you carry out your creation once and for all during WM_CREATE. Your created memory dc and bitmap variaible should be preferrably global so that they can remain in existence throughout the time the window is in existence.

Ensure you delete the memory dc and destroy the created bitmap associated with it when the window is destroyed. Typically during WM_DESTROY
 
Share this answer
 
Comments
Richard MacCutchan 22-Jan-24 4:24am    
You should not do that in WM_CREATE. As I have mentioned in a number of your other questions, you should do all screen displaying code in your WM_PAINT handler. And the size of the client window is returned in the PAINTSTRUCT structure after the call to BeginPaint, so you have all the relevant information to paint your client area. I am not sure why you need the dimensions of the scren or a bitmap of that size.
Gbenbam 22-Jan-24 18:34pm    
I tried your suggestion and their was flicker. How do you handle flicker? My application, like many others have to access database frequently, in fact, it does not access file at all. Sometimes, queries generate errors due to different kind of reasons. Some times there is break down of communication with database because it is in a remote server and there is temporal internet network connection breakdown. In many o f such situations users have to wait for response to the database and respond to errors and exceptions apprpriately. Will handling all such from WM_PAINT be suitable? For, for now, I connect with database from WM_COMMAND generate by menus and connect to database to fill up a buffer with required data. if the buffer was successfully filled, I write data to memory dc and call invalidaterect to generate WM_PAINT message which causes the written data to be copied to the window DC from the memory DC. If you can be generous an kind to guide me into unerstanding how all these can be achieved by doing all writing in WM_PAINT , I will greatly appreciate it. I do wish to be a better programmer. Your input will go a long way to ensure that.

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