|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Dynamic Menu-building problemhttp://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.vb.general.discussion&mid=d6275694-54f8-4542-88e3-b7aaf772295f The last exchange on the old thread was on April 24, so perhaps it's not going to show up on folks' browsers any more. I had a few exchanges with Steve Gerrard, and a lot of my problems were eventually solved after those, but we concentrated on the mechanics of containing one UC inside another, and my original problem (see subject) has still not been solved. Steve, I hope you're still watching! To recap - I have a form which displays one of many user controls, the UCs being sited on the form dynamically when it is opened, and according to what it is intended to do. Other controls on the form allow the user to switch between visible UCs, or to move the current UC across a host PictureBox using scrollbars, in the event that the form has been resized to the point that the entire UC is not visible within the host PictureBox. Previously the app had many different forms, and the selection of UCs on each was fixed, but the resizing management code was identical across them all, and I wanted to avoid having to maintain it in many places. Hence the move to a single form and dynamic siting of UCs. OK - in the days when I had many forms, the various menus were all written into the forms, and if a different UC were selected by the user, the form could hide some menus and display others. With my new scenario, I have menus written into the UCs, so that if a new one gets the focus, its menus appear instead of those of the previous UC. However - I mentioned a few moments ago that the form has other controls on it. If one of those gets the focus, the UC's menus disappear. That's not what I want to happen. I want the presently visible UC's menus showing on the form even when it loses the focus. After all, it seems unreasonable to expect the user to click on the UC to get its menus back! I have one simple option - the code can immediately set the focus back to the UC as soon as one of the other controls gets it. But this isn't pretty - because the UC's menus momentarily disappear and then reappear. In fact, it looks pretty ugly. I think the only way to avoid this is to make the menus part of the form, and set them up dynamically at the same time that the form is configured with its selection of UCs. But I have no idea how to do this. Perhaps someone here could explain? Since I will have to manage the showing and hiding of menus myself, I am going to need some way of reproducing (a) menu(s) without going through the form configuration code again - so I need to store the definition of each menu somehow, so that it can be rebuilt as required. How will I associate a menu item with a specific code entry point in the UC? What happens if some condition in the UC requires that a menu item become invisible, disabled, or has a check mark added (or removed)? Clearly the UC needs some way to control its menus, even though they are now owned by the form. "Andy" <andrewjellis@hotmailnospam.com> wrote in message Yup I am, not sure if that is good :)news:8D47B357-AEC7-4590-9B3B-D3D413C96C46@microsoft.com... > This is really a continuation of an earlier thread - see > http://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.vb.general.discussion&mid=d6275694-54f8-4542-88e3-b7aaf772295f > > Steve, I hope you're still watching! > I think the only way to avoid this is to make the menus part of the form, It seems to me you have two options. The first is to put all the menus for all > and set them up dynamically at the same time that the form is configured with > its selection of UCs. But I have no idea how to do this. Perhaps someone > here could explain? > > Since I will have to manage the showing and hiding of menus myself, I am > going to need some way of reproducing (a) menu(s) without going through the > form configuration code again - so I need to store the definition of each > menu somehow, so that it can be rebuilt as required. How will I associate a > menu item with a specific code entry point in the UC? What happens if some > condition in the UC requires that a menu item become invisible, disabled, or > has a check mark added (or removed)? Clearly the UC needs some way to > control its menus, even though they are now owned by the form. the UCs in the main form, then show and hide them when the form changes to a different UC. That would separate the menus from the UCs, which is not so good, but you could use the menu designer to build them all. The second is to setup a class that defines the properties a menu needs (caption, etc), then have each UC expose a collection of these CMenu items. If you need nesting, you would need to build that into the class as well, presumably as a collection of NestedItems, which are themselves CMenus. Try to minimize nesting, as loading them dynamically will be trickier. In either case, you should become familiar with menu arrays, where the items have the same name and different indexes. As with control arrays, these all fire the same event, which receives the Index as a parameter. You will need some base menu items on the main form, setup to be menu arrays, which you can then fill in dynamically. On the main form, the event handler for a menu item can call the current UC, telling it which menu item got clicked. You could use the Tag property of menu items to help identify them, or use the indexes or captions. The UC would have a method such as MenuClicked that can be called from the main form. It would then do some sort of Select Case on the passed parameter, and act accordingly. You could also raise an event from the UC when a menu state needs to change. It would need to identify which menu item to change, and what to change. The main form can then receive the event and make the change. Or the main form can ask the UC about state just before showing the menu items, when the top level menu gets clicked. Nobody said it would be simple... "Steve Gerrard" wrote: It's good for me - at least you have a fair idea where I'm at with this. > > Steve, I hope you're still watching! > > Yup I am, not sure if that is good :) Although I can see I might have to explain the app in a bit more detail for you to see where I'm going with it... > It seems to me you have two options. The first is to put all the menus for all I'm not sure I like that idea very much. I could end up with very many menu > the UCs in the main form, then show and hide them when the form changes to a > different UC. That would separate the menus from the UCs, which is not so good, > but you could use the menu designer to build them all. items on the form, and a huge 'ConfigureForm' Sub which serves to hide most of them, depending on which object type will be maintained by a particular form instance. I still have the problem of specifying which UC's code (and which public Sub within that UC) must be called when each menu item is clicked. That kind of suggests having a structure within the form which is maintained by Sub ConfigureForm, and by means of which the corresponding Sub in a UC is called in response to clicking a menu item. That could be messy. > The second is to setup a class that defines the properties a menu needs Maybe I like this approach a bit more. I'm not too worried about nesting, > (caption, etc), then have each UC expose a collection of these CMenu items. If > you need nesting, you would need to build that into the class as well, > presumably as a collection of NestedItems, which are themselves CMenus. Try to > minimize nesting, as loading them dynamically will be trickier. because collections don't frighten me. I already have a collection of 'EditMode's in the main form - each EditMode has a reference to the hosted UC which must be brought into view when the corresponding (leaf) node in the TreeView is clicked. (Remember my TreeView? I now add nodes to this from ConfigureForm, by calling Subs in the main form. The nodes in the TreeView have keys matching those of the EditModes collection, so it's an easy matter to identify which UC to bring to the front after a TreeView node is clicked.) If there's a corresponding Menu structure to be stored against an EditMode, I can add that to the EditMode class, and all I need is a means of rebuilding the menu from the stored structure. But against each menu item rebuilt in this way, I need to make the association with a specific chunk of code in the UC. > On the main form, the event handler for a menu item can call the current UC, OK, I can see how that works.> telling it which menu item got clicked. You could use the Tag property of menu > items to help identify them, or use the indexes or captions. The UC would have a > method such as MenuClicked that can be called from the main form. It would then > do some sort of Select Case on the passed parameter, and act accordingly. > You could also raise an event from the UC when a menu state needs to change. It That looks like good common sense as well. Although I can see a major > would need to identify which menu item to change, and what to change. The main > form can then receive the event and make the change. Or the main form can ask > the UC about state just before showing the menu items, when the top level menu > gets clicked. complication with it. Remember, my UCs are there because they might be present on many different instances of the form, and the different instances may potentially host different selections of UCs. That means there's always the danger that between different instances of the form, the specific menu items could have different Index values. I will have to keep a lookup dictionary in the form, and set this up from Sub ConfigureForm, so that the form can identify which menu item to modify by concatenating the current EditMode's key with the menu item identifier passed in the event raised by the UC, then looking that up in the dictionary to find the correct menu item in the form. Looks like great fun! Please don't go away - I can see I might have further issues to solve before I have this working properly.
Show quote
"Andy" <andrewjellis@hotmailnospam.com> wrote in message It is more work, but it is a more robust and flexible way to go, especially if news:B4664C30-DF3F-49F2-BC1F-2EF08A9A334D@microsoft.com... > "Steve Gerrard" wrote: > >> The second is to setup a class that defines the properties a menu needs >> (caption, etc), then have each UC expose a collection of these CMenu items. >> If >> you need nesting, you would need to build that into the class as well, >> presumably as a collection of NestedItems, which are themselves CMenus. Try >> to >> minimize nesting, as loading them dynamically will be trickier. > Maybe I like this approach a bit more. further development will occur in the future. > Please don't go away - I can see I might have further issues to solve before LOL. I'm not going anywhere soon, save a couple of days to see my nephew > I have this working properly. graduate high school. If you are going to try this route, I would begin with the CMenuItem class. The main properties to have are Caption, Tag, Checked, Enabled, and Visible, to be set in the UC code as it builds its collection. You could also add an Index, initially 0. If this is read/write, you could store the actual index in it when it gets put in a menu on the main form. However I would try and use the Tag property to keep track of the menu items, unless you need it for something else. If you are going to have sub menus, then CMenuItem would also need a collection property that would return a collection of CMenuItem objects to define it's sub menu. To set them up in your UC's, you can open each .ctl file using Notepad. You will find the menu described in the first part of the file, before Option Explicit and the beginning of the actual code. It might look something like Begin VB.Menu mnuTest Caption = "Test" Enabled = 0 'False Begin VB.Menu mnuTestA Caption = "TestA" Checked = -1 'True End End Begin VB.Menu mnu2 Caption = "Menu2" Enabled = 0 'False End Using this, you can write code to create a collection of CMenuItem objects in each UC, to match the menu you have put there using the designer. Once that's all done, we can talk about the code in the main form that will load up real menu items based on this data. One hint of what I would recommend, and have done myself in a major app: create an interface such as UCWithMenu, and implement it in each UC. This will allow the form code to work with different UCs the same way. More next time... "Steve Gerrard" <mynameh***@comcast.net> wrote in message One more thing: if you make the Tag property of each CMenuItem be what was the news:35adnVl3IJrHTNrbnZ2dnUVZ_sWdnZ2d@comcast.com... > > "Andy" <andrewjellis@hotmailnospam.com> wrote in message > news:B4664C30-DF3F-49F2-BC1F-2EF08A9A334D@microsoft.com... >> "Steve Gerrard" wrote: >> > > > Using this, you can write code to create a collection of CMenuItem objects in > each UC, to match the menu you have put there using the designer. > Name property of the original menu item, your later code will still make sense, and require less changes. The main MenuClicked(Tag As String) sub in your UC can do a select case on the Tag, and then call the matching menu click handler you already have. "Steve Gerrard" <mynameh***@comcast.net> wrote in message One more-more thing: if you want to take this out of the newsgroup, feel free to news:upCdnRx-vZoTT9rbnZ2dnUVZ_sSmnZ2d@comcast.com... > > email instead. Just put my name without spaces where it says to in mynameh***@comcast.net "Andy" <andrewjellis@hotmailnospam.com> wrote in message Or maybe just use a toolbar on each UC?news:8D47B357-AEC7-4590-9B3B-D3D413C96C46@microsoft.com... > This is really a continuation of an earlier thread - see > http://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.vb.general.discussion&mid=d6275694-54f8-4542-88e3-b7aaf772295f > "Steve Gerrard" wrote: But wouldn't I see the same problem - i.e. the toolbar would disappear when > Or maybe just use a toolbar on each UC? one of the other controls on the main form got the focus? "Andy" <andrewjellis@hotmailnospam.com> wrote in message No, the toolbar could be in the UC, and would a part of it, like a picture box, news:4DC80D85-F22D-40E1-A1E3-34E4A25D18A8@microsoft.com... > "Steve Gerrard" wrote: > >> Or maybe just use a toolbar on each UC? > > But wouldn't I see the same problem - i.e. the toolbar would disappear when > one of the other controls on the main form got the focus? aligned at the top of it. It doesn't have the same range as a menu, i.e. drop down items can't be checked, but it can live in the UC. "Steve Gerrard" wrote: I see what you mean - but I have to dismiss that idea I think. Remember, my > No, the toolbar could be in the UC, and would a part of it, like a picture box, > aligned at the top of it. It doesn't have the same range as a menu, i.e. drop > down items can't be checked, but it can live in the UC. UCs are hosted in a PictureBox (picHost) on the form, and if there isn't enough room in picHost for the entire UC, we get scrollbars for repositioning the UC so that (for example) we can now see the bottom of the UC instead of the top. That means the toolbar would disappear off the top. Any 'tools' functionality provided by the toolbar would then be unavailable. So the toolbar would have to be independent of the UC. With a menu, the functionality is always available. |
|||||||||||||||||||||||