2009-02-06 17 views
5

Tengo una ventana que maneja los mensajes WM_NCLBUTTONUP, para manejar los clics en los botones personalizados en la barra de título. Esto funciona muy bien cuando la ventana está maximizada, pero cuando no lo es, ¡el mensaje WM_NCLBUTTONUP nunca llega! Sin embargo, recibo un mensaje WM_NCLBUTTONDOWN. Extrañamente WM_NCLBUTTONUP llega si hago clic a la derecha de la barra de menú, pero en cualquier lugar a lo largo de la barra de título/marco de ventana, el mensaje nunca llega.El curioso problema del mensaje WM_NCLBUTTONUP que falta cuando una ventana no está maximizada

Después de un tiempo de depuración descubrí que si establecía un punto de interrupción en CMainFrame :: OnNcLButtonDown(), hacía clic en la barra de título, pero mantenía presionado el botón del mouse, dejaba que el depurador interrumpa la función, pulsa F5 para continuar depuración, luego suelte el botón del mouse - ¡mágicamente se envía WM_NCLBUTTONUP!

Mi pregunta es doble, (1) ¿Qué demonios está pasando? (2) ¿cómo puedo solucionar este "problema"?

También observo que hay muchas otras personas en Internet que tienen el mismo problema (un Google rápido revela muchas otras personas con el mismo problema, pero no tiene solución).

Editar
Gracias por las dos primeras respuestas, he intentado llamar ReleaseCapture en NCLButtonDown, pero no tiene ningún efecto (de hecho, devuelve NULL, lo que indica una captura no está en su lugar). Solo puedo suponer que la funcionalidad de la clase base (def window proc) puede establecer una captura. Voy a investigar el lunes ...

Respuesta

4

He tenido este mismo problema. El problema es que, al hacer clic con el botón izquierdo en el título de la ventana, se inicia un arrastre y, por lo tanto, se captura el mouse, lo que impide que llegue WM_NCLBUTTONUP.

la solución es anular WM_NCHITTEST:

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (nMsg) 
    { 
     ... 
     case WM_NCHITTEST: 
      Point p(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam); 
      ScreenToClient(p); 
      if (myButtonRect.Contains(p)) 
      { 
       return HTBORDER; 
      } 
      break; 
    } 
    return DefWindowProc(hWnd, nMsg, wParam, lParam); 
} 

Así que, esencialmente se informe de Windows que el área ocupada por el botón no es parte del título de la ventana, pero una parte no específica de la zona no cliente (HTBORDER).

Nota al pie: Si ha llamado a SetCapture() y aún no se llama ReleaseCapture() cuando espera que entre el mensaje WM_NCLBUTTONDOWN, no llegará incluso con el cambio anterior. Esto puede ser irritante ya que es normal capturar el mouse durante la interacción con dichos botones personalizados para que pueda cancelar el clic/resaltar si el mouse sale de la ventana. Sin embargo, como alternativa al uso de la captura, puede considerar SetTimer()/KillTimer() con un intervalo corto (por ejemplo, 100 ms), que no hará que los mensajes WM_NCLBUTTONUP desaparezcan.

2

Una conjetura salvaje: algún código está capturando el mouse, probablemente para facilitar el movimiento de la ventana cuando agarras el título. Eso explicaría también por qué la interrupción del depurador provocaría la aparición del mensaje: la interacción del depurador borra la captura del mouse.

Le sugiero que ejecute Spy ++ en esa ventana y en sus hijos y trate de averiguar quién recibe el mensaje de botón.

En cuanto a cómo solucionarlo, no puedo ayudarlo sin mirar el código real. Tendrás que descubrir quién es el culpable y mirar su código.

1

Para agregar a Franci Penov's answer, un clic en la barra de título se interpreta como el inicio de un arrastre para cambiar la posición de la ventana. La ventana está capturando el mouse para que pueda realizar el arrastre. Como no se puede arrastrar una ventana maximizada, la captura se salta y el mensaje se enruta normalmente.

1

incluyen ReleaseCapture() en WM_NCLBUTTONDOWN {bloque de código}

Cuestiones relacionadas