pyqt and VTK : problem to connect slider to vtk ob

2019-06-11 00:09发布

问题:

This question already has an answer here:

  • Why is PyQt connect() syntax so verbose? 3 answers

I'm dealing with some issues, using vtk in PyQt5. The problem is that I have a vtk sphere with an initial radius value and some sliders to connect to the sphere dans QLCD Numbers. Indeed, what I want is to have one of the sliders set at 128 at first dans when the user slide to change the value, this value will be displayed in the QLCDNumber and the current value of the slider will be taken to change the Radius of the VTK Sphere.

Here's my code :

    import sys
from PyQt5.QtWidgets import QApplication, QWidget, QSlider, QLCDNumber
from PyQt5.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox,
                             QMenu, QPushButton, QRadioButton, QVBoxLayout, QWidget, QSlider,QLineEdit,QLabel)
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import *
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from PyQt5 import Qt

def window():

   source = vtk.vtkSphereSource()
   source.SetCenter(0, 0, 0)
   source.SetRadius(5.0)

   app = QApplication(sys.argv)
   win = QWidget()

   Display_1 = QLCDNumber(3)
   Display_2 = QLCDNumber(3)
   Display_3 = QLCDNumber(3)

   Display_1.setSegmentStyle(QLCDNumber.Flat)
   Display_2.setSegmentStyle(QLCDNumber.Flat)
   Display_3.setSegmentStyle(QLCDNumber.Flat)

   Display_1.display(128)
   Display_2.display(128)
   Display_3.display(128)

   Slider_1 = QSlider(QtCore.Qt.Horizontal)
   Slider_1.setMinimum(0)
   Slider_1.setMaximum(255)
   Slider_1.setValue(128)
   Slider_1.valueChanged.connect(Display_1.display)
   Slider_1.valueChanged.connect(changevalue(Slider_1,source))

   Slider_2 = QSlider(QtCore.Qt.Horizontal)
   Slider_2.setMinimum(0)
   Slider_2.setMaximum(255)
   Slider_2.setValue(128)
   Slider_2.valueChanged.connect(Display_2.display)


   Slider_3 = QSlider(QtCore.Qt.Horizontal)
   Slider_3.setMinimum(0)
   Slider_3.setMaximum(255)
   Slider_3.setValue(128)
   Slider_3.valueChanged.connect(Display_3.display)

   label_1 = QLabel("Label_1")
   label_1.setAlignment(QtCore.Qt.AlignCenter)

   label_2 = QLabel("Label_2")
   label_2.setAlignment(QtCore.Qt.AlignCenter)

   label_3 = QLabel("Label_3")
   label_3.setAlignment(QtCore.Qt.AlignCenter)  

   vbox = QtWidgets.QVBoxLayout()


   vbox.addWidget(label_1)
   vbox.addWidget(Display_1)
   vbox.addWidget(Slider_1)

   vbox.addWidget(label_2)
   vbox.addWidget(Display_2)
   vbox.addWidget(Slider_2)

   vbox.addWidget(label_3)
   vbox.addWidget(Display_3)
   vbox.addWidget(Slider_3)

   vbox.addStretch()






   hbox = QtWidgets.QHBoxLayout()

   frame = QtWidgets.QFrame()
   frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
   frame.setFrameShape(QtWidgets.QFrame.StyledPanel) # Application de la forme
   frame.setFrameShadow(QtWidgets.QFrame.Raised) # application d'une ombre
   frame.setObjectName("frame") # Appellation du cadre

   #b3 = QtWidgets.QPushButton("Button3")
   #b4 = QtWidgets.QPushButton("Button4")
   hbox.addWidget(frame)
   hbox.addStretch()
   #hbox.addWidget(b4)

   vbox.addStretch()
   hbox.addLayout(vbox)
   win.setLayout(hbox)



   vtkWidget = QVTKRenderWindowInteractor(frame)
   vl = Qt.QVBoxLayout()
   vl.addWidget(vtkWidget)

   ren = vtk.vtkRenderer()
   vtkWidget.GetRenderWindow().AddRenderer(ren)
   iren = vtkWidget.GetRenderWindow().GetInteractor()



  # Create a mapper
   mapper = vtk.vtkPolyDataMapper()
   mapper.SetInputConnection(source.GetOutputPort())

  # Create an actor
   actor = vtk.vtkActor()
   actor.SetMapper(mapper)

   ren.AddActor(actor)
   ren.ResetCamera()
   frame.setLayout(vl)
   #setCentralWidget(self.frame)
   #show()
   iren.Initialize()
   iren.Start()

   win.setWindowTitle("PyQt")
   win.resize(743, 430)
   win.show()
   sys.exit(app.exec_())

def changevalue(slider,source):
   value  = slider.value()
   source.SetRadius(int(value))


if __name__ == '__main__':
   window()

When I try to use the code the python returns me the following error : "File "window.py", line 38, in window Slider_1.valueChanged.connect(changevalue(Slider_1,source)) TypeError: argument 1 has unexpected type 'NoneType'"

Any idea ?

Thanks in advance

回答1:

The connect method in PyQt is expecting a function object. Instead, you are calling a function:

changevalue(Slider_1,source)

The function changevalue doesn't return anything. In other words, it returns None.

So, when you call the line:

Slider_1.valueChanged.connect(changevalue(Slider_1,source))

what you are really doing is calling connect with None as the argument becuase this is what your function call to changevalue is returning. Instead, you need to pass it the function changevalue, but since you need to call that function with arguments, you'll need to do something like this:

...
Slider_1 = QSlider(QtCore.Qt.Horizontal)
   Slider_1.setMinimum(0)
   Slider_1.setMaximum(255)
   Slider_1.setValue(128)
   def handler():
       changevalue(Slider_1, source)
   Slider_1.valueChanged.connect(Display_1.display)
   Slider_1.valueChanged.connect(handler)
...

I ran your code with this modification and the sphere displays. However, there is one other issue and that is that when you move the sliders, your sphere doesn't update. In order to get the VTK renderer to update, you'll need to figure out how to call iren.reinitialize() in your changevalue handler, or something to this effect. The reinitialize call will cause the render window to update in response to the slider movement.



标签: python pyqt vtk