Question about WxNotebook, threads, and GUI refreshing

I’m running into a problem I’ve had before with wxRuby where the GUI
does not update while my App is processing some set of data. The fix for
this I know is to put the data processing piece in a new thread and in
the Wx::App code make a timer to pass the threads. This has always
worked in the past, but now my problem is slightly more complex and I’m
at a loss.

Basically I am trying to put together a bunch of small reporting apps
I’ve made into one single application using tabs to separate them. I’ve
redesigned each of the other applications so that they each contain
their own panel class and controller class (for doing the processing)
then I have the main application which contains the Wx::App and
Wx::Notebook and the notebook simply adds pages using instances of the
panel classes I created. So the problem (I assume) is that I’m not
setting up the thread switching properly for use with a Wx::Notebook.
Here is the main app code:

— MultiTool.rb —

require ‘wx’
require ‘wx_sugar/all’
require ‘panels/all.rb’

class MainNB < Wx::Notebook
def initialize(parent, id)
super(parent, id, Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
Wx::NB_TOP)

    fpar_page = add_page(FPARPanel.new(self), "Acct. Report", true, 
  1.  gsbis_page = add_page(GSBISPanel.new(self), "Inv. Scan", true, 
    
  2.  mpa_page = add_page(MPAPanel.new(self), "Product Addition", 
    

true, 0)
msrpc_page = add_page(MSRPCPanel.new(self), “SRP Change”, true,
0)
payparse_page = add_page(PayParsePanel.new(self), “Payroll
Report”, true, 0)

    set_selection(0)
end

end

class MyApp < Wx::App
def on_init
frame = Wx::Frame.new(nil, :size => Wx::Size.new(686, 303),
:title => “MultiTool”)
notebook = MainNB.new(frame, 0)

    t = Wx::Timer.new(self, 55)
    evt_timer(55) { Thread.pass }
    t.start(20)

    frame.show
end

end

MyApp.new.main_loop

— END —

So that is where I create the timer and pass the thread… then the
thread is actually created when a button is pressed on one of the panels
in the notebook. The end result is that whatever is in the new thread
just never executes. I’m trying to break this up into a larger but
easily maintainable set of applications which is why I have all the
files separated out in the way I do, but I’m really unsure of how this
affecting the execution of the code.

The code for the panels is all pretty lengthy and in the middle of being
cleaned up and re-written, but its basically in the form:

— example panel —

class GSBISPanel < Wx::Panel
def initialize(*args)
super(*args)

   # bunch of crap in a grid
   # button that starts data processing
   add(Wx::Button[:label => 'Run']) do |@b_run|
      listen(:button, @b_run, :run)
   end
end

def run
   t = Thread.new { #process a bunch of data (this never runs)}
end

end

— END example —

I hope I am explaining this thoroughly and clearly. If anyone has some
pointers or ideas of how to approach this please let me know.

thanks,
-alex

Hi Alex

Alex C. wrote:

I’m running into a problem I’ve had before with wxRuby where the GUI
does not update while my App is processing some set of data. The fix for
this I know is to put the data processing piece in a new thread and in
the Wx::App code make a timer to pass the threads. This has always
worked in the past, but now my problem is slightly more complex and I’m
at a loss.

I can’t see anything wrong with the way you’ve set things out. As the
etc/threaded.rb sample shows, there should be no problem with having
multiple ruby 1.8 threads running in the background of a wxRuby
application.

Perhaps ensure that you set abort_on_exception = true for each of the
child threads. I’ve sometimes been puzzled that a thread’s not running,
only to find that there’s some bug in the thread’s code which means it’s
crashed and stopped, but silently.

Incidentally, as of wxRuby 1.9.4, you’ll be able to use a slightly
neater notation to pass control among ruby threads, eg:

Wx::Timer.every(50) { Thread.pass }

to rotate every 50ms

Basically I am trying to put together a bunch of small reporting apps
I’ve made into one single application using tabs to separate them.
THere’s probably different ways to design this. Depending on what the
child notebooks are doing, you could run two timers, one to make ruby’s
threads run, and another to check a queue for updates to the GUI. Then
the child threads could add updates to this queue.

alex

If you are running 1.8.6, make sure you have patch level 36 or later.
There were some thread-related defects fixed at p36.