Loading and saving a class using qsettings - c++

I have an ini file as shown
[Profiles]
hh\Ta=20
hh\Te=48
hh\Texp=38
hh\lim1=0
hh\lim2=0
hh\offset=0
hh\profilename=hh
tt\Ta=20
tt\Te=48
tt\Texp=38
tt\lim1=0
tt\lim2=0
tt\offset=0
tt\profilename=hh
I'm trying to load it, but I get all the data as zeros, like Ta Te Texp,..etc
The file is saved correctly but loading the values back is not working.
Is it a problem with setting the group,..etc ?
here is my load and save mechanism
void Method::loadFrom(Settings &set, bool ownGroup)
{
set.beginGroup("Profiles");
foreach (const QString &group, set.childGroups()) {
set.beginGroup(group);
Profile *profile = new Profile();
profile->setObjectName(group);
profile->loadFrom(set);
set.endGroup();
m_currentProfile->m_Profiles << profile;
}
set.endGroup();
EraObject::staticLoadFrom(set, this, ownGroup);
}
void Method::saveTo(Settings &set, bool ownGroup, bool force)
{
set.beginGroup("Profiles");
foreach(Profile * profile, m_currentProfile->m_Profiles) {
profile->saveTo(set);
set.endGroup();
}
set.sync();
EraObject::staticSaveTo(set, this, ownGroup, force);
}
class Settings : public QSettings
{
Q_OBJECT
public:
explicit Settings(QString fileName);
~Settings();
private:
Q_DISABLE_COPY(Settings)
};
void EraObject::staticLoadFrom(Settings &set, QObject *object, const bool &ownGroup)
{
Q_ASSERT(object);
bool modified;
const QMetaObject *superMeta = object->metaObject()->superClass();
const QMetaObject *meta = object->metaObject();
const QString &group = object->objectName().isEmpty() ? meta->className() : object->objectName();
if (ownGroup)
set.beginGroup(group);
qCDebug(loadLog) << group;
for (int i = superMeta->propertyOffset(); i < meta->propertyCount(); i++) {
modified = false;
const QMetaProperty &prop = meta->property(i);
QMetaType::Type type = (QMetaType::Type)prop.type();
if (prop.isUser()) {
switch (type) {
case QMetaType::QDateTime:
modified = setOrReset(set, object, prop, QDateTime::fromString(set.value(prop.name(), "").toString(), "yyyyMMddhhmmsszzz"));
break;
case QMetaType::QString: { //check if there is an localized string first (eg.: name#de=test)
const QVariant value = set.value(QString("%1#%2").arg(prop.name()).arg(QLocale::system().bcp47Name()),
set.value(prop.name(), ""));
modified = setOrReset(set, object, prop, value);
break;
}
case QVariant::UserType: {
QObject *obj = prop.read(object).value<QObject *>();
Q_ASSERT_X(obj, "staticLoadFrom", "Custom class NOT known to QMetaType, register it with qmlRegisterType()!");
bool check = QMetaObject::invokeMethod(obj,
"loadFrom",
Qt::DirectConnection,
Q_ARG(Settings &, set)); //we invoke cause it can be just QObject(e.g. QAbstractItemModel)
Q_ASSERT_X(check, "staticLoadFrom", "Could not invoke. Be sure you subclassed EraObject or defined method!: " + obj->objectName().toLatin1());
break;
}
default:
modified = setOrReset(set, object, prop, set.value(prop.name(), ""));
}
qCDebug(loadLog) << "modified:" << modified << "Property:" << prop.name();
}
}
if (ownGroup)
set.endGroup();
object->setProperty("dirty", NotDirty);
}
void EraObject::staticSaveTo(Settings &set, QObject *object, const bool &ownGroup, const bool &force)
{
Q_ASSERT(object);
if (force || object->property("dirty").toInt() == RamDirty) {
const QMetaObject *superMeta = object->metaObject()->superClass();
const QMetaObject *meta = object->metaObject();
const QString &group = object->objectName().isEmpty() ? meta->className() : object->objectName();
if (ownGroup)
set.beginGroup(group);
qCDebug(saveLog) << group;
for (int i = superMeta->propertyOffset(); i < meta->propertyCount(); i++) {
const QMetaProperty &prop = meta->property(i);
if (prop.isUser()) {
QMetaType::Type type = (QMetaType::Type)prop.type();
switch (type) {
case QMetaType::QDateTime:
set.setValue(prop.name(), prop.read(object).toDateTime().toString("yyyyMMddhhmmsszzz"));
break;
case QMetaType::Float:
case QMetaType::Double:
set.setValue(prop.name(), QString::number(prop.read(object).toDouble(), 'g', MAX_SAVED_DECIMALS));
break;
case QMetaType::User: {
QObject *obj = prop.read(object).value<QObject *>();
Q_ASSERT_X(obj, "staticLoadFrom", "Custom class NOT known to QMetaType, register it with qmlRegisterType()!");
bool check = QMetaObject::invokeMethod(obj,
"saveTo",
Qt::DirectConnection,
Q_ARG(Settings &, set),
Q_ARG(bool, true),
Q_ARG(bool, force));
Q_ASSERT_X(check, "saveTo", "Could not invoke. Be sure you subclassed EraObject or defined method!: " + obj->objectName().toLatin1());
break;
}
default:
if (!prop.isConstant())
set.setValue(prop.name(), prop.read(object));
}
}
}
if (ownGroup)
set.endGroup();
object->setProperty("dirty", NotDirty);
set.sync();
}
}

Related

What to use instead of QStringList?

I'm new to Qt, so I'm not sure what to use.
I thought I would have a QStringList to give to my QStringListModel and display it in a ListView.
Now, however, I need to divide QStringList in the values of 2 types. So, I need to have string + some typeId, not just one string, but QStringList is for one-dimensional list only.
Anyone could give an advice on what is the best way to try to implement this?
The solution is to use QAbstractListModel subclass as a Qt Quick model. An example of base class for a models (I use it for convenience):
// abstractobjectlistmodel.h
#pragma once
#include <QtCore>
struct AbstractObjectListModel
: public QAbstractListModel
{
explicit AbstractObjectListModel(QObject * const parent = Q_NULLPTR)
: QAbstractListModel{parent}
{ ; }
int rowCount(QModelIndex const & parent = {}) const Q_DECL_OVERRIDE Q_DECL_FINAL
{
Q_UNUSED(parent);
return items.count();
}
QVariant data(QModelIndex const & index, const int role = Qt::DisplayRole) const Q_DECL_OVERRIDE Q_DECL_FINAL
{
if (!index.isValid()) {
return {};
}
switch (role) {
case Qt::UserRole : {
return QVariant::fromValue(items[index.row()].data());
}
default : {
return {};
}
}
}
QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE Q_DECL_FINAL
{
auto roleNames = QAbstractListModel::roleNames();
roleNames.insert(Qt::UserRole, "modelData");
return roleNames;
}
Q_INVOKABLE
virtual
QObject * get(int row) const
{
if (row < 0) {
return {};
}
if (row >= rowCount()) {
return {};
}
return items[row];
}
void remove(int row, int count = 1)
{
Q_ASSERT(count > 0);
Q_ASSERT(row >= 0);
Q_ASSERT(row + count <= rowCount());
beginRemoveRows({}, row, row + count - 1);
while (0 < count) {
items.takeAt(row)->deleteLater();
--count;
}
endRemoveRows();
}
void clear()
{
if (!items.isEmpty()) {
remove(0, rowCount());
}
}
protected :
~AbstractObjectListModel() Q_DECL_OVERRIDE Q_DECL_EQ_DEFAULT; // derived classes should not meant to be manipulated polymorphically
QList< QPointer< QObject > > items;
void insert(int row, QObject * const item)
{
item->setParent(this);
beginInsertRows({}, row, row);
items.insert(row, item);
endInsertRows();
}
void append(QObject * const item)
{
insert(rowCount(), item);
}
};
But one need to override get to access items' Q_PROPERTY properties (in addition to dynamic ones):
// type of element
class Project
: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name MEMBER name NOTIFY nameChanged)
Q_PROPERTY(QString path MEMBER path NOTIFY pathChanged)
public :
Project(QString name, QString path,
QObject * const parent = Q_NULLPTR)
: QObject{parent}
, name{name}
, path{path}
{ ; }
Q_SIGNALS :
void nameChanged(QString name);
void pathChanged(QString path);
private :
QString name;
QString path;
};
// custom model
class ProjectsListModel
: public AbstractObjectListModel
{
Q_OBJECT
public :
explicit ProjectsListModel(QObject * const parent = Q_NULLPTR)
: AbstractObjectListModel{parent}
{ ; }
void appendProject(QString name, QString path)
{
AbstractObjectListModel::append(::new Project{name, path});
}
Q_INVOKABLE
Project *
get(int row) const Q_DECL_OVERRIDE
{
return qobject_cast< Project * >(AbstractObjectListModel::get(row));
}
};
Before use one need to register concrete model with qmlRegisterType< ProjectsListModel >();. Properties of Project class are avaliable in delegate and highlight by means of members of modelData.
Another example:
struct TimeZoneModel Q_DECL_FINAL
: public QAbstractListModel
{
Q_OBJECT
public :
explicit TimeZoneModel(QObject * const parent = Q_NULLPTR)
: QAbstractListModel{parent}
{ ; }
int rowCount(QModelIndex const & parent = {}) const Q_DECL_OVERRIDE
{
Q_UNUSED(parent);
return timeZoneIds.count();
}
QVariant data(QModelIndex const & index, const int role = Qt::DisplayRole) const Q_DECL_OVERRIDE
{
if (!index.isValid() || (role > Qt::UserRole + 4)) {
return {};
}
QTimeZone timeZone{timeZoneIds[index.row()]};
if (!timeZone.isValid()) {
return {};
}
return roleData(timeZone, role);
}
QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE
{
auto roleNames = QAbstractListModel::roleNames();
int i = Qt::UserRole;
for (const auto role : {"modelData", "id", "comment", "name", "country"}) {
roleNames.insert(i++, role);
}
return roleNames;
}
Q_INVOKABLE
QByteArray get(int row) const
{
if (row < 0) {
return {};
}
if (row >= rowCount()) {
return {};
}
return timeZoneIds[row];
}
private :
QVariant roleData(QTimeZone const & timeZone, int role = Qt::UserRole) const
{
switch (role) {
case Qt::UserRole : {
QVariantMap modelData;
const auto names = roleNames();
while (++role < Qt::UserRole + 5) {
modelData.insert(QString::fromUtf8(names[role]), roleData(timeZone, role));
}
return modelData;
}
case Qt::UserRole + 1: {
return QString::fromUtf8(timeZone.id());
}
case Qt::UserRole + 2 : {
return timeZone.comment();
}
case Qt::UserRole + 3 : {
return timeZone.displayName(QTimeZone::StandardTime);
}
case Qt::UserRole + 4 : {
return QLocale::countryToString(timeZone.country());
}
default : {
return {};
}
}
}
const QByteArrayList timeZoneIds = QTimeZone::availableTimeZoneIds();
};
In addition to access via modelData's fields (modelData.id, modelData.comment etc) all the symbols are accessible directly (i.e. id, comment etc) in delegate and highlight contexts of the ListView.
Model TimeZoneModel is const and can be injected into global scope directly without any performance drawbacks:
QQmlApplicationEngine engine;
TimeZoneModel timeZoneModel;
Q_SET_OBJECT_NAME(timeZoneModel);
qmlRegisterType< TimeZoneModel >();
const auto rootContext = engine.rootContext();
rootContext->setContextProperty(timeZoneModel.objectName(), &timeZoneModel);
If you need dictionary that contains QString and any other type I suggest you to use
QMap<QString, YourType> myMap;
Here you have some example of usage:
QMap<int, QString> myMap;
myMap.insert(1,"A");
myMap.insert(2,"B");
myMap[3] = "C";
foreach(int i, myMap.keys()) qDebug() << myMap[i];

QSortFilterProxyModel not showing 2nd column in QTreeView

I have inherited a class from QSortFilterProxyModel to support filtering of a hierarchical tree in my code.
I have added code below of what I have done. After filtering is done, data in the 2nd column is NOT shown...
I am not able to understand why is that...
Can anyone help me on that?
Also, when filtering is completed, the tree is collapsed... I want to call expandAll on the tree when the filtering is completed. Is there some signal emitted or some function called where I know that the filtering is done?
Class Declaration
class MySortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
MySortFilterProxyModel(QObject *parent = 0);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
bool ShowThis(const QModelIndex index) const;
private:
};
USAGE:
_proxyModel = new MySortFilterProxyModel(this);
_proxyModel->setFilterKeyColumn(-1);
_proxyModel->setSourceModel(_directiveTreeModel);
DEFINITION:
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return ShowThis(index);
}
bool MySortFilterProxyModel::ShowThis(const QModelIndex index) const
{
bool retVal = false;
//Gives you the info for number of childs with a parent
if ( sourceModel()->rowCount(index) > 0 )
{
for( int nChild = 0; nChild < sourceModel()->rowCount(index); nChild++)
{
QModelIndex childIndex = sourceModel()->index(nChild,0,index);
if ( ! childIndex.isValid() )
break;
retVal = ShowThis(childIndex);
if (retVal)
{
break;
}
}
}
else
{
QModelIndex useIndex0 = sourceModel()->index(index.row(), 0, index.parent());
QString name = sourceModel()->data(useIndex0, Qt::DisplayRole).toString();
QModelIndex useIndex1 = sourceModel()->index(index.row(), 1, index.parent());
QString value = sourceModel()->data(useIndex1, Qt::DisplayRole).toString();
std::cout << "name : " << name.toStdString() << ", value : " << value.toStdString() << "\n";// , filterRegExp : " << filterRegExp() << "\n";
if ( (name.contains(filterRegExp()) || value.contains(filterRegExp())) )
{
retVal = true;
}
else
retVal = false;
}`enter code here`
return retVal;
}
OUTPUT : (Data in the 2nd column is missing)
I figured out the issue...
I was using QStyledItemDelegate and I had derived a class from it and overridden the paint function.
In the pain function, I was referring to my original model .. But, in case of filtering, that model is NULL and I should have used the proxy model that I had created.

How do I know the values on Qt property browser changed?

I'm using a Qt property browser widget. I'm creating all the values of the property grid automatically using the moc but I didn't find how to make the values entered in the property grid be set automatically in my class instance? is there any sginal where I can know that?
I creating the property grid like this:
QWidget *w = new QWidget();
Foo *o = new Foo();
QtBoolPropertyManager *boolManager = new QtBoolPropertyManager(w);
QtIntPropertyManager *intManager = new QtIntPropertyManager(w);
QtStringPropertyManager *stringManager = new QtStringPropertyManager(w);
QtGroupPropertyManager *groupManager = new QtGroupPropertyManager(w);
const QMetaObject *meta = o->metaObject();
const QString className = meta->className();
QMap<QString, PropManager*> dic;
QtProperty *root = groupManager->addProperty(className);
for(int i = meta->propertyOffset(); i < meta->propertyCount(); ++i)
{
QMetaProperty metaProp = meta->property(i);
const QString name = metaProp.name();
QVariant value = metaProp.read(o);
QVariant::Type t = metaProp.type();
QtProperty *prop = NULL;
PropManager *propMan = NULL;
switch(t)
{
case QVariant::Int:
{
prop = intManager->addProperty(name);
root->addSubProperty(prop);
intManager->setValue(prop, value.toInt());
propMan = new PropManager(prop, intManager, t);
break;
}
case QVariant::String:
{
prop = stringManager->addProperty(name);
root->addSubProperty(prop);
stringManager->setValue(prop, value.toString());
propMan = new PropManager(prop, stringManager, t);
break;
}
default:
throw std::invalid_argument("unknow type");
}
if(prop != NULL)
dic.insert(name, propMan);
}
QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(w);
QtSpinBoxFactory *spinBoxFactory = new QtSpinBoxFactory(w);
QtLineEditFactory *lineEditFactory = new QtLineEditFactory(w);
QtAbstractPropertyBrowser *editor = new QtTreePropertyBrowser();
editor->setFactoryForManager(boolManager, checkBoxFactory);
editor->setFactoryForManager(intManager, spinBoxFactory);
editor->setFactoryForManager(stringManager, lineEditFactory);
editor->addProperty(root);
QGridLayout *layout = new QGridLayout(w);
layout->addWidget(editor, 1, 0);
w->show();
Foo.h is defined like this:
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo() { }
~Foo() { }
Q_PROPERTY(QString name READ getA WRITE setA)
Q_PROPERTY(int age READ getNum WRITE setNum)
QString name;
int age;
QString getA() const { return name; }
int getNum() const { return age; }
void setA(QString a) { this->name = a; }
void setNum(int n) { this->age = n; }
};
Partial solution:
I found propertyChanged() from QtAbstractPropertyManager but this does raise every time a single character is edited. I'd like to have an slot where this is fired when the user is done with the editing.

segfault accessing qlist element through an iterator

I get a segfault while iterating over a QList. I don't understand what I am doing wrong.
I have a QList of Conversation. Inside a Conversation I have a QList of Msg. Below are the class description :
Msg class :
class Msg {
public:
Msg();
Msg(const Msg& other);
Msg& operator=(const Msg& other);
virtual ~Msg();
bool operator==(const Msg& other);
QString id() const { return _id; }
MsgContact author() const { return _author; }
MsgContact dest() const { return _dest; }
QDateTime date() const { return _receivedDate; }
MsgDirection direction() const { return _direction; }
QString text() const { return _text; }
bool transmitted() const { return _transmitted; }
void setId(const QString& id) { _id = id; }
void setAuthor(const MsgContact& author) { _author = author; }
void setDest(const MsgContact& dest) { _dest = dest; }
void setDate(const QDateTime& receivedDate) { _receivedDate = receivedDate; }
void setDirection(const MsgDirection& direction) { _direction = direction; }
void setText(const QString& text) { _text = text; }
void setTransmitted(const bool& transmitted) { _transmitted = transmitted; }
private:
QString _id;
MsgContact _author;
MsgContact _dest;
QDateTime _receivedDate;
MsgDirection _direction;
QString _text;
bool _transmitted; //indique que le message a été transmis
bool _read; //indique la lecture
};
Conversation class :
class Conversation
{
public:
Conversation();
Conversation(const Conversation& other);
virtual ~Conversation();
Conversation& operator=(const Conversation& other);
bool operator==(const Conversation& other);
bool isNull() const { return (NULL == _title || NULL == _destId); }
const QString title() const { return _title; }
const QString destId() const { return _destId; }
QList<Msg> messages() const { return _messages; }
void setDestId(const QString& destId) { _destId = destId; }
void setTitle(const QString& title) { _title = title; }
void addMsg(const Msg& msg);
static Conversation INVALID_CONVERSATION;
private:
QList<Msg> _messages;
QString _title;
QString _destId;
};
void Conversation::addMsg(const Msg& msg)
{
_messages.append(msg);
}
Code that generate the segfault. I create a message, I iterate over the Conversation list to add the message in the related conversation. Then, i want to iterate over the message list and I get a segfault. I use different way to access to the message which works fine.
Msg *m = new Msg();
m->setId(xmppMsg.id());
m->setDest(findContactById(conversationId));
m->setDirection(MsgOutgoing);
m->setAuthor(_myContact);
m->setText(message);
m->setDate(xmppMsg.stamp());
QList<Conversation>::iterator it;
for(it = _conversations.begin(); _conversations.end() != it; it++)
{
if((*it).destId() == conversationId)
{
(*it).addMsg(*m);
Q_EMIT(conversationChanged((*it)));
break;
}
}
qDebug() << "NB : " <<(*it).messages().size(); // ok, the number of message is incremented.
//test several way of accessing a message, these works fine.
qDebug() << "doSend " << it->messages().at(0).id();
qDebug() << "doSend " << it->messages().begin()->id();
qDebug() << "doSend " << (*(it->messages().begin())).id();
//try to iterate
QList<Msg>::iterator msgIt = it->messages().begin();
if(msgIt != it->messages().end())
{
qDebug() << "TEST - "<< msgIt->id(); //segfault.
}
Thank you for your help
(Edited away first "answer", this is an actual attempt at an answer)
My guess:
QList<Msg> messages() const { return _messages; }
It's returning a copy of the QList _messages, rather than a reference to it. I'm not sure that it would give the results you're seeing, but it looks wrong to me. Maybe try something like this?
QList<Msg>& messages() const { return _messages; }

Using QTableView with a model

I have the QVector cars that I want to filter basing on the car's registration number. I want to create a new filtered vector. I don't think that this is ok because i'm iterating 2 vectors, copying from the first one to the second one. Am I doing this right?
void MainWindow::on_actionBy_registration_number_triggered()
{
myDialog = new MyDialog(this);
myDialog->exec();
QString toSearchString = myDialog->getRegistrationNumber();
QVector<Vehicle> founded;
QVectorIterator<Vehicle> iterator(cars);
while(iterator.hasNext()){
Vehicle car = iterator.next();
QString num = car.getRegistration().getRegistrationNumber();
if(num.contains(toSearchString,Qt::CaseInsensitive)){
founded.append(car);
}
}
model = new QStandardItemModel(founded.size(),5,this);
//create header
createHeader(model);
int j = 0; //row
QVectorIterator<Vehicle> iter(founded);
while(iter.hasNext()){
Vehicle output = iter.next();
//set car
QString makeAndModel = output.getGeneralData().getMake() + output.getGeneralData().getModel();
QStandardItem *mAndM = new QStandardItem(QString(makeAndModel));
model->setItem(j,0,mAndM);
//set type
QStandardItem *type = new QStandardItem(QString(output.getGeneralData().getType()));
model->setItem(j,1,type);
//set mileage
QString mileageString = QString::number(output.getGeneralData().getMileage());
QStandardItem *mileage = new QStandardItem(QString(mileageString));
model->setItem(j,2,mileage);
//set year
QString yearString = QString::number(output.getGeneralData().getYear());
QStandardItem *year = new QStandardItem(QString(yearString));
model->setItem(j,3,year);
//set registration
QString regString = VehicleHelper::convertBoolToString(output.getRegistration().isRegistered());
QStandardItem *regDate = new QStandardItem(QString(regString));
model->setItem(j,4,regDate);
j++;
}
ui->tableView->setModel(model);
ui->tableView->setEnabled(false);
}
This can be done neatly using a proxy filter model. Below is a self-contained example that runs on both Qt 4 and 5.
// https://github.com/KubaO/stackoverflown/tree/master/questions/filter-18964377
#include <QtGui>
#if QT_VERSION_MAJOR > 4
#include <QtWidgets>
#endif
class Vehicle {
QString m_make, m_model, m_registrationNumber;
public:
Vehicle(const QString & make, const QString & model, const QString & registrationNumber) :
m_make{make}, m_model{model}, m_registrationNumber{registrationNumber} {}
QString make() const { return m_make; }
QString model() const { return m_model; }
QString registrationNumber() const { return m_registrationNumber; }
bool isRegistered() const { return !m_registrationNumber.isEmpty(); }
};
class VehicleModel : public QAbstractTableModel {
QList<Vehicle> m_data;
public:
VehicleModel(QObject * parent = {}) : QAbstractTableModel{parent} {}
int rowCount(const QModelIndex &) const override { return m_data.count(); }
int columnCount(const QModelIndex &) const override { return 3; }
QVariant data(const QModelIndex &index, int role) const override {
if (role != Qt::DisplayRole && role != Qt::EditRole) return {};
const auto & vehicle = m_data[index.row()];
switch (index.column()) {
case 0: return vehicle.make();
case 1: return vehicle.model();
case 2: return vehicle.registrationNumber();
default: return {};
};
}
QVariant headerData(int section, Qt::Orientation orientation, int role) const override {
if (orientation != Qt::Horizontal || role != Qt::DisplayRole) return {};
switch (section) {
case 0: return "Make";
case 1: return "Model";
case 2: return "Reg.#";
default: return {};
}
}
void append(const Vehicle & vehicle) {
beginInsertRows({}, m_data.count(), m_data.count());
m_data.append(vehicle);
endInsertRows();
}
};
class Widget : public QWidget {
QGridLayout m_layout{this};
QTableView m_view;
QPushButton m_button{"Filter"};
VehicleModel m_model;
QSortFilterProxyModel m_proxy;
QInputDialog m_dialog;
public:
Widget() {
m_layout.addWidget(&m_view, 0, 0, 1, 1);
m_layout.addWidget(&m_button, 1, 0, 1, 1);
connect(&m_button, SIGNAL(clicked()), &m_dialog, SLOT(open()));
m_model.append({"Volvo", "240", "SQL8941"});
m_model.append({"Volvo", "850", {}});
m_model.append({"Volvo", "940", "QRZ1321"});
m_model.append({"Volvo", "960", "QRZ1628"});
m_proxy.setSourceModel(&m_model);
m_proxy.setFilterKeyColumn(2);
m_view.setModel(&m_proxy);
m_dialog.setLabelText("Enter registration number fragment to filter on. Leave empty to clear filter.");
m_dialog.setInputMode(QInputDialog::TextInput);
connect(&m_dialog, SIGNAL(textValueSelected(QString)),
&m_proxy, SLOT(setFilterFixedString(QString)));
}
};
int main(int argc, char *argv[])
{
QApplication a{argc, argv};
Widget w;
w.show();
return a.exec();
}