0

this is my code

devicemodel.h

class Device
{
public:
    Device(const int &nodeId ,const QString &type, const int &lampVoltage);
//![0]

    QString type() const;
    int lampVoltage() const;
    int nodeId() const;
public:
    QString m_type;
    int m_lampVoltage;
    int m_nodeId;
//![1]


};

class DeviceModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum DeviceRoles {
        NodeIdRole = Qt::UserRole + 1,
        TypeRole ,
        LampVoltageRole

    };

    DeviceModel(QObject *parent = 0);
//![1]

    void addDevice(const Device &Device);

    int rowCount(const QModelIndex & parent = QModelIndex()) const;

    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

protected:
    QHash<int, QByteArray> roleNames() const;
private:
    QList<Device> m_Devices;
//![2]

public slots :
    void callFromQml(int index);

};

devicemodel.cpp

Device::Device(const int &nodeId ,const QString &type, const int &lampVoltage)
    : m_nodeId(nodeId) , m_type(type), m_lampVoltage(lampVoltage)
{
}

QString Device::type() const
{
    return m_type;
}

int Device::nodeId() const
{
    return m_nodeId;
}

int Device::lampVoltage() const
{
    return m_lampVoltage;
}

DeviceModel::DeviceModel(QObject *parent)
    : QAbstractListModel(parent)
{
}



void DeviceModel::callFromQml(int index){

   Device k= m_Devices.at(index);
   qDebug() << k.type() << k.lampVoltage();
   k.m_lampVoltage = 5;
    emit dataChanged(createIndex(index,0), createIndex(index,0), {0,1,2} );
}

void DeviceModel::addDevice(const Device &Device)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_Devices << Device;
    endInsertRows();
}

int DeviceModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_Devices.count();
}

QVariant DeviceModel::data(const QModelIndex & index, int role) const {
    if (index.row() < 0 || index.row() >= m_Devices.count())
        return QVariant();

    const Device &Device = m_Devices[index.row()];
    if (role == NodeIdRole)
        return Device.nodeId();
    else if (role == TypeRole)
        return Device.type();
    else if (role == LampVoltageRole)
        return Device.lampVoltage();
    return QVariant();
}

//![0]
QHash<int, QByteArray> DeviceModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[NodeIdRole] = "nodeId";
    roles[TypeRole] = "type";
    roles[LampVoltageRole] = "lampVoltage";
    return roles;
}

main.qml

ListView {
    width: 200; height: 250
    spacing: 10
    model: myModel
    delegate:
        Text { text: "Animal: " + type + ", " + lampVoltage

        MouseArea {
            anchors.fill: parent
            onClicked: {
                console.log("egwegweg");
                myModel.callFromQml(index);
                //lampVoltage = 10;

               // myModel.setData(index , 10 , 2);
            }
        }
    }
}

main.cpp

QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    DeviceModel model;
    model.addDevice(Device(1, "Medium" , 200));
    model.addDevice(Device(1, "Medium" , 200));
    model.addDevice(Device(1, "Medium" , 200));
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("myModel", &model);
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    model.addDevice(Device(1, "Medium" , 200));
    model.addDevice(Device(1, "Medium" , 200));
    model.addDevice(Device(1, "Medium" , 200));

    return app.exec();

i want modify my item values from Qml i wrote a slot named callFromQml and pass index of item from qml to c++ code and want update the values from it but can not do it i don not know emit signal works or not and do not know pass index to it correctly or not and don not

mehran
  • 41
  • 10
  • Not really an answer, but something that will save you a lot of time and effort: https://stackoverflow.com/a/35161903/991484 – dtech Sep 26 '17 at 20:04
  • You can just add a `Q_INVOKABLE` that takes a integer index, a rolename and a value. Internally the method will translate the integer index into a `ModelIndex` and calls [`setData(...)`](http://doc.qt.io/qt-5/qabstractitemmodel.html#setData) with this. Alternatively, I think, if you write to `model.someRole = someNewValue` it will be automatically written back through some magic. – derM - not here for BOT dreams Sep 27 '17 at 07:19
  • i can not understand how do it properly can you provide me snippet code? – mehran Sep 27 '17 at 07:26
  • @derM there will be no automagically writing back, unless the setData() method of the model is implemented surely? – Mark Ch Sep 27 '17 at 19:26
  • Thanks for pointing that out. I have not realized that `setData()` was not implemented, though in the doucmentation it is stated, this is a requirement for editable models. – derM - not here for BOT dreams Sep 27 '17 at 20:20

1 Answers1

1

Thanks for @MarkCh for pointing out, that you have not reimplemented the setData()-method.

The signature is:

bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)

It returns true if some data was set successfully, and false if not. Further, uppon success, before returning, it is necessary to emit dataChanged(...) so any views will be aware of the change.

Let's do it:

  1. Add the appropriate declaration to the header file
  2. Add the implementation to the .cpp-file. This might look like this:

bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.row() < 0 || index.row() >= m_Devices.count())
        return false;

    const Device &Device = m_Devices[index.row()];
    if (role == NodeIdRole) {
        Device.m_nodeId = value.toInt();
        emit dataChanged(index, index);
        return true;
    }
    else if (role == TypeRole) {
        Device.m_type = value.toString();
        emit dataChanged(index, index);
        return true;
    }
    else if (role == LampVoltageRole) {
        Device.m_lampVoltage = value.toInt();
        emit dataChanged(index, index);
        return true;
    }
    return false;
}
  1. Make DeviceModel a friend of Device or change the access of the private fields to usage of getters. As you like.

Now you should be able to set the roles in the delegate as if they were properties... Like:

onClicked: model.nodeId = 100;

The code above is not tested, but should include the most relevant details.