PDA

View Full Version : [PyQt4] QSortFilterProxyModel doesn't work with my simple custom model



draGy
5th July 2009, 07:35
Hi,

I want to use the QSortFilterProxyModel on my custom model for sorting/filtering purpose. But when applying it, the list in my TableView is empty.

If I do not use my custom model, but the QStandardItemModel (as in the examples "basic sort/filter model"), it works.

So it seems my custom model is at fault here, although it works just fine if I do not use the QSortFilterProxyModel.
Does my custom model require additional method implementations for it to work?
Or do I have subclass the QSortFilterProxyModel? If so, what would I need to change?

Here is my custom model:

class MyTableModel(QAbstractTableModel):
def __init__(self, datain, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.arraydata = datain

def rowCount(self, parent):
return len(self.arraydata)

def columnCount(self, parent):
return len(self.arraydata[0])

def data(self, index, role):
if not index.isValid():
return QVariant()
elif role != Qt.DisplayRole:
return QVariant()
return QVariant(self.arraydata[index.row()][index.column()])

wysota
5th July 2009, 08:42
How do you add data to your model? Do you remember about emitting signals?

draGy
5th July 2009, 08:57
In this simple programm I have an array

my_array = [['00','01','02'],
['10','11','12'],
['20','21','22']]
which will be given to the constructor of the model.

tablemodel = MyTableModel(my_array, self)

At this stage I simply want to display my model. Later on I will add the necessary methods where I can add items to the model. Or do I need these methods already for the sorting/filtering?

As for "emmiting signals" I am not sure what you are getting at. I know the idea behind the signal/slot thing, but I don't see where I need it in my model or view.

wysota
5th July 2009, 09:05
Can you show us the code where you use the sort filter proxy model?

draGy
5th July 2009, 09:18
here it is:


myView = QTableView()
myModel = MyTableModel(my_array)
proxyModel = QSortFilterProxyModel()
proxyModel.setSourceModel(myModel)
#proxyModel.setDynamicSortFilter(True)
myView.setModel(proxyModel)

wysota
5th July 2009, 09:41
The code looks fine, could you check what does columnCount() return for both the source model and the proxy?

draGy
5th July 2009, 09:48
I added the print statement, so I can see what will be returned.


def columnCount(self, parent):
print(len(self.arraydata[0]))
return len(self.arraydata[0])


as well for
myView.setModel(proxyModel)
as for
myView.setModel(myModel)

it always returns 3

wysota
5th July 2009, 10:04
It's not what I mean. Call columnCount() on both the proxy and the source model and print the result. It is important to see what the proxy reports (0 or 3).

By the way, if you omit the proxy then the view displays the data properly, correct?

draGy
5th July 2009, 10:14
print("proxyModel:")
print(proxyModel.columnCount(QModelIndex()))
print("myModel:")
print(myModel.columnCount(QModelIndex()))


results in:


proxyModel:
3
myModel:
3




By the way, if you omit the proxy then the view displays the data properly, correct?
yes. It works fine without the proxy model.

Ps: I will be out for a few hours (so my next reply won't be coming right away :D).
And before I forget it: thanks for the fast replies.

wysota
5th July 2009, 10:16
The only thing that comes to my mind is that you didn't implement the parent() method although it might already be implemented for the table model. On the other hand it wouldn't hurt to return an empty model index from it. Also make sure you return non-zero values of rowCount and columnCount only if the parent index is invalid.

draGy
5th July 2009, 14:45
Would anyone have an example where QSortFilterProxyModel is used with a custom model?
Preferably for PyQt.

wysota
5th July 2009, 14:58
I do (in c++) :) But your code really looks fine apart from ignoring the parent indexes.

Here is a complete working example:

#include <QAbstractTableModel>
#include <QSortFilterProxyModel>
#include <QTableView>
#include <QApplication>


class Model : public QAbstractTableModel {
public:
Model() : QAbstractTableModel(){
for(int i=0;i<3;i++){
QVector<int> row;
for(int j=0;j<3;j++)
row << qrand()%100;
m_data << row;
}
}
int rowCount(const QModelIndex &parent = QModelIndex()) const {
return m_data.size();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const {
return m_data.at(0).size();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
if(!index.isValid()) return QVariant();
else if(role!=Qt::DisplayRole) return QVariant();
return m_data[index.row()][index.column()];
}
private:
QVector< QVector<int> > m_data;
};

int main(int argc, char **argv){
QApplication app(argc, argv);
Model model;
QSortFilterProxyModel proxy;
proxy.setSourceModel(&model);
QTableView tv;
tv.setModel(&proxy);
tv.show();
return app.exec();
}

Check if the problem is not outside the model class (i.e. maybe the proxy model gets deleted somewhere inbetween setting it on the view and launching the application).

draGy
5th July 2009, 16:03
Hi,

thanks for that little example.
I converted it in python and it works. I will not try to find out whats wrong with my programm with the help of that code.
When I find the solution I will post it here.
Thanks again.

Here they python code:


import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Model(QAbstractTableModel):
def __init__(self, parent=None):
QAbstractTableModel.__init__(self, parent)
self.m_data = [["1","2","3"],["4","5","6"],["7","8","9"]]

def rowCount(self, parent=QModelIndex()):
return len(self.m_data)

def columnCount(self, parent=QModelIndex()):
return len(self.m_data[0])

def data(self, index, role = Qt.DisplayRole):
if(not index.isValid()):
return QVariant()
elif(role!=Qt.DisplayRole):
return QVariant()
return QVariant(self.m_data[index.row()][index.column()])

if __name__ == "__main__":
app = QApplication(sys.argv);
model = Model()
proxy = QSortFilterProxyModel()
proxy.setSourceModel(model)
tv = QTableView()
tv.setModel(proxy);
tv.show();
sys.exit(app.exec_())


Oh man, you were so right.

I wasn't the fault of the model.
I thought once I set
proxyModel.setSourceModel(myModel)
that myModel would be referenced by proxyModel and thus stay alive. But apparently it got deleted after the method exited and thus I never saw something.

I now saved it as an instance variable (instead of an local variable) and now it works.


Man, the whole day got wasted, just because of this.

Well anyways, thanks a lot for your help!