Hi all, I''m looking for a way to get a block of code to execute once a modal dialog has been displayed (via a call to show_modal.) I was hoping to find some event that would fire when the window was shown, but the only one that seemed vaguely promising (evt_window_create) seems to do nothing at all, at least in my environment (Ruby 1.9.1 on Win32, wxruby 2.0.1.) Here''s a very simple (non-modal) example, which fails to print ''Created!'' as I''d (perhaps naively) expect it to: -------------------------- require "wx" class TestFrame < Wx::Frame def initialize(*args) super(*args) puts ''In Initialize!'' evt_window_create { puts ''Created!'' } end end class TestApp < Wx::App def on_init TestFrame.new(nil, -1, ''Test!'').show() end end TestApp.new.main_loop -------------------------- (incidentally, the RubyForge doc page here: http://wxruby.rubyforge.org/doc/windowcreateevent.html still refers to this event as ''evt_create'', which might be worth fixing, but that''s a different issue.) I don''t know if I''m misusing this event, or if there''s a bug here somewhere, but at any rate I''m open to other approaches if this isn''t the right way to go. My current solution is an icky hack involving timers which I''d love to be able to replace with something more sensible. I''m pretty new to both Ruby and wxRuby, so I apologize in advance if I''m missing something obvious here. Ben
Alex Fenton
2009-Sep-24 09:02 UTC
[wxruby-users] Running code after a modal dialog is shown
Ben Van Hof wrote:> I''m looking for a way to get a block of code to execute once a modal > dialog has been displayed (via a call to show_modal.)I would probably do it by subclassing the modal dialog, providing your own show_modal method and executing the code there after super has been called. If you want it to run variable code provided by the caller, pass and capture in the constructor. eg (untested) class MyDialogWithShowHook < Wx::Dialog def initialize([args], &block) super(*args) @hook = block end def show_modal super @hook.call end end> I was hoping to find some event that would fire when the window was > shown, but the only one that seemed vaguely promising > (evt_window_create) seems to do nothing at all, at least in my > environment (Ruby 1.9.1 on Win32, wxruby 2.0.1.)There is Wx::ShowEvent which can be requested for processing with evt_show. However in wxWidgets it isn''t provided on OS X, at least in some versions, so you might want to avoid that. It''s not a CommandEvent so you need to call it on the instance you''re capturing. Again, untested dlg = Wx::Dialog.new(...) dlg.evt_show { puts "i''m here" } dlg.show_modal evt_window_create is low level and only generally meant for debugging rather than GUI logic control. evt_window_create I think fires in a parent frame when its child windows are created, and for app when any window is created. But the exact meaning and timing of "created" may vary with the underlying toolkit - on OS X, for example, I think it fires for all the child widgets in the frame as the frame''s constructor returns.> (incidentally, the RubyForge doc page here: > http://wxruby.rubyforge.org/doc/windowcreateevent.html > still refers to this event as ''evt_create'', which might be worth > fixing, but that''s a different issue.)Thanks, I''ve fixed that in SVN.> I don''t know if I''m misusing this event, or if there''s a bug here > somewhere, but at any rate I''m open to other approaches if this isn''t > the right way to go. My current solution is an icky hack involving > timers which I''d love to be able to replace with something more sensible.Hopefully the above will help, but if you want to say more about what you''re trying to achieve I''m sure people will be happy to offer some advice. alex
Ben Van Hof
2009-Sep-24 16:24 UTC
[wxruby-users] Running code after a modal dialog is shown
On Thu, 24 Sep 2009, Alex Fenton wrote:> I would probably do it by subclassing the modal dialog, providing your > own show_modal method and executing the code there after super has been > called. If you want it to run variable code provided by the caller, pass > and capture in the constructor. eg (untested)Thanks, Alex, for your quick and thoughtful response. I tried your first approach out; the problem is that when you call super, control doesn''t return until the modal dialog has been closed:> def show_modal > super > @hook.call # we don''t get here until the dialog is closed > end> There is Wx::ShowEvent which can be requested for processing with > evt_show. However in wxWidgets it isn''t provided on OS X, at least in > some versions, so you might want to avoid that. It''s not a CommandEvent > so you need to call it on the instance you''re capturing. Again, untested > > dlg = Wx::Dialog.new(...) > dlg.evt_show { puts "i''m here" } > dlg.show_modalI gave this a try, too, but evt_show fires before the window is actually visible on the screen (at least on win32), and so still doesn''t get me what I want.> Hopefully the above will help, but if you want to say more about what > you''re trying to achieve I''m sure people will be happy to offer some > advice.Makes sense. I''ve got a long-running external process that I want to be able to report progress for, using a small modal dialog that just contains a progress bar and cancel button (it needs to be modal, since I''ve got a main window underneath it that I don''t want the user interacting with while the process runs.) My initial approach was to spawn a worker thread and communicate progress back to the UI periodically, but ran into some ugly problems having a popen''ed process on one thread and wxRuby on another. I wasted way too much time trying to get that to work, and am basically considering that avenue of investigation closed (if you''re really interested in the gory details I can provide them, but I think it boils down to a problem with having non-Ruby code in both threads interacting badly with the GIL.) My current approach, then, is to keep it all in one thread: open the dialog, start the process, and keep the UI responsive by periodically calling Wx::get_app().yield. This all works great, except that I''m currently having to use a timer event to get my code started once the modal dialog is displayed, and it seems like there should be a less-hacky solution. Anyway, I hope that''s enough background on what I''m trying to accomplish here. If it spurs any additional ideas, I''d love to hear them. Ben