If I have an overridden QAbstractTableModel
that supplies a non-qt type, it's my understanding that supplying overloads for the <<
and >>
operators will allow Qt to natively represent those types.
I have prepared an example with std::u16string
in an attempt to create the most minimal test case, but can't seem to render anything.
Here's how I register the type with Qt:
#include <QtCore>
Q_DECLARE_METATYPE(std::u16string);
QDataStream& operator<<(QDataStream& out, const std::u16string& myObj)
{
return out << QString::fromStdU16String(myObj);
}
QDataStream& operator>>(QDataStream& in, std::u16string& myObj)
{
QString tmp;
in >> tmp;
myObj = tmp.toStdU16String();
return in;
}
My trivial main.cpp which connects the type to the appropriate widget:
#include <QItemEditorFactory>
#include <QLineEdit>
int main()
{
// not sure if this is required.
// this blogpost (https://www.qt.io/blog/whats-new-in-qmetatype-qvariant) suggests it's
// needed for name-to-type conversions, but no idea if that is still needed internally.
qRegisterMetaType<std::u16string>();
// tell qt that we would like to visualise std::u16string with the default text editor.
QItemEditorFactory* factory = new QItemEditorFactory;
factory->registerEditor(QMetaType::fromType<std::u16string>().id(), new QStandardItemEditorCreator<QLineEdit>());
QItemEditorFactory::setDefaultFactory(factory);
// kick off ui, etc
return doApp();
}
And my trivial model, which supplies the external type via a variant:
#include <QAbstractTableModel>
class simple_model : public QAbstractTableModel
{
public:
explicit simple_model(QObject* parent = nullptr) : QAbstractTableModel(parent) {}
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
{
return QVariant::fromValue<std::u16string>(u"Hello, World!");
}
};
Now, when I create QTableView like so:
QTableView* tableView = new QTableView;
tableView->setModel(new simple_model);
I would expect every column and row to print "Hello, World!". However, I just get a blank text box instead. Attaching my debugger to my overloaded <<
and >>
operators shows they don't get run at all.
I feel like I'm missing a link here, but I'm not quite sure what. Some ideas about what could possibly be wrong:
QLineEdit
not actually invoke any data conversions to display custom data? Perhaps there's a more appropriate text editor I should be using? I was hoping that QLineEdit
would automatically convert them because it's the default QString
editor; would be nice to have the exact same behaviour.In my case, it turns out that the <<
and >>
operators weren't needed at all. Instead, providing an appropriate meta type converter allowed for what I wanted.
Sample code for converter:
struct string_converter
{
static QString toQString(const std::u16string& value)
{
return QString::fromStdU16String(value);
}
static std::u16string tou16String(const QString& value)
{
return value.toStdU16String();
}
};
and to register these converters:
QMetaType::registerConverter<std::u16string, QString>(&string_converter::toQString);
QMetaType::registerConverter<QString, std::u16string>(&string_converter::tou16String);
Once these are provided, no other registration code appears to be needed. The simple_model
seems to be able to construct a QVariant
from the std::u16string
and represent it with a QLineEdit
without any extra boilerplate code.
However, we'll need to explicitly convert the modified data back to std::u16string
in simple_model
, because they get tweaked and returned as a QString
from QLineEdit
. Eg:
QVariant simple_model::setData(const QModelIndex& index, const QVariant& value, int role) override
{
std::u16string newData = value.value<std::u16string>();
// do something with newData
}
While this has unblocked me, I'm not sure this is preferred Qt approach as it seems to be quite different to what the documentation says (as I cited originally in the question). Any extra feedback or tips would be appreciated.