We can use vtkButtonWidget to create 2D buttons in the render window. The vtkWidgetRepresentation object controls the button’s position and show button pictures.
Write our class ButtonCallBack that inherits vtkCommand and use it to listen for vtkCommand::StateChangedEvent, then we can add our button click function in it. Finally, the widget seems like a fully functional button.



#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkButtonWidget.h>
#include <vtkPNGReader.h>
#include <vtkTexturedButtonRepresentation2D.h>
#include <vtkCoordinate.h>
#include <QString>

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

using namespace std;

enum ButtonType{ E_Button0, E_Button1, E_ButtonCount };

vtkSPtr<vtkButtonWidget> m_Button[E_ButtonCount];
vtkSPtr<vtkRenderWindowInteractor> m_RenderWindowInteractor;
vtkSPtr<vtkRenderer> m_Renderer;

ButtonType GetButtonType( const vtkButtonWidget *const buttonWidget )
{
    ButtonType result = E_ButtonCount;
    for( int i = 0; i < E_ButtonCount; ++i )
    {
        if( buttonWidget == m_Button[i] )
        {
            result = (ButtonType)i;
            break;
        }
    }
    return result;
}

class ButtonCallBack: public vtkCommand
{
public:
    static ButtonCallBack *New(){ return new ButtonCallBack(); }
    virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
    {
        vtkButtonWidget* buttonWidget = reinterpret_cast<vtkButtonWidget*>(caller);
        vtkTexturedButtonRepresentation2D* rep = reinterpret_cast<vtkTexturedButtonRepresentation2D*>(buttonWidget->GetRepresentation());
        int state = rep->GetState();
        ButtonType buttonT = GetButtonType( buttonWidget );
        cout << "state: " << state << ", buttonT: " << buttonT << endl;
        // add your costum click function for different button.
    }
};

void InitButton(const ButtonType buttonType, const QString& beforeImagePath, const QString& afterImagePath)
{
    vtkSPtrNew(pngReader, vtkPNGReader);
    pngReader->SetFileName( beforeImagePath.toLocal8Bit().data() );
    pngReader->Update();

    vtkSPtrNew(pngReader1, vtkPNGReader);
    pngReader1->SetFileName( afterImagePath.toLocal8Bit().data() );
    pngReader1->Update();

    vtkSPtrNew( buttonRep, vtkTexturedButtonRepresentation2D );
    if( beforeImagePath != afterImagePath )
    {
        buttonRep->SetNumberOfStates( 2 );
        buttonRep->SetButtonTexture( 0, pngReader->GetOutput() );
        buttonRep->SetButtonTexture( 1, pngReader1->GetOutput() );
    }
    else
    {
        buttonRep->SetNumberOfStates( 1 );
        buttonRep->SetButtonTexture( 0, pngReader->GetOutput() );
    }

    m_Button[buttonType]->SetInteractor( m_RenderWindowInteractor );
    m_Button[buttonType]->SetRepresentation( buttonRep );

    buttonRep->SetPlaceFactor( 1 );
    m_Button[buttonType]->On();

    vtkSPtrNew(buttonCB, ButtonCallBack);
    m_Button[buttonType]->AddObserver( vtkCommand::StateChangedEvent, buttonCB );
}

void UpdateButtonsPosition()
{
    vtkWidgetRepresentation* buttonRep = m_Button[E_Button0]->GetRepresentation();

    vtkSPtrNew(coordinate, vtkCoordinate);
    coordinate->SetCoordinateSystemToNormalizedDisplay();
    coordinate->SetValue(1.0, 0.8);
    double bds[6];
    double sz = 50;
    bds[0] = coordinate->GetComputedDisplayValue(m_Renderer)[0] - sz;
    bds[1] = bds[0] + sz;
    bds[2] = coordinate->GetComputedDisplayValue(m_Renderer)[1] - sz;
    bds[3] = bds[2] + sz;
    bds[4] = bds[5] = 0;
    buttonRep->PlaceWidget(bds);

    // ================== Put the second button ==================
    double tmpBds[6] = { bds[0], bds[1], bds[2], bds[3], bds[4], bds[5] };
    buttonRep = m_Button[E_Button1]->GetRepresentation();
    bds[0] = tmpBds[0];
    bds[1] = bds[0] + sz;
    bds[2] = tmpBds[2] - sz - 5;
    bds[3] = bds[2] + sz;
    bds[4] = bds[5] = 0;
    buttonRep->PlaceWidget( bds );
}

int main()
{
    vtkSPtrNew( cone, vtkConeSource );
    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputConnection( cone->GetOutputPort() );

    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );

    m_Renderer = vtkSPtr<vtkRenderer>::New();
    m_Renderer->AddActor(actor);
    m_Renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( m_Renderer );

    m_RenderWindowInteractor = vtkSPtr<vtkRenderWindowInteractor>::New();
    m_RenderWindowInteractor->SetRenderWindow( renderWindow );

    for( int i = 0; i < 2; ++i )
    {
        m_Button[i] = vtkSmartPointer<vtkButtonWidget>::New();
    }
    QString path0 = "/Users/weiyang/Desktop/1.png";
    QString path1 = "/Users/weiyang/Desktop/2.png";
    InitButton( E_Button0, path0, path1 );
    InitButton( E_Button1, path1, path0 );

    m_Renderer->ResetCamera();
    renderWindow->Render();

    UpdateButtonsPosition();

    m_RenderWindowInteractor->Start();
    return 0;
}

We can use the original size of image when put it at a reasonable position in the above program.

    vtkWidgetRepresentation *buttonRep = m_Button[E_Button0]->GetRepresentation();
    vtkImageData *imageData = dynamic_cast<vtkTexturedButtonRepresentation2D *>(buttonRep)->GetButtonTexture( 0 );
    int *extent = imageData->GetExtent();
    double size[2] = { extent[1] - extent[0], extent[3] - extent[2] };
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
trackback

[…] Here is an example using vtkButtonWidget, Use vtkButtonWidget To Create 2D Button. […]

Content Summary
: Input your strings, the tool can get a brief summary of the content for you.

X
1
0
Would love your thoughts, please comment.x
()
x