How to make a subchild to a child in QTreeWidget? - c++

I want to make it so that I can expand a third level (subchild) to a child under the top level item (root). All I've been able to do is make multiple children to a single root.
this is in my .cpp
QStringList string1, string2;
string1 << "xxxxxxxx" << "xxxxxxxxxxx";
string2 << "yyyyyy" << "yy";
m_treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(string1));
m_treeWidget->insertTopLevelItem(1, new QTreeWidgetItem(string2));
//here I add a child
AddChild(m_treeWidget->topLevelItem(0),"hello","world", m_treeWidget);
//here I make two attempts to make a sub child
AddChild(m_treeWidget->itemBelow(m_treeWidget->topLevelItem(0)),"hello_sub1","world_sub1", m_treeWidget);
AddChild(m_treeWidget->itemAt(0,0),"hello_sub2","world_sub2", m_treeWidget);
The following is my Add Child Method also in the same .cpp file:
void Dialog::AddChild (QTreeWidgetItem *parent, QString name, QString Description, QTreeWidget* treeWidget)
{
QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
item->setText(0,name);
item->setText(1, Description);
parent->addChild(item);
}

In order to make a tree hierarchy you can use the QTreeWidgetItem's API, especially its constructors. Constructors can accept either QTreeWidget or QTreeWidgetItem as a parent object. In the first case, the top level item will be added to the tree widget and in the second case - child item of another item. This API is easier to use because you don't need to explicitly append items to the tree widget. Here is the sample code that implements the idea:
QStringList string1, string2;
string1 << "xxxxxxxx" << "xxxxxxxxxxx";
string2 << "yyyyyy" << "yy";
QTreeWidget tv;
// The top level items
QTreeWidgetItem *top1 = new QTreeWidgetItem(&tv, string1);
QTreeWidgetItem *top2 = new QTreeWidgetItem(&tv, string2);
// A child item.
QTreeWidgetItem *child1 =
new QTreeWidgetItem(top1, QStringList() << "Hello" << "World");
// The grandchildren.
new QTreeWidgetItem(child1, QStringList() << "Hello_sub1" << "World_sub1");
new QTreeWidgetItem(child1, QStringList() << "Hello_sub2" << "World_sub2");

Actually I was able to solve it another way...
in the .cpp:
//Initialize the QTreeWidget with 2 columns
QTreeWidget m_treeWidget = new QTreeWidget();
m_treeWidget->setColumnCount(2);
//these are the method calls:
AddRoot("Root1_Column1", "Root2_Column2", m_treeWidget);
AddRoot("Root2_Column1", "Root2_Column2", m_treeWidget);
//topLevelItem(0) makes it a child of the first root... topLevelItem(1) makes it a child of the second root
AddChild(m_treeWidget->topLevelItem(0),"Child1_Column1","Child1_Column2");
AddChild(m_treeWidget->topLevelItem(1),"Child2_Column1","Child2_Column2");
AddSubChild(m_treeWidget->itemBelow(m_treeWidget->topLevelItem(0)),"SubChild_Column1", "SubChild_Column2");
With these being the methods I used within the same .cpp file:
void Dialog::AddRoot (QString name, QString Description, QTreeWidget* treeWidget)
{
QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
item->setText(0,name);
item->setText(1,Description);
item->setExpanded(true); //expand automatically
treeWidget->addTopLevelItem(item);
}
void Dialog::AddChild (QTreeWidgetItem *parent, QString name, QString Description)
{
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText(0,name);
item->setText(1, Description);
parent->addChild(item);
}
void Dialog::AddSubChild (QTreeWidgetItem *parent, QString name, QString Description)
{
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText(0,name);
item->setText(1, Description);
parent->addChild(item);
}

Related

Why can't I add or remove a QListWidgetItem?

I have two ListWidget at my ui and I want to move one QListWidgetItem from availableMeasurementsListWidget to selectedMeasurementListWidget
But this won't work for me. Nothing adds into selectedMeasurementListWidget and the item does not removes from availableMeasurementsListWidget. Why?
That only who works is displaying the text of the qDebug() << item->text();
void ChartSettingsWindow::on_availableMeasurementsListWidget_doubleClicked(const QModelIndex &index)
{
Q_UNUSED(index);
QListWidgetItem *item = ui->availableMeasurementsListWidget->currentItem();
qDebug() << item->text();
ui->selectedMeasurementListWidget->addItem(item);
ui->availableMeasurementsListWidget->removeItemWidget(item);
}
Note that QListWidget:: removeItemWidget doesn't remove the QListWidgetItem from the QListWidget: it only...
Removes the widget set on the given item.
To remove an item (row) from the list entirely, either delete the item
or use takeItem().
So you probably want something like...
auto *available = ui->availableMeasurementsListWidget;
auto *selected = ui->selectedMeasurementListWidget;
auto *item = available->currentItem();
selected->addItem(available->takeItem(available->indexFromItem(item).row()));

QT5 C++, Is there a way I can get the current text of a widget within a qlist container

I need to retrieve the text in the order in which they appear on the user form. I am trying as below:
QString line = "QLineEdit";
QString combo = "QComboBox";
QList<QWidget *> childWidgets = ui->frame_3->findChildren<QWidget *>();
QStringList data;
for(auto widget : childWidgets){
if(widget->metaObject()->className() == line || widget->metaObject()->className() == combo){
data.append(widget->text()); //append the text of the lineEdits and ComboBoxes to data
}
}
I get the following compile error from the above code:
"no member named 'text' in QWidget
Since you pointed out the QWidget base class does not have a text member function you will need to access the QComboBox and QLineEdit directly to get the current text.
QList<QWidget *> childWidgets = ui->frame_3->findChildren<QWidget *>();
QStringList data;
for(auto widget : childWidgets){
auto combo = dynamic_cast<QComboBox*>(widget);
if (combo) {
data << combo->currentText(); // currentText() returns the text from the combobox
}
else {
auto lineEdit = dynamic_cast<QLineEdit*>(widget);
if (lineEdit) {
data << lineEdit->text(); // A line edit has a text() member.
}
}
}
This code does not handle ordering. I believe the order is in the same order as added to the parent.

QTableWidget and QLineEdit - position and text content

I'm having a hard time figuring out how to get the position(column and row) and the content in the QLineEdit. I'm using a eventFilter to get the signal but from there i'm stuck. any advice? Thank you
ui->tableWidget->setRowCount(5);
ui->tableWidget->setColumnCount(5);
QStringList wordList;
wordList << "alpha" << "omega" << "omega2" << "omega3" <<"omicron" << "zeta";
for(int i = 0; i<5;i++)
{
QLineEdit *lineEdit = new QLineEdit;
QCompleter *completer = new QCompleter(wordList);
completer->setCaseSensitivity(Qt::CaseInsensitive);
lineEdit->installEventFilter(this);
lineEdit->setCompleter(completer);
ui->tableWidget->setCellWidget(i,i,lineEdit);
}
....
bool MainWindow::eventFilter(QObject * object, QEvent *event)
{
}
I would like to get the position when I finish editing. I would like to pick a word from the list either through up and down key or left mouse click. Once a word is picked that word would populate the QLineEdit. Then i would want to know the position. Now, if the user writes a text different from the content of the list then no position should be returned. I'm only interested on whats in the "wordList". Thank you
As you indicate in your comments, you only want to obtain the text when an element that is set in the QCompleter is selected, for this we must use the void QCompleter::activated(const QString & text) signal.
To do this, a slot is created and the connection is made:
*.h
private slots:
void onActivated(const QString &text);
*.cpp
QCompleter *completer = new QCompleter(wordList);
...
connect(completer, qOverload<const QString &>(&QCompleter::activated), this, &MainWindow::onActivated);
There are 2 possible solutions:
The first to use the position of the QLineEdit that we obtain through the widget() method of the QCompleter, and the QCompleter we obtain it through sender() which is the object that emits the signal and pos(). then we get the QModelIndex with indexAt(), and this has the information of the row and column:
void MainWindow::onActivated(const QString &text)
{
QCompleter *completer = static_cast<QCompleter *>(sender());
QModelIndex ix = ui->tableWidget->indexAt(completer->widget()->pos());
if(ix.isValid()){
qDebug()<<ix.row()<<ix.column()<<text;
}
}
Or the row and column is saved as a property:
QCompleter *completer = new QCompleter(wordList);
...
completer->setProperty("row", i);
completer->setProperty("column", i);
void MainWindow::onActivated(const QString &text)
{
QCompleter *completer = static_cast<QCompleter *>(sender());
qDebug()<< completer->property("row").toInt()<<completer->property("column").toInt()<<text;
}
In the following link you can find both complete examples

Getting variable from widget in a QListWidget

I have a custom QWidget class called VideoWidget. Its source file looks something like this:
VideoWidget::VideoWidget(QWidget *parent, string test) :
QWidget(parent)
{
pathname=test;
QLabel *label= new QLabel(pathname.c_str(), this);
//...
}
string VideoWidget::getFilePath(){
return pathname;
}
In my MainWindow class I add the VideoWidget to a QListWidget through looping through a xml file and getting the string argument from that file like this:
QDomNode node = rootXML.firstChild();
while( !node.isNull() )
{
if( node.isElement() )
{
QDomElement element = node.toElement();
VideoWidget* mytest = new VideoWidget(this, element.attribute( "Pathname", "not set").toStdString());
QListWidgetItem* item = new QListWidgetItem;
item->setSizeHint(QSize(150,100));
ui->myList->addItem(item);
ui->myList->setItemWidget(item,mytest);
}
node = node.nextSibling();
}
This correctly fills my QListWidget with the VideoWidget where all the labels have a different value.
Now I'd like to get the pathname variable everytime I doubleclick on a item in the QListWidget like this:
connect(ui->myList,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(playClip(QModelIndex)));
void MainWindow::playClip(QModelIndex index){
QListWidgetItem* item = ui->myList->itemAt(0,index.row());
VideoWidget* widget = dynamic_cast<VideoWidget*>(ui->myList->itemWidget(item));
cout << widget->getFilePath() << endl;
}
My problem is that widget->getFilePath() always returns the same value for every clicked widget. It is the value of the first time I set pathname=test;. What am I missing here?
This is probably mistake:
QListWidgetItem* item = ui->myList->itemAt(0,index.row());
Method "itemAt" takes x and y coordinates, not indexes. Use "takeItem" instead.
Next thing I want to say is that this part:
ui->myList->itemWidget(item)
is useless. You can convert "item" directly.
And last - use qobject_cast since you use Qt. And never use dynamic_case (especially when you anyway do not check result against NULL).

sort qtreewidget toplevel item base on a child data

i have a qtreewidget with toplevelitems. each toplevelitem has 4 childeren, each child has special value, first child of all toplevelitems is its parrent cost, i want to sort this toplevelitems base on this cost, but i don't know how to do this? my idea is to keep this toplevelitems and their cost in a map and add and take them each time a toplevelitem is added, but i'm looking for a better way.
thanks in advance.
By default, tree widget sorts items according to their texts, however you can change it by overriding the operator<() of the QTreeWidgetItem. Below is the example of custom QTreeWidgetItem with specific operator (see comments):
class TreeWidgetItem : public QTreeWidgetItem
{
public:
// The constructors. Add more, if needed.
TreeWidgetItem(QTreeWidget *parent, const QStringList &strings,
int type = Type)
: QTreeWidgetItem(parent, strings, type)
{}
TreeWidgetItem(QTreeWidgetItem *parent, const QStringList &strings,
int type = Type)
: QTreeWidgetItem(parent, strings, type)
{}
// Compares two tree widget items. The logic can be changed.
bool operator<(const QTreeWidgetItem& other) const
{
// Get the price - the first child node
int price1 = 0;
if (childCount() > 0)
{
QTreeWidgetItem *firstChild = child(0);
price1 = firstChild->text(0).toInt();
}
// Get the second price - the first child node
int price2 = 0;
if (other.childCount() > 0)
{
QTreeWidgetItem *firstChild = other.child(0);
price2 = firstChild->text(0).toInt();
}
// Compare two prices.
return price1 < price2;
}
};
And here is how this class can be used with QTreeWidget:
// The sortable tree widget.
QTreeWidget tw;
tw.setSortingEnabled(true);
QTreeWidgetItem *item1 = new TreeWidgetItem(&tw, QStringList() << "Item1");
QTreeWidgetItem *child1 = new TreeWidgetItem(item1, QStringList() << "10");
QTreeWidgetItem *item2 = new TreeWidgetItem(&tw, QStringList() << "Item2");
QTreeWidgetItem *child2 = new TreeWidgetItem(item2, QStringList() << "11");
tw.show();