2016-03-08 150 views
3

我有2個數據處理類(CGameList和CGame)。QT/QML C++從QML訪問QList程序崩潰

我在QML限定一個遊戲列表(_gamelist)對象與它的工作。
我有一個Listviews顯示從這個GameList(editGames_open())的遊戲。

如果我點擊這個列表中的一個條目,則打開一個新的列表這個遊戲(editGame_open(指數))的詳細視圖。

這項工作如預期般運作。

現在我的問題:
如果我回到列表並嘗試再次打開它,我的程序崩潰(不是每次,有時它的工作20倍)。 getGame調用後出現崩潰。

如果我使用調試器,我可以看到我的CGameList對象看起來很好(數據在我的QList正確+項目是正確的),但是這與分段錯誤的程序崩潰之後。
該callstack只顯示QQMlData :: wasDeleted作爲最後一項。

我認爲這個問題是,我的目標是刪除,但我不能找到這個。

我不得不嘗試改變我的QList從QList作_games到的QList * _games但沒有成功。

另外一件事(我認爲它也是同樣的問題): 有時getGame會給出一個NULL指針(雖然遊戲在列表中,但數據是錯誤的)。

cgamelist.h

#ifndef CGAMELIST_H 
#define CGAMELIST_H 

#include <QObject> 
#include <QList> 
#include <qfile.h> 
#include <QTextStream> 
#include <QDir> 
#include <QStandardPaths> 
#include <QDateTime> 


#include <cgame.h> 

class CGameList : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(int itemCount READ getItemCount) 
public: 
    CGameList(QObject *parent = 0); 
    Q_INVOKABLE bool addGame(QString name,int layout); 
    Q_INVOKABLE int getItemCount() const; 
    Q_INVOKABLE void saveGame(int index); 
    Q_INVOKABLE void loadGames(bool force=true); 
    Q_INVOKABLE CGame* getGame(int i) const; 
    Q_INVOKABLE QString getGamename(int i) const; 
    Q_INVOKABLE QString getGamedate(int i) const; 
    Q_INVOKABLE void delGame(int i); 
private: 
    QList<CGame*>* _games; 
}; 

#endif // CGAMELIST_H 

cgamelist.cpp

CGameList::CGameList(QObject *parent) : QObject(parent) 
{ 
    _games=new QList<CGame*>(); 
    _games->clear(); 
} 
... 
CGame* CGameList::getGame(int i) const 
{ 

    /* CGame*g=new CGame(); 
    g->setGamename("test"); 
    return g;*/ 
    try 
    { 
     return _games->at(i); 
    } 
    catch(...) 
    { 
     return NULL; 
    } 
} 
... 

cgame.h *

#ifndef CGAME_H 
#define CGAME_H 

#include <QObject> 
#include <QString> 
#include <QDateTime> 

class CGame : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(QString gamename READ getGamename WRITE setGamename) 
    Q_PROPERTY(int itemCount READ getItemCount) 
    Q_PROPERTY(int layout READ getLayout WRITE setLayout) 
    Q_PROPERTY(int duration READ getDuration WRITE setDuration) 
    Q_PROPERTY(QDateTime date READ getDate WRITE setDate) 
public: 
    CGame(QObject *parent = 0); 
    Q_INVOKABLE QString getGamename() const; 
    Q_INVOKABLE void setGamename(QString name); 
    Q_INVOKABLE int getItemCount() const; 
    Q_INVOKABLE int getLayout() const; 
    Q_INVOKABLE void setLayout(int layout); 
    Q_INVOKABLE int getDuration() const; 
    Q_INVOKABLE void setDuration(int duration); 
    Q_INVOKABLE QDateTime getDate() const; 
    Q_INVOKABLE void setDate(QDateTime date); 

    Q_INVOKABLE QString getEvent(int i) const; 
    Q_INVOKABLE void addEvent(QString ename,int time,int sec,int duration); 

private: 
    QString _name; 
    int _layout; 
    int _duration; 
    QList<QString>* _events; 
    QDateTime _date; 
}; 

#endif // CGAME_H 

main.cpp中

#include <QGuiApplication> 
#include <QQmlApplicationEngine> 
#include <QtQml> 

#include "clayoutlist.h" 
#include "clayout.h" 
#include "clayoutitem.h" 
#include "cgame.h" 
#include "cgamelist.h" 

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

    QQmlApplicationEngine engine; 
    qmlRegisterType<CLayoutList>("STSP.Tag",1,0,"TagLayoutList"); 
    qmlRegisterType<CLayout>("STSP.Tag",1,0,"TagLayout"); 
    qmlRegisterType<CLayoutItem>("STSP.Tag",1,0,"TagLayoutItem"); 
    qmlRegisterType<CGame>("STSP.Tag",1,0,"Game"); 
    qmlRegisterType<CGameList>("STSP.Tag",1,0,"GameList"); 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 

    return app.exec(); 
} 

main.qml

import QtQuick 2.5 
import QtQuick.Controls 1.4 
import QtQuick.Dialogs 1.2 
import QtQuick.Window 2.2 

import STSP.Tag 1.0 

ApplicationWindow { 
    TagLayoutList { 
     id: _layoutlist 
    } 
    GameList 
    { 
     id:_gamelist 
    } 


    visible: true 

    MainForm { 
     id: mainform 
     anchors.fill: parent 
    } 
    MessageDialog{ 
     id:info 

    } 
    ... 
    function editGames_open() 
    { 
     _gamelist.loadGames() 
     mainform.p_gameslistmodel.clear() 
     var i 
     for (i = 0; i < _gamelist.getItemCount(); i++) { 

      mainform.p_gameslistmodel.append({ 
                name: _gamelist.getGamename(i), 
                date: _gamelist.getGamedate(i), 
                gameindex: i 
               }) 
     } 
     mainform.p_editgames.delmode=false 
     mainform.p_editgames.visible = true 
     mainform.p_startmenu.visible=false 
    } 
    function editGame_open(index) 
    { 
     mainform.p_eventlistmodel.clear() 
     var game={} 
     try 
     { 
     game=_gamelist.getGame(index) 
     } 
     catch(exc) 
     { 
      console.log("Serious Error 2 "+exc) 
      return 
     } 

     if(game==null) 
     { 
      console.log("Reload Games") 
      _gamelist.loadGames() 
      game=_gamelist.getGame(index) 
     } 
     if(game==null) 
     { 
      console.log("Error Game not found") 
      return 
     } 

     var i 
     var event 
     var events 
     var t,s,m,h 
     for(i=0;i<game.getItemCount();i++) 
     { 
      event=game.getEvent(i).split('#')[1] 
      //console.log(event) 
      events=event.split(',') 
      t=events[1] 
      s=t%60 
      t=(t-s)/60 
      m=t%60 
      h=(t-m)/60 
      mainform.p_eventlistmodel.append({ 
                name: events[0], 
                time: h+":"+(m<10?"0":"")+m+":"+(s<10?"0":"")+s, 
                eventindex: i 
               }) 
     } 
     mainform.p_editgame.gname=game.getGamename() 
     t=game.getDuration() 
     s=t%60 
     t=(t-s)/60 
     m=t%60 
     h=(t-m)/60 
     mainform.p_editgame.gtime=h+":"+(m<10?"0":"")+m+":"+(s<10?"0":"")+s 
     mainform.p_editgames.delmode=false 
     mainform.p_editgames.visible=false 
     mainform.p_editgame.visible=true 

    } 

    function editGame_back() 
    { 
     mainform.p_editgame.visible=false 
     mainform.p_editgames.visible=true 
    } 
+0

這是很好,你張貼代碼來顯示問題,但你省略了它,它是不可能讓它運行。 :p你應該嘗試縮小到一個較小的例子。 – Mitch

回答

1

很難不能夠調試程序的說法,但它聽起來像QML是你CGame對象的taking ownership

當數據由C++轉移到QML,數據的所有權總是保持與C++。這個規則的例外是,當從一個明確的C++方法調用中返回一個QObject時:在這種情況下,QML引擎承擔該對象的所有權,除非通過調用QQmlEngine ::明確地將對象的所有權設置爲保留在C++中指定了QQmlEngine :: CppOwnership的setObjectOwnership()。

此外,QML引擎尊重Qt C++對象的正常QObject父所有權語義,並且永遠不會擁有已經擁有父對象的QObject實例的所有權。

最簡單的解決方案是在將每個對象分配給每個CGame對象之前,將其返回給QML。或者,你可以爲每個對象如下:

QQmlEngine::setObjectOwnership(game, QQmlEngine::CppOwnership); 
+0

Thx for this tip 我更改我的代碼並測試ist。直到現在,我也沒有崩潰,它像預期的那樣工作。 – DarkRider

0

我想你將創建一個從C++你的QList,並把在QML像contextProperty(與你不需要申報的QML類,但你仍然需要註冊類型),但問題是你需要刷新(再次執行contextPropertie的聲明的語句)以適應模型中的每個變化,並且是,更好的用戶QObject *。

也許是更好的嘗試使用QmlListProperty(這裏我的情況Use QQmlListProperty to show and modify QList in Qml),在youtube存在其他教程使用該類),或QAbstractListModel(我以前沒有與該類工作,但告訴我在一些稍好例)。