ComboBoxes: the easy way to add, delete, rename items


#1

Hi, I feel a little bit bad for asking so many questions… But believe me, I always do a search in the previous posts. Once again I didn’t find anything. So here it is…

I have a ComboBox with a set of Items. I want to be able to add, delete and rename items. In order to do that, I set the ComboBox editable and display three buttons next to it: add,delete,rename.

Here’s my current solution with its weird things… I wonder if it can be done in an easier way. I don’t understand why JUCE doesn’t make it easy (it always does it, right? :). I guess I didn’t find again the proper way to do it.

ADD:
addItem(value,id) does the job.
However the selected id of the combobox is set to 0 so I have to write
an additional setSelectedId(numberOfItems). For me it would make sense that the selected id is kept constant or that it is set automatically to the id of the added item. What do you think?

DELETE:
I didn’t find any method to delete an item. So I basically used clear() and
added all the resulting items (stored elsewhere), again using the previous procedure. Did I miss the right method to do it?

RENAME:
changeItemText(id,value) does the job.
This method turns the selected id into 0 if the item changed was the one it was displayed. So I have to write an additional setSelectedId(numberOfItems) too, however here I have to add a condition: only if the item displayed is the one we are renaming. I’d rather expect the selected id to keep constant in all cases and refresh automatically the name of the combobox (now I have to do it)…

Let me know… Once again, thanks for reading…


#2

Hmm - I’ve never needed to change or remove any items from a combobox.

A UI component is not a place for storing and manipulating lists of data. In a decent model/view design, then the combo box is just a view for your list of items. When your list changes, you should clear and regenerate the combobox’s contents to reflect the new list.


#4

I see - so when you delete something from the list, you’d remove it from both the box and your proper list? That’s a pretty reasonable design. If I get a moment I’ll see if it’s hard to add those methods, though I wouldn’t have thought that regenerating the list would be a problem in terms of speed, unless you’ve got many thousands of items.


#6

Fair enough, but I’d never do it that way myself. For me, the small expense of rebuilding the list is preferable because you only have to write one small, simple bit of code to build the list. That means less time coding, less errors, smaller exe size, and less chance of the two things getting out of sync.

Basically, I think it’s best to write the simplest code that does the job, and only worry about optimising it later, if it’s actually a problem.


#8

Nah… just do

int oldId = getSelectedId();
regenerate
setSelectedId (oldId)


#9

(that’s assuming all your items have unique ids, which they probably should)


#11

[quote=“MarC”][quote=“jules”]Nah… just do

int oldId = getSelectedId();
regenerate
setSelectedId (oldId)[/quote]

OK. I think I got you. My Id is exactly the index of the item in the externally stored vector of items. I think you’re saying I should store/generate their id apart too, so that when I regenerate the combo, the id’s of the elements after the deleted one don’t change.
This means that if a new id is created each time an item is add, the user won’t be able to delete/add about 32000 times the attributes in one session (hehe) or that I’ll have to set up a hash function of the item to generate the id (I won’t).[/quote]

Typically though, if your combo box needs to persist selection state between list rebuilds, it’s because your application as a whole understands that persistent state.

In other words, in the case of a selected patch in a VST plug for example, you’ll have some state variable somewhere, either as part of the program list, or as part of a helper structure, that knows the currently selected program number.

By extension therefore, all program add/delete/insert operations will be natively shifting the main selection index.

In this case, when it comes to updating your list, you’d just refill the list, then use the selection index to update setSelectedId(). You really shouldn’t need any kind of fancy look-up table.


#13

[quote]* (wish list > jules) this implementation would be much better if some changes were done in JUCE (hopefull shallow things…)
(now there are patches to overcome them, but some of them are nasty and not fully working aestetically)

  1. avoid these functions I had to reimplement: drawComboBox and getComboBoxFont, make them more general and avoid using explicitly the ComboBox object
  2. add to PopMenu class a function that returns the string corresponding to an index. It’s simple and will make
    ComboBoxOnline::showPopup() simpler (avoid the use of StringArray values).
  3. is it easy to introduce new class such as this one in the JUCER? my project is getting JUCE not compatible…
  • potential bugs that I found on my way: I detected smth that looks as an error to me in juce_ComboBox.cpp:

Code:
const String ComboBox::getItemText (const int index) const
{
ItemInfo* const item = getItemForIndex (index);

if (item != 0)
    return item->name;

return String::empty; // > TextWhenNothingSelected

}
[/quote]

Well… if you’re calling drawComboBox or getComboBoxFont, you’ve clearly got a combobox that you’re interested in, so what’s wrong with passing it as a parameter?

There’s already a popup menu iterator to get the items. An index->string mapping would be pretty meaningless because of things like separators and subheadings. That’s why I wrote the iterator.

And that’s not a bug - the text when nothing is selected is for display only, it’s never returned.


#16

But in future I might want to write a look and feel that needs to know some other aspect of the combobox. That’s why it passes a pointer, and not just a bunch of settings.


#18