Add a node to TTreeView in C++ Builder - c++

It is a very simple question that I have to ask, but I couldn't find the answer anywhere.
I'm using C++ Builder XE6 and I want to use a TTreeView. I have found several tutorials about it, saying that the method to add a node is to do this :
TreeView->Items->Add(NULL, "name");
But it doesn't work, I get the error that Add() is not a member of Items. After a quick research, I have found that Add() is a method for TTreeNodes, but TreeView->Items is a TTreeViewItem. Maybe all the tutorials that I have read are outdated. Anyway, I can't find any way to do it.
Thank you for your help.

TTreeViewItem is a FireMonkey class, not a VCL class. All of the tutorials you have read are likely based on VCL.
In VCL, TTreeView::Items as a TTreeNodes object:
__property TTreeNodes* Items = {read=FTreeNodes, write=SetTreeNodes};
TTreeNodes does have an Add() method:
TTreeNode* __fastcall Add(TTreeNode* Sibling, const System::String S);
The code you showed works fine in VCL.
In FireMonkey, TTreeView::Items is an indexed array of TTreeViewItem objects:
__property TTreeViewItem* Items[int Index] = {read=GetTreeItem};
TTreeViewItem does not have an Add() method. The correct way to add a new node to a FireMonkey TTreeView is to create a TTreeViewItem object and set its Parent property, eg:
TTreeViewItem *node = new TTreeViewItem(TreeView);
node->Text = "name";
node->Parent = TreeView;

You need to call TreeView->Items->AddChild(NULL, "name"); - This will add a child node of root (NULL). If you need to add a child of a specific node then you need to pass the node as parameter.
According to the docs, and a quick check in the hpp file, Items is a TTreeNodes so Add and AddChild should work. Are you sure you're not accessing, for instance, Items[0] ?

Related

add a QListWidgetItem to a QListWidget using a std::shared_ptr to fix fortify issue

Fortify doesn't like QListWidget::addItem(new QListWidgetItem) and reports a false memory leak, even though QT manages the memory properly.
I'm trying to figure out a work-around.
I was told to use a std::shared_ptr, but I haven't figured out the syntax yet.
Here's what I've got so far, but it reports an error about the type.
These 2 lines of code are all I need to fix, there is no further context. Just looking for the syntax for a shared pointer to QListWidgetItem, adding the item to the list widget with addItem().
Any syntax that works is fine. MUST create a QListWidgetItem and THEN add it. Cannot use additem("string") syntax.
In a header file, declare member variable item:
...
class Class1{
...
std::shared_ptr<QListWidgetItem> item;
...
};
In a source file:
...
Class1::ClassFunction1()
{
std::make_shared<QListWidgetItem> item("AStringToAdd");
ui->qlw->addItem(item);
}
As per my comment you might be able to utilize std::unique_ptr to silence fortify...
Class1::ClassFunction1 ()
{
auto item = std::make_unique<QListWidgetItem>("AStringToAdd");
/*
* Use std::unique_ptr::release() to transfer ownership of the
* QListWidgetItem to the QListWidget.
*/
ui->qlw->addItem(item.release());
}
The solution provided in the answer by #hyde is certainly the more robust. Having said that the original post is essentially seeking ways of trying to fix a problem with the fortify tool. So the real solution is "fix the tool" or find other, better analysis tools.
This might do the trick, based on code you show in your question:
class Class1{
...
std::unique_ptr<QListWidgetItem> item; // no need to use shared ptr
std::unique_ptr<...whatever you need here...> ui; // change ui to unique_ptr and put it after the item!
// remember to change construction of `ui` accordingly, and remove deleting it in destructor
...
};
Class1::ClassFunction1()
{
// reset member variable, don't create a new local variable
item.reset(new QListWidgetItem>("AStringToAdd"));
ui->qlw->addItem(item.get()); // pass naked pointer
}
That way, item will go out of scope before ui, and will be deleted by the unique_ptr. When the item is deleted, it will notify the view, and view will remove the item.
If you do it the other way around, view will delete the item, but it has no way to notify the unique_ptr. Therefore unique_ptr will delete it again, resulting in Undefined Behavior, with luck just a crash.

How to get the currently selected text in a CComboBoxEx?

My first approach to the problem was to call the GetWindowsText method on the CComboBoxEx control, but I found that there is no associated text. After analyzing the control with Spy++ and reading some documentation on CComboBoxEx, I realised that these type of controls are only the parent of a classic ComboBox:
I tried using the GetLBText() method on the child ComboBox, passing GetCurSel() as an argument, but I only get some wrong text (the correct text should be "English"):
Am I missing something? Thanks in advance!
What you want to do is map the control to a int variable using Class Wizard:
Now it is easy to access the selected text at any time. You need to use the GetItem function. For example (code not tested):
COMBOBOXEXITEM cmbItem;
CString strText;
cmbItem.mask = CBEIF_TEXT;
cmbItem.iItem = m_cbItemIndex;
cmbItem.pszText = strText.GetBuffer(_MAX_PATH);
m_cbMyCombo.GetItem(&cmbItem);
strText.ReleaseBuffer();
In short, you need to use the COMBOBOXEXITEM and initialise it with the right flags to state what information you want to get from the extended combo. That, and the item index. Job done!
I realise that you have your own inherited class, but the mechanics are the same. You don't use GetLBText. You use the structure with the index and GetItem to get the selected text.
In the end I managed to retrieve the correct name; as you can see in the image below, the ComboBox is only a child of a CombBoxEx32:
I retrieved the pointer to the parent ComboBoxEx32 from the child ComboBox, and searched for the text this way:
CString szText;
CComboBoxEx cbParentCombo ;
cbParentCombo.Attach( GetParent()->GetSafeHwnd()) ;
cbParentCombo.GetLBText( GetCurSel(), szText) ;
cbParentCombo.Detach() ;
My mistake was that I was calling GetLBText() directly from the child ComboBox, instead of the parent CComboBoxEx; because of that, all I was getting was some random gibberish. GetLBText() was indeed the correct solution.

Replace QWidget with a new QWidget

This questions to me reeks of maybe a lack of understanding of C++, as the possibilities I've considered for my problem all seem to make no sense on why this could be occuring. Feedback appreciated.
I'm using the form designer to create a form class with a table in it. I'm trying to replace the table with another table generated in a helper class. I'm only doing this so I can (hopefully) maintain the nice grid layout I've designed, and through pointer manipulation, get the replacement I desire. Here's some code snippets from the table form constructor and relevant calls :
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
....
setup();
void setup(){
tableData = Utilities::createTable(this->file, tableDelim);
//createTable returns QTableWidget*
... other assignments, and label text updates, which seem to all work
}
My understanding is that tableData is a pointer, and if printed, will give the address of the QTableWidget from the layout. So then if I create a QTableWidget* and then assign tableData to that, tableData should now point to the new widget. Instead, I see only a blank screen.
I tried checking what the tableData pointer is before I assign it to the new QTableWidget*, and after. The second pointer shown is what is generated by createTable() :
QTableWidget(0x101272d40, name = "tableData") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
It seems the pointer is being reassigned, but the table drawn isn't the right one.
What gives?
My understanding is that you want to design the table layout in designer but fill in the data from an external source.
I would suggest, to just use the QTableWidget that is created in setupUi() and modify Utilities::createTable() such that it becomes Utilities::populateTable(QTableWidget & table, <all the other parameters you need>). (Or use QTableWidget * if you prefer - however I like putting the non-zero assertion responsibility on the caller...)
Apart from that, I agree with Sebastian Lange.
You are right with your assumption. You do set a variable to be a pointer to a object and next you set the variable to be a pointer to another object. You never change any objects, just your variable which is not used to display anything.
You would need to do something like:
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
parentLayout = tableData->parent()->layout(); //Get the parent widget to add another table.
parentLayout->removeWidget(tableData);
delete tableData;
parentLayout->addWidget(createTable());
You need to use pTheContainerOfTheOriginalTableWidget->addWidget(tableData); See here: http://qt-project.org/forums/viewthread/16547
Be sure you remove the original tableWidget so you don't have two (I assume you don't want two).
If I understand you correctly we have such situation.
call of setupUi (which generated by qt tootls),
there there is something like this(pseudo code):
oldTablePtr = new QTableWidget(parent);
someLayout->addWidget(oldTablePtr);
So parent and layout hold value of oldTablePtr.
And if you set variable oldTablePtr nothing changed.
parent send QPaintEvent to oldTablePtr.
So you need call delete oldTablePtr, that remove this widget from list of childs of parent, and move newTablePtr to the same layout.
There's no need to replace it in code, you can do it in Qt Designer. Just place QTableWidget on form, then rightclick it and choose Promote widget in menu, then you will need just enter your classname.
Currently I don't have Qt Designer near me, so edits will be appreciated.

How do I append elements with duplicate names using MSXML & C++?

I am write some code to update a XML DOM using MSXML4 & C++. I need a method that appends a child element to a parent element. The code I have written below works until the title of the child matches the title of another child under the parent. I cannot change the title of the children so I need to find a way to append them to the parent.
Can anyone provide some guidance?
// this call creates '<parent><child/></parent>'
AppendChild("/root/parent", "child");
// this call attempts to create '<parent><child/><child/></parent>' but the DOM remains unchanged ('<parent><child/></parent>')
AppendChild("/root/parent", "child");
void AppendChild(const std::string kPathOfParent, const std::string kNameOfChild)
{
MSXML2::IXMLDOMNodePtr pElement = m_pXmlDoc->createNode(NODE_ELEMENT, kNameOfChild.c_str(), m_xmlns.c_str());
MSXML2::IXMLDOMNodePtr pParent = m_pXmlDoc->selectSingleNode(kPathOfParent.c_str());
MSXML2::IXMLDOMNodePtr pNewChild = pParent->appendChild(pElement);
}
I am not sure exactly what the problem was, but somewhere my binaries were out of step. I rebuilt the entire project via 'Clean Solution' instead of just the 'Build Solution' option. Now both children are created using the code above. It is not clear to me why I was able to step in to the code via the debugger, but the second child was never created until I cleaned the solution.
Jeff & Remy, thank-you for your comments.

Is it possible to enumerate the wxFrame children in wxWidgets?

I'm using the wxGlade designer to generate the GUI for a small application.
It generates a class, inherited from wxFrame, which is the main application window.
In order to facilitate the maintenance, I'd like to avoid writing additional code in this generated class.
But all the widgets created with the wxGlade are actually created in the auto-generated method do_layout() and it is not possible to access them outside the scope of that generated method in the generated class.
Is there a way to get pointer of certain widget outside that generated class - by name, by type, by enumerating the children or something like that?
All classes inherited from wxWindow (wxFrame being one of them) have a function "GetChildren", which returns a list of child windows that you can then enumerate over. If you are looking for a specific field by name then use the "FindWindow" function.
Actually I found the answer myself:
wxWindowList & children = myframe->GetChildren();
for ( wxWindowList::Node *node = children.GetFirst(); node; node = node->GetNext() )
{
wxWindow *current = (wxWindow *)node->GetData();
// .. do something with current
}
May I recommend you try wxFormBuilder. I also used wxGlade before, but it presents too much constraints on how you use it. For example, with wxFormBuilder you can select 'visibility' (public,protected,private) for each control on the form. It can also generate virtual functions for event handlers, so you just derive your class from wxFormBuilder generated class and implement those functions.