Saturday, January 16, 2010

Calling Python from JavaScript in PyQt's QWebkit

QtWebKit makes it very easy to expose methods and properties implemented in Python to JavaScript. Qt will automatically expose Qt-slots and Qt-properties to a JavaScript when a QObject is made available in the frame's JavaScript context.

I think the code speaks for itself
import sys
from PyQt4 import QtCore, QtGui, QtWebKit

"""Html snippet."""
html = """
<html><body>
  <center>
  <script language="JavaScript">
    document.write('<p>Python ' + pyObj.pyVersion + '</p>')
  </script>
  <button onClick="pyObj.showMessage('Hello from WebKit')">Press me</button>
  </center>
</body></html>
"""

class StupidClass(QtCore.QObject):
    """Simple class with one slot and one read-only property."""

    @QtCore.pyqtSlot(str)
    def showMessage(self, msg):
        """Open a message box and display the specified message."""
        QtGui.QMessageBox.information(None, "Info", msg)

    def _pyVersion(self):
        """Return the Python version."""
        return sys.version

    """Python interpreter version property."""
    pyVersion = QtCore.pyqtProperty(str, fget=_pyVersion)

def main():
    app = QtGui.QApplication(sys.argv)

    myObj = StupidClass()

    webView = QtWebKit.QWebView()
    # Make myObj exposed as JavaScript object named 'pyObj'
    webView.page().mainFrame().addToJavaScriptWindowObject("pyObj", myObj)
    webView.setHtml(html)

    window = QtGui.QMainWindow()
    window.setCentralWidget(webView)
    window.show()

    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
Some references:

Thursday, January 14, 2010

New-style PyQt Signals and Slots

I was to lazy to take a look at the new-style signal and slot support which was introduced in PyQt 4.5 until yesterday. I did know that there were something called new-style signals and slots but that was the end of the story. Now I have taken the time and I think it's a cleaner solution than the old-style.

I'll just give you a short intro to whet your appetite, find all details here yourself.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui

def clicked():
    print "Button Clicked"

qApp = QtGui.QApplication(sys.argv)

button = QtGui.QPushButton("Click Me")
QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), clicked)
button.show()

sys.exit(qApp.exec_())
This is the old way of connecting a signal to a slot. To use the new-style support just replace line 11 with following code
button.clicked.connect(clicked)
The new-style support introduces an attribute with the same name as the signal, in this case clicked.

If you need to define your own signal you'll do something like this (off the top of my head):
class X(QtCore.QObject):
    mySignal = QtCore.pyqtSignal(int)

    def emitMySignal(self):
        self.mySignal.emit(100)
And the old way:
class X(QtCore.QObject):
    def emitMySignal(self):
        self.emit(QtCore.SIGNAL('mySignal'), 100)

IMHO the new-style support is more pythonic and you don't have to specify your signals as strings when connecting. If you use pydev (eclipse) you'll also have completion support for signals.

Friday, January 8, 2010

Digikam - Light table

This post is somewhat related to the post about ctypes and gphoto.

Background
I consider myself a pre-amateur photographer and that means I'm taking a lot of shots just to learn how the camera works. I own a Canon EOS 1000D and have recently moved from the fully automatic exposure modes to the advanced exposure modes, and to be more specific, the programmed auto exposure mode.

So, I needed an application that could load a couple of pictures, showing two pictures side-by-side for visual comparison and at the same time presenting the more important meta-data attributes such as focal length, exposure time, ISO and aperture. I considered doing such application myself and that's why I came across and started to explore gphoto. But luckily, I managed to stop myself and took yet another look at what Digikam offers. I'm a die-hard KDE-fan and have been using digikam, which is a KDE photo manager application, for quite some time to organize my photos but never actually used any other features except removing red-eyes.

To my surprise digikam included exactly the feature I was looking for! It's called the Light Table.

The Light Table
Digikam allows you to select a couple of pictures which can be placed onto the light table, as shown in the screenshot below.



By choosing Place onto Light Table a new window is opened with, in this case, the three pictures loaded and two of them shown side-by-side.



The light table also displays the meta-data for the respective picture (sorry about that some of the attributes are in Swedish) that are currently shown. You can synchronize operations like zooming and panning. When you zoom, both pictures will be zoomed to the same level and when panning, both pictures will be panned to the same area, really nice.

This was exactly what I was looking for. Now I can take a couple of shots with different settings, for example, changing the white balance, ISO and/or other parameters and compare the result rather easily. I get both a visual and a meta-data diff in the same view.

I just wanted to share my findings and hope this post was to some use for others that are looking for something similar.