как кодировать для уменьшения мерцания? нужна ваша помощь с кодом. мерцание win32 VC ++

Я пытаюсь преобразовать растровое изображение в битовое изображение в положение курсора мыши с помощью мыши movemont. Но с проблемами мерцания.

Я читал о двойной буферизации для уменьшения мерцания, но не знаю, как ... это вызывает сильное мерцание. Я читал о двойной буферизации для уменьшения мерцания, но не уверен, как это реализовать в этом примере. Пожалуйста, не могли бы вы помочь? Спасибо

вот код ниже. Спасибо за вашу помощь!

// screen blinks.trying to use double buffer so solve this problem.
#include <windows.h>
HDC bufferDC = NULL;
HDC           hdc=GetWindowDC(NULL) ;
HDC hammerDC = NULL; 
HBITMAP hammer1BMP = NULL;
HBITMAP bufferBMP = NULL;
POINT cursorpoint;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("DigClock") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("Digital Clock"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;


     bufferDC=CreateCompatibleDC(hdc);
     hammerDC=CreateCompatibleDC(hdc);
     hammer1BMP=(HBITMAP)LoadImage(NULL,"star.bmp",IMAGE_BITMAP,160,160,LR_LOADFROMFILE);
     SelectObject(hammerDC,hammer1BMP);

     while (GetMessage (&msg, NULL, 0, 0))
          {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
          }
     return msg.wParam ;
     }

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static BOOL   f24Hour, fSuppress ;
     static HBRUSH hBrushRed ;
     static int    cxClient, cyClient ;
     HDC           hdc ;
     PAINTSTRUCT   ps ;
     TCHAR         szBuffer [2] ;

     switch (message)
     {
     case WM_CREATE:
          hBrushRed = CreateSolidBrush (RGB (255, 0, 0)) ;
          SetTimer (hwnd, ID_TIMER, 1000/24,NULL) ;//1000

                                                  // fall through

     case WM_SETTINGCHANGE:

          InvalidateRect (hwnd, NULL, TRUE) ;
          return 0 ;

     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;

     case WM_TIMER:
          InvalidateRect (hwnd, NULL, TRUE) ;
          return 0 ;

     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;
          bufferBMP=CreateCompatibleBitmap(hdc,cxClient,cyClient);
          SelectObject(bufferDC,bufferBMP);
          // SelectObject(bufferDC,hammer1BMP); 
          GetCursorPos(&cursorpoint);
          BitBlt(bufferDC,0,0,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
          BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,bufferDC,0,0,SRCCOPY);


          EndPaint (hwnd, &ps) ;
          return 0 ;
     case WM_LBUTTONDOWN:
         // GetCursorPos(&cursorpoint);
          //BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
          return 0;
     case WM_DESTROY:
          KillTimer (hwnd, ID_TIMER) ;
          DeleteDC(hammerDC);
          DeleteObject (hBrushRed) ;
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

person user185369    schedule 09.10.2009    source источник


Ответы (4)


В этом случае похоже, что вам действительно не нужна двойная буферизация - на самом деле, это, вероятно, вам вообще не поможет.

Основная причина вашего мерцания - стирание фона и немедленное рисование поверх него. Поскольку вы, по-видимому, рисуете всю клиентскую область своего окна в WM_PAINT, просто добавьте обработчик для WM_ERASEBKGND, который ничего не делает, кроме как возвращает TRUE, чтобы указать, что фон был стерт.

Изменить (в ответ на комментарии):

Для большей полноты, мерцание результатов (почти) всегда, когда вы рисуете область одним цветом, а затем быстро перекрашиваете ее в другой цвет. Двойная буферизация помогает, когда / если ваш передний план имеет несколько перекрывающихся элементов разных цветов. Вы рисуете (по крайней мере) перекрывающиеся области в задний буфер, и только тогда, когда у вас есть правильные цвета, вы рисуете их на экране. В этом случае исходный код выполняет двойную буферизацию, но он все еще рисует фон, затем передний план, и вы все еще мерцаете.

В другом ответе упоминается передача false в качестве второго параметра InvalidateRect. Это очень поможет, так как не будет перерисовывать фон в ответ на этот InvalidateRect. Будет нарисован только передний план, поэтому он не будет мерцать. К сожалению, когда прямоугольник окна (хотя бы его часть) недействителен по какой-либо другой причине, вы все равно будете мерцать, потому что он все равно будет рисовать фон, а затем передний план.

person Jerry Coffin    schedule 09.10.2009
comment
Эээ ... он уже выполняет двойную буферизацию. Просто еще не до конца добрался до совершенства. Однако хорошая идея с WM_ERASEBACKGROUND. - person Steve314; 09.10.2009
comment
@ Steve314 - вы можете удалить свой комментарий, а затем повторно отправить отредактированную версию - person philsquared; 09.10.2009

Снимите таймер. Таймер заставляет вас аннулировать, даже если в окне нет изменений. Кроме того, вы стираете окно с каждым истечением таймера.

В принципе, вы поняли правильную концепцию. Когда вам нужно WM_PAINT, скопируйте свой задний буфер. Когда вам нужно обновить графику, обновите задний буфер, а затем сделайте его недействительным только один раз.

Другой совет - использовать GetUpdateRect () для получения области обновления в WM_PAINT. Копируйте только загрязненную область из заднего буфера. Это еще больше оптимизирует вашу двойную буферизацию.

person Andrew Keith    schedule 09.10.2009
comment
Для анимации может потребоваться таймер, но, как вы предлагаете, третий параметр InvalidateRect всегда должен иметь значение FALSE. Мерцание происходит из-за времени между стиранием прямоугольника на экране и миганием поверх него, и нет никакого смысла стирать, когда вы все равно перезапишете все это целиком. Очистка должна выполняться в фоновом буфере как часть закадрового рисования. - person Steve314; 09.10.2009
comment
В этом тоже может быть виноват MSDN - взгляните на InvalidateRect в msdn. microsoft.com/en-us/library/ms969905.aspx - правда, это только на WM_SETTEXT, но это все равно вводящий в заблуждение пример. - person Steve314; 09.10.2009

Причина мерцания (и возможного сбоя программы) множественная:

  1. Есть фоновая кисть - установите hbrBackground, чтобы запретить генерацию сообщений WM_ERASEBKGND.
  2. Вы создаете (и пропускаете) буферBMP для каждого WM_PAINT.
  3. Вы неправильно рисуете окно - почему вы рисуете в позицию курсора? Если вы хотите, чтобы «молоток» отслеживал мышь, вы должны нарисовать молоток на внеэкранном растровом изображении в соответствующем месте, а затем скопировать закадровое растровое изображение, чтобы покрыть клиентскую область, то есть до 0,0, cx, cy
person Chris Becke    schedule 09.10.2009

Чтобы избежать мерцания, используйте метод двойной буферизации. В этом методе мы выполняем процедуру рисования поверх экрана DC (hdcBuffer), а затем копируем содержимое этого DC на фактический экран DC (hdc). . Также избегайте стирания фона, возвращая ненулевое значение в сообщении WM_ERASEBKGND. Вот алгоритм:

hdc = BeginPaint(hwnd,&ps); // actual screen DC

hdcBuffer = CreateCompatibleDC (hdc)  // OFF screen DC

hBitmapBuffer = CreateCompatibleBitmap (hdc,BitmapWidth, BitmapHeight);  // create memory bitmap for that off screen DC

SelectObject(hdcBuffer,hBitmapBuffer); // Select the created memory bitmap into the OFF screen DC

/* Then do your painting job using hdcBuffer over off screen DC */

BitBlt(hdc,0,0,BitmapWidth,BitmapHeight,hdcBuffer,0,0,SRCCOPY); // copy the content of OFF screen DC to actual screen DC

DeleteDC (hdcBuffer); // Release the OFF screen DC

DeleteObject (hBitmapBuffer); // Free the memory for bitmap

EndPaint(hwnd,&ps); // Release the actual screen DC
person ibrahim    schedule 23.02.2015