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 <lja...@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
> lja...@apollo3.com
> www.apollo3.com/~ljames
>
> _______________________________________________
> gtkmm-list mailing list
> gtkmm-list@gnome.org
> https://mail.gnome.org/mailman/listinfo/gtkmm-list
>
_______________________________________________
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list

Reply via email to