【问题标题】:Insert VTK into the right spot of layout将VTK插入布局的正确位置
【发布时间】:2019-12-09 10:01:32
【问题描述】:

我正在尝试将 VTK 3D 场景小部件放入 pyqtgraphics.GraphicsLayout() 的正确位置。但是,如果我没有将窗口指定为父窗口,或者如果我这样做,场景不会出现 - 场景不适应空闲区域,它只是漂浮在左上角。

我目前正在努力寻找将视图框和 vtkrenderer 放入同一窗口的解决方案。

我的一个尝试是分配 self.w(请参阅本段下方) - 这是我作为渲染器父级的主窗口,但我不知道如何告诉渲染器将自己放置在较低的窗口的右上角而不是浮动在左上角 - 这也会导致窗口中的其他元素重叠。

创建新窗口并将此窗口指定为父窗口

self.vtkWidget = QVTKRenderWindowInteractor(self.w_3d)

使用引用窗口作为父窗口 -> 导致渲染场景浮动和重叠

self.vtkWidget = QVTKRenderWindowInteractor(self.w)

import pyqtgraph as pg
import pyqtgraph.opengl as gl
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
from PyQt5 import Qt
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import vtk, sys

class GUI:
    def __init__(self):
        self.init_gui() 

    def proxyWidget(self, item, width=None, height=None):
        proxy = QtGui.QGraphicsProxyWidget()
        if(height != None):
            height = item.sizeHint().height() if height==None else height
            item.setMaximumHeight(height)
        if(width!=None):
            width = item.sizeHint().width() if width==None else width
            item.setMaximumWidth(width)
        proxy.setWidget(item)
        return proxy

    def init_gui(self, win_height=800, win_width=1800):
        #self.w = self
        #self.w.scene().sigMouseClicked.connect(self.mousePressEvent) #mouseMoveEvent
        #self.w.scene().sigMouseMoved.connect(self.mouseMoveEvent)
        pg.setConfigOptions(imageAxisOrder='row-major')
        pg.setConfigOption('background', 'w')
        pg.setConfigOption('foreground', 'k')
        self.w = pg.GraphicsWindow(size=(win_width,win_height), border=True)
        self.img = pg.ImageItem()
        self.list_imgs       = QtGui.QListWidget()
        self.btn_Del_Mark    = QtGui.QPushButton('Del Mark')
        self.btn_MarkPed     = QtGui.QPushButton('Mark ped')
        self.lbl_list1       = QtGui.QLabel("List Images")
        self.lbl_list2       = QtGui.QLabel("List Markings")
        self.list_imgs       = QtGui.QListWidget()
        self.list_marks      = QtGui.QListWidget()
        self.layout = pg.GraphicsLayout()
        self.w_3d = pg.GraphicsWindow()
        self.vb = pg.ViewBox()


        self.lbl_list1.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_list2.setAlignment(QtCore.Qt.AlignCenter)
        self.vb.setAspectLocked()
        self.vb.addItem(self.img)
        self.vb.invertY(True)
        self.vtkWidget = QVTKRenderWindowInteractor(self.w_3d)
        self.w_3d.addItem(self.proxyWidget(self.vtkWidget))

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

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

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

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

        self.ren.AddActor(actor)

        self.ren.ResetCamera()
        self.iren.Initialize()
        self.iren.Start()
        self.vtkWidget.show()

        self.layout.addItem(self.vb                             , 1,  3, 20,  20)
        self.layout.addItem(self.proxyWidget(self.lbl_list1     , width=(int(1./10.*win_width)), height=(int(0.9/20.*win_height))),  0,1,1,1)   
        self.layout.addItem(self.proxyWidget(self.lbl_list2     , width=(int(1./10.*win_width)), height=(int(0.9/20.*win_height))),  0,2,1,1)  
        self.layout.addItem(self.proxyWidget(self.list_imgs     , width=(int(1./10.*win_width))),  1,1,20,1)   
        self.layout.addItem(self.proxyWidget(self.list_marks    , width=(int(1./10.*win_width))),  1,2,20,1)   

        self.w.addItem(self.layout)

if __name__ == "__main__":
    app = QtGui.QApplication([])
    guiobj = GUI()

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

编辑:

目前我已经通过有两个窗口解决了这个问题 - 经过几天的失败尝试。但即使这样看起来也很糟糕——因为渲染的场景漂浮在窗口中,对窗口大小调整事件没有反应......

我希望将这两个窗口合二为一:

其中一个失败的尝试如下 - 但随后 pyqt 在布局中获取空间而没有在窗口中显示渲染器场景...... - 只是空白:

self.vtkWidget = QVTKRenderWindowInteractor() #No Parent
#...see rest of code in the section above with exception of the following 2 lines
self.layout.addItem(self.proxyWidget(self.vtkWidget), 10, 3, 10, 20)
self.vtkWidget.show()

【问题讨论】:

  • 好吧,也许它只是我,但看起来好像你在这里有一种循环引用——vtkWidget 依赖于 w-3d,它依赖于 layout_3d,它依赖于 vtkWidget ?这可能是为什么它不能按预期工作的问题的一部分。那么先有鸡还是先有蛋?
  • @DennisJensen 是的,但是 - 在本例中,它们是两个单独的窗口 - 但问题是 - 我不能将 layout_3d 作为父级分发 - 因为它不接受 graphicslayout 类的对象 - 所以我接受不知道如何解决这个问题...
  • @DennisJensen 我无论如何都希望在一个窗口中拥有所有小部件.. :/
  • 我确信有办法做到这一点,但我现在没有时间查看它。我认为您仍然需要改写您的问题-至少更详细地概述您的问题完全是什么-因为我认为循环引用根本无法正常工作
  • @DennisJensen 好的,我现在就做 - 因为我已经工作了好几天了 - 我仍然不知道 - 为什么不工作......如果我将小部件直接插入layout.addItem(...) 的布局并且没有绕过 vtkwidget 的父级 - 它根本不会出现在窗口中

标签: python qt pyqt vtk qt-designer


【解决方案1】:

我能够解决它 - 我已经用 QGridlayout 替换了 QGraphicsLayout 并删除了所有 proxywidget-wrappers,并且我找到了使用 plotwidget 添加视图框的解决方法。

我现在只需要移除轴 - 但这是次要的

import pyqtgraph as pg
import pyqtgraph.opengl as gl
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
from PyQt5 import Qt
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import vtk, sys
import numpy as np
from PIL import Image
class GUI:
    def __init__(self):
        self.init_gui() 

    def proxyWidget(self, item, width=None, height=None):
        proxy = QtGui.QGraphicsProxyWidget()
        if(height != None):
            height = item.sizeHint().height() if height==None else height
            item.setMaximumHeight(height)
        if(width!=None):
            width = item.sizeHint().width() if width==None else width
            item.setMaximumWidth(width)
        proxy.setWidget(item)
        return proxy

    def init_gui(self, win_height=800, win_width=1800):
        pg.setConfigOptions(imageAxisOrder='row-major')
        pg.setConfigOption('background', 'w')
        pg.setConfigOption('foreground', 'k')
        self.w = pg.GraphicsWindow(size=(win_width,win_height), border=True)
        self.img = pg.ImageItem()
        self.list_imgs       = QtGui.QListWidget()
        self.btn_Del_Mark    = QtGui.QPushButton('Del Mark')
        self.btn_MarkPed     = QtGui.QPushButton('Mark ped')
        self.lbl_list1       = QtGui.QLabel("List Images")
        self.lbl_list2       = QtGui.QLabel("List Markings")
        self.list_imgs       = QtGui.QListWidget()
        self.list_marks      = QtGui.QListWidget()
        self.layout = QtGui.QGridLayout()
        self.w.setLayout(self.layout)
        #self.w_3d = pg.GraphicsWindow()

        self.vtkWidget = QVTKRenderWindowInteractor()
        #self.w_3d.addItem(self.proxyWidget(self.vtkWidget))

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

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

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

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

        self.ren.AddActor(actor)

        self.ren.ResetCamera()
        self.iren.Initialize()
        self.iren.Start()
        path = "/home/brain/uni/frustum-pointnets/dataset/KITTI/object/testing/image_2/000000.png"
        imgdata = Image.open(path)
        self.imgArr = np.array(imgdata)
        #ToDo: undistort Image if neccessary

        self.img.setImage(self.imgArr)
        #self.vbLayout = self.w.addLayout(row=0,  col=3, rowspan=10,  colspan=20)
        imageGraph = pg.PlotWidget(name='Signalgraph')
        self.vb = imageGraph.plotItem.vb
        self.lbl_list1.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_list2.setAlignment(QtCore.Qt.AlignCenter)
        self.vb.setAspectLocked()
        self.vb.addItem(self.img)
        self.vb.invertY(True)
        self.vb.setMaximumSize(int(7/10.*win_width), int(9/20.*win_height))
        self.layout.addWidget(imageGraph,                           1 , 3, 10,  20)
        self.layout.addWidget(self.vtkWidget                      , 11, 3, 10,  20)
        self.layout.addWidget(self.lbl_list1 ,                                  0, 1, 1, 1)   
        self.layout.addWidget(self.lbl_list2 ,                                  0, 2, 1, 1)  
        self.layout.addWidget(self.list_imgs ,                                  1, 1, 20,1)   
        self.layout.addWidget(self.list_marks,                                  1, 2, 20,1)   
        sizeHint =  lambda: pg.QtCore.QSize(int(1./10.*win_width), int(0.9/20.*win_height))
        self.lbl_list1.sizeHint = lambda: pg.QtCore.QSize(int(1./10.*win_width), int(0.9/20.*win_height))
        self.lbl_list2.sizeHint = lambda: pg.QtCore.QSize(int(1./10.*win_width), int(0.9/20.*win_height))
        self.list_imgs.sizeHint  = lambda: pg.QtCore.QSize(int(1./10.*win_width), int(18/20.*win_height))
        self.list_marks.sizeHint = lambda: pg.QtCore.QSize(int(1./10.*win_width), int(18/20.*win_height))
        self.list_imgs.setMaximumWidth(int(1./10.*win_width))
        self.list_marks.setMaximumWidth(int(1./10.*win_width))

        self.vtkWidget.show()


if __name__ == "__main__":
    app = QtGui.QApplication([])
    guiobj = GUI()

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

【讨论】:

  • 请注意——您应该清理导入行,因为它们有点混乱和混乱。例如,当您在不同的命名空间下导入其中的 2 个时,您实际使用的是哪个 Qt 库
  • @DennisJensen thnx 提示 - 当我遇到某些问题时,我已经开始编写这个程序并添加和删除东西,我显然必须清理代码..
猜你喜欢
  • 2021-03-24
  • 2018-04-14
  • 2014-01-04
  • 2015-04-16
  • 2013-02-28
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 2018-04-07
相关资源
最近更新 更多