Setting the "Cancel" button in a modal dialog does not work

I need a dialog that can return two values ​​"Yes" or “No”. I want that when closing the dialog (pressing X or Esc), the return result is wx.ID_NO.

I am using self.SetEscapeId(wx.ID_NO) for this.

But when I close the dialog not through the “Yes” button, I always get wx.ID_CANCEL. Why?

Example:

import wx


class Dialog(wx.Dialog):

    def __init__(self, parent):
        super().__init__(parent, title='Dialog', style=wx.CAPTION)

        self.SetAffirmativeId(wx.ID_YES)
        self.SetEscapeId(wx.ID_NO)  # <---

        sizer = self.CreateButtonSizer(wx.YES_NO)
        sizer.Fit(self)
        self.SetSizer(sizer)


class Frame(wx.Frame):

    def __init__(self):
        super().__init__(None)

        def callback():
            with Dialog(self) as dlg:
                answer = dlg.ShowModal()
                print(answer == wx.ID_YES,
                      answer == wx.ID_NO,
                      answer == wx.ID_CANCEL,
                      sep='\n')
        wx.CallAfter(callback)


if __name__ == '__main__':
    app = wx.App()
    Frame().Show()
    app.MainLoop()

Windows 10, wxPython 4.1.1 (and 4.0.7.post2), Python 3.7.9.

In the documentation for SetEscapeId() it says: “Sets the identifier of the button which should work like the standard “Cancel” button in this dialog”.

The standard “Cancel” button returns wx.ID_CANCEL, so I think that that in order to work like the standard “Cancel” button, your “No” button should also return wx.ID_CANCEL.

Well, since one can only set the two states Affirmative and Escape one shouldn’t expect more to be returned!!! (the introductory description of the Dialog describes this in more, may be too many words); what about a non modal dialog? :ghost:

if one feels uncomfortable about CallAfter or Python allows self to learn itself…

import wx

class Dialog(wx.Dialog):

    def __init__(self, parent):
        super().__init__(parent, title='Dialog', style=wx.CAPTION)

        self.SetAffirmativeId(wx.ID_YES)
        self.SetEscapeId(wx.ID_NO)  # <---

        sizer = self.CreateButtonSizer(wx.YES_NO)
        sizer.Fit(self)
        self.SetSizer(sizer)

class Frame(wx.Frame):

    def __init__(self):
        super().__init__(None)

        def callback(self):
            with Dialog(self.GetEventObject()) as dlg:
                answer = dlg.ShowModal()
                print(answer == wx.ID_YES,
                      answer == wx.ID_NO,
                      answer == wx.ID_CANCEL,
                      sep='\n')
        self.Bind(wx.EVT_SIZE, callback)

if __name__ == '__main__':
    app = wx.App()
    Frame().Show()
    app.MainLoop()

I didn’t want to ruin the closure, I sincerely apologise :sweat_smile:

dialog_evt_clo.py (861 Bytes)