PlanetSquires Forums

Support Forums => Other Software and Code => Topic started by: dacarle on June 23, 2005, 04:35:30 PM

Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 23, 2005, 04:35:30 PM
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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 23, 2005, 07:14:33 PM
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.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 23, 2005, 09:51:58 PM
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.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 23, 2005, 10:58:41 PM
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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 23, 2005, 11:08:27 PM
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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 24, 2005, 12:10:27 AM
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?
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 24, 2005, 12:16:43 AM
... 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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 24, 2005, 12:21:12 AM
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.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 24, 2005, 12:25:07 AM
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.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 24, 2005, 09:59:48 AM
Paul-

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

-David
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 26, 2005, 04:52:27 PM
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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 26, 2005, 05:41:04 PM
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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 27, 2005, 12:21:48 PM
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
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 27, 2005, 02:10:58 PM
hmmm.... so in your WM_SIZE message handler you are destroying the control and re-creating it ???
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 27, 2005, 02:42:23 PM
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.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 27, 2005, 02:47:28 PM
control kill prior to calling the chart with the new size and the recreating the subclass works.  Thanks.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 27, 2005, 03:19:20 PM
It may work but that certainly doesn't seem like the best solution. I guess that internally RMChart is resetting its window procedure when it redraws the new chart. I'll try some tests later to see what exactly happens. You should be able to resize the control without having to kill it and re-apply the subclass.

Have you seen Rainier's post in his form about the beta that he has ready. Apparantly, it handles the mouse messages for you now.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 27, 2005, 03:21:44 PM
Scratch that last post... looks like you have already posted in the RMChart forum about the beta. I hope that it will solve the problem more elagantly than having to go through this subclass route.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 27, 2005, 03:24:12 PM
Agreed about Rainer's updates.  However, just making sure I have backup in case he run's into some delays.
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 27, 2005, 05:24:57 PM
David,

I just tried an extremely simple experiment by resizing the chart in the Form's WM_SIZE message handler. The chart resized and it did not affect the subclassing at all. I did not have to destroy or re-create the control at all. Are you doing something strange that I am not aware of? :)


Function FORM1_WM_SIZE ( _
                      hWndForm      As Dword, _  ' handle of Form
                      fwSizeType    As Long,  _  ' type of resizing request
                      nWidth        As Long,  _  ' new width of client area
                      nHeight       As Long   _  ' new height of client area
                      ) As Long


'resize chart to 75% of the Form's width and height
SetWindowPos GetDlgItem(hWndForm, %ID_RMC1), 0, 0, 0, nWidth * .75, nHeight * .75, %SWP_NOZORDER


End Function
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 27, 2005, 05:45:05 PM
Will try your example in a few.  As far as strange goes, odds are extremely likely.  I tend to prefer to think of myself as unique, which when all is said and done is just a fancy word for strange.  Thanks again.

-David
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 27, 2005, 05:48:16 PM
Paul-

The challenge is going to be to be able to pass data to the form.  I am using the button up to detect moving a global variable onto the graph which adds or changes price data.  This is detected in the subclass perfectly, however, how can I redraw or modify the chart while I am in the subclass?

-David
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 27, 2005, 09:11:05 PM
Off the top of my head:

Create a user defined message (place at the top of the Form).

%USR_RECREATE_CHART = %WM_USER + 1000


In your subclass mouse code, simply post your user message to the Form with the appropriate variable value (or store the value in your global variable like you are doing now). You could pass your value via the wParam or lParam parameter of the PostMessage....

PostMessage HWND_FORM1, %USR_RECREATE_CHART, 0, 0


To get the user defined message, use the CUSTOM message handler for the FORM:

Function FORM1_CUSTOM ( _
                     hWndForm      As Dword, _  ' handle of Form
                     wMsg          As Long,  _  ' type of message
                     wParam        As Dword, _  ' first message parameter
                     lParam        As Long   _  ' second message parameter
                     ) As Long

If wMsg = %USR_RECREATE_CHART Then
 
  'destroy the existing chart
  RMC_DeleteChart %ID_RMC1     'or, maybe simply: DestroyWindow GetDlgItem(hWndForm, %ID_RMC1)
  Call Show_BarsImage( HWND_FORM1, aData() )    
 
      ' 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 If

End Function


I haven't tested this, but it should work.  :)
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 28, 2005, 08:59:17 AM
Will try this morning.  You are the Man!!!!!!!!
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: dacarle on June 29, 2005, 05:27:04 PM
Paul-

Works the first time like it should, in appearance.  However, does not work after the first time and the app becomes unstable.  Closing the chart window closes the entire application.  

-David
Title: Detecting LButtonUp LButtonDown over RMChart
Post by: TechSupport on June 29, 2005, 10:23:12 PM
Okay, I tested it on a live project.

Replace:

RMC_DeleteChart %ID_RMC1

With:

DestroyWindow GetDlgItem( hWndForm, %ID_RMC1)

No GPF's now.

It looks like the RMC_DeleteChart does not actually destroy the control (no WM_DESTROY is sent).