Adding multiple QTreeWidgetItems - c++

Im trying to build a QTreeWidget that has multiple QTreeWidgetItems, i tried to add some of them manually and it works. My question is how can i add the items using a for or a while loop.
here is a part of my code
Dwidget= new QDockWidget(this);
Dwidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
treeWidget= new QTreeWidget(Dwidget);
Titem= new QTreeWidgetItem(treeWidget);
Titem1= new QTreeWidgetItem();
Titem2= new QTreeWidgetItem();
Titem3= new QTreeWidgetItem();
Titem->setText(0,"WriterIdenSystem");
Titem->setIcon(0,*(new QIcon("D:/Users/200656336/Documents/Writer Identification/data_repository_icon.jpg")));
Titem1->setText(0,"Database for Writer Identification");
Titem1->setIcon(0,*(new QIcon("D:/Users/200656336/Documents/Writer Identification/card_file.png")));
Titem2->setText(0,"0001");
Titem2->setIcon(0,*(new QIcon("D:/Users/200656336/Documents/Writer Identification/Folder Open.png")));
Titem3->setText(0,"0002");
Titem3->setIcon(0,*(new QIcon("D:/Users/200656336/Documents/Writer Identification/Folder Open.png")));
Titem->addChild(Titem1);
Titem1->addChild(Titem2);
Titem1->addChild(Titem3);
treeWidget->addTopLevelItem(Titem);
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(on_actionRetrieve_Documents_triggered()));
Dwidget->setWidget(treeWidget);
addDockWidget(Qt::LeftDockWidgetArea,Dwidget);
Dwidget->show();
any ideas?? :)

According to your code, could could do something like this.
QTreeWidgetItem* items[ITEM_COUNT]; // Must be multiple of 3
QTreeWidget* treeWidget = new QTreeWidget;
if(!treeWidget){ /* operating system out of memory, handle the error */ }
for(int i=0;i<=(ITEM_COUNT-3);i+=3)
{
items[i ] = new QTreeWidgetItem(treeWidget);
if(!items[i]){ /* operating system out of memory, handle the error */ }
items[i+1] = new QTreeWidgetItem(treeWidget);
items[i+2] = new QTreeWidgetItem(treeWidget);
/* set text here */
items[i ]->addChild(items[i]);
items[i+1]->addChild(items[i+1);
items[i+1]->addChild(items[i+2);
treeWidget->addTopLevelItem(items[i]);
}

Related

qt treewidget widget item QCheckBox alignment

I have a QTreeWidget where I insert different widgets (QDoubleSpinBox,QSpinBox,QCheckBox...)
QTreeWidget *t = ui->treeWidget;
QTreeWidgetItem *item = new QTreeWidgetItem();
int c = 0;
QDoubleSpinBox *dspb = new QDoubleSpinBox();
t->setItemWidget(item, c++, dspb);
QSpinBox *spb = new QSpinBox();
t->setItemWidget(item, c++, spb);
QCheckBox *cb = new QCheckBox();
t->setItemWidget(item, c++, cb);
t->addTopLevelItem(item);
However, the cb widget looks wired since the checkbox is aligned to the left. I would like to see it aligned in the center.
Q: How can I change the checkbox to appear in the middle of the TreeWidget cell?
I need to be able to access the cb item again later. Currently, I use the following code:
QTreeWidgetItem *itm = t->topLevelItem(0);
bool checked = qobject_cast<QCheckBox *>(t->itemWidget(itm,c++))->checkState() == Qt::Checked;
If I need to do some workaround to get the central alignment going, how can I access the cb object then?
Found it:
cb->setStyleSheet("margin-left:50%; margin-right:50%;");
works!

Crash while calling setItemWidget

I am using a QTreeWidget and setting a widget for the QTreeWidgetItem in the QTreeWidget. It is working fine but when I do the same for second time, the application is crashing.
The below is working fine.
QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
But if I add the last line once again, it is crashing when running the application.
The below is crashing.
QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0); // Intentionally added to simulate the issue
The above is an example to show the issue, but in my application, based on some events, I delete the tree widget items and add it later. When I set the item widget (after adding the items later), I am getting the crash.
I could not figure out why. Any ideas? FYI, I am using Qt 5.3.2 MSVC 2010, 32 bit.
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0);// Intentionally added to simulate the issue
I look at Qt code (4.x):
void QTreeWidget::setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget)
{
Q_D(QTreeWidget);
QAbstractItemView::setIndexWidget(d->index(item, column), widget);
}
and QAbstractItemView::setIndexWidget:
void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
{
Q_D(QAbstractItemView);
if (!d->isIndexValid(index))
return;
if (QWidget *oldWidget = indexWidget(index)) {
d->persistent.remove(oldWidget);
d->removeEditor(oldWidget);
oldWidget->deleteLater();
}
so if you add slider0 two times, then at first call it was added,
at seconds call Qt call for it deleteLater, and then added it,
are sure that this is what you want?
You have to set correct parent in the constructor of QTreeWidgetItem. Try this:
QTreeWidgetItem* item0 = new QTreeWidgetItem(treewidget);
Also it is important to understand who is owner of the slider0 after calling of setItemWidget(): the owner is your table, so 1) you don't need to delete this object; 2) the object will be deleted if you call setItemWidget for the same cell again. So, double call of treewidget->setItemWidget(item0, 0, slider0); seems very strange (second time you are setting the deleted object into that cell).

Filter with QComboBox C++

I want to create an editable QComboBox which filters results according to the search query and updates the dropdown entries accordingly.
After reading How do I Filter the PyQt QCombobox Items based on the text input? I tried to implement something similar in C++.
But I can't store anything inside the QComboBox now. Even after adding new entries through addItem() the total count remains 0.
What is the reason for this and how do I insert entries inside the QComboBox with QSortFilterProxyModel?
Here is the relevant snippet of the code:
SearchBox = new QComboBox(this);
SearchBox->setEditable(true);
// Try adding a few entries and check if they persist after changing the model
SearchBox->addItem(QString("hi"));
SearchBox->addItem(QString("bye"));
int count = SearchBox->count(); // count = 2
ProxyModel = new QSortFilterProxyModel;
ProxyModel->setSourceModel(SearchBox->model());
ProxyModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
SearchBox->setModel(ProxyModel);
// Check count again
count = SearchBox->count(); // count = 0 <- Why?
// Try adding new entries
SearchBox->addItem(QString("Hi again"));
count = SearchBox->count(); // count = 0 .. So new entries don't get stored
Completer = new QCompleter(ProxyModel,this);
Completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
SearchBox->setCompleter(Completer);
QObject::connect(SearchBox->lineEdit(), SIGNAL(textChanged(const QString)), ProxyModel, SLOT(setFilterFixedString(const QString)));
QObject::connect(Completer, SIGNAL(activated(const QString &)), this, SLOT(onCompleterActivated(const QString &)));
Use QStringListModel to store items. Application crashes if proxy model have no items (if filter string filters out all items)(this needs further investigation - is this completer issue or combobox). This can be fixed by not applying such filter (onTextChanged(QString text) slot). Completer completes input if theres only one item (not sure if it's ok). And sometimes checkbox doubles all items (don't know why). If this issues is critical, I think you need to write custom ComboBox from scratch and this is serious work.
{
SearchBox = new QComboBox(this);
SearchBox->setEditable(true);
QStringList Items;
Items << "hi" << "bye";
StringListModel = new QStringListModel();
StringListModel->setStringList(Items);
ProxyModel = new QSortFilterProxyModel;
ProxyModel->setSourceModel(StringListModel);
ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
SearchBox->setModel(ProxyModel);
// Check count again
int count = SearchBox->count(); // count = 2
// Try adding new entries
QStringList Items_ = StringListModel->stringList();
Items_ << "hi again";
StringListModel->setStringList(Items_);
count = SearchBox->count(); // count = 3
Completer = new QCompleter(ProxyModel,this);
Completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
SearchBox->setCompleter(Completer);
QObject::connect(SearchBox->lineEdit(), SIGNAL(textChanged(const QString)), this, SLOT(onTextChanged(QString)));
QObject::connect(Completer, SIGNAL(activated(const QString &)), this, SLOT(onCompleterActivated(const QString &)));
}
void MainWindow::onTextChanged(QString Text) {
QStringList Items = StringListModel->stringList();
QString Item;
foreach(Item,Items) {
if (Item.indexOf(Text) > -1) {
ProxyModel->setFilterFixedString(Text);
return;
}
}
}

QTreeWigetItem - How to manage a click to directly change the name of the item text

I have create a QTreeView and which is filed by QTreeWidgetItem. My application is a kind of file browser.
ViewTree is defined as below:
void MainWindow::createTreeView()
{
TreeViewSection = new QWidget();
QVBoxLayout *TreeViewLayout = new QVBoxLayout(TreeViewSection);
MyTree = new TreeWidget();
contextMenu = new QMenu(MyTree);
MyTree->setContextMenuPolicy(Qt::ActionsContextMenu);
addFolderAction = new QAction("Add Folder", contextMenu);
MyTree->addAction(addFolderAction);
connect(addFolderAction, SIGNAL(triggered()),this,SLOT(onAddFolderAction()));
deleteAction = new QAction("Delete", contextMenu);
MyTree->addAction(deleteAction);
connect(deleteAction, SIGNAL(triggered()),this,SLOT(onDeleteAction()));
MyTree->setSortingEnabled(true);
MyTree->setColumnWidth(0, 400);
headerItem = new QTreeWidgetItem();
headerItem->setText(0,QString("File Name"));
headerItem->setText(1,QString("Last Modified"));
headerItem->setText(2,QString("Size"));
MyTree->setHeaderItem(headerItem);
MyTree->setAcceptDrops(true);
MyTree->setDragEnabled(true);
MyTree->setDragDropMode(QAbstractItemView::InternalMove);
MyTree->setDefaultDropAction(Qt::MoveAction);
MyTree->setDropIndicatorShown(true);
MyTree->setDragDropOverwriteMode(true);
MyTree->setSelectionMode(QAbstractItemView::SingleSelection);
TreeViewLayout->addWidget(MyTree);
}
I have added an "Add Folder" Button, as defined below for the action:
void MainWindow::onAddFolderAction()
{
QList<QTreeWidgetItem *> item;
uint32_t index;
item = MyTree->selectedItems();
if (item.empty())
index = 0;
else {
QString str = item[0]->text(0);
QByteArray latin_str = str.toLatin1();
char *utf8_text = latin_str.data();
index = m_device.getIdByName(utf8_text);
}
if(m_device.isFolder(index) == true) {
QTreeWidgetItem* child = new QTreeWidgetItem();
child->setText(0, "NewFolder");
child->setText(1, "--");
child->setText(2, "--");
item[0]->addChild(child);
item[0]->setExpanded(true);
//item[0]->setSelected();
// MyTree->edit(selectedItem());
m_device.CreateNewFolder("New Folder", index);
}
}
As you see, by default I create a "NewFolder" which on a mtp FS system.
What I want to do it before creating the folder, I would like to be able to rename "NewFolder" to what the user want. I don't want to create a pop-up to enter text. What I want is a "kind of renaming" behavior. The folder appears in the treeview, the new folder is selected and the text is allowed to be changed directly. Like on Finder when you made a single click on the folder name, it become selected, and user can change the name in the finder without any pop-up
Thanks
If you want to edit the item right after creating it you should be able to achieve this behaviour by simply calling the editor on it:
QTreeWidgetItem* child = new QTreeWidgetItem();
child->setText(0, "NewFolder");
child->setText(1, "--");
child->setText(2, "--");
child->setFlags(child->flags() | Qt::ItemIsEditable);
item[0]->addChild(child);
item[0]->setExpanded(true);
MyTree->editItem(child);

Memoryleak with QListWidget addItem() + setItemWidget()

When I press a key there shall be a query to an engine. The results get put into a QListWidget by adding an item and setting the widget. Somehow this causes a massive memory overflow and even crashed my machine. But I dont get the error. Does clear() not delete the items passed to the QListWidget and the widgets set by setItemWidget(). I even tried to delete them on my own (comment), but still got a memoryleak. The error is in the if (!results.empty())-block, I guess, since commenting it out plugs the memoryleak.
void Widget::onTextEdited(const QString & text)
{
// QListWidgetItem * takenItem;
// while (takenItem = _results->takeItem(0)){
// delete _results->itemWidget(takenItem);
// delete takenItem;
// }
_results->clear(); _results->hide();
if (!text.isEmpty())
{
const std::vector<const Items::AbstractItem *> results = _engine.request(text);
if (!results.empty())
{
for (auto i : results){
QListWidgetItem *lwi = new QListWidgetItem;
_results->addItem(lwi);
ListItemWidget *w = new ListItemWidget;
w->setName(i->name());
w->setTooltip(i->path());
_results->setItemWidget(lwi, w);
}
_results->setFixedHeight(std::min(5,_results->count()) * 48); // TODO
_results->show();
}
}
this->adjustSize();
}
You should definitely use a memory leak detection tool instead of guessing around :)
UPDATE: clear() only deletes items but does not delete the widgets belonging to it. The widgets will be deleted if the QListWidget is deleted.
clear() does delete items and widgets belonging to it. And you mentioned that commenting out if(!results.empty()) solved the problem. I don't see any problem in the setItemWidget part. So I think the problem lies somewhere else, maybe ListItemWidget. How about you try replacing ListItemWidget with QLabel and see what happens. Eg:
QListWidgetItem *lwi = new QListWidgetItem;
_results->addItem(lwi);
//ListItemWidget *w = new ListItemWidget;
//w->setName(i->name());
//w->setTooltip(i->path());
QLabel *w = new QLabel;
w->setText("Hello");
_results->setItemWidget(lwi, w);