[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