GTKmm with Threads and Timeouts for control the refresh of a Window
In last days I ask for help in a problem that I had. I have resolved and I present here the solution because I consider that don't exist much information about that.
Problem:
The problem was that when I wanted to run the window with Gtk::Main::run(window) , my principal code was stopping until I was closing the window. Then the principal code was not executing and my window was not presenting any result.
When I resolved that problem I had another problem. My window refresh only when I click in it.
I solved my problems with POSIX Threads to avoid that my main code was stopped and I use signals to avoid the problem of which my window was not refresh.
Then the code is the next:
In main.cpp
#include <pthread.h>
#include <gtkmm/main.h>
.
.
.
#include "debugger.h"
.
.
.
//Next code is for Window Creation
//****************************************
Debugger *windowDebugger; //My Object Window. I utilize this variable in all my code. Without *
//the code present problems because of absence of Gtk::Main kit before
struct str_Window //I utilize this for start the pthread
{
int i;
char **c;
};
struct str_Window strW;
//*****************************************
//Window Creation from a thread
void *openWindow(void *strW)
{
struct str_Window *my_data;
my_data = (struct str_Window *) strW;
Gtk::Main kit(my_data->i, my_data->c);
Debugger window; //After Gtk::Main kit(my_data->i, my_data->c) one can star a object
//window
windowDebugger = &window; //I have to make this for can utilize the object in all my code.
Gtk::Main::run(window);
pthread_exit((void *) 0);
}
.
.
.
.
.
.
int main(int argc, char *argv[])
{
//****************WINDOW CREATION****************************************
strW.i = argc;
strW.c = argv;
pthread_setconcurrency(100);
pthread_attr_t attr;
int rc, t, status;
// Initialize and set thread detached attribute
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_t threadWindow; // declare threads
pthread_create(&threadWindow,&attr,openWindow,(void *) &strW); // create threads
sleep(1); //I have to sleep my principal code only for start the window.
windowDebugger->controlUpdate(); //I utilize this for control the refresh.
.
.
.
.My code
.
.
.
.
pthread_join(threadWindow, (void **)&status);
return 0;
}
Then in all my code I utilize windowDebugger->UpdateWorldModel for change the results in the window.
I present here the code of my object. controlRefresh, refreshWindow and updateWorldModel are the important.
DEBUGGER.cpp
#include "debugger.h"
#include "worldmodel.h" //part of my code
#include <iostream>
#include <stdio.h>
extern WorldModel wm;
using namespace salt;
//using namespace Geometry;
Debugger::Debugger()
:
m_Frame_WorldModel("World Model"),
m_Frame_Command("Give me a Command"),
m_Frame_Pos("Calculated Position"),
m_Frame_MyPos("Real Position"),
m_Frame_Times("Times"),
m_HBox_Main(false, 10),
m_Label_PosX("X"), m_Label_PosY("Y"), m_Label_PosZ("Y"),
m_Label_MyPosX("X"), m_Label_MyPosY("Y"), m_Label_MyPosZ("Y"),
m_Label_Time("T"), m_Label_Cycle("C"),
m_adjustment_day(1.0, 1.0, 31.0, 1.0, 5.0, 0.0),
m_adjustment_month(1.0, 1.0, 12.0, 1.0, 5.0, 0.0),
m_adjustment_year(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0),
m_adjustment_value(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0),
m_adjustment_digits(2.0, 1.0, 5.0, 1.0, 1.0, 0.0),
m_Button_Close("Close")
{
set_title("Borregos3D Debugger Ver 0.1");
m_HBox_Main.set_border_width(10);
add(m_HBox_Main);
m_HBox_Main.pack_start(m_Frame_WorldModel);
m_VBox_WorldModel.set_border_width(5);
m_Frame_WorldModel.add(m_VBox_WorldModel);
//m_VBox.set_border_width(5);
m_VBox_WorldModel.pack_start(m_Frame_Pos);
m_HBox_Pos.set_border_width(5);
m_Frame_Pos.add(m_HBox_Pos);
m_Label_PosX.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_Pos.pack_start(m_Label_PosX, Gtk::PACK_EXPAND_WIDGET, 30);
m_Label_PosY.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_Pos.pack_start(m_Label_PosY, Gtk::PACK_EXPAND_WIDGET, 30);
m_Label_PosZ.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_Pos.pack_start(m_Label_PosZ, Gtk::PACK_EXPAND_WIDGET, 30);
m_VBox_WorldModel.pack_start(m_Frame_MyPos);
m_HBox_MyPos.set_border_width(5);
m_Frame_MyPos.add(m_HBox_MyPos);
m_Label_MyPosX.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_MyPos.pack_start(m_Label_MyPosX, Gtk::PACK_EXPAND_WIDGET, 30);
m_Label_MyPosY.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_MyPos.pack_start(m_Label_MyPosY, Gtk::PACK_EXPAND_WIDGET, 30);
m_Label_MyPosZ.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_MyPos.pack_start(m_Label_MyPosZ, Gtk::PACK_EXPAND_WIDGET, 30);
m_VBox_WorldModel.pack_start(m_Frame_Times);
m_HBox_Times.set_border_width(5);
m_Frame_Times.add(m_HBox_Times);
m_Label_Time.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_Times.pack_start(m_Label_Time, Gtk::PACK_EXPAND_WIDGET, 30);
m_Label_Cycle.set_alignment(Gtk::ALIGN_CENTER);
m_HBox_Times.pack_start(m_Label_Cycle, Gtk::PACK_EXPAND_WIDGET, 30);
//Close button:
m_HBox_Main.pack_start(m_Frame_Command);
m_VBox_Command.set_border_width(1);
m_Frame_Command.add(m_VBox_Command);
m_Button_Close.signal_clicked().connect( sigc::mem_fun(*this, &Debugger::on_button_close) );
m_VBox_Command.pack_start(m_Button_Close, Gtk::PACK_SHRINK);
show_all_children();
}
Debugger::~Debugger()
{
}
//This function control the refresh, it refresh every 250 milliseconds.
void Debugger::controlUpdate()
{
sigc::slot<bool> my_slot = sigc::bind(sigc::mem_fun(*this, &Debugger::refreshWindow),4);
// I don't know but I have to give some variable, in this ocassion 4 to the function that will execute
//repeatably
sigc::connection conn = Glib::signal_timeout().connect(my_slot, 250);
}
void Debugger::on_button_close()
{
hide();
}
//update
void Debugger::Update_WorldModel()
{ Vector3f RealPos = wm.GetMyPosition();
Vector3f DebugPosition = wm.GetMyDebugPosition();
char PosX[10];
char PosY[10];
char PosZ[10];
char MyPosX[10];
char MyPosY[10];
char MyPosZ[10];
char time[10];
char cycleTime[10];
sprintf(PosX, "%.3f", RealPos[0]);
sprintf(PosY, "%.3f", RealPos[1]);
sprintf(PosZ, "%.3f", RealPos[2]);
sprintf(MyPosX, "%.3f", DebugPosition[0]);
sprintf(MyPosY, "%.3f", DebugPosition[1]);
sprintf(MyPosZ, "%.3f", DebugPosition[2]);
sprintf(time, "%.3f", wm.GetTime());
sprintf(cycleTime, "%d", wm.GetSimTime());
m_Label_PosX.set_text(PosX);
m_Label_PosY.set_text(PosY);
m_Label_PosZ.set_text(PosZ);
m_Label_MyPosX.set_text(MyPosX);
m_Label_MyPosY.set_text(MyPosY);
m_Label_MyPosZ.set_text(MyPosZ);
m_Label_Time.set_text(time);
m_Label_Cycle.set_text(cycleTime);
// show_all_children();
// draw(0);
// if(Gtk::Main::instance()->events_pending()){
// Gtk::Main::instance()->iteration();
// }
// return true;
}
bool Debugger::refreshWindow(int n){
queue_draw(); //refresh the window
return true; //without this the signal will died
}
Finally I have to say that I utilized gtkmm2.4, if one want utilize gtkmm2.0 one must redefine the function Debugger::controlUpdate() because the the sigc is different.
I think that is all, I hope that this can help somebody. I consider that If were exist more documentation this will more simple. I last 3 weeks because of that......
César Omar Flores García