Detecting LButtonUp LButtonDown over RMChart

Started by dacarle, June 23, 2005, 04:35:30 PM

Previous topic - Next topic

dacarle

I have a dialogue which displays a graph using RMChart.  I need to be able to detect LButtonUp and LButtonDown on the chart area.  

All help appreciated.

-David

TechSupport

I suspect that you should subclass the RMChart control and respond to the appropriate message in your subclassed message handler. There are lots and lots of examples of subclassing on the PB Forum.

dacarle

Not sure how to do this.  There are no callbacks, the control just paints the graph onto a designated dialogue window to specific coordinates.  Any thoughts or examples or work arounds would be appreciated.

TechSupport

I have never used RMChart, but if it only paints the chart onto a dialog then I assume that you can use the built in FireFly mouse message handlers for the Form.

I mean, you know at what coordinates you are drawing the chart on the Form. In the FireFly mouse message handlers you normally get the client xPos and yPos mouse position.... so all you need to do is to determine if the mouse is currently over the chart.


Function FORM1_WM_LBUTTONDOWN ( _
                             hWndForm      As Dword, _  ' handle of Form
                             MouseFlags    As Long,  _  ' virtual keys that are pressed
                             xPos          As Long,  _  ' x-coordinate of cursor
                             yPos          As Long   _  ' y-coordinate of cursor
                             ) As Long

Local rc As Rect

'Example, the rectangle that contains the RMChart
SetRect rc, 5, 5, 50, 100

If PtInRect( rc, xPos, yPos ) Then
  MsgBox "Mouse clicked on chart"
End If  

End Function

dacarle

Thanks Paul.  Will try in the morning.  My only concern is when trying something like this earlier, the lbuttonup and down worked fine on the form similar to what you suggest, however, only outside of the graph area, but not within the graph area.  I will try adding the rect code you specified.

-David

TechSupport

I just downloaded RMChart and ran the PowerBASIC demo. The graphs are not painted on to the dialog. They are created as child controls as I had originally thought. The class name is "RMC". You can easily see this for yourself using a program like Spy++.

So, I still say that the best route is to subclass the child control (i.e. the Chart control) and then respond to the mouse messages in your subclass message handler.

Do you need help with the subclassing code?

TechSupport

... a very quick search in POFFS shows a generic skeleton for subclassing posted by Lance Edmonds:

Quote
Subclassing is a method of specifying your own Window or Dialog Procedure (WNDPROC/DLGPROC) that is called instead of the original procedure.
This permits your code to intercept messages and events for particular windows, dialogs and/or controls.  Your code then has the choice of
passing each message on, changing the behaviour of the control to certain messages, or simply "discarding" certain messages.  Additionally,
your code can process the message both before and after the message is passed on to the original procedure if required.


' Create our global variable
GLOBAL gOrigSubClassProc AS DWORD
...
' Set a new class handler (Subclass procedure. Do this immediately after you create your control).
gOrigSubClassProc = SetWindowLong(hWnd, %GWL_WNDPROC, CODEPTR(NewWndProc))
...
FUNCTION NewWndProc(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                 BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG

SELECT CASE wMsg
 CASE %WM_some_message_to_intercept
   ' process the message and exit the function (the original WNDPROC does not get the message)
   EXIT FUNCTION

 CASE %WM_somethingElse
    ' Pass the message on to the orignal WNDPROC()
    EXIT SELECT

 CASE %WM_DESTROY
    ' Restore the original handler, and then pass the message on for the last time
    SetWindowLong hWnd, %GWL_WNDPROC, gOrigSubClassProc
    EXIT SELECT

END SELECT

FUNCTION = CallWindowProc(gOrigSubClassProc, hWnd, wMsg, wParam, lParam)

END FUNCTION

TechSupport

I am a little surprised to see that the RMChart control does not post notification messages to the parent dialog (ie. WM_COMMAND or WM_NOTIFY messages) that would indicate when the mouse is over the control or has clicked on the control. Maybe you could suggest this to the control's author.

TechSupport

Okay, I see that you have already asked a similar question in the author's forum.... Looks like Rainer will be adding it in the next release. Cool.

dacarle

Paul-

thanks for the help.  will let you know how I make out.

-David

dacarle

Paul-

Having a little trouble with the subclassing.  Not sure exactly how and where to set subclassing up to trap the RM Chart.  Any suggestions or direction appreciated.

-David

TechSupport

Okay, I used the sample PB code that comes with RMChart.

Step 1: Define the global variable to hold the original window procedure of the chart control. I simply put it as the first line in the Form's code editor.

GLOBAL gOrigSubClassProc AS DWORD



Step 2: Subclass the chart after it is created. In my test I created the chart after clicking a Command Button.

'------------------------------------------------------------------------------------------------------------------------
Function FORM1_COMMAND1_BN_CLICKED ( _
                                  ControlIndex     As Long,  _  ' index in Control Array
                                  hWndForm         As Dword, _  ' handle of Form
                                  hWndControl      As Dword, _  ' handle of Control
                                  idButtonControl  As Long   _  ' identifier of button
                                  ) As Long

 Call Show_BarsImage( hWndForm)

 ' Set a new class handler (Subclass procedure. Do this immediately after you create your control).
 gOrigSubClassProc = SetWindowLong(GetDlgItem(hWndForm, %ID_RMC1), %GWL_WNDPROC, CodePtr(NewWndProc))

End Function


Step 3: Respond to the mouse message.

FUNCTION NewWndProc(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                 BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG

SELECT CASE wMsg
 Case %WM_LBUTTONDOWN
   ' process the message and exit the function (the original WNDPROC does not get the message)
   
   MsgBox "We have clicked on the Chart"
   Exit Function                        
   

 'CASE %WM_somethingElse
 '   ' Pass the message on to the orignal WNDPROC()
 '   EXIT SELECT

 CASE %WM_DESTROY
    ' Restore the original handler, and then pass the message on for the last time
    SetWindowLong hWnd, %GWL_WNDPROC, gOrigSubClassProc
    EXIT SELECT

END SELECT

FUNCTION = CallWindowProc(gOrigSubClassProc, hWnd, wMsg, wParam, lParam)

End Function

dacarle

Paul-

This works great with an unfortunately large exception which is when the form is sized I have it recalling the function to display the graph with the correct new size.  When this happens the subclassing ceases to work.  I tried calling the subclass routine again also without success and also tried destroying (not sure I did this correctly) the subclass before calling the subclass routine, also without success.  I am sure there is a simple solution for this which is eluding me.

-David

TechSupport

hmmm.... so in your WM_SIZE message handler you are destroying the control and re-creating it ???

dacarle

not destroying the control, trying to destroy the subclass and recreate it.  I know the problem is muddled in here somewhere.

1 .Create Form
2. Call Chart Function (with current form size which creates ctrl on form)
3. Create SubClass
works fine
4. When form is sized Call Chart Function (with current form size which creates ctrl on form)??


I have tried before recreating the subclass after #4 as well as killing subclass prior to call chart in #4, calling the chart and then creating the sublcass again.

I can see I tell I am not doing something right, but not sure exactly what.