VTK+PyQt5:将滑块值连接到翻译变量
VTK+PyQt5: Connecting slider values to translation variables
我使用下面的代码并尝试使用 transform.trasnlate(x,y,z)
的第一个变量更改滑块值
但我遇到了以下错误:
TypeError:翻译参数 %Id:%V
详细信息:我想在滑块上下移动时更改 STL 文件的位置。
我认为我的问题是我使用的是方法而不是整数,但我不知道如何解决。它
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.widget = QtWidgets.QWidget()
self.gridLayout = QtWidgets.QGridLayout()
#First STL file
reader = vtk.vtkSTLReader()
reader.SetFileName(filename)
transform = vtk.vtkTransform()
transform.Translate(self.size, 0, 0)
transformFilter = vtk.vtkTransformPolyDataFilter()
transformFilter.SetTransform(transform)
transformFilter.SetInputConnection(reader.GetOutputPort())
transformFilter.Update()
mapper = vtk.vtkPolyDataMapper()
if vtk.VTK_MAJOR_VERSION <= 5:
mapper.SetInput(transformFilter.GetOutput())
else:
mapper.SetInputConnection(transformFilter.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
self.vtkwidget = QVTKRenderWindowInteractor(self.widget)
self.gridLayout.addWidget(self.vtkwidget, 1, 0, 1, 1)
#Slider
self.title = "Rotaion"
self.top = 200
self.left = 500
self.width = 400
self.height = 300
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.slider = QSlider()
self.slider.setOrientation(Qt.Vertical)
self.slider.setTickPosition(QSlider.TicksBelow)
self.slider.setTickInterval(10)
self.slider.setMinimum(-100)
self.slider.setMaximum(100)
self.slider.valueChanged.connect(self.handler)
self.gridLayout.addWidget(self.slider, 1, 1, 1, 1)
# Create a rendering window and renderer
self.ren = vtk.vtkRenderer()
self.vtkwidget.GetRenderWindow().AddRenderer(self.ren)
self.iren = self.vtkwidget.GetRenderWindow().GetInteractor()
self.ren.AddActor(actor)
self.iren.Initialize()
# Enable user interface interactor
self.widget.setLayout(self.gridLayout)
self.setCentralWidget(self.widget)
self.ren.ResetCamera()
def handler(self):
global size
self.size = self.slider.value()
print(self.size)
#self.label.setText(str(self.size))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
size()
is one of the basic default properties of all QWidget classes, and since all Qt properties are accessible as callables what you're getting with self.size
(without parentheses) is a reference to a method, and that's clearly not an acceptable type for the transform. In any case, the self.size()
will return a QSize 值,这也是不可接受的类型。
所以,必须做两个考虑:
- 继承的 class(es) 的现有属性不应该 曾经 被覆盖以用于不同于其范围的用途;由于您使用的是 QMainWindow,因此您需要确保没有覆盖 QMainWindow、QWidget 和 QObject 的任何属性或函数;我强烈建议您始终检查它们(您可以通过单击开头的 “所有成员列表,包括继承成员” link 查看完整成员列表每个 class) 的文档,但经验法则是:如果它是一个 非常通用的 属性名称(如“大小”、“宽度”、“字体”),它可能已经存在并且应该不被覆盖。
- 如果
size
不是一个已经存在的属性,您将面临 AttributeError
,因为您在此之前从未声明过它。
最后,如果你想改变转换,你当然不能通过覆盖 self.size
值来实现; Python 不是这样工作的,至少对于简单的实例属性而言:您只会更改 self.size
的值,但转换对象可以知道任何相关信息。
您需要将 valueChanged
信号连接到更改变换(或设置新变换)的插槽。我没有使用Vtk,所以下面只是一些伪代码:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# ...
<b>self.transformSize = 0</b>
<b>self.</b>transform = vtk.vtkTransform()
self.transform.Translate(<b>self.transformSize</b>, 0, 0)
<b>self.</b>transformFilter = vtk.vtkTransformPolyDataFilter()
# ...
def handler(self, <b>value</b>):
self.transformSize = value
self.transform.Translate(<b>value</b>, 0, 0)
self.transformFilter.Update()
一些注意事项:
- 与
size()
一样,您还应该 而不是 覆盖其他现有属性,例如 width()
or height()
.
- 几乎每个 属性 发生变化时发出的信号都会提供新值作为参数,QAbstractSlider 的
valueChanged
也是如此,因此您不需要使用 self.slider.value()
inside handler()
因为该值已经是参数。
- 网格布局(与任何其他基于索引的对象一样)是基于 0 索引的,如果您没有向网格的第一行或第一列添加任何内容(或者您没有设置最小值 height/width 对他们来说)向第二个 row/column 添加小部件是没有用的;此外,如果添加的小部件仅使用一个“网格单元格”,则 rowSpan 和 columnSpan 参数(
addWidget
中的最后一个 1, 1
)是多余的,因为它们是默认值。
- 我不知道
handler()
中的 global
在那里做什么,因为它没有被使用,但请记住你应该 始终避免使用全局变量:一般规则是“如果你正在使用它们,你就做错了”,或者更好的是,“你不应该使用全局变量,除非你知道什么时候需要它们,并且如果你 真的知道你什么时候需要它们,你也知道你不应该使用它们。
我使用下面的代码并尝试使用 transform.trasnlate(x,y,z)
的第一个变量更改滑块值
但我遇到了以下错误:
TypeError:翻译参数 %Id:%V
详细信息:我想在滑块上下移动时更改 STL 文件的位置。
我认为我的问题是我使用的是方法而不是整数,但我不知道如何解决。它
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.widget = QtWidgets.QWidget()
self.gridLayout = QtWidgets.QGridLayout()
#First STL file
reader = vtk.vtkSTLReader()
reader.SetFileName(filename)
transform = vtk.vtkTransform()
transform.Translate(self.size, 0, 0)
transformFilter = vtk.vtkTransformPolyDataFilter()
transformFilter.SetTransform(transform)
transformFilter.SetInputConnection(reader.GetOutputPort())
transformFilter.Update()
mapper = vtk.vtkPolyDataMapper()
if vtk.VTK_MAJOR_VERSION <= 5:
mapper.SetInput(transformFilter.GetOutput())
else:
mapper.SetInputConnection(transformFilter.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
self.vtkwidget = QVTKRenderWindowInteractor(self.widget)
self.gridLayout.addWidget(self.vtkwidget, 1, 0, 1, 1)
#Slider
self.title = "Rotaion"
self.top = 200
self.left = 500
self.width = 400
self.height = 300
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.slider = QSlider()
self.slider.setOrientation(Qt.Vertical)
self.slider.setTickPosition(QSlider.TicksBelow)
self.slider.setTickInterval(10)
self.slider.setMinimum(-100)
self.slider.setMaximum(100)
self.slider.valueChanged.connect(self.handler)
self.gridLayout.addWidget(self.slider, 1, 1, 1, 1)
# Create a rendering window and renderer
self.ren = vtk.vtkRenderer()
self.vtkwidget.GetRenderWindow().AddRenderer(self.ren)
self.iren = self.vtkwidget.GetRenderWindow().GetInteractor()
self.ren.AddActor(actor)
self.iren.Initialize()
# Enable user interface interactor
self.widget.setLayout(self.gridLayout)
self.setCentralWidget(self.widget)
self.ren.ResetCamera()
def handler(self):
global size
self.size = self.slider.value()
print(self.size)
#self.label.setText(str(self.size))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
size()
is one of the basic default properties of all QWidget classes, and since all Qt properties are accessible as callables what you're getting with self.size
(without parentheses) is a reference to a method, and that's clearly not an acceptable type for the transform. In any case, the self.size()
will return a QSize 值,这也是不可接受的类型。
所以,必须做两个考虑:
- 继承的 class(es) 的现有属性不应该 曾经 被覆盖以用于不同于其范围的用途;由于您使用的是 QMainWindow,因此您需要确保没有覆盖 QMainWindow、QWidget 和 QObject 的任何属性或函数;我强烈建议您始终检查它们(您可以通过单击开头的 “所有成员列表,包括继承成员” link 查看完整成员列表每个 class) 的文档,但经验法则是:如果它是一个 非常通用的 属性名称(如“大小”、“宽度”、“字体”),它可能已经存在并且应该不被覆盖。
- 如果
size
不是一个已经存在的属性,您将面临AttributeError
,因为您在此之前从未声明过它。
最后,如果你想改变转换,你当然不能通过覆盖 self.size
值来实现; Python 不是这样工作的,至少对于简单的实例属性而言:您只会更改 self.size
的值,但转换对象可以知道任何相关信息。
您需要将 valueChanged
信号连接到更改变换(或设置新变换)的插槽。我没有使用Vtk,所以下面只是一些伪代码:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# ...
<b>self.transformSize = 0</b>
<b>self.</b>transform = vtk.vtkTransform()
self.transform.Translate(<b>self.transformSize</b>, 0, 0)
<b>self.</b>transformFilter = vtk.vtkTransformPolyDataFilter()
# ...
def handler(self, <b>value</b>):
self.transformSize = value
self.transform.Translate(<b>value</b>, 0, 0)
self.transformFilter.Update()
一些注意事项:
- 与
size()
一样,您还应该 而不是 覆盖其他现有属性,例如width()
orheight()
. - 几乎每个 属性 发生变化时发出的信号都会提供新值作为参数,QAbstractSlider 的
valueChanged
也是如此,因此您不需要使用self.slider.value()
insidehandler()
因为该值已经是参数。 - 网格布局(与任何其他基于索引的对象一样)是基于 0 索引的,如果您没有向网格的第一行或第一列添加任何内容(或者您没有设置最小值 height/width 对他们来说)向第二个 row/column 添加小部件是没有用的;此外,如果添加的小部件仅使用一个“网格单元格”,则 rowSpan 和 columnSpan 参数(
addWidget
中的最后一个1, 1
)是多余的,因为它们是默认值。 - 我不知道
handler()
中的global
在那里做什么,因为它没有被使用,但请记住你应该 始终避免使用全局变量:一般规则是“如果你正在使用它们,你就做错了”,或者更好的是,“你不应该使用全局变量,除非你知道什么时候需要它们,并且如果你 真的知道你什么时候需要它们,你也知道你不应该使用它们。