Search code examples
pythonpython-3.xmodal-dialogwxpython

Possible to use with statement with wx.DirDialog()


I have the following button event handler:

def select_source_folder(self, event):
     with wx.DirDialog(self.panel,message="Choose Source Directory" style=wx.DD_DEFAULT_STYLE):
         if wx.DirDialog.ShowModal() == wx.ID_CANCEL:
              pass

I was reading on this page about wx.FileDialog and in the example it uses the with statement. I'm aware I'm using wx.DirDialog but is it possible to use the with statement with wx.DirDialog?

I get the following error when I try my code:

TypeError: DirDialog.ShowModal(): first argument of unbound method must have type 'DirDialog'

From this page, it seems I would have t close and clean it up manually.


Solution

  • This is probably a bug. You can submit bugs on wxPython's website here: https://github.com/wxWidgets/Phoenix/issues

    Be sure to check that this hasn't already been reported before you do so though.

    In the meantime, you can just subclass wx.DirDialog and make it work like a context manager. Here's an example:

    import wx
    
    class ContextDirDialog(wx.DirDialog):
    
        def __enter__(self):
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.Destroy()
    
    
    class MyPanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
    
            btn = wx.Button(self, label='Choose Folder')
            btn.Bind(wx.EVT_BUTTON, self.select_source_folder)
    
        def select_source_folder(self, event):
            with ContextDirDialog(self, message="Choose Source Directory",
                                  style=wx.DD_DEFAULT_STYLE) as dlg:
                if dlg.ShowModal() == wx.ID_CANCEL:
                    print('You cancelled the dialog!')
    
    class MyFrame(wx.Frame):
    
        def __init__(self):
            wx.Frame.__init__(self, None, title='Contexts')
            panel = MyPanel(self)
            self.Show()
    
    if __name__== '__main__':
        app = wx.App(False)
        frame = MyFrame()
        app.MainLoop()
    

    You might also find the following article helpful: