Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Can't trap mouse WM_LBUTTONUP events

Brooks_Van_Horn
New Contributor I
670 Views

I have a running application in x64 mode and I wanted to trap a WM_LEFTBUTTONDOWN event, translate the mouse position to my real world coordinates and write out those coordinates on my GUI and then immediately pick up the WM_LBUTTONUP event and basicall erase the text I had just written. Either I'm not getting the second event or my XOR mode of writing is not working. Any ideas? Here is the code:

!======================================
      case (WM_LBUTTONDOWN)
!======================================
         mx = LOWORD(lParam)       
         my = HIWORD(lParam)
!        mx = GET_X_LPARAM(lParam)
!        my = GET_Y_LPARAM(lParam)
         Call M2R (mx, my, xm, ym)
         write(TxtOut,'(f8.2,1x,f8.2)') xm, ym
         hDC = GetDC(ghWndMain)
         if (hDC == NULL) Then
            WinMainProc = 0
            return
         end if
         ghPen = CreatePen(PS_SOLID, 2, RGB(0,0,0))   ! Thick black Pen
         bret = SelectObject(hDC, ghPen)
         ret = SetROP2(hDC, R2_XORPEN)
         iret = SetBkMode(hDC,TRANSPARENT)
         bret = textOut(hDC, mx, my, TxtOut, 17)
         WinMainProc = -1
         return

!======================================
      case (WM_LBUTTONUP)
!======================================

         bret = textOut(hDC, mx, my, TxtOut, 17)
         bret = DeleteObject(ghPen)
         bret = DeleteDC (hDC)
         WinMainProc = -1
         return

 

Thanks for looking at it. BTW, the first part is working flawlessly. Just not erasing the text I've written.

Brooks

0 Kudos
1 Solution
IanH
Honored Contributor II
670 Views

Unless the application captures the mouse (SetCapture) you cannot rely on getting the WM_xBUTTONUP message as the user may have moved the mouse over a different window in that time.  Typically an application captures the mouse in the button down event and then releases it in the button up event.

You should not call DeleteObject on an object that is still selected into a DC.  Instead you should remember the handle to the object that was originally selected into the DC (it is return value of the SelectObject call) and select that back into the DC, then delete your object.  That is:

new_pen = CreatePen(....)    
old_pen = SelectObject(hdc, new_pen)
! ....Do some drawing here with the new pen
xxx = SelectObject(hdc, old_pen)
xxx = DeleteObject(new_pen)

If you fail to follow the above pattern (or an equivalent) then the DeleteObject call will fail (check the return code!) and you will leak GDI object handles.  This will eventually stop your application from being able to draw anything.

In between the mouse down event and mouse up event, many things could happen that might change the state of the DC and your window - for instance WM_PAINT might get processed.  I wonder whether some of those changes interfere with your application's logic.  I would be inclined to release the DC and delete the relevant objects at the end of the button down processing, and reacquire a DC and recreate the objects when the button up even occurs. 

Note that if the window is repainted in between button down and button up, then that repaint will erase the text that you draw in button down processing, button up processing will then redraw the text, not erase it.  A more typical arrangement is for button down processing to set a flag that communicates to your general window painting code that it should draw the coordinate text on the screen and then invalidate (and perhaps update) the rectangle that bounds that coordinate text.  The general window painting code then checks that flag when painting to decide whether to draw the coordinate text.  The button up processing then clears the flag, and again invalidates (and perhaps updates) the rectangle that bounds the coordinate text.  This gives you a clearer separation of responsibilities between your chunks of code.

View solution in original post

0 Kudos
2 Replies
IanH
Honored Contributor II
671 Views

Unless the application captures the mouse (SetCapture) you cannot rely on getting the WM_xBUTTONUP message as the user may have moved the mouse over a different window in that time.  Typically an application captures the mouse in the button down event and then releases it in the button up event.

You should not call DeleteObject on an object that is still selected into a DC.  Instead you should remember the handle to the object that was originally selected into the DC (it is return value of the SelectObject call) and select that back into the DC, then delete your object.  That is:

new_pen = CreatePen(....)    
old_pen = SelectObject(hdc, new_pen)
! ....Do some drawing here with the new pen
xxx = SelectObject(hdc, old_pen)
xxx = DeleteObject(new_pen)

If you fail to follow the above pattern (or an equivalent) then the DeleteObject call will fail (check the return code!) and you will leak GDI object handles.  This will eventually stop your application from being able to draw anything.

In between the mouse down event and mouse up event, many things could happen that might change the state of the DC and your window - for instance WM_PAINT might get processed.  I wonder whether some of those changes interfere with your application's logic.  I would be inclined to release the DC and delete the relevant objects at the end of the button down processing, and reacquire a DC and recreate the objects when the button up even occurs. 

Note that if the window is repainted in between button down and button up, then that repaint will erase the text that you draw in button down processing, button up processing will then redraw the text, not erase it.  A more typical arrangement is for button down processing to set a flag that communicates to your general window painting code that it should draw the coordinate text on the screen and then invalidate (and perhaps update) the rectangle that bounds that coordinate text.  The general window painting code then checks that flag when painting to decide whether to draw the coordinate text.  The button up processing then clears the flag, and again invalidates (and perhaps updates) the rectangle that bounds the coordinate text.  This gives you a clearer separation of responsibilities between your chunks of code.

0 Kudos
LRaim
New Contributor I
670 Views

This is my hint about this problem.

Create a new pop-up window (e.g. like a tooltip window) at the button-down event, pass the value, paint it and then delete the window at the button-up event.

 

0 Kudos
Reply