Deleting multiple rows in QTableView - qt

While searching for clues on how i can delete multiple rows from QTableView i came across this function: remove selected rows from QTableView
Here is the code:-
QItemSelection selection( ui.tableView->selectionModel()->selection() );
QList<int> rows;
foreach( const QModelIndex & index, selection.indexes() ) {
rows.append( index.row() );
}
qSort( rows );
int prev = -1;
for( int i = rows.count() - 1; i >= 0; i -= 1 ) {
int current = rows[i];
if( current != prev ) {
tableModel->removeRows( current, 1 );
prev = current;
}
}
I need help writing the query doing that.I have been trying this:-
query.exec(QString("DELETE FROM %1 id IN %2").arg(tableName,rows));
but i think i should be using QStringList somewhere but i am still reading the QList examples.Anyone?.

Since you seem to be using a QSqlTableModel:
in QSqlTableModel::OnFieldChange or OnRowChange modes, removeRows also deletes the records from the database.
in QSqlTableModel::OnManualSubmit mode you have to call QSqlTableModel::submitAll() at the end of the loop.
If you were using a QSqlQueryModel, you would have to subclass that model to implement the deletion within removeRows.

Related

QSqlTableModel, QTableView change columns not updated

I have a SQL model that connects to a single table, this table will change the number of columns depending on certain conditions during the execution of the program. The model is connected to a QTableView.
I have a function that controls the number of columns at the end of the function i have a call to model->select(), to update the information of the model and tableView->reset(), to what i thought would rearrange the view adding or taking away columns.
The problem is that the view does not change from the original number of columns that it had. If i reduce the number i can see that the data change and show empty on the missing columns. Is there a command for the tableView to resize it self?
Editing the question
in the constructor of the class i'm reading the table and setting it to the view:
header = new QSqlTableModel(parent,data->m_db);
header->setTable("C"+QString::number(markTime.toSecsSinceEpoch())+"T");
header->select();
ui->heading->setModel(header);
ui->heading->show();
Every time that that the number of columns is changed is an SQL procedure to change the number of columns:
void ImportProcess::copyTable(QString oldTable, QString newTable)
{
QSqlQuery queryOld, queryNew;
queryOld.prepare("select * from :oldTable");
queryOld.bindValue(":oldTable",oldTable);
queryOld.exec();
if(queryOld.record().isEmpty()==true) return; //Old table was empty, nothing to copy
int oldColumn=queryOld.record().count();
QString replaceLine="insert into "+newTable+" values(";
while(queryOld.next()==true)
{
replaceLine.append(QString::number(queryOld.value(0).toInt()));
replaceLine.append(", "+queryOld.value(1).toString());
for(int y=0;y<(oldColumn < ui->columns->value() ? oldColumn : ui->columns->value());y++)
{
replaceLine.append(", "+QString::number(queryOld.value(y+2).toFloat()));
}
replaceLine.append(")");
queryNew.exec(replaceLine);
}
}
Then the header file is updated, and here is where I thought that the tableview will be redrawn:
void ImportProcess::updateHeadingTable()
{
QSqlQuery query;
query.exec("delete from C"+QString::number(markTime.toSecsSinceEpoch())+"T");
QString description= ui->Week->isChecked() == true ? "Week" : "Size";
query.exec("insert into C"+QString::number(markTime.toSecsSinceEpoch())+"T (id, description) values (101, '"+description+"')");
for(int x=0;x<ui->columns->value();x++)
{
query.exec("update C"+QString::number(markTime.toSecsSinceEpoch())+"T set col"+QString::number(x)+" = '30'");
}
header->select();
ui->heading->reset();
}
I believe you forgot about some protected methods:
void QAbstractItemModel::beginInsertColumns(const QModelIndex &parent, int first, int last);
void QAbstractItemModel::beginRemoveColumns(const QModelIndex &parent, int first, int last);
void QAbstractItemModel::endInsertColumns();
void QAbstractItemModel::endRemoveColumns();
Every time the number of column about to be change you should call first or second method. After change you should call third or fours method.
You can read about these methods in Qt documentation.

Want to execute a QString statement, which has the last part as integer variable

The statement is:
int nmbr;
QString strngs;
for( nmbr = 62; nmbr <65; nmbr++)
{
strngs=(QString)"qDebug()<<(QString)ui->label_"+QString::number(nmbr)+"->text();";
}
Actually I want to access QLabels, a lot of them and extract their text for using at some other place.
Thanks!
Are you trying to get the text from a lot of QLabels of a current widget?
Then you'd better do something like that:
for( int nmbr = 62; nmbr <65; nmbr++)
{
QString labelname = QString("label_%1") .arg( nmbr );
QLabel * label = findChild<QLabel*>( labelname );
if ( label )
qDebug() << label->text();
}
Is this what you're looking for?

QGraphicsItem: Why no `stackAfter` method?

I'm having an annoying time trying to get around the 'recommended' way of doing something.
So, I have a stack of cards. I want to make it so that when I deal a card, it becomes the last-drawn object of the entire scene (typical bring_to_front functionality).
The recommended way to do this is just adding to the object's zValue until it is larger than all the rest, but I was hoping to do away with rather "lazy" integers running around all over the place with judicious use of the stackBefore method, which simulates reorganizing the order in which objects were added to the scene.
This works perfectly fine when I shuffle my cards in a limited set (get list of selected items, random.shuffle, for item do item.stackBefore(next item)), but it is certainly not working when it comes to bubbling the card to the top of the entire scene.
I considered adding a copy of the object to the scene and then removing the original, but it just seems like I should be able to do stackAfter like I would when using a Python list (or insertAt or something).
Sample code:
def deal_items(self):
if not self.selection_is_stack():
self.statusBar().showMessage("You must deal from a stack")
return
item_list = self.scene.sorted_selection()
for i,item in enumerate(item_list[::-1]):
width = item.boundingRect().width()
item.moveBy(width+i*width*0.6,0)
another_list = self.scene.items()[::-1]
idx = another_list.index(item)
for another_item in another_list[idx+1:]:
another_item.stackBefore(item)
This works. It just seems somewhat... ugly.
self.scene.items returns the items in the stacking order (link). So if you want to stackAfter an item, you can just query the z value of the current topmost item and then set the z value of the new topmost card to a value one larger.
item.setZValue(self.scene.items().first().zValue() + 1)
Hope that helps.
Edit added src for stackBefore and setZValue from http://gitorious.org/qt/
src/gui/graphicsview/qgraphicsitem.cpp
void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
{
if (sibling == this)
return;
if (!sibling || d_ptr->parent != sibling->parentItem()) {
qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
return;
}
QList<QGraphicsItem *> *siblings = d_ptr->parent
? &d_ptr->parent->d_ptr->children
: (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0);
if (!siblings) {
qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
return;
}
// First, make sure that the sibling indexes have no holes. This also
// marks the children list for sorting.
if (d_ptr->parent)
d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
else
d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
// Only move items with the same Z value, and that need moving.
int siblingIndex = sibling->d_ptr->siblingIndex;
int myIndex = d_ptr->siblingIndex;
if (myIndex >= siblingIndex) {
siblings->move(myIndex, siblingIndex);
// Fixup the insertion ordering.
for (int i = 0; i < siblings->size(); ++i) {
int &index = siblings->at(i)->d_ptr->siblingIndex;
if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
++index;
}
d_ptr->siblingIndex = siblingIndex;
for (int i = 0; i < siblings->size(); ++i) {
int &index = siblings->at(i)->d_ptr->siblingIndex;
if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
siblings->at(i)->d_ptr->siblingOrderChange();
}
d_ptr->siblingOrderChange();
}
}
void QGraphicsItem::setZValue(qreal z)
{
const QVariant newZVariant(itemChange(ItemZValueChange, z));
qreal newZ = newZVariant.toReal();
if (newZ == d_ptr->z)
return;
if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
// Z Value has changed, we have to notify the index.
d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
}
d_ptr->z = newZ;
if (d_ptr->parent)
d_ptr->parent->d_ptr->needSortChildren = 1;
else if (d_ptr->scene)
d_ptr->scene->d_func()->needSortTopLevelItems = 1;
if (d_ptr->scene)
d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
itemChange(ItemZValueHasChanged, newZVariant);
if (d_ptr->flags & ItemNegativeZStacksBehindParent)
setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));
if (d_ptr->isObject)
emit static_cast<QGraphicsObject *>(this)->zChanged();
}

QFileSystemModel sorting DirsFirst

How do you do to sort a QFileSystemModel with QDir::DirsFirst like in QDirModel?
The QFileSystemModel does not have a setSorting method.
Maybe somebody will need this. I have implemented directories first sorting using QSortFilterProxyModel for QFileSystemModel as Kuba Ober mention in comment.
Might be not perfect yet, but still right direction.
bool MySortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
// If sorting by file names column
if (sortColumn() == 0) {
QFileSystemModel *fsm = qobject_cast<QFileSystemModel*>(sourceModel());
bool asc = sortOrder() == Qt::AscendingOrder ? true : false;
QFileInfo leftFileInfo = fsm->fileInfo(left);
QFileInfo rightFileInfo = fsm->fileInfo(right);
// If DotAndDot move in the beginning
if (sourceModel()->data(left).toString() == "..")
return asc;
if (sourceModel()->data(right).toString() == "..")
return !asc;
// Move dirs upper
if (!leftFileInfo.isDir() && rightFileInfo.isDir()) {
return !asc;
}
if (leftFileInfo.isDir() && !rightFileInfo.isDir()) {
return asc;
}
}
return QSortFilterProxyModel::lessThan(left, right);
}
As far as I can tell, you can't (in Qt4).
The default sort order (by the "name" column), or sorting by size behaves like QDir::DirsFirst (or DirsLast if in reverse order for ), but sorting by time or type doesn't treat directories differently from ordinary files.
The QFileSystemModel doesn't expose an API for changing the sort order, and I don't see any opportunity for influencing it in the QFileSystemModel code.
(I don't see anything in the current Qt5 docs to indicate that this has changed, but those aren't final and I haven't looked very closely.)

how to get selected rows in QTableView

After watching many threads about getting selected rows numbers, I am really confused.
How do you get ROW numbers in QTableView using QStandardItemModel I used below selection model and behavior as
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
and if you have your own way of selecting can you explain how it works.
Thanks for the help!
The method selectionModel() return a QItemSelectionModel.
You can use QItemSelectionModel class to check/change/other selection(s)
Example:
QItemSelectionModel *select = table->selectionModel();
select->hasSelection() //check if has selection
select->selectedRows() // return selected row(s)
select->selectedColumns() // return selected column(s)
...
Check selectedRows method of the QItemSelectionModel Class .
QModelIndexList selection = yourTableView->selectionModel()->selectedRows();
// Multiple rows can be selected
for(int i=0; i< selection.count(); i++)
{
QModelIndex index = selection.at(i);
qDebug() << index.row();
}
try:
QModelIndexList indexList = yourTableView->selectionModel()->selectedIndexes();
int row;
foreach (QModelIndex index, indexList) {
row = index.row();
....
}
Since you use
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
so only one row can be selected each time, then you can try this:
auto rowList = yourTableView->selectionModel()->selectedRows();
if(rowList.count() > 0)
int rowNumber = rowList.constFirst().row();
else
// no row is selected

Resources