Qt - creating object with new with parent param - no delete? - c++

Do I understand everything right - if I am creating some Qt object via new and this object has constructor with parent parameter then if I'm passing value to this param I don't need to call delete on this object, it will be called automatically be parent object? And this is true for every Qt class that has parent param in constructor?

Yes:
When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is.

Related

How set C++ class to an Item in qml?

I have a c++ class with name Class2 and I registered it with qmlRegisterType method and I use it as code behind of qml pages in my application.
I have qml file and in onCompleted I want to get an object of Class2 and set it to cl2 in the qml file .but I get an error
left-hand side of assignment operator is not an lvalue
Rectangle{
Component.onCompleted: {
cl2=ObjectAccessor.class2obj;//error is here
}
Class2 {
id: cl2
onMessageChanged: { }
}
}
In qml file I changed the defenition of Class2
property Class2 cl2: Class2 {}
but now i get another error
Cannot assign [undefined] to Class2*
How can i set object of `Class2' so i can all data on this object an all signals?
First of all class2obj being undefined means it is not property interfaced to be accessible from QML.
Second, you cannot assign a qml object to another qml object. It depends on what you want to do.
If you want to assign identity, you will have to put it into a target reference, implemented as a property:
property Class2 cl2: null
...
cl2=ObjectAccessor.class2obj
If you want to assign value, as in to make the property values of the one object to the other, you will have to that member by member.
And if all you need is to connect to a signal, then all you need is a connection element, provided that ObjectAccessor.class2obj actually works:
Connections {
target: ObjectAccessor.class2obj
onMessageChanged: doStuff()
}
For a more complete answer, you will have to post the code related to Class2 and ObjectAccessor. And also clarify that bit:
so i can all data on this object an all signals

Which method get called when i remove a node from parent

I want to know which method of child get called when we remove any Node from its
parent.
I created MyLayer by extending Layer class and then add my own sprite MySprite which extend Sprite class of cocos2d-x framework. I need to decrease a counter when child removed so i need a method which i'd override in my MySprite class.
I use this method to remove.
parent->removeChild(child);
Here parent is MyLayer and child is MySprite pointer.
If the child is running these two methods will be called:
child->onExitTransitionDidStart();
child->onExit();
If you remove the child with cleanup = true(which is the default value), child->cleanup(); will be also called.
So the best solution for you would be to override virtual void onExit(); function of the child. And in the overridden method don't forget to call Node::onExit(); or whatever your superclass will be.

Deleting Pointer to widget Qt C++

I am new with Qt and i am very confused about how widgets are deleted. I was reading a video and i wanted to show up a QProgressbar while the video frames are being read and then remove this QProgressbar when the video is loaded.
I have done it with 2 different ways:
Using Pointers
QWidget* wd = new QWidget();
QProgressBar* pB = new QProgressBar(wd);
QLabel* label = new QLabel(wd);
//setting geometry and updating the label and progressbar
wd->deleteLater();
wd->hide();
this code is written inside a class and i was assuming when the destructor of this class is called, the widget will be deleted with all of it's children but that didn't happen and everytime i run this function again a new widget is created without hiding or deleting the previous one (NOTE: i have tried to delete the label and progressbar from the widget assuming that they will disappear from inside the widget but this didn't happen "delete(pB);")
Using Objects
QWidget wd;
QProgressBar pB(&wd);
QLabel label(wd);
//setting geometry and updating the label and progressbar
wd.deleteLater();
wd.hide();
When i have run the same code but using objects instead of pointers , it has run exactly as i have wanted and everytime i run the function, the old widget is destroyed and a new one is created.
NOTE: -Also when i close the main window, in case of pointers, the widget wd still exists and the program doesn't terminate until i close them manually
- In case of Objects, when i close the main window everything is closed and the program is terminated correctly.
I need someone to explain me why is this happening and how if i am having a vector of pointers to widgets to delete all pointers inside that vector without any memory leakage
In typical C++ the rule would be "write one delete for every new". An even more advanced rule would be "probably don't write new or delete and bury that in the RIAA pattern instead". Qt changes the rule in this regard because it introduces its own memory management paradigm. It's based on parent/child relationships. QWidgets that are newed can be given a parentWidget(). When the parentWidget() is destroyed, all of its children will be destroyed. Hence, in Qt it is common practice to allocate objects on the stack with new, give them a parent, and never delete the memory yourself. The rules get more complicated with QLayout and such becomes sometimes Qt objects take ownership of widgets and sometimes they don't.
In your case, you probably don't need the deleteLater call. That posts a message to Qt's internal event loop. The message says, "Delete me when you get a chance!" If you want the class to manage wd just give it a parent of this. Then the whole parent/child tree will get deleted when your class is deleted.
It's all really simple. QObject-derived classes are just like any other C++ class, with one exception: if a QObject has children, it will delete the children in its destructor. Keep in mind that QWidget is-a QObject. If you have an instance allocated usingnew`, you must delete it, or ensure that something (a smart pointer!) does.
Of course, attempting to delete something you didn't dynamically allocate is an error, thus:
If you don't dynamically allocate a QObject, don't deleteLater or delete it.
If you don't dynamically allocate a QObject's children, make sure they are gone before the object gets destructed.
Also, don't hide widgets you're about to destruct. It's pointless.
To manage widget lifetime yourself, you should use smart pointers:
class MyClass {
QScopedPointer<QWidget> m_widget;
public:
MyClass() :
widget{new QWidget};
{
auto wd = m_widget->data();
auto pb = new QProgressBar{wd};
auto label = new QLabel{wd};
}
};
When you destroy MyClass, the scoped pointer's destructor will delete the widget instance, and its QObject::~QObject destructor will delete its children.
Of course, none of this is necessary: you should simply create the objects as direct members of the class:
class MyClass {
// The order of declaration has meaning! Parents must precede children.
QWidget m_widget;
QProgressBar m_bar{&m_widget};
QLabel m_label{&m_widget};
public:
MyClass() {}
};
Normally you'd be using a layout for the child widgets:
class MyClass {
QWidget m_widget;
QVBoxLayout m_layout{&m_widget};
QProgressBar m_bar;
QLabel m_label;
public:
MyClass() {
m_layout.addWidget(&m_bar);
m_layout.addWidget(&m_label);
}
};
When you add widgets to the layout, it reparents them to the widget the layout has been set on.
The compiler-generated destructor looks as below. You can't write such code, since the compiler-generated code will double-destroy the already destroyed objects, but let's pretend you could.
MyClass::~MyClass() {
m_label.~QLabel();
m_bar.~QProgressBar();
m_layout.~QVBoxLayout();
// At this point m_widget has no children and its `~QObject()` destructor
// won't perform any child deletions.
m_widget.~QWidget();
}

QWidget created in an aux method does not show/draw

I have a QWidget based class that I need to instantiate from another object.
If I create the widget in the body of its parent widget class it is all good:
new NodeWidget(rootItem, this); // this works
But when I use the aux method the widget is created, but never drawn.
rootItem->createWidget(this); // internally rootItem does the same thing as above
The method itself:
void createWidget(QWidget * target) {
if (!_ui) _ui = new NodeWidget(this, target);
...
}
The way I see it, both approaches do the same thing, but the first one works while the second one does not. The NodeWidget constructor runs, but the widget does not appear in the parent widget and the paintEvent is never called. Any ideas why?
EDIT: This is certainly odd, I noticed that the following line:
new QPushButton(this);
works when called in the constructor of the parent widget, but not when called from the mousePress event. What IS the difference?
Do you call show() for your custom widget?
If the child widget is created after it's parent is already showed the parent-child relationship can't show the child too, so you need to explicitly call show().
But when the widget is added in the constructor, the parent isn't showed yet and then when the parent is showed it automatically shows all the children that were not explicitly hidden.

C++ MFC MDI change child window variables on creation

I have an MDI application where a dialog is called when the OnFileNew() function (processed by the theApp object) is called. This dialog allows the user to set values to some variables that then need to be passed on to the CChildFrame object that is created when the ->CreateNewChild() function is called.
How do I pass these variables onto the CChildFrame object that is created by the ->CreateNewChild() function?
EDIT:
In response to an answer I got, here are the results for using ->Create() vs ->CreateNewChild().
Link: CMainFrame *pFrame; - pFrame->CreateNewChild()
Link: CChildFrame *childFrame; - childFrame->Create()
How do I get the tabbed windows shown in the first link with the function declarations described in the second link?
You can pass the data via a customized document template. Derive a class from CMultiDocTemplate to add additional data members, then add a pointer to your derived document template class to your CWinApp-derived app class. Initialize your document template in the usual way, except when you finish, save the new document template object to the pointer in your app class.
Now in your CreateNewChild function, instead of calling CWinApp::OnFileNew, you can just get the data from the current frame, then assign to the data member in the document template saved in the app class, before calling OpenDocumentFile(NULL). You can clear the data members when OpenDocumentFile returns.
The document template will in turn create the child frame and pass the doc template in the create context. To get the create context in the child frame, you can either override CChildFrame::OnCreateClient, or read the create structure in OnCreate:
MDICREATESTRUCT * pMDICreateStruct=(MDICREATESTRUCT * )lpCreateStruct->lpCreateParams;
CCreateContext *pCreateContext=(CCreateContext *)pMDICreateStruct->lParam;
Instead of passing the initialization data in the document template, you could also pass data to the new document. You will basically copy the code from CMultiDocTemplate::OpenDocumentFile and add the code to get the initialization data from the active document of the main frame.