Re: What is the minimum number of lines to update a gui window without user clicking a button



I've changed Example 4 to use a TextView instead of a Label and
renamed report_progress() to gui_print().

//========== Example 5 Begin ============//
#include <gtkmm.h>
#include <unistd.h>
#include <queue>

class CallbackDispatcher {
public:
    CallbackDispatcher() {
        dispatcher.connect(sigc::mem_fun(this,
&CallbackDispatcher::on_dispatch));
    }

    typedef sigc::slot<void> Message;
    void send(Message msg) {
        Glib::Threads::Mutex::Lock lock(mutex);
        queue.push(msg);
        dispatcher();
    }

private:
    /* CallbackDispatcher may not be copied, so we must hide these
     * constructors. */
    CallbackDispatcher(const CallbackDispatcher&);
    CallbackDispatcher& operator=(const CallbackDispatcher&);

    Glib::Threads::Mutex mutex;
    std::queue<Message> queue;
    Glib::Dispatcher dispatcher;

    void on_dispatch() {
        Glib::Threads::Mutex::Lock lock(mutex);
        while (!queue.empty()) {
            queue.front()();
            queue.pop();
        }
    }
};

class Example {
private:
    Glib::RefPtr<Gtk::Application> app;
    Gtk::Window                    win;
    Gtk::TextView                  tv;
    Glib::RefPtr<Gtk::TextBuffer>  tb;
    CallbackDispatcher             callback_dispatcher;
    Glib::Threads::Thread         *thread;

    void gui_print(const Glib::ustring& str) {
        /* Get a function pointer to the set_text method we want to
         * use. We must explicitly declare the method pointer
         * signature because Gtk::TextBuffer::set_text is an
         * overloaded method. */
        void (Gtk::TextBuffer::*fptr)(const Glib::ustring&) =
&Gtk::TextBuffer::set_text;

        /* Create a functor that points at the TextBuffer method we
         * want to use. Because tb is a Glib::RefPtr and sigc::mem_fun
         * needs the actual Gtk::TextBuffer object, we must use
         * operator->(). See GNOME Bugzilla #495762. */
        sigc::slot<void, const Glib::ustring&> set_text_functor =
sigc::mem_fun(tb.operator->(), fptr);

        /* Bind the arguments of the functor to create a
         * sigc::slot<void> that can be sent to the callback
         * dispatcher.
         */
        sigc::slot<void> bound_functor = sigc::bind(set_text_functor, str);

        /* callback_dispatcher can execute any sigc::slot<void> on the
         * Main Loop. Since we have one now, send it.
         */
        callback_dispatcher.send(bound_functor);
    }

   /* This function is called on a separate thread so as to avoid
    * blocking GTK+'s main loop.
    */
    void blocking_operation() {
        /* This simulates a blocking process */
        sleep(5);
        gui_print("5% complete.");

        sleep(5);
        gui_print("15% complete.");

        sleep(5);
        gui_print("35% complete.");

        sleep(5);
        gui_print("55% complete.");

        sleep(5);
        gui_print("75% complete.");

        sleep(5);
        gui_print("95% complete.");

        sleep(5);
        gui_print("100% complete.");

        /* When the process is finished, we notify the GTK+ Main Loop by
         * using the dispatcher */
        callback_dispatcher.send(sigc::mem_fun(this,
&Example::blocking_operation_finished));
    };

    /* This function is called on GTK+'s main loop via a
     * Glib::Dispatcher */
    void blocking_operation_finished() {
        cleanup_thread();
        tb->set_text("Operation finished.");
    };

    void cleanup_thread() {
        /* We must call Glib::Threads::Thread::join() in order to
         * correctly clean up the resource. */
        if (thread) {
            thread->join();
            thread = NULL;
        }
    }

public:
    ~Example() {
        /* This will prevent the Window from being closed while
         * the blocking operation is ongoing. */
        cleanup_thread();
    }

    Example(int argc, char *argv[]) :
        app(Gtk::Application::create(argc, argv, "com.example")),
        tb(tv.get_buffer()),
        thread(NULL)
    {
        win.add(tv);
        win.show_all();
    }

    void run() {
        /* Create a slot to the blocking_operation() member function
         * to pass to Glib::Threads::Thread::create().
         */
        sigc::slot<void> op_functor = sigc::mem_fun(this,
&Example::blocking_operation);

        /* Create a worker thread to perform the blocking_operation
         * function.
         */
        thread = Glib::Threads::Thread::create(op_functor);

        /* Now set the text in the buffer.
         */
        tb->set_text("Operation started.");

        app->run(win);
    }
};

int main(int argc, char *argv[]) {
    Example example(argc, argv);

    example.run();
    return 0;
}
//========== Example 5 End ============//


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