Qt5-QML: ColumnLayout is overwriting another ColumnLayout when in a nested loop - qt

After successfully designing the layout of a small application from my previous post I am adding the logic of the events. I almost completed it but some events are not happening as I am planning. Below the logic and the full source code here in case would like to verify:
1) As soon as I chose the robot to connect to as show below, It does show I am connecting, but I am not able to interact with the QML page at all and all actions are blocked. I think this could be due to the fact that I have 2 ColumnLayout and I think that one is overwriting the other but I am not sure why that is happening as I thought the logic was complete:
The expected result would be that when I am connecting to the robot, the entire page works instead of being (or looking) disable.
Below the most important part of the code that composes the Minimal Reproducible Example with the problem:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtWebEngine 1.8
import QtQuick.Controls.Styles 1.4
ApplicationWindow {
id: root
visible: true
width: 440
height: 630
title: qsTr("Conn")
property Page1 page1: Page1 {}
property Page2 page2: Page2 {}
Component.onCompleted: {
page1.selectDialog.connect(function() {
mystackview.push(page2);
});
page2.onButtonClicked.connect(function(buttonId) {
page1.dialogId = buttonId;
mystackview.pop();
});
}
StackView {
id: mystackview
anchors.fill: parent
initialItem: page1
}
}
Page1.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.impl 2.12 // for IconLabel
import QtWebEngine 1.8
Page {
property int dialogId: -1
signal selectDialog()
function buttonClick(button)
{
button.text = qsTr("Connecting to %1...").arg(button.text);
button.enabled = false;
if (button.background && button.background instanceof Rectangle) {
button.background.color = "green";
button.background.gradient = null;
button.background.visible = true;
}
if (button.contentItem && button.contentItem instanceof IconLabel) {
button.contentItem.color = "white";
button.contentItem.font.bold = true;
button.contentItem.font.pointSize = 20;
}
}
function buttonClearList(buttonClear)
{
buttonClear.text = qsTr("Clear List").arg(buttonClear.text);
buttonClear.enabled = true;
if (buttonClear.background && buttonClear.background instanceof Rectangle) {
buttonClear.background.color = "red";
buttonClear.background.gradient = null;
buttonClear.background.visible = true;
}
if (buttonClear.contentItem && buttonClear.contentItem instanceof IconLabel) {
buttonClear.contentItem.color = "white";
buttonClear.contentItem.font.bold = true;
buttonClear.contentItem.font.pointSize = 20;
}
}
ColumnLayout {
// anchors.fill: parent
// anchors.topMargin: 0 // margin from top of the page
Layout.fillWidth: true
width: parent.width
spacing: 5
Button {
id: button1
text: "Select Robot"
width: parent.width
onClicked: selectDialog()
Layout.fillWidth: true
font.pointSize: 20
}
Button {
id: dialogA
text: "Freddie Mercury: Connected"
visible: dialogId === 1
Layout.fillWidth: true
font.pointSize: 20
spacing: 10
onClicked: {
buttonClick(this)
}
ColumnLayout {
anchors.fill: parent
anchors.topMargin: 50 // margin from top of the page
Layout.fillWidth: true
spacing: 10
GroupBox {
id: box1
width: parent.width
title: "Connection"
font.pointSize: 20
Layout.fillWidth: parent
spacing: 10
GridLayout {
width: parent.width
columns: 1
RowLayout {
id: row1
spacing: 200
Layout.fillWidth: true
Layout.fillHeight: false
Label {
id: textField
text: "Connection:"
font.pointSize: 15
Layout.fillWidth: true
}
Text {
id: connected
text: "Not-Connected"
color: "red"
font.pointSize: 15
horizontalAlignment: Text.AlignRight
Layout.fillWidth: true
}
}
}
}
Button {
id: clist
text: "Clear List";
Layout.fillWidth: true
font.pointSize: 20
width: parent.width
onClicked: {
buttonClearList(this)
}
}
}
}
}
}
Page2.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Page {
signal onButtonClicked(var buttonId)
Component.onCompleted: {
button1.clicked.connect(function() {
onButtonClicked(1);
});
}
ColumnLayout {
id: mybuttons
anchors.fill: parent
spacing: 5
Button {
id: button1
Layout.fillWidth: true
Layout.fillHeight: true
text: "Freddie Mercury"
font.pointSize: 20
}
}
}
So far I have been trying very different combinations of locating the ColumnLayout in different places. But my doubt i: I already have a ColumnLayout and after that I have another ColumnLayout, and I think that they are overwriting each other.
However, from the official documentation and also consulting other sources re is no problem in using it in a nested loop.
The same post talks about how a Column is a Positioner, while a ColumnLayout is a Layout.
I was sure I was using in the right way but something is missing.
Please point out in the right direction to solve this problem.

Basic design rule: If the parent item is disabled the children too.
Explanation:
In your case, the ColumnLayout is the child of the Button and this is the container of the other items that are your children, so if Button is disabled by the previous ColumnLayout rule, it will also be, and consequently also the entire contents of the ColumnLayout.
Solution:
In your case it is not necessary for ColumnLayout to be the children of Button but it can be on the same level.
On the other hand you have other errors:
If you are going to use Layout.XXX then you should not use the widths.YYY since they fulfill the same task but if you use both you can have problems since it can have an indefinite behavior since they will compete with each other.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.impl 2.12 // for IconLabel
Page {
property int dialogId: -1
signal selectDialog()
function buttonClick(button)
{
button.text = qsTr("Connecting to %1...").arg(button.text);
button.enabled = false;
if (button.background && button.background instanceof Rectangle) {
button.background.color = "green";
button.background.gradient = null;
button.background.visible = true;
}
if (button.contentItem && button.contentItem instanceof IconLabel) {
button.contentItem.color = "white";
button.contentItem.font.bold = true;
button.contentItem.font.pointSize = 20;
}
}
function buttonClearList(buttonClear)
{
buttonClear.text = qsTr("Clear List").arg(buttonClear.text);
buttonClear.enabled = true;
if (buttonClear.background && buttonClear.background instanceof Rectangle) {
buttonClear.background.color = "red";
buttonClear.background.gradient = null;
buttonClear.background.visible = true;
}
if (buttonClear.contentItem && buttonClear.contentItem instanceof IconLabel) {
buttonClear.contentItem.color = "white";
buttonClear.contentItem.font.bold = true;
buttonClear.contentItem.font.pointSize = 20;
}
}
ColumnLayout {
Layout.fillWidth: true
width: parent.width
spacing: 5
Button {
id: button1
text: "Select Robot"
width: parent.width
onClicked: selectDialog()
Layout.fillWidth: true
font.pointSize: 20
}
Button {
id: dialogA
text: "Freddie Mercury: Connected"
visible: dialogId === 1
Layout.fillWidth: true
font.pointSize: 20
spacing: 10
onClicked: {
buttonClick(this)
}
}
ColumnLayout {
id: layout
visible: dialogId === 1
Layout.fillWidth: true
spacing: 10
GroupBox {
id: box1
width: parent.width
title: "Connection"
font.pointSize: 20
Layout.fillWidth: parent
spacing: 10
GridLayout {
width: parent.width
columns: 1
RowLayout {
id: row1
spacing: 200
Layout.fillWidth: true
Layout.fillHeight: false
Label {
id: textField
text: "Connection:"
font.pointSize: 15
Layout.fillWidth: true
}
Text {
id: connected
text: "Not-Connected"
color: "red"
font.pointSize: 15
horizontalAlignment: Text.AlignRight
Layout.fillWidth: true
}
}
}
}
Button {
id: clist
visible: dialogId === 1
text: "Clear List";
Layout.fillWidth: true
font.pointSize: 20
width: parent.width
onClicked: {
buttonClearList(this)
}
}
}
}
}

Related

Qt Select At Most 1 Marker on Map

In my code every marker that I clicked are selected(turn into green from red). I want just 1 can change. When I click another marker the marker I clicked before turns red again. Or When I click an empty area the marker I clicked before turns red again.
In qml my Item's code:
Component {
id: hazardous_img
MapQuickItem {
id: hazardousitem
anchorPoint.x: image.width/4
anchorPoint.y: image.height
coordinate: position
property bool isClicked: false
MouseArea {
anchors.fill: parent
onDoubleClicked: {
mainwindow.hazardousIconClicked(mapview.toCoordinate(Qt.point(mouse.x,mouse.y)))
}
onClicked: {
if (isClicked === false) {
image.source = "qrc:/grn-pushpin.png"
isClicked = true
} else {
image.source = "qrc:/red-pushpin.png"
isClicked = false
}
}
}
sourceItem: Image {
id: image
source: "qrc:/red-pushpin.png"
}
}
}
In QML this is usually done with using a ButtonGroup, but as you're not using AbstractButtons you need to write it yourself. Here is my solution for it.
I've used the ListModel to not only store the coordinates of each marker, but also a selected flag which is set to false by default. In the delegate I'm using the selected data role to show if a marker is selected or not.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
ApplicationWindow {
id: window
width: 640
height: 480
visible: true
title: qsTr("Map")
ListModel { id: markerModel }
Plugin {
id: mapPlugin
name: "osm"
}
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MouseArea {
anchors.fill: parent
onDoubleClicked: {
var coordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y))
var jsonObject = JSON.parse(JSON.stringify(coordinate))
jsonObject["selected"] = false
markerModel.append(jsonObject)
}
onClicked: map.deselectAll()
}
MapItemView {
model: markerModel
delegate: markerDelegate
}
function deselectAll() {
for (var i = 0; i < markerModel.count; ++i)
markerModel.setProperty(i, "selected", false)
}
Component {
id: markerDelegate
MapQuickItem {
id: markerItem
required property int index
required property real latitude
required property real longitude
required property bool selected
anchorPoint.x: waypointMarker.width / 2
anchorPoint.y: waypointMarker.height / 2
coordinate: QtPositioning.coordinate(latitude, longitude)
sourceItem: Rectangle {
id: waypointMarker
width: 20
height: 20
radius: 20
border.width: 1
border.color: mouseArea.containsMouse ? "red" : "black"
color: markerItem.selected ? "red" : "gray"
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
map.deselectAll()
markerModel.setProperty(markerItem.index, "selected", true)
}
}
}
}
}
}
I came up with yet another solution without looping over all items in the model. It just stores the index of the selected marker in a dedicated property. This has the drawback that if the model order changes the index can become invalid, also potential multi selection is hard to handle, but on the other hand it is faster because it doesn't need to iterate over all items.
I experimented a lot with DelegateModel, it seems to be a perfect match if one could use it in combination with MapItemView, because of the groups and the attached properties like inGroupName.
After that I've tried ItemSelectionModel, but it seems it is only intended to be used in combination with a view, e.g. TreeView. I couldn't find out how to generate a QModelIndex in QML without a TreeView.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
ApplicationWindow {
id: root
width: 640
height: 480
visible: true
title: qsTr("Map")
property int selectedMarker: -1
Map {
id: map
anchors.fill: parent
plugin: Plugin {
id: mapPlugin
name: "osm"
}
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MouseArea {
anchors.fill: parent
onDoubleClicked: {
var coordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y))
markerModel.append(JSON.parse(JSON.stringify(coordinate)))
}
onClicked: root.selectedMarker = -1
}
MapItemView {
model: ListModel { id: markerModel }
delegate: markerDelegate
}
Component {
id: markerDelegate
MapQuickItem {
id: markerItem
required property int index
required property real latitude
required property real longitude
anchorPoint.x: waypointMarker.width / 2
anchorPoint.y: waypointMarker.height / 2
coordinate: QtPositioning.coordinate(latitude, longitude)
sourceItem: Rectangle {
id: waypointMarker
width: 20
height: 20
radius: 20
border.width: 1
border.color: mouseArea.containsMouse ? "red" : "black"
color: markerItem.index === root.selectedMarker ? "red" : "gray"
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: root.selectedMarker = markerItem.index
}
}
}
}
}
I promise this is the last answer on that question.
This one is using an ItemSelectionModel and a few undocumented functions, e.g. ListModel.index(row, col).
itemSelectionModel.hasSelection is used in the color binding to trigger a reevaluation in order to call isRowSelected and set the color accordingly whenever the selection has changed.
If the user clicks on the background the clear() is called to clear the selection.
I think out of the three this is the best solution. It can be easily upgraded to allow multi selection as shown below. Also the ItemSelectionModel can be used by other views to show the data and selection.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
import QtQml.Models 2.15
ApplicationWindow {
id: root
width: 640
height: 480
visible: true
title: qsTr("Map")
Map {
id: map
anchors.fill: parent
plugin: Plugin {
id: mapPlugin
name: "osm"
}
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MouseArea {
anchors.fill: parent
onDoubleClicked: function(mouse) {
markerModel.append(map.toCoordinate(Qt.point(mouse.x, mouse.y)))
}
onClicked: itemSelectionModel.clear()
}
MapItemView {
model: ListModel { id: markerModel }
delegate: markerDelegate
}
ItemSelectionModel {
id: itemSelectionModel
model: markerModel
}
Component {
id: markerDelegate
MapQuickItem {
id: markerItem
required property int index
required property real latitude
required property real longitude
anchorPoint.x: waypointMarker.width / 2
anchorPoint.y: waypointMarker.height / 2
coordinate: QtPositioning.coordinate(latitude, longitude)
sourceItem: Rectangle {
id: waypointMarker
width: 20
height: 20
radius: 20
border.width: 1
border.color: mouseArea.containsMouse ? "red" : "black"
color: {
itemSelectionModel.hasSelection
return itemSelectionModel.isRowSelected(markerItem.index) ? "red" : "gray"
}
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: itemSelectionModel.select(markerModel.index(markerItem.index, 0),
ItemSelectionModel./*ClearAnd*/Select)
}
}
}
}
}

how can I put a splash screen on my project using EGFLS in Qt/QML

I am new to Qt QML and trying to implement a splash screen in qml.
But, I am ended with below error when running the ui in eglfs instance.
"EGLFS: OpenGL windows cannot be mixed with others."
I have referred the below code from GIT and it was working good in x86 instance
Could you please help me in resolving this.
main.qml
Item {
Loader {
id: mainWindowLoader
anchors.fill: parent
visible: false
source: "qrc:/window.qml"
asynchronous: true
onLoaded: {
item.visible = true;
splashScreenLoader.item.visible = false;
splashScreenLoader.source = "";
}
}
Loader {
id: splashScreenLoader
source: "qrc:/splashscreen.qml"
anchors.fill: parent
asynchronous: false
onLoaded: {
mainWindowLoader.active = true;
}
}
}
spalshscreen.qml
Window {
id: splashScreen
modality: Qt.ApplicationModal
flags: Qt.SplashScreen
width: 1024
height: 600
Rectangle {
id: splashRect
anchors.fill: parent
color: "white"
border.width: 1
border.color: "black"
Text {
id: initializationErrorMessage
text: "This is the splash screen"
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 50
font.bold: true
font.pixelSize: 20
color: "black"
}
}
Component.onCompleted: visible = true
}
window.qml
ApplicationWindow {
id: mainWindow
flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowCloseButtonHint
width: 1024
height: 600
visible: false
title: "Scresh Screen Test"
Component.onCompleted: {
var timeout = new Date().valueOf() + 3000;
while(timeout > new Date().valueOf()) {}
}
Text {
text: "Window ready!"
anchors.centerIn: parent
font.bold: true
font.pixelSize: 20
color: "black"
}
}
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}

TableView QML Type onClicked event

I am currently using a TableView in my QML file. I would like to know which cell the user clicked.. There is a post here: https://forum.qt.io/topic/84284/tableview-onclicked-slot/2 which shows the onClicked code in the QML file. However, when i tried on my code it says invalid property name. My QML file code is:
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import TransactionHistoryTableModel 1.0
import tech.siotgov.DataManager 1.0
import "../../components" as Components
import "../../utils/httpRequest.js" as HttpRequest
Rectangle {
id: root
objectName: "TransactionHistory"
color: "white"
property string pageTitle: "Transaction History"
ColumnLayout {
id: home
anchors.leftMargin: parent.width * 0.05
anchors.rightMargin: parent.width * 0.05
anchors.fill: parent
anchors.horizontalCenter: parent.horizontalCenter
Components.PageTitle {
title: pageTitle
}
Rectangle {
id: transactionHistoryDisplay
color: "white"
Layout.fillWidth: true
Layout.preferredHeight: parent.height - 100
Components.Table {
model: _transactionHistoryTableModelAPI
columnWidths: [0.4, 0.6]
onClicked: {
console.log(" click ")
console.log(color_string)
}
}
}
Item { //spacer
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
anchors.fill: parent
color: "white"
}
}
}
Component.onCompleted: {
const locationId = DataManager.currentLocation.locationId;
const d = new Date()
d.setTime(d.getTime() - d.getTimezoneOffset()*60*1000);
const datetimeStamp = d.toISOString().split('.')[0]
_transactionHistoryTableModelAPI.resetTable(locationId);
HttpRequest.query(
"query { transactionsByLocation(fromDateTime:\"2019-01-01T07:54:34\", toDateTime:\"" + datetimeStamp + "\", location:" + locationId + ") { transactionId, datetime, items { transactionItemId }, transactionType {name}, location_1{locationName}, location_2{locationName} } }",
res => {
_transactionHistoryTableModelAPI.updateTable(res.data.transactionsByLocation);
})
}
}
The Table.qml file is:
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
TableView {
anchors.fill: parent
clip: true
property var columnWidths: [0.5, 0.5] // as fractions of parent width
// preferably overwrite this when using
columnWidthProvider: function (column) { return Math.max(parent.width * columnWidths[column], 1) }
delegate: Rectangle {
implicitHeight: text.implicitHeight
border.color: "#dddddd"
color: (heading==true)?"#dddddd":"white"
Text {
id: text
text: tabledata
width: parent.width
wrapMode: Text.Wrap
padding: 5
}
}
}
In a view you must set the MouseArea in the delegate and expose it through a signal from the root of the component:
Table.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
TableView {
id: root
anchors.fill: parent
clip: true
signal clicked(int row, int column) // <---
property var columnWidths: [0.5, 0.5] // as fractions of parent width
// preferably overwrite this when using
columnWidthProvider: function (column) { return Math.max(parent.width * columnWidths[column], 1) }
delegate: Rectangle {
implicitHeight: text.implicitHeight
border.color: "#dddddd"
color: heading ? "#dddddd" : "white"
Text {
id: text
text: tabledata
width: parent.width
wrapMode: Text.Wrap
padding: 5
}
MouseArea{
anchors.fill: parent
onClicked: root.clicked(model.row, model.column) // <---
}
}
}
*.qml
// ...
Components.Table {
model: _transactionHistoryTableModelAPI
columnWidths: [0.4, 0.6]
onClicked: console.log(row, column)
}
// ...

Make BusyIndicator run when click on button (signal to C++)

I created an interface has a ListView and two Buttons. When click on Scan button it will call to C++ and make change to the model of ListView. After that C++ will emit signal to inform model is changed therefore ListView in QML will update with new model. I want to make BusyIndicator running during that process. How can i do that ?.
I saw a few solutions on stackoverflow like this one: BusyIndicator does not show up but none of them worked for my case.
Can anyone help me ? Thanks.
Here is my qml code:
import QtQuick 2.5
import QtQuick.Layouts 1.3
import Qt.labs.controls 1.0
Rectangle
{
objectName: "bluetoothPage"
anchors.fill: parent
property var bluetoothDataModel: messageFromApp.bluetoothData
onBluetoothDataModelChanged: listView.update()
signal qmlScanButtonSignal()
signal qmlDisconnectButtonSignal()
ColumnLayout
{
anchors.fill: parent
spacing: 6
RowLayout
{
Layout.fillWidth: true
Text
{
Layout.fillWidth: true
text: "Connect with ECU"
font.bold: true
font.pixelSize: 20
}
BusyIndicator
{
id: busyIndicator
Layout.preferredWidth: 30
Layout.preferredHeight: 30
running: false
visible: false
}
}
GroupBox
{
Layout.fillHeight: true
Layout.fillWidth: true
title: qsTr("Available device:")
ListView
{
id: listView
anchors.fill: parent
model: bluetoothDataModel
delegate: Component
{
Item
{
width: parent.width
height: 40
Column
{
Text { text: "Name:" + model.modelData.name }
Text { text: "Number:" + model.modelData.macAddress }
}
MouseArea
{
anchors.fill: parent
onClicked: listView.currentIndex = index
}
}
}
highlight: Rectangle
{
color: "blue"
}
}
}
RowLayout
{
Layout.fillWidth: true
Layout.preferredHeight: 10
Button
{
Layout.fillHeight: true
Layout.fillWidth: true
text: "Scan"
onClicked: qmlScanButtonSignal()
}
Button
{
Layout.fillHeight: true
Layout.fillWidth: true
text: "Disconnect"
onClicked: qmlDisconnectButtonSignal()
}
}
}
}
Only this solution worked for me in my case. However, like everybody said using QCoreApplication::processEvents()
is really bad practice. I also try to using QThread but it got crash when emitted signal inside thread. If you guy have any futher solutions, please let me now. I'm really appreciate. Thanks.
QML
BusyIndicator {
running: CPPModule.busy
}
CPP
void CPPModule::setBusy(const bool &busy)
{
m_busy = busy;
emit busyChanged();
}
void CPPModule::InsertIntoDB()
{
setBusy(true);
QThread::msleep(50);
QCoreApplication::processEvents();
/*
very Long Operation
*/
setBusy(false);
}
Another solution is this:
Timer {
id: myTimer
interval: 1
onTriggered: {
app.someLongRunningFunction();
myActivityIndicator.visible = false;
}
}
Butoon{
....
onClicked: {
myActivityIndicator.visible=true;
myTimer.start();
}
}

QtQuick TableView delete row doesn't work

I am using QtQuick TableView to show data from a database through QSqlTableModel and QSortFilterProxyModel.
The remove row operation doesn't work as it should. I have implemented a method in a class derived from QSortFilterProxyModel to call removeRows methods of QSortFilterProxyModel.
Everything works correctly as long as I have a filter setted in QSortFilterProxyModel ( i set it through a text box ). But when the filter is empty, the TableView rowCount property doesn't decrement and, after each delete, the currentRow property is set to rowCount-2. Why? To me it looks like a bug. Why it works when the filter is not empty?
Q_INVOKABLE void eliminaCliente(int row) {
removeRows(row,1);
}
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
import Material 0.2
import Material.ListItems 0.1
ApplicationWindow {
id: root
visible: true
width: 1024
height: 640
title: qsTr("assiBase")
Page {
id: pLayout
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
Toolbar {
id: aBar
Layout.fillWidth: true
page: pLayout
backgroundColor: "#eeeeee"
RowLayout {
anchors.fill: parent
ActionButton {
id: addButton
Layout.leftMargin: 10
iconName: "content/add_circle"
backgroundColor: "#4CAF50"
onClicked: modalDialog.show()
isMiniSize: true
}
ActionButton {
id: editButton
iconName: "content/create"
isMiniSize: true
}
ActionButton {
id: deleteButton
iconName: "action/delete"
isMiniSize: true
backgroundColor: "#FF0000"
onClicked: {
if (dataView.currentRow != -1) {
var r = dataView.currentRow
console.log(dataView.currentRow)
sqlSortedData.eliminaCliente(dataView.currentRow)
console.log(dataView.rowCount)
//dataView.currentRow = r
}
}
}
RowLayout {
Layout.alignment: Qt.AlignRight
Icon {
name: "action/search"
Layout.alignment: Qt.AlignBottom
}
TextField {
id: searchBox
Layout.rightMargin: 20
Layout.minimumWidth: 400
Layout.preferredWidth: 500
placeholderText: qsTr("cerca...")
onTextChanged: sqlSortedData.setFilterWildcard(searchBox.text)
font.capitalization: Font.MixedCase
}
}
}
}
TableView {
anchors.top: aBar.bottom
anchors.topMargin: 3
sortIndicatorVisible: true
frameVisible: false
Layout.fillWidth: true
Layout.fillHeight: true
onSortIndicatorColumnChanged: model.sort(sortIndicatorColumn, sortIndicatorOrder)
onSortIndicatorOrderChanged: model.sort(sortIndicatorColumn, sortIndicatorOrder)
id: dataView
TableViewColumn {
role: "ID"
visible: false
}
TableViewColumn {
role: "Nome"
title: "Nome"
width: 200
}
TableViewColumn {
role: "Residenza"
title: "Residenza"
width: 200
}
TableViewColumn {
role: "Assicurazione"
title: "Assicurazione"
width: 200
}
TableViewColumn {
width: 128
resizable: false
delegate: RowLayout {
anchors.fill: parent
clip: true
IconButton {
iconName: "content/create"
onClicked: console.log(styleData.row)
}
IconButton {
iconName: "action/delete"
onClicked: {
console.log(styleData.row)
sqlSortedData.eliminaCliente(styleData.row)
console.log(dataView.rowCount)
}
}
}
}
model: sqlSortedData
}
}
}
Take a look at here. There is an workaround suggestion.
It seems like QSortFilterProxyModel needs some love for a long time.

Resources