• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Psychopathetica

WM_PAINT Slowdown Issues With RichEdit

9 posts in this topic

I created a Win32 window with a child window using C++ 2010. In my child window I have a richedit control. It works but there is one problem. When I want to use the WM_PAINT message in the parent window, even if I leave it empty with a breakpoint, it seems to slow down the program only its not really. Only as I try to type in the RichEdit control, it makes it feel very unresponsive. But if I comment out the WM_PAINT: and break, it works as it should. I need the WM_PAINT message to eliminate flicker in the border when you drag the child window using InvalidateRect(hChildWnd, NULL, FALSE); and quite possibly other things if I need to. How can I allow the WM_PAINT message without slowing down the RichEdit control when I type. Thanks in advance and heres the code I currently have:

 

#include <windows.h>
#include <Richedit.h>

HWND hWnd;
HWND hChildWnd;
HWND hRichEdit;
MSG msg;
WNDCLASSEX wc;
WNDCLASSEX wcChild;
HBRUSH brush;
HINSTANCE hChildInstance = NULL;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWindowProcedure (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow);

#define ID_FILE_EXIT 1000

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
    wc.lpfnWndProc   = WindowProcedure;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "Window";
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);
    hWnd = CreateWindowEx (0, "Window", "Parent Window", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, hWnd, NULL, hInstance, NULL);
    
    wcChild.cbSize        = sizeof(WNDCLASSEX);
    wcChild.style         = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
    wcChild.lpfnWndProc   = ChildWindowProcedure;
    wcChild.cbClsExtra    = 0;
    wcChild.cbWndExtra    = 0;
    wcChild.hInstance     = hChildInstance;
    wcChild.hIcon         = NULL;
    wcChild.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wcChild.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wcChild.lpszMenuName  = NULL;
    wcChild.lpszClassName = "ChildWindow";
    wcChild.hIconSm       = NULL;
    RegisterClassEx(&wcChild);
    hChildWnd = CreateWindowEx (0, "ChildWindow", "Child Window", WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, hWnd, NULL, hChildInstance, NULL);

    LoadLibrary("riched32.dll");
    hRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, RICHEDIT_CLASS, "", WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_MULTILINE | ES_LEFT | ES_NOHIDESEL | ES_AUTOVSCROLL, 0, 0, 640, 480, hChildWnd, NULL, hChildInstance, NULL);
    if( !hRichEdit ) MessageBox(hWnd,"Couldnt create rich textbox", "Message", MB_OK);

    CHARFORMAT2 cf;
    cf.cbSize = sizeof(CHARFORMAT2);
    cf.dwMask = CFM_COLOR | CFM_BACKCOLOR;
    cf.crTextColor = RGB(255, 255, 255);
    cf.crBackColor = RGB(0 ,0, 0);
    cf.dwEffects = 0 ;
    SendMessage(hRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf );
    SendMessage(hRichEdit, EM_SETBKGNDCOLOR,0, RGB(0, 0, 0));

    ShowWindow (hWnd, SW_SHOWMAXIMIZED);
    ShowWindow(hRichEdit, nCmdShow);
    SetFocus(hRichEdit);

    while (GetMessage (&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            HMENU hFile = CreateMenu();
            HMENU hExit = CreateMenu();
            AppendMenu(hFile, MF_POPUP, (UINT_PTR)hExit, "File");
            AppendMenu(hExit, MF_STRING, ID_FILE_EXIT, "Exit");
            SetMenu(hWnd, hFile);
            break;
        }
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case ID_FILE_EXIT:
                {
                    DestroyWindow(hWnd);
                    return(0);
                    break;
                }
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        case WM_PAINT: //THIS IS WHERE THE PROBLEM IS!!!
            InvalidateRect(hChildWnd, NULL, FALSE);
            break;
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}

LRESULT CALLBACK ChildWindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}
0

Share this post


Link to post
Share on other sites

Yea it doesnt work. I even removed the CS_VREDRAW | CS_HREDRAW from both windows since I ran into this article: http://www.catch22.net/tuts/flicker-free-drawing and it still flickers when I drag the child window. But what is making me scratch my head is the fact that WM_PAINT with the break or even return 0 causes slowdown when I type. And after about a dozen characters later it nearly doesnt respond at all. The only thing thats very responsive then is dragging the window and exiting out. Thats what I dont understand.

0

Share this post


Link to post
Share on other sites

Flicker in Windows can sometimes be tricky, I have been dealing with it quite a lot at work latly, when we decided to eliminate all flicker in an app. The key is to never paint the same pixel twice during one WM_PAINT (yes, double buffering is a common solution for this). If you can describe in more detail what kind of flicker you ar experiencing, maybe I can help.

Remove your WM_PAINT handler entirely, and we'll work from there.

 

EDIT:

Since I'm lying here with a broken leg and nothing better to do, I pasted your code into VS. I think I know whar is causing the flicker. I'll be back after some tests.

Edited by wack
0

Share this post


Link to post
Share on other sites

I dont know about RichEdit controls, but WM_PAINT is not the only message that signals drawing is needed and if you overdraw everything there you dont need to draw the background first which happens on WM_ERASEBKGND . You call InvalidateRect which causes another WM_PAINT together with some other things, but you never do any painting and you also dont call DefWindowProc which would take care of letting Windows know painting is done, which could cause an endless stream of those messages.

These are some lines cut from a program I wrote a while ago to do the minimum of work needed on those messages:

    case WM_ERASEBKGND:
      {
        // do nothing as its overdrawn anyway through WM_PAINT, possibly reducing flicker
        return 1; // pretend its done
      }
    case WM_PAINT:
      {
        Paint();
        ValidateRect(wnd,NULL);
        return 0;
      }
0

Share this post


Link to post
Share on other sites

Have you tried setting WS_CLIPCHILDREN on the "child" window?

It turns out that this is indeed all that is needed, in combination with removing your WM_PAINT handler.

0

Share this post


Link to post
Share on other sites

The reason your RichEdit appears to be lagging is because you don't do a "ValidateRect" on your paren'ts "InvalidatedRect" area. You see, WM_PAINT expects you to at least call BeginPaint and EndPaint, even if you don't do any drawing - EndPaint validates the "InvalidatedRect" area.

 

If you don't validate the invalidated area during WM_PAINT, the windows GUI system will assume that your client area still needs to be painted, and it will keep posting WM_PAINT messages to your message loop (in the case of a modal DialogBox, that's the internal message loop handled by the DialogBox API - or by the CDialog::DoModal wrapper in MFC).

 

This means that every time there is no input (keyboard/moase) or I/O (newtork, disk, sync etc.) message, your message loop will be continuously processing WM_PAINT messages - they have the lowest priority, so your application/dialog still gets input, but the continuous WM_PAINTing that it does when there's no input will be slowing it down - you should also see your CPU being used accordingly - e.g., 25% CPU used continuously until you close the dialog, if you have a quad-core).

 

 

P.S.: Sorry for posting with a bugmenot account - I read these forums daily, and I find many occasions of replying to tricky questions like this one, but I don't want to be bound by an account. :)

1

Share this post


Link to post
Share on other sites

I tried the methods shown above but WM_ERASEBKGND makes my black background white and doesnt clear. Instead when I drag the child window it leaves a trail of windows everywhere. I'm sorry if I sound too much of a noob in C++. I'm trying to get away from VB. Been using that language too long. lol

 

I honestly dont know when to use ValidateRect and InvalidateRect. Should I use ValidateRect before I BeginPaint, in between, or after EndPaint. Should I InvalidateRect before I ValidateRect? I honestly dont know. Thank you guys so much so far but I still get slowdown in this code even with ValidateRect and BeginPaint / EndPaint

 

#include <windows.h>
#include <Richedit.h>

HWND hWnd;
HWND hChildWnd;
HWND hRichEdit;
MSG msg;
WNDCLASSEX wc;
WNDCLASSEX wcChild;
HBRUSH brush;
HINSTANCE hChildInstance = NULL;
PAINTSTRUCT  PS;
HDC          hDC;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWindowProcedure (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow);

#define ID_FILE_EXIT 1000

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WindowProcedure;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "Window";
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);
    hWnd = CreateWindowEx (0, "Window", "Parent Window", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, hWnd, NULL, hInstance, NULL);
    
    wcChild.cbSize        = sizeof(WNDCLASSEX);
    wcChild.style         = 0;
    wcChild.lpfnWndProc   = ChildWindowProcedure;
    wcChild.cbClsExtra    = 0;
    wcChild.cbWndExtra    = 0;
    wcChild.hInstance     = hChildInstance;
    wcChild.hIcon         = NULL;
    wcChild.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wcChild.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wcChild.lpszMenuName  = NULL;
    wcChild.lpszClassName = "ChildWindow";
    wcChild.hIconSm       = NULL;
    RegisterClassEx(&wcChild);
    hChildWnd = CreateWindowEx (0, "ChildWindow", "Child Window", WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, hWnd, NULL, hChildInstance, NULL);

    LoadLibrary("riched32.dll");
    hRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, RICHEDIT_CLASS, "", WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_MULTILINE | ES_LEFT | ES_NOHIDESEL | ES_AUTOVSCROLL, 0, 0, 640, 480, hChildWnd, NULL, hChildInstance, NULL);
    if( !hRichEdit ) MessageBox(hWnd,"Couldnt create rich textbox", "Message", MB_OK);

    CHARFORMAT2 cf;
    cf.cbSize = sizeof(CHARFORMAT2);
    cf.dwMask = CFM_COLOR | CFM_BACKCOLOR;
    cf.crTextColor = RGB(255, 255, 255);
    cf.crBackColor = RGB(0 ,0, 0);
    cf.dwEffects = 0 ;
    SendMessage(hRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf );
    SendMessage(hRichEdit, EM_SETBKGNDCOLOR,0, RGB(0, 0, 0));

    ShowWindow (hWnd, SW_SHOWMAXIMIZED);
    ShowWindow(hRichEdit, nCmdShow);
    SetFocus(hRichEdit);

    //while (1)
 //   {
 //       if (PeekMessage(&msg,NULL,0,0,PM_REMOVE) > 0)
 //       {
 //           if (WM_QUIT == msg.message) break;
 //           TranslateMessage (&msg);
 //           DispatchMessage (&msg);
 //       }
 //   }

    while (GetMessage (&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            HMENU hFile = CreateMenu();
            HMENU hExit = CreateMenu();
            AppendMenu(hFile, MF_POPUP, (UINT_PTR)hExit, "File");
            AppendMenu(hExit, MF_STRING, ID_FILE_EXIT, "Exit");
            SetMenu(hWnd, hFile);
            break;
        }
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case ID_FILE_EXIT:
                {
                    DestroyWindow(hWnd);
                    return(0);
                    break;
                }
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        case WM_ERASEBKGND:
          {
            return 1;
          }
        case WM_PAINT:
          {
            ValidateRect(hWnd,NULL);
            hDC = BeginPaint(hWnd, &PS);
            EndPaint(hWnd, &PS);
            return 0;
          }
          break;
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}

LRESULT CALLBACK ChildWindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0