Radio buttons in menus

18 views
Skip to first unread message

Eric Sokolowsky

unread,
Apr 15, 2024, 2:29:53 PMApr 15
to fltkg...@googlegroups.com
I'm trying to figure out how to set one specific radio button in a section of my menu.

I am dynamically generating the menu entries in question, by using the menu bar's "insert" method. The menu entries are displayed correctly.

I see the "setonly" method in the Fl_Menu_ class, but it takes a Fl_Menu_Item* as a parameter, and the only methods that return a menu item all return "const Fl_Menu_Item*" pointers. How am I supposed to find the right pointer without casting away the const, which, I assume, is there for a good reason?

Eric

Matthias Melcher

unread,
Apr 15, 2024, 3:38:10 PMApr 15
to fltk.general
Using arrays for menu trees is one of those old relics from original FLTK. We have been trying to make it bearable by adding some convenience methods. 

So when you declare a menu array, it is located in read-only memory and therefor `const`. Once you link it to a widget derived form `Fl_Menu_` and use `add()`, Fl_Menu_ will clone the original menu into red-write memory and values within the menu are no longer `const`, so you can safely cast away const. Note however that adding more menu items  may cause Fl_Menu_ to reallocate the menu array and create a new clone, making previously found pointers invalid.

Fl_Menu_::add() returns the index of the newly added menu item. So `int ix = myMenuBar->add("Edit"); Fl_Menu_Item *mi = myMenuBar->menu()+ix;` will return a pointer to the menu item that you just added. 

There are other functions to find the index of a menu item: Fl_Menu_::find_index() , or find the menu item itself: Fl_Menu::find_item(), find_item_with_argument(), find_item_with_userdata(). Yes, it can be cumbersome, and yes, actively changing the menu array may cause relocation of the array. FLTK 1.5 will add menus that use the same parent/child API that FLTK windows and widget use.

I like to use a trick to avoid re-allocating menu item arrays: I reserve an array large enough to hold everything I may ever add, but I keep the spare items invisible using the `FL_MENU_INVISIBLE` flag (or call hide() on the menu item).

Hope this helps a little.

Eric Sokolowsky

unread,
Apr 16, 2024, 9:05:22 AMApr 16
to fltkg...@googlegroups.com
Thank you. The main issue I encountered is that all of the methods I found, such as find_index() or find_item() also return a const pointer, so I have to cast away the const regardless of how I access the menu item. Even the menu() method returns a const pointer.

Eric

--
You received this message because you are subscribed to the Google Groups "fltk.general" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/5a40c19a-f538-4cbe-bea1-80911ca63d33n%40googlegroups.com.

Matthias Melcher

unread,
Apr 16, 2024, 10:29:31 AMApr 16
to fltk.general
Yes, this is a side effect of offering the shortcut to use a statically allocated Menu Item array. You can safely cast away the `const` once you know that your menu array was copied. To be absolutely sure, instead of Fl_Menu_::menu(myMenu) you can call Fl_Menu_::copy(myMenu), and you are guaranteed that the menu array is no longer const.

If you want to avoid the const cast in your application, you can derive your own class and write a method:

Fl_Menu_Item *MyMenuBar::non_const_menu() { 
  if (alloc==0) copy(menu(), NULL); 
  return const_cast<Fl_Menu_Item*>(menu());
}

Historically, the F and L in FLTK were absolute priority. By referencing a const array of menu items, there was no need to copy labels or allocate memory, making the library extremely fast and light. This is the same reason why Fl_Wdget::label() does not duplicate the text, but instead just references it (vs. copy_label()). We are keeping these interfaces alive for back compatibility, and I sometimes surprise myself by compiling apps that I wrote 20 years ago, and they compile with minor changes.

Greg Ercolano

unread,
Apr 16, 2024, 11:05:31 AMApr 16
to fltkg...@googlegroups.com

On 4/15/24 12:38, 'Matthias Melcher' via fltk.general wrote:

I like to use a trick to avoid re-allocating menu item arrays:

    Huh, I never worried about re-allocating menu item arrays..
    do you avoid it because it's slow, or is the idea to allow pointers to not change?

    When I build menus I always use add() to construct menus dynamically,
    as often I need to change the menus, such as in my app's main menubar:

      File -> Recent -> <dynamic list of recently edited files>

    Even for menus that I originally design not to change, I figure inevitably
    I'll need to add a feature that does involve dynamic changes, so better
    to always design for dynamic than to have to retrofit later.

    So I always use find_item() to access menu pointers to avoid problems
    with old pointers going stale; that seems to be less brittle.

    If there's any overhead for using find_item(), I've never found it
    to be a problem, even on slow machines with "large" menus.
   

.. I reserve an array large enough to hold everything I may ever add, but I keep the spare items invisible using the `FL_MENU_INVISIBLE` flag (or call hide() on the menu item).

    I always worry about trying to predict array sizes always bites me
    in the ass later, so I always try to do everything dynamically with
    add() and find_item().

Albrecht Schlosser

unread,
Apr 16, 2024, 11:18:12 AMApr 16
to fltkg...@googlegroups.com
[about having to "cast away" const:]


On 4/16/24 16:29 'Matthias Melcher' via fltk.general wrote:
Yes, this is a side effect of offering the shortcut to use a statically allocated Menu Item array. You can safely cast away the `const` once you know that your menu array was copied. To be absolutely sure, instead of Fl_Menu_::menu(myMenu) you can call Fl_Menu_::copy(myMenu), and you are guaranteed that the menu array is no longer const.

To add to this statement: as soon as you add at least one menu entry dynamically (or if you build the menu dynamically from the beginning) the menu is always allocated in writable memory.

It is recommended to call menu_end() after all menu modifications are done, which copies the menu from some random internal storage to its final place [1]. After that it is safe to get and store pointers to menu items ... until the menu is modified again.

[1] otherwise the menu will be copied later at an unpredictable time (e.g. when other menus are changed) but always before it is shown by popup() etc.

Matthias Melcher

unread,
Apr 16, 2024, 12:12:57 PMApr 16
to fltk.general
er...@seriss.com schrieb am Dienstag, 16. April 2024 um 17:05:31 UTC+2:

On 4/15/24 12:38, 'Matthias Melcher' via fltk.general wrote:

I like to use a trick to avoid re-allocating menu item arrays:

    Huh, I never worried about re-allocating menu item arrays..
    do you avoid it because it's slow, or is the idea to allow pointers to not change?

Reallocating unnecessarily fragments memory. find_item() walks the menu array every time. It's all absolutely irrelevant on a modern PC. I like that menus are not reallocated and my pointers stay valid. Especially under FLUID, which calculates widget addresses during initialization, this would be a concern. It does not really matter.

So, yes,  find_item() every time is just as fine.
Reply all
Reply to author
Forward
0 new messages