I''ve seen a few e-mails about multithreading with respect to wxruby but nothing recent. Unless I''m mistaken, and that may be, there still appear to be problems. The following code seems to hang my spawned thread in favor of the wxruby event loop: Thread.new do puts "in thread" loop do sleep 5 puts "looping" end end puts "main loop" app.main_loop "in thread" and "main loop" appear at approximately the same time, contending for STDOUT. However, "looping" never appears on STDOUT. Is wxruby halting all non wxruby threads? Evan Light IMs (all): sleight42 http://evan.tiggerpalace.com _______________________________________________ wxruby-users mailing list wxruby-users@rubyforge.org http://rubyforge.org/mailman/listinfo/wxruby-users
Evan Light wrote:> I''ve seen a few e-mails about multithreading with respect to wxruby > but nothing recent. Unless I''m mistaken, and that may be, there still > appear to be problems.I think you''re right that other ruby threads don''t receive very high priority relative to wxruby''s thread. However, you can explicitly tell wxruby to let other threads run when the GUI is idle, by adding something like the following to your App''s on_init method. evt_idle { Thread.pass } If you simply want to do timed events, Wx::Timer class should work. This code moves a Gauge forward once per second timer = Wx::Timer.new(self, 42) # 42 is an arbitrary id evt_timer(42) { | e | @gauge.value += 1 } timer.start(1000) # 1000ms = 1s interval Do other ruby GUI co-operate better with ruby''s lightweight threadS? alex
First off, thanks for the reply. On Apr 29, 2007, at 5:13 AM, Alex Fenton wrote:> Evan Light wrote: >> I''ve seen a few e-mails about multithreading with respect to wxruby >> but nothing recent. Unless I''m mistaken, and that may be, there >> still >> appear to be problems. > I think you''re right that other ruby threads don''t receive very high > priority relative to wxruby''s thread. >It certainly seems that way. Wx appears to be doing something tricky underneath the covers somewhere with respect to other Threads. I ratcheted the priority on my Thread higher and higher to absolutely no avail. If I had to guess, Wx is downgrading the priority of other Threads while significantly increasing the priority of the event loop thread.> However, you can explicitly tell wxruby to let other threads run when > the GUI is idle, by adding something like the following to your App''s > on_init method. > > evt_idle { Thread.pass } >Cute idea. I''d tried playing with the idle event handler; however, I hadn''t specifically tried getting the event handler thread to pass. Unfortunately, this simply causes my program to exit immediately despite the following call to Wx:App.main_loop class MyApp < Wx::App def on_init evt_idle {Thread.pass} end end app = MyApp.new Thread.new do loop do puts "foo" end end puts "main loop" app.main_loop This causes "foo" to print several times but Wx, for some misbegotten reason, seems to dump out of the main loop and exit without a RuntimeError.> If you simply want to do timed events, Wx::Timer class should work. > This > code moves a Gauge forward once per second > > timer = Wx::Timer.new(self, 42) # 42 is an arbitrary id > evt_timer(42) { | e | @gauge.value += 1 } > timer.start(1000) # 1000ms = 1s interval >Ah, yes. I didn''t look for this but, if memory serves, X has a similar way of handling timed events without additional threads. Sadly, I didn''t think to look for this. Be it enough to say that I tend to shy away from thick client development when I can. This should do the trick! Thank you!> Do other ruby GUI co-operate better with ruby''s lightweight threadS? >Good question! I''ll play with Ruby/Tk and FXRuby and let you know. Evan Light IMs (all): sleight42 http://evan.tiggerpalace.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wxruby-users/attachments/20070429/44906c23/attachment.html
> Unfortunately, this simply causes my program to exit immediately > despite the following call to Wx:App.main_loop > > class MyApp < Wx::App > def on_init > evt_idle {Thread.pass} > end > end...> This causes "foo" to print several times but Wx, for some misbegotten > reason, seems to dump out of the main loop and exit without a > RuntimeError.The problem here is just that App#on_init isn''t returning a true value - the return value of evt_idle is nil. You have to a return a true value from on_init, signalling successful initialisation, otherwise the main_loop is never entered and execution ends. That aside, however, I''ve tried on a few more platforms and am getting inconsistent results using ''evt_idle { Thread.pass }''. On OS X and the current dev branch, which I tried before, it works well. However OS X + 0.0.39 segfaults. And on Linux/GTK with either dev or 0.0.39 the non-GUI thread seems to be running slow, and the application won''t close on exit. Perhaps some tweaking of the Ruby thread code would help. What OS are you on?>> If you simply want to do timed events, Wx::Timer class should work. This >> code moves a Gauge forward once per second...>> evt_timer(42) { | e | @gauge.value += 1 }PS - this is wxSugar code - not wxRuby. ...> This should do the trick!:)>> Do other ruby GUI co-operate better with ruby''s lightweight threadS? >> > > Good question! I''ll play with Ruby/Tk and FXRuby and let you know.That would be useful. If another toolkit has addressed this we may be able to borrow their approach. alex
Alex Fenton wrote:> That aside, however, I''ve tried on a few more platforms and am getting > inconsistent results using ''evt_idle { Thread.pass }''. >Sorry to reply to my own post, but just to let you know that using Wx::Timer + Thread.pass + evt_timer inside App#on_init seems to work well on OS X (dev, not 0.0.39), GTK (both) and Windows (both). def on_init t = Wx::Timer.new(self, 55) evt_timer(55) { Thread.pass } t.start(100) ... A sleep(1) loop plus a 100ms timer runs every 1s to 1.1s, which is what I''d expect. This would be suitable for a background task; Wx::Timer alone would probably be better for a timed loop. A quick search suggests that the ruby ports of QT, GTK and Fox all suffer the same problem and recommend a similar solution. hth a
On Apr 29, 2007, at 1:50 PM, Alex Fenton wrote:> > What OS are you on?OS X 10.4.9>>> If you simply want to do timed events, Wx::Timer class should >>> work. This >>> code moves a Gauge forward once per second > ... > ... >> This should do the trick! > :) >Yup, the timer works. Now I''m just fighting what is probably PEBKAC. Trying to remove all of the widgets within a Sizer and then add new ones. Having problems there.>>> Do other ruby GUI co-operate better with ruby''s lightweight threadS? >>> >> >> Good question! I''ll play with Ruby/Tk and FXRuby and let you know. > That would be useful. If another toolkit has addressed this we may be > able to borrow their approach. >Sounds like you just answered that one in your latest e-mail. Great information, BTW, thanks! Being able to spawn another thread is hugely preferable to making the event loop wait for some or another operation. Evan Light IMs (all): sleight42 Skype-In: (703) 531-8484 http://evan.tiggerpalace.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wxruby-users/attachments/20070429/515aab6c/attachment-0001.html
Uh, woops. That Sizer.remove is now unsupported may be the problem. So how does one empty sizer? Simply creating a new sizer and calling Window#set_sizer seems to have unusual effects... On Apr 29, 2007, at 2:31 PM, Evan Light wrote:> Trying to remove all of the widgets within a Sizer and then add > new ones. Having problems there.Evan Light IMs (all): sleight42 Skype-In: (703) 531-8484 http://evan.tiggerpalace.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wxruby-users/attachments/20070429/a3bfd395/attachment.html
One final self reply. Window#destroy_children seems to mostly do the trick. Still have some other issues but closer now. On Apr 29, 2007, at 2:44 PM, Evan Light wrote:> Uh, woops. That Sizer.remove is now unsupported may be the > problem. So how does one empty sizer? Simply creating a new sizer > and calling Window#set_sizer seems to have unusual effects... > > On Apr 29, 2007, at 2:31 PM, Evan Light wrote: > >> Trying to remove all of the widgets within a Sizer and then add >> new ones. Having problems there. >Evan Light IMs (all): sleight42 Skype-In: (703) 531-8484 http://evan.tiggerpalace.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wxruby-users/attachments/20070429/e4a71f1d/attachment.html
> Trying to remove all of the widgets within a Sizer and then add new > ones. Having problems there.Perhaps something like sizer = Wx::BoxSizer.new(Wx::VERTICAL) sizer.add( Wx::Button.new(self, -1, ''water'') ) sizer.add( Wx::Button.new(self, -1, ''wood'') ) self.set_sizer(sizer) get_children.length.times { sizer.remove(0) } sizer.add( Wx::Button.new(self, -1, ''ice'') ) sizer.add( Wx::Button.new(self, -1, ''fire'') ) sizer.add( Wx::Button.new(self, -1, ''earth'') ) sizer.layout If things aren''t looking right after some removals or additions, make sure you are calling sizer.layout to recalculate the widgets'' sizes a