DougHennig / Ribbon

A Microsoft Office 365-like ribbon control for VFP forms
24 stars 11 forks source link

After form / ribbon released I get error "1923 - Object LOTHISFORM is not found" #18

Open VfpImaging opened 1 year ago

VfpImaging commented 1 year ago

This happens occasionally under production only, I still could not get the right steps. I am using some short scripts for the ribbon buttons. It seems that if I close the Form during the execution of a process EXECSCRIPT gets angry ;-)

LOGOmichael commented 1 year ago

I just stumpled across a very related point where the definition of loThisForm is defined.

I found this weird to do so, but i do understand the neccesity of it. I marked it for me to find something better.

...especially because i really do not like the nameing. loThisfoform suggests it is local, but indeed this is explicity defined as public and a name so simple as "loThisform" is destined to collide with other (local) defintion in surrounding codes.

But that's only my 2 cent on this 😃

VfpImaging commented 1 year ago

I worked a little bit more on that. This issue was because the dropdown menu was still alive, and the menu was still trying to fire using ExecScript the commands. After I added on Destroy() event of my form : Thisform.RemoveObject("oRibbon") the dropdown menu was imediately closed and the error did not happen again. Anyway, to avoid this issue I would auto close the Menu form when on the "MouseLeave" event, avoiding some known timer issues.

DougHennig commented 1 year ago

@VfpImaging Unfortunately, there is no MouseLeave event for a form, so I have to use a timer instead.

Also, if i drop down a menu for a button and then close the form, the menu disappears. Can you give me some steps to reproduce this using the sample form that comes with the project, or provide me with some code I can run to create the ribbon and then steps to reproduce the problem?

VfpImaging commented 1 year ago

Hi Doug, Yes, but you could add all menu items in a container, of the same size of the Main form, so that we could have a "MouseLeave" event! I know this would bring some extra work, I truly don't know if it's worth. My issue was happening because I instantiated the ribbon class using NewObject, and some object references were probably being held. Usng "RemoveObject" in my form's Destroy event solved the issue, and the Menu was gone!

DougHennig commented 1 year ago

Thanks for the suggestion. I will consider doing that in the future.

VfpImaging commented 1 year ago

Been playing a little more, and noticed that in my form the menu is not released when another menu is opened. Crazy then, both menus are opened at the same time, see the animated GIF below. If you give me some hints, I could try to debug it and look for the issue. I played with the sample form provided, but it works perfectly. IOW, the issue happens only on my side.

RibbonMenu

DougHennig commented 1 year ago

I'd have to see your code. It almost looks like two events are firing.

VfpImaging commented 1 year ago

Here it is, I made a big "CleanUp at the code", trying to identify the problematic object. Also removed from the parent form all the API Calls, removed the Ctl32 objects and scrollbars. Using the ribbon in an "InScreen" form

Below is the code that generates the video below:

LOCAL lcImagePath
m.lcImagePath = ADDBS(_SCREEN._FoxyPath) +  "Images\" 

THISFORM.NEWOBJECT("oRibbon", "SFRIBBON", "PR_SFRIBBON.VCX", _SCREEN._FoxyModule)

WITH THIS.oRibbon
    * Set up the Home tab.
    m.loTab = .ADDTAB("Home")

    WITH m.loTab
        .CAPTION = "Home"

        * Set up the New section.
        m.loSection = .AddSection()
        WITH m.loSection
            .CAPTION = "Output"
            * Show the Save to file button
                m.loButton = .AddButton()
                WITH m.loButton
                    .CAPTION = "Save Report"
                    .Image = lcImagePath + "pr_Save_32_0.bmp"
                    .AddBar("Save as PDF", "_goFP._oExHandler.DoSave(2)", m.lcImagePath + "pr_Pdf.bmp")
                    .AddBar("Save as XLS", "_goFP._oExHandler.DoSave(5)", m.lcImagePath + "pr_Excel.bmp")
                ENDWITH && loButton
        ENDWITH

        * Set up the ZOOM section.
        m.loSection = .AddSection()
        WITH m.loSection
            .CAPTION = "Zoom"
            m.loButton = .AddButton()
            WITH m.loButton
                .CAPTION = "Zoom"
                .Image = m.lcImagePath + "pr_Zoomin_32.bmp"
                .AddBar(ZOOM_LEVEL_PROMPT_50_LOC, "Thisform.ActionSetZoom2(3)")
                .AddBar(ZOOM_LEVEL_PROMPT_75_LOC, "Thisform.ActionSetZoom2(4)")
                .AddBar(ZOOM_LEVEL_PROMPT_100_LOC, "Thisform.ActionSetZoom2(5)")
                .AddBar(ZOOM_LEVEL_PROMPT_150_LOC, "Thisform.ActionSetZoom2(6)")
                .AddBar(ZOOM_LEVEL_PROMPT_200_LOC, "Thisform.ActionSetZoom2(7)")
            ENDWITH
        ENDWITH
    ENDWITH && m.loTab

    * Auto-select the Home tab.
    .HOME.SELECTED = .T.

ENDWITH

THISFORM.oRibbon.LEFT = 1
THISFORM.oRibbon.TOP  = 1
THISFORM.oRibbon.VISIBLE = .T.

RibbonMenu2

VfpImaging commented 1 year ago

I went a little bit further with my tests,

In "SfRibbonToolbarButton.ShowMenu()", adding the following code solved the issue of the two menu forms visible:

LOCAL loExc
TRY
    * If the last menu is visible, close it.
    IF NOT PEMSTATUS(_Screen, "oLastMenu", 5)
        _Screen.AddProperty("oLastMenu", "")
    ENDIF

    LOCAL loLastMenu as Control
    m.loLastMenu = _Screen.oLastMenu

    IF VARTYPE(NVL(m.loLastMenu,"")) = "O" AND m.loLastMenu.Menu.Visible
        m.loLastMenu.Menu.HideMenu()
        RELEASE loThisform
    ENDIF
    _Screen.oLastMenu = This

CATCH TO m.loExc
    SET STEP ON
ENDTRY

* The original code comes below:

* Display the menu below ourselves.
local llInScreen
m.llInScreen = Thisform.HWnd = _screen.HWnd
dodefault(objtoclient(This, 1) + ;
      This.Height + Thisform.Top + ;
      iif(m.llInScreen, 0, sysmetric(9) + sysmetric(4)) + ;
      iif(Thisform.Desktop or m.llInScreen, 0, sysmetric(9) + sysmetric(20)), ;
      objtoclient(This, 2) + Thisform.Left + iif(m.llInScreen, 0, sysmetric(3)))

The "oLastMenu" property should reside on the main object, and obviously be properly released on "destroy()"

RibbonMenu3

VfpImaging commented 1 year ago

Whenever a user clicks outside the menu it will loose focus, so even better and sweeter than the above, "Deactivate()" comes to the rescue:

This.Hide()

DougHennig commented 1 year ago

The problem with using This.Hide in SFRibbonMenuForm.Deactivate is when a menu has a submenu, the first menu disappears when the submenu is displayed. I went with the oLastMenu solution.