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

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.

Related

How to assign a specific number to QListWidget so that it can be modified later?

Are there any way to assign a specific int number to a QListWidget item?
I am creating a lot of instances of my designed widget class by doing the following each time and setting some data by passing them as arguments
MyWidgetClass *object = new MyWidgetClass(this);
object->setData(data_1,data_2,.....,data_n);
then I am setting this widget to ui's qListWidget with the help of QListWidgetItem by this:
QListWidgetItem *listWidgetItem = new QListWidgetItem(ui->qListWidget);
ui->qListWidget->addItem(listWidgetItem);
listWidgetItem->setSizeHint(object->sizeHint());
ui->qListWidget->setItemWidget (listWidgetItem, object);
Later depending on the signal received, the already passed data will have to be modified automatically. So, I thought, if any specific number is assigned to each item of QListWidget, then it can be modified at any time automatically.
Any helps or suggestion will be appreciated. Thanks in advance.
You can do the following to store a custom data in a list widget item:
int identifier = 111;
QListWidgetItem *listWidgetItem = new QListWidgetItem(ui->qListWidget);
listWidgetItem->setData(Qt::UserRole, identifier);
and this to retrieve it back:
int identifier = listWidgetItem->data(Qt::UserRole).toInt();

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

dynamic qtreeview with custom delegates

I'm using Qt 5.6 and my goal is to develop a dynamic tree using QTreeView that needs to populate items such as combo boxes, edit box, checkbox, buttons..etc depending on the settings loaded and the tree data can change as new data is loaded. There will be many nodes to populate in the tree with parent and child nodes.
I've read about different options to implement this type of treeview such as populating a QTreeView and implementing my own delegate by inheriting from QITemDelegate or QStyledItemDelegate or using Qt Quick's QML treeview.
For my purposes I've chosen the first option to dynamically populate a tree and modify parameters but I'm having trouble setting the delegate i want for a selected cell only as the only options to set the delegate in the tree is to setItemDelegateForRow, setItemDelegateForColumn or setItemDelegate. The tree will look something like the below. How should i set a different delegate for each of the child nodes?
by (col, row)
Parent(cell 0,0)
->Child(cell 0,1) -combo box(1,1)
->Child(cell 0,2) -button(1,2)
->Child(cell 0,3) -check box(1,3)
...
...etc
Parent(cell 0,10)
->Child(cell 0,11) - edit box(1,11)
->Child(cell 0,12) - edit box(1,12)
->Child(cell 0,13) - check box(1,13)
...
...etc
Edit
This is a simplified version of how I have setup my tree view so far. Found out the answer to why my child node column 1 was not showing was because i did not set the column count of the model. I have updated the code below and it works now.
enum EditType
{
TYPE_Text,
TYPE_CheckBox,
TYPE_ComboBox,
TYPE_Button
};
QTreeView* tree = new QTreeView(this);
QStandardItemModel* model = new QStandardItemModel;
model->setColumnCount(2);
tree->setModel(model);
//set custom delegate for column 1 of the tree
CustomDelegate *customDelegate = new CustomDelegate(this);
tree->setItemDelegateForColumn(1, customDelegate);
// Add parent nodes
QStandardItem* parent1 = new QStandardItem(tr("parent1"));
QStandardItem* parent2 = new QStandardItem(tr("parent2"));
model->appendRow(parent1);
model->appendRow(parent2);
// add a child
QList<QStandardItem*> childrow;
QStandardItem* child = new QStandardItem(tr("child1"));
childrow.append(child);
QStandardItem* child_value = new QStandardItem();
child_value->setData(TYPE_ComboBox, Qt::UserRole);
childrow.append(child_value);
parent1->appendRow(it_child);
As you can see from QAbstractItemView documentation, there is only methods for set delegate for
whole view, for columns or for rows. As you noticed, this methods are: setItemDelegate, setItemDelegateForColumn, setItemDelegateForRow. That's why you can not set delegate for certain cell.
There is another way, you can use for showing different widgets in QTreeView - method SetIndexWidget of QAbstractItemView. But you must keep in mind that:
This function should only be used to display static content within the
visible area corresponding to an item of data. If you want to display
custom dynamic content or implement a custom editor widget, subclass
QItemDelegate instead.
Use SetIndexWidget method is very "expensive" and if you have many rows in you QTreeView, you can see performance degradation.
Addition:
If you need widgets in QTreeView only for edit data items from your model, the best way to solve you problem will be reimplement QStyledItemDelegate. Look for method createEditor.
Addition:
Example of reimplement QStyledItemDelegate

How to disable filtering option for a QTreeView or Model

I am having a piece of code which deals with two QTreeView, where the items are added from left tree view to the right tree view. Here is a part of code:
MasterModel *model = new MasterModel;
leftProxyFilterModel *leftModel = new leftProxyFilterModel;
rightSelectedRowsFiletrModel *rightModel = new rightSelectedRowsFilterModel;
QTreeView *leftTreeView;
QTreeView *rightTreeView;
leftModel->setSourceModel(model);
rightModel->setSourceModel(leftModel);
leftTreeView->setModel(leftModel);
rightTreeView->setModel(rightModel);
Now for filtering some strings are set like this:
leftModel->setFilterWildcard(LineEdit->text());
This line is Filtering the contents of both the tree views, what I want is filtering option should be applicable only for left tree view.
Can someone help me to achieve this???
If rightModel's source is leftModel, then any filters you apply to leftModel will also affect rightModel.
Change rightModel->setSourceModel(leftModel) to rightModel->setSourceModel(model)
UPDATE: Or, you can add another layer of QSortFilterProxyModel so that your filter doesn't propagate to rightModel:
leftModel->setSourceModel(model);
rightModel->setSourceModel(leftModel);
auto leftFilteredModel = new QSortFilterProxyModel;
leftFilteredModel->setSource(leftModel);
leftFilteredModel->setFilterWildcard(LineEdit->text());
leftTreeView->setModel(leftFilteredModel);
rightTreeView->setModel(rightModel);

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.