In a QTextEdit object, let's say I want to know the character's position under the mouse cursor.
I can write...
void MyQTextEditObject::mousePressEvent(QMouseEvent* mouse_event) {
mycursor = this->textCursor();
qDebug() << "pos=" << mycursor.position();
}
... it works (the mouse position changes from 0 to the last index of the last character) but the mousePressEvent() method creates a new cursor every time an event occurs. It bothers me since I don't know the "cost" of such a creation.
So, why not create a cursor attribute and use it in mousePressEvent() ?
Something like :
class MyQTextEditObject : public QTextEdit {
Q_OBJECT
public:
// [...]
QTextCursor cursor;
}
MyQTextEditObject::MyQTextEditObject(QWidget* parent) : QTextEdit(parent) {
// [...]
this->cursor = this->textCursor();
}
void MyQTextEditObject::mousePressEvent(QMouseEvent* mouse_event) {
qDebug() << "pos=" << this->cursor.position();
}
But the position doesn't change anymore, as if it was fixed. So, is there a way to somehow update the cursor ? Or is the cost of repeated creation of a QTextCursor insignificant ?
update : writing something like...
mycursor= this->cursorForPosition(mouse_event->pos());
... creates a new cursor and seems to be the equivalent to :
mycursor= this->textCursor();
In your first example, instead of
mycursor = this->textCursor();
qDebug() << "pos=" << mycursor.position();
why do not you call it directly as?
qDebug() << "pos=" << this->textCursor().position();
Because in python
self.textCursor().position()
works.
Also, I am not sure but in your second example maybe you need to set the "cursor" as "textCursor" again with setTextCursor().
void MyQTextEditObject::mousePressEvent(QMouseEvent* mouse_event) {
this->setTextCursor(cursor)
qDebug() << "pos=" << this->cursor.position();
}
Related
I'm using Qt3D. I'm adding QObjectPicker to my 3D entities like this:
Qt3DRender::QObjectPicker *MyScene::createObjectPickerForEntity(Qt3DCore::QEntity *entity)
{
if (!entity)
return nullptr;
picker = new Qt3DRender::QObjectPicker(entity);
picker->setHoverEnabled(true); // I set this correctly
picker->setDragEnabled(true); // Also required!
picker->setObjectName(QStringLiteral("__internal ") + entity->objectName());
entity->addComponent(picker);
connect(picker, &Qt3DRender::QObjectPicker::pressed, this, &MyScene::handlePickerPress);
connect(picker, &Qt3DRender::QObjectPicker::moved, this, &MyScene::handlePickerMove);
return picker;
}
The mouse press events are fired, and corresponding slot logs the name of pressed entity and global coordinate correctly:
void MyScene::handlePickerPress(Qt3DRender::QPickEvent *event)
{
Qt3DCore::QEntity *pressedEntity = qobject_cast<Qt3DCore::QEntity *>(sender()->parent());
if (!pressedEntity && !pressedEntity->isEnabled())
return;
qDebug() << "Pressed Entity Name: "<< pressedEntity->objectName();
qDebug() << "Global Coord: " << event->worldIntersection();
}
However, to my surprise, the mouse move (hover) events are not working. The following slot function is NOT logging anything. Also, when I place a debugger break-point at this slot, I see that it is NOT invoked at all:
void MyScene::handlePickerMove(Qt3DRender::QPickEvent *event)
{
qDebug() << "Hover Intersection:" << event->worldIntersection();
}
Am I missing something?
My Qt3D rendering settings are:
m_renderSettings = new Qt3DRender::QRenderSettings();
m_renderSettings->pickingSettings()->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
m_renderSettings->pickingSettings()->setPickResultMode(Qt3DRender::QPickingSettings::NearestPick);
m_renderSettings->setObjectName(QStringLiteral("__internal Scene frame graph"));
m_renderer = new Qt3DExtras::QForwardRenderer();
m_renderer->setClearColor(QColor("#c8c8c8"));
m_renderSettings->setActiveFrameGraph(m_renderer);
m_renderSettings->setRenderPolicy(Qt3DRender::QRenderSettings::RenderPolicy::OnDemand);
m_rootEntity->addComponent(m_renderSettings);
m_rootEntity->addComponent(new Qt3DInput::QInputSettings());
UPDATE
Relates to this report.
The description of the moved signal says: "This signal is emitted when the bounding volume defined by the pickAttribute property intersects with a ray on a mouse move with a button pressed".
So this signal is not emitted on hover/mouse move, but on mouse move while pressing a mouse button.
So I want to create the gui interface in Qt/cpp for the server which can be in many different states, and depending on its state the buttons in gui need to be set differently ex:
GUI:
button1 - unchecked and enabled to click
button2 - disabled(grayed out)
button3 - disabled
button3 - disabled
Then after click button1
GUI:
button1 - checked
button2 - enabled to click
button3 - enabled to click
button3 - enabled to click
But for example if server is in different state and you connect via gui the buttons should look like this:
GUI:
button1 - checked
button2 - enabled to click
button3 - disabled to click
button3 - disabled to click
Is there some established pattern/way of handling that intuitively? The biggest problem here is that if the server has a lot of different states that need the buttons to be set in a lot of different configurations. The only thing I can come up with is mapping the state of all buttons to the specific state but well... there's a lot of buttons and a lot of states.
You could try using flags, the idea is that when an event happens and you want the GUI to change you set a flag which in turn is recalled in a loop. Below you can see the general idea and concept.
If you change the state of the flag you will get a different output and it will loop over and over listening for events just write the GUI code for each in the different states.
#include <iostream>
using namespace std;
int getserverstatusfunction() {/*your code to check server status returns 0,1 or 2*/
return 0;
}
UI.button.click(true) { getresult = 1; }; //change the UI state when the button is clicked
int main() {
bool running;
while (running){
int getresult = getserverstatusfunction();
if (getresult == 0)
{
cout << "Draw flag one interface code\n";
}
else if (getresult == 1)
{
cout << "Draw flag two interface code\n";
}
else {
cout << "Draw flag three interface code\n";
}
system("pause");
return 0;
}
I've found the best way to do this is just to have a single slot-method (e.g. UpdateAllButtonStates() that updates all of your buttons and checkboxes, e.g.:
void MyWindow::UpdateAllButtonStates() // Qt-slot method
{
const bool shouldButton1BeEnabled = [...];
button1->setEnabled(shouldButton1BeEnabled);
const bool shouldButton2BeEnabled = [...];
button2->setEnabled(shouldButton2BeEnabled);
[... and so on for all enables and checked/unchecked states in your GUI]
}
... then anytime your program's internal state has changed in any way that might require an update to one or more buttons/checkboxes in the GUI, call this method explicitly, or set up a signal/slot connection that will call it for you.
The advantage of doing it this way is the simplicity -- with this approach, it's trivial to guarantee that your GUI widgets will be in updated to the expected state after any internal-state-change, because there is only one code-path to write and debug. The alternative (trying to come up with the correct transitional behavior for every possible state-change in your program) quickly leads to an intractable amount of complexity, and endless debugging and hair-pulling.
You might think the downside is inefficiency -- after all, we are updating all the buttons even though in any cases, only one of them may have changed -- but Qt's code is smart enough that calling setEnabled(false) on a button that is already disabled is a no-op (likewise calling setEnabled(true) on a button that is already enabled, and so on), so the heavyweight code of redrawing a widget's pixels will only be executed when the widget's state has actually changed.
The logic inside UpdateAllButtonStates() that calculates shouldButton1BeEnabled, etc, does get executed a lot, but it usually ends up being pretty trivial logic so that turns out not to be important. However, if for some reason that logic turns out to be expensive, you have the option of reducing the frequency at which UpdateAllButtonStates() gets executed, by using asynchronous execution and a boolean "dirty-bit", e.g.:
void MyWindow::ScheduleUpdateAllButtonStates() // Qt-slot method
{
if (_dirtyBit == false)
{
_dirtyBit = true;
QTimer::singleShot(0, this, SLOT(UpdateAllButtonStates()));
}
}
void MyWindow::UpdateAllButtonStates()
{
if (_dirtyBit == false) return;
_dirtyBit = false;
// Update button enables/checked states as previously, here
}
... then have all your internal-state-change code call ScheduleUpdateAllButtonStates() rather than calling UpdateAllButtonStates() directly; the advantage is that even if ScheduleUpdateAllButtonStates() gets called 500 times in a row, it will only result in UpdateAllButtonStates() getting called once, during the next iteration of Qt's event loop.
Enabling/disabling button UI logic can be very dirty and difficult to manage and trace. Also, sometimes we want to be in particular state and want to make a minor change like changing state of just one button. Here is an approach. It's generic but you will have to adrop it accordingly with your UI.
#include <iostream>
class UIState
{
protected:
bool btn1;
bool btn2;
bool btn3;
public:
UIState()
{
btn1 = false;
btn2 = false;
btn3 = false;
}
virtual void setBtn1State(bool new_state)
{
btn1 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
virtual void setBtn2State(bool new_state)
{
btn2 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
virtual void setBtn3State(bool new_state)
{
btn3 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
};
class UIStateAllEnabled : public UIState
{
public:
UIStateAllEnabled()
{
btn1 = true;
btn2 = true;
btn3 = true;
std::cout << btn1 << btn2 << btn3 << std::endl;
}
};
class UIStateAllDisabled : public UIState
{
public:
UIStateAllDisabled()
{
btn1 = false;
btn2 = false;
btn3 = false;
std::cout << btn1 << btn2 << btn3 << std::endl;
}
};
class UI
{
UIState * currentState;
public:
UI()
{
currentState = NULL;
}
~UI()
{
if (currentState != NULL)
{
delete currentState;
std::cout << "deleted current state" << std::endl;
}
}
void setState(UIState * new_state)
{
// should also check for if already current state?
UIState * prevState = currentState;
currentState = new_state;
if (prevState != NULL)
{
delete prevState;
std::cout << "deleted previous state" << std::endl;
}
}
void setBtn1State(bool new_state)
{
currentState->setBtn1State(new_state);
};
void setBtn2State(bool new_state)
{
currentState->setBtn2State(new_state);
};
void setBtn3State(bool new_state)
{
currentState->setBtn3State(new_state);
};
};
int main()
{
UI ui;
// enable all buttons
ui.setState(new UIStateAllEnabled);
// Now say you want to change state of a particular button within this state.
ui.setBtn1State(false);
ui.setBtn3State(false);
// switch to a completely new state, disable all buttons
ui.setState(new UIStateAllDisabled);
// customize within that sate
ui.setBtn3State(true);
return 0;
}
To resize items in a QGraphicsView, I'm putting child items representing vertices onto the item to be moved (using the parent-child relationship established in the constructor). Those are the four blue circles in the picture below:
But the child vertices are not receiving mouse events. Only the parent item (red square) is getting mouse events.
Here is the definition for Item:
Item::Item(QGraphicsItem * parent) :
QGraphicsItem(parent)
{
setFlag(ItemIsMovable);
setFlag(ItemIsSelectable);
setFlag(ItemSendsGeometryChanges);
setCacheMode(DeviceCoordinateCache);
}
void Item::paint(
QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->fillRect(option->rect,Qt::red);
}
QVariant Item::itemChange(GraphicsItemChange change, const QVariant & value)
{
switch(change)
{
case QGraphicsItem::ItemSelectedHasChanged:
qWarning() << "item: " + value.toString();
updateVertices(value.toBool());
break;
default:
break;
}
return QGraphicsItem::itemChange(change, value);
}
void Item::updateVertices(bool visible) {
if(visible) {
if(vertices.length() == 0) {
for(int i = 0; i < 4; i++)
vertices.append(new Vertice(this));
} else
for(int i = 0; i < 4; i++)
vertices[i]->setVisible(true);
QRectF rect = boundingRect();
vertices[0]->setPos(rect.topLeft());
vertices[1]->setPos(rect.topRight());
vertices[2]->setPos(rect.bottomLeft());
vertices[3]->setPos(rect.bottomRight());
} else {
for(int i = 0; i < 4; i++) {
p_vertices[i]->setVisible(false);
}
}
}
While here is the definition for Vertice:
Vertice::Vertice(QGraphicsItem * parent) :
QGraphicsItem(parent)
{
setFlag(ItemIsMovable);
setFlag(ItemIsSelectable);
setFlag(ItemSendsGeometryChanges);
}
void Vertice::paint(
QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setBrush(Qt::blue);
painter->setPen(Qt::darkGray);
painter->drawEllipse(-5,-5,10,10);
}
QVariant Vertice::itemChange(GraphicsItemChange change, const QVariant & value)
{
switch(change) {
case QGraphicsItem::ItemSelectedHasChanged:
qWarning() << "vertex: " + value.toString(); // never happened
break;
default:
break;
}
}
You say that your child items aren't getting mouse events, but they are. You can verify this by adding a void mousePressEvent(QGraphicsSceneMouseEvent * event) to Vertice and noticing that it is getting called.
Your problem is that Qt is ignoring the ItemIsMovable flag on a child QGraphicsItem. It's not even setting the flag when you ask.
You can verify this by changing your Vertice constructor:
Vertice::Vertice(QGraphicsItem * parent) :
QGraphicsItem(parent)
{
setFlag(ItemIsMovable);
Q_ASSERT(flags() & ItemIsMovable); // fails
setFlag(ItemIsSelectable);
setFlag(ItemSendsGeometryChanges);
}
Now why would that be? As the programming Jedi say: "use the source, Luke!"
https://qt.gitorious.org/qt/qtbase/source/7df3321f934e5bd618e2ad00bf801f2b7edd31df:src/widgets/graphicsview/qgraphicsitem.cpp#L1789
Notice that one of the things it does when flags are set is it offers that to itemChange to inspect with an ItemFlagsChange notification. Not only that, but it allows the flags to be overwritten by the result of that call. But look at your implementation of itemChange() on Vertice:
QVariant Vertice::itemChange(GraphicsItemChange change, const QVariant & value)
{
switch(change) {
case QGraphicsItem::ItemSelectedHasChanged:
qWarning() << "vertex: " + value.toString(); // never happened
break;
default:
break;
}
}
Uh-oh. No return result! Add this line to the end, as you have in your Item:
return QGraphicsItem::itemChange(change, value);
...and there you have it. Other notes:
Singular of "Vertices" is actually "Vertex"
If you have a case like this, think about paring it down from whatever specific program you are writing. If you can demonstrate the problem with one child item and one parent item, then why have a loop making four? If selection isn't part of the problem--and code for hiding and showing vertices need not be involved--then why involve it? It would be much better to use the code you provide to give required virtual methods like boundingRect() rather than make others write it to test. See Short, Self-Contained, Compilable Example
Qt source is fairly readable and well-organized, so do get into the habit of looking at it...!
I have a QTreeWidget in which each of its items has a QComboBox in a column. I have connected it to a slot with a QSignalMapper, and I'm successfully retrieving both the item and the index in the combobox when it is triggered. I did it like this:
foreach(Workplace *wp, allWorkplaces){
QTreeWidgetItem *workplaceItem = new QTreeWidgetItem;
workplaceItem->setText(0, wp->workplaceName());
workplaceItem->setText(1, wp->workplaceDescription());
myWorkplaceUi->treeWidget->addTopLevelItem(workplaceItem);
QComboBox *combo = new QComboBox();
combo->addItems(allShiftModels);
combo->setAutoFillBackground(true);
ShiftModel *shiftModel = qobject_cast<ShiftModel *>(wp->usedShiftModel);
myWorkplaceUi->treeWidget->setItemWidget(workplaceItem,2, combo);
if(shiftModel && !shiftModel->shiftModelName().isEmpty()){
qDebug()<<"after the cast: "<< shiftModel->shiftModelName();
combo->setCurrentIndex(combo->findText(shiftModel->shiftModelName(), Qt::MatchExactly));
}else{
combo->setCurrentIndex(combo->findText("None", Qt::MatchExactly));
}
connect(combo, SIGNAL(currentIndexChanged(int)), signalMapper, SLOT(map()));
signalMapper->setMapping(combo, QString("%1").arg(wp->workplaceName()));
}
connect(signalMapper, SIGNAL(mapped(const QString &)),this, SLOT(changed(const QString &)));
My objective is, after retrieving both the Workplace and the ShiftModel, to update them in the instances of my already created Workplaces. So, basically, I try to find the Workplace and the ShiftModel that were selected, because depending on the ShiftModel selected, I will change a pointer to the ShiftModel in the Workplace class:
class Workplace : public QObject
{
Q_OBJECT
public:
(...)
ShiftModel *usedShiftModel;
(...)
}
And the changed slot:
void workplacesdialog::changed(QString position){
QList<Workplace* > allWorkplaces = this->myProject->listMyWorkplaces();
QList<ShiftModel*> allShiftModels = this->myProject->myFactory->listShiftModels();
foreach(Workplace* workplace, allWorkplaces){
foreach(ShiftModel *shiftmodel, allShiftModels){
qDebug() <<"workplace:"<< workplace->workplaceName();
qDebug() <<"shiftmodel:"<< shiftmodel->shiftModelName();
QString wp = position;
QTreeWidgetItem* item=(QTreeWidgetItem*)myWorkplaceUi->treeWidget->findItems(wp,Qt::MatchExactly,0).at(0);
QComboBox *combo = (QComboBox*)myWorkplaceUi->treeWidget->itemWidget(item,2);
if(combo && item){
QString sm = combo->currentText();
qDebug() << "selected shiftmodel "<< sm << " on workplace "<< wp;
if(workplace->workplaceName()==wp && shiftmodel->shiftModelName()==sm){
workplace->usedShiftModel = shiftmodel;
break;
}
else{
workplace->usedShiftModel = 0;
return;
}
}else{
qDebug() << "cast failed!";
return;
}
}
}
}
So, my problem with this is, when I click one of the comboboxes, successfully retrieve both the item and index selected, but then, when I try to traverse them with the two foreach loops in the slot, it does not work as I expected. I hoped that every time I clicked on an index in one of the comboboxes, this would be called, and it is. Although, for some reason, the method I'm using to match what the user selected with what was already instatiated doesn't work.
Also, it looks like it only hits both the 1st workplace on the allWorkplaces list as well as the 1st shiftmodel on the ShiftModels list, and this is my problem.
If anyone knows how to fix this or has any ideas to share, please let me know. Thank you.
The problem is this:
if(workplace->workplaceName()==wp && shiftmodel->shiftModelName()==sm){
workplace->usedShiftModel = shiftmodel;
break;
}
else{
workplace->usedShiftModel = 0;
return;
}
If either the workplace name does not match, or the shift model name does not match, the relation between the work place and its currently linked shift model is removed and your function returns.
I could restructure the two for-loops for you, but there is an easier and less error-prone way:
Note: I marked some code paths with "TODO" which I skipped due to lack of time. You should be able to figure them out yourself though.
// Set up hashes for quick lookup
QHash< QString, Workplace* > workplaceHash;
QList<Workplace* > allWorkplaces = this->myProject->listMyWorkplaces();
foreach( Workplace* workplace, allWorkplaces )
{
workplaceHash.insert( workplace, workplace->workplaceName() );
}
// TODO: Do a similar thing for the shift models here
// Find the selected workplace
if( !workplaceHash.contains( position ) )
{
// TODO: Error handling (An unknown/No workplace was selected)
return;
}
// else: A valid workplace was selected
Workplace* selectedWorkplace = workplaceHash.value( position );
// TODO: Retrieve the name of the shift model (stored in variable sm)
// Find the selected shiftmodel
if( !shiftplaceHash.contains( sm ) )
{
// No shift model was selected
selectedWorkplace->usedShiftModel= 0;
return;
}
// Else: Both work place and shift model were selected
Shiftplace* selectedShiftModel = shiftplaceHash.value( sm );
selectedWorkplace->usedShiftModel = selectedShiftModel;
A few ideas for refactoring:
You could maybe do the creation of the hashes outside of this method and store them in member variables. Just make sure that the hash is always updated when a workplace is added or removed.
You could make spotting errors easier by extracting parts of the code into separate methods, e.g. QString getSelectedShiftModelName() etc.
So, In the end I figured out my loops were really messed up... This is working now:
void workplacesdialog::changed(QString position){
QList<Workplace* > allWorkplaces = this->myProject->listMyWorkplaces();
QList<ShiftModel*> allShiftModels = this->myProject->myFactory->listShiftModels();
qDebug() << allWorkplaces.size() << " workplaces";
qDebug() << allShiftModels.size() << " ShiftModels";
QString wp = position;
QString sm;
QTreeWidgetItem* item=(QTreeWidgetItem*)myWorkplaceUi->treeWidget->findItems(wp,Qt::MatchExactly,0).at(0);
QComboBox *combo = (QComboBox*)myWorkplaceUi->treeWidget->itemWidget(item,2);
if(combo && item){
sm = combo->currentText();
qDebug() << "selected shiftmodel "<< sm << " on workplace "<< wp;
}else{
qDebug() << "cast failed!";
return;
}
foreach(Workplace* workplace, allWorkplaces){
foreach(ShiftModel *shiftmodel, allShiftModels){
qDebug() <<"workplace:"<< workplace->workplaceName();
qDebug() <<"shiftmodel:"<< shiftmodel->shiftModelName();
if(workplace->workplaceName()==wp && shiftmodel->shiftModelName()==sm){
qDebug() << "found match!: "<< wp << " >>>>> " << sm;
workplace->usedShiftModel = shiftmodel;
return;
}else if(workplace->workplaceName()==wp && sm=="None"){
qDebug() << "clear match: "<< wp << " >>>>> " << sm;
workplace->usedShiftModel = 0;
return;
}
}
}
}
I have following strange problem.
I've implemented a QAbstractItemModel to the point that I can insert child nodes to the tree view but something strange occurs when I try to add the nodes via the insertRows() method.
First where all is called:
QApplication a(argc, argv);
QResource::registerResource("Qt5Tutorial.rcc");
QTreeView *treeView = new QTreeView();
treeView->show();
Node rootNode("rootNode");
CameraNode childNode0("childNode0", &rootNode);
CameraNode childNode1("childNode1", &rootNode);
LightNode childNode2("childNode2", &rootNode);
CameraNode childNode3("childNode3", &childNode0);
TransformNode childNode4("childNode4", &childNode2);
TransformNode tryNode("potato");
// setup model
ObjectTreeModel model(&rootNode);
treeView->setModel(&model);
// insert directly via the insert child method
// this works!
childNode0.insertChild(1, &tryNode);
// get the QModelIndex of childNode1
// must be passed in the insertRows() method
QModelIndex index(model.index(1, 0, QModelIndex()));
// the output is "childNode1" what is totally right
qDebug() << "index: "<<static_cast<Node*>(index.internalPointer())->getName();
// output see posted beneath
qDebug() << rootNode.log();
// should insert in "childNode1" -> at 0th position and just 1 Node object
// see the method beneath
model.insertRows(0, 1, index);
// if i try to call the method rootNode.log(); now again, it crashes
return a.exec();
This is the output from the rootNode.log() call:
---rootNode
---childNode0
---childNode3
---potato
---childNode1
---childNode2
---childNode4
As you can see the "Potato" Node is correctly inserted.
View an image
http://www10.pic-upload.de/04.01.13/m65huuqq4ruu.png
But once I try to expand the childNode1 node it crashes. But look at the last comment in the code above. As i mentioned -> if i try to output the tree view now (it iterates through all nodes) it crashes.
When the method is called everything seems to be ok - just when i try to expend the tree view it crashes -> the debug output let me think that all should be ok
The actual error message is a access violation when reading at position ... (translated from German - don't know if its called the same in English)
bool ObjectTreeModel::insertRows(int position, int row, const QModelIndex &parent)
{
beginInsertRows(parent, position, position + row - 1);
Node *parentNode = getNode(parent);
qDebug() << "parentName: " << parentNode->getName();
bool success = false;
for(int i = position; i < row; i++)
{
qDebug() << "inside loop";
qDebug() << "position: " << position << "row: " << row;
TransformNode childNode("insertedNode");
success = parentNode->insertChild(i, &childNode);
qDebug() << "success: " << success;
}
endInsertRows();
return success;
}
The debug output for the method above:
getNode: successful
parentName: "childNode1"
inside loop
position: 0 row: 1
called inserchild
success: true
I have no idea why this happens becuase the debug output seems right and it should be basically the same as insert the node directly via the insertChild method.
I hope that someone has an idea why it doesn't work.
Best regards, Michael
Almost everything is correct. Just this two lines not:
TransformNode *childNode = new TransformNode("insertedNode");
success = parentNode->insertChild(i, childNode);