Why is QListView blank after setRootIndex? - c++

I have a tree like model (which iff non-empty has always height 2). In a tree view, the data is correctly displayed. However, I want to display the data in two ListViews, dupFilesOverview and dupFilesDetailview:
dupFilesOverview is showing the elements at depth 1, while dupFileDetailView should show the children of the of the element selected in the overview.
To do this, I'm currently using the following code (where dm is my model):
ui.dupFilesOverview->setModel(&dm);
ui.dupFilesDetailview->setModel(&dm)
QObject::connect(ui.dupFilesOverview->selectionModel(), &QItemSelectionModel::selectionChanged, [&ui, &dm](const QItemSelection& selection) {
QModelIndex index =selection.indexes().first();
ui.dupFilesDetailview->setRootIndex(index);
});
Via some qDebug output,
qDebug() << index << dm.data(index, Qt::DisplayRole) << dm.hasChildren(index) << dm.data(index.child(1,0), Qt::DisplayRole);
I verified that the index I've obtained is indeed the one that I want: It is valid and has the expected children. From the documentation, I would expect dupFilesDetailDetailview to now show the children of my model at the specified index. Alas, it stays blank instead. Is there anything that I'm missing?

In the end it turned out to be an embarrassing off-by-one error in the model: The parent function returned the wrong index.

Related

QCompleter - Tree Model Unique Items

I'm trying to create a solution for a custom QCompleter that only returns one selection choice when there are multiple rows with the same value, however there may be different children.
In the picture bellow there is an example of a tree (formatted wrong), where there are two rows with the same name "Parent1". As you can see at the bottom of the image this return two entries for each row. I would like to only return one option however on the next search term "Parent1.Ch" for the options to be returned for both rows.
I have tried to implement a QSortFilterProxyModel to only return a row if another row with the same text hasn't been shown already:
bool UniqueFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
if(!(m_list.contains(index.data().toString()))) {
const_cast<UniqueFilterProxyModel *>(this)->m_list.append(index.data().toString());
return true;
}
else
return false;
}
However this this doesn't solve the problem as QCompleter will still only search the children of the row that is valid. I'm a bit stuck on how to correct this issue without creating a separate model.
Based on code provided, which is very limited, I would check that the method contains() does exactly what is expected. Or, provide more implementation details.

qt - how to permanently sort a qstandarditemmodel

I have a program where I am trying to implement sorting on a qstandarditemmodel that is displayed in a table view. However, the method I am using doesn't seem to actually sort the model itself, but only the view. I need it to be able to sort the source model because I save the data to a .csv file using a delegate that passes the items from the model into an object of a class, and if the view is the only thing that is sorted it causes data loss due to the positions of the items in the view being changed but not in the model itself.
This is the code I use in the mainwidget constructor to connect the headerview clicked signal to a method that sorts the model:
currentStudentsModel = new QStandardItemModel(this);
ui->currentTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->currentTableView->setModel(currentStudentsModel);
ui->currentTableView->setItemDelegate(currentStudentsDelegate);
currentTableHeader = ui->currentTableView->horizontalHeader();
connect(currentTableHeader, SIGNAL(sectionClicked(int)), this, SLOT(on_sectionClicked(int)));
Here is on_sectionClicked():
void mainWidget::on_sectionClicked(int index)
{
currentStudentsModel->sort(index,Qt::AscendingOrder);
}
As I previously stated, this appears to only sort the items in the view as when I try to output all of the records stored in the model it has not changed from when they were initially entered. How do I get the model to be sorted itself and that order to be saved?
QStandardItemModel does not implements sort.
From Qt documentation:
void QAbstractItemModel::sort(int column, Qt::SortOrder order =
Qt::AscendingOrder)
Sorts the model by column in the given order. The base class
implementation does nothing.
You need to sort through QSortFilterProxyModel
currentStudentsProxyModel = new QSortFilterProxyModel;
currentStudentsModel->setSourceModel( currentStudentsProxyModel );
currentStudentsProxyModel->sort( 0, Qt::AscendingOrder );
void mainWidget::on_sectionClicked(int index)
{
currentStudentsProxyModel->sort(index,Qt::AscendingOrder);
}

Qt: Recognizing items of QTreeView

Example Tree View:
1. a
1.1. b
1.1.1. c
I want to know how I can make my code recognize I right clicked whether a or b or c. I am able to create a TreeView, add a b c to it, and get the item at the position of the right click but I don't know how I can recognize the item so right clicks would create different context menus respecting the item clicked. I use standard item model (QStandardItemModel) and so far what I got is:
void MyWindow::make_tree_custom_menu(const QPoint& pos){
QModelIndex index = treeView->indexAt(pos);
int itemRow = index.row();
int itemCol = index.column();
QStandardItem* itemAtPos = model->item(itemRow, itemCol);
itemAtPos->setText("meh");
}
I know that with QTreeWidgetItems you can do QTreeWidgetItem* newitem = new QTreeWidgetItem(name, itemtype); but as far as I could see in the docs, QStandardItem doesn't have such constructor. Also, I know that this exists, but it is unanswered. Therefore, I would like any help on possible methods to identify tree view items in such an application.
First of all, I suggest to use the QStandardItemModel::itemFromIndex(const QModelIndex & index) method to get the item in this case. The QStandardItemModel::item(int row, int column) method hasn't the parent parameter, so I think it returns only top level items (this method is good for lists or tables).
Then, when you get the item, you have exactly the pointer to the item you have created, so you have all you need to recognize it. If you want to set an attribute to the item to define a type (like QTreeWidgetItem itemType), you can use the QStandardItem::setData(const QVariant & value, int role) method (using e.g. the Qt::UserRole) when you create the item. Then you can get the item type using the QStandardItem::data(int role) method in your make_tree_custom_menu method.
See:
QStandardItemModel::itemFromIndex
QStandardItem::setData
QStandardItem::data
Qt::UserRole

Qt: View not updating after QAbstractItemModel::beginInsertRows/endInsertRows

I have a QAbstractItemModel derived model attached to a QTreeView
I want to programatically append a single row to a node somewhere in my tree hierarchy.
I have a slot which is connected to a signal from my view. The signal sends the QModelIndex of the node to which I want to append my new row. In the slot I call beginInsertRows(...) using that QModelIndex and the new row's row number, append the new row to my model data, and then call endInsertRows():
The value passed to beginInsertRows(...) is the number of child rows the parent node has prior to appending the new node.
That is, if there are 4 child rows, they will have row indices 0, 1, 2 and 3. Therefore the new row number added will be 4.
void Model::slotOnAddRow(QModelIndex parent, std::string key)
{
assert(parent.isValid());
Row& parent_row = *static_cast<Row*>(parent.internalPointer());
beginInsertRows(parent, parent_row.numChildren(), parent_row.numChildren());
parent_row.addChildRow(key);
endInsertRows();
}
The problem I'm having is that after calling endInsertRows() my view does not update.
Example:
Here is an example of my tree view.
Scenario:
I want to append a new row to SPREAD_1.
SPREAD_1 currently has 4 children rows:
0: inst_id
1: LEG_1
2: LEG_2
3: LEG_3
The new row will therefore have row index 4, so I call beginInsertRows(SPREAD_1, 4, 4);
I do just this, and my view does not show my new row.
Proof the node does actually exist:
I know the row exists in my model, because if I collapse the SPREAD_1 node, and then re-expand it, my newly added row is now visible:
Question:
AFAIKT I've followed the example online correctly, but I'm obviously missing something.
How can I append a new row to a tree node, and have the view update?
Do I need to emit a signal or override another base class method?
An issue like this is indicative of an error elsewhere in the model. Without seeing the implementation of the model it is impossible to say where.
Using Model Test can be very helpful in diagnosing the issue.
Literally all you need to is instantiate a ModelTest instance with your model
QTreeView(&_model);
ModelTest test(&_model);
If the model doesn't conform, you will get assertion failures from ModelTest
I fixed this by adding ui->treeView->reset(); after insert rows
Make sure that the index passed to beginInsertRows is correct. In particular the column number for the index needs to be zero if the children are attached to column zero (which they normally are)!
Try to emit dataChanged signal with parent index as argument.

(Qt) Losing contact with items added to an scene. Cannot get positions

I'm trying to set up a configuring widget for an editable structure form widget so that the positions of the "to be filled LineEdits" are chose arbitrary by the user.
My idea is to gather the wanted positions of the LineEdits by using a widget made of a QGraphicsScene scene, a QGraphicsView view, and some references to the LineEdits items with proper name: QTextItems.
I have managed to add the reference items to the scene, have shown the view and have been able to put the items on the positions I wanted. The problem is once the items are added to the scene, I lose all contact with them and I can't know which item is in which position.
Here is a little example:
scene = new QGraphicsScene(myWidgetSize_QRect);
view = new QGraphicsView(scene);
view->setAcceptDrops(true);
for(int i=0, i<number_of_input_fields, i++)
{
GraphicsTextItem *item=new GraphicsTextItem();
//Configure Item
item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable);
item->setAcceptedMouseButtons(Qt::LeftButton);
item->setAcceptDrops(true);
item->setCursor(Qt::OpenHandCursor);
QString txt("");
txt = textForItem(i);//some function that defines the text.
//Suppose it have returned for some items: "Name", "Address"
item->setPos(20+20*i,20+20*i);//load the items on different positions
scene->addItem(item);
}
view->show();
Well, having done a code alike I don't know how to get the positions back once they were moved to the desired location.
Let me be more specific if I have placed the items with the text "Name" and "Adress" on the positions I wanted, I don't know how to get the position of the "Name" item.
The only access I have to the items after adding them to the scene is:
scene->items();
I don't how the items on that list are ordered. And don't know how to know which is which...
I'm having a very hard time doing this, I have been putting off this while concentrating in some other things... but I have reached the time I cannot continue coding other things because this is a main feature of my program
Any help will be very appreciated... Thank you.