10

通常、ダブルバッファリングを使用している場合でも、ウィンドウのサイズを変更する場合、ちらつきが発生することは避けられないようです。

ステップ1、元のウィンドウ。

ステップ1

ステップ2、ウィンドウのサイズが変更されましたが、余分な領域はペイントされていません。

ステップ2

ステップ3、ウィンドウのサイズが変更され、余分な領域がペイントされました。

ステップ3

どういうわけかsetp2を隠すことは可能ですか?ペイントアクションが完了するまで、サイズ変更プロセスを一時停止できますか?

次に例を示します。

#include <Windows.h>
#include <windowsx.h>
#include <Uxtheme.h>

#pragma comment(lib, "Uxtheme.lib")

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);
void MainWindow_OnDestroy(HWND hWnd);
void MainWindow_OnSize(HWND hWnd, UINT state, int cx, int cy);
void MainWindow_OnPaint(HWND hWnd);

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wcex = { 0 };
  HWND hWnd;
  MSG msg;
  BOOL ret;

  wcex.cbSize = sizeof(wcex);
  wcex.lpfnWndProc = WindowProc;
  wcex.hInstance = hInstance;
  wcex.hIcon = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
  wcex.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
  wcex.lpszClassName = TEXT("MainWindow");
  wcex.hIconSm = wcex.hIcon;

  if (!RegisterClassEx(&wcex))
  {
    return 1;
  }

  hWnd = CreateWindow(wcex.lpszClassName, TEXT("CWin32"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
  if (!hWnd)
  {
    return 1;
  }

  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
  {
    if (ret == -1)
    {
      return 1;
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
    HANDLE_MSG(hWnd, WM_CREATE, MainWindow_OnCreate);
    HANDLE_MSG(hWnd, WM_DESTROY, MainWindow_OnDestroy);
    HANDLE_MSG(hWnd, WM_SIZE, MainWindow_OnSize);
    HANDLE_MSG(hWnd, WM_PAINT, MainWindow_OnPaint);
  default:
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
  }
}

BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
  BufferedPaintInit();
  return TRUE;
}

void MainWindow_OnDestroy(HWND hWnd)
{
  BufferedPaintUnInit();
  PostQuitMessage(0);
}

void MainWindow_OnSize(HWND hWnd, UINT state, int cx, int cy)
{
  InvalidateRect(hWnd, NULL, FALSE);
}

void MainWindow_OnPaint(HWND hWnd)
{
  PAINTSTRUCT ps;
  HPAINTBUFFER hpb;
  HDC hdc;

  BeginPaint(hWnd, &ps);
  hpb = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &hdc);

  FillRect(hdc, &ps.rcPaint, GetStockBrush(DKGRAY_BRUSH));
  Sleep(320); // This simulates some slow drawing actions.

  EndBufferedPaint(hpb, TRUE);
  EndPaint(hWnd, &ps);
}

ちらつきをなくすことはできますか?

4

4 に答える 4

9

ドラッグ操作中にウィンドウが更新されると、OS は拡張されたウィンドウ領域に何かを表示する必要があります。何も提供できない場合は、提供するまで背景が表示されます。背景を指定しなかったため、黒くなります。背景ブラシを指定する必要がありますか? 以下をコードに追加するだけで、動作がより快適になります。

wcex.hbrBackground = GetStockBrush(DKGRAY_BRUSH);

ただし、応答に 320 ミリ秒もかかるとWM_PAINT、ユーザーのサイズ変更 UI が台無しになります。ぎくしゃくして無反応になります。このシステムは、スムーズにドラッグできるようにウィンドウをすばやくペイントできるという前提に基づいて設計されています。問題を解決する正しい方法WM_PAINTは、妥当な時間内に実行することです。

スムーズにドラッグするのに十分な速さでペイントできない場合は、いくつかの代替案をお勧めします。

  1. ドラッグ中のウィンドウの更新を無効にします。これは個々のウィンドウに対して実行できると確信していますが、頭のてっぺんからそれを行う方法を思い出せません。
  2. サイズ変更/ドラッグがアクティブなときに偽物をペイントし、サイズ変更/ドラッグが完了するまで実際のペイントを延期します。WM_ENTERSIZEMOVEとを聞くことWM_EXITSIZEMOVEがこれの鍵です。この Microsoft サンプル プログラムは、その方法を示しています: https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/winui/fulldrag/
于 2012-08-26T13:57:08.383 に答える
3

WM_SIZINGの代わりに使用WM_SIZEし、忘れないでくださいWM_ERASEBKGND

于 2012-08-26T13:35:09.323 に答える