MainMenu manipulation library

Discussion in 'Additional Libraries' started by agraham, Dec 7, 2008.

  1. agraham

    agraham Expert Licensed User

    Form main menus are somewhat limited in Basic4ppc in that they may only be constructed in the IDE Designer and their structure is fixed at runtime.This library allows the manipulation of existing main menus and the creation of entirely new ones at runtime. As well as Click events it also provides Popup events for menu items and these events may be attached to existing or new menu items. Besides allowing the menu structure of a form to be altered this library also offers the ability to store complete menu structures and assign them to a form as required.

    This library was inspired by a wishlist item posted by caesar (Michael).

    As usual demo, help file, dll and source code for merging are provided. This library will work on .NET 1.0/1.1 or later on both desktop and device and in the IDE and both legacy or optimised compiled applications.

    Edit :- Version 1.1 posted. See post #17 for details.
     

    Attached Files:

    Last edited: Nov 19, 2010
  2. derez

    derez Expert Licensed User

    Menu

    So you are going to write a new library for every wish ?

    Looks useful, I'll start learning it.
    In the help file, the first "GetMainMenu" is meant to be SetMainMenu...

    edit: This post gave me another star, so thank you twice :)
     
  3. agraham

    agraham Expert Licensed User

    I'm afraid that I can't see anything wrong with that, unless I am missing something obvious! Maybe its a languange nuance. That methods "gets", that is fetches, the MainMenu from the Form specified and "sets" the value in the MainMenu to what has been "got" (or "gotten" - US :)). Similarly NewMainMenu "sets" the present MainMenu to a new empty one.

    EDIT :- I think I may now see what you mean. I originally thought that you meant there was an error in the help file, what you actually meant was that the method itself is misnamed - which I admit it probably is as the direction of the "get" is opposite to that which it usually indicates. Ah well ....!
     
    Last edited: Dec 8, 2008
  4. agraham

    agraham Expert Licensed User

    I've posted an updated help in the first post that may explain this library a little more clearly than the original help does.
     
  5. mjcoon

    mjcoon Well-Known Member Licensed User

    I expect so, but I am still struggling. (My wisdom is going along with my wisdom teeth, perhaps!)

    My problem is understanding how the click or pop-up events (which must be mutually exclusive for any given item) are linked to the user's action. Presumably the event Subs are named after the object that is the subject of the New1() method. But that object can be used (if I follow right) to spawn any number of items that can be added to a main menu.

    Can Sender.Text be used, as for other potentially ambiguous events, to discover which actual menu item was chosen? If so it would be useful to mention this in the Help. If not, how is it done?

    (Of course Sender.Text would require that the leaf nodes in the menu tree all have distinct texts, even if they are theoretically distinguishable by higher levels in the tree. I appreciate that using Sender.Name or SenderFullName.Name would be better, but NewMenuItem() only offers a Text property, not a Name.)

    BTW I stumbled upon this library thread after posting my wishlist item http://www.basic4ppc.com/forum/basic4ppc-wishlist/6298-move-menus-form-form.html#post36868

    Mike.
     
  6. agraham

    agraham Expert Licensed User

    Sender will only give you the name of the Basic4ppc MenuItem object, not the .NET menu item that was clicked or popped up. When a MenuItem event occurs its Text property contains the text of the menu item in question.
    From the demo
    Code:
    Sub MenuItem1_Click
       TextBox1.Text = 
    "Click : " & [B]MenuItem1.Text [/B]& " : " & MenuItem1.Checked
    End Sub
    In the Compact Framework there is no way of identifying individual menu items except by their Text property. They do have a Parent property, not exposed by the library, that is itself a menu item so you could look at the Text property of this with the Door library
    Code:
    Sub MenuItem1_Popup
       Obj1.FromLibrary(
    "NewMenu.MenuItem1""mitem", B4PObject(2))   
       Obj1.Value = Obj1.GetProperty(
    "Parent"' a MainMenu or MenuItem object
       parent = obj1.RunMethod("ToString")
       
    If StrIndexOf(parent, "MenuItem"0) < 0 Then
          parent = 
    "Root" ' a MainMenu doesn't have a Text property
       Else
          parent = Obj1.GetProperty(
    "Text")
       
    End If   
       TextBox1.Text = parent 
    End Sub
     
  7. mjcoon

    mjcoon Well-Known Member Licensed User

    Thanks for that Andrew. I hadn't even noticed that you provided a demo, let alone tried it out. But now I have I still have puzzlement. Originally I could not get the demo to breakpoint on that Sub you cited. Then I spotted the difference between "Click:" and "Click :"! So I added SenderFullName and discovered that there is a name associated with menu items but it is always that of the originating object menuitem1!

    There is a lurking problem behind the use of text rather than name: localisation. Not that I'm going multi-lingual, but it would make identifying menu items that much more complicated.

    I still have not plucked up courage to try that Door. (Must be anticipating "a maze of twisty passages; all alike" - even though I never went into any Dungeons.)

    On the other hand, given I originally wanted to propagate a menu built with the Designer to multiple forms, so I have started experimenting with that. Such menu items of course have names as well as text, and these can be disclosed with Sender. Furthermore SenderFullName shows the module too. But the module remains that in which the menu originated; it is not modified by the copying (not that that is very surprising; are they multiple references to the same structure?). Similarly the click event Sub remains that one that was established in the Designer, in the original module. However I should be able to get around both of those problems (which together would require some tricky use of globals to discover what the environment of the menu click was) by resetting the click event Sub of each cloned menu to a Sub in the corresponding module, and hence inherently aware of the environment. What fun!

    Mike.
     
  8. agraham

    agraham Expert Licensed User

    That's what I told you in the first line of my post above!

    I can't disagree but it's a limitation of the Compact Framework. MenuItem objects in the full .NET Framework have a Tag property that can be used to uniquely label them. However the library is intended for use on both desktop and device and so is lower common denominator. You can always use the Door library to access the Tag property on the desktop if necessary.
     
  9. agraham

    agraham Expert Licensed User

    Just noticed this. Not a good idea! Basic4ppc doesn't cope with removing events from controls so you will probably end up with multiple event sub invocations. You should do something like a CallSub from the event Sub to the code you want to run and get the Sub name from a global, or do a Select.
     
  10. mjcoon

    mjcoon Well-Known Member Licensed User

    So you did!:signOops:

    Ah, I guess that's an unstated hidden limitation of AddEvent(). I had expected to get a slap for calling the menus "cloned" because there is no "Clone()" method in MainMenu and I suspect that each item/structure has to be built separately or else will merely be multiple references to the same structure.

    Oh, well, I guess that the use of CallSub with (yet more) Public Globals is the only way to get what I want.

    An alternative I have been toying with is to use panels on one form so that they can share the same menus. But the Designer is not good at dealing with that, and it makes dividing up code into modules inconvenient too.

    Mike.
     
  11. mjcoon

    mjcoon Well-Known Member Licensed User

    And it was all going so well... :sign0161:

    I was as usual working on the PC IDE until I got what I wanted and moved to my PDA since Andrew assured us that MainMenu.dll will work just as well, including under the two IDEs.

    What I wanted, and got on PC, was a menu structure built in Designer on an arbitrary form amongst at least a half-dozen, read that menu into the MainMenu.dll cache, and then move it to each other form as they are invoked. The menu is a list of the forms to be switched to. Thus the menu always looks the same and if I want to introduce a new form I only have to do it in the single arbitrary version via Designer.

    (Actually I got a bit ambitious, though I don't think that was my downfall. Some of the forms have additional menus specific to their function. I retain these using the cache mechanism in MainMenu.dll, and re-instate them during the menu switching process. This works on PC.)

    Since there are a lot of "leaf" entries in this menu I use AddEvent() in a loop to connect all those leaf entries to a single event Sub. Strangely (on the PC) even when the menu is moved to other forms this Sub remains the capture route for menu activation in all forms. (Not an event for the MenuItem object; I haven't used AddClickEvent ().) But the Sub that does the menu switching knows which is the current form/module and can do the CallSub() as we discussed.

    The code that works on the PC but fails at the last line (#86) cited is as follows:
    Code:
    MainMenuObj.GetMainMenu("Progress.ProgressForm")
       MenuItemObj.ControlRef = MainMenuObj.GetMenuItem(
    0)
       MainMenuObj.SaveMenuItem(MenuItemObj.ControlRef, 
    0)
       MainMenuObj.NewMainMenu
       MenuItemObj.ControlRef = MainMenuObj.SavedMenuItem(
    0)
       MainMenuObj.AddMenuItem(MenuItemObj.ControlRef)
    I don't think that the last four lines are really necessary, so I tried commenting them out and can get past that failure point. However I then get a failure later, in the same way, the next time I attempt an AddMenuItem().

    This is by way of putting down a marker; I can do more experiments such as trimming down Andrew's demo code and then bolting on my sequences.

    Mike.
     
  12. mjcoon

    mjcoon Well-Known Member Licensed User

    I've done all that, and had a frustrating time of it! Almost got to the point where the same code worked on PC and PDA, but...

    Now I'm stumped because I seem prevented from using any version of "Sender" which is crucial to using a single event Sub for multiple menu entries in multiple forms. The "InvalidCastException" error message is attached. Unfortunately it also fails on the PC now with a similar and superficially more explicit but equally baffling "Unable to Cast" message (also attached). Under the PC IDE it runs fine, though without doing any more than showing the MsgBox outputs!

    I have made a simple exhibition of the problem in the attached derivative of Andrew's MainMenu.dll demo code. It shows the menu OK but when you click the event Sub is called but fails at any variety of Sender as above.
     

    Attached Files:

  13. agraham

    agraham Expert Licensed User

    What do I do to create the error in the code you posted :confused:
     
  14. agraham

    agraham Expert Licensed User

    OK got it.

    This doesn't work when compiled for reasons that I won't try to explain why as it concerns how the compiler does things compared to the IDE.

    senderText = Control(SenderFullName).Text




    This is the intended way to get you the text of the MenuItem that was clicked.

    senderText = MenuItem2.Text
     
  15. mjcoon

    mjcoon Well-Known Member Licensed User

    Magic; that works for me, thank you. I'll happily forgo the explanation!

    Mike.
     
  16. agraham

    agraham Expert Licensed User

    For completeness I should also note that if you really do require runtime determination of a control (which you don't appear to) then the new v6.90 syntax for controls works when compiled so I would avoid using the old deprecated "Control(something)" syntax.

    senderText = Menuitem(SenderFullName).Text

    In fact the old syntax will still work when compiled if you provide the control type but I would avoid it and use the new way.

    senderText = Control(SenderFullName, "MenuItem").Text
     
  17. agraham

    agraham Expert Licensed User

    Version 1.1 now posted has had its namespace changed to avoid a name clash with FormExDesktop that occurred when merging the two libraries in the exe.
     
  18. berndgoedecke

    berndgoedecke Active Member Licensed User

    MainMenu and FormExDesktop

    Hello Andew,
    I think you have a lot of work with Android Libaries but I have still another question concerning your B4P library MainMenu.
    Is this library compatibel with Menu of a FormExDesktop Form and how to code it?

    Best Regards

    Bernd Goedecke
     
  19. agraham

    agraham Expert Licensed User

    It should work. Just use FormExName.ControlRef instead of "FormName" when a Form is required.

    MainMenu1.GetMainMenu(FormExName.ControlRef )
     
  20. berndgoedecke

    berndgoedecke Active Member Licensed User

    I've tried it already with no success, but now i'll try it again more meticulously.

    Best Regards

    Bernd
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice