Been beating my head against the wall for a while now, and am almost embarrassed to ask the community since it will most likely result in me getting schooled for a pointer or scoping .
I am using ROS to manipulate a robot that has two arms; each arm has a gripper. I have an arm class and a gripper class; the gripper is a member of the arm class. Relevant code posted below.
To sum up my code: the gripper class has members such as id which need to be initialized by the callback function. If these members are accessed before the callback is called, they will get bad data. Therefore, the class has an initialized_ variable and associated initialized() function, which simply checks to see if the callback has been called yet (initialized is set to false when constructed, then set to true in the callback). The design pattern for the arm class is similar; its initialize() function checks to see if the gripper is initialized. In the main function, in my ros loop, I check to make sure the arms are both initialized; if not, ros spins (aka calls the callbacks) until the callbacks initialize the grippers, allowing the program to continue.
To sum up my problem: the gripper's callback function is definitely being called, since "gripper initialized" is being printed. However, the properties it sets are not being retained, since "success!" is not being printed. Furthermore, an id of -1 is printed, a value set by the constructor rather than by the callback (an id of -1 is impossible).
Smells like a scoping or pointer issue, but I can't seem to find the problem. Since callback functions modify the "this" object, it is modifying the gripper itself, and that modification should remain after the function exits.
If anyone can offer help, it would be very greatly appreciated.
Thanks in advance.
class Gripper
{
private:
int id;
bool initialized_;
ros::Subscriber subscriber;
void callback(const baxter_core_msgs::EndEffectorState::ConstPtr& msg);
void init();
public:
Gripper();
Gripper(ros::NodeHandle handle);
bool initialized() { return this->initialized_; }
int get_id() { return this->id; }
};
// DEFAULT CONSTRUCTOR
Gripper::Gripper()
{
this->init();
...
}
// CONSTRUCTOR
Gripper::Gripper(ros::NodeHandle handle)
{
this->init();
this->subscriber = handle.subscribe(sub_topic, 10, &Gripper::callback, this);
...
}
// CALLBACK FUNCTION
// initializes gripper fields
void Gripper::callback(const baxter_core_msgs::EndEffectorState::ConstPtr& msg)
{
this->initialized_ = true;
this->id = msg->id;
...
if (this->initialized_) ROS_INFO("gripper initialized");
}
// INIT FUNCTION
// common code in constructors
// sets all bools to false, ints to -1
void Gripper::init()
{
this->initialized_ = false;
this->id = -1;
...
}
class Arm
{
public:
Gripper gripper;
Arm();
Arm(ros::NodeHandle handle);
bool initialized()
{
if (this->gripper.initialized()) ROS_INFO("success!");
ROS_INFO("gripper id: %d");
return this->gripper.initialized();
};
};
// DEFAULT CONSTRUCTOR
Arm::Arm()
{
this->gripper = gripper();
...
}
// CONSTRUCTOR
Arm::Arm(ros::NodeHandle handle)
{
this->gripper = gripper(handle);
...
}
int main(int argc, char **argv)
{
// initialize the node and create a node handle
ros::init(argc, argv, "master_node");
ros::NodeHandle nh;
ros::Rate loop_rate(10);
// make some variables for later
Arm left_arm(nh, LEFT);
Arm right_arm(nh, RIGHT);
// main program content
while (ros::ok())
{
// if everything is initialized, start doing the stuff
if (left_arm.initialized() && right_arm.initialized())
{
...
}
// spin & sleep
ROS_INFO("spin");
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
Related
I am building a gtkmm application. The program open with a setting window asking the user to specify some information, and when sanity checks are done, this window should be closed, and the maih window of the application should open.
Right now, opening the main window, and hiding the setting window completely close the application.
From the setting windows, I am doing:
MainWindow* main_window = new MainWindow();
main_window->show();
this->hide();
How can I get the behavior described above ?
Apparently, you can add and remove windows from a Gtk::App. Would it does what I described, and does it mean I would have to pass to my window the Gtk::App pointer ? Thanks.
What seems to be the proper solution is to pass to the window the application pointer (m_app), add the new window to it, show that window and hide the current one. Removing the current one from the application will let the run() function return:
MainWindow* main_window = new MainWindow(m_app);
m_app->add_window(*main_window);
main_window->show();
this->hide();
m_app->remove_window(*this);
delete->this;
This work, but this might not be the proper way of doing things.
Although the question is quite old, I will show my approach which may help someone else to deal with this task.
I use a general application object which holds all window objects: MainApplication.cpp
MainApplication::MainApplication(int argc, char **argv)
{
// Creating the main application object as first
mainApp = Gtk::Application::create(argc, argv, APPLICATION_ID);
// Create the entry window
createEntryWindow();
}
int MainApplication::run()
{
if (!isRunning) {
// Set the current window to entry window for startup
currentWindow = entryWindow;
return mainApp->run(*entryWindow);
} else {
return -1;
}
}
void MainApplication::createEntryWindow()
{
// Load the entry_window.glade layout with the Gtk::Builder Api
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("../layout/entry_window.glade");
// Calls the constructor of my own derived widget class which details are specified inside the builder file
builder->get_widget_derived(WND_ENTRY, entryWindow);
// Set this main application object to the new window
entryWindow->setMainApplicationContext(this);
}
MainApplication.h
static const int WS_ENTRY = 100;
static const int WS_SOMETHING = 200;
class MainApplication {
public:
MainApplication(int argc, char* argv[]);
int run();
void switchCurrentWindow(int specifier);
private:
void createEntryWindow();
private:
Glib::RefPtr<Gtk::Application> mainApp;
Gtk::Window* currentWindow = nullptr;
EntryWindow* entryWindow = nullptr;
bool isRunning = false;
};
The MainApplication object will be created inside the main() and after that run() is called: main.cpp
int main(int argc, char* argv[])
{
// Create main application object
MainApplication mainApplication(argc, argv);
// Starts the event loop
// No events propagate until this has been called
return mainApplication.run();
}
The EntryWindow.cpp looks like this (just a simple example):
EntryWindow::EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade)
: Gtk::Window(object), builder(refGlade)
{
// Set widgets to builder
builder->get_widget(btnName, btn);
// Set on click methods for signal_clicked
btn->signal_clicked().connect(sigc::mem_fun(*this, &EntryWindow::onBtnClicked));
}
void EntryWindow::onBtnClicked()
{
mainApplicationContext->switchCurrentWindow(WS_SOMETHING);
}
void EntryWindow::setMainApplicationContext(MainApplication* mainApplication)
{
this->mainApplicationContext = mainApplication;
}
EntryWindow.h:
class EntryWindow : public Gtk::Window {
public:
EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade);
void setMainApplicationContext(MainApplication* mainApplication);
protected:
void onBtnClicked();
protected:
const Glib::RefPtr<Gtk::Builder> builder;
Gtk::Button* btn;
private:
MainApplication* mainApplicationContext = nullptr;
const Glib::ustring btnName = BTN_NAME;
};
So now when the button was clicked, you can switch the windows with following function inside the MainApplication class:
void MainApplication::switchCurrentWindow(int specifier)
{
// Check if the passed specifier exist
int tmpSpecifier = 0;
switch (specifier) {
case WS_ENTRY:
tmpSpecifier = WS_ENTRY;
break;
case WS_SOMETHING:
tmpSpecifier = WS_SOMETHING;
break;
default:
tmpSpecifier = 0;
}
// If the specifier exist
if (tmpSpecifier != 0) {
// Increase the use counter of the main application object
mainApp->hold();
// Hide the current window
currentWindow->hide();
// Remove the current window
mainApp->remove_window(*currentWindow);
} else {
return;
}
switch (tmpSpecifier) {
case WS_ENTRY:
currentWindow = entryWindow;
break;
case WS_SOMETHING:
currentWindow = somethingWindow;
break;
}
// Add the new current window
mainApp->add_window(*currentWindow);
// Show the new window
currentWindow->show();
// Decrease the use counter of the main application object
mainApp->release();
}
Summary: Create an Object which holds all windows. So whenever you need to have a new window, you have to create it inside this object. This main application object will be called by the main() and there it will call run() when the application is ready to start. After that you will handle which window is shown and hidden by the main application object only.
In response to your answer: delete->this is a pure syntax error, and even without ->, writing delete this is usually a code smell. Barring that, what you did seems like it will work, if perhaps not be as intuitive as it could be.
However, doing things in that sequence is not always possible. For example, you may not know what the next Window will be. Perhaps which window opens next depends on an HTTP response that may take a while to arrive.
The general solution is to call Application.hold() before removing the Window. Calling .hold() increments the use count of the GApplication, just as adding a window does. The app quits when its use count is zero. Saying its life is controlled by windows is just a quick way to approximate an explanation of that (and is obviously only relevant to GtkApplication, not the base GApplication). Removing a window decrements the use count.
So, in this case, you would now go from a use count of 2 to 1 - not 1 to 0 - so removing the 1st window would no longer make the app quit. Then, after you add the 2nd window, however much later that occurs, call .release() to remove the extra use count, so the remaining window(s) now exclusively control the application's lifetime again.
I made a little code for my EventManager, it works correctly, but the thing is, I created it with a lot of copy-paste, and I think that every time you start doing copy-paste on a few lines, your code is badly designed.
So, having done a lot of copy-paste on that EventManager, I think it's time to find out if there is another way to make it (and there probably is, and probably better).
What I achieved is that when an Event happens (window.pollEvent(event)), it calls the onEvent(sf::Event, sf::RenderWindow*) method of the EventManager class, and for every event I need to listen, I call all instances of the listener.
Here's the class :
public:
void registerKeyPressed(std::shared_ptr<KeyPressedEventListener> listener);
void registerWindowResized(std::shared_ptr<WindowResizedEventListener> listener);
void registerWindowFrameUpdate(std::shared_ptr<WindowFrameUpdateEventListener> listener);
private:
std::vector<std::shared_ptr<KeyPressedEventListener>> m_keyPressedListeners;
std::vector<std::shared_ptr<WindowResizedEventListener>> m_windowResizedListeners;
std::vector<std::shared_ptr<WindowFrameUpdateEventListener>> m_windowFrameUpdateListeners;
So, the thing is, it is a lot of code for only 3 listeners (I currently have 6, but it's not useful to show them as the code is always similar).
My problem is that I want a class to be able to listen to one, two or more events at a time, so all my listeners have a different function that's called when the event happens. For example, these three listeners have the functions onKeypressed(sf::Event);, onWindowResized(sf::Event, sf::RenderWindow* window); and onFrameUpdate(sf::RenderWindow* window);. That's the only way I found to make this code work.
It actually works, but I'd like to make something better, because it's a lot of code for every event :
void EventManager::onEvent(sf::Event event, sf::RenderWindow* window) { // The window argument is used further, but it's not useful to show it here as the code is quite the same
switch (event.type) {
case sf::Event::Resized:
for (unsigned int i = 0; i < m_windowResizedListeners.size(); i++) {
if (m_windowResizedListeners.at(i)->onWindowResized(event)) break; // The events return a bool value : True if the loop has to stop (for an error, for example), false otherwise. I always return false unless an error happen, but it's in case I need to stop it.
}
break;
}
}
void EventManager::registerWindowResized(std::shared_ptr<WindowResizedEventListener> listener) {
m_windowResizedListeners.push_back(listener);
}
And I have to duplicate this code for every event. If there's a bug, you understand it'll be a lot of work to correct it, so I hoped you could help me find a better way to achieve it.
Thank you for your help.
You could use a common class:
class EventHandler{
public:
virtual void handle(sf::RenderWindow &window) = 0;
};
class EventManager {
public:
void registerKeyPressed(std::shared_ptr<EventHandler> listener);
void registerWindowResized(std::shared_ptr<EventHandler> listener);
void registerWindowFrameUpdate(std::shared_ptr<EventHandler> listener);
private:
std::vector<std::shared_ptr<EventHandler>> m_keyPressedListeners;
std::vector<std::shared_ptr<EventHandler>> m_windowResizedListeners;
std::vector<std::shared_ptr<EventHandler>> m_windowFrameUpdateListeners;
}
You can now define a map in the class, the key is the event type and the value is his listener's vector.
std::map<int,std::vector<std::shared_ptr<EventHandler>>*> eventType;
}
//...
EventManager::EventManager(){
eventType[sf::EventType::Resized] = &m_windowResizedListeners;
eventType[sf::EventType::KeyPressed] = &m_keyPressedListeners;
//Keep going...
}
So now, the onEvent function is pretty straightforward:
void EventManager::onEvent(sf::Event event, sf::RenderWindow* window) {
std::vector<std::shared_ptr<EventHandler>>* ptr = eventType[event.type];
for (int i = 0;i < ptr->size();i++)
(*ptr)[i]->handle(window);
}
Let's put an example:
class SettingsSaver : public EventHandler{
public:
void handle(sf::RenderWindow &window) override {
std::cout << "I am saving the state in the hardrive before of exit" << std::endl;
}
}
class MoveHero : public EventHandler{
public:
void handle(sf::RenderWindow &window) override {
std::cout << "I am moving the character" << std::endl;
}
}
// Main
std::shared_ptr<EventHandler> settingsSaver(new SettingsSaver);
std::shared_ptr<EventHandler> moveHero(new MoveHero);
EventManager manager;
manager.registerWindowClosed(settingsSaver);
manager.registerKeyPressed(moveHero);
I am learning to build programs in c++ and am stuck at something basic. I use SDL2 to get inputs from and to deal with screens etc. I have defined an object "Program" and an object "EventHandler". The "EventHandler" handles all events (sends the events to lower level objects), but the "EventHandler" should also be able to create a new window, thus to access "Program".
This means I guess that "EventHandler" should be on the same level as "Program" and they should both be able to communicate with each other. Can this be done in c++ and how? Maybe there is some other more logical way in doing this.
The code below does obviously not work because of the order in which the classes are defined, and my selfmade "&this" to send the address of "program" is wrong, but it gives a nice overview of what I am trying to do.
//handles all events, is in contact with and same level as Program
class EventHandler {
private:
Program *program = NULL;
SDL_Event e;
//inputarrays
const Uint8 *currentKeyStates;
int mouseX = 0;
int mouseY = 0;
bool mousemotion = false;
int mouseButtons[4] = {0, 0, 0, 0};
public:
EventHandler(Program *p) {
program = p;
}
void handleEvents() {
while(SDL_PollEvent(&e) != 0) {
}
}
};
class Program {
private:
EventHandler *eh = NULL;
std::vector<Window> windows;
public:
bool running;
Program() {
//Here the most basic form of the program is written
//For this program we will use SDL2
//Initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
//This program uses 1 window
Window window(200, 200, 1200, 1000, "");
windows.push_back(window);
//Adds an event handler
eh = new EventHandler(&this);
//now simply run the program
run();
}
void run() {
running = true;
//while (running) {
//}
SDL_Delay(2000);
delete eh;
//Quit SDL subsystems
SDL_Quit();
}
};
int main( int argc, char* args[]) {
Program program;
return 0;
}
Yes, it's possible, and you're close!
this is already a pointer. It's [not] already "the address of the Program".
When you write &test you're obtaining a pointer to a pointer, which is not what you want.
So you'd just write:
new EventHandler(this);
Now I'm not saying that this sort of tight coupling is a good idea, but I admit I've done similar things in the past and it can work to an acceptable degree.
Your design would be clearer and cleaner if you instead took whatever resources you want to share out of Program and literally shared them between the two classes.
What you need is forward declaration of Program
class Program;
class EventHandler
{
private:
Program *program;
....
};
class Program
{
....
};
Such declaration allows you to declare pointers to Program objects before the type is fully defined.
In order to use a COM object from a thread, I inserted CoInitialize(NULL) into the thread Execute function and CoUninitialize() into the Terminate function.
Everything works fine, except if the user aborts the thread by calling the Terminate function from the calling form.
It seems that the Terminate function called by a form is considered as another thread (Error message: 'The application called an interface that was marshalled for a different thread').
On the other hand I cannot put the code into a specific function to call by using Synchronize. This way makes the program still until the COM process of called function ends.
I know that functions to readdress the COM marshaling exist. But don't know exactly what to do. I did not find examples in C++, too.
Before asking help, I tried various ways to overcome the problem. Unfortunately I am here.
Here is my code:
class TThreadCamera : public TThread
{
private:
Variant Camera;
protected:
void __fastcall Execute();
public:
void __fastcall Terminate(TObject *Sender);
public:
__fastcall TThreadCamera();
};
-
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
}
//---------------------------------------------------------------------------
void __fastcall TThreadCamera::Execute()
{
FreeOnTerminate = true;
OnTerminate = &Terminate;
CoInitialize(NULL);
Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while ((! (bool) Camera.OlePropertyGet("ImageReady")))
Sleep 100;
}
//---------------------------------------------------------------------------
void __fastcall TThreadCamera::Terminate(TObject *Sender)
{
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
CoUninitialize();
}
//---------------------------------------------------------------------------
You need to call CoInitialize and CoUninitialize on the same thread, since they act on the calling thread. The OnTerminate event is always executed on the main thread.
So, remove your OnTerminate event handler, move that code into the thread, and so call CoUninitialize from the thread:
void __fastcall TThreadCamera::Execute()
{
FreeOnTerminate = true;
CoInitialize(NULL);
Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
// code to operate on the camera goes here
CoUninitialize();
}
It would probably be prudent to protect the uninitialization inside a finally block.
In Delphi, if you need to call a thread termination code in the thread context, you should override the protected TThread.DoTerminate method instead of writing OnTerminate event handler.
The TThread.OnTerminate event is called in the context of the main UI thread. The virtual TThread.DoSynchronize() method, which the worker thread calls after Execute() exits, uses TThread.Synchronize() to call OnTerminate. DoTerminate() is always called, even if Execute() exits due to an uncaught exception, so overriding DoTerminate() is a good way to perform thread-specific cleanup.
CoInitialize() and CoUninitialize() must be called in the same thread. So, you must call CoUninitialize() inside of Execute(), or override DoTerminate(). I prefer the latter, as it reduces the need for using try/catch or try/__finally blocks in Execute() (an RAII solution, such as TInitOle in utilscls.h, is even better).
An apartment-threaded COM object can only be accessed in the context of the thread that creates it. So you must call the camera's CameraStateproperty and AbortExposure() procedure inside of Execute(), or override DoTerminate(), as well.
The TThread.Terminate() method simply sets the TThread.Terminated property to true, it does nothing else. It is the responsibility of Execute() to check the Terminated property periodically and exit as soon as possible. Your while that waits for the camera's ImageReady property to be true can, and should, check the thread's Terminated property so it can stop waiting when requested.
Try something more like this:
class TThreadCamera : public TThread
{
private:
bool init;
protected:
void __fastcall Execute();
void __fastcall DoTerminate();
public:
__fastcall TThreadCamera();
};
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
FreeOnTerminate = true;
}
void __fastcall TThreadCamera::Execute()
{
init = SUCCEEDED(CoInitialize(NULL));
if (!init) return;
Variant Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while (!Terminated)
{
if ((bool) Camera.OlePropertyGet("ImageReady"))
return;
Sleep(100);
}
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
}
void __fastcall TThreadCamera::DoTerminate()
{
if (init) CoUninitialize();
TThread::DoTerminated();
}
Or:
class TThreadCamera : public TThread
{
protected:
void __fastcall Execute();
public:
__fastcall TThreadCamera();
};
#include <utilcls.h>
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
FreeOnTerminate = true;
}
void __fastcall TThreadCamera::Execute()
{
TInitOle oleInit;
Variant Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while (!Terminated)
{
if ((bool) Camera.OlePropertyGet("ImageReady"))
return;
Sleep(100);
}
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
}
Im using wxWidgets and I call function which takes a long time to proceed. I would like to do it in background.
How can I do that?
Thanks for help
I've worked with threads in wxWidgets in pretty much all of the ways described here, and I can say that using custom events, while initially a bit more complex, saves you some headache in the long run. (The wxMessageQueue class is quite nice, but when I used it I found it to leak; I haven't checked it in about a year though.)
A basic example:
MyFrm.cpp
#include "MyThread.h"
BEGIN_EVENT_TABLE(MyFrm,wxFrame)
EVT_COMMAND(wxID_ANY, wxEVT_MYTHREAD, MyFrm::OnMyThread)
END_EVENT_TABLE()
void MyFrm::PerformCalculation(int someParameter){
//create the thread
MyThread *thread = new Mythread(this, someParameter);
thread->Create();
thread->Run();
//Don't worry about deleting the thread, there are two types of wxThreads
//and this kind deletes itself when it's finished.
}
void MyFrm::OnMyThread(wxCommandEvent& event)
{
unsigned char* temp = (unsigned char*)event.GetClientData();
//do something with temp, which holds unsigned char* data from the thread
//GetClientData() can return any kind of data you want, but you have to cast it.
delete[] temp;
}
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <wx/thread.h>
#include <wx/event.h>
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_MYTHREAD, -1)
END_DECLARE_EVENT_TYPES()
class MyThread : public wxThread
{
public:
MyThread(wxEvtHandler* pParent, int param);
private:
int m_param;
void* Entry();
protected:
wxEvtHandler* m_pParent;
};
#endif
MyThread.cpp
#include "MyThread.h"
DEFINE_EVENT_TYPE(wxEVT_MYTHREAD)
MyThread::MyThread(wxEvtHandler* pParent, int param) : wxThread(wxTHREAD_DETACHED), m_pParent(pParent)
{
//pass parameters into the thread
m_param = param;
}
void* MyThread::Entry()
{
wxCommandEvent evt(wxEVT_MYTHREAD, GetId());
//can be used to set some identifier for the data
evt.SetInt(r);
//whatever data your thread calculated, to be returned to GUI
evt.SetClientData(data);
wxPostEvent(m_pParent, evt);
return 0;
}
I feel like this is much more clear, concise example than the one the wiki offers. Obviously I left out code concerning actually launching the app (wx convention would make that MyApp.cpp) and any other non-thread-related code.
If you simply need to have something work in the background until it's finished -- fire and forget if you will, something like this:
// warning: off the top of my head ;-)
class MyThread
: public wxThread
{
public:
MyThread() : wxThread(wxTHREAD_DETACHED)
{
if(wxTHREAD_NO_ERROR == Create()) {
Run();
}
}
protected:
virtual ExitCode Entry()
{
// do something here that takes a long time
// it's a good idea to periodically check TestDestroy()
while(!TestDestroy() && MoreWorkToDo()) {
DoSaidWork();
}
return static_cast<ExitCode>(NULL);
}
};
MyThread* thd = new MyThread(); // auto runs & deletes itself when finished
A few tips from implementing the above:
Using MingW32 and Codeblocks I've had the following warning: EVENT redeclared without dllimport attribute: previous dllimport ignored. The soultion to this is that if you do not need to export your events, use DEFINE_LOCAL_EVENT_TYPE and DECLARE_LOCAL_EVENT_TYPE (instead of DEFINE_EVENT_TYPE and DECLARE_EVENT_TYPE).
If you want to pass objects via SetClientData(), make sure you create the data using the new operator in the detachable thread. The calling application will then have to delete the data once it's copied.
For example:
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_LOCAL_EVENT_TYPE(wxEVT_CALC_THREAD, -1)
END_DECLARE_EVENT_TYPES()
void* MyThread::Entry()
{
wxCommandEvent evt(wxEVT_CALC_THREAD, GetId());
// do some work
vector<map<int, int> > *vm = new vector<map<int, int> >();
// perform operations with the object vm ...
evt.SetClientData((void*)vm);
wxPostEvent(m_pParent, evt);
}
and in the calling application:
DEFINE_LOCAL_EVENT_TYPE(wxEVT_CALC_THREAD)
// change this to your event table
BEGIN_EVENT_TABLE(..., ...)
EVT_COMMAND(wxID_ANY, wxEVT_CALC_THREAD, ThreadDone)
END_EVENT_TABLE()
void ThreadDone(wxCommandEvent& event)
{
vector<map<int, int> > *temp = (vector<map<int, int> > *)event.GetClientData();
// store the data in *temp
delete temp;
}
If your program is simple and you don't want to mess around with threads, you may consider calling wxWindow::Update() periodically in your long function.