[vtkusers] Nonblocking vtkRenderWindowInteractor

Budd Hirons bhiron at lsuhsc.edu
Tue Jun 14 15:20:22 EDT 2005


I like it, I have one question : when you close one of the rendering 
windows the interactor does a PostQuitMessage under win32 (and I guess 
it must do a similar thing under the other platforms you support) and 
kills the whole program, how do you stop this in a cross platform way 
without overriding or modifying all the interactor classes?

Budd.

Clinton Stimpson wrote:
> 
> Ok, I've attached some code that shows some things you can do by having 
> your own event loop.
> This example includes console input and two windows in one event loop.
> Commented out is some example code for timers.
> It shows a few different things which I've seen other vtk users in the 
> past try to use multithreading to solve.  I'm not saying this is better 
> than threading for what you need to do, I'm just giving this as an 
> example as another way to do these kinds of things.  And this time, I'm 
> posting the code so it gets archived.
> 
> The object connected to the event loop is on unix, a pipe (int), on 
> Windows a HANDLE, and on Mac a CFRunLoopSource (which is made from a 
> CFSocketRef of the stdin).
> So you have flexibility in what you can connect to the event loop in 
> this sample app.
> 
> Hmm.. I wonder if it would be nice to put this kind of stuff into 
> vtkRenderWindowInteractor.
> 
> Clint
> 
> 
> Kim Chuan Lim wrote:
> 
>> Hi Clinton,
>>
>> Can i have your example (Event loops, timer, etc) please. Thanks in 
>> advance.
>>
>> Best Regards,
>> Kim Chuan.
>>
>>  
>>
> 
> 
> ------------------------------------------------------------------------
> 
> 
> 
> #include "vtkRenderWindowInteractor.h"
> #include "vtkInteractorStyle.h"
> #include "vtkInteractorStyleTrackballCamera.h"
> #include "vtkCamera.h"
> #include "vtkRenderWindow.h"
> #include "vtkRenderer.h"
> #include "vtkCallbackCommand.h"
> 
> #include "vtkActor.h"
> #include "vtkPolyDataMapper.h"
> #include "vtkCylinderSource.h"
> #include "vtkToolkits.h"
> 
> #if defined(VTK_USE_X)
> #  include <stdio.h>
> #  include <unistd.h>
> #  include <X11/Intrinsic.h>
> #  include "vtkXRenderWindowInteractor.h"
>    typedef int PipeHandle;
>    XtAppContext app_context;  // global app context
> #elif defined(VTK_USE_CARBON)
> #  include <Carbon/Carbon.h>
>    typedef CFSocketRef PipeHandle;
> #else
> #  include <windows.h>
>    typedef HANDLE PipeHandle;
> #endif
> 
> 
> void handle_timer(vtkObject* caller, unsigned long, void* clientdata, void*)
> {
>   vtkRenderWindowInteractor* iren = static_cast<vtkInteractorStyle*>(caller)->GetInteractor();
>   vtkCamera* cam = reinterpret_cast<vtkCamera*>(clientdata);
>   // keep the timer going
>   iren->CreateTimer(VTKI_TIMER_UPDATE);
>   cam->Azimuth(1);
>   iren->Render();
> }
> 
> 
> // function to handle console input -- called by our event loop
> // this same technique can be used for any pipe (e.g. network socket)
> // note: By default, this gets called when a '\n' is encountered.
> //       Use setvbuf() or whatever to control that behavior.
> void handle_console_event(PipeHandle handle)
> {
>   static char buf[1024];
>   int num_read=0;
> 
> #if defined(VTK_USE_X)
> 
>   num_read = read(handle, buf, 1024);
> 
> #elif defined(VTK_USE_CARBON)
> 
>   num_read = read(CFSocketGetNative(handle), buf, 1024);
> 
> #else
> 
> 
>   INPUT_RECORD console_input;
>   DWORD num_console_read;
>   if(!ReadConsoleInput(handle, &console_input, 1, &num_console_read) || num_console_read != 1)
>     return;
> 
>   static char* pbuf=buf;
>   if(pbuf == buf)
>     *pbuf = '\0';
> 
>   // only deal with key down event
>   if(console_input.EventType == KEY_EVENT && console_input.Event.KeyEvent.bKeyDown)
>   {
>     char key = console_input.Event.KeyEvent.uChar.AsciiChar;
>     if(key)
>     {
>       if(key == '\r')  // change line feeds to carriage returns
>         key = '\n';
>       printf("%c", key);  // gotta echo it back to the console
>       *pbuf++ = key;
>     }
>   }
> 
>   // if there is no newline, return and wait for more input
>   if( *(pbuf-1) != '\n')
>     return;
> 
>   *pbuf = '\0';
>   num_read = pbuf - buf;
>   pbuf = buf;
> 
> #endif
>   
>   // see if we should exit
>   // compare string without the '\n' at the end
>   if(num_read == 5 && (strncmp("exit", buf, 4) == 0 || strncmp("quit", buf, 4) == 0))
>   {
> #if defined(VTK_USE_X)
>     XtAppSetExitFlag(app_context);
> #elif defined(VTK_USE_CARBON)
>     QuitApplicationEventLoop();
> #else
>     PostQuitMessage(0);
> #endif
>   }
> }
> 
> #if defined(VTK_USE_X)
> // callback to insert into the X11 event loop
> static void x11_handle_console_event(XtPointer, int* pipe, XtInputId*)
> {
>   handle_console_event(*pipe);
> }
> #elif defined(VTK_USE_CARBON)
> // callback to insert into the Mac event loop
> static void cf_handle_console_event(CFSocketRef s, CFSocketCallBackType,
>                                     CFDataRef, const void*, void*)
> {
>   handle_console_event(s);
> }
> #endif
> 
> 
> 
> int main(int, char**)
> {
> 
>   // first initialize event loop stuff for X11 and Mac
> #if defined(VTK_USE_X)
>   XtToolkitInitialize();
>   // create X11 application context
>   app_context = XtCreateApplicationContext();
>   
>   // add processing of stdin to the event loop
>   XtAppAddInput(app_context, fileno(stdin), (XtPointer)XtInputReadMask,
>                 x11_handle_console_event, NULL);
> 
> #elif defined(VTK_USE_CARBON)
> 
>   // add processing of stdin to the event loop
>   CFSocketRef socket_ref = CFSocketCreateWithNative(NULL, STDIN_FILENO, kCFSocketReadCallBack,
>                                                     cf_handle_console_event, NULL);
>   CFRunLoopSourceRef rlsr = CFSocketCreateRunLoopSource(NULL, socket_ref, 0);
>   CFRunLoopAddSource(CFRunLoopGetCurrent(), rlsr, kCFRunLoopDefaultMode);
> 
> #endif
>   
>   // create two renderers
>   vtkRenderer* ren1 = vtkRenderer::New();
>   vtkRenderer* ren2 = vtkRenderer::New();
> 
>   // create 2 windows and hook the renderers up to them
>   vtkRenderWindow* win1 = vtkRenderWindow::New();
>   win1->AddRenderer(ren1);
>   vtkRenderWindow* win2 = vtkRenderWindow::New();
>   win2->AddRenderer(ren2);
> 
> #ifdef VTK_USE_X
>   // create the X11 interactors and give them the application context
>   vtkXRenderWindowInteractor* iren1 = vtkXRenderWindowInteractor::New();
>   iren1->SetRenderWindow(win1);
>   iren1->Initialize(app_context);
>   vtkXRenderWindowInteractor* iren2 = vtkXRenderWindowInteractor::New();
>   iren2->SetRenderWindow(win2);
>   iren2->Initialize(app_context);
> #else
>   // create two interactors
>   vtkRenderWindowInteractor* iren1 = vtkRenderWindowInteractor::New();
>   iren1->SetRenderWindow(win1);
>   iren1->Initialize();
>   vtkRenderWindowInteractor* iren2 = vtkRenderWindowInteractor::New();
>   iren2->SetRenderWindow(win2);
>   iren2->Initialize();
> #endif
> 
> 
>   // use trackball camera style
>   vtkInteractorStyle* style1 = vtkInteractorStyleTrackballCamera::New();
>   iren1->SetInteractorStyle(style1);
> 
>   vtkInteractorStyle* style2 = vtkInteractorStyleTrackballCamera::New();
>   iren2->SetInteractorStyle(style2);
> 
> 
>   // put something in the windows so we know we can interact with it
>   vtkActor* actor1 = vtkActor::New();
>   vtkPolyDataMapper* mapper1 = vtkPolyDataMapper::New();
>   actor1->SetMapper(mapper1);
>   vtkCylinderSource* cyl1 = vtkCylinderSource::New();
>   mapper1->SetInput(cyl1->GetOutput());
>   ren1->AddProp(actor1);
>   
>   vtkActor* actor2 = vtkActor::New();
>   vtkPolyDataMapper* mapper2 = vtkPolyDataMapper::New();
>   actor2->SetMapper(mapper2);
>   vtkCylinderSource* cyl2 = vtkCylinderSource::New();
>   mapper2->SetInput(cyl2->GetOutput());
>   ren2->AddProp(actor2);
> 
>   // reset the view
>   ren1->ResetCamera();
>   ren2->ResetCamera();
> 
> #if 0
>   
>   // put our timer handler on the first window
>   vtkCallbackCommand* callback = vtkCallbackCommand::New();
>   callback->SetClientData(ren1->GetActiveCamera());
>   callback->SetCallback(handle_timer);
>   style1->AddObserver(vtkCommand::TimerEvent, callback);
> 
>   // kickstart the timer
>   iren1->CreateTimer(VTKI_TIMER_FIRST);
> 
> #endif
> 
>   printf("type 'exit' to quit\n");
>   
>   // now run the event loop
> 
> #if defined(VTK_USE_X)
>   
>   while(!XtAppGetExitFlag(app_context))
>     XtAppProcessEvent(app_context, XtIMAll);
> 
> #elif defined(VTK_USE_CARBON)
>   
>   RunApplicationEventLoop();
> 
> #else
> 
>   MSG  msg;
>   int running = 1;
>   HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
> 
>   while(running)
>   {
>     // just sit around and wait forever until we get a window event or a console event ...
>     DWORD wait_object = MsgWaitForMultipleObjects(1, &stdin_handle,
>                                                   FALSE, INFINITE, QS_ALLINPUT);
>     // see if we got a console event
>     if(wait_object == WAIT_OBJECT_0)
>     {
>       // handle the console event
>       handle_console_event(stdin_handle);
>     }
> 
>     // process queued window events without blocking, if there are any
>     while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
>     {
>       ::TranslateMessage (&msg);
>       ::DispatchMessage (&msg);
>       if(msg.message == WM_QUIT)
>         running = 0;
>     }
> 
>   }
> 
> #endif
> 
>   return 0;
> 
> }
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> This is the private VTK discussion list. 
> Please keep messages on-topic. Check the FAQ at: http://www.vtk.org/Wiki/VTK_FAQ
> Follow this link to subscribe/unsubscribe:
> http://www.vtk.org/mailman/listinfo/vtkusers



More information about the vtkusers mailing list