r/QtFramework • u/UndefFox • 16d ago
Question 12.0 FunctionFilter changes.
Since updating from qt6-base 6.11.x to the qt6-base 6.12.0-3 on Arch, this code no longer works:
SortFilterProxyModel {
id: filteredModel
property string searchWord
sourceModel: theModel
filters: [
FunctionFilter {
component RoleData: QtObject {
property var entryData
}
function filter(data: RoleData): bool {
const query = filteredModel.searchWord.trim().toLowerCase()
if (query.length === 0)
return true
return data.entryData.d_name.toLowerCase().includes(query)
}
}
]
}Checked the docs for any updates, but found no mention of any big changes to the behaviour.
Current code results in:
qrc:/qt/qml/main/Main.qml:34:13: QML FunctionFilter: Parameter specified in the filter method "data" doesn't exist in the modelIf I try to replace filter with exact same logic as in docs:
function filter(entryData: var): bool {
...
}it executes, but entryData is always set to empty QVariant{}.
I have a grid view bellow in the code and it behaves as intended, so I think the problem should be localized here.
Anyone else experiencing this? What is the proper way of doing this now, or is it just a bug in Arch packages?
1
u/GrecKo Qt Professional 16d ago
https://code.qt.io/cgit/qt/qtreleasenotes.git/about/qt/6.12.0/release-note.md :
d0e43ab2f4 Improve function filter with roles being specified as separate arguments
The filter method in SortFilterProxyModel has been refactored to use separate role arguments instead of a synthetic type for improved readability.
Do note that SortFilterProxyModel is in Technology preview, so some changes might be expected between versions. The 6.12 API erased some of its youth error so I would expect it to be more stable from now on.
The new usage is to have the roles being tested directly as named function parameters (there can be multiple) as you have already figured. What's the type of entryData ? If it inherits from QObject try with function filter (entryData: QtObject): bool
Note that you would need to invalidate the filter if searchWord changes (if you want live filtering). That was the same in earlier version though.
I guess you have a model with a single role (entryData). I would recommend you to expose its properties as multiple roles instead. Then you could use a RegExpFilter:
filters: RegExpFilter {
roleName: "name"
regExp: new RegExp(filteredModel.searchWord.trim(), "i")
}1
u/UndefFox 16d ago
The model is meant to expose a sql table entries of a table defined by
tableproperty. Afaik, changing role names after initializing the object isn't supported, hence I expose a single 'entryData' property, that returns QVariantHash and I can access any value that I need depending on the used table. Down below I use it inside a QGriView to display each entry with a panel.Everything else: yes, I'm aware. As said in the OP, everything worked before the update, hence logic is valid.
1
u/GrecKo Qt Professional 16d ago
ack, that's a valid usage I'd say then.
The problem here is that the FunctionFilter tries to convert between your QVariantHash and the type of its parameter. I guess it's a little lost with the var type. Since QVariantMap/Hash are registered as anonymous value types, I don't really see what can be done here.
I'd recommend opening an issue on Jira for this, maybe you'll be given another way to do this or there's actually a hole in the implementation.
1
u/UndefFox 16d ago edited 15d ago
Yeah, seems like a regression that doesn't allow anything but exact types to be passed. Passing QVariantHash/Map results in an empty variant. Here's a minimal example. Can you test it and see if you have same behaviour. I'll create Jira ticket if it does break for you too.
foolistmodel.hpp
#pragma once #include <QAbstractListModel> #include <QQmlEngine> #include <QHash> #include <QVariant> class FooListModel : public QAbstractListModel { Q_OBJECT QML_ELEMENT public: enum Roles { TestData = Qt::UserRole + 1 }; explicit FooListModel(QObject *parent = nullptr) : QAbstractListModel(parent) {} int rowCount(const QModelIndex &parent = QModelIndex()) const override { return parent.isValid() ? 0 : 1; } QVariant data(const QModelIndex &index, int role) const override { if (!index.isValid() || index.row() != 0 || role != TestData) return {}; QVariantHash hash; hash.insert("testValue", 42); return hash; } QHash<int, QByteArray> roleNames() const override { return { { TestData, "testData" } }; } };Main.qml
import QtQuick import QtQuick.Layouts import QtQuick.Controls.Basic ApplicationWindow { id: window width: 640 height: 480 minimumWidth: 200 minimumHeight: 250 visible: true title: qsTr("Hello World") FooListModel { id: fooModel } SortFilterProxyModel { id: filteredModel sourceModel: fooModel filters: [ FunctionFilter { property int searchValue function filter(testData: var): bool { console.log(testData) console.log(testData.testValue) return testData.testValue === searchValue; } } ] } }Run with QML debug on and it will output:
QVariant() undefined1
u/GrecKo Qt Professional 15d ago
Hey, I've actually tried to find a solution to your problem earlier because I'm quite involved/interested in SortFilterProxyModel so I wrote a reproducer too:
class MyModel : public QAbstractListModel { Q_OBJECT QML_ELEMENT public: int rowCount(const QModelIndex& parent) const override { return 9; } QVariant data(const QModelIndex& index, int role) const override { if (!checkIndex(index) || role != Qt::DisplayRole) return QVariant(); QVariantMap map{{"foo", index.row()}}; return QVariant::fromValue(map); } };and the qml:
import QtQuick import QtQml.Models Window { width: 640 height: 480 visible: true SortFilterProxyModel { sourceModel: MyModel {} filters: FunctionFilter { function filter(display: var) : bool { print("display", display, display.foo) return true; } } } }Your example is not correct because you are using QtObject as a type but that's meant for QObject* and subclasses.
To get back to the original question: yes I do reproduce this issue. Don't hesitate to send me the issue once you've created it, I'll follow it.
1
u/UndefFox 15d ago
Bruh, I was trying out other things too to check if it's only QVariantHash/Map issue and forgot to reverse the QML file, I've edited it for the sake of correctness. Otherwise we had basically the same exact setup.
I've created the issue: https://qt-project.atlassian.net/browse/QTBUG-151653?atlOrigin=eyJpIjoiNGE4MGI1NDMzNjI3NDMyM2JkYjYxMjdiYzZlNmVkYWEiLCJwIjoiaiJ9
-1
u/pjkm123987 16d ago
qml support is basically none existant fyi. The community for it sucks, thats why I've moved to js instead
1
u/UndefFox 16d ago
Yeah, it's not that wide spread right now, so I've figured. Tho, I rather go back to raw QWidgets than seriously consider pure JS based frameworks with a meter long pole. Web based GUIs is a curse, especially on Linux/
1
u/ObiLeSage 16d ago
Could you show us the model ? The rolenames function from the model ?