Re: Gtkmm thread example



Murray Cumming wrote:
On Fri, 2008-06-06 at 16:07 -0400, Damon Register wrote:
[snip]
dispatch2.cpp:133: error: `bind' is not a member of `SigC'
[snip]

This means that the code was for libgsigc++ 1.2 instead of libgsigc++
2.x. Such code can generally be ported by changing SigC:: to sigc:: .

That was the clue that I needed.  I changed all the SigC places as you
suggested.  I still got compile errors but since you explained that SigC
is 1.2 while sigc is 2.x, I realized that the glibmm version of the
dispatcher example is for sigc.  I was able to match the sigc calls with
the ones from the glibmm example and fix the gtkmm one accordingly.
It actually compiles and runs.  Thanks.

May I ask one final favor on this thread?  While it seems to compile
and run, could you please look at what I did and see if what I changed
seems to be the right thing to do?  I changed all the SigC to sigc and
where I changed anything else, I put //changed at the end of the line.

Damon Register

/*
 * Glib::Dispatcher example -- cross thread signalling
 * by Daniel Elstner
 *
 * Copyright (c) 2005  Free Software Foundation
 */

#include <sigc++/class_slot.h>
#include <glibmm.h>
#include <gtkmm/box.h>
#include <gtkmm/button.h>
#include <gtkmm/buttonbox.h>
#include <gtkmm/main.h>
#include <gtkmm/progressbar.h>
#include <gtkmm/stock.h>
#include <gtkmm/window.h>

#include <algorithm>
#include <functional>
#include <list>


namespace
{

class ThreadProgress : public Gtk::ProgressBar
{
public:
  ThreadProgress();
  virtual ~ThreadProgress();

  void launch();
  sigc::signal<void>& signal_finished();  //changed Signal0 to signal

private:
  unsigned int        progress_;
  Glib::Dispatcher    signal_increment_;
  sigc::signal<void> signal_finished_;   //changed Signal0 to signal

  void progress_increment();
  void thread_function();
};

class MainWindow : public Gtk::Window
{
public:
  MainWindow();
  virtual ~MainWindow();

  void launch_threads();

protected:
  virtual bool on_delete_event(GdkEventAny* event);

private:
  std::list<ThreadProgress*>  progress_bars_;
  Gtk::Button*                close_button_;

  void on_progress_finished(ThreadProgress* progress);
};


ThreadProgress::ThreadProgress()
:
  progress_ (0)
{
  // Connect to the cross-thread signal.
  signal_increment_.connect(sigc::mem_fun(*this, &ThreadProgress::progress_increment));  //changed slot to mem_fun
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
  // Create a non-joinable thread -- it's deleted automatically on thread exit.
  Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), false);  //changed slot_class to mem_fun
}

sigc::signal<void>& ThreadProgress::signal_finished()  //changed Signal0 to signal
{
  return signal_finished_;
}

void ThreadProgress::progress_increment()
{
  // Use an integer because floating point arithmetic is inaccurate --
  // we want to finish *exactly* after the 1000th increment.
  ++progress_;

  const double fraction = double(progress_) / 1000.0;
  set_fraction(std::min(fraction, 1.0));

  if(progress_ >= 1000)
    signal_finished_();
}

void ThreadProgress::thread_function()
{
  Glib::Rand rand;
  int usecs = 5000;

  for(int i = 0; i < 1000; ++i)
  {
    usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
    Glib::usleep(usecs);

    // Tell the GUI thread to increment the progress bar value.
    signal_increment_();
  }
}


MainWindow::MainWindow()
:
  close_button_ (0)
{
  set_title("Thread Dispatcher Example");

  Gtk::VBox *const vbox = new Gtk::VBox(false, 10);
  add(*Gtk::manage(vbox));
  vbox->set_border_width(10);

  for(int i = 0; i < 5; ++i)
  {
    ThreadProgress *const progress = new ThreadProgress();
    vbox->pack_start(*Gtk::manage(progress), Gtk::PACK_SHRINK);
    progress_bars_.push_back(progress);

    progress->signal_finished().connect(
        sigc::bind<1>(sigc::mem_fun(*this, &MainWindow::on_progress_finished), progress)); //changed bind to bind<1> and slot to mem_fun
  }

  Gtk::ButtonBox *const button_box = new Gtk::HButtonBox();
  vbox->pack_end(*Gtk::manage(button_box), Gtk::PACK_SHRINK);

  close_button_ = new Gtk::Button(Gtk::Stock::CLOSE);
  button_box->pack_start(*Gtk::manage(close_button_), Gtk::PACK_SHRINK);
  close_button_->set_flags(Gtk::CAN_DEFAULT);
  close_button_->grab_default();
  close_button_->set_sensitive(false);
  close_button_->signal_clicked().connect(sigc::mem_fun(*this, &Gtk::Widget::hide));  //changed slot to mem_fun

  show_all_children();
  set_default_size(300, -1);
}

MainWindow::~MainWindow()
{}

void MainWindow::launch_threads()
{
  std::for_each(
      progress_bars_.begin(), progress_bars_.end(),
      std::mem_fun(&ThreadProgress::launch));
}

bool MainWindow::on_delete_event(GdkEventAny*)
{
  // Don't allow closing the window before all threads finished.
  return !progress_bars_.empty();
}

void MainWindow::on_progress_finished(ThreadProgress* progress)
{
  progress_bars_.remove(progress);

  // Enable the close button when all threads finished.
  if(progress_bars_.empty())
    close_button_->set_sensitive(true);
}

} // anonymous namespace


int main(int argc, char** argv)
{
  Glib::thread_init();
  Gtk::Main main_instance (&argc, &argv);

  MainWindow window;

  // Install a one-shot idle handler to launch the threads
  // right after the main window has been displayed.
  Glib::signal_idle().connect(
      sigc::bind_return(sigc::mem_fun(window, &MainWindow::launch_threads), false));  //changed slot to mem_fun

  Gtk::Main::run(window);

  return 0;
} 	


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]