Re: How to update both the Console and the GTKMM gui window after running other functions



On Thu, Aug 1, 2013 at 7:24 AM, Jonas Platte <jonasplatte myopera com> wrote:
Am 01.08.2013 16:11, schrieb L. D. James:
// sample code begin
// -------------------------------------
String updatetext = "About to run a process that might take an hour... sit
back and wait...\n";
System.out.printl(updatetext);
textArea.append(updatetext);
int count = 0;
TimeUnit.SECONDS.sleep(3600); // Scanning all the local and network hard
drives for files larger than 1 gig
// Scanning all the local and network hard drives for files larger than 1
gig
updatetext = "The scan has completed with " << count << " files found";
System.out.println(updatetext);
textArea.append(updatetext);
// -------------------------------------
// sample code end
Your Java code appears to be broken according to standard GUI design
principals in that the GUI will not respond to events during your
blocking operation.

Here is the same broken code in C++:
#include <gtkmm.h>
#include <iostream>
#include <unistd.h>

void run_first(Gtk::Label& label) {
    label.set_text("Starting blocking operation");
    std::cout << "Starting blocking operation" << std::endl;
    sleep(5);
    label.set_text("The scan has completed");
    std::cout << "The scan has completed" << std::endl;
}

int main(int argc, char *argv[]) {
    Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create(argc, argv, "com.example");
    Gtk::Window win;
    Gtk::Label label;
    Gtk::Button btn("Start");
    Gtk::Box box(Gtk::ORIENTATION_VERTICAL);
    box.add(label);
    box.add(btn);

    btn.signal_clicked().connect(sigc::bind(sigc::ptr_fun(&run_first),
sigc::ref(label)));
    label.set_text("Program started.");
    std::cout << "Program started." << std::endl;
    win.add(box);
    win.show_all();
    app->run(win);

    return 0;
}

Notice that it will not run as expected, the "Starting blocking
operation" text is never shown in the label because control is never
passed back to the main loop so that the text may be rendered and
drawn on screen. Here is a program that allows the "Starting blocking
operation" text to actually be painted, but it still incorrectly
blocks the main loop:
void run_second(Gtk::Label& label) {
    sleep(5);
    label.set_text("The scan has completed");
    std::cout << "The scan has completed" << std::endl;
}

void run_first(Gtk::Label& label) {
    label.set_text("Starting blocking operation");
    std::cout << "Starting blocking operation" << std::endl;
    Glib::signal_timeout().connect_seconds_once(sigc::bind(sigc::ptr_fun(&run_second),
sigc::ref(label)),1);
}

This is still, however, not correct program design. Blocking
operations should not be performed in the main loop. Glib provides a
wide host of facilities for asynchronous file and network I/O. If glib
does not provide sufficient facility for you, you may use threads to
perform blocking operations. However, you must keep in mind you may
not update the GUI from a separate thread.

Here is a complete example:
#include <gtkmm.h>
#include <iostream>
#include <unistd.h>

class MyClass
{
public:
    MyClass(Gtk::Label *label, Gtk::Button *button) : m_label(label),
m_button(button), m_thread(NULL) {
        m_dispatcher.connect(sigc::mem_fun(this,
&MyClass::blocking_operation_finished));
    };

    ~MyClass() {
        if (m_thread)
            m_thread->join();
    }

    void start_operation() {
        m_button->set_sensitive(false);
        m_label->set_text("Starting blocking operation");
        std::cout << "Starting blocking operation" << std::endl;
        m_thread = Glib::Threads::Thread::create(sigc::mem_fun(this,
&MyClass::blocking_operation));
    }

private:
    void blocking_operation() {
        sleep(5);
        m_dispatcher();
    };

    void blocking_operation_finished() {
        m_thread->join();
        m_thread = NULL;
        m_button->set_sensitive(true);
        m_label->set_text("The scan has completed");
        std::cout << "The scan has completed" << std::endl;
    }

    Gtk::Label *m_label;
    Gtk::Button *m_button;
    Glib::Threads::Thread *m_thread;
    Glib::Dispatcher m_dispatcher;
};

int main(int argc, char *argv[]) {
    Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create(argc, argv, "com.example");
    Gtk::Window win;
    Gtk::Label label;
    Gtk::Button btn("Start");
    Gtk::Box box(Gtk::ORIENTATION_VERTICAL);
    MyClass myClass(&label, &btn);

    box.add(label);
    box.add(btn);
    btn.signal_clicked().connect(sigc::mem_fun(myClass,
&MyClass::start_operation));
    label.set_text("Program started.");
    std::cout << "Program started." << std::endl;
    win.add(box);
    win.show_all();
    app->run(win);

    return 0;
}

I strongly recommend you read the Gtkmm tutorial:
https://developer.gnome.org/gtkmm-tutorial/unstable/index.html


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