在dataChanged信号后未更新MapItemView [英] MapItemView is not updated after a dataChanged signal

查看:247
本文介绍了在dataChanged信号后未更新MapItemView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将QML MapItemView组件与基于C ++ QAbstractListModel的模型一起使用.重置模型或添加新项目或删除现有项目时,MapItemView正常工作.但是,MapItemView不能反映对已添加项目的更改.

I am using the QML MapItemView component with a C++ QAbstractListModel-based model. The MapItemView is working fine when the model is reset, or whenever a new item is added or an existing item is removed. However, the MapItemView is not reflecting changes to already added items.

我第一次在Qt 5.4上遇到了这个问题,但是在更新到Qt 5.5之后我仍然面对它

I have first experienced this issue with Qt 5.4 but I still face it after updating to Qt 5.5

以下示例显示了2种不同模型的问题:基于QAbstractListModel的C ++模型和QML ListModel. 按下右上角的按钮,可以从一种模式切换到另一种模式:

The following example shows the issue with 2 different models : a C++ model based on QAbstractListModel and a QML ListModel. It is possible to switch from one model to another, pressing the top-right button:

  • 使用QML模型时,单击地图将添加一个新元素并修改第一个元素.
  • C ++模型使用QTimer每秒钟修改其内容.
  • When the QML model is used, clicking in the map will add a new element and modify the first element.
  • The C++ model used a QTimer to modify its content every seconds.

MapItemView不会显示模型更改,无论模型类型是什么.从一种模型切换到另一种模型时,可以看到MapView得到更新.

The MapItemView is not showing the model changes whatever the model type is. When switching from one model to another, one can see that the MapView gets updated.

我可能缺少一些非常明显的东西,但是我看不到它是什么.预先感谢您的帮助.

I am probably missing something very obvious but I don't see what it is. Thank you in advance for your help.

main.cpp代码:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "playermodel.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    PlayerModel playerModel;
    engine.rootContext()->setContextProperty("playerModel", &playerModel);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

C ++模型头(playermodel.h):

#ifndef PLAYERMODEL_H
#define PLAYERMODEL_H


#include <QObject>
#include <QAbstractListModel>
#include <QGeoPositionInfoSource>
#include <QTimer>
#include <QDebug>

struct PlayerData
{
    PlayerData(){    }
    PlayerData(int _Azimuth, double lat, double lng){
        Azimuth = _Azimuth;
        Latitude = lat;
        Longitude = lng;
    }

    int Azimuth = -1;
    double Latitude = 0.;
    double Longitude = 0.;

    QVariant getRole(int role) const;

    enum Roles{
        RoleAzimuth = Qt::UserRole + 1,
        RoleLatitude,
        RoleLongitude

    };

};

class PlayerModel : public QAbstractListModel
{
    Q_OBJECT
public:
    PlayerModel();

    ~PlayerModel();

    int rowCount(const QModelIndex & parent = QModelIndex()) const;
    QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const;
    Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;    

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

    bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());

    void resetModel();
    void updateModel();

public slots:
    void testUpdateModel();

protected:
    QHash<int, QByteArray> roleNames() const;

private:
    QTimer m_timer;
    QVector< PlayerData> m_lstValues ;
};


#endif // PLAYERMODEL_H

C ++模型(playermodel.cpp)

#include "playermodel.h"

QVariant PlayerData::getRole(int role) const
{
    switch (role)
    {
        case Roles::RoleAzimuth:
            return Azimuth;
        case Roles::RoleLatitude:
            return Latitude;
        case Roles::RoleLongitude:
            return Longitude;

    default:
        return QVariant();
    }
}

PlayerModel::PlayerModel()
{

    resetModel();
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(testUpdateModel()));
    m_timer.start(1000);

}

PlayerModel::~PlayerModel()
{

}

void PlayerModel::testUpdateModel()
{
    updateModel();

}

int PlayerModel::rowCount(const QModelIndex & parent) const
{
    Q_UNUSED(parent);
    return m_lstValues.size();
}

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

    return m_lstValues[ index.row()].getRole( role);

}

void PlayerModel::resetModel()
{
    qDebug() << "Reset players model";

    beginResetModel();

    m_lstValues.clear();
    //populate with dummy value

    m_lstValues.push_back( PlayerData( 10,  47.1, -1.6 ));
    m_lstValues.push_back( PlayerData( 20,  47.2, -1.6 ));
    m_lstValues.push_back( PlayerData( 30,  47.1, -1.5 ));
    m_lstValues.push_back( PlayerData( 40,  47.2, -1.5 ));

    endResetModel();

}


void PlayerModel::updateModel()
{
    qDebug() << "update players model upon timeout";

    //change the Azimuth of every model items
    int row = 0;
    for (PlayerData player : m_lstValues)
    {
        setData( index(row), (player.Azimuth + 1) % 360, PlayerData::RoleAzimuth);
        row++;
    }

    //qDebug() << "First element azimuth is now : " << data( index(0),PlayerData::RoleAzimuth).toInt() << "°";
}

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

    PlayerData& player = m_lstValues[ index.row() ];
    switch (role)
    {

        case PlayerData::RoleAzimuth:
            player.Azimuth = value.toInt();
            break;
        case PlayerData::RoleLatitude:
            player.Latitude = value.toDouble();
            break;
        case PlayerData::RoleLongitude:
            player.Longitude = value.toDouble();
            break;

    }
    emit dataChanged(index, index );//, QVector<int>( role));

    return true;
}

bool PlayerModel::removeRows(int row, int count, const QModelIndex & parent)
{
    Q_UNUSED(count);
    Q_UNUSED(parent);
    beginRemoveRows(QModelIndex(), row, row);
    m_lstValues.remove( row);
    endRemoveRows();
    return true;
}

QHash<int, QByteArray> PlayerModel::roleNames() const
{
    QHash<int, QByteArray> roles;

    roles[PlayerData::Roles::RoleAzimuth] = "Azimuth";
    roles[PlayerData::Roles::RoleLatitude] = "Latitude";
    roles[PlayerData::Roles::RoleLongitude] = "Longitude";

    return roles;

}

Qt::ItemFlags PlayerModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
            return 0;

    return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

,最后是QML文件:

import QtQuick 2.4
import QtQuick.Window 2.2
import QtLocation 5.3
import QtPositioning 5.0

Window {
    id:mainWnd
    visible: true
    width : 1024
    height:768
    property bool  useQMLModel: true
    Map {
       id: map
       anchors.fill: parent
       anchors.margins: 50
       plugin: Plugin{ name:"osm";}
       center: QtPositioning.coordinate(47.1, -1.6)
       zoomLevel: map.maximumZoomLevel

       MapItemView{
           id:mapItemView
           model: mainWnd.useQMLModel ? qmlModel : playerModel

           delegate: MapQuickItem {
              //anchorPoint:
              id:delegateMQI
              rotation: model.Azimuth
              sourceItem: Rectangle{
                  id:defaultDelegate
                  width:32
                  height:32
                  radius:16
                  opacity: 0.6
                  rotation:Azimuth
                  color:"blue"

                  Text{
                      text: Azimuth
                      anchors.centerIn : parent
                  }

              }
              coordinate: QtPositioning.coordinate(Latitude,Longitude)
          }

       }
       MouseArea{
           anchors.fill: parent
           enabled : useQMLModel
           //preventStealing: true
           propagateComposedEvents: true
           onClicked:
           {
               //Modify an item
               var newAzim = Math.random()*360;
               qmlModel.setProperty(0, "Azimuth", newAzim);
               //Check modification
               console.log("Azim:" + qmlModel.get(0).Azimuth );
               qmlModel.setProperty(0, "Color", "blue");


               //add a new item
               qmlModel.append({"Latitude": 47.05 + Math.random() *0.2, "Longitude":-1.75 + Math.random() *0.3, "Azimuth":0, "Color":"red"})
               console.log("Nb item:" + qmlModel.count );


               map.update();
               map.fitViewportToMapItems();

               mouse.accepted = false

           }
       }
    }


    Connections{
        target:mapItemView.model
        onDataChanged:{
            if (useQMLModel)
                console.log("dataChanged signal Azim:" + qmlModel.get(0).Azimuth );
            else
                console.log("dataChanged signal Azim:" + playerModel.data( topLeft, 0x0101) );
        }
    }

    ListModel{
        id:qmlModel
        ListElement {
            Latitude: 47.1
            Longitude: -1.6
            Azimuth: 10.0
        }

    }

    Rectangle{
        anchors.top : parent.top
        anchors.left : parent.left
        width : 400
        height : 300
        radius: 10
        color:"grey"
        ListView{
            id:lstView
            model:mapItemView.model
            anchors.fill:parent
            delegate: Text{
                width:parent.width
                height:50
                verticalAlignment: TextInput.AlignVCenter
                fontSizeMode : Text.Fit
                font.pixelSize: 42
                minimumPixelSize: 5
                text: "Latitude : " + Latitude + " - Longitude :" + Longitude + " - Azimuth : " + Azimuth
            }
        }
    }




    Rectangle{
        anchors.right : parent.right
        anchors.top : parent.top
        radius : 10
        color : "red"
        width : 200
        height : 50
        Text{
            anchors.centerIn: parent
            text:"switch model"
        }
        MouseArea{
            anchors.fill: parent
            onClicked:{
                mainWnd.useQMLModel = !mainWnd.useQMLModel;
            }
        }
    }

}

推荐答案

以防万一有人面对相同的问题

Just in case that someone faces the same issue reported by the post's author, the problem was solved in Qt 5.6.0

请注意,此问题已通过更改集Ib92252d18c2229bc6d43e11362b8f13cdb48f315( https://codereview.qt -project.org/#/c/123660/)已合并到5.6分支中

Note that this is fixed by changeset Ib92252d18c2229bc6d43e11362b8f13cdb48f315 (https://codereview.qt-project.org/#/c/123660/ ) already merged in the 5.6 branch

这篇关于在dataChanged信号后未更新MapItemView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆