Dialog/Form Validation

When a user presses OK in a dialog, it means that something should happen. But this can only happen if the data in the dialog are valid. The dialog/form must be validated. This tutorial describes the validation mechanism supported by PFC GUI. It also shows how to use the validating controls integerControl and realControl, and how to validate other controls in a dialog/form.

In this tutorial, we will show you how to validate controls in a dialog or in a form. First we will describe the validation concept. We will show how integerControl and realControl use the validation concept. Then we consider the validation in a container control. And finally we will add the validation for several usual controls: editControl, listBox and a newly created custom control.

Source files corresponding to this tutorial is available in the examples Help -> Install Examples...

Validation Concept
The validation concept is based on the idea: "control values should be valid". The validation check happens on pressing OK button in a dialog or a form, but the validation check can be forced programmatically also.

It is the responsibility of a control to state that its contents is valid, therefore a validation responder can be set to a control.

When a dialog or a form makes the validation check, the controls are tested sequentially, but if one of the tests results in

contentsInvalid(Source, FocusControl, ErrorMessage)

then the validation check is terminated.

Validation in integerControl and realControl
Let us create a form and add two custom controls in it with the classes integerControl and realControl. You can see the result in the supplied example project in the form integerControlAndRealControl.

The generated code will look like:

integerControl_ctl := integercontrol::new(This), integerControl_ctl:setPosition(92, 4), integerControl_ctl:setSize(60,12), realControl_ctl := realcontrol::new(This), realControl_ctl:setPosition(92, 20), realControl_ctl:setSize(60,12),

Also we need to add invocation of integerControlAndRealControl form:

predicates onFileIntegercontrolRealcontrol : window::menuItemListener. clauses onFileIntegercontrolRealcontrol(Source, _MenuTag) :- Form = integerControlAndRealControl::new(Source), Form:show.

When we run the project and input non-integral values, we will see a dialog box with an explanation about the mistake.

We can add also onOK responder to retrieve values of the validated controls:

predicates onOk : button::clickResponder. clauses onOk(_) = button::defaultAction :- Integer = integerControl_ctl:getInteger, Real = realControl_ctl:getReal, stdIO::write("Integer value = ",Integer, "\n"), stdIO::write("Real value = ",Real, "\n").

It is important to notice onOK responder is not invoked if the dialog validation is not successful. And of course, onOK responder is invoked after all validation predicates.

Let us look in file \pfc\gui\controls\integerControl.pro to inspect how the validation is implemented. We can see:

clauses new :- editControl::new, addValidateResponder(onIntValidate).

predicates onIntValidate : validateResponder. clauses onIntValidate(_) = contentsInvalid(This,This, ErrorMessage) :- string(ErrorMessage) = checkContent(getText), !.   onIntValidate(_) = contentsOk.

I.e. if the local predicate checkContent considers the text as an integer, then the validation is successful.

As it is mentioned above we can also force validation programmatically. We will add button TryValidation and code:

predicates onTryValidation : button::clickResponder. clauses onTryValidation(_Source) = button::defaultAction :- tryValidateWithErrorDialog, !,       stdIO::write("All controls are valid\n"). onTryValidation(_Source) = button::defaultAction.

Validation in Container Controls
For considering the validation in a container control, we should create such control first. Let us create a new control fromTo in our project and add two controls integerControl in it.

We will consider that fromTo control is valid if From</vp> value is less than To</vp> value, therefore we will add a validation responder to fromTo</vp> control:

predicates validateFromTo : control::validateResponder. clauses validateFromTo (Source) = control::contentsInvalid(Source,from_ctl,     "From value must be less than To value") :- from_ctl:getInteger >= to_ctl:getInteger, !.   validateFromTo (_) = control::contentsOk.

Please notice that control from_ctl</vp> will receive the focus if the validation is not successful.

Validation in Usual Controls
Let us create a new control myControl</vp> in our project, and then create a form and add three controls in it:


 * edit control;


 * listbox control;


 * custom control of myControl</vp> class.

You can see the result in the supplied example project in the form usualControls.

Initialization code will contain the setting of responders and initialization for these three controls:

clauses new(Parent) :- formWindow::new(Parent), generatedInitialize, edit_ctl:addValidateResponder(validateEditCtl), listbox_ctl:addList(["First","Second","Third"]), listbox_ctl:addValidateResponder(validateListBox).

And validation responders will look like:

predicates validateEditCtl : control::validateResponder. clauses validateEditCtl(_) = control::contentsOk :- "OK" = edit_ctl:getText, !.   validateEditCtl(Source) = control::contentsInvalid(          Source, Source,          "Edit control expects to have the text 'OK'").

predicates validateListBox : control::validateResponder. clauses validateListBox(Source) = control::contentsInvalid(         Source,Source,          "Selection of the first row is not allowed") :- 0 = listbox_ctl:tryGetSelectedIndex, !.   validateListBox(_) = control::contentsOk.

predicates validateMyControl : control::validateResponder. clauses validateMyControl(Source) = control::contentsInvalid(         Source,Source,          string::concat("A marker in the ",Missed, " part is mandatory")) :- Missed = toString(isMandatoryMarkNotActive( mandatoryMark, activatedMark)), !.   validateMyControl(_) = control::contentsOk.

That is, you can see that it is possible to validate a control in really different ways.