как код для уменьшения мерцания? нужна ваша помощь с кодом. Win32 VC ++ мерцание - PullRequest
1 голос
/ 09 октября 2009

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

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

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

// 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) ;
}

Ответы [ 4 ]

7 голосов
/ 09 октября 2009

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

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

Редактировать (в ответ на комментарии):

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

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

3 голосов
/ 09 октября 2009

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

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

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

1 голос
/ 23 февраля 2015

Чтобы избежать мерцания, используйте метод двойной буферизации. В этом методе мы выполняем процедуру рисования за пределами экрана 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
1 голос
/ 09 октября 2009

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

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