2015-07-21 2 views
2

Я использую компонент QML MapItemView с моделью на C++ QAbstractListModel. MapItemView работает нормально при сбросе модели или при добавлении нового элемента или удалении существующего элемента. Однако MapItemView не отражает изменения уже добавленных элементов.MapItemView не обновляется после сигнала dataChanged

я впервые испытал этот вопрос с Qt 5.4, но я до сих пор перед этим после обновления до Qt 5.5

Следующий пример показывает проблему с 2-х различных моделей: модель C++ на основе QAbstractListModel и 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(); 
} 

модель заголовка С ++ (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' и добавить его к этому вопросу. Этот код должен содержать весь код модели, а также 'main()', который устанавливает QML, модель и запускает приложение. –

+0

Благодарим вас за ответ. На самом деле, я хотел показать проблему с меньшим количеством кода, поэтому я использовал модель QML вместо моей модели C++, поскольку у меня такая же проблема с моделью QML: мы можем видеть, что модель изменяется, когда нажатие мыши (можно также использовать элемент «Соединение» для демонстрации передаваемых сигналов DataChanged). Во всяком случае, я добавляю полный код с использованием модели C++ в новый комментарий. –

+0

Теперь я редактирую свой вопрос с полным примером. –

ответ

0

Только в том случае, кто-то сталкивается с теми же issue сообщенный автора поста, эта проблема была решена в Qt 5.6.0

Обратите внимание, что это фиксируются Ib92252d18c2229bc6d43e11362b8f13cdb48f315 (набор изменений https://codereview.qt-project.org/#/c/123660/) уже объединено в 5.6 ветви

Смежные вопросы