How to iterate through all indexes in Tree Model - qt

I want to iterate through all indexes in the Tree model as shown in the image.
The function that I have written gives stack overflow error.
void iterate(const QModelIndex & index, const QAbstractItemModel * model)
{
if (index.isValid())
PrintData( index );
if (!model->hasChildren(index) || (index.flags() & Qt::ItemNeverHasChildren))
{
return;
}
auto rows = model->rowCount();
for (int i = 0; i < rows; ++i)
iterate(model->index(i, 0, index), model);
}

Pass the current index as parameter of QAbstractItemModel::rowCount() to get its number of rows. Otherwise, you will get the number of root items in your tree.
So, replace auto rows = model->rowCount(); by auto rows = model->rowCount(index);

Related

How to remove all child items of the root item in tree view

I want to remove all the tree items in the tree view of the invisible Root Item.
Currently this is what my workflow is
QModelIndex index = treeView->rootIndex();
QAbstractItemModel *model = treeView->model();
TreeModel *myModel = qobject_cast<TreeModel*>(model);
TreeItem* itm = myModel->getItem(index);
itm->removeChildren(0, itm->childCount());
bool TreeItem::removeChildren(int position, int count)
{
if (position < 0 || position > childItems.count())
return false;
for (int row = 0; row < count; ++row)
{
delete childItems.takeAt(position);
}
return true;
}
Though i am able to delete all the items in the tree view it seems as if the Tree model indexes are not getting updated.
After deleting all the Tree items if i try to add a new item the application crashes.
You need delete your elements in between these calls.
beginResetModel();
and
endResetModel()

How to get the position(col, row) of the user changed cell in a Table control?

I'm using tutorial_Form_Table.
The table has dynamically assigned values, something like:
for (col = 1; col <= 5; col++)
{
for (row = 1; row <= 5; row++)
{
if ((col == 2) || (col == 4))
{
if (row > 1)
table.cell(col,row).data(row*col);
else
table.cell(col,row).data("Text "+int2str(row*col));
}
else
table.cell(col,row).data("Text "+int2str(row*col));
}
}
I need to get the position of the cell when I enter new value in it, so I can update the corresponding table with the value entered.
Thank you.
Table has two properties: row() and column() which return values of current active cell.
public void activeCellChanged()
{
super();
info(strFmt('%1 %2 %3', Table.row(), Table.column(), Table.cell(Table.column(), Table.row()).data()));
}
On each of the controls you add to the table control you can override the modified method to see the new value you entered.
public boolean modified()
{
boolean ret;
ret = super();
info(strFmt('New data that we need to save: %1, %2 -> %3', Table.row(), Table.column(), Table.cell(Table.column(), Table.row()).data()));
return ret;
}
If you are working with a lot of data you should consider using some other control such as .NET grid control because of performance issues.

QTableView + custom TableModel + lazy loading

I need to load heavy dataset into QTableView. Dataset is no less then 700Mb in memory and I don't want to load all it to memory.
QSqlQueryModel is not ideal for me for 2 reasons - it is not editable and it is not realy load-on-demand (because fetching whole data to memory).
What I want to get
I want to store only some part of data in memory. Just for
displaying and maybe some buffer for fast scrolling.
Model should be editable
It should be low-memory-consumption
Should have no freezes
How I am trying to solve this (straightforward model of my code)
Custom QTableView (tableView)
Custom TableModel (model)
Model wrapper. (wrapper)
Model wrapper select rows count from database, and set this value to model. Now model can answer for int rowCount().
This same value is set for tableView.verticalScrollBar().
tableView.verticalScrollBar signal(valueChanged) is connected to tableview slot(on_valueChanged)
Some code
tableView::on_valueChanged(value)
{
wrapper.changeOffset(value);
}
wrapper::changeOffset(value)
{
if (_offset == value){
return;
}
_selectQuery->seek(value);
int endValue = qMin(value + _cacheSize, model->rowCount());
_list.clear();
for(int i = value; i < endValue-1; i++){
_list.append(_selectQuery->record());
}
model->setRecordList(_list);
_offset = value;
model->setOffset(_offset);
}
_selectQuery in wrapper::changeOffset is previosly executed QSqlQuery cursor for select query results.
I also implemented several methods in model
QVariant SqlRecModel::data(const QModelIndex &index, int role) const
{
int row = index.row() - _offset;
if (row > m_recList.size() || row < 0){
return QVariant();
}
if (role == Qt::DisplayRole)
{
QVariant value = m_recList.at(row).value(index.column());
return value;
}
return QVariant();
}
Setter for model data storage
void SqlRecModel::setRecordList(const QList<QSqlRecord> &records)
{
qDebug() << "r:";
emit layoutAboutToBeChanged();
m_recList = records;
emit layoutChanged();
}
Problem
I can scroll _cacheSize rows, but I get crash (The program has unexpectedly finished.) after going out of old cacheRange.
Any advice? I don't know where to dig. Thanks!
Sorry for disturbing.
Error was in other code block.
This way is just okay to solve the task I have.
btw: if you play with cache buffer you can achive more smooth scroll.

Copying part of QTableView

So I have a question very closely related to another question I've seen on here but when I tried posing my question there I got no responses, I'm hoping by asking this as a fresh question someone can help me out. Basically I want simply copy a portion of my table that I've created so that I can paste it to an excel file. Here's what I have:
QAbstractItemModel *abmodel = ui.tableview->model();
QItemSelectionModel *model = ui.tableview->selectionModel();
QModelIndexList list = model->selectionIndexes();
qSort(list);
QModelIndex index = list.first();
for(int i = 0; i < list.size(); i++)
{
QModelIndex index = list.at(i);
QString text = abmodel->data(index).toString();
copy_table.append(text);
if(index.row() != previous.row())
{
copy_table.append('\n');
}
else
{
copy_table.append('\t');
}
previous = index;
}
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(copy_table);
This will copy a column fine, but when I attempt to copy a row or say a 2x2 subtable the row index gets messed up, incorrectly assigning the row index for the values. Any thoughts?
Well, already figured it out, sorry anyone that wasted their time and looked.
void TestCopyTable::on_pushButton_copy_clicked()
{
QAbstractItemModel *abmodel = ui.tableView->model();
QItemSelectionModel * model = ui.tableView->selectionModel();
QModelIndexList list = model->selectedIndexes();
qSort(list);
if(list.size() < 1)
return;
QString copy_table;
QModelIndex last = list.last();
QModelIndex previous = list.first();
list.removeFirst();
for(int i = 0; i < list.size(); i++)
{
QVariant data = abmodel->data(previous);
QString text = data.toString();
QModelIndex index = list.at(i);
copy_table.append(text);
if(index.row() != previous.row())
{
copy_table.append('\n');
}
else
{
copy_table.append('\t');
}
previous = index;
}
copy_table.append(abmodel->data(list.last()).toString());
copy_table.append('\n');
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(copy_table);
}
I wrote some code based on Phil's to copy the selection when the user types Control-C.
I subclassed QTableWidget and overrode keyPressEvent():
void MyTableWidget::keyPressEvent(QKeyEvent* event) {
// If Ctrl-C typed
// Or use event->matches(QKeySequence::Copy)
if (event->key() == Qt::Key_C && (event->modifiers() & Qt::ControlModifier))
{
QModelIndexList cells = selectedIndexes();
qSort(cells); // Necessary, otherwise they are in column order
QString text;
int currentRow = 0; // To determine when to insert newlines
foreach (const QModelIndex& cell, cells) {
if (text.length() == 0) {
// First item
} else if (cell.row() != currentRow) {
// New row
text += '\n';
} else {
// Next cell
text += '\t';
}
currentRow = cell.row();
text += cell.data().toString();
}
QApplication::clipboard()->setText(text);
}
}
Output example (tab-separated):
foo bar baz qux
bar baz qux foo
baz qux foo bar
qux foo bar baz
Regarding the cdline:
qSort(cells); // Necessary, otherwise they are in column order
currently(20190118) it brings a warning:
Warnung: 'qSort >' is deprecated: Use std::sort
so my solution to replace the line with:
std::sort(cells.begin(),cells.end());
Compile, Run OK -> so far so good. But Question: Benefit of this cdline?
I found there is no one. Made several Test with copy from gui and parsing it to excel. Everything was fine even with the scenario 2x2 or othe XxY.

save state of a dataGrid: visible columns, columns width and order

I want to save remotely (on a database) the state (visible columns, columns width and order) of a Flex3 DataGrid.
For width and visibility I can simply save them by accessing each column attribute.. ugly but possible..
But for the order? Do I have to create the dataGrid dynamically??
Any idea is appreciated
thanks
In my case I have saved the order by header name (I'm making an assumption that your DataGrid always has the same columns and header names).
for (var n:Number = 0; n< datagrid.columns.length; n++)
{
var thiscol:DataGridColumn = DataGridColumn(datagrid.columns[n]);
colArray.addItem(thiscol.headerText);
}
Then I can restore the column order by retrieving the ordered list of column headers, and swapping the position of columns in the datagrid as required.
for (var n:Number = 0; n < colArray.length; n++)
{
moveColumnTo(String(colArray.getItemAt(n)), n);
}
I have defined a function moveColumnTo() to perform the switch.
private function moveColumnTo(columnName:String, columnIndex:Number):void
{
// Find current column position
var i:Number = -1;
for (var n:Number = 0; n < datagrid.columns.length; n++)
{
if (DataGridColumn(datagrid.columns[n]).headerText == columnName)
{
i = n;
break;
}
}
if (i == -1 || i == columnIndex) return; // Don't shift column
this.mx_internal::shiftColumns(i, columnIndex); // Shift column to required position
}
Why can't you just save the order as you're looping through each column?
for(var i:int = 0; i < dataGrid.columns.size; i++)
{
var column:DataGridColumn = dataGrid.columns[i];
arr.push({column.visible, column.width, i});
}

Resources