Skip to content

RenderWindowUISingleInheritance

Repository source: RenderWindowUISingleInheritance

Description

Using a QVTKOpenGLNativeWidget with the Qt Single Inheritance model. This cleanly separates the public interface of the class from its internals.

The main widget is derived from from QMainWindow and the class Ui::RenderWindowUISingleInheritance becomes a variable in the class.

The procedure is:

  • In the header file RenderWindowUISingleInheritance.h forward declare the class Ui_RenderWindowUISingleInheritance and create a private variable in the class:
private:
  // Designer form
  Ui_RenderWindowUISingleInheritance* ui;
  • In the source file RenderWindowUISingleInheritance.cxx, assign and initialise in the constructor:
  this->ui = new Ui_RenderWindowUISingleInheritance;
  this->ui->setupUi(this);

This approach also ensures that when CMAKE_AUTOUIC is set to ON and subfolders are used we get a build with no errors.

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

RenderWindowUISingleInheritance.cxx

#include "RenderWindowUISingleInheritance.h"
#include "ui_RenderWindowUISingleInheritance.h"

#include <vtkCamera.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkLookupTable.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlatonicSolidSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkVersion.h>

#if VTK_VERSION_NUMBER >= 89000000000ULL
#define VTK890 1
#endif

namespace {
/** Get a specialised lookup table for the platonic solids.
 *
 * Since each face of a vtkPlatonicSolidSource has a different
 * cell scalar, we create a lookup table with a different colour
 * for each face.
 * The colors have been carefully chosen so that adjacent cells
 * are colored distinctly.
 *
 * @return The lookup table.
 */
vtkNew<vtkLookupTable> GetPlatonicLUT();
} // namespace

// Constructor
RenderWindowUISingleInheritance::RenderWindowUISingleInheritance(
    QWidget* parent)
  : QMainWindow(parent), ui(new Ui::RenderWindowUISingleInheritance)
{
  this->ui->setupUi(this);

  vtkNew<vtkNamedColors> colors;

  vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
#if VTK890
  this->ui->qvtkWidget->setRenderWindow(renderWindow);
#else
  this->ui->qvtkWidget->SetRenderWindow(renderWindow);
#endif

  auto lut = GetPlatonicLUT();

  vtkNew<vtkPlatonicSolidSource> source;
  source->SetSolidTypeToIcosahedron();

  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputConnection(source->GetOutputPort());
  mapper->SetLookupTable(lut);
  mapper->SetScalarRange(0, 19);

  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);

  vtkNew<vtkRenderer> renderer;
  renderer->AddActor(actor);
  renderer->GetActiveCamera()->Azimuth(180.0);
  renderer->ResetCamera();
  renderer->SetBackground(colors->GetColor3d("SteelBlue").GetData());

  // VTK/Qt wedded.
#if VTK890
  this->ui->qvtkWidget->renderWindow()->AddRenderer(renderer);
  this->ui->qvtkWidget->renderWindow()->SetWindowName(
      "RenderWindowUISingleInheritance");
#else
  this->ui->qvtkWidget->GetRenderWindow()->AddRenderer(renderer);
  this->ui->qvtkWidget->GetRenderWindow()->SetWindowName(
      "RenderWindowUISingleInheritance");
#endif
  // Set up action signals and slots.
  connect(this->ui->actionExit, SIGNAL(triggered()), this, SLOT(slotExit()));
}

RenderWindowUISingleInheritance::~RenderWindowUISingleInheritance()
{
  delete this->ui;
}

void RenderWindowUISingleInheritance::slotExit()
{
  qApp->exit();
}

namespace {

vtkNew<vtkLookupTable> GetPlatonicLUT()
{
  vtkNew<vtkLookupTable> lut;
  lut->SetNumberOfTableValues(20);
  lut->SetTableRange(0.0, 19.0);
  lut->Build();
  lut->SetTableValue(0, 0.1, 0.1, 0.1);
  lut->SetTableValue(1, 0, 0, 1);
  lut->SetTableValue(2, 0, 1, 0);
  lut->SetTableValue(3, 0, 1, 1);
  lut->SetTableValue(4, 1, 0, 0);
  lut->SetTableValue(5, 1, 0, 1);
  lut->SetTableValue(6, 1, 1, 0);
  lut->SetTableValue(7, 0.9, 0.7, 0.9);
  lut->SetTableValue(8, 0.5, 0.5, 0.5);
  lut->SetTableValue(9, 0.0, 0.0, 0.7);
  lut->SetTableValue(10, 0.5, 0.7, 0.5);
  lut->SetTableValue(11, 0, 0.7, 0.7);
  lut->SetTableValue(12, 0.7, 0, 0);
  lut->SetTableValue(13, 0.7, 0, 0.7);
  lut->SetTableValue(14, 0.7, 0.7, 0);
  lut->SetTableValue(15, 0, 0, 0.4);
  lut->SetTableValue(16, 0, 0.4, 0);
  lut->SetTableValue(17, 0, 0.4, 0.4);
  lut->SetTableValue(18, 0.4, 0, 0);
  lut->SetTableValue(19, 0.4, 0, 0.4);
  return lut;
}

} // namespace

RenderWindowUISingleInheritance.h

#ifndef RenderWindowUISingleInheritance_H
#define RenderWindowUISingleInheritance_H

#include <vtkSmartPointer.h>

#include <QMainWindow>

/*
 * See "The Single Inheritance Approach" in this link:
 * [Using a Designer UI File in Your C++
 * Application](https://doc.qt.io/qt-5/designer-using-a-ui-file.html)
 */
namespace Ui {
class RenderWindowUISingleInheritance;
}

class RenderWindowUISingleInheritance : public QMainWindow
{
  Q_OBJECT
public:
  // Constructor/Destructor
  explicit RenderWindowUISingleInheritance(QWidget* parent = nullptr);
  virtual ~RenderWindowUISingleInheritance();

private:
  // Designer form
  Ui::RenderWindowUISingleInheritance* ui;

public slots:
  void slotExit();
};

#endif

RenderWindowUISingleInheritance.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>RenderWindowUISingleInheritance</class>
 <widget class="QMainWindow" name="RenderWindowUISingleInheritance">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>541</width>
    <height>583</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>RenderWindowUISingleInheritance</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QVTKOpenGLNativeWidget" name="qvtkWidget">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>20</y>
      <width>511</width>
      <height>541</height>
     </rect>
    </property>
   </widget>
  </widget>
  <action name="actionOpenFile">
   <property name="enabled">
    <bool>true</bool>
   </property>
   <property name="text">
    <string>Open File...</string>
   </property>
  </action>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
  <action name="actionPrint">
   <property name="text">
    <string>Print</string>
   </property>
  </action>
  <action name="actionHelp">
   <property name="text">
    <string>Help</string>
   </property>
  </action>
  <action name="actionSave">
   <property name="text">
    <string>Save</string>
   </property>
  </action>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QVTKOpenGLNativeWidget</class>
   <extends>QWidget</extends>
   <header>QVTKOpenGLNativeWidget.h</header>
  </customwidget>
 </customwidgets>
 <resources>

 </resources>
 <connections/>
</ui>

RenderWindowUISingleInheritanceDriver.cxx

#include <QApplication>
#include <QSurfaceFormat>
#include <QVTKOpenGLNativeWidget.h>

#include "RenderWindowUISingleInheritance.h"

int main(int argc, char* argv[])
{
  // needed to ensure appropriate OpenGL context is created for VTK rendering.
  QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());

  // QT Stuff
  QApplication app(argc, argv);

  RenderWindowUISingleInheritance renderWindowUISingleInheritance;
  renderWindowUISingleInheritance.show();

  return app.exec();
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

if(POLICY CMP0020)
  cmake_policy(SET CMP0020 NEW)
  cmake_policy(SET CMP0071 NEW)
endif()

PROJECT(RenderWindowUISingleInheritance)

find_package(VTK COMPONENTS 
  CommonColor
  CommonCore
  FiltersSources
  InteractionStyle
  RenderingContextOpenGL2
  RenderingCore
  RenderingFreeType
  RenderingGL2PSOpenGL2
  RenderingOpenGL2
  GUISupportQt
  RenderingQt
)

if(NOT VTK_FOUND)
  message(FATAL_ERROR "RenderWindowUISingleInheritance: Unable to find the VTK build folder.")
endif()

if(NOT(TARGET VTK::GUISupportQt))
  message(FATAL_ERROR "RenderWindowUISingleInheritance: VTK not built with Qt support.")
endif()

if(NOT DEFINED VTK_QT_VERSION)
  set(VTK_QT_VERSION 5)
endif()

set(qt_components Core Gui Widgets)
if(${VTK_QT_VERSION} VERSION_GREATER_EQUAL 6)
  list(APPEND qt_components OpenGLWidgets)
endif()
list(SORT qt_components)
# We have ui files, so this will also bring in the macro:
#   qt5_wrap_ui or qt_wrap_ui from Widgets.
find_package(Qt${VTK_QT_VERSION} QUIET
  REQUIRED COMPONENTS ${qt_components}
)

foreach(_qt_comp IN LISTS qt_components)
  list(APPEND qt_modules "Qt${VTK_QT_VERSION}::${_qt_comp}")
endforeach()

message (STATUS "VTK_VERSION: ${VTK_VERSION}, Qt Version: ${Qt${VTK_QT_VERSION}Widgets_VERSION}")

# Instruct CMake to run moc and uic automatically when needed.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)

include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})

file(GLOB UI_FILES *.ui)
file(GLOB QT_WRAP *.h)
file(GLOB CXX_FILES *.cxx)

# For VTK versions greater than or equal to 8.90.0:
#  CMAKE_AUTOUIC is ON so we handle uic automatically for Qt targets.
#  CMAKE_AUTOMOC is ON so we handle moc automatically for Qt targets.

# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
# CMAKE_AUTOMOC in ON so the MOC headers will be automatically wrapped.
add_executable(RenderWindowUISingleInheritance MACOSX_BUNDLE
  ${CXX_FILES} ${UI_FILES} ${QT_WRAP}
)
if (Qt${VTK_QT_VERSION}Widgets_VERSION VERSION_LESS "5.11.0")
  qt5_use_modules(RenderWindowUISingleInheritance ${qt_components})
else()
  target_link_libraries(RenderWindowUISingleInheritance ${qt_modules})
endif()
target_link_libraries(RenderWindowUISingleInheritance ${VTK_LIBRARIES})
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS RenderWindowUISingleInheritance
  MODULES ${VTK_LIBRARIES}
)

Download and Build RenderWindowUISingleInheritance

Click here to download RenderWindowUISingleInheritance and its CMakeLists.txt file. Once the tarball RenderWindowUISingleInheritance.tar has been downloaded and extracted,

 cd RenderWindowUISingleInheritance/build

This example requires Qt and VTK.

If VTK and Qt are installed:

 cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

 cmake -DVTK_DIR=/home/me/vtk_build ..

If Qt is not found on your system, you will need to tell CMake where to find qmake:

cmake -DQT_QMAKE_EXECUTABLE:FILEPATH=/usr/something/qmake  ..

Build the project:

make

and run it:

./RenderWindowUISingleInheritance

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time. You may also need to add a Qt related path.