Skip to content
This repository


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 46ebe52970
Fetching contributors…


Cannot retrieve contributors at this time

file 281 lines (153 sloc) 10.647 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
PyQt By Example: Session 3

Designer is a Good Resource


If you have not done it yet, please check the previous sessions:
* `Session 1`_

* `Session 2`_

All files for this session are here: `Session 3 at GitHub`_

.. _Session 3 at GitHub:

Designer is a Good Resource

Today we are going to make our application look better, and introduce some new things, like resource files.

When we finished Session 2, our main window looked like this:
.. figure:: window3.png

   Not a good looking application.
There are several things wrong with that picture. Let's tackle them one at a time, using Qt Designer.

Window Title

.. figure:: wrong1.png

   It is a MainWindow, but it's not called MainWindow!
That's just wrong. While I have not yet chosen a name for this example application, it's silly to have the window title (and taskbar entry!) say "MainWindow"!

Here's how you change objet properties in Designer.

First, you select the object you want to modify. You can do that by clicking on it, or by selecting it
from the Object Inspector. For some widgets one or the other is easier. For example, it may be hard to find empty space in a window to click and select the window itself, or click in a very small widget, like a separator. In those cases, just use the Inspector.

Once you have the right object selected, look at the Property Editor.

There is a list of properties (obvious ;-) separated by titles like "QObject" or "QWidget". Don't worry about those titles much, just look for what you need, (it often is pretty obvious!).

In our case it's the windowTitle property.

.. figure:: windowtitle.png

I will not be writing these detailed explanations and pictures for each property. I trust you can find them if I tell you "The windowTitle property of the MainWindow Object".

Let's change that to "Todo".

Application Icon

.. figure:: wrong2.png

   Generic icon.
The window icon is the default generic icon. This is important because it appears in the taskbar along the window title, and if you are using it in some operating systems or configurations, the user may **only** see the icon!

Finding icons to use in your applications is a big problem. There are several things you can do:
1. Hire a graphics designer to do icons for you.

   This, of course, is rather expensive, specially if you are a hobbyist.
2. Search the web and see what you can find.

   For example, if I look for "todo icon" in google, I find many, some really nice. However, many of those are subject to copyright, so it's a better idea to look for them in places like `wikimedia commons`_:
   .. image::
   Or maybe `Open Clipart`_:
   .. image::
   But my point is: those two icons are not all that awesome, and searching for a nice one is going to take a while. If you will need 10 or 15 icons in your application, the problem is even worse, because you want the icons to be consistant!
3. Find a set of KDE (or maybe GNOME) icons you like, and steal consistently. This is my preferred solution.

   I prefer KDE icons because I use a KDE desktop but there's no reason to avoid GNOME icon themes.
   You can find KDE icons in kde-look.org_ and GNOME icons at gnome-look.org_
   An added perk is that all KDE (or GNOME) icon themes have consistent internal names. That way you can later on switch to another theme very easy.
Then there is the icons file format. If the icon theme you like is available in SVG format, that's good. SVG is scalable, which means the icons will look good at all sizes without the need to include multiple copies in different sizes.

In this tutorial I will use icons from the Reinhardt_ set. Why? I like them, and the style is simple enough that I feel I can hack a fitting icon using Inkscape_ if needed (as I did in this case, see below).
This is how the folder icon from Reinhardt_ looks at different sizes, compared with Snowish_, a PNG icon theme:

.. figure:: compsize.png

    The Reinhardt SVG folder icon: nice at all sizes.
    The Snowish PNG folder icon: from lovely to blobly.

So, in short: choose an icon theme you like, and use only icons from that theme, if possible.

For this app's icon, I made this out of a piece of "mark_as_ham.svg" and some green colour:
.. figure:: todo_icon.png
   todo.svg: Not the prettiest icon ever, but will do for a tutorial example!
So, after all this icon talk, how do we use it? Well... that needs yet more talk, because there are two ways: use icon files and use a resource file.

* Icon files:
  In Designer, go to the windowIcon property of MainWindow. Click on the down arrow. Select "Choose File".
  The bad news: doing this makes packaging and distribution a bit harder later on.
  The worse news: this will not work with a SVG icon. So forget about it.
* Resource file:
  In Designer, go to the windowIcon property of MainWindow. Click on the down arrow. Select "Choose Resource". You will see a rather empty window.
.. figure:: resource1.png

   The empty resource window
A resource file is a XML file that contains references to all the icons you want to use. Later, this is compiled to a python module, which you can use from your application. As long as that python module is distributed along with the others, you will be fine, so there is never a problem of not finding an icon, or worrying about where they are installed. Things will *just work*. So it's worth a bit of effort getting this right.

Here's how I do it:
1. Click on the pencil button in the top right to get to the "Edit Resources" window.

   .. figure:: resource2.png

      The empty resource editor window

2. Click on the "New Resource File" button in the bottom-left. Call it "icons" (or whatever you want)

3. Click in the "Add prefix" button (fourth from the left). I called my prefix "/"

4. Click in the "Add files" button (fifth from the left). Add todo.svg (finally!), click OK.

Steps 1, 2 and 3 are only needed the first time you use an icon. To add the icons we will use later it's just step 4.

So now your resource window looks like this:
.. figure:: resource3.png

   There is an icon here!

Choose it, and that's it, the window has the right icon! Well ... not really.

First compile the UI. Remember we need to do this whenever we change something using designer!

    $ pyuic4 window.ui -o
Then run the program::
    $ python
    Traceback (most recent call last):
    File "", line 11, in <module>
        from windowUi import Ui_MainWindow
    File "/home/ralsina/Desktop/proyectos/pytut/session3/", line 41, in <module>
        import icons_rc
    ImportError: No module named icons_rc
This is because you also need to compile the `icons.qrc`_ file we created. This is done using ``pyrcc4``::
    $ pyrcc4 icons.qrc -o
And the icon works now :-)

.. figure:: window4.png

   The longest explanation ever on how to change an icon, but it worked!
Since it's boring having to remember to run ``pyuic4`` and ``pyrcc4``, I wrote a trivial script to handle it, build.sh_. If you are in windows, a similar BAT file is trivial.

Luckily, the next two UI fixes are much simpler!

Tree Decorations

At the left of our task list there is a tree decoration. Since this is not meant to be a tree, they are just a waste of space. They can be removed with the rootIsDecorated property of the list widget.

.. figure:: wrong3.png

   This is really a list, not a tree.

Wide Margins

I think the default margins here (4 pixels) look old fashioned. I prefer 0 pixels. YMMV.

.. figure:: wrong4.png

   Personal taste: too wide.

You can change them in the layout[something]Margin properties of centralWidget.
Extra Fixes

I also prefer to set these in our QTreeWidget:
* allColumnsShowFocus True

* uniformRowHeights True (better performance for long lists)
* sortingEnabled True

* alternatingRowColors True

See the docs_ to see what they do!

.. _docs:


So, after running, this is how the app looks now:
.. figure:: window5.png

   A cleaner look.

Coming Soon

In this session, we did no coding at all, we just worked on designer and graphical details. This may not seem too important to you, if you are a hardcore coder, but trust me: it is. Making apps as pleasant to
use and look at as you can within your possibilities is very important if you want the first release to make any kind of impact. I learned it the hard way by releasing ugly apps ;-)

It doesn't matter if your graphical design skills are limited, like mine, try not to overreach and do your best.

In session 4 we will dive into coding, and make this app functional for the first time, introducing one of the neatest features in Qt: Actions.

Further Reading

* `First Principles of Interaction Design`_

* `User Interface`_ in Wikipedia

* `Beautiful versus functional`_

.. _First Principles of Interaction Design:

.. _User interface:

.. _The Apple HIG:

.. _Beautiful versus functional:

.. _icons.qrc:
.. _Inkscape:

.. _Reinhardt:

.. _snowish:

.. _Session 1:

.. _Session 2:

.. _wikimedia commons:

.. _Open Clipart:
Something went wrong with that request. Please try again.