I want to be able to create a combo box in QT using C++ that works on a model (QAbstractItemModel or QAbstractListModel - in this case the latter) but which works with actual objects not just QString as is the default. Here is the model I have:
// H file
#pragma once
#include <QAbstractListModel>
#include <QList>
#include "Test.h"
using net::draconia::test::model::Test;
namespace net
{
namespace draconia
{
namespace test
{
namespace ui
{
namespace model
{
class TestModel : public QAbstractListModel
{
QList<Test> mLstModel;
public:
TestModel();
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QList<Test> &getModel();
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
};
}
}
}
}
}
// cpp
#include <QtDebug>
#include "TestModel.h"
using namespace net::draconia::test::ui::model;
TestModel::TestModel()
: QAbstractListModel()
{
mLstModel.append(Test("English", "EN"));
mLstModel.append(Test("French", "FR"));
}
QVariant TestModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(role);
qDebug() << index;
if(index.isValid())
{
QVariant retVal;
retVal.setValue(const_cast<TestModel &>(*this).getModel()[index.row()]);
return(retVal);
}
else
return(QVariant());
}
QList<Test> &TestModel::getModel()
{
return(mLstModel);
}
int TestModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
qDebug() << "There are " << const_cast<TestModel &>(*this).getModel().count() << " rows";
return(const_cast<TestModel &>(*this).getModel().count());
}
I don't know if the problem is there - Here's the code for the Test class upon which this combo box is based. As you'll see it is declared as a metatype:
// H file
#pragma once
#include <QString>
#include <QVariant>
namespace net
{
namespace draconia
{
namespace test
{
namespace model
{
class Test
{
QString msLanguage, msRegion;
public:
Test();
Test(const QString &sLanguage, const QString &sRegion);
Test(const Test &refCopy);
~Test();
QString &getLanguage() const;
QString &getRegion() const;
void setLanguage(const QString &sLanguage);
void setRegion(const QString &sRegion);
Test &operator=(const Test &refCopy);
bool operator==(const Test &refOther) const;
bool operator!=(const Test &refOther) const;
operator QString() const;
QString toString() const;
};
}
}
}
}
Q_DECLARE_METATYPE(net::draconia::test::model::Test);
// CPP file
#include "Test.h"
using namespace net::draconia::test::model;
Test::Test()
{ }
Test::Test(const QString &sLanguage, const QString &sRegion)
: msLanguage(sLanguage)
, msRegion(sRegion)
{ }
Test::Test(const Test &refCopy)
: Test(refCopy.getLanguage(), refCopy.getRegion())
{ }
Test::~Test()
{ }
QString &Test::getLanguage() const
{
return(const_cast<Test &>(*this).msLanguage);
}
QString &Test::getRegion() const
{
return(const_cast<Test &>(*this).msRegion);
}
void Test::setLanguage(const QString &sLanguage)
{
msLanguage = sLanguage;
}
void Test::setRegion(const QString &sRegion)
{
msRegion = sRegion;
}
Test &Test::operator=(const Test &refCopy)
{
setLanguage(refCopy.getLanguage());
setRegion(refCopy.getRegion());
return(*this);
}
bool Test::operator==(const Test &refOther) const
{
return ( (getLanguage() == refOther.getLanguage())
&& (getRegion() == refOther.getRegion()));
}
bool Test::operator!=(const Test &refOther) const
{
return(!operator==(refOther));
}
Test::operator QString() const
{
return(toString());
}
QString Test::toString() const
{
return(getLanguage() + "(" + getRegion() + ")");
}
From what I can see in the debug statements, it is entering rowCount and telling me there are 2 rows and it is entering the data method twice to print the rows but there's nothing being printed. Here's the code for the simple window (I do NOT use QML at all - never have nor ever will - I think it's lazy!):
// H file
#pragma once
#include <QComboBox>
#include <QMainWindow>
namespace net
{
namespace draconia
{
namespace test
{
namespace ui
{
class TestMainWindow : public QMainWindow
{
Q_OBJECT
QComboBox *mCboTest;
protected:
QComboBox *getTestComboBox();
void initControls();
void initWindow();
public:
TestMainWindow(QWidget *parent);
~TestMainWindow();
};
}
}
}
}
// CPP file
#include <QHBoxLayout>
#include "TestMainWindow.h"
#include "TestModel.h"
using namespace net::draconia::test::ui;
using net::draconia::test::ui::model::TestModel;
QComboBox *TestMainWindow::getTestComboBox()
{
if(mCboTest == nullptr)
{
mCboTest = new QComboBox(this);
mCboTest->setModel(new TestModel());
}
return(mCboTest);
}
void TestMainWindow::initControls()
{
QLayout *layout = new QHBoxLayout(this);
layout->addWidget(getTestComboBox());
setLayout(layout);
}
void TestMainWindow::initWindow()
{
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
initControls();
}
TestMainWindow::TestMainWindow(QWidget *parent)
: QMainWindow(parent)
, mCboTest(nullptr)
{
initWindow();
}
TestMainWindow::~TestMainWindow()
{ }
If I must I will include the code to the Application class and my main.cpp file but those are the important ones - The rest are boilerplate code. If you question the namespace - I always include namespaces - it keeps code from infesting the global namespace even in examples.
What am I omitting out of my code for the combo box items to be displayed? I copied much of the code from a larger project which is where my problem really is experienced but it happens here too luckily so I can showcase it. In the larger project, I have observer classes that retrieve the selected object from the combo box and use them 'as' the object class themselves. I got this from Java Swing which combo box model items will automatically be called the ToString() for every item to print - Here it doesn't seem so. I thought maybe it would try to cast to QString but it's not even doing that. I'm stumped.