okcerg / sortfilterproxymodel Goto Github PK
View Code? Open in Web Editor NEWA nicely exposed QSortFilterProxyModel for QML
License: MIT License
A nicely exposed QSortFilterProxyModel for QML
License: MIT License
Hi,
I am fairly new to QT and Cpp so maybe I missed something really obvious, but I can't figure it out myself. I would like to use your lib, but after a qpm install and an include in my project file I got some errors. I also tried downloading your repo and including you project file, but I got the same errors.
I got lots of undefined reference to 'vtable' errors. Here I just showed one, but I got loads of errors.
<path>\sortfilterproxymodel\qqmlsortfilterproxymodel.cpp:8: error: undefined reference to `vtable for QQmlSortFilterProxyModel'
This is my project file
QT += qml quick serialport quickcontrols2
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp \
qlibdivecomputer.cpp \
dccomputerlist.cpp \
sessionstore.cpp
HEADERS += \
qlibdivecomputer.h \
dccomputerlist.h \
sessionstore.h
RESOURCES += qml.qrc
DESTDIR = bin
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
unix|win32: LIBS += -L$$PWD/libdivecomputer/lib/ -llibdivecomputer
INCLUDEPATH += $$PWD/libdivecomputer/include
DEPENDPATH += $$PWD/libdivecomputer/include
include(vendor/vendor.pri)
at Line 441 qmlRegisterType("SortFilterProxyModel", 0, 2, "RegexpFilter");
according to documentation/sample complex filtering & camel case tradition at there the "E" is uppercase in "ExpFilter" like
qmlRegisterType<RegexpFilter>("SortFilterProxyModel", 0, 2, "RegExpFilter");
Class name could be also in camel case
Your public slots should all be public member functions instead, since you are exposing them to QML as QML properties. Exposing them as public slots is somewhat redundant.
First filtering operation is very slow, and then it was well for nex filtering, what caused this problem?
problem above:
Compilation fails if the main project uses CONFIG+=no_keywords, due to the suage of "signals" "slots" and "emit".
Hi,
First of all great work :)
Second: Possible to release version 0.1.1 via qpm?
In general, when we are using Expression {} filter, the return value of the expression is determined by a fixed list of roles.
For example, a code looks like:
SortFilterProxyModel {
id: brokenObjectsModel
sourceModel: myControlledObjectsModel
filtres: [
ExprrssionFilter {
expression: { return model.telemetry.status & 0b00110010 // some bitmask to detect broken objects
}
]
}
SortFilterProxyModel {
id: allActiveObjectsModel
sourceModel: myControlledObjectsModel
filtres: [
ExprrssionFilter {
expression: { return model.status.isActive }
triggerOnRoles: [ 'status' ] // List only roles affecting the result of expression
}
]
}
My suggestion is: for the allActiveObjectsModel the 'telemetry' role does never change the result of filtering. So, we really should not call the expression and waste cpu time on it.
Do not have a nice idea how to implement this, let it be a long-term issue.
The types and properties exposed by this module should be documented in the source code.
It would be good to have the proxy model's count exposed
When configuring filtering directly using filterRoleName, filterValue - the model is filtered in unpredictable way. But when using filters[] property, the filtering is correct.
Please see the example code:
ListModel {
id: bugTestModel
Component.onCompleted: {
bugTestModel.append({ col1: '1', col2: '1' })
bugTestModel.append({ col1: '2', col2: '1' })
bugTestModel.append({ col1: '3', col2: '2' })
bugTestModel.append({ col1: '4', col2: '2' })
bugTestModel.append({ col1: '5', col2: '1' })
bugTestModel.append({ col1: '6', col2: '1' })
bugTestModel.append({ col1: '7', col2: '2' })
bugTestModel.append({ col1: '8', col2: '2' })
}
}
SortFilterProxyModel {
id: bugTestProxy1
sourceModel: bugTestModel
filterRoleName: 'col2'
filterValue: '2'
}
SortFilterProxyModel {
id: bugTestProxy2
sourceModel: bugTestModel
filters: [
ValueFilter {
enabled: true
roleName: 'col2'
value: '2'
}
]
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log('in bugTestProxy1 count:', bugTestProxy1.count)
for (var i = 0; i < bugTestProxy1.count; i++) {
var row = bugTestProxy1.sourceModel.get(bugTestProxy1.mapRowToSource(i))
console.log(' ', row.col1, row.col2)
}
console.log('in bugTestProxy2 count:', bugTestProxy2.count)
for (var i = 0; i < bugTestProxy2.count; i++) {
var row = bugTestProxy2.sourceModel.get(bugTestProxy2.mapRowToSource(i))
console.log(' ', row.col1, row.col2)
}
}
}
The result is:
qml: in bugTestProxy1 count: 1
qml: 2 1
qml: in bugTestProxy2 count: 4
qml: 3 2
qml: 4 2
qml: 7 2
qml: 8 2
~/$ qpm install fr.grecko.sortfilterproxymodel
INFO: Package fr.grecko.sortfilterproxymodel has a different license (MIT) than it's dependant (NONE).
Installing [email protected]
~/$ ls vendor/fr/grecko/sortfilterproxymodel/
LICENSE qqmlsortfilterproxymodel.cpp
SortFilterProxyModel.pri qqmlsortfilterproxymodel.h
qpm.json
I suspect because this
Line 13 in 99d89d8
v.0.1.0
, but I'm unfamiliar with qpm
so this is just a guess.
P.S. Why am I just now finding this project? It's awesome, and I implemented a far inferior version for some auto-complete text boxes I made. Thanks a million!
How do I use this SortFilterProxyModel which is in c ++ with PyQt??
If sourceModel is empty and you append entries later, SortFilterProxyModel
stops working.
I made a testcase from your example. If you remove the comment, everything works as expected.
import QtQuick 2.2
import QtQuick.Controls 2.0
import SortFilterProxyModel 0.1
ApplicationWindow {
visible: true
width: 640
height: 480
Timer {
interval: 500; running: true; repeat: false
onTriggered: {
personModel.append({
firstName: "Erwan",
lastName: "Castex"
});
personModel.append({
firstName: "Some",
lastName: "Foo"
});
personModel.append({
firstName: "Another",
lastName: "Bar"
});
}
}
ListModel {
id: personModel
// ListElement { firstName: "inital"; lastName: "data" }
}
TextField {
id: textField
anchors { top: parent.top; left: parent.left; right: parent.right }
height: implicitHeight
}
SortFilterProxyModel {
id: filteredPersonModel
sourceModel: personModel
filterRoleName: "lastName"
filterPattern: textField.text
filterCaseSensitivity: Qt.CaseInsensitive
}
ListView {
width: parent.width / 2
anchors { top: textField.bottom; bottom: parent.bottom; left: parent.left; }
model: filteredPersonModel
delegate: Text { text: firstName + " " + lastName }
}
ListView {
width: parent.width / 2
anchors { top: textField.bottom; bottom: parent.bottom; right: parent.right }
model: personModel
delegate: Text { text: firstName + " " + lastName }
}
}
When using it on a large model, let's say starting from 10k items and more then the performance is not great. If the number of items is larger then 20k then the problem becomes significantly noticeable.
SortFilterProxyModel {
id: proxyModel
filters: AnyOf {
RegExpFilter {
roleName: "role1"
pattern: searchInput
caseSensitivity: Qt.CaseInsensitive
}
RegExpFilter {
roleName: "role2"
pattern: searchInput
caseSensitivity: Qt.CaseInsensitive
}
}
sorters: RoleSorter {
roleName: "role2"
sortOrder: Qt.AscendingOrder
}
}
Above is a snippet of how I'm using it.
Great work and API overall.
Cheers,
Petref
class SwitchRole : public SingleRole, public FilterContainer
{
Q_OBJECT
Q_INTERFACES(qqsfpm::FilterContainer)
Q_PROPERTY(QString defaultRoleName READ defaultRoleName WRITE setDefaultRoleName NOTIFY defaultRoleNameChanged)
Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue NOTIFY defaultValueChanged)
Q_PROPERTY(QQmlListPropertyqqsfpm::Filter filters READ filtersListProperty)
public:
using ProxyRole::ProxyRole;
ProxyRole is not a direct base for SwitchRole, so inherit constructors are prohibited
One thing I've noticed recently is that (presumably) changes in the QML debugger have started to cause crashes in qqsfpm. It seems that the debugger sometimes ends up (for whatever reason) in calling qqsfpm::data with an invalid index, which ultimately results in sourceModel() returning nullptr, and thus a nullptr de-reference. My fix is as follows, which is probably no bad thing anyway.
QVariant QQmlSortFilterProxyModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
return {};
return sourceData(mapToSource(index), role);
}
To be published, need your instuctions.
if sortOrder is not specified, defining sortRoleName has no effect
The readme in the filters-and-sorters branch should show some usage of the new properties and types.
The documentation of those properties should be externalized and not put on the readme.
Model
role1
role2
role3
Label {
text: role1
}
Label {
text: role2
}
//role 1 changes, role 2 is re-evaluated as well
//with 0 filters/sorters
It seemed that when appending dict in Json array to ListModel, proxymodel crashes.
It would be great if someone can reproduce this.
I am running on windows 10, using QT 5.9.2
The testing code snippet is attached below.
if I split array and attach entry separately, everything works fine.
ListModel {
id: test
// ListElement {
// first_name: "Erwan"
// last_name: "Castex"
// count: 100
// sum: 99.99
// ssn: "xxxxxxx"
// }
// ...
Component.onCompleted: {
// test.clear()
// test.append({first_name:"jun", last_name:"yan", count:100, sum: 888, ssn:"xxx"})
}
}
SortFilterProxyModel{
id: _proxy_model
sourceModel: _model
sorters: StringSorter{ roleName: "first_name"}
}
Timer{
interval: 2000
running: true
repeat: true
property int rand: 1
onTriggered: {
test.clear()
// test.append([
// {first_name:"jun" + (++rand).toString(), last_name:"yan", count:100, sum: 888, ssn:"xxx"},
// {first_name:"jis" + (++rand).toString(), last_name:"yan", count:100, sum: 888, ssn:"xxx"}
// ])
test.append(
{first_name:"jun" + (++rand).toString(), last_name:"yan", count:100, sum: 888, ssn:"xxx"}
)
test.append(
{first_name:"jin" + (++rand).toString(), last_name:"yan", count:100, sum: 888, ssn:"xxx"}
)
}
I'd like to implement a model with user selected elements (a file explorer). I want to add a Boolean property to each item provided by the model. It looks like this code only provides sorting and selection but no ability to modify the model data? Thanks
I have already implemented that, need to cleanup my code and contribute it for you.
Are implemented, running in my production, but I do not know how to contribute it.
ValueInListFilter {
roleName: 'someN'
value: [ 'some1', 'some2', 'just5' ]
}
Depends on #9
Write some tests,
Decide first with what test framework those should be written with, and then what to test and how.
Hi
I am trying to use filterPattern to hide from the list view. Default, it displays only what is filtered but now I would like it to hide the filtered and display the rest. Is there a get around for this?
Thanks!!
I already download the deposit, and i added include(SortFilterProxyModel/SortFilterProxyModel.pri) in my .pro, but When I put "import SortFilterProxyModel 0.2"
i have this error: qrc:/main.qml:04 module "SortFilterProxyModel" is not installed
so please i need help
When ValueFilter's property enabled is changed, the filtering is'nt applied.
The fix :
filter.cpp L23
replace it with :
emit invalidate();
Good work though ๐
Hi, i have custom model which derivative from QAbstractListModel, custom model could be updated by backend at any time and i will sort that in custom model, the custom model goes to SortFilterProxyModel for filtering, sorting and filtering are ok but transition effect for move and moveDisplaced doesn't work anymore, i have eliminated SortFilterProxyModel and the effects comes.
also i have disabled sorting in my custom model, with SortFilterProxyModel sorting is ok by the effects are gone.
in my custom model, i just have used beginMoveRows endMoveRows for swaping rows.
In the sortFilterPoxyModel, it is not possible to know when these one has finished the filtering of an input list that has just been changed which for example doesn't allow the positionning of a listView on modification of the input list.
To realize that, follow these steps:
- Modification of the input list of the sortFilterPoxyModel on user's action
- Tracing of the input list changed event
- Tracing of the contentHeightChanged event of the listView
After the input list change event, we observe that few contentHeightChanged events are thrown which means that the filtering is still running.
The problem is that we can't know when this filtering is finished which doesn't allow to perform actions successive to input list changing.
A nice solution would be to throw an event after the filtering is done.
Best regards
Similar bug to #14 with filter being disabled not triggering a filtering change.
I think this is a big missing API in QML, so I would like to see it at codereview.qt-project.org, I can help to get it in there, if it is needed.
That should be real;y a nice feature for tricky models. See example in code:
SortFilterProxyModel {
// ...
filters: [
Function {
property real minSomething
property real maxSomething
acceptsRow: function(row) {
if (row.somerole.something > minSomething && row.somerole.something < maxSomething) { return true }
else if (Math.random() < 0.1) { return true }
else { return false }
}
}
]
}
I need filtering for SortFilterProxyModel.FixedString
but with a "does not equal to" functionality.
I dont think this feature exists yet and I would like to suggest it as a feature request. I am not familiar enough with the library to implement it on my own.
I dont want to use regexes with negative look aheads as I would have to escape the search string beforehand.
Should be very usefull as extension of ValueFilter. See example code:
SortFilterProxyModel {
// ...
filters: [
ValueInListFilter {
RoleName: 'some_key_role'
valueList: [ 'key1', 'key2', 'key3']
// Filter should accept row if (row.some_key_role in valueList)
}
]
}
For example when no minimumValue
is set, the minimumValue is still compared to the role value as if it was an invalid QVariant.
This can lead to rows being filtered out when they should instead be kept.
Hi
The widget looks awesome and is a life saver once it works.
The only thing is when i use the copy and pasted code with just changing out the model for my list model it won't work.
It gives me this error:
Cannot assign to non-existent property "sorters"
I've included the vendor/vendors.pri already and included the qml import but it still won't work properly.
It's like its not registered by qml as the sorting and filters properties both have red lines under them.
And off topic but in the near future are you planning on implementing a Date or Other types of sorters?
At the moment I only see StringSorter.
Thank you and your help will be much appreciated.
It could be dup with #30
One of th typical DB join query will have the following shape.
Group Value
A 1
A 2
B 1
B 3
I can do 2 queries but would it be convenient if it provides UNIQUE filter?
To test out SortFilterProxyModel, I made a very simple stopwatch application that utilizes a QAbstractListModel for the base model to store time elapsed and differences in times between laps. A SortFilterProxyModel is then used to sort the data in descending order of elapsed time so the newer entries appear first in my ListView.
Anyway, while initially trying to use the proxy model in the main QML file, it did not appear to work. Debugging the underlying class showed that sortOrder was being set before sortRoleName despite the order being flipped in the QML declaration. This caused sorting to not work as intended. Setting sortOrder in QML first before setting the sortRoleName was necessary in order for the instance of SortFilterProxyModel to do its job and sort the data the way I wanted. Here is how I am using the SortFilterProxyModel in QML.
SortFilterProxyModel {
id: filteredLapModel
sourceModel: testModel
sortOrder: Qt.DescendingOrder
sortRoleName: "lapTime"
}
Is this expected behavior? I would normally want to set the sortRoleName before the sortOrder. Is there any way to change the behavior so sortRoleName can be declared first in the QML declaration and work?
That will be nice if the model is availiable as a standalone QML plugin, for example when running QML application from PyQT.
Code of plugin.cpp:
#include <qqmlsortfilterproxymodel.h>
#include <sorter.h>
#include <filter.h>
#include <QtQml/QQmlExtensionPlugin>
#include <QtQml/qqml.h>
using namespace qqsfpm;
class QExampleQmlPlugin : public QQmlExtensionPlugin {
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri) {
Q_ASSERT(uri == QLatin1String("QQSFPM"));
qmlRegisterType<QQmlSortFilterProxyModel>(uri, 0, 2, "SortFilterProxyModel");
qmlRegisterUncreatableType<Sorter>(uri, 0, 2, "Sorter", "Sorter is an abstract class");
qmlRegisterType<RoleSorter>(uri, 0, 2, "RoleSorter");
qmlRegisterType<ExpressionSorter>(uri, 0, 2, "ExpressionSorter");
qmlRegisterUncreatableType<Filter>(uri, 0, 2, "Filter", "Filter is an abstract class");
qmlRegisterType<ValueFilter>(uri, 0, 2, "ValueFilter");
qmlRegisterType<IndexFilter>(uri, 0, 2, "IndexFilter");
qmlRegisterType<RegExpFilter>(uri, 0, 2, "RegExpFilter");
qmlRegisterType<RangeFilter>(uri, 0, 2, "RangeFilter");
qmlRegisterType<ExpressionFilter>(uri, 0, 2, "ExpressionFilter");
qmlRegisterType<AnyOfFilter>(uri, 0, 2, "AnyOf");
qmlRegisterType<AllOfFilter>(uri, 0, 2, "AllOf");
}
};
#include "plugin.moc"
Code of SortFilterProxyModel.pro to build a standalone plugin library using qmake:
!c++11: warning("SortFilterProxyModel needs c++11, add CONFIG += c++11 to your .pro")
TEMPLATE = lib
CONFIG += plugin
QT += qml
INCLUDEPATH += $$PWD
TARGET = qmlqsortfilterproxymodelplugin
SOURCES += $$PWD/qqmlsortfilterproxymodel.cpp \
$$PWD/filter.cpp \
$$PWD/sorter.cpp \
$$PWD/plugin.cpp
HEADERS += $$PWD/qqmlsortfilterproxymodel.h \
$$PWD/filter.h \
$$PWD/sorter.h
On line 16 in the file Proxyrole.h , 'using QObject::QObject;' breaks the build with the above error.
I specifically only tested on msvc2013, because i m using another lib that requires that i stay in that kit.
Removing the statement seems to fix the issue and the code subset i am experimenting with still works, but I haven't verified that it breaks something else.
Is my fix workable? asking if it doesn't affect newer compilers.
To potentially save you some work, the code under question was added on August 7,2018
3a55ea0
can i use filtering and sorting to a hierarchical source?
this is just for example my model is ListModel not json :
{
"identifier": 2,
"childs": [{
"identifier": 201,
"name": "a",
"image": "\ueae5",
"levels": [{
"level": 1,
"push": "surathesab.qml"
}
]
}]
}, {
"identifier": 3,
"name": "b",
"image": "\uf02c",
"childs": [{
"identifier": 301,
"name": "c",
"image": "\uf53c",
"levels": [{
"level": 1,
"push": "check.qml"
}
}]
}
final output should be name=="a"
and name=="c"
so in this data i should see levels!=null which i go with this :
ValueFilter{
roleName: "levels"
value: !null
}
but , name == "c"
is a child how can i handle it?
Hello,
sorry for creating an "issue" here because it is only a question:
I did not find the part of code where the files in "sorters" directory are made available for QML context. So I am not really sure how to add a custom sorter on my own.
The function 'append_sorter' is never called.
Can you please give me a hint?
Thanks!
Occasionally it would be useful to be able to access QSortFilterProxyModel::mapToSource from within a QML context. It is already Q_INVOKABLE, but since it takes a QModelIndex as its parameter and also returns a QModelIndex, it is quite awkward to use. In order to make sense of the return value we need to hop back into C++ to get the value of QModelIndex::row(), which is much more useful on the QML side, than the raw QModelIndex.
Perhaps SortFilterProxyModel could provide a more QML friendly interface to mapToSource? (and also sourceToMap.)
The possibility of accessing an element imperatively can be useful.
The function interface coud look like this : get(rowNumber, roleName = "") returning all the roles or just the specified role for this element.
An alternative taking a QModelIndex could also be made.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.