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 值,这也是不可接受的类型。

所以,必须做两个考虑:

  1. 继承的 class(es) 的现有属性不应该 曾经 被覆盖以用于不同于其范围的用途;由于您使用的是 QMainWindow,因此您需要确保没有覆盖 QMainWindow、QWidget 和 QObject 的任何属性或函数;我强烈建议您始终检查它们(您可以通过单击开头的 “所有成员列表,包括继承成员” link 查看完整成员列表每个 class) 的文档,但经验法则是:如果它是一个 非常通用的 属性名称(如“大小”、“宽度”、“字体”),它可能已经存在并且应该被覆盖。
  2. 如果 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()

一些注意事项:

  1. size() 一样,您还应该 而不是 覆盖其他现有属性,例如 width() or height().
  2. 几乎每个 属性 发生变化时发出的信号都会提供新值作为参数,QAbstractSlider 的 valueChanged 也是如此,因此您不需要使用 self.slider.value() inside handler() 因为该值已经是参数。
  3. 网格布局(与任何其他基于索引的对象一样)是基于 0 索引的,如果您没有向网格的第一行或第一列添加任何内容(或者您没有设置最小值 height/width 对他们来说)向第二个 row/column 添加小部件是没有用的;此外,如果添加的小部件仅使用一个“网格单元格”,则 rowSpan 和 columnSpan 参数(addWidget 中的最后一个 1, 1)是多余的,因为它们是默认值。
  4. 我不知道 handler() 中的 global 在那里做什么,因为它没有被使用,但请记住你应该 始终避免使用全局变量:一般规则是“如果你正在使用它们,你就做错了”,或者更好的是,“你不应该使用全局变量,除非你知道什么时候需要它们,并且如果你 真的知道你什么时候需要它们,你也知道你不应该使用它们。