I have a TableView that has a Sudoku grid in it. I wanted to validate it so that a number cannot be placed in the same row or column using a c++ functions. When the user enters an invalid number it the MessageDialog should appear but that not happens. What can be the problem? This is the DialogBox and:
MessageDialog {
id: msgDial
text: "Invalid number."
informativeText: "Do you want to save your changes?"
buttons: MessageDialog.Ok
onAccepted: msgDial.close()
}
This is the TableView that I want to validate:
TableView {
anchors.fill: parent
clip: true
model: SudokuGrid {
id: grid
}
delegate: Rectangle {
required property var model
implicitWidth: 50
implicitHeight: 50
TextField {
anchors.fill: parent
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" : "lightblue"
border {
width: 1
color: "white"
}
}
color: "black"
validator: IntValidator {
bottom: 1
top: 9
}
onEditingFinished: {
if (text !== "" && model.display === 0) {
var enteredNumber = parseInt(text);
if (validator.validate(text, 0).valid && model.isNumberValid(model.row, model.column, enteredNumber)) {
model.display = text;
} else {
msgDial.open();
}
}
}
TableView.onCommit: {
if (text !== "" && model.display === 0) {
var enteredNumber = parseInt(text);
if (validator.validate(text, 0).valid && model.isNumberValid(model.row, model.column, enteredNumber)) {
model.display = text;
} else {
msgDial.open();
}
}
}
}
and this is the setData c++ function:
bool Grid::isNumberValid(int row, int col, int number) const
{
for (int j = 0; j < 9; j++) {
if (j != col && gridData[row][j] == number) {
return false;
}
}
for (int i = 0; i < 9; i++) {
if (i != row && gridData[i][col] == number) {
return false;
}
}
return true;
}
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;
if (isNumberValid(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 or column!";
}
}
return false;
}
Maybe the fact that I used the id instead of an object passed to qml with setContextProperty that creates the class of the sudoku grid can be the problem? I am new to qml and I don't know what can be the problem.
To use the validator you should not call the IntValidator's validate
method, you should check the TextField's acceptableInput
property. For example:
TextField {
id: textField
validator: IntValidator { bottom: 1; top: 9 }
background: Rectangle {
color: textField.acceptableInput ? "green" : "red"
}
}
As this property is continuously available during the editing, I see there is no need to wait for onAccepted
/onEditingFinished
. Because you have a validator, I doubt that onAccepted
/onEditingFinished
would be triggered since your validator would be guarding against invalid input.