在dataChanged信号之后,MapItemView不会更新

时间:2015-07-21 10:04:03

标签: qt geolocation qml qtquick2

我正在使用QML MapItemView组件和基于C ++ QAbstractListModel的模型。重置模型时,或者添加新项目或删除现有项目时,MapItemView正常工作。但是,MapItemView并未反映已添加项目的更改。

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

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

  • 使用QML模型时,单击地图将添加新元素并修改第一个元素。
  • C ++模型使用QTimer每秒修改一次内容。

MapItemView未显示模型更改,无论模型类型如何。从一个模型切换到另一个模型时,可以看到MapView得到更新。

我可能错过了一些非常明显的东西,但我不知道它是什么。提前感谢您的帮助。

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;
            }
        }
    }

}

1 个答案:

答案 0 :(得分:0)

如果有人面对帖子作者报告的同一issue,问题在Qt 5.6.0中得到解决

  

请注意,这由已在5.6分支中合并的变更集Ib92252d18c2229bc6d43e11362b8f13cdb48f315(https://codereview.qt-project.org/#/c/123660/)修复