Maxim Popravko
Maxim Popravko

Reputation: 4159

Row, deleted from model, stays in view, what am I doing wrong?

I have QTableView, filled by QSqlRelationalTableModel. Changes should be committed or reverted on button hit. When I edit some row, it changes state in the view when editing finishes, and succesfully commits changes to DB when submitAll() called. But when I trying to delete row, it stays in view. Here is slot, connected to Remove button:

def _removeSelectedStatuses(self):
    '''
    Удаляет выбранные строки из таблицы

    pre[self]: self._model is not None
    '''
    model = self.ConservationStatusesTableView.selectionModel()
    l = model.selectedRows()
    if not len(l): return

    rows = set([i.row() for i in l])
    rows = list(rows)
    rows.sort()
    first = rows[0]
    count = len(rows)
    self._model.removeRows(first, count)

What am I doing wrong?

Upvotes: 6

Views: 3978

Answers (4)

StarterKit
StarterKit

Reputation: 585

I faced the same problem recently and found another solution for myself. You may use QTableView.setRowHidden() method after QSqlTableModel.deleteRow() if you have only one QTableView connected to this model. Works fine.

(I would prefere to strike out text in custom paint delegate... but I failed to find suitable flag to distinguish non-coommited rows.)

Upvotes: 2

sindhu
sindhu

Reputation: 1

If you want to remove the selected row from a model you just need to call:model->removeRow(row); Here row is the row number of which you want to delete. This works fine for me.

Upvotes: 0

Maxim Popravko
Maxim Popravko

Reputation: 4159

I investigated, that this nasty behaviour is by design. Rows are deleted from model on commit, and no views know, which rows must be drawn and which aren't. Only thing done when rows removed from model is '!' marker in header.model().headerData(index, vert).text(). And it's disgusting.

I'm ashamed the way I fixed the problem, but here is my ugly hack:

from PyQt4 import QtGui
from PyQt4 import QtSql
from PyQt4 import QtCore

class SqlTableView(QtGui.QTableView):
    '''
    Представление, которое не показывает удалённые столбцы, 
    когда коммит ещё не прошёл
    '''


    def __init__(self, parent = None):
        '''
        Конструктор
        '''
        QtGui.QTableView.__init__(self, parent)

    def setModel(self, model):
        '''
        Мы не можем соединиться с моделями, не являющимися QSqlTableModel
        '''
        assert isinstance(model, QtSql.QSqlTableModel)
        QtGui.QTableView.setModel(self, model)

    def paintEvent(self, event):
        '''
        Тут всё и происходит. Осторожно, может стошнить.
        '''
        if self.model() is not None:
            header = self.verticalHeader()
            hm = header.model()
            for i in range(hm.rowCount()):
                if (hm.headerData(i, QtCore.Qt.Vertical).toPyObject() == '!' 
                    and not header.isSectionHidden(i)):
                    header.hideSection(i)
                elif (header.isSectionHidden(i) and 
                    hm.headerData(i, QtCore.Qt.Vertical).toPyObject() != '!'):
                    header.showSection(i)
        PyQt4.QtGui.QTableView.paintEvent(self, event)

I also added it to QtDesigner to simplify interface design.

Second solution, not so nasty:

class PSqlRelationalTableModel : public QSqlRelationalTableModel
{
    Q_OBJECT

public:
    explicit PSqlRelationalTableModel(QObject *parent = 0, 
        QSqlDatabase db = QSqlDatabase());
    virtual ~PSqlRelationalTableModel();

    bool removeRows(int row, int count, 
        const QModelIndex &parent = QModelIndex());

public slots:
    void revertRow(int row);

signals:
    void rowIsMarkedForDeletion(int index);
    void rowDeletionMarkRemoved(int index);

private:
    QSet<unsigned int> rowsToDelete;
};

//////////////////////////////////////////////////////////////////
void PTableView::setModel(PSqlRelationalTableModel *model)
{
    connect(model, SIGNAL(rowIsMarkedForDeletion(int)), 
        this, SLOT(onRowMarkedForDeletion(int)));
    connect(model, SIGNAL(rowDeletionMarkRemoved(int)), 
        this, SLOT(onRowDeletionMarkRemoved(int)));
    QTableView::setModel(model);
}

void PTableView::onRowMarkedForDeletion(int index)
{
    QHeaderView *hv = verticalHeader();
    hv->hideSection(index);
}

void PTableView::onRowDeletionMarkRemoved(int index)
{
    QHeaderView *hv = verticalHeader();
    hv->showSection(index);
}

Upvotes: 1

Andy M
Andy M

Reputation: 6065

Did you implement the removeRows method ?

Have a look here :

pyqt: Trying to understand insertrows for QAbstractDataModel and QTreeView

I guess what is missing is simply a emitDataChanged that tells the view that something changed ! Without that, the view cannot know if it has to refresh itself !

Hope this helps !

Upvotes: 1

Related Questions