Why does BINDEVENT not work with StatusBar_Change?


A customer had a question and sent some code:


 


PUBLIC oHandler


oHandler = NEWOBJECT(“StatusBarText”)


?BINDEVENT(_VFP,[STATUSBAR],oHandler,[STATUSBAR_CHANGE],1)


 


_VFP.StatusBar = “AAAA” && triggers handler


 


SET MESSAGE TO “1111” && does not trigger handler


 


*navigate menus: does not trigger handler


 


DEFINE CLASS StatusBarText AS Session


      PROCEDURE StatusBar_Change


            ?PROGRAM(),_vfp.StatusBar


      RETURN


ENDDEFINE


 


 


 


This code demonstrates 3 ways to change the status bar text, but only one fires the hooked event.


 


The status bar text can change in various ways, which means there are various code paths internal to VFP that are followed. When changing the status bar text directly via direct assignment to _VFP.Statusbar, the normal VFP code (the object manager) that changes an object’s property gets invoked, which knows to check for and execute any BindEvent code.


 


When the user activates a menu, the WM_ENTERIDLE Notification  is sent to VFP’s Window procedure with WPARAM = MSGF_MENU, which tells VFP to draw the menu message on the status bar.


 


When the user executes SET MESSAGE TO, the internal VFP object manager is completely bypassed to change the status bar text.


 


The BINDEVENT  feature allows the user to bind events to when an object property or method is invoked or changed. When I implemented the feature, I modified the internal VFP object manager to check for user bound events. I paid no attention to the SET MESSAGE TO and the WM_ENTERIDLE code, which had been in existence for several versions.


 


I suppose one could argue that this is a bug, but the documentation says:


to bind events, properties, or methods from native Visual FoxPro objects to other Visual FoxPro objects.


 


 


There is a simple workaround: use Bindevents to bind to the WM_ENTERIDLE message and change SET MESSAGE TO cNewMessage to _VFP.StatusBar=cNewMessage


 


 


 


#define GWL_WNDPROC         (-4)


 


#define WM_ENTERIDLE                    0x0121


#define MSGF_DIALOGBOX      0


#define MSGF_MESSAGEBOX     1


#define MSGF_MENU           2


#define MSGF_SCROLLBAR      5


 


PUBLIC oHandler


oHandler = NEWOBJECT(“StatusBarText”)


?BINDEVENT(_VFP,[STATUSBAR],oHandler,[STATUSBAR_CHANGE],1)


?BINDEVENT(_vfp.HWnd,WM_ENTERIDLE,oHandler, “HandleMsg”,5)


_VFP.StatusBar = “AAAA” && triggers handler


 


SET MESSAGE TO TRANSFORM(SECONDS()) && does not trigger handler


 


 


 


DEFINE CLASS StatusBarText AS Session


      dwOrigWindProc=0


 


      PROCEDURE init


            DECLARE integer GetWindowLong IN WIN32API ;


                  integer hWnd, ;


                  integer nIndex


            DECLARE integer CallWindowProc IN WIN32API ;


                  integer lpPrevWndFunc, ;


                  integer hWnd,integer Msg,;


                  integer wParam,;


                  integer lParam


 


            THIS.dwOrigWindProc =GetWindowLong(_VFP.HWnd,GWL_WNDPROC)  


      PROCEDURE HandleMsg(hWnd as Integer, msg as Integer, wParam as Integer, lParam as Integer)


            LOCAL nRetvalue


            nRetvalue=0


*           ?PROGRAM(),msg,TRANSFORM(wParam,”@0x”),TRANSFORM(lParam,”@0x”),” “


            DO CASE


            CASE msg =WM_ENTERIDLE


                  IF wParam = MSGF_MENU


                        *call default processing to set menu message


                        nRetvalue=CallWindowProc(this.dwOrigWindProc,hWnd,msg,wParam,lParam)


                        ?PROGRAM(),_vfp.StatusBar


                  ENDIF


            ENDCASE


            RETURN nRetvalue


 


      PROCEDURE StatusBar_Change


            ?PROGRAM(),_vfp.StatusBar


      RETURN


ENDDEFINE


 


 


See also How to hook command window keystrokes.


Why doesn’t drag/drop work with BindEvents?


Is this a bug in BindEvents?


 


 

Comments (6)

  1. Carlos Alloatti says:

    Nice workaround, thanks! Can this code be used freely?

    Now, what about the StatusBarText property of controls?

    And lets not forget about the database:table recno/reccount, etc messages, but those nobody wants to display anyway…

    It looks like there are a lot of guys displaying text in the VFP statusbar, each of them competing to overwrite each other´s text.

    If they all just relied on setting the _vfp.statusbar property, that would be nice.

  2. Fabián says:

    It works great! but only when a Menu or Popup has a MESSAGE, but not occurs the same when i modify the property StatusBarText of a control (commandbutton, textBox, comboBox, …, etc.). What can i do in that case?

  3. Luis Navas says:

    Calvin, any other workaround for what Fabian wrote?

  4. ChrisRChamberlain says:

    Calvin – would like to SET STATUS BAR OFF and add a container c/w controls to _SCREEN to create a standalone StatusBar class.

    Your code posted relies on SET STATUS BAR ON and outputting the messages to controls in the container simulating the statusbar fails if SET STATUS BAR OFF.

    Any ideas on a workaround?

    Chris

  5. Terry Thurber says:

    Is it possible to trap for the instant a form resize begins and the instant it stops?

    Looking for a list of other CallWindowProc message pointers, like "WM_ENTERIDLE" that would be appropriate to bind to a form "resize" in VFP.

    Thanks