QTableView problems with row - qt

Hello guys i new to QT and i am doing Qtableview to add information in 3 columns to infinite row like
|--1--|--2--|--3--|
|--1--|--2--|--3--|
|--1--|--2--|--3--|
this is how i want to insert/append row but this is how i am getting after insert/append row functions.
|--1--|--2--|--3--|
|-----|-----|-----||--1--|--2--|--3--|
|-----|-----|-----||-----|-----|-----||--1--|--2--|--3--|
i am getting empty gaps and increased column count
i am using QStandardItemmodel for model this is code that creates the model item
void tableview::add_tableview() //this is used to add data to tableview
{
//to get data from line edit in add window
QStandardItem *item_1 = new QStandardItem(QString(enter1_edit->text()));
QStandardItem *item_2 = new QStandardItem(QString(enter2_edit->text()));
QStandardItem *item_3 = new QStandardItem(QString(enter3_edit->text()));
list << item_1 << item_2 << item_3;
model->appendRow(list);
//to set the model
main_tableview->setModel(model);
}
The values in the rows are added using qlineedit enter1_edit,enter2_edit & enter3_edit(its in other function/method)
main_tableview is the object of qtableview
Thanks for helping me!

Ding Ding Ding, I have it.
I tried to reproduce your problem without success unil I tried something...suboptimal :).
Is your list by any chance a global entity? If yes (and I assume it is) you keep adding items to it.
First time you call add_tableview() all is good, list is empty, gets three QStandardItem pointers added and is used to append a row with those three items. So far so god.
You call add_tableview() again, now you create another three QStandardItems and APPEND them to the list (which still contains the three from the last call). Invoking appendRow() actually tries to insert six items, from which the first three allready exist in the model. And as you know you mustn't add the same item pointer to a model twice. Thankfully Qt doesn't crash but inserts three empty columns for the item pointers allready in it.
Solution: At the end of your add_tableview() method call list.clear() or use a local variable for the list. The overhead should be minimal.
Best regards
D

Related

How to fix QTableWidget setText/setCellWidget causing crash when loading QSettings

Hello I'm using a QTableWidget and essentially have code such that the first column will allow the table to grow/shrink dynamically. The last populated row's first cell will have a Plus button to add a new row that can be edited and the Minus button will remove its corresponding button's row. For example, If I click the Plus button 5 times, it will be at the 6th row and the previous 5 rows will all have a Minus buttons to remove their row. If the cell's row has a Minus button on it, the row is implied editable, otherwise not. However, I allow the table to have a default amount of rows, such that it can never visually shrink less than 5, for example, even if it's technically "empty". To edit the row, you need to hit the Plus button which will check if we need to insert a new row, for example if we're at 5 rows and the base row size is 5, then we need a new row and to populate each column's index of the new row.
The main reason for this table is to read and write the table's information to a QSettings and be able to import the past exported information to the same cells and essentially restore the table's state as it appeared last. However, when reading from the QSettings, the table will crash after all cells are populated correctly with the information and I can tell they are correctly populated because the debugger will freeze the GUI and I can visually see and qDebug() how far into the loop of the QSettings array I got to before seg-faulting.
Now when I do everything manually, such as clicking the Plus button, everything is fine and the program performs as expected.
//newRowCount is assumed to be the amount of rows with Minus Buttons currently, only creates a new row if the table needs to expand
void TableTest::enableNewRow(){
newRowCount++;
if(newRowCount > table->rowCount()){
table->insertRow(table->rowCount());
for(int i = 0; i < table->columnSize(); ++i){
QTableWidgetItem* item = new QTableWidgetItem;
item->setFlags(item->flags() ^ Qt::ItemisEditable);
table->setItem(newRowCount, i, item);
//Code to set the previous column's item (newRowCount--) to have an Qt::ItemisEditable flag set to true
...
}
}
//Some button setup to make Plus button and create a new Minus button connect and do their jobs and move the Plus button down into the newly inserted row
...
}
void MainWindow::importFile(){
int settingRows = settings->beginReadArray("Groups");
for(int i = 0; i < settingRows; ++i){
settings->setArrayIndex(i);
//Will only add a new row if needed, check inside above function and all row items will be allocated if made
table->enableRow();
for(int j = 1; j < table->columnCount(); ++j){
table->item(i, j)->setText("testing");
}
}
}
And the program crashes with the following stack trace:
1 QWidget::show()
2 QAbstractItemView::updateEditorGeometries()
3 QAbstractItemView::updateGeometries()
4 QTableView::updateGeometries()
5 QTableView::timerEvent(QTimerEvent *)
6 QObject::event(QEvent *)
7 QWidget::event(QEvent *)
8 QFrame::event(QEvent* )
9 QAbstractScrollArea::event(QEvent* )
10 QAbstractItemView::event(QEvent* )
11-21 ... Not useful information about any of the code
22 QCoreApplication::exec()
23 main
However, it's all byte code and I can't actually inspect which line is crashing the code in any of the traces using the debugger. What I don't understand is that the same process for manually clicking the Plus button is being completed (I connect the click event of the Plus button to the enableRow() function) and when I programmatically call enableRow() from the QSettings loop in importFile() it will crash after it loops through all of the items.
Things to note: setting the base size of the table to the size of the QSettings array I'm reading from (i.e. if I want 10 rows, just setting 10 rows to begin with before setting the item texts will work correctly), however, I want the base size of the table upon creation to be something like 5. It seems once the loop goes beyond the row count I specified from the constructor, then the program will crash, but not at say, index 6, but only after it has completely looped through the table. It does not crash on any line such as QTableWidgetItem::setText or QTableWidget::setCellWidget(). I'm kind of confused and wondering if the table is populating too quickly for the QTableWidget::timerEvent on stack trace line 5. Nothing I do in the loop is any different than what I do when manipulating the table normally.
It turns out that the error was that I was setting the QTableWIdgetItem one row earlier than I should have been. I'm not sure why the table would be able to iterate up until the end of the QSettings loop before crashing, but that was essentially the error. I'm not quite sure why the stack trace was so cryptic.
in my enableRow() function, I actually posted above from memory the correct logic, which differed in my code's logic by 1 index previously for the row value. Why the code did not crash when using it normally with the buttons whose slots called the same function as the import() seems to baffle me, perhaps a case of undefined behavior.

QT: QTableView read cell content

I'm writing a small program with QT creator (QT 5.2.1) under Windows 7 (32 bit) and I'm having problems reading the informations stored in a TableView. My application has 3 elements, a TableView to store text data, a TextBrowser to show info and a buttom.
I modified the TableView properties: when the user selects with the mouse a cell, the full row is selected and multiple row selection is not allowed.
The user select a row and when the buttom is pressed, I would like to read the content of a specific TableView cell and show it in a TextBrowser. In particular, I would like to know the row index of the selected row and read the content of the cell with that row index and a specific column index (example 2).
The pseudo-code is this:
void my_program::on_pushButton_clicked()
{
ui->textBrowser->append("button pressed");
QItemSelectionModel *select = ui->tableView->selectionModel();
int index_row = select->selectedRows();
int index_column = 2;
char cell_data[30] = ??[index_row][index_column]
ui->textBrowser->append(cell_data);
}
The main problem is that select->selectedRows() returns a QModelIndex that is a collection of indexs and I do not know how to convert it to int (since multiple selection are not allowed, it should have only one element).
I would be glad if someone can suggest me a way to proceed.
Thanks
Francesco
edit:
Hi Bogdan, thanks a lot!! I succeed to read the cell content by using
ui->textBrowser->append(ui->tableView->model()->data(ui->tableView->model()->index(2,5)).toString());
this give me the content of the cell in position 2,5.
not sure if this is the best way or not but it works !!.
Can you be a bit more precise about how to iterate the QModeIndexList ? thanks :)
selectedRows() returns QModelIndexList, thus you need to iterate over it and call QModelIndex::data() to get stored data.

QTreeView / QAbstractItemModel - adding items and using beginInsertRows

I'm implementing my model based on QAbstractItemModel and I'm using it with QTreeView to display hierachical data. Data are stored in sqlite table.
My question is how should I call beginInsertRows when adding subnodes.
Lets say I have some parent node, it contains 10 subnodes. And I want to add new subnode (at the end).
I'm doing it like this:
beginInsertRows(parentIndex, currentNodesCount, currentNodesCount);
// actual inserting
endInsertRows()
currentNodesCount contains value 10 which is the number of rows in this subnode.
The new node will be placed at the 11th position (10th counting from 0).
Is this logic correct ?
Thanks for help.
I'm wondering also about using beginRemoveRows.
Is this correct:
beginRemoveRows(parentIndex, currentRow, currentRow);
// delete record
endRemoveRows();
currentRow contains position in the list of the removed node counting from 0.
Yes that's it.
Was this your only question?

Programmatically adding a new row to a QAbstractListModel subclass

Within an already-instantiated QAbstractListModel subclass, how do I add a row with data in each column, and have the associated QListView display the new row?
It seems that the only way to do it is to reimplement insertRow and setData within my model, and then hack them together in some sort of sequence within another function to add a row. Must I do this? Surely Qt must make it easier to add a new row.
Thanks much!
--Dany.
Just change your model's data storage, in between beginInsertRows() and endInsertRows().
For instance, let's say you have a flat list model and your model stores the data internally in a QVector m_data. You want to prepend the list, i.e. insert a row at position 0:
beginInsertRows( QModelIndex(), 0, 0 ); //notify views and proxy models that a line will be inserted
m_data.prepend( somedata ); // do the modification to the model data
endInsertRows(); //finish insertion, notify views/models
I'm afraid you have to do it that way. From the docs:
Models that provide interfaces to resizable list-like data structures can provide implementations of insertRows() and removeRows().

QTreeView: Setting all selected cells to the user-entered value at once

I have a QTreeView which has the ExtendedSelection attribute (users may select more than one non-contiguous range of cells).
I would like my app to allow them to select these multiple cells and then enter a value and have all the cells take that value.
My issue is that I don't know how to get the full range of cells passed to my model. Right now the index that is passed to the setData method is only the active cell, not the full range of selected cells.
In the past, I have had my view store the currently selected range in the model every time it changes, and then use that to control which cells to modify. This seems kind of hacky and I wonder whether anyone has a better and more elegant solution.
I am using PyQt by the way, though I suspect this applies to QT by itself.
Thanks!
I believe you can use selectionModel method of the QAbstractItemView class to iterate through selected indexes and change values of the corresponding cells. Below is a small example:
foreach (QModelIndex index, ui->treeView->selectionModel()->selectedIndexes())
{
qDebug() << "Changing index " << index.row();
ui->treeView->model()->setData(index, "new data");
}
hope this helps, regards

Resources