(Windows API) WM_PAINT Проблемы с мышью

Я создал окно со следующими флагами для наложения приложения d3d: WS_EX_TOPMOST | WS_EX_COMPOSITED | WS_EX_TRANSPARENT | WS_EX_LAYERED Я применил цветовую маркировку окна для прозрачности, и все сработало хорошо. Однако как только я начал рисовать с помощью GDI, возникла непредвиденная проблема:

По какой-то причине события мыши (особенно движение) не проходят через окно правильно, когда выполняется WM_PAINT, и поэтому кажется, что мышь и клавиатура в этом отношении отстают. FPS в порядке, это какая-то проблема API, я подозреваю, что по какой-то причине сообщения клавиатуры/мыши не обрабатываются должным образом, пока выполняется WM_PAINT, потому что чем медленнее установлен таймер, тем меньше рывков.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

 switch(msg)
 {
  case WM_DESTROY:
  {
          KillTimer(hwnd, ID_TIMER);
          PostQuitMessage(0);
          break;
         }
  case WM_CREATE:
  {
   SetTimer(hwnd, ID_TIMER, 10, NULL);
   break;
  }
  case WM_TIMER:
  {
   InvalidateRect(hwnd, 0, 1);
   break;
         }
  case WM_PAINT:
  {
   paint(hwnd);
   break;
  }
 }
 return DefWindowProc(hwnd, msg, wParam, lParam);
}

и

void paint (HWND hwnd)
{
 PAINTSTRUCT Ps;
 HDC hdc = BeginPaint(hwnd, &Ps);

 SetBkColor(hdc, RGB(0,0,0));
 SetBkMode(hdc, TRANSPARENT);



 LOGBRUSH log_brush;
 log_brush.lbStyle = BS_NULL;
 HBRUSH handle_brush = CreateBrushIndirect(&log_brush);
 SelectObject(hdc, handle_brush);


..........................................


 DeleteObject(font);
 DeleteObject(pen);
 DeleteObject(handle_brush);

 EndPaint(hwnd, &Ps);
}

Спасибо за любую помощь, которую вы можете оказать.


person Nick    schedule 20.02.2010    source источник


Ответы (2)


Сообщения WM_PAINT никогда не доставляются в ваше окно, если кто-то не вызывает UpdateWindow или в вашей очереди ввода нет сообщений клавиатуры или мыши.

Как только вы начинаете обрабатывать WM_PAINT, если приходит сообщение клавиатуры или мыши, оно просто находится в вашей очереди, пока вы не закончите с WM_PAINT. Так что то, что вы описываете, невозможно.

Если ваш код WM_PAINT выполняется долго, это может вызвать рывки, но вы говорите, что это не проблема, так что, возможно, это ваша обработка WM_ERASEBKGND? Я не вижу этого кода, но я вижу, что когда вы InvalidateRect, вы передаете TRUE в качестве последнего параметра, что означает, что вы хотите, чтобы фон был стерт.

Если вы не обрабатываете WM_ERASEBKGND, то DefWindowProc сделает это за вас, удалив все ваше окно кистью из вашего класса окна. Это может привести к тому, что окна будут думать, что никакая часть вашего окна не прозрачна.

Если вы хотите, чтобы сообщения мыши проходили через ваше окно, более надежный способ — обработать сообщение WM_NCHITTEST и вернуть HTTRANSPARENT там, где вы хотите, чтобы мышь проходила.
Это в основном то, как работает стиль WS_EX_TRANSPARENT. нравится

case WM_NCHITTEST:
   {
   lRet = DefWindowProc(hwnd, uMsg, wParam, lParam);
   if (HTCLIENT == lRet)
      lRet = HTTRANSPARENT;
   }

Если в вашем окне нет неклиентской области, то вызов DefWindowProc можно пропустить.

person John Knoeller    schedule 20.02.2010
comment
Изменив третий параметр InvalidateRect на FALSE, рывки ушли, однако предыдущие кадры больше не стираются, вам это о чем-нибудь говорит? Этот Windows API сбивает с толку. Спасибо. - person Nick; 20.02.2010
comment
Вместо этого попытался использовать Fillrect, чтобы стереть предыдущий кадр, и это помогло значительно уменьшить рывки. - person Nick; 20.02.2010
comment
@Nick: Вы не показываете, что вы на самом деле делаете в своем коде рисования, поэтому я не вижу, что вам нужно делать вместо erasebkgnd, извините. Fillrect звучит так, как будто это может помочь. или вы можете использовать PatBlt, чтобы заполнить прямоугольную область продаваемым цветом. - person John Knoeller; 20.02.2010
comment
Ну, может показаться, что заполнение нескольких мегапикселей сплошным цветом создает небольшую задержку в обработке, и эта задержка является проблемой, потому что во время этой задержки события мыши не передаются в приложение d3d через окно наложения, вызывая эту задержку мыши или, скорее, подергивания. Что я должен делать? Спасибо за вашу помощь. - person Nick; 20.02.2010
comment
@Ник: не делай этого ;) Просто сотри самый маленький прямоугольник, который тебе сойдет с рук. Вы можете попробовать использовать ExtTextOut(.. ETO_OPAQUE, ...) с пустой строкой, когда-то это был самый быстрый способ рисовать прямоугольники сплошного цвета, но ничто не сравнится с просто не стиранием там, где вы этого не делаете. нужно стереть - person John Knoeller; 20.02.2010
comment
PAINT кажется проблемой, он задерживает обработку сообщений, поможет ли двойная буферизация с одним буфером в другом потоке? - person Nick; 21.02.2010
comment
двойная буферизация может помочь, но не так сильно, как просто рисование меньшего количества пикселей. Вы даже не начали оптимизировать свой код рисования. Нет необходимости создавать кисть для каждого сообщения рисования и т. д. - person John Knoeller; 21.02.2010
comment
Ну, я понимаю, о чем вы говорите, и я мог бы попытаться найти разницу между двумя кадрами и просто стереть разницу, но это все равно не решит назойливую проблему, связанную с ожиданием цикла сообщений на WM_PAINT. Нет ли способа убедиться, что WM_PAINT не мешает обработке сообщения? Спасибо. - person Nick; 21.02.2010
comment
Извините, единственное возможное решение — ускорить код WM_PAINT. Windows не позволит вам обрабатывать сообщения для одного окна более чем в 1 потоке. - person John Knoeller; 21.02.2010
comment
Что, если вместо этого я использую opengl? Решит ли это проблему? Спасибо за вашу помощь. - person Nick; 21.02.2010
comment
Извини, Ник. Я понятия не имею, поможет ли это. каким-то образом вам нужно ускорить рисование, но я понятия не имею, что ваше рисование делает, и в любом случае я не специалист по opengl. - person John Knoeller; 21.02.2010
comment
Есть ли способ полностью игнорировать насос сообщений? И просто рисовать в созданном окне? У меня есть некоторые успехи, но это не идет гладко. - person Nick; 22.02.2010
comment
Вы можете нарисовать любое сообщение, которое хотите, но если вы не сделаете свой рисунок быстрее, то все, что вы сделаете, это переместите проблему. Вам никогда не будет позволено обрабатывать более одного сообщения одновременно. вам нужно сделать код рисования быстрее. как я уже говорил несколько раз. Если вам нужна помощь в выяснении того, как сделать это быстрее, чем публиковать больше вопросов, показывающих, что вы пытаетесь сделать и что вы пробовали, таким образом вы получите больше взглядов и советов, чем просто мои. - person John Knoeller; 22.02.2010
comment
Быстрее? Я даже не могу использовать двойную буферизацию с битблтом, потому что, когда я это делаю, времени, которое требуется для битблта, достаточно, чтобы мышь снова начала дергаться. Я попробую использовать opengl или d3d. - person Nick; 22.02.2010

WndProc() не всегда является повторным входом. Я полагаю, что с основным потоком сообщений сообщения мыши и клавиатуры ставятся в очередь и ждут, пока вы закончите предыдущее сообщение WM_PAINT. И наоборот, если бы вы вызвали SendMessage() из WndProc(), то вы столкнулись бы с повторным входом. Другой случай — PostMessage(), который добавит сообщение в очередь. Возможно, стоит рассмотреть использование DirectInput для ввода с помощью мыши и клавиатуры, если это проблема. В противном случае ищите способы ускорить рисование.

person Jeff    schedule 20.02.2010
comment
Вы также должны изменить свой вызов SelectObject() на DeleteObject(SelectObject(hdc, handle_brush)); - person Jeff; 20.02.2010
comment
@ Ответ Джона - его таймер вызывает InvalidateRect(), поэтому WM_PAINT будет результатом WM_TIMER. Правильный? - person Jeff; 20.02.2010