why vtkCommand::TimerEvent not work?

#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
//定义一个类,该类将是一个定时器回调函数
class vtkTimerCallback : public vtkCommand
{
public:
    static vtkTimerCallback* New()
    {
        vtkTimerCallback* cb = new vtkTimerCallback;
        cb->TimerCount = 0;
        return cb;
    }
    //定义定时器回调函数
    virtual void Execute(vtkObject* vtkNotUsed(caller), unsigned long eventId,
        void* vtkNotUsed(callData))
    {
        if (vtkCommand::TimerEvent == eventId)
        {
            std::cout << "Timer count: " << this->TimerCount << std::endl;
            ++this->TimerCount;
        }
    }
private:
    int TimerCount;
};

int main(int, char* [])
{
    //创建一个球源,用来显示
    vtkSmartPointer<vtkSphereSource> sphereSource =
        vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetCenter(0.0, 0.0, 0.0);
    sphereSource->SetRadius(5.0);
    sphereSource->Update();

    //将该球源放入一个Mapper
    vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(sphereSource->GetOutputPort());

    //将Mapper放入一个Actor
    vtkSmartPointer<vtkActor> actor =
        vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    //创建一个渲染窗口,并将Actor放入该窗口
    vtkSmartPointer<vtkRenderer> renderer =
        vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    renderer->AddActor(actor);

    //创建一个Interactor,并将渲染窗口放入该Interactor
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow(renderWindow);

    //创建一个定时器回调函数
    vtkSmartPointer<vtkTimerCallback> timerCallback =
        vtkSmartPointer<vtkTimerCallback>::New();

    //添加一个定时器事件
    renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, timerCallback);
    int timerId = renderWindowInteractor->CreateRepeatingTimer(1000); //1秒钟
    renderWindow->Render();
    //开始渲染
    renderWindowInteractor->Start();

    //删除定时器
    renderWindowInteractor->DestroyTimer(timerId);

    return EXIT_SUCCESS;
}

I use Linux, and TimerEvent works well. I see it counting:

Timer count: 0
Timer count: 1
Timer count: 2
Timer count: 3

But right now I tried on Windows. And it doesn’t work. So maybe the timers in vtkWin32RenderWindowInteractor are broken. That is bad, hopefully it will be fixed. One work-around is to use Qt, which has very good timers, but that increases the complexity of your application even more.


I will make a suggestion about callbacks in VTK: it is not necessary to derive your callback class from vtkCommand. The methods of any class can be used with AddObserver(). For example:

class MyClass
{
public:
    // a simple callback method
    void OnTimer() {
        std::cout << "Timer count: " << this->TimerCount << std::endl;
        ++this->TimerCount;
    }
/* // a callback method with arguments
    void OnTimerWithArgs(vtkObject* caller, unsigned long event, void*) {
        std::cout << caller->GetClassName() << " ";
        std::cout << vtkCommand::GetStringFromEventId(event) << " ";
        std::cout << this->TimerCount << std::endl;
        ++this->TimerCount;
    }
*/
private:
    int TimerCount = 0;
};

Using AddObserver with these callback methods:

    MyClass o;

    // simple callback
    renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, &o, &MyClass::OnTimer);
/*  // callback with arguments
    renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, &o, &MyClass::OnTimerWithArgs);
*/

Later, I solved the problem. The key is to initialize the interactor in advance. The timer will work only if the interactor is initialized early enough. I think it should be fixed. This is a bad way to use it.