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