Difference between revisions of "Dialog/Form Validation"

From wiki.visual-prolog.com

(example links)
Line 24: Line 24:
==Validation in integerControl and realControl==
==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.
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 <vp>integerControlAndRealControl</vp>.


The generated code will look like:
The generated code will look like:
Line 35: Line 35:
realControl_ctl:setSize(60,12),</vip>
realControl_ctl:setSize(60,12),</vip>


Also we need to add invocation of integerControlAndRealControl'''' form:
Also we need to add invocation of <vp>integerControlAndRealControl</vp> form:


<vip>predicates
<vip>predicates
Line 46: Line 46:
When we run the project and input non-integral values, we will see a dialog box with an explanation about the mistake.
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:
We can add also <vp>onOK</vp> responder to retrieve values of the validated controls:


<vip>predicates
<vip>predicates
Line 57: Line 57:
         stdIO::write("Real value = ",Real, "\n").</vip>
         stdIO::write("Real value = ",Real, "\n").</vip>


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.
It is important to notice <vp>onOK</vp> responder is '''not''' invoked if the dialog validation is not successful. And of course, <vp>onOK</vp> 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:
Let us look in file '''\pfc\gui\controls\integerControl.pro''' to inspect how the validation is implemented. We can see:


<vip>clauses
<vip>clauses
Line 74: Line 74:
     onIntValidate(_) = contentsOk.</vip>
     onIntValidate(_) = contentsOk.</vip>


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


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

Revision as of 14:43, 9 March 2009

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.

Download source files of the example project used in this tutorial:

Visual Prolog 7.2 version.

Visual Prolog 7.1 version.


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 value is less than To value, therefore we will add the validation responder to fromTo' control:

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

Please notice that control from_ctl' will receive the focus if the validation is not successful.

Validation in Usual Controls

Let us create a new control myControl' in our project, and then create a form and add three controls in it:

  • edit control;
  • listbox control;
  • custom control of myControl' 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.

References