2016-06-28 60 views
0

我需要得到一个vtkChartParallelCoordinates和其他使用与PyQt应用程序并行运行的vtkContextView的图。问题在于它们都使用用户鼠标交互的无限循环,并且我一次只能运行其中的一个。当我通过view.GetInteractor()启动vtk交互器时,Start()在关闭vtk窗口之前不会显示PyQt应用程序。 我想,我对如何做两种选择:VTK交互器和PyQt并行运行

  1. 照顾VTK对象的用户交互的PyQt的的循环手动
  2. 渲染PyQt的应用
内vtk的图

关于第二个选项:我不能使用QVTKRenderWindowInteractor,它似乎不能使用vtkContextView图形。我发现Kitware的一个文档: http://www.na-mic.org/Wiki/images/1/18/NA-MIC-VTK-Charts-2011.pdf 在第22页他们使用QVTKWidget但我的编译vtk没有它。

我试图做一些关于选项1没有成功,没有相关的例子可用。

在我的代码下面,当我注释掉“view.GetInteractor().Start()”时,PyQt窗口显示并且是交互式的。

我在linux上使用Python 2.7.11版本,vtk版本7.0.0。

我会感谢任何帮助!

from PyQt4 import QtCore, QtGui 
import vtk 
import math 




class Ui_widgetParallel(object): 
    def setupUi(self, widgetParallel): 
     widgetParallel.setObjectName("widgetParallel") 
     widgetParallel.resize(802, 651) 
     #button 
     self.button = QtGui.QPushButton(widgetParallel) 
     self.button.setGeometry(QtCore.QRect(180, 100, 75, 23)) 
     self.button.setText("Click on me") 

     QtCore.QMetaObject.connectSlotsByName(widgetParallel) 
     self.button.clicked.connect(self.testClick) 

    def testClick(self): 
     print('I was clicked on') 




def selectionCallback(caller, event): 
    #executes when new data is selected by the user 
    #prints row numbers of all selected data rows 
     annSel = annotationLink.GetCurrentSelection() 
     if annSel.GetNumberOfNodes() > 0: 
      idxArr = annSel.GetNode(0).GetSelectionList() 
      if idxArr.GetNumberOfTuples() > 0: 
       for ii in range(idxArr.GetNumberOfTuples()): 
        print(idxArr.GetValue(ii)) 




if __name__ == "__main__": 
    import sys 


    ############################ 
    # CREATE A DATA TABLE 
    ############################ 

    arrX = vtk.vtkFloatArray() 
    arrX.SetName("XAxis") 

    arrC = vtk.vtkFloatArray() 
    arrC.SetName("Cosine") 

    arrS = vtk.vtkFloatArray() 
    arrS.SetName("Sine") 

    arrS2 = vtk.vtkFloatArray() 
    arrS2.SetName("Tan") 

    numPoints = 20 
    inc = 0.2/(numPoints-1) 

    for i in range(numPoints): 
     arrX.InsertNextValue(i * inc) 
     arrC.InsertNextValue(math.cos(i * inc) + 0.0) 
     arrS.InsertNextValue(math.sin(i * inc) + 0.0) 
     arrS2.InsertNextValue(math.tan(i * inc) + 0.5) 

    table = vtk.vtkTable() 
    table.AddColumn(arrX) 
    table.AddColumn(arrC) 
    table.AddColumn(arrS) 
    table.AddColumn(arrS2) 


    ############################ 
    # STARTS THE QtGui application 
    ############################ 
    app = QtGui.QApplication(sys.argv) 
    widgetParallel = QtGui.QWidget() 
    ui = Ui_widgetParallel() 
    ui.setupUi(widgetParallel) 
    widgetParallel.show() 


    ############################ 
    # PARALLEL COORDINATES VIEW AND ANNOTATION 
    ############################ 
    #render contextView and parallel coordinates view 
    view = vtk.vtkContextView() 
    view.GetRenderer().SetBackground(1.0, 1.0, 1.0) 
    view.GetRenderWindow().SetSize(600,300) 
    chart = vtk.vtkChartParallelCoordinates() 
    view.GetScene().AddItem(chart) 
    # Create a annotation link to access selection in parallel coordinates view 
    annotationLink = vtk.vtkAnnotationLink() 
    annotationLink.GetCurrentSelection().GetNode(0).SetFieldType(1)  # Point 
    annotationLink.GetCurrentSelection().GetNode(0).SetContentType(4) # 1 = GlobalIds, 2 = PedigreeIds, 4 = Indices 
    chart.SetAnnotationLink(annotationLink) 
    annotationLink.AddObserver("AnnotationChangedEvent", selectionCallback) 

    #link input data and refresh attributes view 
    chart.GetPlot(0).SetInputData(table) 
    chart.GetPlot(0).SetScalarVisibility(1) 
    chart.GetPlot(0).SetScalarVisibility(1) 
    chart.GetPlot(0).SetWidth(5) 
    chart.GetPlot(0).SetOpacity(0) 
    #render view 
    view.ResetCamera() 
    view.GetRenderWindow().SetMultiSamples(0) 
    view.Render() 
    view.GetInteractor().Start() 

    ############################ 
    # EXITS THE APPLICATION WHEN GUI LOOP IS CLOSED 
    ############################ 
    sys.exit(app.exec_()) 

回答

0

我不知道我是否完全理解了你的第一个问题。不过,我附上了一个Python原型,用QVTKRenderWindowInteractor类在Qt主窗口中显示您的vtk图。至于第一个问题,我认为通过附加的方法,您可以轻松地将pyQt事件与vtk事件连接起来。

from PyQt4 import QtCore, QtGui 
from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor 
import vtk 
import math 
import sys 


class test(QtGui.QMainWindow): 

    def __init__(self, parent=None): 
     QtGui.QMainWindow.__init__(self, parent) 
     self._initUI() 

    def _initUI(self): 
     self.setWindowTitle(self.tr("PyQt4 widgetParallel")) 
     self.workspace = QtGui.QWorkspace() 
     self.setCentralWidget(self.workspace) 
     self.frame1 = QtGui.QFrame(self.workspace) 
     self.hbox1 = QtGui.QHBoxLayout() 
     self.frame2 = QtGui.QFrame(self.workspace) 

     self.frame1.resize(600, 600) 
     self.frame2.resize(600, 600) 
     self.frame2.move(QtCore.QPoint(600, 0)) 

     self.hbox2 = QtGui.QHBoxLayout() 

     self.widgetParallel = Ui_widgetParallel(self.frame2) 

     self.widget = QVTKRenderWindowInteractor(self.frame1) 
     self.iren = self.widget.GetRenderWindow().GetInteractor() 

     self.arrX = vtk.vtkFloatArray() 
     self.arrX.SetName("XAxis") 

     self.arrC = vtk.vtkFloatArray() 
     self.arrC.SetName("Cosine") 

     self.arrS = vtk.vtkFloatArray() 
     self.arrS.SetName("Sine") 

     self.arrS2 = vtk.vtkFloatArray() 
     self.arrS2.SetName("Tan") 

     numPoints = 20 
     inc = 0.2/(numPoints-1) 

     for i in range(numPoints): 
      self.arrX.InsertNextValue(i * inc) 
      self.arrC.InsertNextValue(math.cos(i * inc) + 0.0) 
      self.arrS.InsertNextValue(math.sin(i * inc) + 0.0) 
      self.arrS2.InsertNextValue(math.tan(i * inc) + 0.5) 

     self.table = vtk.vtkTable() 
     self.table.AddColumn(self.arrX) 
     self.table.AddColumn(self.arrC) 
     self.table.AddColumn(self.arrS) 
     self.table.AddColumn(self.arrS2) 

     self.view = vtk.vtkContextView() 
     self.view.SetInteractor(self.iren) 
     self.widget.SetRenderWindow(self.view.GetRenderWindow()) 

     self.ren = self.view.GetRenderer() 
     self.ren.SetBackground(1.0, 1.0, 1.0) 
     self.renWin = self.widget.GetRenderWindow() 

     self.iren.SetRenderWindow(self.widget.GetRenderWindow()) 

     self.chart = vtk.vtkChartParallelCoordinates() 
     self.view.GetScene().AddItem(self.chart) 
     # Create a annotation link to access selection in parallel coordinates 
     # view 
     self.annotationLink = vtk.vtkAnnotationLink() 
     # Point 
     self.annotationLink.GetCurrentSelection().GetNode(0).SetFieldType(1) 
     # 1 = GlobalIds, 2 = PedigreeIds, 4 = Indices 
     self.annotationLink.GetCurrentSelection().GetNode(0).SetContentType(4) 
     self.chart.SetAnnotationLink(self.annotationLink) 
     self.annotationLink.RemoveObservers("AnnotationChangedEvent") 
     self.annotationLink.AddObserver("AnnotationChangedEvent", 
             self.selectionCallback) 

     # link input data and refresh attributes view 
     self.chart.GetPlot(0).SetInputData(self.table) 
     self.chart.GetPlot(0).SetScalarVisibility(1) 
     self.chart.GetPlot(0).SetScalarVisibility(1) 
     self.chart.GetPlot(0).SetWidth(5) 
     self.chart.GetPlot(0).SetOpacity(0) 

     self.renWin.AddRenderer(self.ren) 
     self.renWin.SetMultiSamples(0) 

     self.hbox1.addWidget(self.widget) 
     self.hbox2.addWidget(self.widgetParallel) 

     self.frame1.setLayout(self.hbox1) 
     self.frame2.setLayout(self.hbox2) 

     self.workspace.addWindow(self.frame1) 
     self.workspace.addWindow(self.frame2) 

     self.widget.show() 
#  self.widgetParallel.show() 
     self.iren.Initialize() 

    def selectionCallback(self, caller, event): 
     # executes when new data is selected by the user 
     # prints row numbers of all selected data rows 
     annSel = self.annotationLink.GetCurrentSelection() 
     if annSel.GetNumberOfNodes() > 0: 
      idxArr = annSel.GetNode(0).GetSelectionList() 
      if idxArr.GetNumberOfTuples() > 0: 
       for ii in range(idxArr.GetNumberOfTuples()): 
        print(idxArr.GetValue(ii)) 


class Ui_widgetParallel(QtGui.QWidget): 

    def __init__(self, parent): 
     super(Ui_widgetParallel, self).__init__(parent) 
     self._setupUi() 

    def _setupUi(self): 
     self.setObjectName("widgetParallel") 
     self.resize(802, 651) 
     # button 
     self.button = QtGui.QPushButton(self) 
     self.button.setGeometry(QtCore.QRect(180, 100, 75, 23)) 
     self.button.setText("Click on me") 

     layout = QtGui.QHBoxLayout() 
     layout.addWidget(self.button) 

     self.setLayout(layout) 

#  QtCore.QMetaObject.connectSlotsByName(self) 
     self.button.clicked.connect(self.testClick) 

     self.show() 

    def testClick(self): 
     print('I was clicked on') 


if __name__ == "__main__": 
    app = QtGui.QApplication(sys.argv) 
    mainwindow = test() 
    mainwindow.show() 
    sys.exit(app.exec_()) 

p.s.而不是QWidgets,你也可以使用QDockWidgets。

+0

这正是我所期待的,非常感谢! – Kubik