0

Can someone help to clear up the confusion of how to update a gui window without user input.

In other words, I would like to be able to output text to either or both the console our the gui window.

At present I can call the gui window (Window with a label for example) and output the initial text. However, the process doesn't return to my c++ code until the window closes. I'm trying to figure out how to (or where to have my code) for updating the gui screen before the gui window exits.

This is an example:

#include <gtkmm.h>
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
    Gtk::Main kit(argc, argv);

    Gtk::Window window;
    Gtk::TextView textview;
    Gtk::Label label;

    string mylabeltext = "This is the first line of text in my gui window.\n";

    window.set_default_size(600, 360);
    window.set_title("Gtkmm Programming - C++");
    window.set_position(Gtk::WIN_POS_CENTER);

    label.show();
    window.add(label);

    label.set_text(mylabeltext);

    mylabeltext += "About to run some routines...\n";

    label.set_text(mylabeltext);

    cout << "An initial line has been set to the gui window." << endl;
    // The Gui Window is displayed
    Gtk::Main::run(window);
    // Now my main program has performed some functions and wants to update
    // the console and the gui window.
    cout << "Continuing after various functions and processing..." << endl;
    mylabeltext = "Showing the results of the functions and processing.";
    label.set_text(mylabeltext);

    return 0;
}

The last line of text is never printed to the console until the gui is exited. The last line of the mylabeltext is never printed to the label window.

What I'm trying to describe is how to keep the gtkmm window active while I run other routines in my c++ code and update the output to both the console and the gui window without closing the gui window to continue the c++ routines.

All the examples that I can find uses a button in the code. I have tested and experimented enough that I can update the gui screen after a button is pressed. However, I don't want to have to rely on the user for screen updates. I hope to be able to run disc scans and other functions and periodically update the screen so that the user can see the progress and know that the program is still working and not dead.

Some of the resources that I have studied in my attempts at understanding this include:

L. D. James
  • 1,679
  • 1
  • 22
  • 35
  • I don't understand what you mean about timer. But if I run a sleep() function after and try to append new text, no window will appear until after every sleep() function. If I add a sleep() function after the window displayed, the window will stay displayed and the sleep() function will never execute until the gui window is exited. – L. D. James Jul 30 '13 at 15:10

2 Answers2

1

Like tp1 said in their comment on your question, a timer is going to be the easiest way to do this.

To set a 1.5 second timeout that will call another function, do this (gtkmm 3):

#include <gtkmm.h>
#include <iostream>

using namespace std;

class MyApp : public Gtk::Window{
 public:
    Gtk::Label label;
    bool on_timeout(); //return true to keep the timeout and false to end it
    MyApp();
    virtual ~MyApp();
};

MyApp::MyApp(){
 string mylabeltext = "This is the first line of text in my gui window.\n";

 set_default_size(600, 360);
 set_title("Gtkmm Programming - C++");
 set_position(Gtk::WIN_POS_CENTER);

 add(label);

 label.set_text(mylabeltext);

 mylabeltext += "About to run some routines...\n";

 label.set_text(mylabeltext);

 cout << "An initial line has been set to the gui window." << endl;

 //create slot for timeout signal
 int timeout_value = 1500; //in ms (1.5 sec)
 sigc::slot<bool>my_slot = sigc::mem_fun(*this, &MyApp::on_timeout);
 //connect slot to signal
 Glib::signal_timeout().connect(my_slot, timeout_value);
 show_all_children();
}

MyApp::~MyApp(){

}

bool MyApp::on_timeout(){
 cout << "Continuing after various functions and processing..." << endl;
 string temp = label.get_text();
 temp += "Showing the results of the functions and processing.\n";
 label.set_text(temp);
 return true;
}

int main(int argc, char* argv[])
{
 Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.kaze.test");

 MyApp myapp;

 // The Gui Window is displayed
 return app->run(myapp);
}

More info here: https://developer.gnome.org/gtkmm-tutorial/3.3/sec-timeouts.html.en

Christian Smith
  • 605
  • 3
  • 11
  • Thanks, Senshikaze. This is a start. I believe there's something missing (most likely in my naive way of describing the objective). This places a an infinite loop where the "Continuing after various functions..." continute to repeat over and over. This might be because I don't understand how to use the "myapp" class. I placed it in the main ( Gtk::Main::run(myapp); ), replacing run(window) with run(myapp). It is my objective to proceed through the code to the last line, leaving the last line of output on the screen waiting for the user to exit the gui after he reads it. – L. D. James Jul 30 '13 at 18:04
  • To do specifically what you want, you would return false in the timeout function (on_timeout). The MyApp class is a class I built that inherits the Gtk::Window class. – Christian Smith Jul 30 '13 at 18:40
  • I replaced return true with return false. It appeared to work. However, (I'm sure it a matter of me understanding the code more, of which I'm studying. But I'm still kind of at the same blockage in a different point. I added 30 second sleep (to represent other activity that will generate new out put, then added the lines: temp += "Results of another function." and tried to add it to the screen with label.set_text(temp). The gui window went faded for the 30 seconds, then printed all at once. I'm trying to keep all the text on the screen with updates according to the output of each step. – L. D. James Jul 30 '13 at 19:30
0

This is crude, but this is functional for what I was trying to do:

#include <gtkmm.h>
#include <iostream>

using namespace std;

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

protected:
    Gtk::Label m_label;
    string labeltext;
    string newtext;
    void myprocess1();
};

myLabel::myLabel() :
        m_label()
{
    void myprocess1();

    set_title("Gtkmm Programming - C++");
    add(m_label);

    m_label.show();

    Glib::Thread::create(sigc::mem_fun(*this, &myLabel::myprocess1), true);
}

myLabel::~myLabel()
{
}

void myLabel::myprocess1()
{
    labeltext = "About to preform a number of processes.\n";
    labeltext += "Each process may take up to three hours.\n";
    labeltext += "Please carry your daily chores and wait.\n";
    cout << labeltext;
    cout.flush();
    m_label.set_text(labeltext);

    sleep(10); // Back from a three hour function
    newtext = "Back from a three hour function\n";
    labeltext += newtext;
    m_label.set_text(labeltext);
    cout << newtext;
    cout.flush();

    sleep(10); // Back from a three hour function
    newtext = "Back from another three hour function\n";
    labeltext += newtext;
    m_label.set_text(labeltext);
    cout << newtext;
    cout.flush();

    newtext = "Exiting in 1 minute...\n";
    labeltext += newtext;
    m_label.set_text(labeltext);
    cout << newtext;
    cout.flush();
    sleep(60);
    exit(0);
}

int main(int argc, char* argv[])
{
    if (Glib::thread_supported())
        Glib::thread_init();
    else
    {
        cerr << "Threads aren't supported!" << endl;
        exit(1);
    }

    Gtk::Main kit(argc, argv);

    myLabel mylabel;
    Gtk::Main::run(mylabel);
    return 0;
}

Hope the example can help anyone else that wants to output to the gtkmm gui with updates, similar to updating info to the console.

L. D. James
  • 1,679
  • 1
  • 22
  • 35