Embedding FreeCADGui

From FreeCAD Documentation
Revision as of 14:03, 27 December 2009 by Yorik (talk | contribs) (Created page with 'You already know that you can import the FreeCAD module into a python application, and use all its tools from the host application. But the FreeCAD User Int…')
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

You already know that you can import the FreeCAD module into a python application, and use all its tools from the host application. But the FreeCAD User Interface (GUI) can also be imported as a python module. Normally you can only import the complete interface as a whole, not pieces of it. That is because the FreeCAD interface system is not only made of independent widgets and toolbars, but is a complex construction where several invisible components (such as the selection system, etc) are needed for the main 3D view to be able to function.

But, with a bit of hacking, it is possible to import the whole FreeCAD interface, then move the 3D view from it to your own Qt application.

But be aware that there are still a lot of problems with this approach. The Qt event handling doesn't seem to work (no idea why) and if you use the 3d view's context-menu the application crashes. A better way could be to create your own 3d view SoQtExaminerViewer or SoQtViewer and "push" the content of FreeCAD's 3d view to your view, as shown below.

First, get the main window via PyQt:

   from PyQt4 import QtGui
   from PyQt4 import QtCore
      
   def getMainWindow():
      toplevel = QtGui.qApp.topLevelWidgets()
      for i in toplevel:
         if i.metaObject().className() == "Gui::MainWindow":
            return i
      raise Exception("No main window found")

   mw=getMainWindow()

Then get the View3DInventor view the same way:

   def get3dview(mw):
         childs=mw.findChildren(QtGui.QMainWindow)
         for i in childs:
            if i.metaObject().className()=="Gui::View3DInventor":
               return i
         return None

   v=get3dview(mw)

The following code is generated automatically, by creating a Ui-file with QtDesigner, and converting it to python code with the pyuic tool:

   # -*- coding: utf-8 -*-

   # Form implementation generated from reading ui file 'mainwindow.ui'
   #
   # Created: Sun Dec 27 11:18:56 2009
   #      by: PyQt4 UI code generator 4.6
   #
   # WARNING! All changes made in this file will be lost!

   from PyQt4 import QtCore, QtGui

   class Ui_MainWindow(object):
       def setupUi(self, MainWindow):
           MainWindow.setObjectName("MainWindow")
           MainWindow.resize(508, 436)
           self.centralwidget = QtGui.QWidget(MainWindow)
           self.centralwidget.setObjectName("centralwidget")
           self.gridLayout = QtGui.QGridLayout(self.centralwidget)
           self.gridLayout.setObjectName("gridLayout")
           self.mdiArea = QtGui.QMdiArea(self.centralwidget)
           self.mdiArea.setViewMode(QtGui.QMdiArea.TabbedView)
           self.mdiArea.setTabPosition(QtGui.QTabWidget.South)
           self.mdiArea.setObjectName("mdiArea")
           self.gridLayout.addWidget(self.mdiArea, 0, 0, 1, 1)
           MainWindow.setCentralWidget(self.centralwidget)
           self.menubar = QtGui.QMenuBar(MainWindow)
           self.menubar.setGeometry(QtCore.QRect(0, 0, 508, 27))
           self.menubar.setObjectName("menubar")
           MainWindow.setMenuBar(self.menubar)
           self.statusbar = QtGui.QStatusBar(MainWindow)
           self.statusbar.setObjectName("statusbar")
           MainWindow.setStatusBar(self.statusbar)

           self.retranslateUi(MainWindow)
           QtCore.QMetaObject.connectSlotsByName(MainWindow)

       def retranslateUi(self, MainWindow):
           MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))

Then, create a main window that should be your application's main window, apply the UI setup above to it in order to add an MDI area and "move" our 3d view to it

   ui=Ui_MainWindow()
   my_mw=QtGui.QMainWindow()
   ui.setupUi(my_mw)
   ui.mdiArea.addSubWindow(v)
   my_mw.show()

Alternatively, you can also use the FreeCADGui module to extract a coin/openInventor representation of the objects of your scene, then use that coin data in an external viewer (your application). Here is an easy way to get the 3d representation of an object:

   FreeCAD.activeDocument().addObject("Part::Box","myBox")
   s=FreeCADGui.activeDocument().getObject("myBox").toString() # store as string
   from pivy import coin
   inp.setBuffer(s)
   myNode=coin.SoDB.readAll(inp) # restore from string

Then, create a standalone viewer with pivy:

 from pivy.sogui import *
 from pivy.coin import *
 import sys

 def myViewer():
     # Initialize Coin. This returns a main window to use.
     # If unsuccessful, exit.
     myWindow = SoGui.init(sys.argv[0])
     if myWindow == None: sys.exit(1)
 
     # Make an empty scene and add our node to it
     scene = SoSeparator()
     scene.addChild(myNode)

     # Create a viewer in which to see our scene graph.
     viewer = SoGuiExaminerViewer(myWindow)

     # Put our scene into viewer, change the title
     viewer.setSceneGraph(scene)
     viewer.setTitle("FreeCAD Object Viewer")
     viewer.show()

     SoGui.show(myWindow) # Display main window
     SoGui.mainLoop()     # Main Coin event loop

Then you just need to run your viewer:

     myViewer()