PDA

View Full Version : Probelm after porting from Qt 3.3.4 to Qt 4.2.2



joseph
30th May 2007, 07:41
Hai

In our application we have developed a "Chemisty Molecule Drawing Chanvas" ,with some other features.
We are now porting the application from Qt3.3.4 to Qt4.2.2.

Here am attaching my code snippet which explains our framework ( precised ). main.cpp will explain the whole thing what we are trying to achive
This is working in Qt3 , but in Qt4 it gives run time exceptions.


Could you please help me out to port the same senario in Qt4.
thanks in advance.

N:B . This code snippet will work only in Qt3.3.4 .

marcel
30th May 2007, 08:37
Ok, no time to attach:
childobject.cpp


#include "childObject.h"

Atom::Atom(QObject *parent)
:QObject(parent)
{
setObjectName( "Atom" );
isSelected = false;
}

Atom::~Atom()
{}

void Atom::deleteSelected()
{
if( isSelected )
delete this;
}
void Atom::setSelected( bool flag )
{
isSelected = flag;
}

Bond::Bond(QObject *parent)
:QObject(parent)
{
setObjectName( "Bond" );
isSelected = false;
}

Bond::~Bond()
{
emit beingDeleted(this);
}

void Bond::setSelected( bool flag )
{
isSelected = flag;
}

bool Bond::selected()
{
return isSelected;
}

void Bond::deleteSelected()
{
if( isSelected )
{
delete this;
}
}
Ring::Ring(QObject *parent)
:QObject(parent)
{
setObjectName( "Ring" );
isSelected = false;
}

Ring::~Ring()
{}

void Ring::setSelected( bool flag )
{
isSelected = flag;
}

bool Ring::selected()
{
return isSelected;
}

void Ring::deleteSelected()
{
if( isSelected )
{
delete this;
}
}

void Ring::addBond(Bond * b)
{
connect( b, SIGNAL(beingDeleted(QObject *)),
this, SLOT(childBeingDeleted(QObject *)) );
}

void Ring::childBeingDeleted(QObject *)
{
/*delete this;*/
}
parentobject.cpp


#include "parentobject.h"
#include "childObject.h"
#include <qobject>

Molecule::Molecule(QObject *parent)
: QObject(parent)
{
isSelected = false;
_ring = 0;
}

Molecule::~Molecule()
{
if( isSelected ){
isSelected = false;
}
}

void Molecule::createRing( Bond* b)
{
if( !_ring )
{
_ring = new Ring( this );
}
_ring->addBond(b);
}

void Molecule::deleteSelected()
{
if( isSelected ){
delete this;
return;
}
QList<QObject*> list;
QObject *obj;
list = children();

foreach( obj, children() )
{
if( obj )
{
qDebug( obj->objectName().toAscii().constData() );
if( obj->objectName() == QString("Bond") )
{
bool sel = ((Bond*)obj)->selected();
if( sel )
{
list.removeAll( obj );
((Bond*)obj)->deleteSelected();
obj = NULL;
}
}
}
}
}

You had several problem there, so I corrected them:
- a QObject automatically deletes its children, so no need to connect and delete the Ring
- QObjectList and QObjectListIt were replaced ( by me :) ).
- I added a selected() function. It just returns is selected.

Note: I'm surprised this worked in Qt3

EDIT: some of the code I posted might be redundant. So feel free to remove those parts.

Regards

joseph
30th May 2007, 10:14
I have tried Your code( Qt4 ) .
But this is not what i want. You have given a solution which does not serve my purpose.

My purpose :-
When i delete a "Bond_object" ( is selected ), the "Ring_object" too has to be deleted ( that's why i used
delete this ; emit childBeeingDeleted(); ).

In main.cpp the explanation what i have given is,if a "Bond "( selected ) is deleted ,the "Ring" ( A closed polygon ) also should be deleted.
In the "Molecule_diagram" you cann't see the "Ring_object" ,but logically we are creating it ( Ring Molecule::_ring ).


What you did:-
You are deleting a "bond_object" ( selected ). but the "Ring_object" still exists in MOLECULE object.



Note: I'm surprised this worked in Qt3
Why...???. Please try it in Qt3 and see the output first.

marcel
30th May 2007, 10:19
But both Bond and Ring are QObjects.
Ring is a child of Bond.
When you delete Bond, it automatically deletes all its children, meaning Ring( you can test this by putting a breakpoint in the destructor of Ring, or use qDebug, whatever ).

Ring will not remain in Molecule's hierarchy because Bond was removed, along with it's children.

Using QObject has some other implications than the obvious ones.

Regards

marcel
30th May 2007, 10:46
Anyway, that was the reason your app crashed.
When you iterated through the child list, you encountered child object( Rings ), that were deleted by Bond objects.

Regards

joseph
30th May 2007, 10:53
Sorry marcel. You are little confused , let me explain the class hierarchy first.



---------------------------------------
| QObject |
---------------------------------------
^ ^ ^ ^
| | | |
| | | |
Molecule | | |
| | |
Atom | |
| |
Bond |
Ring







In my senario "Molecule_object" is the parent of "Atom /Bond " objects.
see main.cpp ...


//children of molecule, 3 atoms, 3 bonds
//Atoms
Atom* atom1 = new Atom( molecule );
Atom* atom2 = new Atom( molecule );
Atom* atom3 = new Atom( molecule );

//bonds
Bond* bond1 = new Bond( molecule );
Bond* bond2 = new Bond( molecule );
Bond* bond3 = new Bond( molecule );


And " Molecule_object " has a "Ring" , see the code ..




class Molecule : public QObject
{

---
---

private :
Ring _ring* ;

}




In main.cpp..



//In Molecule , create a RING [ using function Molecule::createRing( Bond * ) ]
//A ring is a closed polygon [ chemistry term ].
molecule->createRing( bond1 );
molecule->createRing( bond2 );
molecule->createRing( bond3 );





So "Ring_object " is NOT A CHILD of "Bond_object".
Instead "Ring_Object" is getting created in a "Molecule_object" [ using function Molecule::createRing( Bond * ) ]
see the code..


void Molecule::createRing( Bond* b)
{
if( !_ring )
{
_ring = new Ring( this );
}
_ring->addBond(b);
}



thanks

marcel
30th May 2007, 11:03
Yes, of course you are right. Sorry.
I looked again at that diagram now and I get it.
Here's the solution too:


void Molecule::deleteSelected()
{
if( isSelected ){
delete this;
return;
}
QList<QObject*> list;
QObject *obj;

foreach( obj, children() )
{
if( obj )
{
qDebug( obj->objectName().toAscii().constData() );
if( obj->objectName() == QString("Bond") )
{
bool sel = ((Bond*)obj)->selected();
if( sel )
list.append( obj );
}
}
}

while( list.count() )
{
Bond* b= (Bond*)list.takeAt( 0 );
b->deleteSelected();
}
}



As for the rest of the code, you should keep it as you already had it, meaning you must still connect the ring to bond deletion.

And this works, just tested it.

Regards.

marcel
30th May 2007, 11:29
The idea is not to act in any way on the children list of a QObject while deleting items from it.

I thought to delay the deletion, and split the process in two steps, as you can see in my previous post.

Regards

joseph
30th May 2007, 11:41
The idea is not to act in any way on the children list of a QObject while deleting items from it.

I thought to delay the deletion, and split the process in two steps, as you can see in my previous post.

Regards


Consider this scenario...

-----
/ \__> atom1
| |
| |--> bond1
| |__> atom2
\ /
-----

Now there are 8 atoms, 8 bonds and a ring. I select atom1,
bond1, and atom2. So the "list" contains 3 items ( atom1, bond1, atom2).

Now I iterate over the list.
atom1 deletes all its neighbours including bond1( which
is a neighbour of atom1 ) and the ring.

Then we go to next iteration, the application crashes as the next item
in the list is "bond1" which is already deleted.

Fails....

marcel
30th May 2007, 11:57
Yes, my solution is somewhat particular.
This does not mean that there isn't a general one.
Unfortunately I am at work now, but I'll be happy to help once I'm done here.

Regards

joseph
30th May 2007, 14:26
Yes, my solution is somewhat particular.
This does not mean that there isn't a general one.
Unfortunately I am at work now, but I'll be happy to help once I'm done here.

Regards

Waiting eagerly....
Thanks..

spud
31st May 2007, 12:23
Hi,
here's a suggestion:


void Molecule::deleteSelected()
{
if( isSelected ){
deleteLater();
return;
}

foreach( Bond *bond, findChildren<Bond*>() )
bond->deleteSelected();
}
In this case you are not iterating and deleting the children list(dangerous!), but you are implicitely working on a copy.
Also you can remove the setName() calls, since you are only using the class names. You can get to them by calling QMetaObject::className()

joseph
31st May 2007, 14:34
Consider this scenario...

Suppose there are 5 bonds( bond1, .... bond5), from the foreach statement,
Now
1) First Iteration leads to deletion of bond1 and bond3;
2) Second iteration works fine.
3) Third iteration, OH!!!:confused: Crashes, the bond is already deleted in
iteration1.

Fails...
Please provide some solution where the list gets updated
automatically like how it worked in Qt3.

Please run the same code without any changes in Qt3 (provided in first post) and then
run again the same code after porting to Qt4, you
can find the differences..

Please help