wxWidgets中的线程

时间:2010-06-01 20:26:53

标签: c++ wxwidgets

我正在使用wxWidgets而且我调用函数需要很长时间才能继续。我想在后台做这件事。

我该怎么做?

感谢您的帮助

4 个答案:

答案 0 :(得分:7)

我使用here描述的几乎所有方式都使用了wxWidgets中的线程,我可以说使用自定义事件虽然最初有点复杂,但从长远来看可以省去一些麻烦。 (wxMessageQueue类非常好,但是当我使用它时,我发现它泄漏了;虽然我在大约一年内没有检查过它。)

一个基本的例子:

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;
}

我觉得这比wiki提供的更加清晰,简洁。显然,我遗漏了有关实际启动应用程序的代码(wx约定会使MyApp.cpp成为可能)以及任何其他与线程无关的代码。

答案 1 :(得分:2)

如果你只是需要在背景中有一些工作直到它完成 - 如果你愿意的话就开火并忘记,这样的事情:

// 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

答案 2 :(得分:2)

实施上述措施的一些提示:

  1. 使用MingW32和Codeblocks我有以下warning: EVENT redeclared without dllimport attribute: previous dllimport ignored。如果您不需要导出活动,请使用DEFINE_LOCAL_EVENT_TYPEDECLARE_LOCAL_EVENT_TYPE(而不是DEFINE_EVENT_TYPEDECLARE_EVENT_TYPE)。

  2. 如果要通过SetClientData()传递对象,请确保使用可分离线程中的new运算符创建数据。一旦复制了数据,调用应用程序就必须delete

  3. 例如:

    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);
    }
    

    并在调用应用程序中:

    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;
    }
    

答案 3 :(得分:0)

如果您的程序很简单,而且您不想乱用线程,可以考虑在长函数中定期调用 wxWindow :: Update()