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



You're problem is that your "myLabel" class isn't a label but a window. You're deriving it from Gtk::Window.
Normally, you wouldn't derive your own label, I wonder what you wanted to accomplish with that...

To make clear how you would structure your code with an own Window class normally, here is a new example:


#include <gtkmm.h>

class myWindow : public Gtk::Window
{
protected:
    Gtk::Label myLabel;

public:
    myWindow();
   
    void set_main_label(Glib::ustring); // Glib::ustring is just another string class. It's used by gtkmm and is fully compatible with std::string
}

myWindow::myWindow()
// instead of set_text, you could also pass the string to be shown by the label in its constructor:
: myLabel("Hello...") // constructing myLabel with "Hello..." as argument
{
    myLabel.set_text("Hello..."); // setting myLabel's text via method
    add(myLabel); // I read you used Java somewhen, there the syntax would be "this->add(myLabel);". You just don't need the "this->" in C++
}

// you could also just make myLabel public, but I consider that bad style
void myWindow::set_main_label(Glib::ustring str)
{
    myLabel.set_text(str);
}

int main()
{
    Gtk::Main kit(argc, argv);
   
    myWindow win;

    win.set_main_label("Changed the text");   
   
    kit.run(win); // if you declare that kit thing, you should also use it instead of the static function ^^
    return 0;
}


The thing is, you have only got one thread here. And the window is when calling run, not before. This was just to make clear how to structure it. Adding a seperate thread would be much too complicated I think. You should understand how to let the program react the certain events first, I think. And for your purpose it would be enough to change the label after a certain amount of time, thus a timeout signal, right?

One last thing: When you call set_text of a Gtk::Label, and then change the string passed to set_text, that won't affect the label. You normally would just call set_text every time instead of changing some string (but you could even simply derive your own Label class to get that behaviour).


Am 01.08.2013 01:42, schrieb L. D. James:
Hi, Alan.  I'm a little embarrassed at the code I'm showing you.  I'm still stuck, but I'm sure I have the gist.  I can figure it out from here.  It's just a matter of time in looking at all the examples from the gtkmm documentation and filling in the glitches I have here.

I'm very self-taught in programming.  I started out with “C” like most people of my era, before C++ came along.  I migrated to C++, kicking and screaming, resisting change.  I'm still getting the grip on classes and class structure.

The current code doesn't compile.  It doesn't do anything much yet (except out put to the console as you suggested as a start in your previous message).

I used “label” instead of “frame”, because I'm currently more familiar with the label data structure (string).

The “*1” and the “*2” comments in the code is where I get error.  I understand this is because I haven't fully implemented the mylabel class yet.

I'll give updates as I come along... and yes, progress is a good thing.  I'm glad for the development of C++ over C.  I appreciate the value, and have been using it for a while, but still learning and getting out   of where I was stuck for a long time, using almost C exclusive in a C++ environment.

// Code (work in progress):
#include <gtkmm.h>
#include <iostream>

using namespace std;

class myLabel: public Gtk::Window
{
// blah blah blah
public:
myLabel();
};

myLabel::myLabel()
{
// myLabel.set_text("hello"); // This line gives errors (*1)
cout << "Hello..." << endl;
}

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

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


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

    // mylabel.set_text(mylabeltext); // This line gives errors (*2)

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

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

    Gtk::Main::run(mylabel);

    return 0;
}
// code end

I tried to cleanup my code before posting it.  Of course it's still sloppy.

The Window comes up, but so far, no text in it.

-- L. James

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

On Wed, 2013-07-31 at 08:13 -0700, Alan Mazer wrote:
As I understand it, you just want a window that display the progress of a computation in ASCII readable text.

Here's how I would approach it.

1. Write a program that creates a window.  This should be trivial, something you already know how to do.
2. Derive a class from your window class and use that instead, e.g.,

class myFrame: public Gtk::Window
{
blah blah blah
}

myFrame frame;
Gtk::Main::run(frame);

3. Modify the constructor for myFrame to start a thread, something like this:

Glib::Thread *m_thread = Glib::Thread::create(sigc::mem_fun(*this, &myFrame::dataThread), true);

You'll need to add "void dataThread(void)" to your class.  Just make the thread write to stdout for now.

4. Put your computation in this new thread.

5. Put a scrolling text widget in your window.  Make sure that you know how to write to it.


Now here's where it gets tricky.

You can probably write to the text widget from your thread.  Try it.  In your thread, write stuff to the text widget.

The problem is that you may have a collision between the thread and the main part of the program, e.g., you try to move the window at the same time you're updating the thread.  For that you need to set up a dispatcher.  You should be able to do something like this:

A. Add Glib::Dispatcher m_dispatcher to your class definition.
B. Add a prototype "void dispatcherWork(void);" to your class definition.

C. You're going to link the dispatcher to this routine, so that the routine (dispatcherWork) can be called in the context of the main thread, but by the secondary thread you created.

In your constructor, add m_dispatcher.connect(sigc::mem_fun(*this, &myFrame::dispatcherWork));

D. Make the code in your compute thread that writes to the text widget write to a buffer instead.

E. Create your dispatcherWork() routine.  It should read from the buffer and write to the text widget.

F. In your thread, after you write to the buffer, call the dispatcher like this: m_dispatcher();

When you call the dispatcher, the main thread will update the widget synchronously with other window activities (like moves or repaints) that may be happening.

This is just an outline, but I think this approach is much more productive than messing with signals, since this approach lets you write asynchronously to the window, which I believe is what you want.

-- Alan



_______________________________________________
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]