2015-07-21 78 views
2

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

我已经第一次遇到这个问题了Qt 5.4,但我仍然面对它更新到Qt的5.5

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

  • 当使用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; 
      } 
     } 
    } 

} 
+0

我们需要为您的模型提供完整的代码。理想情况下,您应该将所有C++代码放在一个'main.cpp'文件中,并将其添加到此问题中。该代码应该包含模型的整个代码,以及设置QML,模型和运行应用程序的'main()'。 –

+0

谢谢你的回复。 实际上,我想用尽可能少的代码来展示问题,这就是为什么我使用QML模型而不是我的C++模型的原因,因为我与QML模型有同样的问题:我们可以看到模型在按下鼠标(也可以使用Connection元素来演示dataChanged信号)。无论如何,我将在新评论中使用C++模型添加完整的代码。 –

+0

我现在用一个完整的例子编辑我的问题。 –

回答