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



Mr. James,
This reply has 3 examples. The last time I sent you a complete
solution you never indicated how it was insufficient, so please be
sure read this entire message.

The minimum amount of lines to use a TextView:

//========== Example 1 Begin ============//
#include <gtkmm.h>

int main(int argc, char *argv[]) {
    Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create(argc, argv, "com.example");
    Gtk::Window win;
    Gtk::TextView tv;

    tv.get_buffer()->set_text("Hello world");
    win.add(tv);
    win.show_all();
    app->run(win);
    return 0;
}
//========== Example 1 End ============//

In your previous emails you have been expressing a desire to output
the result of some long-lasting process to your window. As your
problem was posed to the list it was a contrived problem that had no
simple solution. Most GUI programs start operations by having the user
interact with the window, either by pressing a button or selecting a
menu item.

Nonetheless, I have created another example program that performs a
blocking operation in thread and changes the value of a TextView when
the operation is finished. Note that in the quest for minimality I am
utilizing some features of Gtkmm and C++ that are rarely shown in
beginner examples (such as the ref-to-pointer and sigc::ref()).

This example is 34 lines with no comments or whitespace. But I have
gone ahead and added comments.

//========== Example 2 Begin ============//
#include <gtkmm.h>
#include <unistd.h> /* for sleep() */

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

/* This function is called on a separate thread so as to avoid
 * blocking GTK+'s main loop.
 */
void blocking_operation(Glib::Dispatcher& dispatcher) {
    /* This simulates a "blocking" process */
    sleep(10);

    /* When the process is finished, we "notify" the GTK+ Main Loop by
     * using the dispatcher */
    dispatcher();
}

/* This function is called on GTK+'s main loop via a
 * Glib::Dispatcher */
void blocking_operation_finished(const Glib::RefPtr<Gtk::TextBuffer>& tb,
                                 Glib::Threads::Thread *&thread) {
    cleanup_thread(thread);
    tb->set_text("Operation finished.");
}

int main(int argc, char *argv[]) {
    Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create(argc, argv, "com.example");
    Gtk::Window win;
    Gtk::TextView tv;
    Glib::RefPtr<Gtk::TextBuffer> tb = tv.get_buffer();
    Glib::Dispatcher dispatcher;
    Glib::Threads::Thread *blocking_operation_thread = NULL;

    /* Because I'm not using a class to encapsulate the above objects
     * and the methods (to keep it "simple"), I need to create
     * functors that are bound with these local variables.
     *
     * Note sigc::ref() is used here. Without it sigc::bind would try
     * to copy the dispatcher in this scope. We do not need to use
     * sigc::ref() on tb because RefPtr is a copyable pointer.
     */
    sigc::slot<void> op_functor = sigc::bind(&blocking_operation,
sigc::ref(dispatcher));

    sigc::slot<void> op_finished_functor =
sigc::bind(&blocking_operation_finished,
                                                      tb,

sigc::ref(blocking_operation_thread));

    /* The dispatcher will be used when the operation has finished.
     * Here we set the function the dispatcher will call on the "main
     * thread" -- a.k.a. GTK+'s Main Loop.
    */
    dispatcher.connect(op_finished_functor);

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

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

    win.add(tv);
    win.show_all();
    app->run(win);

    cleanup_thread(blocking_operation_thread);
    return 0;
}
//========== Example 2 End ============//

If one accepts the slight textual overhead of using a class, I have
provided another solution. This allows more straightforward use of
slots/functors, utilizing only sigc::mem_fun().

This example is 46 lines with no comments or whitespace.
//========== Example 3 Begin ============//
#include <gtkmm.h>
#include <unistd.h> /* for sleep() */

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

   /* 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(10);

        /* When the process is finished, we "notify" the GTK+ Main Loop by
         * using the dispatcher */
        dispatcher();
    };

    /* 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)
    {
        /* Create a slot (a.k.a. functor) to the
         * blocking_operation_finished() member function for the
         * dispatcher to execute.
         */
        sigc::slot<void> op_finished_functor = sigc::mem_fun(this,
&Example::blocking_operation_finished);

        /* The dispatcher will be used when the operation has finished.
         * Here we set the function the dispatcher will call on the "main
         * thread" -- a.k.a. GTK+'s Main Loop.
         */
        dispatcher.connect(op_finished_functor);

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

        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);

        app->run(win);
    }
};

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

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

I hope you find these examples sufficiently illustrating.

On Fri, Aug 9, 2013 at 5:54 PM, L. D. James <ljames apollo3 com> wrote:
I'm trying to figure out how to get a minimum amount of lines that will
demonstrate outputting to a gui window (a textview widget) without the user
having to click a button to get started.

Kjell has taken my question serious enough to start an addition to the
examples list (multi-treaded example).  I've been studying the 400 lines and
11 widget in the example for the past 2 days spending about 6 hours a day
going over all the lines and referencing the documentation.

I'm kind of lost at present.  When I try to eliminate the unwanted widgets,
because of the many lines, my example gets broken and fail to work.

If someone understand the code well enough to present an example of the
minimum basic, it would be a good start for me to get a better understanding
of the operation.

I hope the group doesn't mind my question.  I don't doubt that I'm, not
alone in not fully comprehending all the details.  There are other novice
that would be glad to be able to use this environment with their
programming, but may be shy about asking, and not appears as smart as the
others in the group.

I don't mean to take up too much time explaining.  But I hope someone will
understand where I'm coming from and help me with this.

It might take me six months, I'd be glad, with help from others in the group
if I could get it done in 6 days.  But I'll try to get the 400 lines example
down less than 100 lines.  I'm sure it can be done with between 50 and 75
lines.

If I could see the minimum, I'm sure I'd have a grip, where everything else
in the documentation will become clearer.

Thanks for allowing me to use this maillist resource for my question.

-- L. James

--
L. D. James
ljames apollo3 com
www.apollo3.com/~ljames

_______________________________________________
gtkmm-list mailing list
gtkmm-list gnome org
https://mail.gnome.org/mailman/listinfo/gtkmm-list



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