Harsh J

Memoirs of a QWERTY Keyboard

Archive for the ‘Qt’ tag

Writing Android Applications

leave a comment

Cause “app” is a slang I don’t seem to bear anymore. (What blows me over is a ‘you’ substitute in emails, though.)

Android

Android



I finally got around writing out simple applications for the Android mobile platform. For someone who comes from a background of event driven classes (a la Trolltech Qt), this RCP-styled programming in Android looks real bad. I wish we had simple @Override-driven eventing than defining new inline/external classes for every simple event that needs handling. Ah well, different worlds, different paradigms. I could actually go on for hours describing how Android could benefit with a Qt-style event driven programming model, but I have other things to do ;)

Written by Harsh

January 17th, 2011 at 1:08 am

PyQt FAQ – Custom Signals, JPEG, Mouse Hovers and More

one comment

Note: If you’re new to using PyQt but are interested in great cross-platform GUI application development please read the PyQt Introduction article.

I actually think of this more as an FSQ than an FAQ. Frequently Searched Questions on my blog.

These are the contents of this article:


Lets start with the most searched item.

Writing Custom Signals in PyQt

Writing custom signals that you want to ‘emit’ or trigger during certain events is an easy task. You need to create your signal object first. This is done using the PyQt.QtCore provided pyqtSignal() function. Its signature is given as:

QtCore.pyqtSignal([optional argument types], [optional name])

We need to create a signal object using this signal as a property in our class, then call its connect and emit methods to actually use it. If I were to explain diagrammatically:

Creating Custom Signals using PyQt

Creating Custom Signals using PyQt

The following code sample explains three types of signals:

  • Signals with no arguments (simpleSig)
  • Signals with some arguments (2, argumentSig)
  • Signals with multiple-type (overloaded) arguments (int and QString, doubleSig)
# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4.QtCore import *

import sys

class MyWidget(QWidget):

    # Defining signals below:

    # No arguments, its a simple signal that can
    # be emitted.
    simpleSig = pyqtSignal()

    # A signal that requires two parameters.
    # (One is an integer, other is a Python list type)
    # You can have one or more than two as well.
    argumentSig = pyqtSignal(int, list)

    # A signal that allows two different sets of params.
    # One is if you send an int, the other is for QString.
    # This signal is also optionally named using 'name'
    # for use in more dynamic purposes.
    doubleSig = pyqtSignal((int,), (QString,), name='doubles')

    def __init__(self, parent=None):
        # Construct the parent, never forget this!
        super(MyWidget, self).__init__(parent)

        # Connect our signals to their slots
        self.simpleSig.connect(self.simpleSlot)
        self.argumentSig.connect(self.argumentSlot)
        # We have same slot for the double signals
        # (aka) overloaded signals.
        # Cause we can check the argument from within too!
        self.doubleSig['int'].connect(self.doubleSlot)
        self.doubleSig['QString'].connect(self.doubleSlot)

        # Connect our button to a slot which
        # will call the signals.
        self.button = QPushButton('Press me', self)
        self.button.clicked.connect(self.buttonClicked)

    def buttonClicked(self, checked=False):
        # Emit the various signals to use them.
        self.simpleSig.emit()
        self.argumentSig.emit(2, [1,2,3])
        # Overloaded signals have the following format
        # for emitting specifically.
        self.doubleSig['int'].emit(42)
        self.doubleSig['QString'].emit('Hitchhiking a ride.')

    # Defining custom-signal slots below:

    def simpleSlot(self):
        # Takes no arguments
        print "Simple custom signal:",
        print "No arguments in this type of signal."

    def argumentSlot(self, *args):
        # ( Can also be 'argumentSlot(self, intArg, listArg)' )
        # Has two arguments anyway, which is collected into one
        # using '*' (A Python feature)
        print "Multi-argument signal:",
        print "Two arguments were passed: value: '%d' of %s and value: '%s' of %s." % (args[0], type(args[0]), args[1], type(args[1]))

    def doubleSlot(self, someArgument):
        # This slot handles both doubleSig(int)
        # and doubleSig(QString)
        print "Overloaded signal:",
        print "An argument was passed and it was of '%s' and value: '%s'." % (type(someArgument), someArgument)

if __name__=='__main__':
    app = QApplication(sys.argv)
    widget = MyWidget()
    widget.show()
    app.exec_()

The output upon running this example code would be (printed in stdout):

Simple custom signal: No arguments in this type of signal.
Multi-argument signal: Two arguments were passed: value: '2' of <type 'int'> and value: '[1, 2, 3]' of <type 'list'>.
Overloaded signal: An argument was passed and it was of '<type 'int'>' and value: '42'
Overloaded signal: An argument was passed and it was of '<class 'PyQt4.QtCore.QString'>' and value: 'Hitchhiking a ride.'

I hope this makes it clear on how to create your own/custom signals and to piggyback data on it via arguments (using their class/type to create them).

References: PyQt Documentation

Saving an Image as JPEG using QImage

JPEG is a wonderful, lossy image format. PyQt supports JPEG saving if a plugin called libjpeg exists. Anyhow to save a QImage as a JPEG image, do the following:

# Create a 50 pixel square image
# (or load your own using a filename).
img = QImage(50, 50, QImage.Format_RGB32)
# Lets draw a red square on this.
painter = QPainter(img)
painter.setBrush(QBrush(QColor('#ff0000')))
painter.drawRect(0,0,50,50)
painter.end()
# Save it as JPEG. Extension mention does
# all internal magic. 'jpg' also allowed.
img.save("sample.jpeg")

The above code snippet creates an image ‘sample.jpeg’ that looks like below:

A QImage saved JPEG - With a shape drawn using QPainter

A QImage saved JPEG - With a shape drawn using QPainter

There it is, as simple as that! Can be done via QPixmap too.

References: QImage, QPainter (Lots of other shape/figure drawing help here)

Tracking Mouse Hover Events with PyQt

Mouse hover events (known as the mouseMoveEvent(event) in PyQt) are tracked by default if the mouse is pressed and dragged. However if you’d like to also track mouse move events upon simple hover also (without a press requirement) you will need to enable the mouseTracking property of the QWidget (also available in all its derivatives, naturally).

So, to enable mouse tracking / mouse hover tracking for your widget you will need to call widget.setMouseTracking(True). The following code snippet is again a simple program that prints co-ordinates of the mouse pointer upon hover (without requiring a press held).

from PyQt4.QtGui import *
from PyQt4.QtCore import *

import sys

class MyWidget(QWidget):

    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        # Enable mouse hover event tracking
        self.setMouseTracking(True)

    def mouseMoveEvent(self, event):
        # This is a QWidget provided event
        # that fires for every mouse move event
        # (In our case the move is also the hover)
        print "Mouse Pointer is currently hovering at: ", event.pos()

if __name__=='__main__':
    app = QApplication(sys.argv)
    widget = MyWidget()
    widget.show()
    app.exec_()

It should spew out some output like:

Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(415, 66)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(420, 60)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(424, 56)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(427, 51)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(433, 41)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(438, 36)

An additional way, apart from QWidget.setMouseTracking(True) is to set a Qt.Hover attribute via QWidget.setAttribute(attribute) and then filtering this event out. If you’d like me to give an example for this method too, post a comment. I think the mouse tracking solution does it for detecting mouse hover events over your widgets as the other way might look ugly.

References: QMouseEvent

Bonus Tips

Screen Size

Getting the screen size of the desktop (the display resolution in other words) is simple. You need to access the desktop widget using QApplication.desktop() [Its static so you don't need your QApplication object] and then pulling out the size() from it. That is, do:

QApplication.desktop().size()

References: QApplication

Setting the Window Size

Um, am not sure what’s so ambiguous about setting the size/geometry of a widget in PyQt but to generally set any widget’s size, be it your QMainWindow object or a simple inner QWidget derivative, all you have to do is to set its geometry property like so:

# x and y are co-ordinates where the widget/window has to appear
# and width and height are the sizes you're looking to set
# (You can keep position same by using widgetObj.x()/y() to get current
# values of x/y and passing them back in).
widgetObj.setGeometry(x, y, width, height)

References: QWidget

End

That’s all for now folks, keep the searches or comment-queries coming if you still have some! (And oh, please do refer Qt Assistant too, it’s the right thing to do).

Written by Harsh

May 6th, 2010 at 10:46 pm

PyQt – Creating interfaces visually with Designer

4 comments

Note: If you’re new to using PyQt but are interested in great cross-platform GUI application development please read the PyQt Introduction article.

Designing a graphical interface for an application could be a tiresome task. There are guidelines to keep track of, layouts to maintain and more of such stuff. In the PyQt code samples you’ve seen so far we’ve written our interfaces in pure code. While this is fun and easy to do for little applications that consist of about 5 to 10 widgets, it’s not worth spending the time upon in creating fully blown up interfaces for complete applications.

The Qt Designer

Fortunately, Qt provides us a tool to design interfaces and to port it to usable code automatically. This tool is called the Qt Designer, and it comes with the Qt library bundle you installed. Additionally we would require a converter for processing the XML .ui files Designer produces into a python module .py file; also installed with the PyQt4 bundle.

Thus, to design in PyQt we need the two following tools:

  • Qt Designer from Nokia’s Qt Software
  • The pyuic4 script from Riverbank’s PyQt

Once you have Designer and PyQt4 tools installed, let’s fire it up and get started.

The initial interface might look familiar to those who have used Visual Studio, or Glade and such tools. For the rest, it’s intuitive enough to learn smoothly. Read the Qt Designer guide for more elaborate help if you still don’t find it usable.

The Qt Designer

The Qt Designer

In this article, we’ll be using Designer to design and create a simple Image Viewer application.

References: Qt Designer, The PyQt + Qt Designer Documentation

Image Viewer

Our Image Viewer application would be a very simple one, with options to Open an image file of major types (JPEG, PNG, GIF, etc.) and another to Quit. Upon opening of an image, we shall also set the status bar to show the dimensions of the image.

Designing the GUI

Open Qt Designer (‘designer’ command if on Linux) and choose File | New | “Main Window” under templates/forms expansion. This creates a new QMainWindow widget for us to work upon. The QMainWindow is basically a composition of a main-area widget, a menu-bar and a status-bar at the bottom, the very usual stuff an application consists of.

Design of the Image Viewer UI

Design of the Image Viewer UI

From the Widget Box, drag a Label onto the main window’s area. Right-Click at any of the free space available on the same area, choose the “Lay out” sub-menu and then hit the “Lay out Horizontally” option. Designer will automatically stretch your Label across the area available this way. We need this layout (any layout will do here, actually) since we want the image to show in the entire window area.

Now on to menus, Add a File menu and under it add an Open and a Quit option, as shown below. To add these just click where it says “Type here” and get typing; Hit Enter/Return key to get to the next element in the menu after you’ve typed.

Under the Property Editor, select and set the Label’s text property to blank, and its alignment property to AlignHCenter and AlignVCenter. This completes our UI design in Qt Designer. But don’t quit already, do explore the other properties of the widgets used and figure out their possible uses; get used to the interface and available tools like Form Previews, etc.

The imageLabel (QLabel) object Properties

The imageLabel (QLabel) object Properties

For instance, check out the properties like geometry (Height and Width), font, tooltip, etc. If you’re in a good reading mood, also checkout the amazing Style Sheet documentation in Qt Assistant, as it explains a lot about each Widget’s construct and how to go about customizing it till your heart’s content.

Finally, renaming the widget elements’ variables would be a good idea, since it will help us code our application in a much more readable manner. This is how I’ve named these widgets but feel free to follow whatever naming conventions you would like to use:

Image Viewer object names

Image Viewer object names

Just double-click on the Object Name items and edit them in-line after that. Note and remember your QMainWindow class’s object name. Once you’re done, save the file as ‘ImageViewerUI.ui‘.

References: QLabel, QAction, QMenuBar, Layouts Guide

Using PyQt’s pyuic4 script

Our next step requires the use of the aforementioned pyuic4 tool. It’s usage syntax is as follows:

pyuic4 input_file.ui -o output_file.py
# Optionally takes -x parameter to make the generated code executable.

Thus we should run, for our UI file:

pyuic4 ImageViewerUI.ui -o ImageViewerUI.py

This will create a file ImageViewerUI.py that we can now use. Looking into the file will show you that its just a long list of widget constructs and of applying property settings. There is no need to edit this file, and is advised not to since pyuic4 will over-write all changes in it if you run it once again after some changes you wanted to do.

Whenever you edit your .ui files, make sure to run the pyuic4 tool to convert it into its Python equivalent (or to update existing Python code such that it reflects the new changes).

Additional info: Try `pyuic4 –help` for more fine-tuning options.

Running the basic GUI

Create a new file ImageViewer.py to finally add the application logic. Before we get to the code part, let me explain how the Qt’s subclass approach works. A Qt Designer file is inherited by the QMainWindow-derived class, and then the interface is setup using the setupUi() call with an instance. This creates all the objects/widgets for the interface as attributes of the derived QMainWindow class so that it’s ready to show. Next, we need to add the application-level logic to this derived class as normal methods. Since we have access to all the widgets used in the interface via our class, we can do as we like with their available features. The following diagram explains the hierarchy we ought to follow each time we need to implement a UI class for use:

Image Viewer Inheritance Diagram

Image Viewer Inheritance Diagram

Thus, a basic class that can be run would look like:

#!/usr/bin/python

from PyQt4 import QtGui, QtCore
import sys

# Import the interface class
import ImageViewerUI

class ImageViewer(QtGui.QMainWindow, ImageViewerUI.Ui_mainWindow):
    """ The second parent must be 'Ui_<obj. name of main widget class>'.
        If confusing, simply open up ImageViewer.py and get the class
        name used. I'd named mine as mainWindow, hence Ui_mainWindow. """

    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        # This is because Python does not automatically
        # call the parent's constructor.
        self.setupUi(self)
        # Pass this "self" for building widgets and
        # keeping a reference.

    def main(self):
        self.show()

if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    imageViewer = ImageViewer()
    imageViewer.main()
    app.exec_()
    # This shows the interface we just created. No logic has been added, yet.

Run this class and you can see the window you just created.

Basic GUI of Image Viewer during Runtime

Basic GUI of Image Viewer during Runtime

You MUST call self.setupUi(self) to make the UI file run the setup statements and build the GUI interface for use by our class.

References: QMainWindow

Adding Application Logic and other Code

Now to add the opening-an-image feature, let’s define a few methods in the class as:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from PyQt4 import QtGui, QtCore
import sys

# Import the interface class
import ImageViewerUI

class ImageViewer(QtGui.QMainWindow, ImageViewerUI.Ui_mainWindow):
    """ The second parent must be Ui_<obj. name of main widget class>. \
      If confusing, simply open up ImageViewer.py and get the class \
      name used. I'd named mine as mainWindow and hence the use. """

    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        # This is because Python does not automatically
        # call the parent's constructor.
        self.setupUi(self)
        # Pass this "self" for building widgets and
        # keeping a reference.
        self.connectActions()

    def connectActions(self):
        self.actionQuit.triggered.connect(QtGui.qApp.quit)
        # Connect the Quit action's triggered signal
        # to a proper Quit method
        # given by qApp (which points to your QApplication
        # object).
        self.actionOpen.triggered.connect(self.openImage)
        # Connect the Open action's triggered signal
        # to load an image onto the image label.

    def openImage(self):
        # Lets get a user-provided file to open
        # using PyQt's QFileDialog class.
        fileName = QtGui.QFileDialog.getOpenFileName(
                        self,
                        "Open Image File",
                        QtCore.QDir.homePath(),
                        "Image Files (*.jpg *.jpeg *.gif *.png)"
                    )
        # Don't attempt to open if open dialog
        # was cancelled away.
        if fileName:
            self.imageLabel.setPixmap(QtGui.QPixmap(fileName))
            # Load the image file as a pixmap onto the
            # labelImage QLabel GUI object.

    def main(self):
        self.show()

if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    imageViewer = ImageViewer()
    imageViewer.main()
    app.exec_()

Note the two new method additions connectActions() and openImage(). They complete the application logic that’s involved for our image viewing application example. Try to understand them better by seeing the PyQt classes used in them and referring them up in Qt Assistant for much more detailed information.

Now the application can open images via File | Open and can also be quit via File | Quit.

This is the final result of our work:

Image Viewer in Action

Image Viewer in Action

References: QPixmap, QFileDialog, qApp

Exercise

Try to build a simple text-based evaluator application that contains of two things:

  • A text input box that allows for mathematical expressions input.
  • An output label or text area (non-editable) for showing results of these expressions.

Classes you could use are QLabel, QLineEdit and QTextEdit. Another hint is to use Python’s ‘eval‘ function. As a bonus try to make the evaluation via Python safe.

Written by Harsh

April 18th, 2010 at 9:28 pm

Fall of the Sulks

4 comments

My undergraduate project is complete, with a few glitches to cover up. It ain’t much for now, but I guess its enough to make a sizable impact. I’d like to say that PyMT is an excellent library, and I can’t thank the developers behind it enough for their work so far (They’ve written a tracker too now, you gotta check that out). Maybe I shall contribute to it in near future, provided I have the time and skill. Contributing by code is something I only recently learned and its not wise to be hasty. Plus, there’s loads of math involved ;)

Randomly placed warning for a random post.

On the Qt front, I have this draft of a PyQt4 + Designer tutorial lying around for 7 months and it still doesn’t feel complete (alright, am lazy to make it so). Maybe I should do another screenshot + diagramming session and see if that turns out satisfactory. Something brewing in my mind for a feature in KDE 4.5 has pushed me to handle XML with the same toolkit – and writing SAX parsers is ugly, even more so if its C++. I wish I didn’t have to do that, I hate writing readers of tags and the characters between them – it always conks out someday or sometime.

Fall of the Hulks Poster

Poster to 'Fall of the Hulks'

Am addicted to comics these days, more than I’ve been to TV shows or movies (You may count “Lost” and ‘The Matrix’ as exclusions to that). Let’s talk about ‘Fall of the Hulks‘. Its twisted in its story, not many have great guesses on the new Red-Hulk (or Rulk) character and the entire screenplay is Nick Fury-esque; Apparently the story following this arc will have all major heroes of the Marvel Universe hulked up, which would be totally awesome to read (the covers are making me ogle already). For now Siege and Realm of Kings satisfy the addiction hunger. I’m not much of a fan when it comes to DC, having read pretty out-dated stuff only (such as Death of Superman or Knightfall), and thus am not quite enjoying the over-stretched Blackest Night titles they have everywhere. Karthik would not be happy with this, but fear not my friend – the completionist in me won’t give up till it ends.

Re-read Mostly Harmless and am dying to purchase and read ‘And Another Thing…‘ by Eoin Colfer but it seems too expensive even now. Will get it in the sale season probably, and read it at the Eloor libraries until that happens. H2G2 and its associated books are a must read for anyone with brains and capacity for painful-cheeks humor.

Until the next update!

Written by Harsh

March 8th, 2010 at 8:04 pm

Posted in Personal

Tagged with , , , , ,

Sorting entries in a QStringList Case-insensitively

4 comments

This post is simply a snippet-post for the users of Nokia’s Qt C++ cross-platform toolkit.

While writing some C++ code (after 2 long years since I last wrote them for academic reasons), I had this simple issue of sorting a QStringList in a case-insensitive manner. Normally, there exists a QStringList::sort() function that does the sorting of the strings stored in it in a case-sensitive manner, and is very fast at it. But Qt does not provide a way to perform the sort in a non case-sensitive manner, although it has hints on how to in the class’ documentation.

Being mostly a PyQt/PySide user who uses inbuilt Python lists to do all list-work, here’s how its apparently done in Qt/C++, using a QtCore class called QMap:

#include <QtCore/QStringList>
#include <QtCore/QMap>

void sortNonCaseSensitive( QStringList &sList ) {
    ///  Sorts the passed sList non-case-sensitively.
    ///  (Preserves the cases! Just doesn't use them
    ///  while sorting.)
    QMap<QString, QString> strMap;
    foreach ( QString str, sList ) {
        strMap.insert( str.toLower(), str );
    }
    sList = strMap.values();
}

That’s it.

Written by Harsh

October 24th, 2009 at 10:54 pm