Find nth file/folder in QFileSystemModel - c++

I am using a QFileSystemModel and a QTreeView and I am trying to make the TreeView select the first folder/file by default. To do that I need to get the index of the first folder/file but I can't find a method that does that in QFileSystemModel.
Could you please help me?
Thank you in advance.
I have tried setCurrentIndex(_model->index(x, y)) but it didn't work. Here's the code I have and the tree shown:
void CodeView::finished_loading(QString file) {
qDebug()<<"Currently selected : " << _model->fileName( ui->treeView->currentIndex());
qDebug()<<"(0,0) "<< _model->fileName(_model->index(0,0));
qDebug()<<"(1,0) "<< _model->fileName(_model->index(1,0));
qDebug()<<"(2,0) "<< _model->fileName(_model->index(2,0));
qDebug()<<"(3,0) "<< _model->fileName(_model->index(3,0));
qDebug()<<"(0,0) "<< _model->fileName(_model->index(0,0));
qDebug()<<"(1,1) "<< _model->fileName(_model->index(1,1));
qDebug()<<"(2,1) "<< _model->fileName(_model->index(2,1));
qDebug()<<"(3,1) "<< _model->fileName(_model->index(3,1));
ui->treeView->setCurrentIndex(_model.index(1,0));
qDebug()<<"New selected : " << _model->fileName( ui->treeView->currentIndex());
}
Output :
Currently selected : "Wassim Gharbi"
(0,0) "/"
(1,0) ""
(2,0) ""
(3,0) ""
(0,0) "/"
(1,1) ""
(2,1) ""
(3,1) ""
New selected : "Wassim Gharbi"

The method is not in the model, but in the view.
QTreeView::setCurrentIndex
from the docs:
QAbstractItemView::setCurrentIndex(const QModelIndex &index) Sets the
current item to be the item at index.
Unless the current selection mode is NoSelection, the item is also
selected. Note that this function also updates the starting position
for any new selections the user performs.
To set an item as the current item without selecting it, call
selectionModel()->setCurrentIndex(index,
QItemSelectionModel::NoUpdate);
See also currentIndex(), currentChanged(), and selectionMode.
The code for the first folder is not really easy as first glance but you need to remember that the data abstractions on the models makes it powerfull, and cumberstone at the same time, so any item could potentially be a folder or a file, and we need to check for that:
if (model->rowCount()) // has at least one file or folder
{
QModelIndex current = model->index(0,0);
if (model->rowCount(current) == 0); // it's a file.
return current;
else {
// walk the tree trying to find the first file on the folders.
while(model->rowCount(current) > 0) {
current = model->index(0,0,current);
}
if (index.isValid())
return index; // our file inside folders
else
return QModelIndex(); // no file inside folders.
}
}

In order to get the index at a specific location in the model, use QModelIndex::child(row, column)
QFileSystemModel *model = new QFileSystemModel();
model->setRootPath("C:/Qt");//your path
ui->treeView->setModel(model);
ui->treeView->setCurrentIndex(model->index(0, 0).child(0, 0));
I can tell from your question that you don't understand how a treeview's row and column system works. Please read the documentation

Related

Issues trying to make a filter using Qt

I'm trying to make my software filter a list of elements.
I think I need to put my data in a TableWidget because I have to display other information.
I also put 3 Line Edit to search respectively in each category (called leName, leSource, leDestination)
so I tried to implement my filter for the name property, for now I have :
void MyClass::on_leName_textEdited(const QString &arg1)
{
for (int i=0;ui->tableWidget->rowCount()-1;i++)
{
qDebug()<<"before if";
if(ui->tableWidget->item(0,1)->text().contains(arg1) //tried with &arg1, I have the same issue, for now
{
qDebug()<<"If validated";
ui->tableWidget->showRow(i);
}else{
qDebug()<<"If not validated"
ui->tableWidget->hideRow(i)
}
}
}
When I hit a key, my soft crashes
I get "Before if", "If (not) validated", "Before if" from qDebug
I launched with debbugger and got Segmentation fault as error
not sure what I could add as detail about my error
Maybe I did nothing in the good way, I'm no expert in Qt nor c++
If you have any idea of what I should do to correct this, I would appreciate it =)
The fact that a cell exists does not imply that it has an associated QTableWidgetItem, so you must verify that it is not null.
QTableWidgetItem * item = ui->tableWidget->item(0, 1);
if(item && item->text().contains(arg1))
{
qDebug() << "If validated";
ui->tableWidget->showRow(i);
}else{
qDebug() << "If not validated"
ui->tableWidget->hideRow(i)
}

QFileSystemModel and QTreeView

I show a QFileSystemModel through a QTreeView.
Whenever the user clicks on a directory (expanded or not expanded) I want to get a list of the files inside this directory.
void MyModel::selectionChanged(const QItemSelection& selected,const QItemSelection& deselected) {
for (auto const & it : selected.indexes()) {
for (int i=0;i<rowCount(it);i++) {
auto child = it.child(i, it.column());
qDebug() << fileName(child);
}
}
}
The problem with the above code is that this only seems to work once that particular directory has been expanded. As long as the directory has never been expanded (since program start) rowCount is 0.
How can I force the model to populate the children of the given model index? Without necessarily showing the children in the view? One level of children indexes would be enough in this case.

Id of an item in QTreeWidget changed

There is something very strange about Qt.
I have a button ui->addPointButton and a QtreeWidget ui->pointListBox. When I click on the button, it adds a point to the tree. mScenePtr is a pointer to the class I put all my points.AddPoint is a class creating a window asking for some information about the point.
void AddPointsWindow::on_addPointButton_clicked(bool clicked)
{
Q_UNUSED(clicked);
AddPoint addPointWindow(mScenePtr->getColor_or_texture());
int addPointWindowResult = addPointWindow.exec();
if (addPointWindowResult == QDialog::Accepted)
{
SVertex vertex = addPointWindow.getVertex();
mScenePtr->addVertex(vertex);
QTreeWidgetItem* itemPtr = new QTreeWidgetItem(ui->pointListBox);
cout << "id" << ui->pointListBox->indexOfTopLevelItem(itemPtr) << endl;
//itemPtr->setText(0,QString::number(mScenePtr->getVertexNumber()));
//itemPtr->setText(0, QString::number(ui->pointListBox->indexOfTopLevelItem(itemPtr)));
itemPtr->setText(0, "hjhjh");
cout << "id" << ui->pointListBox->indexOfTopLevelItem(itemPtr) << endl;
itemPtr->setText(1, QString::number(vertex.x));
itemPtr->setText(2, QString::number(vertex.y));
itemPtr->setText(3, QString::number(vertex.z));
if (color == mScenePtr->getColor_or_texture())
{
itemPtr->setText(4, QString::number(vertex.r));
itemPtr->setText(5, QString::number(vertex.g));
itemPtr->setText(6, QString::number(vertex.b));
}
//ui->pointListBox->insertTopLevelItem(ui->pointListBox->topLevelItemCount(), itemPtr);
cout << "value : " << vertex.x << endl;
}
}
In this exemple, I click twice on the buttons, create two points with vertex.x = 0 for the first and 1 for the second.
Look at the three lines in the middle :
//itemPtr->setText(0,QString::number(mScenePtr->getVertexNumber()));
//itemPtr->setText(0, QString::number(ui->pointListBox->indexOfTopLevelItem(itemPtr)));
itemPtr->setText(0, "hjhjh");
If there is only the third line, the result is
id0
id0
value : 0
id1
id1
value : 1
Everythong is ok.
But if I put one of the two others lines, the result in both cases is :
id0
id0
value : 0
id1
id0
value : 1
How is it possible ? How can the call to ui->pointListBox->indexOfTopLevelItem(itemPtr) or mScenePtr->getVertexNumber() can change the id of the item ?
Qt 5.5
After using setText, the items in the tree might have sorted automatically.
So in the two commented line cases, when you add the number (using setText), the nodes are getting sorted and the earlier node has become the top level item.
That is the reason you are seeing two different IDs "before setText" and "after setText", when you are querying "top level item".
To see the results properly, Turn off the sorting for the tree. (may be in your constructor)
ui->pointListBox->setSortingEnabled(false);

How to access childWidgets in a QTreeView using QModelIndex?

I'm working on an application using the Qt library (version 4.8).
I have a QTreeView with a QStandardItemModel. My widget looks like that:
Item1
subitem11
subitem12
Item2
subitem21
subitem22
Item3
subitem31
subitem32
Here is how I add the items to my QTreeView:
model->setItem(0, 0, item1);
item1->setChild(0, 0, subitem12);
I want to take an action only when the user double cliked an item (and do nothing when he clicked a subitem). So I use the doubleClicked(const QModelIndex & index) signal.
I want to process the information about the item/subitem which was double cliked by the user. So I get the row of my item/subitem:
index.row();
But every time I try to reference to the item/subitem to display its name or check if it has children, I can only access the items:
index.model()->item(row)->text();
My question is: how can I acces the subitems (vbetween items abd subitems) in my slot? Or how can I prevent them from emitting the signal? I can't disable them - it would be too confusing for the user.
Edit: The problem is that every time I click on an item or subitem and execute:
index.model()->item(row)->hasChildren();
or:
index.model()->item(row)->parent() == 0;
I get true as result. So I can reference only the items.
My question is: What is the correct way to reference to subitems?
When you are trying to access model items by row index, the model returns top-level item at that row. Use itemFromIndex instead:
auto item = index.model()->itemFromIndex(index);
if (item && item->hasChildren()){
// item is not a leaf
}
EDIT index.model() returns QAbstractItemModel*, so a cast is also necessary here (or, better, storing a pointer to the standard model somehwere in the code).
I would do it like this:
// Define your custom role to store item type.
enum MyRoles
{
ItemTypeRole = Qt::UserRole + 1
};
// Define item types.
enum ItemType
{
Primary,
Secondary
};
Than set the proper item type for all your items:
QStandardItem* item = new QStandardItem("Item1");
item->setData(Primary, ItemTypeRole);
QStandardItem* subItem = new QStandardItem("SubItem1");
subItem->setData(Secondary, ItemTypeRole);
And in your slot connected to the doubleClicked signal acces the type like this:
ItemType type = static_cast<ItemType>(index.data(ItemTypeRole).toInt());
if (type == Primary)
std::cout << "It's a Primary item!" << std::endl;
else if (type == Secondary)
std::cout << "It's a Secondary item!" << std::endl;
You can't disable the signal for the subitems. However, you can check if an item has a parent. It it doesn't, it is an item and if it does, it's a subitem.
if (item->parent() != 0)
.. //subitem
else
.. //item
An alternative would be to use the data() function to set some special value to distinguish between the two.
item1->setData(QVariant("item"));
subitem1->setData(QVariant("subitem"));
Then query the value in your doubleclick handler:
QVariant var = item->data();
if (var.toString() == "item")
...
else if (var.toString() == "subitem")
...

QTreeView insertRows via method crushs / direct call works

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);