-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathtut1.html
564 lines (450 loc) · 30.4 KB
/
tut1.html
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
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title>PyQt by Example</title>
<style type="text/css">
/*
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:Date: $Date: 2008/01/29 22:14:02 $
:Revision: $Revision: 1.1.1.1 $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em ;
text-align: center;
max-width: 90%;
}
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin-left: 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left {
clear: left }
img.align-right {
clear: right }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font-family: serif ;
font-size: 100% }
pre.literal-block, pre.doctest-block {
margin-left: 2em ;
margin-right: 2em ;
background-color: #eeeeee }
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
/*
tt.docutils {
background-color: #eeeeee }
*/
ul.auto-toc {
list-style-type: none }
/* diff2html style */
TD.linenum { color: #909090;
text-align: right;
vertical-align: top;
font-weight: bold;
border-right: 1px solid black;
border-left: 1px solid black; }
TD.added { background-color: #DDDDFF; }
TD.modified { background-color: #BBFFBB; }
TD.removed { background-color: #FFCCCC; }
TD.normal { background-color: #FFFFE1; }
</style>
</head>
<body>
<div class="document" id="pyqt-by-example">
<h1 class="title">PyQt by Example</h1>
<div class="section" id="introduction">
<h1>Introduction</h1>
<p>This series of tutorials is inspired by two things:</p>
<ul class="simple">
<li>LatinoWare 2008, where I presented this very app as an introduction to PyQt development.</li>
<li>A lack of (in my very humble opinion) PyQt tutorials that show the way I prefer to develop applications.</li>
</ul>
<p>The second item may sound a bit belligerent, but that's not the case. I am not saying the other tutorials are wrong, or bad, I just say they don't work the way I like to work.</p>
<p>I don't believe in teaching something and later saying "now I will shw you how it's really done". I don't believe in toy examples. I believe that you are smart enough to only learn things once, and learning the true thing the first time.</p>
<p>So, in this series, I will be developing a small TODO application using the tools and procedures I use in my actual development, except for the Eric IDE. That is because IDEs are personal preferences and for a project fo this scope really doesn't add much.</p>
<p>One other thing I will not add is unit testing. While very important, I think it would distract from actually <em>doing</em>. If that's a problem, it can be added in a later version of the tutorial.</p>
</div>
<div class="section" id="requirements">
<h1>Requirements</h1>
<p>You must have installed the following programs:</p>
<ul class="simple">
<li><a class="reference external" href="http://www.python.org">Python</a>: I am using 2.6, I expect 2.5 or even 2.4 will work, but I am not testing them.</li>
<li><a class="reference external" href="http://elixir.ematia.de">Elixir</a>: This is needed by the backend. It requires <a class="reference external" href="http://www.sqlalchemy.org">SQLAlchemy</a> and we will be using <a class="reference external" href="http://www.sqlite.org">SQLite</a> as our database. If you install <a class="reference external" href="http://elixir.ematia.de">Elixir</a> everything else should be installed automatically.</li>
<li><a class="reference external" href="http://www.riverbankcomputing.co.uk/software/pyqt/intro">PyQt</a>: I will be using version 4.4</li>
<li>Your text editor of choice</li>
</ul>
<p>This tutorial doesn't assume knowledge of Elixir, PyQt or databases, but does assume a working knowledge of Python. If you don't know python yet, this is not the right tutorial for you yet.</p>
<p>You can get the full code for this session here: <a class="reference external" href="http://github.com/ralsina/pyqt-by-example/tree/master/session1">Sources</a> (click the "Download" button).</p>
<p>Since this tutorial is completely hosted in <a class="reference external" href="http://www.github.org">GitHub</a> you are free to contribute improvements, modifications, even whole new sessions or features!</p>
</div>
<div class="section" id="session-1-the-basics">
<h1>Session 1: The basics</h1>
<div class="section" id="the-backend">
<h2>The backend</h2>
<p>The most recent version of this session (in RST format) is always available at GitHub's <a class="reference external" href="http://github.com/ralsina/pyqt-by-example/blob/master">master tree</a> as <a class="reference external" href="http://github.com/ralsina/pyqt-by-example/blob/master/tut1.txt">tut1.txt</a></p>
<p>Since we are developing a TODO application, we need a backend that handles the storage, retrieval and general managing of TODO tasks.</p>
<p>To do that the simplest possible way, I will do it using <a class="reference external" href="http://elixir.ematia.de">Elixir</a>, "A declarative layer over the SQLAlchemy Object-Relational Mapper".</p>
<p>If that sounded very scary, don't worry. What that means is "a way to create objects that are automatically stored in a database".</p>
<p>Here is the code, with comments, for our backend, called <a class="reference external" href="http://github.com/ralsina/pyqt-by-example/blob/master/session1/todo.py">todo.py</a>. Hopefully, we will not have to look at it again until much later in the tutorial!</p>
<div class="highlight"><pre><span style="color: #408080; font-style: italic"># -*- coding: utf-8 -*-</span>
<span style="color: #BA2121; font-style: italic">"""A simple backend for a TODO app, using Elixir"""</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">os</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">elixir</span> <span style="color: #008000; font-weight: bold">import</span> <span style="color: #666666">*</span>
dbdir<span style="color: #666666">=</span>os<span style="color: #666666">.</span>path<span style="color: #666666">.</span>join(os<span style="color: #666666">.</span>path<span style="color: #666666">.</span>expanduser(<span style="color: #BA2121">"~"</span>),<span style="color: #BA2121">".pyqtodo"</span>)
dbfile<span style="color: #666666">=</span>os<span style="color: #666666">.</span>path<span style="color: #666666">.</span>join(dbdir,<span style="color: #BA2121">"tasks.sqlite"</span>)
<span style="color: #408080; font-style: italic"># It's good policy to have your app use a hidden folder in</span>
<span style="color: #408080; font-style: italic"># the user's home to store its files. That way, you can</span>
<span style="color: #408080; font-style: italic"># always find them, and the user knows where everything is.</span>
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">Task</span>(Entity):
<span style="color: #BA2121; font-style: italic">"""</span>
<span style="color: #BA2121; font-style: italic"> A task for your TODO list.</span>
<span style="color: #BA2121; font-style: italic"> """</span>
<span style="color: #408080; font-style: italic"># By inheriting Entity, we are using Elixir to make this</span>
<span style="color: #408080; font-style: italic"># class persistent, Task objects can easily be stored in</span>
<span style="color: #408080; font-style: italic"># our database, and you can search for them, change them,</span>
<span style="color: #408080; font-style: italic"># delete them, etc.</span>
using_options(tablename<span style="color: #666666">=</span><span style="color: #BA2121">'tasks'</span>)
<span style="color: #408080; font-style: italic"># This specifies the table name we will use in the database,</span>
<span style="color: #408080; font-style: italic"># I think it's nicer than the automatic names Elixir uses.</span>
text <span style="color: #666666">=</span> Field(Unicode,required<span style="color: #666666">=</span><span style="color: #008000">True</span>)
date <span style="color: #666666">=</span> Field(DateTime,default<span style="color: #666666">=</span><span style="color: #008000">None</span>,required<span style="color: #666666">=</span><span style="color: #008000">False</span>)
done <span style="color: #666666">=</span> Field(Boolean,default<span style="color: #666666">=</span><span style="color: #008000">False</span>,required<span style="color: #666666">=</span><span style="color: #008000">True</span>)
tags <span style="color: #666666">=</span> ManyToMany(<span style="color: #BA2121">"Tag"</span>)
<span style="color: #408080; font-style: italic"># A task has the following:</span>
<span style="color: #408080; font-style: italic">#</span>
<span style="color: #408080; font-style: italic"># * A text ("Buy groceries"). Always try to use unicode</span>
<span style="color: #408080; font-style: italic"># in your app. Using anything else is *not worth</span>
<span style="color: #408080; font-style: italic"># the trouble*.</span>
<span style="color: #408080; font-style: italic">#</span>
<span style="color: #408080; font-style: italic"># * A date for when it's due.</span>
<span style="color: #408080; font-style: italic">#</span>
<span style="color: #408080; font-style: italic"># * A "Done" field. Is it done?</span>
<span style="color: #408080; font-style: italic">#</span>
<span style="color: #408080; font-style: italic"># * A list of tags. For example, "Buy groceries" could be</span>
<span style="color: #408080; font-style: italic"># tagged "Home" and "Important". It's ManyToMany because</span>
<span style="color: #408080; font-style: italic"># a task can have many tags and a tag can have many tasks.</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">__repr__</span>(<span style="color: #008000">self</span>):
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #BA2121">"Task: "</span><span style="color: #666666">+</span><span style="color: #008000">self</span><span style="color: #666666">.</span>text
<span style="color: #408080; font-style: italic"># It's always nicer if objects know how to turn themselves</span>
<span style="color: #408080; font-style: italic"># into strings. That way you can help debug your program</span>
<span style="color: #408080; font-style: italic"># just by printing them. Here, our groceries task would</span>
<span style="color: #408080; font-style: italic"># print as "Task: Buy groceries".</span>
<span style="color: #408080; font-style: italic"># Since earlier I mentioned Tags, we need to define them too:</span>
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">Tag</span>(Entity):
<span style="color: #BA2121; font-style: italic">"""</span>
<span style="color: #BA2121; font-style: italic"> A tag we can apply to a task.</span>
<span style="color: #BA2121; font-style: italic"> """</span>
<span style="color: #408080; font-style: italic"># Again, they go in the database, so they are an Entity.</span>
using_options(tablename<span style="color: #666666">=</span><span style="color: #BA2121">'tags'</span>)
name <span style="color: #666666">=</span> Field(Unicode,required<span style="color: #666666">=</span><span style="color: #008000">True</span>)
tasks <span style="color: #666666">=</span> ManyToMany(<span style="color: #BA2121">"Task"</span>)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">__repr__</span>(<span style="color: #008000">self</span>):
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #BA2121">"Tag: "</span><span style="color: #666666">+</span><span style="color: #008000">self</span><span style="color: #666666">.</span>name
<span style="color: #408080; font-style: italic"># They are much simpler objects: they have a name,</span>
<span style="color: #408080; font-style: italic"># a list of tagged tasks, and can convert themselves</span>
<span style="color: #408080; font-style: italic"># to strings.</span>
saveData<span style="color: #666666">=</span><span style="color: #008000">None</span>
<span style="color: #408080; font-style: italic"># Using a database involves a few chores. I put them</span>
<span style="color: #408080; font-style: italic"># in the initDB function. Just remember to call it before</span>
<span style="color: #408080; font-style: italic"># trying to use Tasks or Tags!</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">initDB</span>():
<span style="color: #408080; font-style: italic"># Make sure ~/.pyqtodo exists</span>
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #AA22FF; font-weight: bold">not</span> os<span style="color: #666666">.</span>path<span style="color: #666666">.</span>isdir(dbdir):
os<span style="color: #666666">.</span>mkdir(dbdir)
<span style="color: #408080; font-style: italic"># Set up the Elixir internal thingamajigs</span>
metadata<span style="color: #666666">.</span>bind <span style="color: #666666">=</span> <span style="color: #BA2121">"sqlite:///</span><span style="color: #BB6688; font-weight: bold">%s</span><span style="color: #BA2121">"</span><span style="color: #666666">%</span>dbfile
setup_all()
<span style="color: #408080; font-style: italic"># And if the database doesn't exist: create it.</span>
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #AA22FF; font-weight: bold">not</span> os<span style="color: #666666">.</span>path<span style="color: #666666">.</span>exists(dbfile):
create_all()
<span style="color: #408080; font-style: italic"># This is so Elixir 0.5.x and 0.6.x work</span>
<span style="color: #408080; font-style: italic"># Yes, it's kinda ugly, but needed for Debian</span>
<span style="color: #408080; font-style: italic"># and Ubuntu and other distros.</span>
<span style="color: #008000; font-weight: bold">global</span> saveData
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">elixir</span>
<span style="color: #008000; font-weight: bold">if</span> elixir<span style="color: #666666">.</span>__version__ <span style="color: #666666"><</span> <span style="color: #BA2121">"0.6"</span>:
saveData<span style="color: #666666">=</span>session<span style="color: #666666">.</span>flush
<span style="color: #008000; font-weight: bold">else</span>:
saveData<span style="color: #666666">=</span>session<span style="color: #666666">.</span>commit
<span style="color: #408080; font-style: italic"># Usually, I add a main() function to all modules that</span>
<span style="color: #408080; font-style: italic"># does something useful, perhaps run unit tests. In this</span>
<span style="color: #408080; font-style: italic"># case, it demonstrates our backend's functionality.</span>
<span style="color: #408080; font-style: italic"># You can try it by running it like this::</span>
<span style="color: #408080; font-style: italic">#</span>
<span style="color: #408080; font-style: italic"># python todo.py</span>
<span style="color: #408080; font-style: italic"># No detailed comments in this one: study it yourself, it's not complicated!</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">main</span>():
<span style="color: #408080; font-style: italic"># Initialize database</span>
initDB()
<span style="color: #408080; font-style: italic"># Create two tags</span>
green<span style="color: #666666">=</span>Tag(name<span style="color: #666666">=</span><span style="color: #BA2121">u"green"</span>)
red<span style="color: #666666">=</span>Tag(name<span style="color: #666666">=</span><span style="color: #BA2121">u"red"</span>)
<span style="color: #408080; font-style: italic">#Create a few tags and tag them</span>
tarea1<span style="color: #666666">=</span>Task(text<span style="color: #666666">=</span><span style="color: #BA2121">u"Buy tomatos"</span>,tags<span style="color: #666666">=</span>[red])
tarea2<span style="color: #666666">=</span>Task(text<span style="color: #666666">=</span><span style="color: #BA2121">u"Buy chili"</span>,tags<span style="color: #666666">=</span>[red])
tarea3<span style="color: #666666">=</span>Task(text<span style="color: #666666">=</span><span style="color: #BA2121">u"Buy lettuce"</span>,tags<span style="color: #666666">=</span>[green])
tarea4<span style="color: #666666">=</span>Task(text<span style="color: #666666">=</span><span style="color: #BA2121">u"Buy strawberries"</span>,tags<span style="color: #666666">=</span>[red,green])
saveData()
<span style="color: #008000; font-weight: bold">print</span> <span style="color: #BA2121">"Green Tasks:"</span>
<span style="color: #008000; font-weight: bold">print</span> green<span style="color: #666666">.</span>tasks
<span style="color: #008000; font-weight: bold">print</span>
<span style="color: #008000; font-weight: bold">print</span> <span style="color: #BA2121">"Red Tasks:"</span>
<span style="color: #008000; font-weight: bold">print</span> red<span style="color: #666666">.</span>tasks
<span style="color: #008000; font-weight: bold">print</span>
<span style="color: #008000; font-weight: bold">print</span> <span style="color: #BA2121">"Tasks with l:"</span>
<span style="color: #008000; font-weight: bold">print</span> [(t<span style="color: #666666">.</span>id,t<span style="color: #666666">.</span>text,t<span style="color: #666666">.</span>done) <span style="color: #008000; font-weight: bold">for</span> t <span style="color: #AA22FF; font-weight: bold">in</span> Task<span style="color: #666666">.</span>query<span style="color: #666666">.</span>filter(Task<span style="color: #666666">.</span>text<span style="color: #666666">.</span>like(<span style="color: #BA2121">ur'</span><span style="color: #BB6688; font-weight: bold">%l%</span><span style="color: #BA2121">'</span>))<span style="color: #666666">.</span>all()]
<span style="color: #008000; font-weight: bold">if</span> __name__ <span style="color: #666666">==</span> <span style="color: #BA2121">"__main__"</span>:
main()
</pre></div>
</div>
<div class="section" id="the-main-window">
<h2>The Main Window</h2>
<p>Now, let's start with the fun part: <a class="reference external" href="http://www.riverbankcomputing.co.uk/software/pyqt/intro">PyQt</a>!</p>
<p>I recommend using designer to create your graphical interfaces. Yes, some people complain about interface designers. I say you should spend your time writing code for the parts where there are no good tools instead.</p>
<p>And here is the Qt Designer file for it: <a class="reference external" href="http://github.com/ralsina/pyqt-by-example/blob/master/session1/window.ui">window.ui</a>. Don't worry about all that XML, just open it on your designer ;-)</p>
<p>This is how it looks in designer:</p>
<div class="figure">
<img alt="window2.png" src="window2.png" />
<p class="caption">The main window, in designer.</p>
</div>
<p>What you see is a "Main Window". This kind of window lets you have a menu, toolbars, status bars, and is the typical window for a standard application.</p>
<p>The "Type Here" at the top is because the menu is still empty, and it's "inviting" you to add something to it.</p>
<p>The big square thing with "Task" "Date" and "Tags" is a widget called QTreeView, which is handy to display items with icons, several columns, and maybe a hierarchical structure (A tree, thus the name). We will use it to display our task list.</p>
<p>You can see how this window looks by using "Form" -> "Preview" in designer. THis is what you'll get:</p>
<div class="figure">
<img alt="window1.png" src="window1.png" />
<p class="caption">The main window preview, showing the task list.</p>
</div>
<p>You can try resizing the window, and this widget will use all available space and resize alongside the window. That's important: windows that can't handle resizing properly look unprofessional and are not adequate.</p>
<p>In Qt, this is done using layouts. In this particular case, since we have only one widget, what we do is click on the form's background and select "Layout" -> "Layout Horizontally" (Vertically would have had the exact same effect here).</p>
<p>When we do a configuration dialog, we will learn more about layouts.</p>
<p>Now, feel free to play with designer and this form. You could try changing the layout, add new things, change properties of the widgets, experiment at will, learning designer is worth the effort!</p>
</div>
<div class="section" id="using-our-main-window">
<h2>Using our Main Window</h2>
<p>We are now going to make this window we created part of a real program, so we can then start making it work.</p>
<p>First we need to compile our .ui file into python code. You can do this with this command:</p>
<pre class="literal-block">
pyuic4 window.ui -o windowUi.py
</pre>
<p>Now let's look at <a class="reference external" href="http://github.com/ralsina/pyqt-by-example/blob/master/session1/main.py">main.py</a>, our application's main file:</p>
<div class="highlight"><pre><span style="color: #408080; font-style: italic"># -*- coding: utf-8 -*-</span>
<span style="color: #BA2121; font-style: italic">"""The user interface for our app"""</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">os</span><span style="color: #666666">,</span><span style="color: #0000FF; font-weight: bold">sys</span>
<span style="color: #408080; font-style: italic"># Import Qt modules</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">PyQt4</span> <span style="color: #008000; font-weight: bold">import</span> QtCore,QtGui
<span style="color: #408080; font-style: italic"># Import the compiled UI module</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">windowUi</span> <span style="color: #008000; font-weight: bold">import</span> Ui_MainWindow
<span style="color: #408080; font-style: italic"># Create a class for our main window</span>
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">Main</span>(QtGui<span style="color: #666666">.</span>QMainWindow):
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">__init__</span>(<span style="color: #008000">self</span>):
QtGui<span style="color: #666666">.</span>QMainWindow<span style="color: #666666">.</span>__init__(<span style="color: #008000">self</span>)
<span style="color: #408080; font-style: italic"># This is always the same</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>ui<span style="color: #666666">=</span>Ui_MainWindow()
<span style="color: #008000">self</span><span style="color: #666666">.</span>ui<span style="color: #666666">.</span>setupUi(<span style="color: #008000">self</span>)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">main</span>():
<span style="color: #408080; font-style: italic"># Again, this is boilerplate, it's going to be the same on</span>
<span style="color: #408080; font-style: italic"># almost every app you write</span>
app <span style="color: #666666">=</span> QtGui<span style="color: #666666">.</span>QApplication(sys<span style="color: #666666">.</span>argv)
window<span style="color: #666666">=</span>Main()
window<span style="color: #666666">.</span>show()
<span style="color: #408080; font-style: italic"># It's exec_ because exec is a reserved word in Python</span>
sys<span style="color: #666666">.</span>exit(app<span style="color: #666666">.</span>exec_())
<span style="color: #008000; font-weight: bold">if</span> __name__ <span style="color: #666666">==</span> <span style="color: #BA2121">"__main__"</span>:
main()
</pre></div>
<p>As you can see, this is not at all specific to our TODO application. Whatever was in that .ui file would work just fine with this!</p>
<p>The only interesting part is the Main class. That class uses the compiled ui file and is where we will put our application's user interface logic. You <strong>never</strong> edit the .ui file or the generated python file manually!</p>
<p>Let me put that in these terms: <strong>IF YOU EDIT THE UI FILE (WITHOUT USING DESIGNER) OR THE GENERATED PYTHON FILE YOU ARE DOING IT WRONG! YOU FAIL! EPIC FAIL!</strong>. I hope that got across, because there is at least one tutorial that tells you to do it. <strong>DON'T DO IT!!!</strong>,</p>
<p>You just put your code in this class and you will be fine.</p>
<p>So, if you run main.py, you will make the application run. It will do nothing interesting, because we need to attach the backend to our user interface, but that's session 2.</p>
</div>
</div>
</div>
</body>
</html>