Tuesday, December 18, 2012

Python in Qt Creator

I've been recently working to port Saera to the N9, which means I have to use Qt. After a few dead ends, I decided to try building a few of the Qt sample apps to get a feel for how it was supposed to work. I learned how to use Qt Creator, how to pair with a device, and how to write a simple QML app. I decided to move on to the project itself - and ran into a large hurdle to clear: Qt Creator doesn't support Python.
Or rather, it does, but only as a filetype; there isn't a way to tell Qt Creator to use a Python file as the main executable rather than the C++ file it automatically generates. I didn't really want to have to port Saera to C, so I went searching for a workaround. It turns out there is a fork of Qt Creator with Python support; however, I couldn't get it to compile properly on my system. And Google wasn't much help; most of the results I found were basically saying "If you want to use Python, you can't have the convenience of Qt Creator, but rather you have to do the whole thing manually."
However, I found a workaround: Leave the C++ in there, but rather than having it load and run the QML, have it load the Python file itself, and just run that. For those who are interested, here's my code:

C++:
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
#include <libgen.h>

Q_DECL_EXPORT int main(int argc, char *argv[])
{


    enum { BUFFERSIZE = 1024 };
    char buf[BUFFERSIZE];
    ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)-1);

    if (len != -1) {
      buf[len] = '\0';
    }
    else {
      return 2;
    }

    char *dirc = strdup(buf);
    char *dname = dirname(dirc);
    strcat(dname, "/../qml/saera/main.py");

    char *arr[] = {"python", dname, NULL};
    execvp("python", arr);
}
Python code (main.py):
#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import sys, os
from PySide import QtCore
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtDeclarative import *
os.chdir(os.path.dirname(os.path.abspath(__file__)))
size = (800, 480)
app = QApplication(sys.argv)
view = QDeclarativeView()
window = QMainWindow()
window.resize(*size)
window.setCentralWidget(view)
view.setResizeMode(QDeclarativeView.SizeRootObjectToView)
view.setSource("main.qml")
window.show()
app.exec_()