是否有可能将mayavi 3d图集成到由pyqt5制作的gui中? 在mayavi文档中,我发现了这一点: http://docs.enthought.com/mayavi/mayavi/building_applications.html,但是在运行代码时出现错误:“ RuntimeError:找不到用于工具箱qt5的traitsui.toolkits插件”。
代码如下:
# First, and before importing any Enthought packages, set the ETS_TOOLKIT
# environment variable to qt4, to tell Traits that we will use Qt.
import os
os.environ['ETS_TOOLKIT'] = 'qt4'
# By default, the PySide binding will be used. If you want the PyQt bindings
# to be used, you need to set the QT_API environment variable to 'pyqt'
#os.environ['QT_API'] = 'pyqt'
# To be able to use PySide or PyQt4 and not run in conflicts with traits,
# we need to import QtGui and QtCore from pyface.qt
from pyface.qt import QtGui, QtCore
# Alternatively, you can bypass this line, but you need to make sure that
# the following lines are executed before the import of PyQT:
# import sip
# sip.setapi('QString', 2)
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, \
SceneEditor
################################################################################
#The actual visualization
class Visualization(HasTraits):
scene = Instance(MlabSceneModel, ())
@on_trait_change('scene.activated')
def update_plot(self):
# This function is called when the view is opened. We don't
# populate the scene when the view is not yet open, as some
# VTK features require a GLContext.
# We can do normal mlab calls on the embedded scene.
self.scene.mlab.test_points3d()
# the layout of the dialog screated
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
resizable=True # We need this to resize with the parent widget
)
################################################################################
# The QWidget containing the visualization, this is pure PyQt4 code.
class MayaviQWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
layout = QtGui.QVBoxLayout(self)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.visualization = Visualization()
# If you want to debug, beware that you need to remove the Qt
# input hook.
#QtCore.pyqtRemoveInputHook()
#import pdb ; pdb.set_trace()
#QtCore.pyqtRestoreInputHook()
# The edit_traits call will generate the widget to embed.
self.ui = self.visualization.edit_traits(parent=self,
kind='subpanel').control
layout.addWidget(self.ui)
self.ui.setParent(self)
if __name__ == "__main__":
# Don't create a new QApplication, it would unhook the Events
# set by Traits on the existing QApplication. Simply use the
# '.instance()' method to retrieve the existing one.
app = QtGui.QApplication.instance()
container = QtGui.QWidget()
container.setWindowTitle("Embedding Mayavi in a PyQt4 Application")
# define a "complex" layout to test the behaviour
layout = QtGui.QGridLayout(container)
# put some stuff around mayavi
label_list = []
for i in range(3):
for j in range(3):
if (i==1) and (j==1):continue
label = QtGui.QLabel(container)
label.setText("Your QWidget at (%d, %d)" % (i,j))
label.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
layout.addWidget(label, i, j)
label_list.append(label)
mayavi_widget = MayaviQWidget(container)
layout.addWidget(mayavi_widget, 1, 1)
container.show()
window = QtGui.QMainWindow()
window.setCentralWidget(container)
window.show()
# Start the main event loop.
app.exec_()
答案 0 :(得分:0)
是的,可以将mayavi 3d图整合到由pyqt5制作的gui中。不仅情节还可以显示动画!通过在您的GUI中的任何位置嵌入mayavi场景,几乎可以在PyQt5 Gui中完成使用单独的Mayavi窗口所做的所有操作。
如果您的代码与此链接完全相同:Qt embedding example。然后尝试在单独的文件中运行此代码,它应该可以工作。如果不是,则必须正确地重新安装库。
您可以参考下面的代码(简单版本),将mayavi嵌入到GUI中:
from PyQt5 import QtWidgets
import os
import numpy as np
from numpy import cos
from mayavi.mlab import contour3d
os.environ['ETS_TOOLKIT'] = 'qt4'
from pyface.qt import QtGui, QtCore
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor
## create Mayavi Widget and show
class Visualization(HasTraits):
scene = Instance(MlabSceneModel, ())
@on_trait_change('scene.activated')
def update_plot(self):
## PLot to Show
x, y, z = np.ogrid[-3:3:60j, -3:3:60j, -3:3:60j]
t = 0
Pf = 0.45+((x*cos(t))*(x*cos(t)) + (y*cos(t))*(y*cos(t))-(z*cos(t))*(z*cos(t)))
obj = contour3d(Pf, contours=[0], transparent=False)
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
resizable=True )
class MayaviQWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
layout = QtGui.QVBoxLayout(self)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.visualization = Visualization()
self.ui = self.visualization.edit_traits(parent=self,
kind='subpanel').control
layout.addWidget(self.ui)
self.ui.setParent(self)
#### PyQt5 GUI ####
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
## MAIN WINDOW
MainWindow.setObjectName("MainWindow")
MainWindow.setGeometry(200,200,1100,700)
## CENTRAL WIDGET
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
## GRID LAYOUT
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
## BUTTONS
self.button_default = QtWidgets.QPushButton(self.centralwidget)
self.button_default.setObjectName("button_default")
self.gridLayout.addWidget(self.button_default, 0, 0, 1,1)
self.button_previous_data = QtWidgets.QPushButton(self.centralwidget)
self.button_previous_data.setObjectName("button_previous_data")
self.gridLayout.addWidget(self.button_previous_data, 1, 1, 1,1)
## Mayavi Widget 1
container = QtGui.QWidget()
mayavi_widget = MayaviQWidget(container)
self.gridLayout.addWidget(mayavi_widget, 1, 0,1,1)
## Mayavi Widget 2
container1 = QtGui.QWidget()
mayavi_widget = MayaviQWidget(container1)
self.gridLayout.addWidget(mayavi_widget, 0, 1,1,1)
## SET TEXT
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Simulator"))
self.button_default.setText(_translate("MainWindow","Default Values"))
self.button_previous_data.setText(_translate("MainWindow","Previous Values"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle('Fusion')
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
尝试在专用控制台中运行此代码。希望对您有帮助。