Check dialog contents before close

Hello,

I have a dialog with text fields to enter data.
Now I want to check if one or more fields are emtpy before clicking “OK” closes the window.
Is there a way to do this?

My idea would have bee to reopen the dialog after submitting, but this does not seem to be the best way to me.

Take a look at the Validator sample in the demo. Validators can serve a few purposes, one of which is to validate the content of some widget, either on every update event, or all at once when the Validate method is called. The other feature is only seldomly used from Python, and that is to transfer data to/from the widget.

There is built-in functionality in wx.Dialog where the all validators for any widgets on the dialog are called to check if it is valid when the Ok button is pressed, and if any fail then the Dialog will refuse to close. You can do similar in other situations, but only the dialog has that functionality built-in.

You can also use event handlers to validate when something changes.
For visualization, colors are an option.
Also you may disable the OK button while the contents are not valid.
Additionally, a button handler for the OK button may decide to call event.Skip() or not.

Note that this code binds EVT_TEXT for the frame, not for the text control. EVT_TEXT is a CommandEvent this will propagate up through the parent widgets.
This allows to bind only once for all text controls in the dialog.

I have attached a quick and dirty example for some options:

dialog_validation.py (5.8 KB)

        # use either of these, as EVT_TEXT will propagate:
        # for the one specific control
        #self.Bind(wx.EVT_TEXT, self.on_text_ctrl_text, self.text_ctrl_1)
        # for all controls in the dialog; EVT_TEXT
        self.Bind(wx.EVT_TEXT, self.on_text)  # note that there are only two arguments

        self.button_OK.Bind(wx.EVT_BUTTON, self.on_button_OK)

    def on_text_ctrl_text(self, event):  # wxGlade: MyDialog.<event_handler>
        print("Event handler 'on_text_ctrl_text' called")
        self.button_OK.Enable( self.validate_contents() )
        event.Skip()

    def on_close(self, event):  # wxGlade: MyDialog.<event_handler>
        print("Event handler 'on_close' called")
        # user has pressed the close icon; call event.Veto() instead of Skip() if you want to keep the dialog open
        #event.Veto()
        event.Skip()

    def on_text(self, event):  # wxGlade: MyDialog.<event_handler>
        print("Event handler 'on_text' called")
        self.button_OK.Enable( self.validate_contents() )
        event.Skip()

    def validate_contents(self):
        # check whether the dialog contents are valid
        OK = True
        if not self.text_ctrl_1.GetValue():
            self.text_ctrl_1.SetBackgroundColour(wx.RED)
            OK = False
        else:
            self.text_ctrl_1.SetBackgroundColour(wx.NullColour)  # for better display, this would also require a refresh
        self.text_ctrl_1.Refresh()
        return OK

    def on_button_OK(self, event):
        print("Event handler 'on_button_OK' called")
        # don't call Skip if you want to keep the dialog open
        if not self.checkbox_allow.IsChecked():  # maybe also check self.validate_contents()
            print("Checkbox not checked -> don't close the dialog")
            wx.Bell()
        else:
            print("Checkbox checked -> close the dialog")
            event.Skip()

Thanks, I looked at the Validator and it looks promising :slight_smile: