I’m currently working on an application for manufacturing. It it was originally written in python and tkinter for personal use by a machinist. The idea of the app was interesting so I got involved to see how we could make a commercial product out of it. The product was to run on Windows with MacOS and Linix versions later.
Features and Requirements
The app allows a person to rapidly create a cabinet and product a cutting list. The method used to define the cabinet ensures that the resulting design can be made, fits into the defined space and can be constructed without errors. In the normal CAD approach, the design is created and then needs to be checked to ensure that there are no gaps. Visual cues are provided and if you are clever when you setup the model with parameters you can avoid the errors. However it still takes longer and requires more CAD skills than required with our app.
There were a number of constraints on the implementation of the application:
- Use python libraries for the GUI (wrapped C/C++ libraries are fine).
- Provide a 3D model view with simple operations without having to implement a 3D modeller.
- Provide data entry controls for manipulating the model whilst keeping the 3D model and controls in sync, e.g. clicking in the 3D view selects a part and displays its attributes.
- Provide a native look and feel for a desktop app. Nothing is worse than a desktop app that almost looks native but is not. Games and such do not have to confirm, but our app would.
- Deliver a single executable with support files inside a simple installer.
GUI and 3D Modelling
The tkinter library is usually part of a standard python installation. The library is great for simple UIs but is lacking functinality for complex apps. I thought it would work well for our application if we could find a 3D model view component that could be embedded as a control/window within the overall application.
This turned out to be next to impossible with tkinter since support in newer versions of libraries like vtk are for Qt and the web. The code is there but hasn’t been touched in a few years. Compiling vtk is not a simple task, especially on a Windows machine. There was a lot of extra work in tkinter to make things like input sanitizers, event propagation and other plumbing. The major stumbling block was that even if I could get vtk going there was no way to confine it to a sub-window within the tkinter app window.
The next thing to try was the new wxPython which turned out to be a lot more fun and full featured. I was able to bring a higher level of polish to the UI quickly and the package contained a control to embed an OpenGL window inside an application. However vtk didn’t support wxPython so I couldn’t use it unfortunately.
I did try several python OpenGL based renders, so of which were quite full featured. However I could get the app to crash reliably by resizing the window. There is some issue with the python OpenGL binding library (common to all the modelling libraries I tried). I tried some simple fixes but was unwilling to compile a custom version on my machine. That would almost guarantee failure on a customer’s machine.
There were quite a number of different 3D modelling packages. One in particular I liked and was keen to use. It had a nice example application that I could use to bootstrap the development of our application.
Packaging
The only issue I ran into was that it was based on conda with no pip compatible wheels available. This did not meet the goal of creating an installable application. When I tried the miniconda route I still ended up with multi-gigabyte install and a massive number of packages. This is fine for data scientists and developers but seriously wrong for our customers
Trying to see how to convert the existing conda setup for this package led me down the rabbit hole of wrapping C++ code and making python packages. It is seriously complicated and I now understand why the interfaces to these packages are so non pythonic and difficult to maintain. Wrapping tens of thousands of lines of C++ code with templates is a difficult proposition and trying to change camel cased function and member names (C++ practice) to python snake case is no easy task. The Shiboken binding tool is providing support to do these sorts of things but the use of XML for type definitions was problematic for me.
Qt and PyQt/Pysider were not options since I wanted to see if the application was commercially viable before buying licenses. You cannot switch from free to commercial. I was thinking at this stage we might want to use the Qt6 and the new Pysider but before spending the money I was going to try to make an executable for an installer.
Executables and Installers
I have past commercial experience with writing and maintaining Windows installers. Let’s just say they are not pretty and it is really easy to make mistakes that can seriously affect a customer’s machine. So I was really not keen to write an installer although the NSIS and Inno Setup tools look like they would make it easier.
For creating an executable I tried PyOxidizer and Pyinstaller . I found pyinstaller easier to work with. I also didn’t like the idea of pyoxidizer’s special python builds. Making an executable was a lot more work and harder than required . In the end I managed to get it working but didn’t progress to writing an installer.
So we had a executable, we could build an installer but we didn’t have a 3D modelling library that we could use inside our application. I found the threejs library and knew we could run it inside a wxpython html2 widget. However, on Windows you run into the old Internet Explorer control which can’t run threejs (unsurprisingly). You need the Edge Chromium control. So I changed the code to only use this control. It worked on my machine but not another developers machine even though he had the latest Edge. Windows refused to instantiate the correct control for some reason.
Around this time I was also trying to see if we could get two way communication between the rest of the app and the code running in the html2 control. I could inject javascript into the control but getting anything back was impossible unless I ran a local http server. You can see where this is going.
Python and React
So in the end we decided on a SaaS with a python server and React application. Python is a wonderful environment and we’ll use for business logic and database interface, but web browser is a faster for us to develop the UI.
Till next time