1

I am having trouble with setting the focus of a button AFTER a modal dialog is destroyed.

Is there a call I can make to destroy the modal dialog or to stop it from being modal and then destroy it?

When the wx.PostEvent triggers an event it forces a Destroy on a modal dialog however as I understand it, it doesn't get destroyed immediately which means that the buttons are still disabled when I do a SetFocus().

import wx
import wx.lib.newevent
from threading import Thread
import time
processFinishes, EVT_PROCESS_FINISHES = wx.lib.newevent.NewEvent()

class Dummy(Thread):
    def __init__(self, arg):
        super(Dummy, self).__init__()
        self.arg = arg

    def run(self):
        time.sleep(15)
        print "Posting"
        wx.PostEvent(self.arg , processFinishes(result=(None)))


class MyRegion(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        self.button = wx.Button(self, label="Click me!")
        self.mybutton2 = wx.Button(self, label="I should have focus!!!")
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.button, 0, wx.ALL)
        sizer.Add(self.mybutton2, 0, wx.ALL)
        self.SetSizerAndFit(sizer)
        self.Bind(wx.EVT_BUTTON, self.OnButton)
        self.Bind(EVT_PROCESS_FINISHES, self.OnFinish)
        self.progress = None
        self.t = Dummy(self)

    def OnButton(self, event):
        self.progress = wx.ProgressDialog("Processing",
                                          "Please wait while the processing finishes.")
        self.progress.Pulse()
        self.progress.ShowModal()
        self.t.start()

    def OnFinish(self, _event):
        print "destroyed"
        self.progress.Destroy()
        print "now setting foucs"
        self.mybutton2.SetFocus()

if __name__ == "__main__":
    app = wx.App()
    frame = MyRegion(None)
    frame.Show()
    app.MainLoop()

EDIT:

When attempting to stop the progress dialog from being modal, the following code gives me errors indicating that the ProgressDialog is not modal whereas it clearly is:

    .....
    def OnButton(self, event):
        # wx.ProgressDialog can also be created with
        # style=wx.wx.PD_APP_MODAL which cannot be made non-modal later on
        # i.e. EndModal() does not work
        self.progress = wx.ProgressDialog("Processing",
                                          "Please wait while the processing finishes.")
        self.progress.Pulse()
        self.progress.ShowModal()
        self.t.start()

    def OnFinish(self, _event):
        print "destroyed"
        # By changing this line
        # wx complains indicating that the progress dialog
        # is not modal whereas a ShowModal was used

        self.progress.EndModal(0) # -> produces a "wx._core.PyAssertionError: C++ assertion "IsModal()" failed at ..\..\src\msw\dialog.cpp(221) in wxDialog::EndModal(): EndModal() called for non modal dialog"
        print "now setting foucs"
        self.mybutton2.SetFocus()
Har
  • 3,727
  • 10
  • 41
  • 75

1 Answers1

2

The modal dialog reenables everything by the time ShowModal() returns, so just call OnFinish() directly from OnButton().

However notice that wxProgressDialog is not a modal dialog at all (it would be pretty useless if it were as you wouldn't be able to call Update() on it!), so in its case you should just destroy it when you are done with it (or use wxPD_AUTO_HIDE style to tell it to go away on its own when maximal progress value is reached).

VZ.
  • 21,740
  • 3
  • 39
  • 42
  • but the problem is that say the computation between OnButton and OnFinish was a long running task and that the GUI would block due to that computation how could you link the start of the computation and the end of the computation with ShowModal() and its return? P.s this is a dummy example of the problem im seeing – Har Dec 12 '14 at 09:58
  • OK, I see the problem. You just shouldn't be using `ShowModal()` on `wxProgressDialog` at all, it's not supposed to be used like this, see any example of its use. – VZ. Dec 12 '14 at 15:02
  • but regardless of what I dialog box I use I get the same problem,.If I used a MessageBox before and after or any other form of dialog, that before and after is whats causing an issue. – Har Dec 15 '14 at 08:27
  • Modal dialogs block the program execution, this is why they are modal. If you don't want this to happen, do not call `ShowModal()`. What exactly is the question? – VZ. Dec 15 '14 at 11:32
  • the question is how do you have a modal dialog and manually control as to when it stops blocking the execution of the program. – Har Jan 03 '15 at 16:47
  • 1
    Typically you don't, a modal dialog remains shown until it is dismissed by user. But you can call `EndModal()` on it if you really need to, the important thing to understand is that you would have to do it from some event handler as your code showing the dialog won't get the control back until it is dismissed. – VZ. Jan 03 '15 at 18:33
  • I now understand your point on how to use Progress dialogs as I should not use ShowModal on them because Progress Dialogs show progress and do not normally expect user input (apart from cancel) so no need to block for user input. There is a style however in the wx.ProgressDialog() which says style=wx.PD_APP_MODAL but even with that style put in or by using ShowModal(), I cant use EndModal since I get in the two circumstances this: "wx._core.PyAssertionError: C++ assertion "IsModal()" failed at ..\..\src\msw\dialog.cpp(221) in wxDialog::EndModal(): EndModal() called for non modal dialog" – Har Jan 14 '15 at 10:55
  • I don't understand what are you doing. `wxProgressDialog` is not, actually, modal and I don't see why would you ever want to call `EndModal()` on it... – VZ. Jan 14 '15 at 17:46
  • I think that's where the confusion is, it behaves like a modal dialog but isn't really a modal dialog... so im not sure what's going on since a progress dialog is a subclass of a wx.Dialog which has that modal functionality which works but doesn't seem to be working properly with wx.ProgressDialog – Har Jan 15 '15 at 11:35
  • 1
    Yes, this is not a great design from OO point of view as you indeed can't call `ShowModal()` on this class. But in practice this is hardly a problem because you don't need to and showing a _progress_ dialog, which is supposed to be updated while it is shown, modally wouldn't make any sense anyhow. – VZ. Jan 15 '15 at 14:24