Now I finally received my Qt certification diploma by mail. Actually, I passed the exam when I attended the Qt DevDays 2010 (october) in Munich. See if I'll go for the advanced exam some day.
Monday, November 29, 2010
Friday, November 12, 2010
Nokia Rules!
There's a conference in the southern part of Sweden (Malmoe) called Oredev which I have been attending this week. I was interested in a talk about MeeGo, meet some Nokia people and to attend a two days Qt course.
Nokia had a booth and I was passing by to check out if they had some Qt stickers which I needed for a demonstration (a simple QML app) I was going to show at my employers booth. To my disappointment they had no stickers but instead I had a great chat with one of guys.
We had an interesting and giving chat about Qt, apps, OviStore, Nokia and MeeGo. Suddenly the guy grabs a package and hands it to me, to my surprise I just realized that he gave me a Nokia N8! He smiled at me and told me to make my app available on OviStore.
Now finally Nokia has given me the opportunity to develop apps for mobile devices since I can use Qt (I already made an app w/o owning a device).
I can't wait for MeeGo devices to show up.
Thanks Nokia!
Nokia had a booth and I was passing by to check out if they had some Qt stickers which I needed for a demonstration (a simple QML app) I was going to show at my employers booth. To my disappointment they had no stickers but instead I had a great chat with one of guys.
We had an interesting and giving chat about Qt, apps, OviStore, Nokia and MeeGo. Suddenly the guy grabs a package and hands it to me, to my surprise I just realized that he gave me a Nokia N8! He smiled at me and told me to make my app available on OviStore.
Now finally Nokia has given me the opportunity to develop apps for mobile devices since I can use Qt (I already made an app w/o owning a device).
I can't wait for MeeGo devices to show up.
Thanks Nokia!
Saturday, November 6, 2010
Getting Interactive With PyQt
One of the cooler features with PyQt (IMHO) is the possibility to write Qt code interactively. It isn't actually something new and I'm sure it's been there for a while but some of you might not be aware of it. I find it very useful when I want to learn new things in Qt, so without further ado, here's a short introduction on using it.
Start an interactive python session by executing python in a shell:
Ok, let's create a push button:
Let's put the button at the center of the window by using a layout manager:
And finally, let's see how 'layout.addStretch()' affects the layout:
You can easily add a slot to the button's clicked signal:
Thanks for reading!
Start an interactive python session by executing python in a shell:
$> python Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>Let's create a simle top-level window (I wont add the '>>>' in case you would like to copy/paste the code):
from PyQt4.QtCore import * from PyQt4.QtGui import * app = QApplication([]) window = QWidget() window.resize(400, 300) window.show()Now you should have a window similar to the screen shot below:
Ok, let's create a push button:
button = QPushButton("Click Me!", window)Hmm, no button shows up... Why? Well, that's because we need to make it visible after we have added it to the window:
button.show()Ahh, sweet! We have added the button to the window interactively:
Let's put the button at the center of the window by using a layout manager:
layout = QHBoxLayout(window) layout.addWidget(button)
And finally, let's see how 'layout.addStretch()' affects the layout:
layout.addStretch()
You can easily add a slot to the button's clicked signal:
def mySlot(): print "Button Clicked" button.clicked.connect(mySlot)As you can see, it's an easy way to try out thing in Qt.
Thanks for reading!
Monday, September 27, 2010
Qt DevDays 2010
I'm attending Qt DevDays 2010 and really looking forward to it.
I haven't decided yet which tracks I'll attend, there are so many interesting but I definitely go for some Quick-talks. I believe I'll have a great time.
And that's not all, in November I'll also attend a two day Mobile Qt course at Öredev with topics such as Qt Mobility API, Gesture framework, Hybrid JavaScript apps and last but not least Quick. Looks very promising.
I haven't decided yet which tracks I'll attend, there are so many interesting but I definitely go for some Quick-talks. I believe I'll have a great time.
And that's not all, in November I'll also attend a two day Mobile Qt course at Öredev with topics such as Qt Mobility API, Gesture framework, Hybrid JavaScript apps and last but not least Quick. Looks very promising.
Saturday, September 11, 2010
PyQt and Signal overloads
I almost spent half an hour trying to figure out why my code didn't work.
I used a QSignalMapper to connect a couple of clickable widgets to emit just one signal, widgetClicked(int index), instead of having multiple signals, one for each widget. I connected the widgetClicked signal to the mapped signal of the QSignalMapper class and did the required set up for the signal mapper, something like the following snippet:
What the #@! is going on? Naturally, I had no option of searching for answers since I was sitting on the train back home from work and had no Internet connection.
Then it come to me, Python is not aware of the C++ signature overload. Python doesn't support overloading. Python/PyQt can't set up the right connection between widgetClicked and mapped. But how do you specify which of the overloads you want to connect to? By indexing:
I used a QSignalMapper to connect a couple of clickable widgets to emit just one signal, widgetClicked(int index), instead of having multiple signals, one for each widget. I connected the widgetClicked signal to the mapped signal of the QSignalMapper class and did the required set up for the signal mapper, something like the following snippet:
self._signalMapper = QSignalMapper(self) self._signalMapper.mapped.connect(self.widgetClicked) for index, widget in enumerate(buttons): widget.clicked.connect(self._signalMapper.map) self._signalMapper.setMapping(widget, index)Everything worked fine until I changed the signature of widgetClicked to pass a string instead of an int, it didn't work anymore. I only got the following print out: TypeError: connect() failed between 'mapped' and 'widgetClicked' and had no clue why because the mapped signal has a couple of overloads:
void mapped(int i) void mapped(const QString & text) void mapped(QWidget * widget) void mapped(QObject * object)I did also try changing widgetClicked to not receive any arguments and that worked, which was expected because the receiver is not required to match all arguments of a signal. Of course, it also worked if I changed back to int...
What the #@! is going on? Naturally, I had no option of searching for answers since I was sitting on the train back home from work and had no Internet connection.
Then it come to me, Python is not aware of the C++ signature overload. Python doesn't support overloading. Python/PyQt can't set up the right connection between widgetClicked and mapped. But how do you specify which of the overloads you want to connect to? By indexing:
# This connects your slot/signal to the string-overload signalMapper.mapped[str].connect(...)The int overload will be used default by PyQt, that's why my code worked when I connected widgetClicked to mapped w/o specifying which overload I wanted.
Sunday, September 5, 2010
IcecastRadio - Qt widget/Qt Quick example Icecast player
I've been toying with modeling a Qt application which supports both a traditional widget-based view and a quick-based (qml) view.
About IcecastRadio
The intention of this project/application is to demonstrate how important
it can be to design a model for your application. If the model is correctly
designed, it can be used from both traditional widget based UIs and
modern UIs built with Qt Quick without too much effort.
The advantage is of course that you can provide both a desktop application which integrates with the native look and feel of the OS and at the same time have a totally different experience UI-wise, for example in an embedded device by only changing the view-layer.
IcecastRadio is actually two applications, QtCast and QuickCast. QtCast implements the widget-based view and QuickCast the quick-based view. Both application depends on a third entity, the model. You'll see this division in the source code in form of three projects, qtcast, quickcast and model.
The application was successfully compiled against Qt 4.7-beta 1 and 2.
Source code
You'll find the source code at http://gitorious.org/icecastradio. The player code is released under the MIT license, clone and have fun. Please read the README file found in the repository for more information.
Screenshots
Must have...
Remark
The application lacks a lot of features that could be expected from a radio player, for example there is no way of sorting the list of stations nor any filtering can be applied. The intention was not to create a full blown Icecast player but to demonstrate how to create a model that is usable from both a widget-based application and a quick-based application.
Patches are welcome :)
About IcecastRadio
The intention of this project/application is to demonstrate how important
it can be to design a model for your application. If the model is correctly
designed, it can be used from both traditional widget based UIs and
modern UIs built with Qt Quick without too much effort.
The advantage is of course that you can provide both a desktop application which integrates with the native look and feel of the OS and at the same time have a totally different experience UI-wise, for example in an embedded device by only changing the view-layer.
IcecastRadio is actually two applications, QtCast and QuickCast. QtCast implements the widget-based view and QuickCast the quick-based view. Both application depends on a third entity, the model. You'll see this division in the source code in form of three projects, qtcast, quickcast and model.
The application was successfully compiled against Qt 4.7-beta 1 and 2.
Source code
You'll find the source code at http://gitorious.org/icecastradio. The player code is released under the MIT license, clone and have fun. Please read the README file found in the repository for more information.
Screenshots
Must have...
Remark
The application lacks a lot of features that could be expected from a radio player, for example there is no way of sorting the list of stations nor any filtering can be applied. The intention was not to create a full blown Icecast player but to demonstrate how to create a model that is usable from both a widget-based application and a quick-based application.
Patches are welcome :)
Wednesday, September 1, 2010
Python Koans - A Great Way to Learn Python!
I just found out about Python Koans by Greg Malcolm (thanks dude) after listening to the from python import podcast podcast (which I find amusing, thanks guys).
It's an awesome way to learn Python. Instead of just reading tutorials and/or books you learn Python by coding.
The interactive tutorial is built around unit-tests and you advance and gain new skills by passing tests and it's really funny. You do learn a lot about the Python language when doing the Koans so I recommend it even if you've been using Python for a while.
Another cool thing is that you learn how to do unit testing in Python, if you're not already familiar with it.
It's an awesome way to learn Python. Instead of just reading tutorials and/or books you learn Python by coding.
The interactive tutorial is built around unit-tests and you advance and gain new skills by passing tests and it's really funny. You do learn a lot about the Python language when doing the Koans so I recommend it even if you've been using Python for a while.
Another cool thing is that you learn how to do unit testing in Python, if you're not already familiar with it.
Tuesday, August 3, 2010
My python fix
It has been a while since I did something in Python. I've been coding C++, Qt and Qt Quick lately and I do enjoy it, especially Quick. I really like the declarative way of describing UIs.
But I still need my shot of Python now and then. Often I end up just doing small non useful snippets like list comprehensions stuff. I just love them, they are so beautiful and they make me happy :)
But I still need my shot of Python now and then. Often I end up just doing small non useful snippets like list comprehensions stuff. I just love them, they are so beautiful and they make me happy :)
>>> # Find the longest words >>> words = "Some random words in a text string" >>> max([(len(w), w) for w in words.split()], key=lambda x:x[0])[1]
Thursday, June 10, 2010
QSignalMapper - at your service
The QSignalMapper class is very useful, for example, in situations were you have a couple of QPushButtons and you want to connect the clicked-signal of each button to a single slot and still be able to identify the sender. It's possible to find out which object emitted a signal by calling sender() inside the slot, but I don't think that's good practice because you introduce a strong coupling between the signaling object and the slot.
A better solution is to use the QSignalMapper class which re-emits the signal with an additional configurable parameter. The parameter can be one of the following types: int, QString, QObject or QWidget.
So without further ado, here's a self describing example:
A better solution is to use the QSignalMapper class which re-emits the signal with an additional configurable parameter. The parameter can be one of the following types: int, QString, QObject or QWidget.
So without further ado, here's a self describing example:
# # Example showing how QSignalMapper can be used to manage an arbitrary # numbers of parameterless signals and re-emit them with an argument # identifying the sender. # # Each signal is associated in the QSignalMapper with either an int, # QString, QObject or a QWidget which is passed as argument to the slot # connected to the QSignalMapper. # from PyQt4.QtCore import QSignalMapper, pyqtSignal from PyQt4.QtGui import QApplication, QFrame, QGridLayout, QPushButton class Grid(QFrame): """ Lay out widgets in a grid. """ clicked = pyqtSignal(int) """ This signal will be emitted when on one of the grid items is clicked. The grid item's index will be passed as argument. """ def __init__(self, items, colCount, parent=None): """ Create Grid and setup QSignalMapper. Connect each item's 'clicked' signal and use the sequence index as map value which will be passed as argument when the Grid's clicked signal is emitted. items: sequence with widgets having a 'void clicked()' signal colCount: column count for each row parent: parent widget, default None """ super(Grid, self).__init__(parent) # Create a grid layout. layout = QGridLayout() self.setLayout(layout) # Create the signal mapper. signalMapper = QSignalMapper(self) for cnt, item in enumerate(items): # Setup mapping for the item. In this case, the # mapping is the sequence index of the item. signalMapper.setMapping(item, cnt) # Connect the item's 'clicked' signal to the signal # mapper's 'map' slot. # The 'map' slot will emit the 'mapped' signal # when invoked and the mapping set previously will be # passed as an argument to the slot/signal that is # connected to the signal mapper's 'mapped' signal. item.clicked.connect(signalMapper.map) # Add the widget to the grid layout layout.addWidget(item, cnt / colCount, cnt % colCount) # Forward the signal mapper's 'mapped' signal via the Grid's # 'clicked' signal. This will handle all widgets' 'clicked' # ssignals. signalMapper.mapped.connect(self.clicked) if __name__ == '__main__': import sys app = QApplication(sys.argv) # Create grid items items = (QPushButton('Open'), QPushButton('Close'), QPushButton('Read'), QPushButton('Write'), QPushButton('Delete')) win = Grid(items, 2) # Handle grid clicks here @win.clicked.connect def clicked(index): print "Button at:", index, " - text:", items[index].text() win.show() sys.exit(app.exec_())Hope this was to any help.
Wednesday, May 26, 2010
ABCs - Abstract Base Classes
What's ABCs?
The abc (abstract base class) module was introduced in version 2.6 of Python. The module provides the infrastructure for defining an abstract base class and can typically be used in situations where frameworks need to specify a bunch of interfaces to be implemented to ensure the functionality. An example can be a database application where the framework requires you to provide a Data Access Object with basic CRUD operations and therefore defines an interface, call it UserDao, with the following methods:
UserDao
The UserDao abc
Just to prevent flaming :) I enjoy duck typing and use it a lot but I think that ABCs are useful is some situations.
Implementing the abc
I haven't investigated if ABCs introduces any performance overhead but I can't really see why they should. One advantage of using ABCs in frameworks is that you can have the documentation and interface details as a simple Python class. Another advantage is that Python will issue an error if a sub-class doesn't implement all abstract methods/properties of the abc, which is probably the author's intention.
The abc (abstract base class) module was introduced in version 2.6 of Python. The module provides the infrastructure for defining an abstract base class and can typically be used in situations where frameworks need to specify a bunch of interfaces to be implemented to ensure the functionality. An example can be a database application where the framework requires you to provide a Data Access Object with basic CRUD operations and therefore defines an interface, call it UserDao, with the following methods:
UserDao
- getById - Return a user entity with the specified id
- store - store a user entity
- remove - remove a user entity from the persistent storage
The UserDao abc
The following example will show you basic usage of the abc module. You should read the module documentation for more details.
Let's create the UserDao abc:
Let's create the UserDao abc:
from abc import ABCMeta, abstractmethod class UserDao: """ This interface should be implemented to provide the framework with basic user CRUD operations. """ __metaclass__ = ABCMeta @abstractmethod def getById(self, userId): """ Return the user with the user id. """ @abstractmethod def store(self, user): """ Persist the user. """ @abstractmethod def remove(self, user): """ Remove the user from the persistent storage. """If we try to create an instance of this class we get the following error:
>>> dao = UserDao() Traceback (most recent call last): File "In other words, we have a well defined interface to support CRUD operations for User entities and we also have an easy to read documentation of what's expected from a UserDao. If we would rely on duck typing instead of defining the abc, we would need to document the expected behavior for the UserDao elsewhere. I think that the biggest advantage of using ABCs is that you have the interface definition and documentation in one place.", line 1, in TypeError: Can't instantiate abstract class UserDao with abstract methods getById, remove, store
Just to prevent flaming :) I enjoy duck typing and use it a lot but I think that ABCs are useful is some situations.
Implementing the UserDao can be done by sub-classing the UserDao.
class User(object): def __init__(self): self.id = None self.name = None class UserDaoImpl(UserDao): def getById(self, userId): user = User() user.id = userId user.name = 'A User' return user def store(self, user): print "Storing: ", user.id, "-", user.name def remove(self, user): print "Removing: ", user.idAnd to complete the example:
userDao = UserDaoImpl() user = userDao.getById(10) user.name = "New Name" userDao.store(user)Wrap up
I haven't investigated if ABCs introduces any performance overhead but I can't really see why they should. One advantage of using ABCs in frameworks is that you can have the documentation and interface details as a simple Python class. Another advantage is that Python will issue an error if a sub-class doesn't implement all abstract methods/properties of the abc, which is probably the author's intention.
Tuesday, May 4, 2010
Network manager problems on Kubuntu 10.04
I installed 10.04 as soon as it was released and it worked right out of the box. But suddenly today the network manager refused to start.
Well, I could see the icon in the systray but it didn't show any network interfaces (I have eth0 and wlan0).
To get me an IP I had to run dhclient manually from the terminal which was successful. Finally I could google for help.
Google pointed me to this blog post where the author had run into the same problem.
Apparently there is a bug filed for this issue, I'm just too lazy to search in the bug database :)
Just wanted to share this with you if you bump into it.
Well, I could see the icon in the systray but it didn't show any network interfaces (I have eth0 and wlan0).
To get me an IP I had to run dhclient manually from the terminal which was successful. Finally I could google for help.
Google pointed me to this blog post where the author had run into the same problem.
Apparently there is a bug filed for this issue, I'm just too lazy to search in the bug database :)
Just wanted to share this with you if you bump into it.
Friday, April 16, 2010
Unit testing with Qt
It's very easy to do unit testing with Qt. If you have any previous experience with
JUnit you shouldn't have any difficulties using QTestLib.
All that is required to create a unit test, besides adding 'QT += testlib' to your .pro file, is that the test class is a sub-class of QObject and each test function is declared as a private slot. To run all your test functions in a class simply call QTest::qExec() from the main function.
The following snippet shows what a unit test looks like:
Data driven tests are used when you want to exercise some piece of code with different values and is supported by the Qt testlib. To feed test data to a test function add a function with the same name as the test function appended with a '_data' suffix. So if the test function is named testFeature, the function that serves the test with data should be named testFeature_data. The test data is setup in a table. Two functions are used to create this table, addColumn and newRow. addColumn is used to define elements in the table and newRow adds data. QFETCH is used to fetch data from the table.
Lets create a simple 'capitalize' function that takes a string, capitalizes the first character and returns the result as a new string. We want to test the function with different data such as an empty string, first character is lower case and first character is upper case.
All that is required to create a unit test, besides adding 'QT += testlib' to your .pro file, is that the test class is a sub-class of QObject and each test function is declared as a private slot. To run all your test functions in a class simply call QTest::qExec() from the main function.
The following snippet shows what a unit test looks like:
#include <QtTest/QTest> class MyTest : public QObject { Q_OBJECT public: explicit MyTest(QObject *parent = 0) : QObject(parent) {} private slots: /** Test function 1 */ void test1() { QCOMPARE('a', 'a'); } /** Test function 2 */ void test2() { QVERIFY(10 != 11); } }; int main(int argc, char *argv[]) { // Simple test cases doesn't require a // Q[Core]Application instance. MyTest t; QTest::qExec(&t); } // The next line is only required if we have the // definition and implementation in the same file // as in this case. #include "qunittest.moc"The test above produces the following output when executed:
Config: Using QTest library 4.6.2, Qt 4.6.2 PASS : MyTest::initTestCase() PASS : MyTest::test1() PASS : MyTest::test2() PASS : MyTest::cleanupTestCase() Totals: 4 passed, 0 failed, 0 skippedQVERIFY evaluates the expression and continues the execution if the expression evaluates to true. If the expression evaluates to false a message is appended to the test log and the test function is stopped. QCOMPARE is similar to QVERIFY and gives a more verbose output. In addition to the test functions the framework will look for the following four functions (must also be declared as private slots):
- initTestCase() - Executed before any test function
- cleanupTestCase() - Executed after the last test function
- init() - Executed before each test function
- cleanup() - Executed after each test function
Data driven tests are used when you want to exercise some piece of code with different values and is supported by the Qt testlib. To feed test data to a test function add a function with the same name as the test function appended with a '_data' suffix. So if the test function is named testFeature, the function that serves the test with data should be named testFeature_data. The test data is setup in a table. Two functions are used to create this table, addColumn and newRow. addColumn is used to define elements in the table and newRow adds data. QFETCH is used to fetch data from the table.
Lets create a simple 'capitalize' function that takes a string, capitalizes the first character and returns the result as a new string. We want to test the function with different data such as an empty string, first character is lower case and first character is upper case.
#include <QtTest/QTest> class MyTest : public QObject { Q_OBJECT public: explicit MyTest(QObject *parent = 0) : QObject(parent) {} QString capitalize(const QString &text) { QString result = text; result[0] = text[0].toUpper(); return result; } private slots: void testCapitalize_data() { QTest::addColumnRunning the test gives the following output:("string"); QTest::addColumn ("expected"); QTest::newRow("empty string") << "" << ""; QTest::newRow("lower case") << "lower case" << "Lower case"; QTest::newRow("upper case") << "Upper case" << "Upper case"; } void testCapitalize() { QFETCH(QString, string); QFETCH(QString, expected); QCOMPARE(capitalize(string), expected); } }; // Macro that implements main QTEST_APPLESS_MAIN(MyTest); #include "qunittest.moc"
********* Start testing of MyTest ********* Config: Using QTest library 4.6.2, Qt 4.6.2 PASS : MyTest::initTestCase() QFATAL : MyTest::testCapitalize(empty string) ASSERT: "i >= 0 && i < size()" in file ../../../../opt/qtsdk-2010.02/qt/include/QtCore/qstring.h, line 690 FAIL! : MyTest::testCapitalize(empty string) Received a fatal error. Loc: [Unknown file(0)] Totals: 1 passed, 1 failed, 0 skipped ********* Finished testing of MyTest *********Oops, forgot to check if the string is empty. We fix that by adding the following check at the beginning of the capitalize function:
if (text.isEmpty()) { return text; }Running the test again:
********* Start testing of MyTest ********* Config: Using QTest library 4.6.2, Qt 4.6.2 PASS : MyTest::initTestCase() PASS : MyTest::testCapitalize() PASS : MyTest::cleanupTestCase() Totals: 3 passed, 0 failed, 0 skipped ********* Finished testing of MyTest *********Ok, this was a quick introduction to get you started. To find out more about the test lib read the manual, api docs, and the tutorial. You'll find examples on how to test your GUI by simulating mouse clicks, key presses and how to do simple benchmarking.
Friday, March 19, 2010
Ternary operation
I'm a big fan of using ternary operations when possible but Python didn't introduced them until the 2.5 release, see Wikipedia page. Before the 2.5 release there existed options like using the and and or operator
x and y or zor a lambda construction, but none if them are considered foolproof (see the wiki page for explanation). So how do you write the ternary operation in python?
a, b = 1, 2 # non ternary operation if a > b: z = a else: z = b # rewritten to z = a if a > b else bClean, readable and simple!
Saturday, February 20, 2010
QTabWidget - Hiding the bar
It has been a while since my last post. I've been sick, my son has been sick and so has my girlfriend. Now I'm back and have been coding on a private project for a couple of days.
While I was toying and trying some ideas I found out how to create tab bars with Qt that are only visible if you have more than one tab. This is quite popular in browser for example. So without further ado, here's the code:
You can use the following snippet to see the TabWidget in action:
While I was toying and trying some ideas I found out how to create tab bars with Qt that are only visible if you have more than one tab. This is quite popular in browser for example. So without further ado, here's the code:
from PyQt4 import QtGui class TabWidget(QtGui.QTabWidget): def __init__(self, parent=None): super (TabWidget, self).__init__(parent) self.setTabsClosable(True) self.tabCloseRequested.connect(self.removeTab) def tabInserted(self, index): self.tabBar().setVisible(self.count() > 1) def tabRemoved(self, index): self.tabBar().setVisible(self.count() > 1)As you can see, it isn't rocket science. I did some googling but couldn't find anything about it, that's why I want to share my findings. The magic is to only hide the TabBar associated with the TabWidget, not the TabWidget itself.
You can use the following snippet to see the TabWidget in action:
import sys from PyQt4 import QtGui class TabWidget(QtGui.QTabWidget): def __init__(self, parent=None): super (TabWidget, self).__init__(parent) self.setTabsClosable(True) self.tabCloseRequested.connect(self.removeTab) def tabInserted(self, index): self.tabBar().setVisible(self.count() > 1) def tabRemoved(self, index): self.tabBar().setVisible(self.count() > 1) qApp = QtGui.QApplication(sys.argv) tab = TabWidget() button = QtGui.QPushButton('Hello') @button.clicked.connect def clicked(): tab.addTab(QtGui.QLabel('Hello'), 'Hello') tab.addTab(button, 'Button') layout = QtGui.QHBoxLayout() layout.addWidget(tab) window = QtGui.QWidget() window.setLayout(layout) window.resize(600, 400) window.show() qApp.exec_()
Saturday, January 30, 2010
Named tuple
I recently read a post on planet python and the author mentioned something about named tuple which made my curious.
So what's a named tuple?
The namedtuple was introduced in Python 2.6. A named tuple is created using a factory function from the collections module and it extends the basic tuple by assigning a name to each position in a tuple but can still be used as a regular tuple. This makes it possible to access fields by name instead of an index. The named tuple should not require more memory, according to the documentation, than regular tuples since they don't have a per instance dictionary.
The factory function signature is:
Enough theory, I'll show you an example.
Example
Say you have a tuple containing username and password. To access the username you get the item at position zero and the password is accessed at position one:
If you are interested of what the code looks like for the newly created Credential-type you can add verbose=True to the argument list when creating the type, in this particular case we get the following output:
Comments
I think the named tuple is useful. They remove the error-prone indexing in tuples by providing access to fields by name without adding any memory overhead. They are also regular Python classes which means you can do anything you can do with classes.
So what's a named tuple?
The namedtuple was introduced in Python 2.6. A named tuple is created using a factory function from the collections module and it extends the basic tuple by assigning a name to each position in a tuple but can still be used as a regular tuple. This makes it possible to access fields by name instead of an index. The named tuple should not require more memory, according to the documentation, than regular tuples since they don't have a per instance dictionary.
The factory function signature is:
collections.namedtuple(typename, field_names[, verbose])The first argument specifies the name of the new type, the second argument is a string (space or comma separated) containing the field names and finally if verbose is true the factory function will also print the class generated.
Enough theory, I'll show you an example.
Example
Say you have a tuple containing username and password. To access the username you get the item at position zero and the password is accessed at position one:
credential = ('mario', 'secret') print 'Username:', credential[0] print 'Password:', credential[1]There's nothing wrong with this code but the tuple isn't self-documented. You have to find and read the documentation about the positioning of the fields in the tuple. This is where named tuple can enter the scene. We can rewrite the previous example as following:
import collections # Create a new sub-tuple named Credential Credential = collections.namedtuple('Credential', 'username, password') credential = Credential(username='mario', password='secret') print 'Username:', credential.username print 'Password:', credential.passwordNice, don't you agree?
If you are interested of what the code looks like for the newly created Credential-type you can add verbose=True to the argument list when creating the type, in this particular case we get the following output:
import collections Credential = collections.namedtuple('Credential', 'username, password', verbose=True) class Credential(tuple): 'Credential(username, password)' __slots__ = () _fields = ('username', 'password') def __new__(_cls, username, password): return _tuple.__new__(_cls, (username, password)) @classmethod def _make(cls, iterable, new=tuple.__new__, len=len): 'Make a new Credential object from a sequence or iterable' result = new(cls, iterable) if len(result) != 2: raise TypeError('Expected 2 arguments, got %d' % len(result)) return result def __repr__(self): return 'Credential(username=%r, password=%r)' % self def _asdict(t): 'Return a new dict which maps field names to their values' return {'username': t[0], 'password': t[1]} def _replace(_self, **kwds): 'Return a new Credential object replacing specified fields with new values' result = _self._make(map(kwds.pop, ('username', 'password'), _self)) if kwds: raise ValueError('Got unexpected field names: %r' % kwds.keys()) return result def __getnewargs__(self): return tuple(self) username = _property(_itemgetter(0)) password = _property(_itemgetter(1))The named tuple doesn't only provide access to fields by name but also contains helper functions such as the _make() function which helps creating an Credential instance from a sequence or iterable. For example:
cred_tuple = ('mario', 'secret') credential = Credential._make(cred_tuple)There are more interesting use-cases and examples in the documentation, so I suggest that you take a peek.
Comments
I think the named tuple is useful. They remove the error-prone indexing in tuples by providing access to fields by name without adding any memory overhead. They are also regular Python classes which means you can do anything you can do with classes.
Wednesday, January 20, 2010
More fun with QWebKit
In the previous post I wrote about calling python methods and accessing
properties from JavaScript executed in QWebKit. In this post I'll show
you how to do the other way around, calling a JavaScript function from
Python.
I would like to thank Rich Moore for commenting on the previous post and pointing out that you should re-add your python object every time the javaScriptWindowObjectCleared() signal is emitted.
Actually, I think this is almost to simple to do a post about so I'll try doing something fun/useful with it.
QWebFrame contains a public slot:
Maybe it's time to wipe the dust off my GMonitor-plasmoid and add support for opening my account in a new window based on the GMail widget above.
I would like to thank Rich Moore for commenting on the previous post and pointing out that you should re-add your python object every time the javaScriptWindowObjectCleared() signal is emitted.
Actually, I think this is almost to simple to do a post about so I'll try doing something fun/useful with it.
QWebFrame contains a public slot:
QVariant evaluateJavaScript(const QString & scriptSource)You simply pass the JavaScript-snippet to the function. The snippet will be evaluated using the frame as context and returns the result of the last executed statement. This makes it possible to 'click' submit buttons, fill form fields and other interesting stuff in the currently loaded frame. I'll give you an example on how you can create an auto-login GMail widget. The widget will automatically login the user by populating the login form with the user's credentials and 'click' the login button.
#!/usr/bin/env python from PyQt4 import QtCore from PyQt4 import QtGui from PyQt4 import QtWebKit javaScriptLogin = """ document.getElementsByName('Email').item(0).value='{email}'; document.getElementsByName('Passwd').item(0).value='{password}'; document.getElementsByName('signIn').item(0).click(); void(0); """ class GmailWebView(QtWebKit.QWebView): def __init__(self, parent=None): super(GmailWebView, self).__init__(parent) self.loggedIn = False def login(self, url, email, password): """Login to gmail.""" self.url = QtCore.QUrl(url) self.email = email self.password = password self.loadFinished.connect(self._loadFinished) self.load(self.url) def createWindow(self, windowType): """Load links in the same web-view.""" return self def _loadFinished(self): if self.loggedIn: self.loadFinished.disconnect(self._loadFinished) self.loggedIn = True jscript = javaScriptLogin.format(email=self.email, password=self.password) self.page().mainFrame().evaluateJavaScript(jscript) def contextMenuEvent(self, event): """Add a 'Back to GMail' entry.""" menu = self.page().createStandardContextMenu() menu.addSeparator() action = menu.addAction('Back to GMail') @action.triggered.connect def backToGMail(): self.load(self.url) menu.exec_(QtGui.QCursor.pos()) def main(): import sys qApp = QtGui.QApplication(sys.argv) # Prevents me from posting my password on the blog :) password, ok = QtGui.QInputDialog.getText(None, "Password request", "Enter password", QtGui.QLineEdit.Password) if not ok: return gmailWebView = GmailWebView() gmailWebView.login('https://mail.google.com/mail', 'mario.boikov', password) gmailWebView.show() sys.exit(qApp.exec_()) if __name__ == "__main__": main()
This is just a quick hack, it lacks a bunch of checkings...
Maybe it's time to wipe the dust off my GMonitor-plasmoid and add support for opening my account in a new window based on the GMail widget above.
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
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.
If you need to define your own signal you'll do something like this (off the top of my head):
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.
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.
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.
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.
Tuesday, January 5, 2010
Let's timeit!
Every now and then you might want to time snippets just to make sure that you choose the more efficient solution. In those cases you can use the timeit module to measure execution time for snippets.
Introduction
It's very easy to setup and measure the execution time for a snippet with timeit. The module contains a class, Timer, which is used to perform the measurement. The class has one constructor and three methods:
Example
Suppose that I would like to create a list containing 100 'c':s like this ['c', 'c', ...]. There are at least two ways of doing this:
The result returned is the total execution time in seconds. In this particular case when we are executing the snippet 1000000 times the result is also the execution time in microseconds for one single pass (1000000*exe_time/1000000 == exe_time).
Normally, the timeit module doesn't have access to things that you have defined in your module. If you would like to measure a function that you have defined in your module you can specify the import statement in the setup parameter:
I find the timeit module as a simple and convenient way to measure execution time for small snippets.
Introduction
It's very easy to setup and measure the execution time for a snippet with timeit. The module contains a class, Timer, which is used to perform the measurement. The class has one constructor and three methods:
- Timer([stmt='pass'[, setup='pass'[, timer=<timer function>]]]) - stmt is the statement to be timed and setup is called once before executing the main statement. A timer function can be specified and default is time.time() for all platforms but windows which is set to time.clock() instead (according to my timeit.py)
- timeit([number=1000000]) - Executes the main statement passed to the constructor number of times and returns the result in seconds as a float.
- repeat([repeat=3[, number=1000000]]) - Convenience function that calls timeit(number) repeat times. Returns a list with the results.
- print_exc([file=None]) - Helper to print a traceback from the timed snippet.
Example
Suppose that I would like to create a list containing 100 'c':s like this ['c', 'c', ...]. There are at least two ways of doing this:
lst = ['c'] * 100 # or lst = ['c' for i in xrange(100)]Which one should I choose? Well, let's execute both statements with timeit and measure the execution time.
>>> import timeit >>> t = timeit.Timer(stmt="lst = ['c'] * 100") >>> print t.timeit() 1.10580182076 >>> t = timeit.Timer(stmt="lst = ['c' for x in xrange(100)]") >>> print t.timeit() 7.66900897026Ok, I think I'll stick with the first snippet :)
The result returned is the total execution time in seconds. In this particular case when we are executing the snippet 1000000 times the result is also the execution time in microseconds for one single pass (1000000*exe_time/1000000 == exe_time).
Normally, the timeit module doesn't have access to things that you have defined in your module. If you would like to measure a function that you have defined in your module you can specify the import statement in the setup parameter:
>>> def create_lst(size): ... return ['c'] * size ... >>> t = timeit.Timer(stmt="create_lst(100)", setup="from __main__ import create_lst") >>> print t.timeit() 1.21339488029This will introduce a little overhead since the create_lst() function is called in the measurement loop instead of just executing an inlined snippet.
Note: Timer.timeit() will by default disable garbage collection during timing. To enable GC you can pass 'gc.enable()' as a setup statement.
I find the timeit module as a simple and convenient way to measure execution time for small snippets.
Subscribe to:
Posts (Atom)