QTimer->Start重复调用会网络延迟造成重复内存泄露吗

乱谈Qt事件循环嵌套 - 开源中国社区
当前访客身份:游客 [
当前位置:
本文旨在说明:QDialog::exec()、QMenu::exec()等开启的局部事件循环,易用的背后,还有很多的陷阱...
Qt 是事件驱动的,基本上,每一个Qt程序我们都会通过QCoreApplication或其派生类的exec()函数来开启事件循环(QEventLoop):
int main(int argc, char**argv)
QApplication a(argc, argv);
return a.exec();
但是在同一个线程内,我们可以开启多个事件循环,比如通过:
QDialog::exec()
QDrag::exec()
QMenu::exec()
这些东西都很常用,不是么?它们每一个里面都在执行这样的语句:
//事件循环
loop.exec();
既然是同一线程内,这些显然是无法并行运行的,那么只能是嵌套运行。
如何演示?
如何用最小的例子来直观说明这个问题呢?
利用定时器来演示应该是最方便的。于是,很容易写出来这样的代码:
#include &QtCore&
class Object : public QObject
Object() {startTimer(200); }
protected:
void timerEvent(QTimerEvent *) {
static int level = 0;
qDebug()&&&Enter: &&&++
//事件循环
loop.exec();
qDebug()&&&Leave: &&&
int main(int argc, char *argv[])
QCoreApplication a(argc, argv);
return a.exec();
然后我们可以期待看到:
但是,很让人失望,这并不会工作。因为Qt对Timer事件派发时进行了处理:
如果当前在处理Timer事件,新的Timer将不会被派发。
我们对这个例子进行一点改进:
收到Timer事件后,我们立即post一个自定义事件(然后我们在对自定义事件的相应中开启局部的事件循环)。这样Timer事件的相应可以立即返回,新的Timer事件可以持续被派发。
另外,为了友好一点,使用了 QPlainTextEdit 来显示结果:
#include &QtGui&
#include &QtCore&
class Widget : public
QPlainTextEdit
Widget() {startTimer(200); }
protected:
bool event(QEvent * evt)
if (evt-&type() == QEvent::Timer) {
qApp-&postEvent(this, new QEvent(QEvent::User));
} else if (evt-&type() == QEvent::User) {
static int level = 0;
this-&appendPlainText(QString(&Enter : %1&).arg(++level));
loop.exec();
this-&appendPlainText(QString(&Leave: %1&).arg(level));
return QPlainTextEdit::event(evt);
int main(int argc, char *argv[])
QApplication a(argc, argv);
return a.exec();
有什么用?
这个例子确实没有什么,因为似乎没人会写这样的代码。
但是,当你调用
QDialog::exec()
QMenu::exec()
QDrag::exec()
等函数时,实际上就启动了嵌套的事件循环,而如果不小心的话,还有遇到各种怪异的问题!
== QDialog::exec() vs QDialog::open()==&在&&以及&&我们解释过QDialog::exec()。它最终就是调用QEventLoop::exec()。
QDialog::exec()这个东西是这么常用,以至于我们很少考虑这个东西的不利因素。QDialog::open()尽管被官方所推荐,但是似乎很少有人用,很多人可能还不知道它的存在。
但是Qt官方blog中:
一文介绍了 exec() 可能造成的危害,并鼓励大家使用 QDialog::open()
在Qt官方的Qt Quarterly中:&*&&对QDialog::open()有详细的介绍
QDialog::open()劣势与优势
看个例子:我们通过颜色对话框选择一个颜色,
使用静态函数,写法很简介(内部调用exec()启动事件循环)
void Widget::onXXXClicked()
QColor c = QColorDialog::getColor();
对话框的常见用法,使用exec()启动事件循环,很直观
void Widget::onXXXClicked()
QColorDialog dlg(this);
dlg.exec();
QColor c = dlg.currentColor();
使用open()函数,比较不直观(因为是异步,需要链接一个槽)
void Widget::onXXXClicked()
QColorDialog *dialog = new QColorD
dialog-&open(this, SLOT(dialogClosed(QColor)));
void Widget::dialogClosed(const QColor &color)
好处嘛(就摘录Andreas Aardal Hanssen的话吧):
By using open() instead of exec(), you need to write a few more lines of code (implementing the target slot). But what you gain is very significant: complete control over execution. Now, the event loop is no longer nested/reentered, you’re not blocking inside a magic exec() function
局部事件循环导致崩溃
Kde开发者官方blog中描述这个问题:
在某个槽函数中,我们通过QDialog::exec() 弹出一个对话框。
void ParentWidget::slotDoSomething()
SomeDialog dlg( this ); //分配在栈上的对话框
if (dlg.exec() == QDialog::Accepted ) {
const QString str = dlg.someUserInput();
//do something with with str
如果这时ParentWidget或者通过其他方式(比如dbus)得到通知,需要被关闭。会怎么样?
程序将崩溃:ParentWidget析构时,将会delete这个对话框,而这个对话框却在栈上。
简单模拟一下(在上面代码中加一句即可):
void ParentWidget::slotDoSomething()
QTimer::singleShot(1000, this, SLOT(deleteLater()));
这篇blog最终给出的结论是:将对话框分配到堆上,并使用QPointer来保存对话框指针。
上面的代码,大概要写成这样:
void ParentWidget::slotDoSomething()
QWeakPointer&SomeDialog& dlg = new SomeDialog(this);
if (dlg.data()-&exec() == QDialog::Accepted ) {
const QString str = dlg.data()-&someUserInput();
//do something with with str
} else if(!dlg) {
if (!dlg) {
delete dlg.data();
感兴趣的可以去看看原文。比较起来 QDialog::open() 应该更值得考虑。
QCoreApplication::sendPostedEvents()
当程序做繁重的操作时,而又不愿意开启一个新线程时,我们都会选择调用
QCoreApplication::sendPostedEvents ()
来使得程序保持相应。这和前面提到的哪些exec()开启局部事件循环的效果其实是完全一样的。
无论是这个,还是QEventLoop::exec()最终都是调用:
QAbstractEventDispatcher::processEvents()
来进行事件派发。前面的问题也都是由它派发的事件引起的。
原文链接:
共有0个评论
更多开发者职位上
有什么技术问题吗?
晨曦之光的其它问题
类似的话题写xml文件时,怀疑有内存泄露,具体哪泄露没有找出来,附一段代码,希望有哪位大神给解决一下:其中XMLSTR&比较大&最大估计得到100多K&再就是Out这个类型&应该是Qtextstream类&能不能被释放掉bool&XMLOp::WriteSetTableEx(SetTable&*SetTables,QString&FilePath,QString&Xml)
&&&&int&i,j,k;
&&&&QString&*XmlS
&&&&XmlStr=new&QString();
&&&&QHash&QString,&Settings*&::const_iterator&C
&&&&QHash&QString,SettingOptions*&::const_iterator&S
&&&&QHash&QString,QString&::const_iterator&O
&&&&&&Cite=SetTables-&GetIterator();
&&&&*XmlStr="&Root&\n";
&&&&for(i=0;i&SetTables-&Count();i++)
&&&&&&&&&&&&&&&Settings&*TmpS
&&&&&&&&QString&TmpK
&&&&&&&&TmpKey=Cite.key();
&&&&&&&&*XmlStr+="&&&&&ClassName&";
&&&&&&&&*XmlStr&+=TmpKey.trimmed()+"\n";
&&&&&&&&TmpSettings=Cite.value();
&&&&&&&&Site=TmpSettings-&GetIterator();
&&&&&&&&for(j=0;j&TmpSettings-&Count();j++)
&&&&&&&&&&&&QString&SK
&&&&&&&&&&&&SettingOptions&*SSettingO
&&&&&&&&&&&&SKey=Site.key();
&&&&&&&&&&&&*&XmlStr+="&&&&&&&&&ConfigData&";
&&&&&&&&&&&&*XmlStr&+=SKey.trimmed()+"\n";
&&&&&&&&&&&&SSettingOptions=Site.value();
&&&&&&&&&&&&&&&&&&&&&Oite=SSettingOptions-&GetIterator();
&&&&&&&&&&&&for(k=0;k&SSettingOptions-&Count();k++)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&QString&TK
&&&&&&&&&&&&&&&&QString&U
&&&&&&&&&&&&&&&&TKey=Oite.key();
&&&&&&&&&&&&&&&&*XmlStr+="&&&&&&&&&&&&Name&";
&&&&&&&&&&&&&&&&*XmlStr+=TKey.trimmed();
&&&&&&&&&&&&&&&&*XmlStr+="&/Name&\n";
&&&&&&&&&&&&&&&&Unit=Oite.value();
&&&&&&&&&&&&&&&&*XmlStr+="&&&&&&&&&&&&Value&";
&&&&&&&&&&&&&&&&*&XmlStr+=Unit.trimmed();
&&&&&&&&&&&&&&&&*XmlStr+="&/Value&\n";
&&&&&&&&&&&&&&&&Oite++;
&&&&&&&&&&&&}
&&&&&&&&&&&&*XmlStr+="&&&&&&&&/ConfigData&\n";
&&&&&&&&&&&&Site++;
&&&&&&&&*XmlStr+="&&&&&/ClassName&\n";
&&&&&&&&Cite++;
&&&&*XmlStr+=Xml+"\n";
&&&&*XmlStr+="&/Root&";
&&&&//add&file&operation&here
&&&&if(QFile::exists(FilePath))
&&&&&&&&QFile::remove(FilePath);
&&&&//Log.Log("开始写入配置文件!\r");
&&&&QFile&*
&&&&file=new&QFile();
&&&&&file-&setFileName(FilePath);
&&&&if(!file-&open(QIODevice::WriteOnly&|&QIODevice::Truncate)&)&&&&return&false&;
&&&&QTextStream&out(file);
&&&&int&XmlC
&&&&XmlCount=0;
&&&&out&&*XmlS
&&&&file-&flush();
&&&&file-&close();
&&&&XmlStr-&clear();
&&&&delete&XmlS
&&&&XmlStr=NULL;
&&&&delete&
&&&&return&
只是一个函数内的QString没必要new吧,(QString&*XmlS&&XmlStr=new&QString();)
还有QFile也没有必要new吧。直接在栈上面声明变量不是很方便吗,函数结束自动销毁,回收内存。
比如:&&if(!file-&open(QIODevice::WriteOnly&|&QIODevice::Truncate)&)&&&&return&false&;
这一行代码,如果失败&return&false,前面new&的QString、QFile全部没有释放,内存泄漏了。
引用&1&楼&jdwx1&的回复:只是一个函数内的QString没必要new吧,(QString&*XmlS&&XmlStr=new&QString();)
还有QFile也没有必要new吧。直接在栈上面声明变量不是很方便吗,函数结束自动销毁,回收内存。
比如:&&if(!file-&open(QIODevice::WriteOnly&|&QIODevice::Truncate)&)&&&&……
+1&没必要的就不要new和delete了,一般我用C++的代码风格是一个函数只有一个返回点,就是函数的最后1行的return,像你这种多个return的风格就容易出现这种问题了,当然在有垃圾回收机制的语言里,多个返回点也是被推荐的,有时候良好的代码风格可以帮助你避免不少问题。
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始终感觉QT的某些机制上是存在问题的,比如QTimer等
恭候大神出现哈~!
引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始终感觉QT的某些机制上是存在问题的,比如QTimer等
恭候大神出现哈~!
能说得具体点,探讨下?
引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始终感觉QT的某些机制上是存在问题的,比如QTimer等
恭候大神出现哈~!
能说得具体点,探讨下?
原来在写一个代码的时候,代码如下:
&//&&&&mMutex.lock();
&&&&QHash&QString,DataPoolUnit&::iterator&i;
&&&&float&S
&&&&Sum=0;
&&&&i=Datas-&begin();
&&&&&&&//&&&&DataPoolUnit&U
&&&&while(i!=Datas-&end())
&&&&&&&&//&&&&&&&&Unit=i.value();
&&&&&&&&if(i.value().ParaType==ParaType)
&&&&&&&&&&&&Sum+=i.value().ParaValue.toFloat();
&&&&&&&&i++;
&&&&//&&&&mMutex.unlock();
&&&&return&S
如果不用上面的方式,而是用&&&&DataPoolUnit&U&来获取某个值的时候,就会出现泄漏,但是
DataPoolUnit&我是做好了COPY&STRUCTURE和析构的
引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始终感觉QT的某些机制上是存在问题的,比如QTimer等
恭候大神出现哈~!
能说得具体点,探讨下?
你上面的代码2种用法都不存在内存泄漏,没有看出有资源分配的地方,我觉得要是有泄漏的现象,最好还是检查DataPoolUnit的实现
引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始终感觉QT的某些机制上是存在问题的,比如QTimer等
恭候大神出现哈~!……
DatapoolUnit的实现应该没问题,这个可以确认的,我把代码也贴出来,
#include&"datapoolunit.h"
DataPoolUnit::DataPoolUnit()
&&&&this-&PLCMD200Data=new&QByteA
&&&&this-&PLCMM50Data=new&QByteA
&&&&this-&PLCSData=new&QByteA
&&&&this-&WarnFlag=0;
&&&&this-&IsWarnEnable=0;
&&&&this-&FunctionStatusCode="NA";
&&&&this-&NameCode="NA";
&&&&this-&DIFlag="2";
&&&&this-&Flag="CSD";
&&&&this-&WarnCount=0;
DataPoolUnit::DataPoolUnit(const&DataPoolUnit&&d)
&&&&*this=d;
DataPoolUnit&&DataPoolUnit::operator&=(const&&DataPoolUnit&&d)
&&&&if(this==&d)
&&&&&&&&return*
&&&&&&&&if(this-&Flag=="CSD")
&&&&&&&&&&&&delete&this-&PLCSD
&&&&&&&&&&&&delete&this-&PLCMM50D
&&&&&&&&&&&&delete&this-&PLCMD200D
&&&&&&&&&&&&PLCSData=NULL;
&&&&&&&&&&&&PLCMM50Data=NULL;
&&&&&&&&&&&&PLCMD200Data=NULL;
&&&&&&&&this-&PLCMD200Data=new&QByteA
&&&&&&&&this-&PLCMM50Data=new&QByteA
&&&&&&&&this-&PLCSData=new&QByteA
&&&&&&&&this-&EquipID=d.EquipID;
&&&&&&&&this-&IsWarnEnable=d.IsWarnE
&&&&&&&&this-&LastDateTime=d.LastDateT
&&&&&&&&this-&LastValue=d.LastV
&&&&&&&&this-&NameCode=d.NameC
&&&&&&&&this-&ParaClass=d.ParaC
&&&&&&&&this-&FunctionStatusCode=d.FunctionStatusC
&&&&&&&&this-&ParaID=d.ParaID;
&&&&&&&&this-&ParaName=d.ParaN
&&&&&&&&this-&ParaType=d.ParaT
&&&&&&&&this-&ParaValue=d.ParaV
&&&&&&&&*&this-&PLCMD200Data=*d.PLCMD200D
&&&&&&&&*this-&PLCMM50Data=*d.PLCMM50D
&&&&&&&&*this-&PLCSData=*d.PLCSD
&&&&&&&&this-&UpdateTime=d.UpdateT
&&&&&&&&this-&WarnFlag=d.WarnF
&&&&&&&&this-&DIFlag=d.DIF
&&&&&&&&this-&WarnCount=d.WarnC
&&&&&&&&return*&
DataPoolUnit::~DataPoolUnit()
&&&&delete&this-&PLCSD
&&&&delete&this-&PLCMM50D
&&&&delete&this-&PLCMD200D
&&&&PLCSData=NULL;
&&&&PLCMM50Data=NULL;
&&&&PLCMD200Data=NULL;
引用&7&楼&ydpro&的回复:引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始终感觉QT的某些机制上是存在问题的……
你的实现是有问题的,c++中要记住copy&constructor不要调用assign&operator,&如果他们有可以复用的代码,请剥离一个函数来实现复用。
copy&constructor对同一对象只会被调用一次,被调用的时候对象还没有创建;而assign&operator是在对象已经存在的情况下调用的,可以多次调用.
你的赋值操作赋的else分支里面,delete一个没有创建的对象的成员,结果应该是未定义的。
另外,建议在构造函数中,优先使用初始化列表,而不是在函数内进行赋值
/questions/2639017/calling-assignment-operator-in-copy-constructor
/questions/2639017/calling-assignment-operator-in-copy-constructor
/questions/1533725/is-it-bad-form-to-call-the-default-assignment-operator-from-the-copy-constructor
引用&8&楼&freebendy&的回复:引用&7&楼&ydpro&的回复:引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内存泄露的时候,是否需要对QT库怀疑,现在始……
对于您说的意思,我的理解如下:
1.对于copy构造来说,被copy的对象本身是存在的,而copy出的对象是被创建的,所以不能用等号?但是很多时候,都是用等号来进行copy构造的?
2.如果不用等号,应该用什么方式来进行呢,一个单独的函数吗?
3.那个else分支里的,有个Flag,那个Flag就是用来标识1这种情况的,是否被构造过;
如有不对之处,还请指正~!
引用&11&楼&ydpro&的回复:引用&8&楼&freebendy&的回复:引用&7&楼&ydpro&的回复:引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内……
另外,能不能写个具体示例学习下,还有请看看1楼的代码有问题吗?
引用&11&楼&ydpro&的回复:引用&8&楼&freebendy&的回复:引用&7&楼&ydpro&的回复:引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本身就可能是内存泄露?
2.在排除内……
A&a1&=&a;&//&Copy&ctor,&not&assignment&operator
a2&=&a;&//&Assignment&operator
这个flag是不需要的,你在一个已经构建了得对象内部判断这个对象有没有被构造,这本身就是个问题。你正确的实现方式应该是,定义一个init函数,将copy&ctor和&assignment&operator重复的代码放在里面,然后被这两者调用。
引用&13&楼&freebendy&的回复:引用&11&楼&ydpro&的回复:引用&8&楼&freebendy&的回复:引用&7&楼&ydpro&的回复:引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题呢,使用这种ITL迭代的方式进行访问,是否本……
本人新手,尚请见谅,还得继续麻烦您,主要是还是有点不理解,呵呵,还请指教,这个代码:
A&a1&=&a;&//&Copy&ctor,&not&assignment&operator
您的意思就是说,虽然是=,但是实际上调用的是copy&constructor,而不是重载的=操作符?
针对于3,这个对象本身被构建了,但是不是仍然可能进行等号赋值操作呢,如果进行了等号赋值,那么这个不属于copy构造的范畴,那么应该只是重载等号,进行操作,是这样理解吗?如果本身被构建了,那么进行重载赋值的时候,是不是考虑要释放资源呢,不然是否还是会内存泄露~
@freebendy
方便的话,是否可以加一下qq~
引用&14&楼&ydpro&的回复:引用&13&楼&freebendy&的回复:引用&11&楼&ydpro&的回复:引用&8&楼&freebendy&的回复:引用&7&楼&ydpro&的回复:引用&6&楼&freebendy&的回复:引用&5&楼&ydpro&的回复:引用&4&楼&freebendy&的回复:引用&3&楼&ydpro&的回复:同问~~
1.是不是QT本身对Hash数据结构的访问机制存在问题……
=只是一个符号,实际上调用copy&ctor还是assignment&operator是由编译器决定,我们的代码比较保证在这些情况下都没有问题,不能设置一些假想,对于3,如果你不让copy&ctor调用assignment&operator,这个flag就是不需要的,因为在赋值的时候你必须释放已分配的资源。
引用&15&楼&ydpro&的回复:@freebendy
方便的话,是否可以加一下qq~
私信你了,上班时间qq和mail都上不了的,只能上网
引用&17&楼&freebendy&的回复:引用&15&楼&ydpro&的回复:@freebendy
方便的话,是否可以加一下qq~
私信你了,上班时间qq和mail都上不了的,只能上网
1.ok,已经加了您的qq
2.那么这样我的copy构造就需要重新写了,实际上对于=这种做法我也发现了对于已经构建的对象是有问题的,所以才会加标志位,这样一说&我就更清楚了,这样我改下试试看
3.还请您麻烦看看下面的代码,为什么会造成泄漏
//曲线数据存储,一天一个文件,300个节点
//1.判断文件是否存在
//2.如果文件不存在,则新建,并将XML字符串直接写入文件,形成SETTABLE类可识别的格式
//3.如果文件存在,则利用SETTABLE将其读入内存,然后利用方法将其生成XML字符串,将本次需要
//追加的内容加载到字符串后,然后重新写入XML文件,释放临时资源
void&SaveHisData::DataGraphicSaveEx(QString&mCurtTime,int&GraphicNo)
&&&&//首先判断&xml文件是否存在
&&&&//根据当前日期,生成文件名
&&&&QDateTime&CT
&&&&QString&DirN
&&&&QString&FileN
&&&&CTime=QDateTime::fromString(mCurtTime,"yyyy-MM-dd&HH:mm:ss");
&&&&DirName=CTime.toString("yyyyMMdd");
&&&&DirName="/media/mmcblk0p1/Graphic/"+DirN&//在相应的文件夹下建立&文件夹
&&&&QDir&temp&;&//判断文件夹是否存在
&&&&if&(!(temp.exists(DirName)))
&&&&&&&&temp.mkdir(DirName);&//创建文件夹
&&&&//--------------------创建文件
&&&&FileName="Graphic";&&//文件的名称为&&G1&&G2&&&...&G300
&&&&QString&FileP
&&&&FilePath=DirName+"/"+FileName+".xml";
&&&&QFile&F
&&&&//&&&&File=new&QFile();
&&&&if&(!File.exists(FilePath))&//如果文件不存在
&&&&&&&&//如果不存在,就先创建一个文件
&&&&&&&&File.setFileName(FilePath);
&&&&&&&&//对文件的操作----------写数据
&&&&&&&&if&(File.open(QIODevice::WriteOnly&|&QIODevice::Append))
&&&&&&&&&&&&QTextStream&out(&File);
&&&&&&&&&&&&QString&XmlS
&&&&&&&&&&&&XmlStr+="&Root&\n";
&&&&&&&&&&&&XmlStr+="&&&ClassName&";
&&&&&&&&&&&&XmlStr+=&QString::number(GraphicNo)+"\n";&&//格式:&1
&&&&&&&&&&&&//压力的数据&//参数ID固定为&ExtPLCSumPa
&&&&&&&&&&&&QString&YLS
&&&&&&&&&&&&YLSum=QString::number(this-&mDataPool-&GetSumValueByParaType("压力"),'f',2);
&&&&&&&&&&&&XmlStr+="&&&&&ConfigData&";
&&&&&&&&&&&&XmlStr+="ExtPLCSumPa\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&设备ID&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数ID&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&ExtPLCSumPa&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数值&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&"+YLSum.trimmed()+"&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&更新时间&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&"+CTime.toString("yyyy-MM-dd&HH:mm:ss")+"&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数名称&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&总压力&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数类型&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&总压力&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&/ConfigData&\n";
&&&&&&&&&&&&//获取总瞬时流量&//参数ID固定为&FlowSumE
&&&&&&&&&&&&QString&SSLLS
&&&&&&&&&&&&SSLLSum=QString::number(this-&mDataPool-&GetSumValueByParaType("瞬时流量"),'f',2);
&&&&&&&&&&&&XmlStr+="&&&&&ConfigData&";
&&&&&&&&&&&&XmlStr+="FlowSumE\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&设备ID&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数ID&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&FlowSumE&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数值&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&"+SSLLSum.trimmed()+"&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&更新时间&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&"+CTime.toString("yyyy-MM-dd&HH:mm:ss")+"&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数名称&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&总瞬时流量&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Name&参数类型&/Name&\n";
&&&&&&&&&&&&XmlStr+="&&&&&&&Value&总瞬时流量&/Value&\n";
&&&&&&&&&&&&XmlStr+="&&&&&/ConfigData&\n";
&&&&&&&&&&&&XmlStr+="&&&/ClassName&\n";
&&&&&&&&&&&&XmlStr+="&/Root&\n";
&&&&&&&&&&&&out&&XmlS
&&&&&&&&&&&&XmlStr.clear();
&&&&&&&&File.flush();
&&&&&&&&File.close();
&&&&else//如果文件存在
&&&&&&&&SetTable&T
&&&&&&&&this-&Xop-&CreateSetTableByXml(FilePath,&Tmp);
&&&&&&&&QString&XmlS
&&&&&&&&XmlStr+="&&&ClassName&";
&&&&&&&&XmlStr+=&QString::number(GraphicNo)+"\n";&&//格式:&1
&&&&&&&&//压力的数据&//参数ID固定为&ExtPLCSumPa
&&&&&&&&QString&YLS
&&&&&&&&YLSum=QString::number(this-&mDataPool-&GetSumValueByParaType("压力"),'f',2);
&&&&&&&&XmlStr+="&&&&&ConfigData&";
&&&&&&&&XmlStr+="ExtPLCSumPa\n";
&&&&&&&&XmlStr+="&&&&&&&Name&设备ID&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数ID&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&ExtPLCSumPa&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数值&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&"+YLSum.trimmed()+"&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&更新时间&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&"+CTime.toString("yyyy-MM-dd&HH:mm:ss")+"&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数名称&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&总压力&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数类型&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&总压力&/Value&\n";
&&&&&&&&XmlStr+="&&&&&/ConfigData&\n";
&&&&&&&&//获取总瞬时流量&//参数ID固定为&FlowSumE
&&&&&&&&QString&SSLLS
&&&&&&&&SSLLSum=QString::number(this-&mDataPool-&GetSumValueByParaType("瞬时流量"),'f',2);
&&&&&&&&XmlStr+="&&&&&ConfigData&";
&&&&&&&&XmlStr+="FlowSumE\n";
&&&&&&&&XmlStr+="&&&&&&&Name&设备ID&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数ID&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&FlowSumE&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数值&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&"+SSLLSum.trimmed()+"&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&更新时间&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&"+CTime.toString("yyyy-MM-dd&HH:mm:ss")+"&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数名称&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&总瞬时流量&/Value&\n";
&&&&&&&&XmlStr+="&&&&&&&Name&参数类型&/Name&\n";
&&&&&&&&XmlStr+="&&&&&&&Value&总瞬时流量&/Value&\n";
&&&&&&&&XmlStr+="&&&&&/ConfigData&\n";
&&&&&&&&XmlStr+="&&&/ClassName&\n";
&&&&&&&&this-&Xop-&WriteSetTableEx(&Tmp,FilePath,XmlStr);
&&&&&&&&Tmp.ReleaseResource();
另,改写了DatapoolUnit的实现,请您看下,十分感谢!!!!
#include&"datapoolunit.h"
DataPoolUnit::DataPoolUnit()
&&&&this-&PLCMD200Data=new&QByteA
&&&&this-&PLCMM50Data=new&QByteA
&&&&this-&PLCSData=new&QByteA
&&&&this-&WarnFlag=0;
&&&&this-&IsWarnEnable=0;
&&&&this-&FunctionStatusCode="NA";
&&&&this-&NameCode="NA";
&&&&this-&DIFlag="2";
&&&&this-&Flag="CSD";
&&&&this-&WarnCount=0;
DataPoolUnit::DataPoolUnit(const&DataPoolUnit&&d)
&&&&this-&PLCMD200Data=new&QByteA
&&&&this-&PLCMM50Data=new&QByteA
&&&&this-&PLCSData=new&QByteA
&&&&this-&EquipID=d.EquipID;
&&&&this-&IsWarnEnable=d.IsWarnE
&&&&this-&LastDateTime=d.LastDateT
&&&&this-&LastValue=d.LastV
&&&&this-&NameCode=d.NameC
&&&&this-&ParaClass=d.ParaC
&&&&this-&FunctionStatusCode=d.FunctionStatusC
&&&&this-&ParaID=d.ParaID;
&&&&this-&ParaName=d.ParaN
&&&&this-&ParaType=d.ParaT
&&&&this-&ParaValue=d.ParaV
&&&&*&this-&PLCMD200Data=*d.PLCMD200D
&&&&*this-&PLCMM50Data=*d.PLCMM50D
&&&&*this-&PLCSData=*d.PLCSD
&&&&this-&UpdateTime=d.UpdateT
&&&&this-&WarnFlag=d.WarnF
&&&&this-&DIFlag=d.DIF
&&&&this-&WarnCount=d.WarnC
DataPoolUnit&&DataPoolUnit::operator&=(const&&DataPoolUnit&&d)
&&&&if(this==&d)
&&&&&&&&return*
&&&&&&&&this-&EquipID=d.EquipID;
&&&&&&&&this-&IsWarnEnable=d.IsWarnE
&&&&&&&&this-&LastDateTime=d.LastDateT
&&&&&&&&this-&LastValue=d.LastV
&&&&&&&&this-&NameCode=d.NameC
&&&&&&&&this-&ParaClass=d.ParaC
&&&&&&&&this-&FunctionStatusCode=d.FunctionStatusC
&&&&&&&&this-&ParaID=d.ParaID;
&&&&&&&&this-&ParaName=d.ParaN
&&&&&&&&this-&ParaType=d.ParaT
&&&&&&&&this-&ParaValue=d.ParaV
&&&&&&&&*&this-&PLCMD200Data=*d.PLCMD200D
&&&&&&&&*this-&PLCMM50Data=*d.PLCMM50D
&&&&&&&&*this-&PLCSData=*d.PLCSD
&&&&&&&&this-&UpdateTime=d.UpdateT
&&&&&&&&this-&WarnFlag=d.WarnF
&&&&&&&&this-&DIFlag=d.DIF
&&&&&&&&this-&WarnCount=d.WarnC
&&&&&&&&return&*
DataPoolUnit::~DataPoolUnit()
&&&&delete&this-&PLCSD
&&&&delete&this-&PLCMM50D
&&&&delete&this-&PLCMD200D
&&&&PLCSData=NULL;
&&&&PLCMM50Data=NULL;
&&&&PLCMD200Data=NULL;
引用&18&楼&ydpro&的回复:引用&17&楼&freebendy&的回复:引用&15&楼&ydpro&的回复:@freebendy
方便的话,是否可以加一下qq~
私信你了,上班时间qq和mail都上不了的,只能上网
1.ok,已经加了您的qq
2.那么这样我的copy构造就需要重新写了,实际上对于=这种做法我也发现了对于已经构建的对象是有问题的,所以才会加标志位,这样一说&我就更清楚了,这样……
你这函数也太长了吧?memory&leak没注意看出来,其他问题倒不少:
1.代码c风格,&遵循RAII,变量的声明和初始化写到一起吧,
2.&if&(!File.exists(FilePath))&//如果文件不存在&---QFile有这个代参数的方法?
3.&组装字符串就抽离出去吧,跟程序逻辑混合在一起,降低代码可读性。
养成良好的编码风格很重要,可以避免很多的低级错误。
另外,别再在别人的地盘继续下去了
引用&20&楼&freebendy&的回复:引用&18&楼&ydpro&的回复:引用&17&楼&freebendy&的回复:引用&15&楼&ydpro&的回复:@freebendy
方便的话,是否可以加一下qq~
私信你了,上班时间qq和mail都上不了的,只能上网
1.ok,已经加了您的qq
2.那么这样我的copy构造就需要重新写了,实际上对于=这种做法我也发现了对于已经构建的对象是有问题的,所以才会加……
恩,代码是比较长,主要是XML字符串组装的过程,其实逻辑很简单,Qfile是有这个方法的
引用&21&楼&freebendy&的回复:另外,别再在别人的地盘继续下去了
热烈欢迎在此讨论问题,大神就是大神。。。。解惑啊!!!!
引用&21&楼&freebendy&的回复:另外,别再在别人的地盘继续下去了
没事的,我想楼主也是欢迎我们讨论的,其实楼主就是我同事,哈哈
大神还在吗,还等着解惑呢....真心求教啊......
引用&19&楼&ydpro&的回复:另,改写了DatapoolUnit的实现,请您看下,十分感谢!!!!
#include&"datapoolunit.h"
DataPoolUnit::DataPoolUnit()
&&&&this-&PLCMD200Data=new&QByteA
&&&&this-&PLCMM50Data=new&QByteA
&&&&this-&……
问题还是有啊
1.DataPoolUnit::DataPoolUnit()&所有成员的初始化都可以放到初始化列表的,这样可以提高效率。
2.同理DataPoolUnit::DataPoolUnit(const&DataPoolUnit&&d)也可以这样做;此外你的那些QByteArray可以使用它的copy&ctor啊,为什么先创建再赋值,很低效。
3.在析构函数,重新赋值为NULL其实是没有必要的,因为对象被析构了,这些指针你也用不了
引用&26&楼&freebendy&的回复:引用&19&楼&ydpro&的回复:另,改写了DatapoolUnit的实现,请您看下,十分感谢!!!!
#include&"datapoolunit.h"
DataPoolUnit::DataPoolUnit()
&&&&this-&PLCMD200Data=new&QByteA
&&&&this-&PLCMM50Data=new&QByte……
恩,您说的问题,我会再改动下,现在,
1.这样写是不是就是没有问题的呢,不会存在泄漏什么的吧,原理理解上应该没有误差了吧?
2.再就是您说的初始化列表,是不是就是指一个Init函数呢?
引用&27&楼&ydpro&的回复:引用&26&楼&freebendy&的回复:引用&19&楼&ydpro&的回复:另,改写了DatapoolUnit的实现,请您看下,十分感谢!!!!
#include&"datapoolunit.h"
DataPoolUnit::DataPoolUnit()
&&&&this-&PLCMD200Data=new&QByteA
&&&&this-……
初始化列表是:
A::A(int&a,&int&b):&mA(a),&mB(b),&mC(NULL)
引用&28&楼&freebendy&的回复:引用&27&楼&ydpro&的回复:引用&26&楼&freebendy&的回复:引用&19&楼&ydpro&的回复:另,改写了DatapoolUnit的实现,请您看下,十分感谢!!!!
#include&"datapoolunit.h"
DataPoolUnit::DataPoolUnit()
&&&&this-&PLCMD200Data=new&QByt……
好的,学习了....
早上来了,继续来盖楼~哈哈
现在还有个问题,就是两个窗体互相调用的问题,比如需要在窗体A中调用显示窗体B,同时关闭窗体A,应该用什么样的方式比较好呢?
引用&30&楼&ydpro&的回复:早上来了,继续来盖楼~哈哈
现在还有个问题,就是两个窗体互相调用的问题,比如需要在窗体A中调用显示窗体B,同时关闭窗体A,应该用什么样的方式比较好呢?
所谓的关闭是什么意思?如果只是表面上关闭,可以把窗口隐藏了,也可以由一个父窗口控制AB2个子窗口,主要看你的应用场景考虑
引用&31&楼&freebendy&的回复:引用&30&楼&ydpro&的回复:早上来了,继续来盖楼~哈哈
现在还有个问题,就是两个窗体互相调用的问题,比如需要在窗体A中调用显示窗体B,同时关闭窗体A,应该用什么样的方式比较好呢?
所谓的关闭是什么意思?如果只是表面上关闭,可以把窗口隐藏了,也可以由一个父窗口控制AB2个子窗口,主要看你的应用场景考虑
关闭是真正意义的关闭,而不是隐藏~,主要是考虑在嵌入式板子上运行,内存空间有限,那个属性Qt::WA_DeleteOnClose已经设置,想知道如何进行窗体互调,看看自己的写法有没有错误
应该没问题吧,你可以测试下看看窗口被销毁了没
引用&33&楼&freebendy&的回复:应该没问题吧,你可以测试下看看窗口被销毁了没
测试了,窗口确实被销毁了,但是内存没有降低~
引用&34&楼&ydpro&的回复:引用&33&楼&freebendy&的回复:应该没问题吧,你可以测试下看看窗口被销毁了没
测试了,窗口确实被销毁了,但是内存没有降低~
你一个窗口占用内存才多大啊,你要测试就要用占用内存很大的窗口对象的看看内存有没有降低
引用&35&楼&freebendy&的回复:引用&34&楼&ydpro&的回复:
引用&33&楼&freebendy&的回复:应该没问题吧,你可以测试下看看窗口被销毁了没
测试了,窗口确实被销毁了,但是内存没有降低~
你一个窗口占用内存才多大啊,你要测试就要用占用内存很大的窗口对象的看看内存有没有降低
就是这么做的,放了好多控件。。。。。
引用&35&楼&freebendy&的回复:引用&34&楼&ydpro&的回复:
引用&33&楼&freebendy&的回复:应该没问题吧,你可以测试下看看窗口被销毁了没
测试了,窗口确实被销毁了,但是内存没有降低~
你一个窗口占用内存才多大啊,你要测试就要用占用内存很大的窗口对象的看看内存有没有降低
大神,看看这个问题怎么解决啊?麻烦了,多谢!!
http://bbs.csdn.net/topics/?page=1
回复
即使是一小步也想与你分享}

我要回帖

更多关于 qtimer singleshot 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信