Pick a widget

I am struggle for a while to achieve something simple: to pick a widget (a distance widget) with mouse pointer, in order to modify it or delete it.

Here is my trial:

	vtkPropPicker* pPicker = vtkPropPicker::New();
	pPicker->Pick(nPosition[0], nPosition[1], 0, m_pRenderer);
	TRACE("Pointer: %p\n", pPicker->GetProp3D());

when I hit the 2d image, I got:

Pointer: 0000020108617B10
Pointer: 0000020108617B10

but when I hit the widget handles (see red arrow):

image

my code is not executed at all … obviously I don’t understand why … can you tell me how to solve this task ? I have worked hard for this task and I didn’t succeeded by now …

Hello, try posting more of your code. Surely there is some if() there to explain why the TRACE() macro does not work when clicking the distance widget.

Is hard to reproduce my situation in a test app, but if is need it, I would do it, because I am stuck here for days :frowning:

My pipe line looks like this: I have a vtkRenderWindowInteractor from over I setup

m_pInteractor->SetInteractorStyle(m_pInteractorStyleImage);

where m_pInteractorStyleImage is vtkInteractorStyleImageEx type.

and vtkInteractorStyleImageEx is

class vtkInteractorStyleImageEx : public vtkInteractorStyleImage

ok.

In this vtkInteractorStyleImageEx I got:

void vtkInteractorStyleImageEx::OnLeftButtonDown()
{
	int nPickPosition[2];
    this->Interactor->GetEventPosition(nPickPosition);
	vtkPropPicker* pPicker = vtkPropPicker::New();
	pPicker->Pick(nPickPosition[0], nPickPosition[1], 0, m_pView->m_pRenderer);
	TRACE("Pointer: %p\n", pPicker->GetProp3D());
	pPicker->Delete();

    vtkInteractorStyleImage::OnLeftButtonDown();
}

that is my testing code …

The point is that I got any pointer when I click on 2d image, but if I click on widget handles, the code is not executed at all.

But if you click on the widget’s handles instead on the image, that is the expected behavior, right? I fail to understand the issue.

I put a widget over my 2d image. That code, from here:

https://discourse.vtk.org/t/pick-a-widget/2573/3?u=flaviu2

is working any time when I didn’t clicked on widget handles. When I clicked on widget handles, that code (vtkInteractorStyleImageEx::OnLeftButtonDown)is not executed at all. And my task is to select that widget in order to change his color, or, to delete it.

So, the issue is: why that code is not executed at click on widget handles ?

I see…

You need to add callbacks to the widget’s interactor. Callbacks are pieces of your own code that are callable from elsewhere.

Try this:


void widgetPickObserver(vtkObject* caller, unsigned long eventId, void* clientdata, void *calldata)
{
   TRACE( "Key code is :%i\n", (static_cast<vtkRenderWindowInteractor*>(caller))->GetKeySym() );
   vtkDistanceWidget* distanceWidget = dynamic_cast<vtkDistanceWidget*>( clientdata );
   if( distanceWidget ){
        /** Good: clicked on the distance widget. */
   } else {
        /** Error: clicked something else. */
   }
}

void MyClass::createDistanceWidget()
{
  distanceWidget = vtkDistanceWidget::New();
  (...)

  vtkSmartPointer<vtkCallbackCommand> cb = vtkSmartPointer<vtkCallbackCommand>::New();
  cb->SetCallback(widgetPickObserver);
  cb->SetClientData(distanceWidget);
  distanceWidget->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, cb);

  (...)
  distanceWidget->On();
} 

Hi Paulo.

I have wrote:

void CVTKDoc::CreateDistanceWidget(CVTKView* pView)
{
	vtkDistanceWidget* pDistanceWidget = vtkDistanceWidget::New();
	pDistanceWidget->SetInteractor(pView->m_pInteractor);
	// Create the default widget representation and set the label format
	pDistanceWidget->CreateDefaultRepresentation();
	static_cast<vtkDistanceRepresentation*>(pDistanceWidget->GetRepresentation())->SetLabelFormat(_T("%-#6.3g mm"));
	// Allow the observer to access the widget
	vtkCallbackCommand* pKeypressCallback = vtkCallbackCommand::New();
	pKeypressCallback->SetCallback(&CVTKDoc::KeypressCallbackFunction);
	pKeypressCallback->SetClientData(pDistanceWidget);
	pDistanceWidget->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, pKeypressCallback);
	pDistanceWidget->On();
	// Add widget pointer to map to cleanup later
	if (NULL != pDistanceWidget)
		InsertWidgetToMap(pView, pDistanceWidget);
	pKeypressCallback->Delete();
}

and then (static method)

void CVTKDoc::KeypressCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData)
{
	CVTKDoc* pDoc = CVTKDoc::GetDoc();
	vtkRenderWindowInteractor* pInteractor = static_cast<vtkRenderWindowInteractor*>(caller);
	CString sKey = pInteractor->GetKeySym();
	TRACE(">>>%s\n", sKey);
}

and I see every keyboard key pressed. In order to select a widget (to modify it or delete it) I change the event, from vtkCommand::KeyPressEvent to vtkCommand::LeftButtonPressEvent. Every time when I press the left button, I see the TRACE, but when I press the button on the widget handle, the callback function is not executed at all, just like in the first solution :frowning:

I guess this task (to select an widget in order to modify it or to delete it) is basic functionality … am I right ?

I see, friend. But I think you’re beeing a bit over-precise on this. If I were your user, the last place I’d click on to delete the ruler widget would be its handles. I’d just click anywhere else and hit DEL. The widget handles are meant to adjust it, thus, your callback being not triggered is the expected behavior.

Good observation. Thank you. I wonder if I could know if user press on widget body and not on 2d image, because the widget is spread over this 2d image …

But you’ve just said this:

I understood this as you were able to respond to a click event on the widget. :thinking:

Yes, in did, but I have to know when user has been clicked on widget line, not anywhere on 2d image … you know what I mean ?

Later edit: vtkCommand::LeftButtonPressEvent is fired every time when I click on 2d image, not only on distance widget.

Recall this line of code:

If the callback is being triggered by a click on another object, then you should report a bug.

Thank you Paulo, I reported a bug: https://gitlab.kitware.com/vtk/vtk/issues/17784

The bug has been closed because is not a bug. It only need to catch accurate the line of the widget.

Thank you a lot Paulo !!!

P.S. Because I picked in my mouse pointer the vtkDistanceRepresentation2D object, I have to see now how can I get the vtkDistanceWidget pointer which contain this picked vtkDistanceRepresentation2D.

Well, if it is not a bug, then you have to carefully review your code as the callback is surelly being triggered by a click on the widget. I can’t see why this is wrong. Just click anywhere in the line to select it, just that. I don’t know why you insist in trying to select it by it’s tiny resizing handles located in the very ends of the widget… Like I said before: the last place I would click to select a widget would be by its resizing handles.

No no, I have picked only when I click on his line, not on his handle. Which is ok.