QTreeWidget Passing multiple Items (more then one selection) through a function - c++

I am a student programmer using Qt to build a GUI for work. I have ran into an issue; more or less and inconvience of sorts wiith multiple selections in the QTreeWidget. My GUI has a main interface with a QTreeWidget as the central item in this window. Below the QTreeWidget I have several buttons; copy, edit, and delete. As you might've already guessed each one of these buttons correlates to a function that executes the command. My tree widget has the ability to select multiple items; however, when multiple items are selected the only item that is passed through is the last item that was selected. I was hoping that somebody with some more insight in this IDE might be able to point me in the right direction for accomplishing this. Here is the process that is followed when one of these functions is executed.
void InjectionGUI::copyInjection_Clicked(QTreeWidgetItem *itemToCopy)
{
InjectionData copyInjectionData; //first use data from the tree widget row
QString converter = itemToCopy->text(0); //to find the vector item that will be copied
int id = converter.toInt();
int nameNumber;
copyInjectionData = qTreeInjectionData.at(id);
qTreeInjectionData.append(copyInjectionData);
buildTreeWidget();
}
void InjectionGUI::slotInjectionCopy()
{
if(ui->treeWidgetInjections->currentItem() == 0)
{
QMessageBox invalidSelection;
invalidSelection.setText("No row selected to copy");
invalidSelection.setWindowTitle("Error");
invalidSelection.exec();
}
else
{
copyInjection_Clicked(ui->treeWidgetInjections->currentItem());
}
}
I'm not too sure what code will be relevant towards making this change; so if there is additional structure that anyone would like to see please just requested. I'm pretty sure that my problem or my solution is going to lie in the way that I'm using current item. After reviewing the documentation from Qt's website I'm still unsure how I would change this to allow multiple selections to be passed through the function. Please only provide constructive feedback; I'm only interested in learning and accomplishing a solution. Thanks in advance.
UPDATE! SOLVED!!!
Just thought it might be nice to show what this looked like implemented:
QList<QTreeWidgetItem *> items = ui->treeWidgetInjections->selectedItems();
for(int i = 0; i < items.size(); i++)
{
QTreeWidgetItem *qTreeWidgetitem = new QTreeWidgetItem;
qTreeWidgetitem = items.at(i);
copyInjection_Clicked(qTreeWidgetitem);
}

If you need to know which items are selected, you can use
QList<QTreeWidgetItem *> QTreeWidget::selectedItems() const
to have a list of all the currently selected items in the tree.
Then you may call your function once for every item in the list, or you can overload your function to take as argument a QList<QTreeWidgetItem *> and then run through the list inside the called function.

Related

Making only one column of QTreeWidget editable // troubleshooting

Mind that this question isn't a duplicate of question Making only one column of a QTreeWidgetItem editable, as it's proposed solution doesn't work.
Hello, so I just want to make only ONE column of my treeWidget editable.
propertyItems.push_back(new QTreeWidgetItem); //gets filled by the while-loop
propertyItems[propertyItems.size()-1]->setText(0, prop.name); //sets the text of the item
propertyItems[propertyItems.size()-1]->setText(1, prop.value);//set the text of the other item
propertyItems[propertyItems.size()-1]->setFlags(Qt::ItemIsEditable);
ui->treeWidget_3->insertTopLevelItem(ui->treeWidget_3->topLevelItemCount(), propertyItems[propertyItems.size()-1]); //appends the items
counter ++;
and
void MainWindow::onTreeWidget3ItemDoubleClicked()
{
if (ui->treeWidget_3->currentColumn() == 2) {
ui->treeWidget_3->editItem(ui->treeWidget_3->currentItem(), ui->treeWidget_3->currentColumn());
}
}
is my approach. ontreeWidget3ItemDoubleClicked is connected with treeWidget::doubleClicked, treeWidget_3 has NO edit-triggers
BUT: when I execute the programm, the QTreeView is just grayed out.
That said, I also tried
propertyItems[propertyItems.size()-1]->setFlags(propertyItems[propertyItem.size()].flags | Qt::ItemIsEditable);
The treeWidget_3 isn't grayed off anymore, but it is still uneditable...
How can I fix this?
BTW: I am a newb to Qt so I might have forgotten something crucial. Sorry in this case.
As mentioned in the documentation:
The QTreeWidgetItem class provides an item for use with the QTreeWidget convenience class.
It means that it won't work for all use cases. The solution is to create your own model and overload the flags(const QModelIndex& index) method returning the appropriate values (basically Qt:: ItemIsEnabled for read-only columns and Qt:: ItemIsEnabled | Qt::ItemIsEditable for the editable one). You can get the column from index.column().
Qt provides an example to start with trees and models.

QT: Searching through QTreeView/QFileSystemModel with a QDtring for a QModelIndex index

I'm working on a custom QDialog for the user to choose a directory on the filesystem. I'm using a QFIleSystemModel inside a QTreeView. Whenever the user selects an item in the QTreeView the directory is written to a QLineEdit. My problem is I would like to do the opposite of-sorts by expanding through the QTreeView nodes by taking the typed text and... well... obviously expanding the nodes if the text typed is an existing, absolute path.
I've searched for quite a few variations of my problem(although I know it's very loaded) and looked through a lot of the documentation of the classes but I can't find anything to really help me. I'm guessing I need to use QTreeView::expand(const QModelIndex) to expand them after finding but searching through the index is my biggest problem as of now. I'm open for any suggestions and any help is truly appreciated. Thank you in advanced and sorry for making such a wall of text.
searching through the index is my biggest problem as of now
And index is just a "pointer" to an item in the model. You can't search "through" it, because there is nothing "in" an index. It's just a pointer to exactly one item.
You should search through the model. The index(const QString & path) method does that for you. Given a path, it returns an index into the element at the end of the path. You can then iterate upwards to extend the items:
// ...because QModelIndex::operator= doesn't exist
QModelIndex & assign(QModelIndex & dst, const QModelIndex & src) {
dst.~QModelIndex();
new (&dst) QModelIndex(src);
return dst;
}
void extend(const QString & path, QTreeView * view) {
auto fs = qobject_cast<QFileSystemModel*>(view->model());
if (!fs) return;
auto idx = fs->index(path);
// ascend up from the child item and expand items in the tree
while (idx.isValid()) {
view->expand(idx);
assign(idx, idx.parent());
}
}
You can use this method with the last item removed from the path as well, since - presumably - the last item might not be valid, and thus fs->index might fail.
Have you check here?
[Model/View Programming][Insert and delete rows in QTreeView]
http://doc.qt.io/qt-4.8/model-view-programming.html
QTreeView & QAbstractItemModel & insertRow
As base design principle, View only render the data.You should not expect to modify the data via View directly.

how can iterate foreach item in QListWidget

i just can find any example in the internet how to loop and get each item in the QListWidget
int count = listWidget->count();
for(int index = 0;
index < count;
index++)
{
QListWidgetItem * item = listWidget->item(index);
// A wild item has appeared
}
The foreach thing is totally different, I think.
If you want more info on that, look at this
http://doc.qt.digia.com/4.2/containers.html#the-foreach-keyword
scroll down to where it talks about the foreach keyword.
Special thanks to Tomalak Geret'kal for adding the proper characters which my keyboard is unable to produce :)
Due to so many upvotes on this, i'll explain the foreach macro here as well.
foreach is a Qt specific C++ addition, implemented using the preprocessor. If you want to disable the thing, just add CONFIG += no_keywords to your XX.pro file.
Qt makes a copy of the list being iterated, but don't worry about performance. Qt containers use implicit sharing, where the actual contents are not copied. Think of it as two reference variables using the same actual variable. This makes it possible to modify the list you are iterating over, without messing up the loop. Note that modifying the list forces Qt to make a copy of the actual contents of the list the first time it's modified.
foreach can be used to loop over all Qt basic containers, QList QVector QMap QMultiMap and so on. QListWidget is not one of these, so it doesn't work on it, sadly. To make matters worse, QListWidget doesn't provide a list of all items, only the ones selected. There is a method called items, which would seem to be nice, but is protected.
To loop over selected items, I think this would work
foreach(QListWidgetItem * item, listWidget->selectedItems())
{
// A wild item has appeared
}
The first Google result for "QWidgetList" told me how to do it.
You can use a QWidgetListIt iterator.
QWidgetList wl = get_some_widget_list();
for (QWidget* w = wl.first(); w != 0; w = wl.next()) {
// use w
}
// or
foreach (QWidget* w, wl) {
// use w
}
I'm not quite sure where this foreach comes from. If it's not provided by Qt, it may be a macro expanding to BOOST_FOREACH, for which you'll need to include boost/foreach.hpp.

Removing rows from QAbstractTableModel derived class don't work, why?

I have a Qt application for which I derived my own model class from QAbstractTableModel. I have implemented the necessary methods as prescribed in the documentation. When I call removeRows method the changes are correct in my View (the rows I wanted to remove are removed).
But somehow, the operations on the model doesn't seem to be propagated to the QList I use in the model to store my data. When I save the values stored in the QList to the disk, it look like nothing was erased from it by removeRows.
Here is what my removeRows implementation looks like (it is based on the code from the book Advanced Qt Programming, Chapter 3, p.125):
bool MyModel::removeRows(int row, int count, const QModelIndex&)
{
beginRemoveRows( QModelIndex(), row, row + count - 1);
for (int i = 0; i < count; ++i) {
mMyQList.removeAt(row);
}
endRemoveRows();
return true;
}
How do I fix this? What did I miss?
Thanks!
Like Frank O. implies, it's hard to know what's going on without seeing some code. But from the sound of it, the values haven't been removed from QList simply because you haven't taken them out. When you move from Widget to Model/View classes, you have to do this yourself. I.e., in your removeRows() method you must remove the rows from the QList 'by hand'.
It turns out that nothing was wrong with my implementation of removeRows.
The save method was called by my unit tests just before showing my dialog. The dialog was not calling the save method at all.
No wonder the change were visible in the View and not in the output file...

Using images in QListWidget, is this possible?

I am using QT to create a chat messenger client. To display the list of online users, I'm using a QListWidget, as created like this:
listWidget = new QListWidget(horizontalLayoutWidget);
listWidget->setObjectName("userList");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(listWidget->sizePolicy().hasHeightForWidth());
listWidget->setSizePolicy(sizePolicy1);
listWidget->setMinimumSize(QSize(30, 0));
listWidget->setMaximumSize(QSize(150, 16777215));
listWidget->setBaseSize(QSize(100, 0));
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Users are shown by constantly refreshing the list, like this: (Note: There are different channels, with different userlists, so refreshing it is the most efficient thing to do, as far as I know.)
void FMessenger::refreshUserlist()
{
if (currentPanel == 0)
return;
listWidget = this->findChild<QListWidget *>(QString("userList"));
listWidget->clear();
QList<FCharacter*> charList = currentPanel->charList();
QListWidgetItem* charitem = 0;
FCharacter* character;
foreach(character, charList)
{
charitem = new QListWidgetItem(character->name());
// charitem->setIcon(QIcon(":/Images/status.png"));
listWidget->addItem(charitem);
}
}
This has always worked perfectly. The line that I commented out is the one I have problems with: my current goal is to be able to display a user's online status with an image, which represents whether they are busy, away, available, etc. Using setIcon() does absolutely nothing though, apparently; the items still show up as they used to, without icons.
I'm aware that this is probably not the way this function needs to be used, but I have found little documentation about it online, and absolutely no useful examples of implementations. My question is, can anybody help me with fixing this problem?
This is how you may conduct your debugging:
Try the constructor that has both icon and text as arguments.
Try to use that icon in another context to ensure it is displayable (construct a QIcon with same argument and use it elsewhere, e.g. QLabel!).
Use icon() from the QListWidgetItem to receive back the icon and then look at that QIcon.
Create a new QListWidget, change nothing, and ordinarily add some stock items in your MainWidget's constructor. See if the icons show up there.