Hi, We have quite a large codebase in Ruby which uses Log4r to log errors, warnings etc. I have been trying to create a log window dialog using wxRuby that can be popped up if a piece of code generates an error or warning in one of our scripts. E.g. GUI::LogWindow::show_dialog( ) do # Do something that will log messages. end def LogWindow::show_dialog( log, auto_popup = false, title = ''Log'', &block ) log_window_thread = Thread.new do begin LogDialogApp.new( log, auto_popup, title ).main_loop( ) rescue Exception => ex throw unless ( ''exit'' == ex.message ) end end yield if ( block_given? ) log_window_thread.join( ) end My current problem is that when the wxRuby''s main_loop is invoked no Ruby code gets executed. Is there any way around this? Or is this a limitation of using wxRuby? Any suggestions appreciated. Cheers, David -- Posted via http://www.ruby-forum.com/.
Mario Steele
2009-Jan-15 11:18 UTC
[wxruby-users] wxRuby dialog separate from main Ruby script execution
Well, given the example, it''s kinda confusing how you are setting this Log Window class up, and how things are truely initializing. First of all, you really should be starting the main_loop at the top level of your code, not inside a Window class method, even if it''s a module/singleton method. Second, if your using threads, you need to setup a point for wxRuby to break from it''s processing of code internally in the main_loop, to yield back control to Ruby under Ruby 1.8. Ruby 1.9 will work perfectly fine, as the threads are system native threads, not Green threads as in 1.8. Third, if you have a single point of entry into your own application, that starts everything off, it would be best to call that method inside the on_init of your App instance inside a thread, and then do the previous method of yielding control back to ruby from wxRuby. You can yield the control back to Ruby, by doing Wx::Timer.every(55) { Thread.pass }. This will execute a timer every 55 milliseconds, that will call Thread.pass to give the next thread a bit of the CPU Scheduling, before returning back to the wxRuby main_loop. Lastely, if you don''t have a single point of entry into your application, then I would suggest making one, and doing as I described above, as this will make things easier to track, should something go wrong. hth, Mario On Thu, Jan 15, 2009 at 4:29 AM, David Muir <lists at ruby-forum.com> wrote:> Hi, > > We have quite a large codebase in Ruby which uses Log4r to log errors, > warnings etc. I have been trying to create a log window dialog using > wxRuby that can be popped up if a piece of code generates an error or > warning in one of our scripts. > > E.g. > GUI::LogWindow::show_dialog( ) do > # Do something that will log messages. > end > > def LogWindow::show_dialog( log, auto_popup = false, title = ''Log'', > &block ) > log_window_thread = Thread.new do > begin > LogDialogApp.new( log, auto_popup, title ).main_loop( ) > rescue Exception => ex > throw unless ( ''exit'' == ex.message ) > end > end > > yield if ( block_given? ) > log_window_thread.join( ) > end > > My current problem is that when the wxRuby''s main_loop is invoked no > Ruby code gets executed. Is there any way around this? Or is this a > limitation of using wxRuby? > > Any suggestions appreciated. > Cheers, > David > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > wxruby-users mailing list > wxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/wxruby-users >-- Mario Steele http://www.trilake.net http://www.ruby-im.net http://rubyforge.org/projects/wxruby/ http://rubyforge.org/projects/wxride/ -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/wxruby-users/attachments/20090115/f2d92c02/attachment.html>
Alex Fenton
2009-Jan-15 11:29 UTC
[wxruby-users] wxRuby dialog separate from main Ruby script execution
David Muir wrote:> My current problem is that when the wxRuby''s main_loop is invoked no > Ruby code gets executed. Is there any way around this? Or is this a > limitation of using wxRuby?It''s a limitation of Ruby 1.8''s green threads with C-based event loops. There is a workaround - add something like this in your App.run block / App#on_init method: Wx::Timer.every(25) { Thread.pass } Alternately, use Ruby 1.9 which I find does not have this problem, because there are real system threads underneath Ruby threads. However you should not update a GUI from the non-main thread. For further, have a look at the etc/threaded.rb sample in the distribution, and previous discussions on this list on wxRuby + threads. hth a
David Muir
2009-Jan-15 12:23 UTC
[wxruby-users] wxRuby dialog separate from main Ruby script execution
Hi, Thanks for the swift responses guys. The reason I don''t have a single point of entry, and spawned a thread for the UI, is because I want this as a bolt on to existing scripts. Such that existing scripts can be run with displaying a log when the end-user runs it or not displaying a UI when an automated process is running the script(s). Having said that I''ll have a go at refactoring the log window taking your comments on board, and checking other threads, to see if I can work something out. Cheers, Dave -- Posted via http://www.ruby-forum.com/.
Alex Fenton
2009-Jan-15 13:17 UTC
[wxruby-users] wxRuby dialog separate from main Ruby script execution
David Muir wrote:> The reason I don''t have a single point of entry, and spawned a thread > for the UI, is because I want this as a bolt on to existing scripts. > > Such that existing scripts can be run with displaying a log when the > end-user runs it or not displaying a UI when an automated process is > running the script(s).I don''t know Log4r but you can define custom Loggers etc. Define one that call Wx::log_message, Wx::log_warn etc in response to the Log4r calls in your core file. Your UI shell is going to look something like the structure below: hth alex __ require ''wx'' ### Custom outputter /logger here # What to run scripts = [ ''foo.rb'' ] Wx::App.run do Wx::log_message(''Starting'') t = Thread.new do scripts.each do | script | Wx::log_message("Running #{script}") load script end end Wx::Timer.every(25) { Thread.pass } true end
David Muir
2009-Jan-16 12:19 UTC
[wxruby-users] wxRuby dialog separate from main Ruby script execution
Hi guys, I had some success yesterday so thought I should complete this thread by showing how I got it working. The LogWindowDialog class is not included because it includes a lot of details that are irrelevant for the topic. In that class I create a Log4r outputter and formatter to pass LogEvent objects straight to the dialog which are then serialised and output into a TextCtrl widget. Seems to work fairly well with the few examples I''ve tried. If the Ruby script kicks off an external app the UI will be unresponsive. Code below. Hope it helps others. Cheers, Dave # # == Description # Generic log window dialog that integrates with our Pipeline::Log # objects for displaying log messages to users. # # === Example Usage # # To auto-popup the display of the log dialog: # Pipeline::GUI::LogWindow::show_dialog( true ) do # # Do something that will log messages, dialog only displayed on # # errors. # end # # # To force the display of the log dialog: # Pipeline::GUI::LogWindow::show_dialog( ) do # # Do something that will log messages # end # class LogWindow < Wx::App #--------------------------------------------------------------------- # Class Methods #--------------------------------------------------------------------- def initialize( log, auto_popup, title = ''Log'', &block ) super( ) @log = log @auto_popup = auto_popup @title = title @proc = Proc.new( ) do yield end end # # Use this method to explicitly display a log dialog box. Only # log messages generated after this call will be displayed. # def LogWindow::show_dialog( auto_popup = false, log = LogSystem::instance().rootlog, title = ''Log'' ) begin dlg = LogWindow.new( log, auto_popup, title ) do yield if ( block_given? ) end dlg.main_loop( ) rescue Exception => ex throw ex unless ( ''exit'' == ex.message ) end end #--------------------------------------------------------------------- # Instance Methods #--------------------------------------------------------------------- def on_init( ) Wx::Timer::every( 25 ) do Thread::pass( ) end dlg = LogWindowDialog::new( @log, @title, @auto_popup ) dlg.show( ) unless ( @auto_popup ) script_thread = Thread.new do @proc.call( ) exit( ) if ( @auto_popup and ( not dlg.is_shown ) ) end script_thread.join( ) end end # # == Description # Log window dialog. # class LogWindowDialog < Wx::Dialog ... end -- Posted via http://www.ruby-forum.com/.
Alex Fenton
2009-Jan-17 08:48 UTC
[wxruby-users] wxRuby dialog separate from main Ruby script execution
David Muir wrote:> I had some success yesterday so thought I should complete this thread by > showing how I got it working. >Thanks for sharing this.> Seems to work fairly well with the few examples I''ve tried. If the Ruby > script kicks off an external app the UI will be unresponsive. >The trick is to call Wx::app.yield or Wx::safe_yield (the latter in SVN only), while an external task is running, to tell Wx to process events and update the UI alex