3

I'd like to be able to access the values in my QComboBox without having to loop over the contents using itemText.

for( auto i = 0u; i < myQComboBox->count(); i++ )
{
    result[i] = myQComboBox->itemText( i );
}

Is there a way that I can get to QComboBox's underlying QList so I can just use the operator[] or even better, iterators and range based loops?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288

2 Answers2

4

It appears that you're hung on the syntax: you want to replace myQComboBox->itemText(i) with myQComboBox[i]. That can be rather easily done:

// implementation
class ModelAdapter {
  QPointer<QAbstractItemModel> m_model;
public:
  explicit ModelAdapter(QComboBox & box) : m_model(box.model()) {}
  explicit ModelAdapter(QAbstractItemModel * model) : m_model(model) {}
  QVariant operator[](int i) { return m_model->index(i, 0); }
};

// point of use
ModelAdapter model(myQComboBox);
for( auto i = 0; i < myQComboBox->count(); i++ )
{
    result[i] = model[i];
}

With a good compiler, you can do the below and have it produce the same code as if you used combobox.model->index(i, 0) directly. I don't see the point of it, but hey, it's possible :)

// implementation
class Adapter {
  QAbstractItemModel* m_model;
public:
  explicit Adapter(QComboBox & box) : m_model(box.model()) {}
  explicit Adapter(QAbstractItemModel * model) : m_model(model) {}
  QVariant operator[](int i) { return m_model->index(i, 0); }
};

// point of use
for( auto i = 0; i < myQComboBox->count(); i++ )
{
    result[i] = Adapter(myQComboBox)[i];
}

A similar adapter could provide you with iterators.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • This idea seems a bit more involved than the solution I was hoping for. But if I could get iterators going I could use `std::algorithm` for transferring data in and out of the `QComboBox` however, I seem to be implementing iterators in my iterator version of the `ModelAdapter` class, and that's going to take a while to get right. Am I over complicating the implementation? Is there a simple way to accomplish this? – Jonathan Mee Jun 04 '14 at 18:17
  • @JonathanMee Wait, a 7 line solution is too involved? This class is tucked away in a header somewhere. The only "involvement" is a single line in the block where you wish to use your model. I see often see one count the size of the implementation instead of the size of the code needed to use it, and it befuddles me to no end. You are not going any smaller than a single statement in cases where you need a statement, so this is, in fact, as small as you can possibly go. I've shown an alternate variant of it. I'll add iterators later. – Kuba hasn't forgotten Monica Jun 06 '14 at 12:25
  • So I've decided to use an `int` to hold position and use that for an iterator. I'm inheriting from `std::random_access_iterator_tag` and implementing its [operations](http://www.cplusplus.com/reference/iterator/RandomAccessIterator/). I'm saying that that is time consuming. If there is a better way I'd love to hear it. – Jonathan Mee Jun 12 '14 at 11:08
  • @JonathanMee Again, the *implementation* is done *once*. What matters is how easy it is to use it - after all, if you really need it, you expect to use it very, very often. If you will only use it a dozen times or less, you're probably wasting your time even worrying about it. – Kuba hasn't forgotten Monica Jun 12 '14 at 11:53
3

You can retrieve items data using the combo box's model. Here is an example, how I would do that:

QComboBox combo;
combo.addItem("Item 1");

QAbstractItemModel *model = combo.model();
QModelIndex idx = model->index(0, 0); // Refers to the first item
QString item = model->data(idx).toString(); // Returns 'Item 1'

To access the second and further items of the combo box, just change the row number in index() function call:

QModelIndex idx = model->index(0, 0);
                the row number ^

I am not aware of any iterators based API for combo boxes so far, but you can use all the strength of QAbstractItemModel.

vahancho
  • 20,808
  • 3
  • 47
  • 55
  • I'll admit I have limited experience with `QAbstractModel`, but it doesn't seem like that's getting me anything, instead of calling `myComboBox->itemText( i )` now I'm calling `model->index( i, 0 )`. Is there a way that I'm missing that `QAbstractItemModel` gets me closer to using range based loops? – Jonathan Mee Jun 04 '14 at 12:51
  • @JonathanMee, both approaches are equivalent, but what is wrong in using a simple `for` loop? Otherwise I am not aware of an API you need. – vahancho Jun 04 '14 at 13:02
  • I have a UI facing method that takes in a `std::vector` which populates a `QComboBox`, deals with user input, then populates a `std::vector` from the `QComboBox` and returns it. The loops work fine but I do this in a bunch of spots in my code and being able to use iterators would let me directly return the `std::vector` everywhere rather than temporarily create it. – Jonathan Mee Jun 06 '14 at 15:12