Cannot open my QML MessageDialog using my C++ signal

71 views Asked by At

I have a sudoku grid, and I want to validate it so that a number cannot be entered in the same row and column. If this happens, I want the message dialog box to open.
I have the function verif_complet that checks the row and column. I emitted a signal, but it is not working correctly, and the message dialog is not opening.

What could be the problem and what can I do to make this work?

This is the QML code of the TableView:

TableView {
    anchors.fill: parent
    clip: true

    model: SudokuGrid {
        id: grid
    }

    delegate: Rectangle {
        required property var model
        implicitWidth: 50
        implicitHeight: 50

        TextField {
            id: textField
            anchors.fill: parent
            validator: IntValidator { bottom: 1; top: 9 }
            text: model.display !== undefined ? model.display.toString() : ""

            readOnly: model.display !== undefined && model.display !== 0

            horizontalAlignment: TextInput.AlignHCenter
            verticalAlignment: TextInput.AlignVCenter

            background: Rectangle {
                color: model.row % 2 ? "lightpink" : "#bfa6ac" && textField.acceptableInput ? "#FFEFD5" : "#bfa6ac"
                border {
                    width: 1
                    color: "white"
                }

            }

            color: "black"

            onEditingFinished: {
                if (!model.verif_complet(model.row, model.column, parseInt(textField.text))) {
                    grid.invalidInput();
                }
            }
        }

        Rectangle {
            width: 1
            height: parent.height
            color: model.column % 3 == 0 ? "black" : "transparent"
        }

        Rectangle {
            width: parent.width
            height: 1
            color: model.row % 3 == 0 ? "black" : "transparent"
        }
    }
}

This is the message dialog:

MessageDialog {
    id: msgDial
    text: "Invalid number."
    informativeText: "Do you want to save your changes?"
    buttons: MessageDialog.Ok

    onAccepted: msgDial.close()
}

This is the connection between the signal and QML to open the message dialog, but the message dialog is not opening.

Connections {
    target: grid
    function onInvalidInput() {
        msgDial.open()
    }
}

This is the C++ code of the setData function:

bool Grid::setData(const QModelIndex &index, const QVariant &value, int role) {
    if (role == Qt::EditRole) {
        if (!checkIndex(index))
            return false;

        int inputValue = value.toInt();

        if (inputValue < 1 || inputValue > 9)
            return false;

        SudokuGenerator sudokuGenerator(1);

        if (sudokuGenerator.verif_complet(index.row(), index.column(), inputValue)) {
            gridData[index.row()][index.column()] = inputValue;
            emit dataChanged(index, index);
            return true;
        } else {
            qDebug() << "Invalid number in the same row, column, or 3x3 square!";
            emit invalidInput();
        }
    }

    return false;
}

and this is the verif_complet function:

bool SudokuGenerator::verif_complet(int i, int j, int nr) {
    if (verif_col(j, nr) == true && verif_lin(i, nr) == true && verif_patrat(i - (i % 3), j - (j % 3), nr) == true)
        return true;
    return false;
}

I tried to call the verif_complet function and emit a signal.

1

There are 1 answers

0
Stephen Quan On

You can build a solution using RegularExpressionValidator instead of IntValidator. The regular expression will begin by allowing the characters from "0123456789" but, over time, the list of available characters disappears as you enter new values.

Because we're ensuring the input is always valid, there is no need for a post-editing check and no need for a dialog.

import QtQuick
import QtQuick.Controls
Page {
    title: "Sudoku Test"
    Item {
        anchors.centerIn: parent
        width: debugCheckBox.checked ? 9 * 60 : 9 * 40
        height: width
        Repeater {
            model: SudokuModel { id: sudokuModel}
            delegate: SudokuCell {
                debug: debugCheckBox.checked
                onActiveFocusChanged: if (activeFocus) updateValidChars()
                function updateValidChars() {
                    let ok = "0123456789".split("");
                    for (let idx = 0; idx < sudokuModel.count; idx++) {
                        let m = sudokuModel.get(idx);
                        if (m.i === i && m.j === j) continue;
                        if (m.i !== i && m.j !== j) continue;
                        if (m.v === 0) continue;
                        if (m.v < 1 || m.v > 9) continue;
                        ok[m.v] = "";
                    }
                    validChars = ok.join("");
                }
            }
        }
    }
    footer: Frame {
        CheckBox { id: debugCheckBox; text: "Debug" }
    }
}

// SudokuModel.qml
import QtQuick
ListModel {
    Component.onCompleted: {
        for (let i = 0; i < 9; i++)
            for (let j = 0; j < 9; j++)
                append( {i:i,j:j,v:0} );
    }
}

// SudokuCell.qml
import QtQuick
import QtQuick.Controls
TextField {
    property bool debug: false
    property var validChars: "0123456789";
    property var regex: new RegExp('^[' + validChars + ']$');
    property int cellSize: debug ? 60 : 40
    background: Rectangle {
        border.color: "black"
        Text {
            visible: debug
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            anchors.margins: 2
            text: validChars; font.pointSize: 6
        }
    }
    x: j * cellSize
    y: i * cellSize
    width: cellSize
    height: cellSize
    color: acceptableInput ? "green" : "red"
    text: v
    validator: RegularExpressionValidator { regularExpression: regex }
    onEditingFinished: v = parseInt(text)
}

You can Try it Online!