Multiple Font PopupMenus in Same Window

You should read the link I made to New.

  • Add a PopupMenu to your window, select it.
  • In the Inspector, click the gear icon on top and make it Member of a new control set
    -Make it invisible
    -load the font names,
    -Make it visible,
    -clone it with New to produce the second one.
    Example in a button :

dim p as new PopupMenu1 p.left = me.left

When a popupmenu is visible, it takes 4 ticks (1/60th a second) to load the font names
When it is invisible, it takes 3 ticks
Cloning the PopupMenu takes only one tick

How many fonts do you have on your system, @Denise?

This doesn’t seem to work. I have a popupmenu called FontMenu in the IDE. In the window open event I use “FontMenu(0).AddRows(fontarray)” … because "FontMenu.AddRows(fontarray) won’t build because FontMenu is the name of the control set.

Then I do “Dim CloneMenu As New FontMenu” and position it and it appears in the built application window but has no font name row data in it like the original FontMenu.

If you are seeing a delay then I would suspect a problematic, possibly corrupt font.

339 Peter.

Instead of loading in the window Open event, do it in the Open event of the PopupMenu.

To speedup the window display, I would start with only one popupmenu, and add the following ones with New, once the window is already displayed, using a timer.

I would still make the popupmenu invisible during the loadtime, with something like

Dim CloneMenu As New FontMenu cloneMenu.visible = false cloneMenu.AddRows(fontarray) cloneMenu.visible = True

Ok, so here’s the results. I created a FontPopup sub class (as per Axel’s post) that populates the menu in its open event while invisible and then sets visible to true. I then created one menu in the IDE as a FontPopup menu and created a control set from this.

Then in the open event of the window I dynamically created new instances of the original popup menu and positioned them accordingly. They all appear correctly but the delay is even greater than manually adding each control to the IDE and populating in the window’s open event with addrows(fontarray) to each one. I’m beginning to think what I want to achieve is not possible.

[quote=237336:@Denise Adams]Ok, so here’s the results. I created a FontPopup sub class (as per Axel’s post) that populates the menu in its open event while invisible and then sets visible to true. I then created one menu in the IDE as a FontPopup menu and created a control set from this.

Then in the open event of the window I dynamically created new instances of the original popup menu and positioned them accordingly. They all appear correctly but the delay is even greater than manually adding each control to the IDE and populating in the window’s open event with addrows(fontarray) to each one. I’m beginning to think what I want to achieve is not possible.[/quote]

The reason why your page takes time to display is because you do all the dynamic creation in Open. If you create the popupmenus in a timer after the page has displayed, you won’t have the issue of waiting for the page to appear.

That said, you may want to ask yourself if having several popup FontMenus on the same page is a valid design.

Maybe what you really need is to refactor your user interface, maybe through selectors or radio buttons which select for which area a single font menu applies.

How many of these Font PopupMenus do you have?

In my timings it takes 0.0002 seconds to build the font name array and 0.01 seconds for the AddRows. If nothing else 100 menus would take about 1 second.

Michel: Yes, a timer or UI redesign may be the only way. I did think of using a single font menu and either radio buttons or another popup menu to select the “area/category” etc but it just means more user-interaction (clicks for the user to make) to make their selections.

Will: I have 9 menus with 339 fonts listed in each one. It takes 1.8 seconds for the window to appear with populated menus and 1.1 seconds without populating them.

I had this same problem. It had nothing to do with adding the rows, but just walking through the font data from the system. I built my cache of the fonts when the application opens and nobody notices an extra 2 seconds at that point. Then all the font popups appeared almost instantaneously. I like the idea of the shared data in a popup subclass, but that will still not load it until the first popup tries to load. You need a preload method that will create that at app open.

[quote=237348:@Denise Adams]Michel: Yes, a timer or UI redesign may be the only way. I did think of using a single font menu and either radio buttons or another popup menu to select the “area/category” etc but it just means more user-interaction (clicks for the user to make) to make their selections.

Will: I have 9 menus with 339 fonts listed in each one. It takes 1.8 seconds for the window to appear with populated menus and 1.1 seconds without populating them.[/quote]

It is doubtful that a user will immediately jump on the popupmenus when the window display. Just position them in the IDE, no need to place them dynamically. So they will be visible right away and the window will not be delayed by too many things in Open.

A single timer dragged over the window will provide very conveniently a delayed Action event to load all the popupmenus after the window has displayed (20-100 ms is probably just fine). Then even if it takes a full second to load all of your menus, it will not be visible to the user.

There is even no need to initiate the timer, as it will fire automatically upon load.

James: I do already load and sort the fonts into a global array on app open so it is the menu population that is the problem in my case.

Michel: Thanks for the advice.

Here’s a thought, you could set each popup menu to only 1 item, then in the font menu subclass you create a menuitem with the fontmenu item.

Dim base as new menuitem Dim n,l as integer n = fontCount for l=0 to n base.append new menuitem( font( 0 ) ) next

In the mousedown event of the popup menu, you then display that menu (menuitem.popup), you can use the X, Y ato get the offset within the control and re-position the menu so it looks like a popup menu’s menu.

Dim m as menuitem = fontmenu.popup( system.mousex-x, system.mousey-y) if m <> nil then // --- Update lablel // --- Fire changed event. end if

When the menuitem is selected, you update the text on the popup menu and fire a changed event.

The above code is for illustrative purposes only, do not attempt to use while operating heavy machinery.

Hey Sam that’s a good idea but you can do it within the PopupMenu itself. That is, put just the initial selection in the PopupMenu (like you said) but on the first MouseDown delete that initial item, add all the real rows, set the ListIndex and finally return false which allows the click to have default behavior and show the menu. The benefit of this as that the menu will pop up in the middle, around your selection.

That’s a great idea Sam/Will!

Sorry about misunderstanding, I somehow missed that you were using these in so many multiple places and just adding a thousand or more items to them all was what was causing the issue.

I like the idea of adding just the one item and then doing the rest of the work on the first click.

I might also experiment with creating only one invisible popup menu with all the fonts and a dummy one with no items other than the initial selection in all the places in the interface where you need one. Then in the mouse over event of the dummy one move the full one into the same position as the dummy one and set it’s list index and make it visible. Then when they click they get a real popup. You’ll have to keep track of which setting is live at any moment so that you know where to put the selection and then conform the dummy behind it again when they move to another selection.