• 3442阅读
  • 5回复

[提问]求助!用setcontextproperty重置gridview的model,运行多次后程序崩溃 [复制链接]

上一主题 下一主题
离线inanity
 

只看楼主 倒序阅读 楼主  发表于: 2017-12-20
主要想实现的功能是:界面中用gridview画视图,gridview的model数据是由QQmlContext::setcontextproperty加载的QList<QOBJECT*>。但修改QList<QOBJECT*>中元素后,用setcontextproperty重置模型时,程序会崩溃。
有几个问题
1.程序是用setcontextproperty重置模型后几次才崩溃的,也就是能运行N次setcontextproperty,界面也能显示出QList中的数据
2.每次setcontextproperty后,程序内存会涨2-3M左右,而且内存值不会往下掉(也就是说setcontextproperty会申请一些空间,还不会释放)。
3.qt creator的debug模式是不是有内存限制,内存涨到500M左右有些要用内存操作就会保存,比如加载图片用的QImage。4.是否用继承QAbstractListModel比使用QList来加载Model数据好些。


以下是简化过的部分代码:
main.qml
  1. GridView{
  2.             id:gridview
  3.             ...
  4.             model: templist
  5.             delegate: gridview_component
  6.         }
  7.     }
  8.     Component{
  9.         id:gridview_component
  10.         Item{
  11.             ...
  12.             Rectangle{
  13.                 ...
  14.                 Text {
  15.                     id: text11
  16.                     ...
  17.                     text: text1
  18.                 }
  19.                 Text {
  20.                     id: text22
  21.                     ...
  22.                     text: text2
  23.                 }
  24.                Text {
  25.                     id: text33
  26.                     ...
  27.                     text: text3
  28.                 }
  29.       }
  30. }
main.cpp:
temp是QList<QObect*>
  1. int main(int argc, char *argv[])
  2. {
  3.     QGuiApplication app(argc, argv);
  4.     QQmlApplicationEngine engine;
  5.     QQmlContext* context=engine.rootContext();
  6.     Midware *midware= new Midware();
  7.     midware->setContext(context);
  8.     context->setContextProperty("templist",QVariant::fromValue(midware->temp));
  9.     engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  10.     return app.exec();
  11. }
Midware类包含一个QTcpsocket,其中
  1. connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(readMsg()));
readMsg中...是省略的接收消息的代码,消息不完整不会进入下面代码,会直接return 出去。
temp是QList<QObect*>
  1. void Midware::readMsg()
  2. {
  3.     while(true)
  4.     {
  5.         ...
  6.         qDeleteAll(temp);
  7.         temp.clear();
  8.         qsrand(time(0));
  9.         int max=qrand()%16+1;
  10.         for(int i=0;i<max;i++)
  11.         {
  12.             Data* dataTemp=new Data();
  13.             temp.append(dataTemp);
  14.         }
  15.         context->setContextProperty("templist"    ,nullptr);
  16.         context->setContextProperty("templist"    , QVariant::fromValue(temp));
  17.     }
  18. }
加这句有时能跑的时间长点,不知道是不是那几次内存没涨到限制值。
  1. context->setContextProperty("templist"    ,nullptr);
Data类:
  1. class Data :public QObject
  2. {
  3.     Q_OBJECT
  4.     Q_PROPERTY(QString text1 READ read_text1 CONSTANT)
  5.     Q_PROPERTY(QString text2 READ read_text2 CONSTANT)
  6.     Q_PROPERTY(QString text3 READ read_text3 CONSTANT)
  7. private:
  8.     QString text1;
  9.     QString text2;
  10.     QString text3;
  11. public:
  12.     Data(){ text1="text1"; text2="text2"; text3="text3";}
  13.     ~Data();
  14.     QString read_text1() const {   return this->text1;    }
  15.     QString read_text2() const {   return this->text2;    }
  16.     QString read_text3() const {   return this->text3;    }
  17. };







离线小韩老师

只看该作者 1楼 发表于: 2017-12-20
程序崩溃一般是内存分配不好造成的,打眼瞟一下这个
        context->setContextProperty("templist"    ,nullptr);
        context->setContextProperty("templist"    , QVariant::fromValue(temp));
每次循环都注册一次templist,感觉很不合理。要把templist看做一个容器,容器就好比一个仓库,你的内容就是仓库里的货,你每次来了一批新货你是先把仓库拆了,再为新货建立一个仓库。
把context->setContextProperty("templist"    , QVariant::fromValue(temp));放到构造函数中,或者这个接收消息函数外初始化。 context->setContextProperty("templist"    ,nullptr);函数删除,你每次就对指针指向的内容操作,消息增加新消息,删除旧消息
离线zxwmail

只看该作者 2楼 发表于: 2017-12-22
,小韩老师讲的对。
离线inanity

只看该作者 3楼 发表于: 2017-12-25
回 小韩老师 的帖子
小韩老师:
程序崩溃一般是内存分配不好造成的,打眼瞟一下这个
        context->setContextProperty("templist"    ,nullptr);
        context->setContextProperty("templist"    , QVariant::fromValue(temp));
每次循环都注册一次templist,感觉很不合理。要把templist看做一个容器,容器就好比一个仓库,你的内容就是仓库里的货,你每次来了一批新货你是先把仓库拆了,再为新货建立一个仓库。
把context->setContextProperty("templist"    , QVariant::fromValue(temp));放到构造函数中,或者这个接收消息函数外初始化。 context->setContextProperty("templist"    ,nullptr);函数删除,你每次就对指针指向的内容操作,消息增加新消息,删除旧消息

每次循环调用setContextProperty是为了重置model的数据。不然QML部分不知道templist中的数据已经修改了。

我发现删除掉qDeleteAll(temp);,程序能正常跑。所有有点疑问是:C++的temp传递到QML时是不是有内存上的联系,要在setContextProperty重置后才能将重置前temp中的数据释放掉。

现在程序先用保存旧的数据,只调用temp.clear();清空temp,没将数据释放,再在temp添加新数据,用setContextProperty重置model后,才调用qDeleteAll(qlistTemp); qlistTemp.clear();
  1. QList<QObject*> qlistTemp=temp;
  2.         temp.clear();
  3.         qsrand(time(0));
  4.         int max=qrand()%16+1;
  5.         for(int i=0;i<max;i++)
  6.         {
  7.             Data* dataTemp=new Data();
  8.             temp.append(dataTemp);
  9.         }
  10.         context->setContextProperty("templist"    ,nullptr);
  11.         context->setContextProperty("templist"    , QVariant::fromValue(temp));
  12.         
  13.         qDeleteAll(qlistTemp);
  14.         qlistTemp.clear();
   程序使能正常跑了,当内存会涨20M后稳定。主要是这内存涨的有点多。。。

离线小韩老师

只看该作者 4楼 发表于: 2017-12-26
1.首先最好用当然是使用QAbstractItemModel,这个是专门为模型设计的,安全高效,你说的这些问题都不会出;
2.你说数据没有更新是指增加的数量不更新还是每个条目里的内容不更新?要是数量没有很新,你就是原来是5个现在是4个,模型更新完了还是显示5个,那你就要手动更新了?要是你这次写进去的内容和上次的不一样,比如这次这个text new但是还是显示上一次的,那就是你的属性写的需要比较全把属性里增加notify的信号?自己去尝试一下吧
离线inanity

只看该作者 5楼 发表于: 2017-12-26
回 小韩老师 的帖子
小韩老师:1.首先最好用当然是使用QAbstractItemModel,这个是专门为模型设计的,安全高效,你说的这些问题都不会出;
2.你说数据没有更新是指增加的数量不更新还是每个条目里的内容不更新?要是数量没有很新,你就是原来是5个现在是4个,模型更新完了还是显示5个,那你就要手动更新了?要是 .. (2017-12-26 12:22) 

谢谢
快速回复
限100 字节
 
上一个 下一个