You are on page 1of 217

See discussions, stats, and author profiles for this publication at: https://www.researchgate.

net/publication/234788146

C++ GUI Programming with Qt 4, Second Edition

Article · February 2015

CITATIONS READS

26 3,398

2 authors, including:

Jasmin Christian Blanchette


Vrije Universiteit Amsterdam
79 PUBLICATIONS   1,068 CITATIONS   

SEE PROFILE

Some of the authors of this publication are also working on these related projects:

Property-Based Testing View project

All content following this page was uploaded by Jasmin Christian Blanchette on 04 May 2014.

The user has requested enhancement of the downloaded file.


INDEX

Copyright
Foreword
Preface
- Acknowledgments
C++ GUI Programming with Qt 4 A Brief History of Qt
By Jasmin Blanchette, Mark Summerfield
Part 1: Basic Qt
!"#$%&'()* !"#$%&"'()** Chapter 1. Getting Started
!"#+,-.(* +,#"'-./'-001
!)%/.+0123456* 02.32.45-6726 Hello Qt
!)%/.+0123457* 754202.32.45-6723 Making Connections
!-8(&* 810
Laying Out Widgets
Using the Reference Documentation
Overview Chapter 2. Creating Dialogs
Subclassing QDialog
9:"';#*<';==%&%)*'>"?$2 !)&$%&"'@,%A"'$B'C$'6D.' !BE!)FF%#E
Signals and Slots in Depth
Rapid Dialog Design
9&%/8+:);$$.(<'=&+>.+?;"+<-/+#"%$@+%/@"&.)%-$4&.)(/8.'+ABB+-CC$%<-.%;/&+.'-.+)"/+/-.%D($?+;/
Shape-Changing Dialogs
E%/@;F&G+H%/"IJ9/%IG+K-<+L1+MG+-/@+(N#(@@(@+H%/"I44F%.';".+N-O%/8+&;")<(+<;@(+<'-/8(& +E%.'
.'%&+#;;O+:);$$.(<'+%/&%@()&+'-D(+F)%..(/+-+&.-).4.;4P%/%&'+8"%@(+.;+8(..%/8+8)(-.+)(&"$.&+F%.'+.'(+N;&. Dynamic Dialogs
C;F()P"$+D()&%;/+;P+>.+(D()+<)(-.(@*+>.+Q 5 Built-in Widget and Dialog Classes
Chapter 3. Creating Main Windows
9&%/8 !!"#$%"&'()'*++,-)".,/0"1/"2+?;"=$$+@%&<;D()+.'(+N;&.+(PP(<.%D(+>.+Q+C);8)-NN%/8 Subclassing QMainWindow
C-..()/&+-/@+.(<'/%R"(&+-&+?;"+N-&.()+O(?+.(<'/;$;8%(&+)-/8%/8+P);N+>.=&+N;@($JD%(F+-)<'%.(<.")( Creating Menus and Toolbars
.;+>.=&+C;F()P"$+/(F+S,+C-%/.+(/8%/( +:'(+-".';)&+C);D%@(+)(-@()&+F%.'+"/C-)-$$($(@+%/&%8'.+%/.;+>.=& Setting Up the Status Bar
(D(/.+N;@($+-/@+$-?;".+&?&.(N +:'(/G+"&%/8+)(-$%&.%<+(I-NC$(&G+.'(?+%/.);@"<(+&"C()%;)+.(<'/%R"(& Implementing the File Menu
P;)+(D()?.'%/8+P);N+#-&%<+T90+@(D($;CN(/.+.;+-@D-/<(@+@-.-#-&(+-/@+MKH+%/.(8)-.%;/ Using Dialogs
Storing Settings
• 0/<$"@(&+/(F+<'-C.()&+;/+>.+Q=&+N;@($JD%(F+-)<'%.(<.")(+-/@+>.=&+/(F+C$"8%/+&"CC;).G+-$;/8
Multiple Documents
F%.'+-+#)%(P+%/.);@"<.%;/+.;+>.;C%-+(N#(@@(@+C);8)-NN%/8
Splash Screens
Chapter 4. Implementing Application Functionality
• A;D()&+-$$+>.+P"/@-N(/.-$&G+P);N+@%-$;8&+-/@+F%/@;F&+.;+%NC$(N(/.%/8+-CC$%<-.%;/
The Central Widget
P"/<.%;/-$%.?
Subclassing QTableWidget
• 0/.);@"<(&+#(&.+C)-<.%<(&+P;)+$-?;".+N-/-8(N(/.+-/@+(D(/.+C);<(&&%/8 Loading and Saving
Implementing the Edit Menu
• 1';F&+';F+.;+N-O(+.'(+N;&.+;P+>.+Q=&+/(F+U!0&G+%/<$"@%/8+.'(+C;F()P"$+/(F+S,+C-%/.+(/8%/( Implementing the Other Menus
-/@+.'(+/(F+(-&?4.;4"&(+<;/.-%/()+<$-&&(& Subclassing QTableWidgetItem
Chapter 5. Creating Custom Widgets
• A;/.-%/&+<;NC$(.($?+"C@-.(@+N-.()%-$+%/+(D()?+<'-C.() Customizing Qt Widgets
Subclassing QWidget
• !)(&(/.&+-@D-/<(@+>.+Q+.(<'/%R"(&+<;D()(@+%/+/;+;.'()+#;;OG+P);N+<)(-.%/8+#;.'+>.+-/@ Integrating Custom Widgets with Qt Designer
-CC$%<-.%;/ C$"8%/&+.;+%/.()P-<%/8+F%.'+/-.%D(+U!0& Double Buffering
Part II: Intermediate Qt
• A;/.-%/&+-/+%/4@(C.'+-CC(/@%I+;/+ABBJ>.+C);8)-NN%/8+P;)+(IC()%(/<(@+V-D-+@(D($;C()& Chapter 6. Layout Management
Laying Out Widgets on a Form
:'(+-<<;NC-/?%/8+A,4WLK+%/<$"@(&+.'(+;C(/+&;")<(+(@%.%;/+;P+>.+Q 5 5+P;)+E%/@;F&G+K-<G+H%/"IG Stacked Layouts
-/@+N-/?+9/%I(&G+-&+F($$+-&+K%/TEG+-+&(.+;P+P)(($?+-D-%$-#$(+@(D($;CN(/.+.;;$&+.'-.+<-/+#(+"&(@+.; Splitters
#"%$@+>.+-CC$%<-.%;/&+;/+E%/@;F&G+-/@+-$&;+.'(+&;")<(+<;@(+P;)+.'(+#;;O=&+(I-NC$(&
Scrolling Areas
Dock Widgets and Toolbars
Multiple Document Interface
Chapter 7. Event Processing
Reimplementing Event Handlers
Installing Event Filters
Staying Responsive During Intensive Processing
Chapter 8. 2D and 3D Graphics
Painting with QPainter
Painter Transformations
High-Quality Rendering with QImage Interfacing with Native APIs
Printing Using ActiveX on Windows
Graphics with OpenGL Handling X11 Session Management
Chapter 9. Drag and Drop Chapter 21. Embedded Programming
Enabling Drag and Drop Getting Started with Qtopia
Supporting Custom Drag Types Customizing Qtopia Core
Clipboard Handling Appendix A. Installing Qt
Chapter 10. Item View Classes A Note on Licensing
Using the Item View Convenience Classes Installing Qt/Windows
Using Predefined Models Installing Qt/Mac
Implementing Custom Models Installing Qt/X11
Implementing Custom Delegates Appendix B. Introduction to C++ for Java and C# Programmers
Chapter 11. Container Classes Getting Started with C++
Sequential Containers Main Language Differences
Associative Containers The Standard C++ Library
Generic Algorithms About the Authors
Strings, Byte Arrays, and Variants Production
Chapter 12. Input/Output Index
Reading and Writing Binary Data
Reading and Writing Text
Traversing Directories
Embedding Resources
Inter-Process Communication
Chapter 13. Databases
Connecting and Querying
Presenting Data in Tabular Form
Implementing MasterDetail Forms
Chapter 14. Networking
Writing FTP Clients
Writing HTTP Clients
Writing TCP ClientServer Applications
Sending and Receiving UDP Datagrams
Chapter 15. XML
Reading XML with SAX
Reading XML with DOM
Writing XML
Chapter 16. Providing Online Help
Tooltips, Status Tips, and "What's This?" Help
Using QTextBrowser as a Simple Help Engine
Using Qt Assistant for Powerful Online Help
Part III: Advanced Qt
Chapter 17. Internationalization
Working with Unicode
Making Applications Translation-Aware
Dynamic Language Switching
Translating Applications
Chapter 18. Multithreading
Creating Threads
Synchronizing Threads
Communicating with the Main Thread
Using Qt's Classes in Secondary Threads
Chapter 19. Creating Plugins
Extending Qt with Plugins
Making Applications Plugin-Aware
Writing Application Plugins
Chapter 20. Platform-Specific Features
Copyright Foreword
K-/?+;P+.'(+@(&%8/-.%;/&+"&(@+#?+N-/"P-<.")()&+-/@+&($$()&+.;+@%&.%/8"%&'+.'(%)+C);@"<.&+-)(+<$-%N(@ E'?+>.e+E'?+@;+C);8)-NN()&+$%O(+"&+<';;&(+>.e+1")(G+.'()(+-)(+.'(+;#D%;"&+-/&F()&*+>.=&+&%/8$(4
-&+.)-@(N-)O& +E'()(+.';&(+@(&%8/-.%;/&+-CC(-)+%/+.'%&+#;;OG+-/@+.'(+C"#$%&'()+F-&+-F-)(+;P+- &;")<(+<;NC-.%#%$%.?G+%.&+P(-.")(+)%<'/(&&G+%.&+ABB+C()P;)N-/<(G+.'(+-D-%$-#%$%.?+;P+.'(+&;")<(+<;@(G
.)-@(N-)O+<$-%NG+.'(+@(&%8/-.%;/&+'-D(+#((/+C)%/.(@+F%.'+%/%.%-$+<-C%.-$+$(..()&+;)+%/+-$$+<-C%.-$& %.&+@;<"N(/.-.%;/G+.'(+'%8'4R"-$%.?+.(<'/%<-$+&"CC;).G+-/@+-$$+.'(+;.'()+%.(N&+N(/.%;/(@+%/
:);$$.(<'=&+8$;&&?+N-)O(.%/8+N-.()%-$& +:'%&+%&+-$$+D()?+F($$G+#".+%.+N%&&(&+.'(+N;&.+%NC;).-/.+C;%/.*
:'(+-".';)&+-/@+C"#$%&'()+'-D(+.-O(/+<-)(+%/+.'(+C)(C-)-.%;/+;P+.'%&+#;;OG+#".+N-O(+/;+(IC)(&&(@ >.+%&+&"<<(&&P"$+#(<-"&(+C);8)-NN()& 9,>7+%.
;)+%NC$%(@+F-))-/.?+;P+-/?+O%/@+-/@+-&&"N(+/;+)(&C;/&%#%$%.?+P;)+());)&+;)+;N%&&%;/& +3;+$%-#%$%.?+%&
-&&"N(@+P;)+%/<%@(/.-$+;)+<;/&(R"(/.%-$+@-N-8(&+%/+<;//(<.%;/+F%.'+;)+-)%&%/8+;".+;P+.'(+"&(+;P+.'( f;F+<;N(+C);8)-NN()&+$%O(+;/(+.(<'/;$;8?G+#".+@%&$%O(+-/;.'()e+!()&;/-$$?+0+#($%(D(+&;P.F-)(
%/P;)N-.%;/+;)+C);8)-N&+<;/.-%/(@+'()(%/ (/8%/(()&+(/c;?+.(<'/;$;8?+.'-.+P(($&+)%8'.G+#".+@%&$%O(+(D()?.'%/8+.'-.+@;(&/=. +gX(($&+)%8'.g+N(-/&
N-/?+.'%/8& +0/+.'(+>.+7+(@%.%;/+;P+.'(+#;;OG+0+N(/.%;/(@+:);$$.(<'=&+C';/(+&?&.(N+-&+-+C-).%<"$-)$?
:'(+C"#$%&'()+;PP()&+(I<($$(/.+@%&<;"/.&+;/+.'%&+#;;O+F'(/+;)@()(@+%/+R"-/.%.?+P;)+#"$O+C")<'-&(&+;) 8;;@+(I-NC$(+;P+&;N(+C-).%<"$-)$?+#-@+.(<'/;$;8? +:'(+C';/(+&?&.(N+@%@/=.+P(($+)%8'.G+#(<-"&(+%.
&C(<%-$+&-$(&G+F'%<'+N-?+%/<$"@(+($(<.);/%<+D()&%;/&+-/@J;)+<"&.;N+<;D()&+-/@+<;/.(/.+C-).%<"$-)+.; P;)<(@+"&+.;+@;+-CC-)(/.$?+)-/@;N+.'%/8&+@(C(/@%/8+;/+&;N(+(R"-$$?+)-/@;N+<;/.(I. +W-/@;N/(&&
?;")+#"&%/(&&G+.)-%/%/8+8;-$&G+N-)O(.%/8+P;<"&G+-/@+#)-/@%/8+%/.()(&.& +X;)+N;)(+%/P;)N-.%;/G+C$(-&( @;(&/=.+P(($+)%8'. +U/;.'()+.'%/8+.'-.+@;(&/=.+P(($+)%8'.+%&+)(C(.%.%D(/(&&+-/@+)(@"/@-/<? +T;;@
<;/.-<.* C);8)-NN()&+-)(+$-h? +E'-.+F(+$;D(+-#;".+<;NC".()&+<;NC-)(@+.;G+&-?G+8-)@(/%/8+%&+.'-.+F(+@;/=.
'-D(+.;+@;+.'(+&-N(+.'%/8&+;D()+-/@+;D()

9 1 A;)C;)-.( -/@ T;D()/N(/. 1-$(& H(.+N(+(NC'-&%h(+.'%&+C;%/.+F%.'+-+)(-$4F;)$@+(I-NC$(*+.)-D($+)(%N#")&(N(/.+P;)N& +:?C%<-$$?+.';&(


YZ66[ 7ZS47Q5\ P;)N&+<;N(+-&+P-/<?+&C)(-@&'((.&i+?;"+P%$$+.'(N+;".G+-/@+?;"+8(.+)(-$+N;/(? +1%NC$(+.(<'/;$;8?G
<;)C&-$(&]C(-)&;/.(<'8);"C <;N ;/(+&';"$@+.'%/OG+-/@+8%D(/+.'(+N;/(.-)?+%/<(/.%D(+.'%&+&';"$@+#(+-+&%NC$(+.-&O+P;)+-+8);F/4"C
(/8%/(()
X;)+&-$(&+;".&%@(+.'(+9/%.(@+1.-.(&G+C$(-&(+<;/.-<.*
W(-$%.?+$;;O&+@%PP()(/.G+.';"8' +E'%$(+/;#;@?+($&(+%/+.'(+<;NC-/?+&((N&+.;+'-D(+-/?+C);#$(N&
F'-.&;(D()+@(-$%/8+F%.'+.';&(+P;)N&G.'(+(/8%/(()&+@; +U/@+'-D%/8+.-$O(@+.;+C(;C$(+%/+;.'()
0/.()/-.%;/-$ 1-$(& <;NC-/%(&G+.'%&+&((N&+.;+#(+-+<;NN;/+C-..()/ +E(+@(P()+)(%N#")&(N(/.+"/.%$+.'(+D()?+$-&.
%/.()/-.%;/-$]C(-)&;/(@ <;N N;N(/.G+-/@+&;N(.%N(&+F(+N%8'.+(D(/+P;)8(.+-#;".+%. +E'?+%&+.'-.e+H;;O%/8+-.+;")+P;)NG+%.=&+-
&.)-%8'.P;)F-)@G+&.-/@-)@+C);<(@")( +L/(+'-&+.;+<;$$(<.+)(<(%C.&G+/"N#()+.'(NG+-/@+C".+.';&(
/"N#()&+%/.;+.'(+C);C()+P%($@&+F%.'+.'(+@-.(G+.'(+$;<-.%;/G+-+@(&<)%C.%;/G+-/@+.'(+-N;"/. +:'(
^%&%.+"&+;/+.'(+E(#* FFF C)(/'-$$C);P(&&%;/-$ <;N
/"N#()%/8+-/@+<;C?%/8+%&+@(&%8/(@+.;+(-&(+&;N(;/(=&+F;)OG+#".+&.)%<.$?+&C(-O%/8+%.+%&+)(@"/@-/.G
8%D(/+.'-.+.'(+@-.(G+$;<-.%;/G+@(&<)%C.%;/G+-/@+-N;"/.+"/-N#%8";"&$?+%@(/.%P?+-+)(<(%C. +U+.%/?+#%.+;P
(I.)-+F;)O+.;+8(.+?;")+N;/(?+#-<OG+;/(+F;"$@+.'%/O
3,4'*'5 (6 (-)'788 */*9(),-):,-:&;49,<*/,(- =*/*
2$-/<'(..(G V-&N%/
U+&N-$$+-//;?-/<(+%&+.'(+C()4@%(N+)-.(G+.';"8'G+F'%<'+@(C(/@&+;/+.'(+.)-D($+$;<-.%;/ +:'()(=&+&;N(
ABB T90 C);8)-NN%/8 F%.' >. Q J V-&N%/ 2$-/<'(..(G K-)O 1"NN()P%($@
&(C-)-.(+@;<"N(/.+&;N(F'()(+.'-.+$%&.&+.'(+&.-/@-)@%h(@+)-.(&+P;)+-$$+.'(+@%PP()(/.+.)-D($+$;<-.%;/&
C <N
j;"+<-/=.+c"&.+&($(<.+gA'%<-8;gi+%/&.(-@+?;"+'-D(+.;+$;;O+"C+.'(+)-.(+P;)+A'%<-8;+?;")&($P +:'()(=&+-
0/<$"@(& #%#$%;8)-C'%<-$ )(P()(/<(& -/@ %/@(I
&%N%$-)+-//;?-/<(+F%.'+.'(+(I<'-/8(+)-.(+P%($@ +L/(+'-&+.;+P%/@+.'(+<"))(/.+(I<'-/8(+)-.(
0123 645745Z_SQ\4Q YC#O * -$O C-C()[
&;N(F'()(C()'-C&+F%.'+T;;8$(=&+'($C-/@+.'(/+(/.()+.'(+)-.(+%/+(D()?+&%/8$(+P%($@ +E($$G+&.)%<.$?
5 T)-C'%<-$ "&() %/.()P-<(& YA;NC".() &?&.(N&[ S ABB YA;NC".() C);8)-N $-/8"-8([
&C(-O%/8G+?;"+&';"$@+F-%.+P;)+?;")+<)(@%. <-)@+<;NC-/?+.;+%&&"(+-+&.-.(N(/.+.;+?;"+F%.'+.'(+-<."-$
0 1"NN()P%($@G K-)O 00 :%.$(
(I<'-/8(+)-.(+.'-.+.'(?+"&(@ +E'%$(+.'%&+%&+/;.+'-)@+.;+@;G+$;;O%/8+"C+@%PP()(/.+C%(<(&+;P+%/P;)N-.%;/
>U_` \ 9Z72a7S S66`
P);N+@%PP()(/.+&;")<(&G+-/@+.'(/+<;C?%/8+.'(+)($(D-/.+%.(N&+.;+&(D()-$+C$-<(&+%/+.'(+P;)N+P(($&
66a Q=7_@<SS
/((@$(&&$?+-FOF-)@
S66`6577_`

!);8)-NN%/8+<-/+#(+-+$;.+$%O(+P%$$%/8+%/+.)-D($+)(%N#")&(N(/.+P;)N&G+;/$?+F;)&( +U/@+.'%&+%&+F'()(+>.
A;C?)%8'.+b+S66`+:);$$.(<'+U1
<;N(&+.;+.'(+)(&<"( +>.+%&+@%PP()(/. +X;)+;/(+.'%/8G+>.+N-O(&+&(/&( +U/@+P;)+-/;.'()G+>.+%&+P"/ +>.
$(.&+?;"+<;/<(/.)-.(+;/+?;")+.-&O& +E'(/+>.=&+;)%8%/-$+-)<'%.(<.&+P-<(@+-+C);#$(NG+.'(?+@%@/=.+c"&.
U$$+)%8'.&+)(&()D(@ +!)%/.(@+%/+.'(+9/%.(@+1.-.(&+;P+UN()%<- +:'%&+C"#$%<-.%;/+N-?+;/$?+#(+@%&.)%#".(@ $;;O+P;)+-+8;;@+&;$".%;/G+;)+.'(+&%NC$(&.+&;$".%;/ +:'(?+$;;O(@+P;)+.'( ',)0/+&;$".%;/G+-/@+.'(/+.'(?
&"#c(<.+.;+.'(+.()N&+-/@+<;/@%.%;/&+&(.+P;).'+%/+.'(+LC(/+!"#$%<-.%;/+H%<(/&(G+D5 6+;)+$-.()+Y.'( @;<"N(/.(@+%. +T)-/.(@+.'(?+N-@(+N%&.-O(&G+-/@+8)-/.(@+&;N(+;P+.'(%)+@(&%8/+@(<%&%;/&+@%@/=.+C-&&
$-.(&.+D()&%;/+%&+-D-%$-#$(+-. '..C*JJFFF ;C(/4<;/.(/. ;)8J;C(/C"#J[ .'(+.(&.+;P+.%N(G+#".+.'(?+&.%$$+8;.+-+$;.+;P+.'%/8&+)%8'.G+-/@+F'-.+F-&/=.+)%8'.+<;"$@+-/@+<-/+#(
<;))(<.(@ +j;"+<-/+&((+.'%&+#?+.'(+P-<.+.'-.+-+&?&.(N+;)%8%/-$$?+@(&%8/(@+.;+#)%@8(+E%/@;F&+\a+-/@
:);$$.(<'dG+>.dG+>.;C%-dG+-/@+.'(+:);$$.(<'+-/@+>.;C%-+$;8;&+-)(+)(8%&.()(@+.)-@(N-)O&+;P+:);$$.(<' 9/%IJK;.%P+/;F+"/%P%(&+N;@()/+@(&O.;C+&?&.(N&+-&+@%D()&(+-&+E%/@;F&+M!G+K-<+L1+MG+-/@
U1 T39JH%/"IG+-/@+C);D%@(&+.'(+P;"/@-.%;/+P;)+.'(+>.;C%-+-CC$%<-.%;/+C$-.P;)N+P;)+(N#(@@(@+H%/"I

:(I.+C)%/.(@+%/+.'(+9/%.(@+1.-.(&+;/+)(<?<$(@+C-C()+-.+A;")%()+%/+1.;"8'.;/G+K-&&-<'"&(..& H;/8+#(P;)(+>.+#(<-N(+&;+C;C"$-)+-/@+&;+F%@($?+"&(@G+.'(+@(@%<-.%;/+;P+>.=&+@(D($;C()&+.;+P%/@%/8
.'(+)%8'.+&;$".%;/&+N-@( >.+&C(<%-$ +:'-.+@(@%<-.%;/+%&+c"&.+-&+&.);/8+.;@-?+-/@+-PP(<.&+(D()?;/(+F';
X%)&.+C)%/.%/8G+V"/(+S66` @(D($;C&+-/@+N-%/.-%/&+>. +X;)+"&G+F;)O%/8+;/+>.+%&+-+)(&C;/&%#%$%.?+-/@+-+C)%D%$(8( +E(+-)(+C);"@+;P
'($C%/8+.;+N-O(+?;")+C);P(&&%;/-$+-/@+;C(/+&;")<(+$%D(&+(-&%()+-/@+N;)(+(/c;?-#$(

K-..'%-&+k..)%<' 4 L&$;G+3;)F-? 4+V"/(+S66`


;P+.'(&(+C);@"<.&G+$%O(+>.+1<)%C.+P;)+UCC$%<-.%;/&+Y>1U[+-/@+.'(+>.+1;$".%;/&+<;NC;/(/.&G+-)(
-D-%$-#$(+P);N+:);$$.(<'G+F'%$(+;.'()&+-)(+&"CC$%(@+#?+;.'()+<;NC-/%(&+-/@+#?+.'(+;C(/+&;")<(
Preface <;NN"/%.? +1(( '..C*JJFFF .);$$.(<' <;NJC);@"<.&J7)@C-).?J+P;)+%/P;)N-.%;/+;/+>.+-@@4;/& +>.
-$&;+'-&+-+F($$4(&.-#$%&'(@+-/@+.')%D%/8+"&()+<;NN"/%.?+.'-.+"&(&+.'( qt-interest+N-%$%/8+$%&.i+&((
'..C*JJ$%&.& .);$$.(<' <;NJ+P;)+@(.-%$&
>.+%&+-+<;NC)('(/&%D(+ABB+P)-N(F;)O+P;)+@(D($;C%/8+<);&&4C$-.P;)N+T90+-CC$%<-.%;/&+"&%/8+-+gF)%.(
;/<(G+<;NC%$(+-/?F'()(g+-CC);-<' +>.+$(.&+C);8)-NN()&+"&(+-+&%/8$(+&;")<(+.)((+P;)+-CC$%<-.%;/&
.'-.+F%$$+)"/+;/+E%/@;F&+\Z+.;+M!G+K-<+L1+MG+H%/"IG+1;$-)%&G+f!49MG+-/@+N-/?+;.'()+D()&%;/&+;P 0P+?;"+&C;.+());)&+%/+.'(+#;;OG+'-D(+&"88(&.%;/&+P;)+.'(+/(I.+(@%.%;/G+;)+F-/.+.;+8%D(+"&+P((@#-<OG
9/%I+F%.'+M55 +:'(+>.+$%#)-)%(&+-/@+.;;$&+-)(+-$&;+C-).+;P+>.;C%-+A;)(G+-+C);@"<.+.'-.+C);D%@(&+%.& F(+F;"$@+#(+@($%8'.(@+.;+'(-)+P);N+?;" +j;"+<-/+)(-<'+"&+-. R.4#;;O].);$$.(<' <;N +:'(+())-.-+F%$$
;F/+F%/@;F+&?&.(N+;/+.;C+;P+(N#(@@(@+H%/"I #(+C$-<(@+;/ '..C*JJ@;< .);$$.(<' <;NJR.4#;;O4())-.- '.N$

:'(+C")C;&(+;P+.'%&+#;;O+%&+.;+.(-<'+?;"+';F+.;+F)%.(+T90+C);8)-N&+"&%/8+>.+Q +:'(+#;;O+&.-).&+F%.'
gf($$;+>.g+-/@+R"%<O$?+C);8)(&&(&+.;+N;)(+-@D-/<(@+.;C%<&G+&"<'+-&+<)(-.%/8+<"&.;N+F%@8(.&+-/@
C);D%@%/8+@)-8+-/@+@);C +:'(+.(I.+%&+<;NC$(N(/.(@+#?+-+A,+.'-.+<;/.-%/&+.'(+&;")<(+<;@(+;P+.'(
(I-NC$(+C);8)-N& +:'(+A,+-$&;+%/<$"@(&+.'(+;C(/+&;")<(+(@%.%;/+;P+>.+Q 5 5+P;)+-$$+&"CC;).(@
C$-.P;)N&G+-&+F($$+-&+K%/TEG+-+&(.+;P+P)(($?+-D-%$-#$(+@(D($;CN(/.+.;;$&+.'-.+<-/+#(+"&(@+.;+#"%$@+>.
-CC$%<-.%;/&+;/+E%/@;F& UCC(/@%I+U+(IC$-%/&+';F+.;+%/&.-$$+.'(+&;P.F-)(

:'(+#;;O+%&+@%D%@(@+%/.;+.')((+C-).& !-).+0+<;D()&+-$$+.'(+<;/<(C.&+-/@+C)-<.%<(&+/(<(&&-)?+P;)
C);8)-NN%/8+T90+-CC$%<-.%;/&+"&%/8+>. +l/;F$(@8(+;P+.'%&+C-).+-$;/(+%&+&"PP%<%(/.+.;+F)%.(+"&(P"$+T90
-CC$%<-.%;/& !-).+00+<;D()&+<(/.)-$+>.+.;C%<&+%/+8)(-.()+@(C.'G+-/@ !-).+000+C);D%@(&+N;)(+&C(<%-$%h(@
-/@+-@D-/<(@+N-.()%-$ :'(+<'-C.()&+;P !-).&+00+-/@ 000+<-/+#(+)(-@+%/+-/?+;)@()G+#".+.'(?+-&&"N(
P-N%$%-)%.?+F%.'+.'(+<;/.(/.&+;P !-).+0

W(-@()&+;P+.'(+>.+7 (@%.%;/+;P+.'%&+#;;O+F%$$+P%/@+.'%&+/(F+(@%.%;/+P-N%$%-)+%/+#;.'+<;/.(/.+-/@+&.?$(
:'%&+(@%.%;/+'-&+#((/+"C@-.(@+.;+.-O(+-@D-/.-8(+;P+>.+Q=&+/(F+P(-.")(&+Y%/<$"@%/8+&;N(+.'-.+F()(
%/.);@"<(@+F%.'+>.+Q 5[+-/@+.;+C)(&(/.+<;@(+.'-.+&';F&+8;;@+%@%;N-.%<+>.+Q C);8)-NN%/8
.(<'/%R"(& +0/+N-/?+<-&(&G+F(+'-D(+"&(@+(I-NC$(&+&%N%$-)+.;+.'(+;/(&+"&(@+%/+.'(+>.+7+(@%.%;/ +:'%&
F%$$+/;.+-PP(<.+/(F+)(-@()&G+#".+F%$$+'($C+.';&(+F';+)(-@+.'(+C)(D%;"&+(@%.%;/+;)%(/.+.'(N&($D(&+.;+>.
Q=&+<$(-/()G+<$(-)()G+-/@+N;)(+(IC)(&&%D(+&.?$(

:'%&+(@%.%;/+%/<$"@(&+/(F+<'-C.()&+<;D()%/8+>.+Q=&+N;@($JD%(F+-)<'%.(<.")(G+.'(+/(F+C$"8%/
P)-N(F;)OG+-/@+(N#(@@(@+C);8)-NN%/8+F%.'+>.;C%-G+-&+F($$+-+/(F+-CC(/@%I +U/@+c"&.+$%O(+.'(+>.+7
#;;OG+.'(+(NC'-&%&+%&+;/+(IC$-%/%/8+>.+C);8)-NN%/8+)-.'()+.'-/+&%NC$?+)('-&'%/8+;)+&"NN-)%h%/8
>.=&+(I.(/&%D(+;/$%/(+@;<"N(/.-.%;/

E(+'-D(+F)%..(/+.'(+#;;O+F%.'+.'(+-&&"NC.%;/+.'-.+?;"+'-D(+-+#-&%<+O/;F$(@8(+;P+ABBG+V-D-G+;)
Am +:'(+<;@(+(I-NC$(&+"&(+-+&"#&(.+;P+ABBG+-D;%@%/8+N-/?+ABB+P(-.")(&+.'-.+-)(+)-)($?+/((@(@
F'(/+C);8)-NN%/8+>. +0/+.'(+P(F+C$-<(&+F'()(+-+N;)(+-@D-/<(@+ABB+<;/&.)"<.+%&+"/-D;%@-#$(G+%.+%&
(IC$-%/(@+F'()(+%.+%&+"&(@

0P+?;"+-$)(-@?+O/;F+V-D-+;)+Am+#".+'-D(+$%..$(+;)+/;+(IC()%(/<(+F%.'+ABBG+F(+)(<;NN(/@+.'-.+?;"
#(8%/+#?+)(-@%/8 UCC(/@%I+2G+F'%<'+C);D%@(&+&"PP%<%(/.+%/.);@"<.%;/+.;+ABB+.;+#(+-#$(+.;+"&(+.'%&
#;;O +X;)+-+N;)(+.';);"8'+%/.);@"<.%;/+.;+;#c(<.4;)%(/.(@+C);8)-NN%/8+%/+ABBG+F(+)(<;NN(/@
!!"?(."/("&'()'*++#?+f-)D(?+,(%.($+-/@+!-"$+,(%.($G+-/@+.'( !!"&',+7'+#?+1.-/$(?+2
H%CCN-/G+V;&n(+H-c;%(G+-/@+2-)#-)-+k +K;;

>.+N-@(+%.&+)(C".-.%;/+-&+-+<);&&4C$-.P;)N+P)-N(F;)OG+#".+#(<-"&(+;P+%.&+%/."%.%D(+-/@+C;F()P"$+U!0G
N-/?+;)8-/%h-.%;/&+"&(+>.+P;)+&%/8$(4C$-.P;)N+@(D($;CN(/. +U@;#(+!';.;&';C+U$#"N+%&+c"&.+;/(
(I-NC$(+;P+-+N-&&4N-)O(.+E%/@;F&+-CC$%<-.%;/+F)%..(/+%/+>. +K-/?+&;C'%&.%<-.(@+&;P.F-)(+&?&.(N&
%/+D().%<-$+N-)O(.&G+&"<'+-&+7,+-/%N-.%;/+.;;$&G+@%8%.-$+P%$N+C);<(&&%/8G+($(<.);/%<+@(&%8/+-".;N-.%;/
YP;)+<'%C+@(&%8/[G+;%$+-/@+8-&+(IC$;)-.%;/G+P%/-/<%-$+&()D%<(&G+-/@+N(@%<-$+%N-8%/8G+-)(+#"%$.+F%.'+>.
0P+?;"+-)(+N-O%/8+-+$%D%/8+F%.'+-+&"<<(&&P"$+E%/@;F&+C);@"<.+F)%..(/+%/+>.G+?;"+<-/+(-&%$?+<)(-.(
/(F+N-)O(.&+%/+.'(+K-<+L1+M+-/@+H%/"I+F;)$@&+&%NC$?+#?+)(<;NC%$%/8

>.+%&+-D-%$-#$(+"/@()+D-)%;"&+$%<(/&(& +0P+?;"+F-/.+.;+#"%$@+<;NN()<%-$+-CC$%<-.%;/&G+?;"+N"&.+#"?+-
<;NN()<%-$+>.+$%<(/&(i+%P+?;"+F-/.+.;+#"%$@+;C(/+&;")<(+C);8)-N&G+?;"+<-/+"&(+.'(+;C(/+&;")<(
YT!H[+(@%.%;/ +>.+%&+.'(+P;"/@-.%;/+;/+F'%<'+.'(+l+,(&O.;C+k/D%);/N(/.+Yl,k[+-/@+.'(+N-/?+;C(/
&;")<(+-CC$%<-.%;/&+.'-.+8;+F%.'+%.+-)(+#"%$.

0/+-@@%.%;/+.;+>.=&+'"/@)(@&+;P+<$-&&(&G+.'()(+-)(+-@@4;/&+.'-.+(I.(/@+>.=&+&<;C(+-/@+C;F() +1;N(
Acknowledgments A Brief History of Qt
L")+P%)&.+-<O/;F$(@8N(/.+%&+;P+k%)%O+A'-N#(4k/8G+:);$$.(<'=&+C)(&%@(/. +k%)%O+/;.+;/$? :'(+>.+P)-N(F;)O+P%)&.+#(<-N(+C"#$%<$?+-D-%$-#$(+%/+K-?+5\\a +0.+F-&+%/%.%-$$?+@(D($;C(@+#?+f--D-)@
(/.'"&%-&.%<-$$?+(/<;")-8(@+"&+.;+F)%.(+.'(+>.+7+(@%.%;/+;P+.'(+#;;OG+'(+-$&;+-$$;F(@+"&+.;+&C(/@+- 3;)@+Y:);$$.(<'=&+AkL[+-/@+k%)%O+A'-N#(4k/8+Y:);$$.(<'=&+C)(&%@(/.[ +f--D-)@+-/@+k%)%O+N(.+-.+.'(
<;/&%@()-#$(+-N;"/.+;P+;")+F;)O+.%N(+F)%.%/8+%. +k%)%O+-/@+:);$$.(<'+AkL+f--D-)@+3;)@+#;.'+)(-@+.'( 3;)F(8%-/+0/&.%.".(+;P+:(<'/;$;8?+%/+:);/@'(%NG+F'()(+.'(?+#;.'+8)-@"-.(@+F%.'+N-&.()=&+@(8)((&
N-/"&<)%C.+-/@+C);D%@(@+D-$"-#$(+P((@#-<O +:'(%)+8(/();&%.?+-/@+P;)(&%8'.+F-&+-%@(@+-/@+-#(..(@ %/+<;NC".()+&<%(/<(
#?+K-..'%-&+k..)%<'G+:);$$.(<'=&+$(-@+@(D($;C() +K-..'%-&+<'(()P"$$?+-<<(C.(@+;")+/(8$(<.+;P+@".?+-&
F(+;#&(&&(@+;D()+.'(+F)%.%/8+;P+.'(+P%)&.+(@%.%;/+;P+.'%&+#;;O+-/@+8-D(+"&+-+$;.+;P+-@D%<(+;/+8;;@+>. f--D-)@=&+%/.()(&.+%/+ABB+T90+@(D($;CN(/.+#(8-/+%/+5\ZZ+F'(/+'(+F-&+<;NN%&&%;/(@+#?+-
C);8)-NN%/8+&.?$( 1F(@%&'+<;NC-/?+.;+@(D($;C+-+ABB+T90+P)-N(F;)O +U+<;"C$(+;P+?(-)&+$-.()G+%/+.'(+&"NN()+;P+5\\6G
f--D-)@+-/@+k%)%O+F()(+F;)O%/8+.;8(.'()+;/+-+ABB+@-.-#-&(+-CC$%<-.%;/+P;)+"$.)-&;"/@+%N-8(& +:'(
X;)+.'(+>.+7+(@%.%;/G+F(+-&O(@+.F;+>.+<"&.;N()&G+!-"$+A").%&+-/@+l$-"&+1<'N%@%/8()G+.;+#(+;") &?&.(N+/((@(@+.;+#(+-#$(+.;+)"/+F%.'+-+T90+;/+9/%IG K-<%/.;&'G+-/@+E%/@;F& +L/(+@-?+.'-.
(I.()/-$+)(D%(F()& +2;.'+-)(+>.+(IC().&+F%.'+-/+-N-h%/8+-..(/.%;/+.;+.(<'/%<-$+@(.-%$G+F'%<'+.'(? &"NN()G+f--D-)@+-/@+k%)%O+F(/.+;".&%@(+.;+(/c;?+.'(+&"/&'%/(G+-/@+-&+.'(?+&-.+;/+-+C-)O+#(/<'G
C);D(@+#?+&C;..%/8+&;N(+D()?+&"#.$(+());)&+%/+;")+N-/"&<)%C.+-/@+&"88(&.%/8+/"N();"& f--D-)@+&-%@G+gE(+/((@+-/+;#c(<.4;)%(/.(@+@%&C$-?+&?&.(N g+:'(+)(&"$.%/8+@%&<"&&%;/+$-%@+.'(
%NC);D(N(/.& +U/@+F%.'%/+:);$$.(<'G+-$;/8&%@(+K-..'%-&G+;")+N;&.+&.-$F-).+)(D%(F()+F-&+W(8%/-$@ %/.($$(<."-$+P;"/@-.%;/+P;)+.'(+;#c(<.4;)%(/.(@+<);&&4C$-.P;)N+T90+P)-N(F;)O+.'(?+F;"$@+&;;/+8;+;/
1.-@$#-"() +f%&+.(<'/%<-$+%/&%8'.+F-&+%/D-$"-#$(G+-/@+'(+.-"8'.+"&+';F+.;+@;+&;N(+.'%/8&+%/+>.+.'-. .;+#"%$@
F(+@%@/=.+(D(/+O/;F+F()(+C;&&%#$(
0/+5\\5G+f--D-)@+&.-).(@+F)%.%/8+.'(+<$-&&(&+.'-.+(D(/."-$$?+#(<-N(+>.G+<;$$-#;)-.%/8+F%.'+k%)%O+;/
X;)+.'%&+>.+Q+(@%.%;/G+F(+'-D(+<;/.%/"(@+.;+#(/(P%.+P);N+.'(+"/&.%/.%/8+'($C+-/@+&"CC;).+;P+k%)%OG .'(+@(&%8/ +:'(+P;$$;F%/8+?(-)G+k%)%O+<-N(+"C+F%.'+.'(+%@(-+P;)+g&%8/-$&+-/@+&$;.&gG+-+&%NC$(+#".
f--D-)@G+-/@+K-..'%-& +l$-"&+1<'N%@%/8()+<;/.%/"(@+.;+8%D(+D-$"-#$(+P((@#-<OG+-/@+F%.'%/+:);$$.(<'G C;F()P"$+T90+C);8)-NN%/8+C-)-@%8N+.'-.+'-&+/;F+#((/+(N#)-<(@+#?+&(D()-$+;.'()+.;;$O%.&
;")+O(?+)(D%(F()&+F()(+U/@)(-&+U-)@-$+f-/&&(/G+f(/)%O+f-).hG+^%D%+T$o<O&.-@+l-)$&(/G+:)(/.;/ f--D-)@+.;;O+.'(+%@(-+-/@+C);@"<(@+-+'-/@4<;@(@+%NC$(N(/.-.%;/ +2?+5\\7G+f--D-)@+-/@+k%)%O+'-@
1<'"$hG+U/@?+1'-FG+-/@+!p$+@(+^%#( @(D($;C(@+>.=&+P%)&.+8)-C'%<&+O()/($+-/@+F()(+-#$(+.;+%NC$(N(/.+.'(%)+;F/+F%@8(.& +U.+.'(+(/@+;P+.'(
?(-)G+f--D-)@+&"88(&.(@+.'-.+.'(?+8;+%/.;+#"&%/(&&+.;8(.'()+.;+#"%$@+g.'(+F;)$@=&+#(&.+ABB+T90
0/+-@@%.%;/+.;+.'(+)(D%(F()&+N(/.%;/(@+-#;D(G+F(+)(<(%D(@+(IC().+'($C+P);N+f-)-$@+X()/(/8($ P)-N(F;)Og
Y@-.-#-&(&[G+^;$O()+f%$&'(%N()+YU<.%D(M[G+2)-@$(?+f"8'(&+YN"$.%.')(-@%/8[G+:);/@+lc()/p&(/+Y7,
8)-C'%<&+-/@+@-.-#-&(&[G+H-)&+l/;$$+YS,+8)-C'%<&+-/@+%/.()/-.%;/-$%h-.%;/[G+1-N+K-8/"&;/+Y qmake[G :'(+?(-)+5\\Q+#(8-/+%/-"&C%<%;"&$?+F%.'+.'(+.F;+?;"/8+C);8)-NN()&+F-/.%/8+.;+(/.()+-+F($$4
K-)%"&+2"88(+K;/&(/+Y%.(N+D%(F+<$-&&(&[G+,%N%.)%+!-C-@;C;"$;&+Y>.JM55[G+!-"$+L$-D+:D(.(+Y<"&.;N (&.-#$%&'(@+N-)O(.G+F%.'+/;+<"&.;N()&G+-/+"/P%/%&'(@+C);@"<.G+-/@+/;+N;/(? +X;)."/-.($?G+#;.'
F%@8(.&+-/@+(N#(@@(@+C);8)-NN%/8[G+W-%/()+1<'N%@+Y/(.F;)O%/8+-/@+MKH[G+UN)%.+!-$+1%/8' .'(%)+F%D(&+F()(+(NC$;?(@+-/@+.'()(P;)(+-#$(+.;+&"CC;).+.'(%)+'"&#-/@&+P;)+.'(+.F;+?(-)&+k%)%O+-/@
Y%/.);@"<.%;/+.;+ABB[G+-/@+T"//-)+1$(..-+YS,+8)-C'%<&+-/@+(D(/.+C);<(&&%/8[ f--D-)@+(IC(<.(@+.;+/((@+.;+@(D($;C+.'(+C);@"<.+-/@+&.-).+(-)/%/8+-/+%/<;N(

kI.)-+.'-/O&+-)(+@"(+.;+:);$$.(<'=&+@;<"N(/.-.%;/+-/@+&"CC;).+.(-N&+P;)+'-/@$%/8+@;<"N(/.-.%;/4 :'(+$(..()+=>=+F-&+<';&(/+-&+.'(+<$-&&+C)(P%I+#(<-"&(+.'(+$(..()+$;;O(@+#(-".%P"$+%/+f--D-)@=&+kN-<&
)($-.(@+%&&"(&+F'%$(+.'(+#;;O+<;/&"N(@+&;+N"<'+;P+;")+.%N(G+-/@+.;+:);$$.(<'=&+&?&.(N P;/. +:'(+=.=+F-&+-@@(@+.;+&.-/@+P;)+g.;;$O%.gG+%/&C%)(@+#?+M.G+.'(+M+:;;$O%. +:'(+<;NC-/?+F-&
-@N%/%&.)-.;)&+P;)+O((C%/8+;")+N-<'%/(&+)"//%/8+-/@+;")+/(.F;)O&+<;NN"/%<-.%/8+.');"8';".+.'( %/<;)C;)-.(@+;/+K-)<'+QG+5\\QG+;)%8%/-$$?+-&+>"-&-)+:(<'/;$;8%(&G+.'(/+-&+:);$$+:(<'G+-/@+.;@-?+-&
C);c(<. :);$$.(<'

L/+.'(+C);@"<.%;/+&%@(G+:)(/.;/+1<'"$h+<)(-.(@+.'(+-<<;NC-/?%/8+A,G+-/@+:);$$.(<'=&+A-.')%/(+2;)( 0/+UC)%$+5\\aG+.'-/O&+.;+-+<;/.-<.+N-@(+.');"8'+;/(+;P+f--D-)@=&+"/%D()&%.?+C);P(&&;)&G+.'(
'-/@$(@+.'(+<;/.)-<.&+-/@+$(8-$%.%(&+;/+;")+#('-$P +:'-/O&+-$&;+.;+3-.'-/+A$(N(/.+P;)+.'(+:);$$ 3;)F(8%-/+<;NC-/?+K(.%&+8-D(+.'(N+-+<;/.)-<.+.;+@(D($;C+&;P.F-)(+#-&(@+;/+>. +U);"/@+.'%&+.%N(G
%$$"&.)-.%;/& +U/@+$-&.+#".+/;. $(-&.G+.'-/O&+.;+H-)-+E?&;/8+P);N+!(-)&;/&G+P;)+'-/@$%/8+.'( :);$$.(<'+'%)(@+U)/.+T"$#)-/@&(/G+F';+@")%/8+'%&+&%I+?(-)&+-.+:);$$.(<'+@(D%&(@+-/@+%NC$(N(/.(@+-/
C);@"<.%;/+C)-<.%<-$%.%(&+&;+F($$ %/8(/%;"&+@;<"N(/.-.%;/+&?&.(N+-&+F($$+-&+<;/.)%#".%/8+.;+>.=&+<;@(

L/+K-?+S6G+5\\aG+>.+6 \6+F-&+"C$;-@(@+.; sunsite.unc.edu +1%I+@-?&+$-.()G+.'(+)($(-&(+F-&


-//;"/<(@+;/ comp.os.linux.announce +:'%&+F-&+>.=&+P%)&.+C"#$%<+)($(-&( +>.+<;"$@+#(+"&(@+P;)+#;.'
E%/@;F&+-/@+9/%I+@(D($;CN(/.G+;PP()%/8+.'(+&-N(+U!0+;/+#;.'+C$-.P;)N& +>.+F-&+-D-%$-#$(+"/@()
.F;+$%<(/&(&+P);N+@-?+;/(*+U+<;NN()<%-$+$%<(/&(+F-&+)(R"%)(@+P;)+<;NN()<%-$ @(D($;CN(/.G+-/@+-
P)((+&;P.F-)(+(@%.%;/+F-&+-D-%$-#$(+P;)+;C(/+&;")<(+@(D($;CN(/. +:'(+K(.%&+<;/.)-<.+O(C.+:);$$.(<'
-P$;-.G+F'%$(+P;)+.(/+$;/8+N;/.'&+/;+;/(+#;"8'.+-+<;NN()<%-$+>.+$%<(/&(

0/+K-)<'+5\\`G+.'(+k");C(-/+1C-<(+U8(/<?+#(<-N(+.'(+&(<;/@+>.+<"&.;N()G+F%.'+-+C")<'-&(+;P+.(/
<;NN()<%-$+$%<(/&(& +E%.'+"/F-D()%/8+P-%.'G+k%)%O+-/@+f--D-)@+'%)(@+-/;.'()+@(D($;C() +>.+6 \_+F-&
)($(-&(@+-.+.'(+(/@+;P+K-?G+-/@+;/+1(C.(N#()+SQG+5\\`G+>.+5 6+<-N(+;". +2?+.'(+(/@+;P+.'(+?(-)G
>.+'-@+)(-<'(@+D()&%;/+5 5i+(%8'.+<"&.;N()&G+(-<'+%/+-+@%PP()(/.+<;"/.)?G+'-@+#;"8'.+5Z+$%<(/&(&
#(.F((/+.'(N +:'%&+?(-)+-$&;+&-F+.'(+P;"/@%/8+;P+.'(+l,k+C);c(<.G+$(@+#?+K-..'%-&+k..)%<'

>.+5 S+F-&+)($(-&(@+%/+UC)%$+5\\_ +K-..'%-&+k..)%<'=&+@(<%&%;/+.;+"&(+>.+.;+#"%$@+l,k+'($C(@+>.


#(<;N(+.'(+@(+P-<.;+&.-/@-)@+P;)+ABB+T90+@(D($;CN(/.+;/+H%/"I +>.+5 7+F-&+)($(-&(@+%/
1(C.(N#()+5\\_

K-..'%-&+c;%/(@+:);$$.(<'+%/+5\\ZG+-/@+.'(+$-&.+N-c;)+>.+5+)($(-&(G+5 Q6G+F-&+N-@(+%/+1(C.(N#()+;P
.'-.+?(-) +>.+S 6+F-&+)($(-&(@+%/+V"/(+5\\\ +>.+S+'-@+-+/(F+;C(/+&;")<(+$%<(/&(G+.'(+>+!"#$%<
H%<(/&(+Y>!H[G+F'%<'+<;NC$%(@+F%.'+.'(+LC(/+1;")<(+,(P%/%.%;/ +0/+U"8"&.+5\\\G+>.+F;/+.'(
H%/"IE;)$@+-F-)@+P;)+#(&.+$%#)-)?J.;;$ +U);"/@+.'%&+.%N(G+:);$$.(<'+!.?+H.@+YU"&.)-$%-[+F-&
(&.-#$%&'(@ Part 1: Basic Qt
:);$$.(<'+)($(-&(@+>.;C%-+A;)(+Y.'(/+<-$$(@+>.JkN#(@@(@[+%/+S666 +0.+F-&+@(&%8/(@+.;+)"/+;/
(N#(@@(@+H%/"I+@(D%<(&+-/@+C);D%@(@+%.&+;F/+F%/@;F+&?&.(N+-&+-+$%8'.F(%8'.+)(C$-<(N(/.+P;)+M55
2;.'+>.JM55+-/@+>.;C%-+A;)(+F()(+/;F+;PP()(@+"/@()+.'(+F%@($?+"&(@+T39+T(/()-$+!"#$%<+H%<(/&(
YT!H[+-&+F($$+-&+"/@()+<;NN()<%-$+$%<(/&(& +2?+.'(+(/@+;P+S666G+:);$$.(<'+'-@+(&.-#$%&'(@+:);$$.(<' A'-C.()+5 +T(..%/8+1.-).(@
0/< Y91U[+-/@+'-@+)($(-&(@+.'(+P%)&.+D()&%;/+;P+>.;C%-G+-/+-CC$%<-.%;/+C$-.P;)N+P;)+N;#%$(+C';/(&
-/@+!,U& +>.;C%-+A;)(+F;/+.'(+H%/"IE;)$@+g2(&.+kN#(@@(@+H%/"I+1;$".%;/g+-F-)@+%/+#;.'+S665+-/@ A'-C.()+S +A)(-.%/8+,%-$;8&
S66SG+-/@+>.;C%-+!';/(+-<'%(D(@+.'(+&-N(+@%&.%/<.%;/+%/+S66Q
A'-C.()+7 +A)(-.%/8+K-%/+E%/@;F&
>.+7 6+F-&+)($(-&(@+%/+S665 +>.+F-&+/;F+-D-%$-#$(+;/+E%/@;F&G+K-<+L1+MG+9/%IG+-/@+H%/"I+Y@(&O.;C
-/@+(N#(@@(@[ +>.+7+C);D%@(@+QS+/(F+<$-&&(&+-/@+%.&+<;@(+(I<((@(@+a66G666+$%/(& +>.+7+F-&+- A'-C.()+Q +0NC$(N(/.%/8+UCC$%<-.%;/+X"/<.%;/-$%.?
N-c;)+&.(C+P;)F-)@+P);N+>.+SG+%/<$"@%/8+<;/&%@()-#$?+%NC);D(@+$;<-$(+-/@+9/%<;@(+&"CC;).G+-
<;NC$(.($?+/(F+.(I.+D%(F%/8+-/@+(@%.%/8+F%@8(.G+-/@+-+!()$4$%O(+)(8"$-)+(IC)(&&%;/+<$-&& +>.+7+F;/
A'-C.()+a +A)(-.%/8+A"&.;N+E%@8(.&
.'(+1;P.F-)(+,(D($;CN(/.+:%N(&+gV;$.+!);@"<.%D%.?+UF-)@g+%/+S66S

0/+.'(+&"NN()+;P+S66aG+>.+Q 6+F-&+)($(-&(@ +E%.'+-#;".+a66+<$-&&(&+-/@+N;)(+.'-/+\666+P"/<.%;/&G


>.+Q+%&+$-)8()+-/@+)%<'()+.'-/+-/?+C)(D%;"&+D()&%;/G+-/@+%.+'-&+#((/+&C$%.+%/.;+&(D()-$+$%#)-)%(&+&;+.'-.
@(D($;C()&+;/$?+/((@+.;+$%/O+-8-%/&.+.'(+C-).&+;P+>.+.'-.+.'(?+/((@ +>.+Q+%&+-+'"8(+-@D-/<(+;/
C)(D%;"&+D()&%;/&+F%.'+%NC);D(N(/.&+.'-.+%/<$"@(+-+<;NC$(.($?+/(F+&(.+;P+(PP%<%(/.+-/@+(-&?4.;4"&(
.(NC$-.(+<;/.-%/()&G+-@D-/<(@+N;@($JD%(F+P"/<.%;/-$%.?G+-+P-&.+-/@+P$(I%#$(+S,+C-%/.%/8+P)-N(F;)OG
-/@+C;F()P"$+9/%<;@(+.(I.+D%(F%/8+-/@+(@%.%/8+<$-&&(&G+/;.+.;+N(/.%;/+.';"&-/@&+;P+&N-$$()
(/'-/<(N(/.&+-<);&&+.'(+<;NC$(.(+)-/8(+;P+>.+<$-&&(& +>.+Q+%&+.'(+P%)&.+>.+(@%.%;/+.;+#(+-D-%$-#$(+P;)
#;.'+<;NN()<%-$+-/@+;C(/+&;")<(+@(D($;CN(/. ;/+-$$+.'(+C$-.P;)N&+%.+&"CC;).&

U$&;+%/+S66aG+:);$$.(<'+;C(/(@+-+)(C)(&(/.-.%D(+;PP%<(+%/+2(%c%/8+.;+C);D%@(+<"&.;N()&+%/+A'%/-+-/@
.'(+)(8%;/+F%.'+&-$(&+&()D%<(&G+.)-%/%/8G+-/@+.(<'/%<-$+&"CC;).+P;)+>.;C%-

1%/<(+:);$$.(<'=&+#%).'G+>.=&+C;C"$-)%.?+'-&+8);F/+"/-#-.(@+-/@+<;/.%/"(&+.;+8);F+.;+.'%&+@-? +:'%&
&"<<(&&+%&+-+)(P$(<.%;/+#;.'+;P+.'(+R"-$%.?+;P+>.+-/@+;P+';F+(/c;?-#$(+%.+%&+.;+"&( +0/+.'(+$-&.+@(<-@(G
>.+'-&+8;/(+P);N+#(%/8+-+C);@"<.+"&(@+#?+-+&($(<.+P(F+g%/+.'(+O/;Fg+.;+;/(+.'-.+%&+"&(@+@-%$?+#?
.';"&-/@&+;P+<"&.;N()&+-/@+.(/&+;P+.';"&-/@&+;P+;C(/+&;")<(+@(D($;C()&+-$$+-);"/@+.'(+F;)$@
gN;"&(+C)(&&g+-/@+-+gN;"&(+)($(-&(g+(D(/.+-)(+8(/()-.(@ +0/+.'%&+)(&C(<.G+T90+-CC$%<-.%;/&+@%PP()
@)-&.%<-$$?+P);N+<;/D(/.%;/-$+#-.<'+C);8)-N&G+F'%<'+.?C%<-$$?+C);<(&&+%/C".G+C);@"<(+)(&"$.&G+-/@
Chapter 1. Getting Started .()N%/-.(+F%.';".+'"N-/+%/.()D(/.%;/

• !""#$%& X;)+&%NC$%<%.?G+F(+@;/=.+#;.'()+<-$$%/8 delete+;/+.'( QLabel+;#c(<.+-.+.'(+(/@+;P+.'( main()+P"/<.%;/


• '()*+,$-#++!.&*#+/ :'%&+N(N;)?+$(-O+%&+'-)N$(&&+%/+&"<'+-+&N-$$+C);8)-NG+&%/<(+.'(+N(N;)?+F%$$+#(+)(<$-%N(@+#?+.'(
• 0(1*+,$23&$4*5,!&/ ;C()-.%/8+&?&.(N+F'(/+.'(+C);8)-N+.()N%/-.(&
• 6/*+,$&7!$8!9!:!+.!$;#.3<!+&(&*#+
G%E,!"'.D.D'("**B'B#'H%#,I
:'%&+<'-C.()+&';F&+';F+.;+<;N#%/(+#-&%<+ABB+F%.'+.'(+P"/<.%;/-$%.?+C);D%@(@+#?+>.+.;+<)(-.(+-+P(F
&N-$$+8)-C'%<-$+"&()+%/.()P-<(+YT90[+-CC$%<-.%;/& +:'%&+<'-C.()+-$&;+%/.);@"<(&+.F;+O(?+>.+%@(-&*
g&%8/-$&+-/@+&$;.&g+-/@+$-?;".& +0/ A'-C.()+SG+F(+F%$$+8;+%/.;+N;)(+@(C.'G+-/@+%/ A'-C.()+7G+F(+F%$$
&.-).+#"%$@%/8+-+N;)(+)(-$%&.%<+-CC$%<-.%;/

0P+?;"+-$)(-@?+O/;F+V-D-+;)+Am+#".+'-D(+$%N%.(@+(IC()%(/<(+F%.'+ABBG+?;"+N%8'.+F-/.+.;+&.-).+#?
)(-@%/8+.'(+ABB+%/.);@"<.%;/+%/ UCC(/@%I+2
0.+%&+/;F+C;&&%#$(+.;+.)?+.'(+C);8)-N+;/+?;")+;F/+N-<'%/( +X%)&.G+?;"+F%$$+/((@+.;+%/&.-$$+>.+Q 5 5+Y;)
-+$-.()+>.+Q+)($(-&([G+-+C);<(&&+.'-.+%&+(IC$-%/(@+%/ UCC(/@%I+U +X);N+/;F+;/G+F(+F%$$+-&&"N(+.'-.
?;"+'-D(+-+<;))(<.$?+%/&.-$$(@+<;C?+;P+>.+Q+-/@+.'-.+>.=& bin+@%)(<.;)?+%&+%/+?;") PATH+(/D%);/N(/.
D-)%-#$( +YL/+E%/@;F&G+.'%&+%&+@;/(+-".;N-.%<-$$?+#?+.'(+>.+%/&.-$$-.%;/+C);8)-N [+j;"+F%$$+-$&;+/((@
.'(+C);8)-N=&+&;")<(+<;@(+%/+-+P%$(+<-$$(@ hello.cpp+%/+-+@%)(<.;)?+<-$$(@ hello +j;"+<-/+.?C(+%/
Hello Qt hello.cpp+?;")&($PG+;)+<;C?+%.+P);N+.'(+A,+C);D%@(@+F%.'+.'%&+#;;OG+F'()(+%.+%&+-D-%$-#$(+-&
/examples/chap01/hello/hello.cpp
H(.=&+&.-).+F%.'+-+D()?+&%NC$(+>.+C);8)-N +E(+F%$$+P%)&.+&."@?+%.+$%/(+#?+$%/(G+.'(/+F(+F%$$+&((+';F+.;
<;NC%$(+-/@+)"/+%.
X);N+-+<;NN-/@+C);NC.G+<'-/8(+.'(+@%)(<.;)?+.; helloG+.'(/+.?C(

1 #include <QApplication>
qmake -project
2 #include <QLabel>
3 int main(int argc, char *argv[])
4 {
5 QApplication app(argc, argv); .;+<)(-.(+-+C$-.P;)N4%/@(C(/@(/.+C);c(<.+P%$(+Yhello.pro[G+.'(/+.?C(
6 QLabel *label = new QLabel("Hello Qt!");
7 label->show();
8 return app.exec(); qmake hello.pro
9 }

.;+<)(-.(+-+C$-.P;)N4&C(<%P%<+N-O(P%$(+P);N+.'(+C);c(<.+P%$(
H%/(&+5+-/@+S+%/<$"@(+.'(+@(P%/%.%;/&+;P+.'( QApplication+-/@ QLabel+<$-&&(& +X;)+(D()?+>.+<$-&&G
.'()(+%&+-+'(-@()+P%$(+F%.'+.'(+&-N(+/-N(+Y-/@+<-C%.-$%h-.%;/[+-&+.'(+<$-&&+.'-.+<;/.-%/&+.'(+<$-&&=&
:?C( make+.;+#"%$@+.'(+C);8)-N rst+W"/+%.+#?+.?C%/8 hello+;/+E%/@;F&G ./hello+;/+9/%IG+-/@ open
@(P%/%.%;/
hello.app+;/+K-<+L1+M +:;+.()N%/-.(+.'(+C);8)-NG+<$%<O+.'(+<$;&(+#"..;/+%/+.'(+F%/@;F=&+.%.$(+#-)

H%/(+a+<)(-.(&+- QApplication+;#c(<.+.;+N-/-8(+-CC$%<-.%;/4F%@(+)(&;")<(& +:'( QApplication [*]


If you get a compiler error on the <QApplication> include, it probably means that you are using an older version of Qt. Make
<;/&.)"<.;)+)(R"%)(& argc+-/@ argv+#(<-"&(+>.+&"CC;).&+-+P(F+<;NN-/@4$%/(+-)8"N(/.&+;P+%.&+;F/ sure that you are using Qt 4.1.1 or a later Qt 4 release.

H%/(+`+<)(-.(&+- QLabel+F%@8(.+.'-.+@%&C$-?&+gf($$;+>.qg +0/+>. -/@+9/%I+.()N%/;$;8?G+- .,@)7/+%&+- !"#$%"&'("%)*+,"-*+.$/)"&+."0&1("*+)2&33(."20("42"56(+"7$%'8("9.*2*$+"&+."20(":*+;-"8$<6*3('=


D%&"-$+($(N(/.+%/+-+"&()+%/.()P-<( +:'(+.()N+&.(N&+P);N+gF%/@;F+8-@8(.g+-/@+%&+.'(+(R"%D-$(/.+;P #$%"/*33"0&1("&")0$'28%2"2$"&">57"?'$<62"/*+.$/"20&2"0&)"&33"20("(+1*'$+<(+2"1&'*&@3()"8$''(823#
#;.'+g<;/.);$g+-/@+g<;/.-%/()g+%/+E%/@;F&+.()N%/;$;8? +2"..;/&G+N(/"&G+&<);$$+#-)&G+-/@+P)-N(&+-)( )(2"%6"!$'"42A" !"#$%")2&'2"20*)"/*+.$/="#$%"8&+"8$<6*3("42"&663*8&2*$+)"/*20*+"*2"%)*+, qmake"&+. make
-$$+(I-NC$(&+;P+F%@8(.& +E%@8(.&+<-/+<;/.-%/+;.'()+F%@8(.&i+P;)+(I-NC$(G+-/+-CC$%<-.%;/+F%/@;F+%& &)".()8'*@(."&@$1(A"B0("(C(8%2&@3()"6'$.%8(."&'("6%2"*+"20("&663*8&2*$+D) debug"$' release"!$3.('=
"&"-$$?+-+F%@8(.+.'-.+<;/.-%/&+- QMenuBarG+-+P(F QToolBar&G+- QStatusBarG+-/@+&;N(+;.'()+F%@8(.& !$'"(C&<63(= C:\qt-book\hello\release\hello.exeA
K;&.+-CC$%<-.%;/&+"&(+- QMainWindow+;)+- QDialog+-&+.'(+-CC$%<-.%;/+F%/@;FG+#".+>.+%&+&;+P$(I%#$(+.'-.
-/?+F%@8(.+<-/+#(+-+F%/@;F +0/+.'%&+(I-NC$(G+.'( QLabel+F%@8(.+%&+.'(+-CC$%<-.%;/+F%/@;F !"#$%"&'("%)*+,":*8'$)$!2"E*)%&3"FGG="#$%"/*33"+((."2$"'%+ nmake"*+)2(&."$! makeA"H32('+&2*1(3#="#$%
8&+"8'(&2("&"E*)%&3"72%.*$"6'$I(82"!*3("!'$< hello.pro"@#"2#6*+,
H%/(+_+N-O(&+.'(+$-#($+D%&%#$( +E%@8(.&+-)(+-$F-?&+<)(-.(@+'%@@(/G+&;+.'-.+F(+<-/+<"&.;N%h(+.'(N
#(P;)(+&';F%/8+.'(NG+.'()(#?+-D;%@%/8+P$%<O()
qmake -tp vc hello.pro
H%/(+Z+C-&&(&+<;/.);$+;P+.'(+-CC$%<-.%;/+;/+.;+>. +U.+.'%&+C;%/.G+.'(+C);8)-N+(/.()&+.'(+(D(/.+$;;C
:'%&+%&+-+O%/@+;P+&.-/@4#?+N;@(+F'()(+.'(+C);8)-N+F-%.&+P;)+"&()+-<.%;/&+&"<'+-&+N;"&(+<$%<O&+-/@
O(?+C)(&&(& +9&()+-<.%;/&+8(/()-.( 7A7-/8+Y-$&;+<-$$(@+gN(&&-8(&g[+.;+F'%<'+.'(+C);8)-N+<-/ &+."20(+"@%*3."20("6'$,'&<"*+"E*)%&3"72%.*$A" !"#$%"&'("%)*+,"J8$.("$+":&8"57"J="#$%"8&+",(+('&2(
)(&C;/@G+"&"-$$?+#?+(I(<".%/8+;/(+;)+N;)(+P"/<.%;/& +X;)+(I-NC$(G+F'(/+.'(+"&()+<$%<O&+-+F%@8(.G+-
&+"J8$.("6'$I(82"%)*+,"20("8$<<&+. *+)2&+8(= QPushButton"(<*2)"& clicked()")*,+&3"/0(+"20("%)('"83*8Q)"20("@%22$+A"H")*,+&3"8&+"@(
8$++(82(."2$"&"!%+82*$+"S8&33(."& %&'"*+"20&2"8$+2(C2T=")$"20&2"/0(+"20(")*,+&3"*)"(<*22(.="20(")3$2"*)
&%2$<&2*8&33#"(C(8%2(.A" +"$%'"(C&<63(="/("8$++(82"20("@%22$+D) clicked()")*,+&3"2$"20(
qmake -spec macx-xcode QApplication"$@I(82D) quit()")3$2A"B0( SIGNAL()"&+. SLOT()"<&8'$)"&'("6&'2"$!"20(")#+2&CY"20(#"&'(
(C63&*+(."*+"<$'(".(2&*3"*+"20("+(C2"80&62('A
[*]
Qt signals are unrelated to Unix signals. In this book, we are only concerned with Qt signals.
!"#$%&'()(&*&+,-%+&.!/0&-,1!2&3456&78$9,//!:"
!"#$%&'(;(&40%&<#!/&,==+!2,/!8:

K(!$'("/(",$"$+"2$"20("+(C2"(C&<63(="3(2D)"0&1(")$<("!%+L"M(63&8("20("3*+(
-("/*33"+$/"@%*3."20("&663*8&2*$+A"-("&))%<("20&2"#$%"0&1("8'(&2(."&".*'(82$'#"8&33(. quit
QLabel *label = new QLabel("Hello Qt!"); 8$+2&*+*+, quit.cppA"M%+ qmake"*+"20( quit".*'(82$'#"2$",(+('&2("20("6'$I(82"!*3(="20(+"'%+"*2"&,&*+"2$
,(+('&2("&"<&Q(!*3(="&)"!$33$/)L

/*20 qmake -project


qmake quit.pro

QLabel *label = new QLabel("<h2><i>Hello</i> "


"<font color=red>Qt!</font></h2>");
Z$/"@%*3."20("&663*8&2*$+="&+."'%+"*2A" !"#$%"83*8Q"4%*2="$'"6'())"76&8("S/0*80"6'())()"20("@%22$+T=
20("&663*8&2*$+"/*33"2('<*+&2(A

&+."'(@%*3."20("&663*8&2*$+A"H)"20("(C&<63("*33%)2'&2()="*2D)"(&)#"2$"@'*,02(+"%6"&"42"&663*8&2*$+D)
%)('"*+2('!&8("%)*+,")$<(")*<63("NB:OP)2#3("!$'<&22*+,A
Laying Out Widgets
+"20*)")(82*$+= /("/*33"8'(&2("&")<&33"(C&<63("&663*8&2*$+"20&2".(<$+)2'&2()"0$/"2$"%)("3&#$%2)"2$
<&+&,("20(",($<(2'#"$!"/*.,(2)"*+"&"/*+.$/"&+."0$/"2$"%)(")*,+&3)"&+.")3$2)"2$")#+80'$+*[("2/$
/*.,(2)A"B0("&663*8&2*$+"&)Q)"!$'"20("%)('D)"&,(="/0*80"20("%)('"8&+"(+2('"@# <&+*6%3&2*+,"(*20('"&
Making Connections )6*+"@$C"$'"&")3*.('A

B0(")(8$+."(C&<63(")0$/)"0$/"2$"'()6$+."2$"%)('"&82*$+)A"B0("&663*8&2*$+"8$+)*)2)"$!"&"@%22$+"20&2 B0("&663*8&2*$+"8$+)*)2)"$!"20'(("/*.,(2)L"& QSpinBox="& QSlider="&+."& QWidgetA"B0( QWidget"*)"20(


20("%)('"8&+"83*8Q"2$"R%*2A"B0(")$%'8("8$.("*)"1('#")*<*3&'"2$"N(33$="(C8(62"20&2"/("&'("%)*+,"& &663*8&2*$+D)"<&*+"/*+.$/A"B0( QSpinBox"&+."20( QSlider"&'("'(+.('(."*+)*.("20( QWidgetY"20(#"&'(
QPushButton"*+)2(&."$!"& QLabel"&)"$%'"<&*+"/*.,(2="&+."/("&'("8$++(82*+,"&"%)('"&82*$+"S83*8Q*+,"& ()!%*+,#"$!"20( QWidgetA"H32('+&2*1(3#="/("8&+")&#"20&2"20( QWidget"*)"20( -$+,#'"$!"20( QSpinBox
@%22$+T"2$"&"6*(8("$!"8$.(A &+."20( QSliderA"B0( QWidget"0&)"+$"6&'(+2"*2)(3!"@(8&%)("*2"*)"@(*+,"%)(."&)"&"2$6P3(1(3"/*+.$/A
B0("8$+)2'%82$')"!$' QWidget"&+."&33"$!"*2)")%@83&))()"2&Q("& QWidget *"6&'&<(2('"20&2")6(8*!*()"20(
B0*)"&663*8&2*$+D)")$%'8("8$.("*)"$+"20("F>"*+"20("!*3( /examples/chap01/quit/quit.cppA"N('(D)"20( 6&'(+2"/*.,(2A
8$+2(+2)"$!"20("!*3(L
!"#$%&'(>(&40%&*"%&,==+!2,/!8:
1 #include <QApplication>
2 #include <QPushButton>
3 int main(int argc, char *argv[])
4 {
5 QApplication app(argc, argv);
6 QPushButton *button = new QPushButton("Quit");
7 QObject::connect(button, SIGNAL(clicked()),
8 &app, SLOT(quit()));
9 button->show();
10 return app.exec(); N('(D)"20(")$%'8("8$.(L
11 }

1 #include <QApplication>
42D)"/*.,(2)"(<*2 !"#$% "2$"*+.*8&2("20&2"&"%)('"&82*$+"$'"&"80&+,("$!")2&2("0&)"$88%''(.A UVW"X$' 2 #include <QHBoxLayout>
3 #include <QSlider>
4 #include <QSpinBox>
5 int main(int argc, char *argv[])
6 {
7 QApplication app(argc, argv);
8 QWidget *window = new QWidget;
9 window->setWindowTitle("Enter Your Age");
10 QSpinBox *spinBox = new QSpinBox;
11 QSlider *slider = new QSlider(Qt::Horizontal);
12 spinBox->setRange(0, 130);
13 slider->setRange(0, 130);
14 QObject::connect(spinBox, SIGNAL(valueChanged(int)),
15 slider, SLOT(setValue(int)));
16 QObject::connect(slider, SIGNAL(valueChanged(int)),
17 spinBox, SLOT(setValue(int)));
18 spinBox->setValue(35);
19 QHBoxLayout *layout = new QHBoxLayout;
20 layout->addWidget(spinBox);
21 layout->addWidget(slider);
22 window->setLayout(layout);
23 window->show();
24 return app.exec();
25 }

+"3*+()"^]"2$"``="/("3&#"$%2"20(")6*+"@$C"&+.")3*.('"/*.,(2)"%)*+,"& %$.&/'01$#$",+A"H"3&#$%2
O*+()"\"&+."]")(2"%6"20( QWidget"20&2"/*33")('1("&)"20("&663*8&2*$+D)"<&*+"/*+.$/A"-("8&33 <&+&,('"*)"&+"$@I(82"20&2")(2)"20(")*[("&+."6$)*2*$+"$!"20("/*.,(2)"20&2"3*("%+.('"*2)"'()6$+)*@*3*2#A
setWindowTitle()"2$")(2"20("2(C2".*)63&#(."*+"20("/*+.$/D)"2*23("@&'A 42"0&)"20'(("<&*+"3&#$%2"<&+&,('"83&))()L

O*+()"^_"&+."^^"8'(&2("& QSpinBox"&+."& QSlider="&+."3*+()"^` &+."^a")(2"20(*'"1&3*."'&+,()A"-("8&+ • QHBoxLayout"3&#)"$%2"/*.,(2)"0$'*[$+2&33#"!'$<"3(!2"2$"'*,02"S'*,02"2$"3(!2"!$'")$<("8%32%'()TA


)&!(3#"&))%<("20&2"20("%)('"*)"&2"<$)2"^a_"#(&')"$3.A"-("8$%3."6&)) window"2$"20( QSpinBox"&+. • QVBoxLayout"3&#)"$%2"/*.,(2)"1('2*8&33#"!'$<"2$6"2$"@$22$<A
QSlider"8$+)2'%82$')=")6(8*!#*+,"20&2"20()("/*.,(2)")0$%3."0&1( window"&)"20(*'"6&'(+2="@%2"*2"*)+D2 • QGridLayout"3&#)"$%2"/*.,(2)"*+"&",'*.A
+(8())&'#"0('("@(8&%)("20("3&#$%2")#)2(<"/*33"!*,%'("20*)"$%2"@#"*2)(3!"&+."&%2$<&2*8&33#")(2"20(
6&'(+2"$!"20(")6*+"@$C"&+."20(")3*.('="&)"/("/*33")((")0$'23#A B0("8&33"2$ QWidget::setLayout()"$+"3*+("``"*+)2&33)"20("3&#$%2"<&+&,('"$+"20("/*+.$/A"K(0*+."20(
)8(+()="20( QSpinBox"&+. QSlider"&'("e'(6&'(+2(.e"2$"@("80*3.'(+"$!"20("/*.,(2"$+"/0*80"20("3&#$%2
B0("2/$ QObject::connect()"8&33)")0$/+"*+"3*+()"^b"2$"^c"(+)%'("20&2"20(")6*+"@$C"&+."20(")3*.('"&'( *)"*+)2&33(.="&+."!$'"20*)"'(&)$+"/(".$+D2"+((."2$")6(8*!#"&+"(C63*8*2"6&'(+2"/0(+"/("8$+)2'%82"&
)#+80'$+*[(.")$ 20&2"20(#"&3/&#)")0$/"20(")&<("1&3%(A"-0(+(1('"20("1&3%("$!"$+("/*.,(2"80&+,()= /*.,(2"20&2"/*33"@("6%2"*+"&"3&#$%2A
*2) valueChanged(int)")*,+&3"*)"(<*22(.="&+."20( setValue(int)")3$2"$!"20("$20('"/*.,(2"*)"8&33(."/*20
20("+(/"1&3%(A !"#$%&'(D(&40%&*"%&,==+!2,/!8:B1&.!A"%/1
O*+("^\")(2)"20(")6*+"@$C"1&3%("2$"adA"-0(+"20*)"0&66(+)= 20( QSpinBox"(<*2)"20( valueChanged(int)
)*,+&3"/*20"&+ int"&',%<(+2"$!"adA"B0*)"&',%<(+2"*)"6&))(."2$"20( QSliderD) setValue(int)")3$2=
/0*80")(2)"20(")3*.('"1&3%("2$"adA"B0(")3*.('"20(+"(<*2)"20( valueChanged(int)")*,+&3="@(8&%)("*2)
$/+"1&3%("80&+,(.="2'*,,('*+,"20(")6*+"@$CD) setValue(int)")3$2A"K%2"&2"20*)"6$*+2= setValue(int)
.$()+D2"(<*2"&+#")*,+&3=")*+8("20(")6*+"@$C"1&3%("*)"&3'(&.#"adA"B0*)"6'(1(+2)"*+!*+*2("'(8%')*$+A
X*,%'("^Ad")%<<&'*[()"20(")*2%&2*$+A

!"#$%&'(?(&@0,:"!:"&8:%&.!A"%/B1&C,+#%&20,:"%1&-8/0 91(+"20$%,0"/(".*.+D2")(2"20("6$)*2*$+"$'")*[("$!"&+#"/*.,(2"(C63*8*23#="20( QSpinBox"&+. QSlider


&66(&'"+*8(3#"3&*."$%2")*.("@#")*.(A"B0*)"*)"@(8&%)( QHBox-Layout"&%2$<&2*8&33#"&))*,+)"'(&)$+&@3(
6$)*2*$+)"&+.")*[()"2$"20("/*.,(2)"!$'"/0*80"*2"*)"'()6$+)*@3(="@&)(."$+"20(*'"+((.)A"B0("3&#$%2
<&+&,(')"!'(("%)"!'$<"20("80$'("$!"0&'.P8$.*+,")8'((+"6$)*2*$+)"*+"$%'"&663*8&2*$+)"&+."(+)%'("20&2
/*+.$/)"'()*[(")<$$203#A

42D)"&66'$&80"2$"@%*3.*+,"%)('"*+2('!&8()"*)")*<63("2$"%+.(')2&+."&+."1('#"!3(C*@3(A"B0("<$)2
8$<<$+"6&22('+"20&2"42"6'$,'&<<(')"%)("*)"2$"*+)2&+2*&2("20("'(R%*'(."/*.,(2)"&+."20(+")(2"20(*'
6'$6('2*()"&)"+(8())&'#A"?'$,'&<<(')"&.."20("/*.,(2)"2$"3&#$%2)="/0*80"&%2$<&2*8&33#"2&Q("8&'("$!
)*[*+,"&+."6$)*2*$+*+,A"f)('"*+2('!&8("@(0&1*$'"*)"<&+&,(."@#"8$++(82*+,"/*.,(2)"2$,(20('"%)*+,"42D)
)*,+&3)"&+.")3$2)"<(80&+*)<A
Using the Reference Documentation
42D)"'(!('(+8(".$8%<(+2&2*$+"*)"&+"())(+2*&3"2$$3"!$'"&+#"42".(1(3$6('=")*+8("*2"8$1(')"(1('#"83&))
&+."!%+82*$+"*+"42A"B0*)"@$$Q"<&Q()"%)("$!"<&+#"42"83&))()"&+."!%+82*$+)="@%2"*2".$()"+$2"8$1('"&33
$!"20(<="+$'".$()"*2"6'$1*.("(1('#".(2&*3"$!"20$)("20&2"&'("<(+2*$+(.A"B$",(2"20("<$)2"@(+(!*2"!'$<
42="#$%")0$%3."!&<*3*&'*[("#$%')(3!"/*20"20("42"'(!('(+8(".$8%<(+2&2*$+"&)"R%*8Q3#"&)"6$))*@3(A

B0(".$8%<(+2&2*$+"*)"&1&*3&@3("*+"NB:O"!$'<&2"*+"42D) doc/html".*'(82$'#"&+."8&+"@("'(&."%)*+,"&+#
/(@"@'$/)('A"g$%"8&+"&3)$"%)( 2'03 ! '$#'="20("42"0(36"@'$/)('="/0*80"0&)"6$/('!%3")(&'80*+,
&+."*+.(C*+,"!(&2%'()"20&2"<&Q("*2"R%*8Q('"&+."(&)*('"2$"%)("20&+"&"/(@"@'$/)('A"B$"3&%+80 2'
3 ! '$#'="83*8Q"42"@#"B'$332(80"1bACA#hH))*)2&+2"*+"20("72&'2"<(+%"$+"-*+.$/)="2#6( assistant"$+
20("8$<<&+."3*+("$+"f+*C="$'".$%@3(P83*8Q"H))*)2&+2"*+"20(":&8"57"J"X*+.('A

B0("'(!('(+8(".$8%<(+2&2*$+"!$'"20("8%''(+2"1(')*$+"$!"42"&+."!$'")$<("(&'3*('"1(')*$+)"*)"&1&*3&@3(
B0("3*+Q)"*+"20("eH? "M(!('(+8(e")(82*$+"$+"20("0$<("6&,("6'$1*.(".*!!('(+2"/&#)"$!"+&1*,&2*+,"42D)
$+3*+("&2 0226Lii.$8A2'$332(80A8$<iA"B0*)")*2("&3)$"0&)")(3(82(."&'2*83()"!'$< 2'02/$+',+%.="20("42
83&))()A"B0("eH33"F3&))()e"6&,("3*)2)"(1('#"83&))"*+"42D)"H? A"B0("e:&*+"F3&))()e"6&,("3*)2)"$+3#"20(
6'$,'&<<(')D"+(/)3(22('")(+2"2$"&33"8$<<('8*&3"3*8(+)(()A
<$)2"8$<<$+3#"%)(."42"83&))()A"H)"&+"(C('8*)(="#$%"<*,02"/&+2"2$"3$$Q"%6"20("83&))()"&+.
!%+82*$+)"20&2"/("0&1("%)(."*+"20*)"80&62('A

!"#$%&'(E(&</B1&A82#9%:/,/!8:&!: !"#$$%$!&'!&8:&5,2&FG&H Widget Styles


[View full size image]
B0(")8'((+)0$2)"/("0&1(")((+")$"!&'"0&1("@((+"2&Q(+"$+"O*+%C="@%2"42"&663*8&2*$+)"3$$Q
+&2*1("$+"(1('#")%66$'2(."63&2!$'<A"42"&80*(1()"20*)"@#"(<%3&2*+,"20("63&2!$'<D)"3$$Q
&+."!((3="'&20('"20&+"/'&66*+,"&"6&'2*8%3&'"63&2!$'<"$'"2$$3Q*2D)"/*.,(2")(2A

!"#$%&'(K(&G/L+%1&,C,!+,-+%&%C%$L.0%$%

-*20"42iJ^^"&+."42$6*&"F$'(="20(".(!&%32")2#3("*)"?3&)2*R%(="/0*80"%)()",'&.*(+2)"&+.
&+2*P&3*&)*+,"2$"6'$1*.("&"<$.('+"3$$Q"&+."!((3A"42"&663*8&2*$+"%)(')"8&+"$1(''*.("20(
Z$2("20&2"*+0('*2(."!%+82*$+) &'(".$8%<(+2(."*+"20("@&)("83&))Y"!$'"(C&<63(= QPushButton"0&)"+$ .(!&%32")2#3("@#"%)*+,"20( -style"8$<<&+.P3*+("$62*$+A"X$'"(C&<63(="2$"3&%+80"20("H,(
show()"!%+82*$+"$!"*2)"$/+="@%2"*2"*+0('*2)"$+("!'$<"*2)"&+8()2$' QWidgetA X*,%'("^A\")0$/)"0$/"20( &663*8&2*$+"%)*+,"20(":$2*!")2#3("$+"J^^=")*<63#"2#6(
83&))()"/("0&1(")((+")$"!&'"'(3&2("2$"(&80"$20('A

!"#$%&'(I(&J:0%$!/,:2%&/$%%&78$&/0%&</&2+,11%1&1%%:&18&7,$ ./age -style motif

$+"20("8$<<&+."3*+(A

!"#$%&'('M(&N+,/78$9O1=%2!7!2&1/L+%1
Chapter 2. Creating Dialogs
• ()*+,&$$%'-" .%&,/-
• (%-'&,$"&'0"(,/!$"%'".12!3
• 4&2%0".%&,/-".1$%-'
• (3&21563&'-%'-".%&,/-$
• .7'&8%+".%&,/-$
• 9)%,!5%'":%0-1!"&'0".%&,/-"6,&$$1$
f+3*Q("20("$20('")2#3()="20("-*+.$/)"J?"&+.":&8")2#3()"&'("$+3#"&1&*3&@3("$+"20(*'"+&2*1(
63&2!$'<)=")*+8("20(#"'(3#"$+"20("63&2!$'<)D"20(<("(+,*+()A
B0*)"80&62('"/*33"2(&80"#$%"0$/"2$"8'(&2(".*&3$,"@$C()"%)*+,"42A">*&3$,"@$C()"6'()(+2"%)(')"/*20
$62*$+)"&+."80$*8()="&+."&33$/"20(<"2$")(2"20("$62*$+)"2$"20(*'"6'(!(''(."1&3%()"&+."2$"<&Q("20(*'
80$*8()A"B0(#"&'("8&33(.".*&3$,"@$C()="$'")*<63#"e.*&3$,)e="@(8&%)("20(#"6'$1*.("&"<(&+)"@#"/0*80
B0*)"80&62('"0&)"*+2'$.%8(."20("Q(#"8$+8(62)"$!")*,+&3)3$2"8$++(82*$+)"&+. 3&#$%2)A" 2"0&)"&3)$ %)(')"&+."&663*8&2*$+)"8&+"e2&3Q"2$e"(&80"$20('A
@(,%+"2$"'(1(&3"42D)"8$+)*)2(+2"&+."!%33#"$@I(82P$'*(+2(."&66'$&80"2$"20("8$+)2'%82*$+"&+."%)("$!
/*.,(2)A" !"#$%"@'$/)("20'$%,0"42D)".$8%<(+2&2*$+="#$%"/*33"!*+."&"%+*!$'<*2#"$!"&66'$&80"20&2 :$)2";f "&663*8&2*$+)"8$+)*)2"$!"&"<&*+"/*+.$/"/*20"&"<(+%"@&'"&+."2$$3@&'="&3$+,"/*20".$[(+)"$!
<&Q()"*2")2'&*,02!$'/&'."2$"3(&'+"0$/"2$"%)("+(/"/*.,(2)="&+."#$%"/*33"&3)$"!*+."20&2"42D)"8&'(!%33# .*&3$,)"20&2"8$<63(<(+2"20("<&*+"/*+.$/A" 2"*)"&3)$"6$))*@3("2$"8'(&2(".*&3$,"&663*8&2*$+)"20&2
80$)(+"+&<()"!$'"!%+82*$+)="6&'&<(2(')="(+%<)="&+.")$"$+="<&Q("6'$,'&<<*+,"*+"42")%'6'*)*+,3# '()6$+.".*'(823#"2$"20("%)('D)"80$*8() @#"6('!$'<*+,"20("&66'$6'*&2("&82*$+)"S!$'"(C&<63(="&
63(&)&+2"&+."(&)#A 8&38%3&2$'"&663*8&2*$+TA

B0("!$33$/*+,"80&62(')"$! ?&'2" "@%*3."$+"20("!%+.&<(+2&3)"8$1('(."0('(=")0$/*+,"0$/"2$"8'(&2( -("/*33"8'(&2("$%'"!*')2".*&3$,"6%'(3#"@#"/'*2*+,"8$.("2$")0$/"0$/"*2"*)".$+(A"B0(+"/("/*33")(("0$/"2$


8$<63(2(";f "&663*8&2*$+)"/*20"<(+%)="2$$3@&')=".$8%<(+2"/*+.$/)="&")2&2%)"@&'="&+.".*&3$,)= @%*3.".*&3$,)"%)*+, 2'04, !"#,+="42D)"1*)%&3".()*,+"2$$3A"f)*+, 2'04, !"#,+"*)"&"3$2"!&)2('"20&+
&3$+,"/*20"20("%+.('3#*+,"!%+82*$+&3*2#"2$"'(&.="6'$8())="&+."/'*2("!*3()A 0&+.P8$.*+,"&+."<&Q()"*2"(&)#"2$"2()2".*!!('(+2".()*,+)"&+."2$"80&+,(".()*,+)"3&2('A

Subclassing QDialog
5%'"!*')2"(C&<63("*)"&"X*+.".*&3$,"/'*22(+"(+2*'(3#"*+"FGGA"-("/*33"*<63(<(+2"20(".*&3$,"&)"&"83&))"*+
*2)"$/+"'*,02A"K#".$*+,")$="/("<&Q("*2"&+"*+.(6(+.(+2=")(3!P8$+2&*+(."8$<6$+(+2="/*20"*2)"$/+
)*,+&3)"&+.")3$2)A

!"#$%&)('(&40%& !:A&A!,+8"

B0(")$%'8("8$.("*)")6'(&."&8'$))"2/$"!*3()L finddialog.h"&+. finddialog.cppA"-("/*33")2&'2"/*20


finddialog.hA

1 #ifndef FINDDIALOG_H
2 #define FINDDIALOG_H
3 #include <QDialog>
4 class QCheckBox;
5 class QLabel;
6 class QLineEdit;
7 class QPushButton;
20(#"&'("&33"6$*+2(')"&+."/(".$+D2"&88())"20(<"*+"20("0(&.('"!*3(=")$"20("8$<6*3('".$()+D2"+((."20(
O*+()"^"&+."`"S&+."`cT"6'$2(82"20("0(&.('"!*3("&,&*+)2"<%32*63("*+83%)*$+)A !%33"83&))".(!*+*2*$+)A"-("8$%3."0&1("*+83%.(."20("'(3(1&+2"0(&.('"!*3()"S <QCheckBox>= <QLabel>="(28AT=
@%2"%)*+,"!$'/&'.".(83&'&2*$+)"/0(+"*2"*)"6$))*@3("<&Q()"8$<6*3*+,")$<(/0&2"!&)2('A
O*+("a"*+83%.()"20(".(!*+*2*$+"$! QDialog="20("@&)("83&))"!$'".*&3$,)"*+"42A QDialog"*+0('*2) QWidgetA
-("/*33"+$/ 3$$Q"&2 finddialog.cpp="/0*80"8$+2&*+)"20("*<63(<(+2&2*$+"$!"20( FindDialog"83&))A
O*+()"b"2$"c"&'("!$'/&'.".(83&'&2*$+)"$!"20("42"83&))()"20&2"/("/*33"%)("2$"*<63(<(+2"20(".*&3$,A"H
5&+6$+*0*,(%$+$'!&#"2(33)"20("FGG"8$<6*3('"20&2"&"83&))"(C*)2)="/*20$%2",*1*+,"&33"20(".(2&*3"20&2"&
83&))".(!*+*2*$+"S%)%&33#"3$8&2(."*+"&"0(&.('"!*3("$!"*2)"$/+T"6'$1*.()A"-("/*33")&#"<$'("&@$%2"20*) 1 #include <QtGui>
)0$'23#A 2 #include "finddialog.h"

Z(C2="/(".(!*+( FindDialog"&)"&")%@83&))"$! QDialogL


X*')2="/("*+83%.( <QtGui>="&"0(&.('"!*3("20&2"8$+2&*+)"20(".(!*+*2*$+"$!"42D)";f "83&))()A"42"8$+)*)2)"$!
)(1('&3"<$.%3()="(&80"$!"/0*80"3*1()"*+"*2)"$/+"3*@'&'#A"B0("<$)2"*<6$'2&+2"<$.%3()"&'( 2'7&+,8
8 class FindDialog : public QDialog 2'9/!802':,'6&+;802'<-,#9=802'>?%= 2'>@"="&+. 2'A1%A"B0( <QtGui>"0(&.('"!*3("8$+2&*+)"20(
9 { .(!*+*2*$+"$!"&33"20("83&))()"20&2"&'("6&'2"$!"20( 2'7&+,"&+. 2'9/!"<$.%3()A" +83%.*+,"20*)"0(&.('
10 Q_OBJECT )&1()"%)"20("@$20('"$!"*+83%.*+,"(1('#"83&))"*+.*1*.%&33#A
11 public:
12 FindDialog(QWidget *parent = 0); + filedialog.h="*+)2(&."$!"*+83%.*+, <QDialog>"&+."%)*+,"!$'/&'.".(83&'&2*$+)"!$' QCheckBox= QLabel=
QLineEdit="&+. QPushButton="/("8$%3.")*<63#"0&1("*+83%.(. <QtGui>A"N$/(1('="*2"*)",(+('&33#"@&.
)2#3("2$"*+83%.(")%80"&"@*,"0(&.('"!*3("!'$<"&+$20('"0(&.('"!*3(="()6(8*&33#"*+"3&',('"&663*8&2*$+)A
B0( Q_OBJECT"<&8'$"&2"20("@(,*++*+,"$!"20("83&))".(!*+*2*$+"*)"+(8())&'#"!$'"&33 83&))()"20&2".(!*+(
)*,+&3)"$'")3$2)A
3 FindDialog::FindDialog(QWidget *parent)
B0( FindDialog"8$+)2'%82$'"*)"2#6*8&3"$!"42"/*.,(2"83&))()A"B0( parent"6&'&<(2('")6(8*!*()"20("6&'(+2 4 : QDialog(parent)
/*.,(2A"B0(".(!&%32"*)"&"+%33"6$*+2('="<(&+*+,"20&2"20(".*&3$,"0&)"+$"6&'(+2A 5 {
6 label = new QLabel(tr("Find &what:"));
7 lineEdit = new QLineEdit;
8 label->setBuddy(lineEdit);
13 signals:
9 caseCheckBox = new QCheckBox(tr("Match &case"));
14 void findNext(const QString &str, Qt::CaseSensitivity cs);
10 backwardCheckBox = new QCheckBox(tr("Search &backward"));
15 void findPrevious(const QString &str, Qt::CaseSensitivity cs);
11 findButton = new QPushButton(tr("&Find"));
12 findButton->setDefault(true);
13 findButton->setEnabled(false);
B0( signals")(82*$+".(83&'()"2/$")*,+&3)"20&2"20(".*&3$,"(<*2)"/0(+"20("%)('"83*8Q)"20("X*+."@%22$+A 14 closeButton = new QPushButton(tr("Close"));
!"20("7(&'80"@&8Q/&'."$62*$+"*)"(+&@3(.="20(".*&3$,"(<*2) findPrevious()Y"$20('/*)(="*2"(<*2)
findNext()A
5+"3*+("b="/("6&))"$+"20( parent"6&'&<(2('"2$"20("@&)("83&))"8$+)2'%82$'A"B0(+"/("8'(&2("20("80*3.
B0( signals"Q(#/$'."*)"&82%&33#"&"<&8'$A"B0("FGG"6'(6'$8())$'"8$+1('2)"*2"*+2$")2&+.&'."FGG /*.,(2)A"B0( tr()"!%+82*$+"8&33)"&'$%+."20(")2'*+,"3*2('&3)"<&'Q"20(<"!$'"2'&+)3&2*$+"2$"$20('
@(!$'("20("8$<6*3('")(()"*2A Qt::CaseSensitivity"*)"&+"(+%<"2#6("20&2"8&+"2&Q("20("1&3%() 3&+,%&,()A"B0("!%+82*$+"*)".(83&'(."*+ QObject"&+."(1('#")%@83&))"20&2"8$+2&*+)"20( Q_OBJECT"<&8'$A
Qt::CaseSensitive"&+. Qt::CaseInsensitiveA 2D)"&",$$."0&@*2"2$")%''$%+."%)('P1*)*@3(")2'*+,)"/*20 TR()="(1(+"*!"#$%".$+D2"0&1("*<<(.*&2("63&+)
!$'"2'&+)3&2*+,"#$%'"&663*8&2*$+)"2$"$20('"3&+,%&,()A"B'&+)3&2*+,"42"&663*8&2*$+)"*)"8$1('(."*+ F0&62('
^cA
16 private slots:
17 void findClicked(); +"20(")2'*+,"3*2('&3)="/("%)("&<6(')&+.)"SDjDT"2$"*+.*8&2(")0$'28%2"Q(#)A"X$'"(C&<63(="3*+("^^"8'(&2()
18 void enableFindButton(const QString &text); & X*+."@%22$+="/0*80"20("%)('"8&+"&82*1&2("@#"6'())*+,"H32GX"$+"63&2!$'<)"20&2")%66$'2")0$'28%2
19 private: Q(#)A"H<6(')&+.)"8&+"&3)$"@("%)(."2$"8$+2'$3"!$8%)L"5+"3*+("k"/("8'(&2("&"3&@(3"/*20"&")0$'28%2"Q(#
20 QLabel *label;
SH32G-T="&+."$+"3*+("\"/(")(2"20("3&@(3D)"@%..#"2$"@("20("3*+("(.*2$'A"H B/**."*)"&"/*.,(2"20&2
21 QLineEdit *lineEdit;
&88(62)"20("!$8%)"/0(+"20("3&@(3D)")0$'28%2"Q(#"*)"6'())(.A"7$"/0(+"20("%)('"6'())()"H32G-"S20(
22 QCheckBox *caseCheckBox;
23 QCheckBox *backwardCheckBox; 3&@(3D)")0$'28%2T="20("!$8%)",$()"2$"20("3*+("(.*2$'"S20("3&@(3D)"@%..#TA
24 QPushButton *findButton;
25 QPushButton *closeButton; 5+"3*+("^`="/("<&Q("20("X*+."@%22$+"20(".*&3$,D)".(!&%32"@%22$+"@#"8&33*+, setDefault(true)A"B0(
26 }; .(!&%32"@%22$+"*)"20("@%22$+"20&2"*)"6'())(."/0(+"20("%)('"0*2)"9+2('A"5+"3*+("^a="/(".*)&@3("20("X*+.
27 #endif @%22$+A"-0(+"&"/*.,(2"*)".*)&@3(.="*2"*)"%)%&33#")0$/+",'&#(."$%2"&+."/*33"+$2"'()6$+."2$"%)('
*+2('&82*$+A

+"20("83&))D)"6'*1&2(")(82*$+="/(".(83&'("2/$")3$2)A"B$"*<63(<(+2"20(")3$2)="/("/*33"+((."2$"&88())
<$)2"$!"20(".*&3$,D)"80*3."/*.,(2)=")$"/("Q((6"6$*+2(')"2$"20(<"&)"/(33A"B0( slots"Q(#/$'."*)="3*Q( 15 connect(lineEdit, SIGNAL(textChanged(const QString &)),
signals="&"<&8'$"20&2"(C6&+.)"*+2$"&"8$+)2'%82"20&2"20("FGG"8$<6*3('"8&+".*,()2A
16 this, SLOT(enableFindButton(const QString &)));
17 connect(findButton, SIGNAL(clicked()),
18 this, SLOT(findClicked()));
X$'"20("6'*1&2("1&'*&@3()="/("%)(."!$'/&'.".(83&'&2*$+)"$!"20(*'"83&))()A"B0*)"/&)"6$))*@3("@(8&%)( 19 connect(closeButton, SIGNAL(clicked()),
20 this, SLOT(close())); &%2$<&2*8&33#"'(6&'(+2(.A"B0(+="/0(+"20("<&*+"3&#$%2"*)"*+)2&33(."$+"20(".*&3$,"S3*+("adT="*2"@(8$<()
&"80*3."$!"20(".*&3$,="&+."&33"20("/*.,(2)"*+"20("3&#$%2)"&'("'(6&'(+2(."2$"@(8$<("80*3.'(+"$!"20(
.*&3$,A"B0("'()%32*+,"6&'(+280*3."0*('&'80#"*)".(6*82(."*+ X*,%'("`AaA
B0("6'*1&2(")3$2 enableFindButton(const QString &)"*)"8&33(."/0(+(1('"20("2(C2"*+"20("3*+("(.*2$'
80&+,()A"B0("6'*1&2(")3$2 findClicked()"*)"8&33(."/0(+"20("%)('"83*8Q)"20("X*+."@%22$+A"B0(".*&3$, !"#$%&)(;(&40%& !:A&A!,+8"B1&=,$%:/20!+A&$%+,/!8:10!=1
83$)()"*2)(3!"/0(+"20("%)('"83*8Q)"F3$)(A"B0( close()")3$2"*)"*+0('*2(."!'$< QWidget="&+."*2)".(!&%32
@(0&1*$'"*)"2$"0*.("20("/*.,(2"!'$<"1*(/"S/*20$%2".(3(2*+,"*2TA"-("/*33"3$$Q"&2"20("8$.("!$'"20(
enableFindButton()"&+. findClicked()")3$2)"3&2('"$+A

7*+8( QObject"*)"$+("$! FindDialogD)"&+8()2$')="/("8&+ $<*2"20( QObject::"6'(!*C"*+"!'$+2"$!"20(


connect()"8&33)A

21 QHBoxLayout *topLeftLayout = new QHBoxLayout;


22 topLeftLayout->addWidget(label);
23 topLeftLayout->addWidget(lineEdit);
24 QVBoxLayout *leftLayout = new QVBoxLayout;
25 leftLayout->addLayout(topLeftLayout);
26 leftLayout->addWidget(caseCheckBox);
27 leftLayout->addWidget(backwardCheckBox); 36 setWindowTitle(tr("Find"));
28 QVBoxLayout *rightLayout = new QVBoxLayout; 37 setFixedHeight(sizeHint().height());
29 rightLayout->addWidget(findButton); 38 }
30 rightLayout->addWidget(closeButton);
31 rightLayout->addStretch();
32 QHBoxLayout *mainLayout = new QHBoxLayout;
33 mainLayout->addLayout(leftLayout); X*+&33#="/(")(2"20("2*23("2$"@(")0$/+"*+"20(".*&3$,D)"2*23("@&'"&+."/(")(2"20("/*+.$/"2$"0&1("&"!*C(.
34 mainLayout->addLayout(rightLayout); 0(*,02=")*+8("20('("&'(+D2"&+#"/*.,(2)"*+ 20(".*&3$,"20&2"8&+"<(&+*+,!%33#"$88%6#"&+#"(C2'&"1('2*8&3
35 setLayout(mainLayout); )6&8(A"B0( QWidget::sizeHint()"!%+82*$+"'(2%'+)"&"/*.,(2D)"e*.(&3e")*[(A

B0*)"8$<63(2()"20("'(1*(/"$! FindDialogD)"8$+)2'%82$'A"7*+8("/("%)(. new"2$"8'(&2("20(".*&3$,D)


Z(C2="/("3&#"$%2"20("80*3."/*.,(2)"%)*+,"3&#$%2"<&+&,(')A"O&#$%2)"8&+"8$+2&*+"@$20"/*.,(2)"&+. /*.,(2)"&+."3&#$%2)="*2"/$%3.")((<"20&2"/("+((."2$"/'*2("&".()2'%82$'"20&2"8&33) delete"$+"(&80"$!
$20('"3&#$%2)A"K#"+()2*+, QHBoxLayout)= QVBoxLayout)="&+. QGridLayout)"*+"1&'*$%)"8$<@*+&2*$+)="*2"*) 20("/*.,(2)"&+."3&#$%2)"/("8'(&2(.A"K%2"20*)"*)+D2"+(8())&'#=")*+8("42"&%2$<&2*8&33#".(3(2()"80*3.
6$))*@3("2$"@%*3."1('#")$60*)2*8&2(.".*&3$,)A $@I(82)"/0(+"20("6&'(+2"*)".()2'$#(.="&+."20("80*3."/*.,(2)"&+."3&#$%2)"&'("&33".()8(+.&+2)"$!"20(
FindDialogA
X$'"20("X*+.".*&3$,="/("%)("2/$ QHBoxLayout)"&+."2/$ QVBoxLayout)="&)")0$/+"*+ X*,%'("`A`A"B0(
$%2('"3&#$%2"*)"20("<&*+"3&#$%2Y"*2"*)"*+)2&33(."$+"20( FindDialog"$+"3*+("ad"&+."*)"'()6$+)*@3("!$'"20( Z$/"/("/*33"3$$Q"&2"20(".*&3$,D)")3$2)L
.*&3$,D)"(+2*'("&'(&A"B0("$20('"20'(("3&#$%2)"&'(")%@P3&#$%2)A"B0("3*223("e)6'*+,e"&2"20("@$22$<"'*,02
$! X*,%'("`A`"*)"&")6&8('"*2(<"S$'"e)2'(280eTA" 2"%)()"%6"20("(<62#")6&8("@(3$/"20("X*+."&+."F3$)(
@%22$+)="(+)%'*+,"20&2"20()("@%22$+)"$88%6#"20("2$6"$!"20(*'"3&#$%2A 39 void FindDialog::findClicked()
40 {
41 QString text = lineEdit->text();
!"#$%&)()(&40%& !:A&A!,+8"B1&+,L8#/1 42 Qt::CaseSensitivity cs =
[View full size image]
43 caseCheckBox->isChecked() ? Qt::CaseSensitive
44 : Qt::CaseInsensitive;
45 if (backwardCheckBox->isChecked()) {
46 emit findPrevious(text, cs);
47 } else {
48 emit findNext(text, cs);
49 }
50 }
51 void FindDialog::enableFindButton(const QString &text)
52 {
53 findButton->setEnabled(!text.isEmpty());
54 }

5+(")%@23("&)6(82"$!"20("3&#$%2"<&+&,('"83&))()"*)"20&2"20(#"&'("+$2"/*.,(2)A" +)2(&.="20(#"*+0('*2 B0( findClicked()")3$2"*)"8&33(."/0(+"20("%)('"83*8Q)"20("X*+."@%22$+A" 2"(<*2)"20( findPrevious()"$'


QLayout="/0*80"*+"2%'+"*+0('*2) QObjectA" +"20("!*,%'(="/*.,(2)"&'("'(6'()(+2(."@#")$3*."$%23*+()"&+. 20( findNext()")*,+&3=".(6(+.*+,"$+"20("7(&'80"@&8Q/&'."$62*$+A"B0( emit"Q(#/$'."*)")6(8*!*8"2$"42Y
3&#$%2)"&'("'(6'()(+2(."@#".&)0(."$%23*+()"2$"0*,03*,02"20(".*!!('(+8("@(2/((+"20(<A" +"&"'%++*+, 3*Q("$20('"42"(C2(+)*$+)"*2"*)"8$+1('2(."*+2$")2&+.&'."FGG"@#"20("FGG"6'(6'$8())$'A
&663*8&2*$+="3&#$%2)"&'("*+1*)*@3(A
B0( enableFindButton()")3$2"*)"8&33(."/0(+(1('"20("%)('"80&+,()"20("2(C2"*+"20("3*+("(.*2$'A" 2
-0(+"20(")%@P3&#$%2)"&'("&..(."2$"20("6&'(+2"3&#$%2"S3*+()"`d="aa="&+."abT="20(")%@P3&#$%2)"&'(
(+&@3()"20("@%22$+"*!"20('("*)")$<("2(C2"*+"20("(.*2$'="&+.".*)&@3()"*2"$20('/*)(A

B0()("2/$")3$2)"8$<63(2("20(".*&3$,A"-("8&+"+$/"8'(&2("& main.cpp"!*3("2$"2()2"$%' FindDialog


Signals and Slots in Depth
/*.,(2L
B0(")*,+&3)"&+.")3$2)"<(80&+*)<"*)"!%+.&<(+2&3"2$"42"6'$,'&<<*+,A" 2"(+&@3()"20("&663*8&2*$+
6'$,'&<<('"2$"@*+."$@I(82)"2$,(20('"/*20$%2"20("$@I(82)"Q+$/*+,"&+#20*+,"&@$%2"(&80"$20('A"-(
1 #include <QApplication> 0&1("&3'(&.#"8$++(82(.")$<(")*,+&3)"&+.")3$2)"2$,(20('=".(83&'(."$%'"$/+")*,+&3)"&+.")3$2)=
2 #include "finddialog.h" *<63(<(+2(."$%'"$/+")3$2)="&+."(<*22(."$%'"$/+")*,+&3)A"O(2D)"2&Q("&"<$<(+2"2$"3$$Q"&2"20(
3 int main(int argc, char *argv[]) <(80&+*)<"<$'("83$)(3#A
4 {
5 QApplication app(argc, argv); 73$2)"&'("&3<$)2"*.(+2*8&3"2$"$'.*+&'#"FGG"<(<@('"!%+82*$+)A"B0(#"8&+"@("1*'2%&3Y"20(#"8&+"@(
6 FindDialog *dialog = new FindDialog; $1('3$&.(.Y"20(#"8&+"@("6%@3*8Y"6'$2(82(.="$'"6'*1&2(="20(#"8&+"@(".*'(823#"*+1$Q(."3*Q("&+#"$20('
7 dialog->show(); FGG"<(<@('"!%+82*$+)Y"&+."20(*'"6&'&<(2(')"8&+"@("$!"&+#"2#6()A"B0(".*!!('(+8("*)"20&2"&")3$2"8&+
8 return app.exec();
&3)$"@("8$++(82(."2$"&")*,+&3="*+"/0*80"8&)("*2"*)"&%2$<&2*8&33#"8&33(."(&80"2*<("20(")*,+&3"*)"(<*22(.A
9 }

B0( connect()")2&2(<(+2"3$$Q)"3*Q("20*)L

B$"8$<6*3("20("6'$,'&<="'%+ qmake"&)"%)%&3A"7*+8("20( FindDialog"83&))".(!*+*2*$+"8$+2&*+)"20(


Q_OBJECT"<&8'$="20("<&Q(!*3(",(+('&2(."@# qmake"/*33"*+83%.(")6(8*&3"'%3()"2$"'%+ moc="42D)"<(2&P connect(sender, SIGNAL(signal), receiver, SLOT(slot));
$@I(82"8$<6*3('A"S42D)"<(2&P$@I(82")#)2(<"*)"8$1('(."*+"20("+(C2")(82*$+AT

X$' moc"2$"/$'Q"8$''(823#="/("<%)2"6%2"20("83&))".(!*+*2*$+"*+"&"0(&.('"!*3(=")(6&'&2("!'$<"20(
/0('( sender"&+. receiver"&'("6$*+2(')"2$ QObject)"&+."/0('( signal"&+. slot"&'("!%+82*$+
*<63(<(+2&2*$+"!*3(A"B0("8$.(",(+('&2(."@# moc"*+83%.()"20*)"0(&.('"!*3("&+."&..)")$<("FGG"<&,*8
)*,+&2%'()"/*20$%2"6&'&<(2('"+&<()A"B0( SIGNAL()"&+. SLOT()"<&8'$)"())(+2*&33#"8$+1('2"20(*'
$!"*2)"$/+A
&',%<(+2"2$"&")2'*+,A

F3&))()"20&2"%)("20( Q_OBJECT"<&8'$"<%)2"0&1( moc"'%+"$+"20(<A"B0*)"*)+D2"&"6'$@3(<"@(8&%)( qmake


+"20("(C&<63()"/("0&1(")((+")$"!&'= /("0&1("&3/&#)"8$++(82(.".*!!('(+2")*,+&3)"2$".*!!('(+2")3$2)A
&%2$<&2*8&33#"&..)"20("+(8())&'#"'%3()"2$"20("<&Q(!*3(A"K%2"*!"#$%"!$',(2"2$"'(,(+('&2("#$%'"<&Q(!*3( B0('("&'("$20('"6$))*@*3*2*()"2$"8$+)*.('A
%)*+, qmake"&+. moc"*)+D2"'%+="20("3*+Q('"/*33"8$<63&*+"20&2")$<("!%+82*$+)"&'(".(83&'(."@%2"+$2
*<63(<(+2(.A"B0("<())&,()"8&+"@("!&*'3#"$@)8%'(A";FF"6'$.%8()"/&'+*+,)"3*Q("20*)"$+(L
• F:%&1!":,+&2,:&-%&28::%2/%A&/8&9,:L&1+8/1P

finddialog.o: In function 'FindDialog::tr(char const*, char const*)': • connect(slider, SIGNAL(valueChanged(int)),
/usr/lib/qt/src/corelib/global/qglobal.h:1430: undefined reference to • spinBox, SLOT(setValue(int)));
'FindDialog::staticMetaObject' • connect(slider, SIGNAL(valueChanged(int)),
• this, SLOT(updateStatusBarIndicator(int)));

E*)%&3"FGGD)"$%26%2")2&'2)"3*Q("20*)L -0(+"20(")*,+&3"*)"(<*22(.="20(")3$2)"&'("8&33(."$+("&!2('"20("$20('="*+"&+"%+)6(8*!*(."$'.('A

• 5,:L&1!":,+1&2,:&-%&28::%2/%A&/8&/0%&1,9%&1+8/P
finddialog.obj : error LNK2001: unresolved external symbol •
"public:~virtual int __thiscall MyClass::qt_metacall(enum QMetaObject • connect(lcd, SIGNAL(overflow()),
::Call,int,void * *)" • this, SLOT(handleMathError()));
• connect(calculator, SIGNAL(divisionByZero()),
• this, SLOT(handleMathError()));
!"20*)"(1('"0&66(+)"2$"#$%="'%+ qmake"&,&*+"2$"%6.&2("20("<&Q(!*3(="20(+"'(@%*3."20("&663*8&2*$+A
-0(+"(*20('")*,+&3"*)"(<*22(.="20(")3$2"*)"8&33(.A
Z$/"'%+"20("6'$,'&<A" !")0$'28%2"Q(#)"&'(")0$/+"$+"#$%'"63&2!$'<="1('*!#"20&2"20(")0$'28%2"Q(#)
H32G-="H32GF="H32GK="&+."H32GX"2'*,,('"20("8$''(82"@(0&1*$'A"?'())"B&@"2$"+&1*,&2("20'$%,0"20( • *&1!":,+&2,:&-%&28::%2/%A&/8&,:8/0%$&1!":,+P
/*.,(2)"/*20"20("Q(#@$&'.A"B0(".(!&%32"2&@"$'.('"*)"20("$'.('"*+"/0*80"20("/*.,(2)"/('("8'(&2(.A •
B0*)"8&+"@("80&+,(."%)*+, QWidget::setTabOrder()A • connect(lineEdit, SIGNAL(textChanged(const QString &)),
• this, SIGNAL(updateRecord(const QString &)));
?'$1*.*+,"&")(+)*@3("2&@"$'.('"&+."Q(#@$&'.")0$'28%2)"(+)%'()"20&2"%)(')"/0$".$+D2"/&+2"2$"S$'
8&++$2T"%)("&"<$%)("&'("&@3("2$"<&Q("!%33"%)("$!"20("&663*8&2*$+A"X%33"Q(#@$&'."8$+2'$3"*)"&3)$
-0(+"20("!*')2")*,+&3"*)"(<*22(.="20(")(8$+.")*,+&3"*)"(<*22(."&)"/(33A"H6&'2"!'$<"20&2=
&66'(8*&2(."@#"!&)2"2#6*)2)A
)*,+&3)*,+&3"8$++(82*$+)"&'("*+.*)2*+,%*)0&@3("!'$<")*,+&3)3$2"8$++(82*$+)A

+ F0&62('"a="/("/*33"%)("20("X*+.".*&3$,"*+)*.("&"'(&3"&663*8&2*$+="&+."/("/*33"8$++(82"20(
• @8::%2/!8:1&2,:&-%&$%98C%AP
findPrevious()"&+. findNext()")*,+&3)"2$")$<(")3$2)A

• disconnect(lcd, SIGNAL(overflow()),
• this, SLOT(handleMathError()));
B0("<(80&+*)<"*)"8&33(."20( 1,'$C&BD,('0 . ',1= &+."*2"6'$1*.()"2/$"Q(#")('1*8()L
B0*)"*)"'&'(3#"+((.(.="@(8&%)("42"&%2$<&2*8&33#"'(<$1()"&33"8$++(82*$+)"*+1$31*+,"&+"$@I(82 )*,+&3))3$2)"&+."*+2'$)6(82*$+A"B0("*+2'$)6(82*$+"!%+82*$+&3*2#"*)"+(8())&'#"!$'
/0(+"20&2"$@I(82"*)".(3(2(.A *<63(<(+2*+,")*,+&3)"&+.")3$2)="&+."&33$/)"&663*8&2*$+"6'$,'&<<(')"2$"$@2&*+"e<(2&P
*+!$'<&2*$+e"&@$%2 QObject")%@83&))()"&2"'%+P2*<(="*+83%.*+,"20("3*)2"$!")*,+&3)"&+.")3$2)
B$")%88())!%33#"8$++(82"&")*,+&3"2$"&")3$2"S$'"2$"&+$20('")*,+&3T="20(#"<%)2"0&1("20(")&<("6&'&<(2(' )%66$'2(."@#"20("$@I(82"&+."*2)"83&))"+&<(A"B0("<(80&+*)<"&3)$")%66$'2)"6'$6('2*()
2#6()"*+"20(")&<("$'.('L S!$' 2'04, !"#,+T"&+."2(C2"2'&+)3&2*$+"S!$'"*+2('+&2*$+&3*[&2*$+T="&+."*2"3&#)"20(
!$%+.&2*$+"!$'"42"78'*62"!$'"H663*8&2*$+)"S47HTA

connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), 72&+.&'."FGG".$()+D2"6'$1*.(")%66$'2"!$'"20(".#+&<*8"<(2&P*+!$'<&2*$+"+((.(."@#"42D)


this, SLOT(processReply(int, const QString &)));
<(2&P$@I(82")#)2(<A"42")$31()"20*)"6'$@3(<"@#"6'$1*.*+,"&")(6&'&2("2$$3= moc="20&2
6&')() Q_OBJECT"83&))".(!*+*2*$+)"&+."<&Q()"20("*+!$'<&2*$+"&1&*3&@3("20'$%,0"FGG
!%+82*$+)A"7*+8( moc"*<63(<(+2)"&33"*2)"!%+82*$+&3*2#"%)*+,"6%'("FGG="42D)"<(2&P$@I(82
9C8(62*$+&33#="*!"&")*,+&3"0&)"<$'("6&'&<(2(')"20&+"20(")3$2"*2"*)"8$++(82(."2$="20("&..*2*$+&3 )#)2(<"/$'Q)"/*20"&+#"FGG"8$<6*3('A
6&'&<(2(')"&'(")*<63#"*,+$'(.L
B0("<(80&+*)<"/$'Q)"&)"!$33$/)L
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(checkErrorCode(int))); • B0( Q_OBJECT"<&8'$".(83&'()")$<("*+2'$)6(82*$+"!%+82*$+)"20&2"<%)2"@(
*<63(<(+2(."*+"(1('# QObject")%@83&))L metaObject()= TR()= qt_metacall()="&+."&
!(/"<$'(A
• 42D) moc"2$$3",(+('&2()"*<63(<(+2&2*$+)"!$'"20("!%+82*$+)".(83&'(."@# Q_OBJECT
!"20("6&'&<(2('"2#6()"&'("*+8$<6&2*@3(="$'"*!"20(")*,+&3"$'"20(")3$2".$()+D2"(C*)2="42"/*33"*))%("&
&+."!$'"&33"20(")*,+&3)A
/&'+*+,"&2"'%+P2*<("*!"20("&663*8&2*$+"*)"@%*32"*+".(@%,"<$.(A"7*<*3&'3#="42"/*33",*1("&"/&'+*+,"*!
• QObject"<(<@('"!%+82*$+)")%80"&) connect()"&+. disconnect()"%)("20(
6&'&<(2('"+&<()"&'("*+83%.(."*+"20(")*,+&3"$'")3$2")*,+&2%'()A
*+2'$)6(82*$+"!%+82*$+)"2$".$"20(*'"/$'QA

7$"!&'="/("0&1("$+3#"%)(.")*,+&3)"&+.")3$2)"/*20"/*.,(2)A"K%2"20("<(80&+*)< *2)(3!"*)"*<63(<(+2(."*+
H33"$!"20*)"*)"0&+.3(."&%2$<&2*8&33#"@# qmake= moc="&+. QObject=")$"#$%"'&'(3#"+((."2$
QObject"&+."*)+D2"3*<*2(."2$";f "6'$,'&<<*+,A"B0("<(80&+*)<"8&+"@("%)(."@#"&+# QObject")%@83&))L
20*+Q"&@$%2"*2A"K%2"*!"#$%"&'("8%'*$%)="#$%"8&+"80(8Q"$%2"20( QMetaObject"83&))
.$8%<(+2&2*$+"&+."0&1("&"3$$Q"&2"20("FGG")$%'8("!*3()",(+('&2(."@# moc"2$")(("0$/"20(
class Employee : public QObject *<63(<(+2&2*$+"/$'Q)A
{
Q_OBJECT
public:
Employee() { mySalary = 0; } Rapid Dialog Design
int salary() const { return mySalary; }
public slots:
void setSalary(int newSalary); 42"*)".()*,+(."2$"@("63(&)&+2"&+."*+2%*2*1("2$"0&+.P8$.(="&+."*2"*)"+$2"%+%)%&3"!$'"6'$,'&<<(')"2$
signals: .(1(3$6"(+2*'("42"&663*8&2*$+)"6%'(3#"@#"/'*2*+,"FGG")$%'8("8$.(A"72*33="<&+#"6'$,'&<<(')"6'(!('"2$
void salaryChanged(int newSalary); %)("&"1*)%&3"&66'$&80"!$'".()*,+*+,"!$'<)="@(8&%)("20(#"!*+."*2"<$'("+&2%'&3"&+."!&)2('"20&+"0&+.P
private: 8$.*+,="&+."20(#"/&+2"2$"@("&@3("2$"(C6('*<(+2"/*20"&+."80&+,(".()*,+)"<$'("R%*8Q3#"&+."(&)*3#
int mySalary; 20&+"*)"6$))*@3("/*20"0&+.P8$.(."!$'<)A
};
void Employee::setSalary(int newSalary) 2'04, !"#,+"(C6&+.)"20("$62*$+)"&1&*3&@3("2$"6'$,'&<<(')"@#"6'$1*.*+,"&"1*)%&3".()*,+
{ 8&6&@*3*2#A2'04, !"#,+"8&+"@("%)(."2$".(1(3$6"&33"$'"I%)2")$<("$!"&+"&663*8&2*$+D)"!$'<)A"X$'<)"20&2
if (newSalary != mySalary) { &'("8'(&2(."%)*+, 2'04, !"#,+"(+."%6"&)"FGG"8$.(=")$ 2'04, !"#,+"8&+"@("%)(."/*20"&
mySalary = newSalary;
8$+1(+2*$+&3"2$$3"80&*+"&+."*<6$)()"+$")6(8*&3"'(R%*'(<(+2)"$+"20("8$<6*3('A
emit salaryChanged(mySalary);
}
} +"20*)")(82*$+="/("/*33"%)( 2'04, !"#,+"2$"8'(&2("20(";$P2$PF(33".*&3$,")0$/+"*+ X*,%'("`AbA"H+.
/0(20('"/(".$"*2"*+"8$.("$'"*+ 2'04, !"#,+="8'(&2*+,"&".*&3$,"&3/&#)"*+1$31()"20(")&<(
!%+.&<(+2&3")2(6)L
Z$2*8("0$/"20( setSalary()")3$2"*)"*<63(<(+2(.A"-("$+3#"(<*2"20( salary-Changed()")*,+&3"*!
• F'(&2("&+."*+*2*&3*[("20("80*3."/*.,(2)A
newSalary != mySalaryA"B0*)"(+)%'()"20&2"8#83*8"8$++(82*$+)".$+D2"3(&."2$"*+!*+*2("3$$6)A
• ?%2"20("80*3."/*.,(2)"*+"3&#$%2)A
• 7(2"20("2&@"$'.('A
• 9)2&@3*)0")*,+&3)3$2"8$++(82*$+)A
Qt's Meta-Object System • <63(<(+2"20(".*&3$,D)"8%)2$<")3$2)A

5+("$!"42D)"<&I$'"&80*(1(<(+2)"0&)"@((+"20("(C2(+)*$+"$!"FGG"/*20"&"<(80&+*)<"!$' !"#$%&)(>(&40%&Q8O/8O@%++&A!,+8"
8'(&2*+,"*+.(6(+.(+2")$!2/&'("8$<6$+(+2)"20&2"8&+"@("@$%+."2$,(20('"/*20$%2"&+#
8$<6$+(+2"Q+$/*+,"&+#20*+,"&@$%2"20("$20('"8$<6$+(+2)"*2"*)"8$++(82(."2$A
B$"3&%+80 2'04, !"#,+="83*8Q"42"@#"B'$332(80"1bACA#h>()*,+('"*+"20("72&'2"<(+%"$+"-*+.$/)="2#6(
designer"$+"20("8$<<&+."3*+("$+"f+*C="$'".$%@3(P83*8Q">()*,+('"*+"20(":&8"57"J"X*+.('A"-0(+ 2' 7(2"(&80"/*.,(2D)"6'$6('2*()"%)*+, 2'04, !"#,+D)"6'$6('2#"(.*2$'L
4, !"#,+")2&'2)="*2"/*33"6$6"%6"&"3*)2"$!"2(<63&2()A"F3*8Q"20("e-*.,(2e"2(<63&2(="20(+"83*8Q"5lA"SB0(
e>*&3$,"/*20"K%22$+)"K$22$<e"2(<63&2("<*,02"3$$Q"2(<62*+,="@%2"!$'"20*)"(C&<63("/("/*33"8'(&2("20( ^A F3*8Q"20("2(C2"3&@(3A":&Q(")%'("20&2"*2) objectName"6'$6('2#"*)"e3&@(3e"&+.")(2"20( text
5l"&+."F&+8(3"@%22$+)"@#"0&+."2$")0$/"0$/"*2"*)".$+(AT"g$%")0$%3."+$/"0&1("&"/*+.$/"8&33(. 6'$6('2#"2$"ejF(33"O$8&2*$+LeA
ef+2*23(.eA `A F3*8Q"20("3*+("(.*2$'A":&Q(")%'("20&2"20( objectName"6'$6('2#"*)"e3*+(9.*2eA
aA F3*8Q"20("!*')2"@%22$+A"7(2"20( objectName"6'$6('2#"2$"e$QK%22$+e="20( enabled"6'$6('2#"2$
K#".(!&%32=2'04, !"#,+D)"%)('"*+2('!&8("8$+)*)2)"$!")(1('&3"2$6P3(1(3"/*+.$/)A" !"#$%"6'(!('"&+":> P e!&3)(e="20( text"6'$6('2#"2$"e5le="&+."20( default"6'$6('2#"2$"e2'%(eA
)2#3("*+2('!&8(="/*20"$+("2$6P3(1(3"/*+.$/"&+.")(1('&3")%@P/*+.$/)="83*8Q"9.*2hf)('" +2('!&8( bA F3*8Q"20(")(8$+."@%22$+A"7(2"20( objectName"6'$6('2#"2$"e8&+8(3K%22$+e"&+."20( text"6'$6('2#
:$.(h>$8Q(."-*+.$/A 2$"eF&+8(3eA
dA F3*8Q"20("!$'<D)"@&8Q,'$%+."2$")(3(82"20("!$'<"*2)(3!A"7(2 objectName"2$"e;$B$F(33>*&3$,e"&+.
B0("!*')2")2(6"*)"2$"8'(&2("20("80*3."/*.,(2)"&+."63&8("20(<"$+"20("!$'<A"F'(&2("$+("3&@(3="$+("3*+( windowTitle"2$"e;$"2$"F(33eA
(.*2$'="$+("0$'*[$+2&3")6&8('="&+."2/$"6%)0"@%22$+)A"X$'"(&80"*2(<=".'&,"*2)"+&<("$'"*8$+"!'$< 2'
4, !"#,+D)"/*.,(2"@$C"&+.".'$6"20("*2(<"'$%,03#"/0('("*2")0$%3.",$"$+"20("!$'<A"B0(")6&8('"*2(<= H33"20("/*.,(2)"3$$Q"!*+("+$/="(C8(62"20("2(C2"3&@(3="/0*80")0$/)"jF(33"O$8&2*$+A"F3*8Q"9.*2h9.*2
/0*80"*)"*+1*)*@3("*+"20("!*+&3"!$'<="*)")0$/+"*+ 2'04, !"#,+"&)"&"@3%(")6'*+,A K%..*()"2$"(+2('"&")6(8*&3"<$.("20&2"&33$/)"#$%"2$")(2"@%..*()A"Z(C2="83*8Q"20("3&@(3"&+.".'&,"20(
'(."&''$/"3*+("2$"20("3*+("(.*2$'="20(+"'(3(&)(A"B0("3&@(3")0$%3."+$/")0$/ F(33"O$8&2*$+"&+."0&1("20(
!"#$%&)(?( !".1$%-'1;&!:&A82R%A&.!:A8.&98A%&8:&S!:A8.1 3*+("(.*2$'"&)"*2)"@%..#A"F3*8Q"9.*2h9.*2"-*.,(2)"2$"3(&1("@%..#"<$.(A

[View full size image]


!"#$%&)(E(&40%&78$9&.!/0&=$8=%$/!%1&1%/

B0("+(C2")2(6"*)"2$"3&#"$%2"20("/*.,(2)"$+"20("!$'<L

'( F3*8Q"20("F(33"O$8&2*$+"3&@(3"&+."6'())"70*!2"&)"#$%"83*8Q"20("3*+("(.*2$'"+(C2"2$"*2")$"20&2"20(#
&'("@$20")(3(82(.A F3*8Q"X$'<hO&#"5%2"N$'*[$+2&33#A

)( F3*8Q"20(")6&8('="20(+"0$3."70*!2"&)"#$%"83*8Q"20("!$'<D)"5l"&+."F&+8(3"@%22$+)A F3*8Q"X$'<hO&#
5%2"N$'*[$+2&33#A

;( F3*8Q"20("@&8Q,'$%+."$!"20("!$'<"2$".()(3(82"&+#")(3(82(."*2(<)="20(+"83*8Q"X$'<hO&#"5%2
Z$/".'&,"20("@$22$<"$!"20("!$'<"%6"2$"<&Q("*2")0$'2('A"B0*)")0$%3."6'$.%8("&"!$'<"20&2"*)")*<*3&'"2$ E('2*8&33#A
X*,%'("`AkA">$+D2")6(+."2$$"<%80"2*<("6$)*2*$+*+,"20("*2(<)"$+"20("!$'<Y"42D)"3&#$%2"<&+&,(')"/*33
3&#"20(<"$%2"6'(8*)(3#"3&2('"$+A >( F3*8Q"X$'<hH.I%)2"7*[("2$"'()*[("20("!$'<"2$"*2)"6'(!(''(.")*[(A

!"#$%&)(D(&40%&78$9&.!/0&189%&.!A"%/1
B0("'(."3*+()"20&2"&66(&'"$+"20("!$'<")0$/"20("3&#$%2)"20&2"0&1("@((+"8'(&2(.A"B0(#".$+D2"&66(&'
/0(+"20( !$'<"*)"'%+A
!"#$%&)(I(&40%&78$9&.!/0&/0%&+,L8#/1 {
public:
QLabel *label;
QLineEdit *lineEdit;
QSpacerItem *spacerItem;
QPushButton *okButton;
QPushButton *cancelButton;
...
void setupUi(QWidget *widget) {
...
}
};

Z$/"83*8Q"9.*2h9.*2"B&@"5'.('A"H"+%<@('"*+"&"@3%("'(82&+,3("/*33"&66(&'"+(C2"2$"(1('#"/*.,(2"20&2
8&+"&88(62"!$8%)A"F3*8Q"(&80"/*.,(2"*+"2%'+"*+"20("$'.('"#$%"/&+2"20(<"2$"&88(62"!$8%)="20(+"83*8Q 56)#8)&)$*').#(-*77#.!)7&='#,&6)$,'#*&B#<'#(-*774#E6)&#")#%7)#'6)#+!$/#,& main.cpp;#")#($)*')#*
9.*2h9.*2"-*.,(2)"2$"3(&1("2&@"$'.('"<$.(A QDialog#*&.#9*77#,'#'! setupUi()4

!"#$%&)(K(&G%//!:"&/0%&78$9B1&/,-&8$A%$ F+#B!%#$%&#'6)#9$!8$*/#&!";#'6)#.,*-!8#",--#"!$0;#A%'#,'#.!)7&='#+%&(',!&#)G*('-B#*7#")#"*&'D

• 56)#HI#A%''!&#,7#*-"*B7#.,7*A-).4
• 56)#>*&()-#A%''!&#.!)7#&!'6,&84
• 56)#-,&)#).,'!$#*(()9'7#*&B#')G';#,&7')*.#!+#!&-B#*(()9',&8#:*-,.#()--#-!(*',!&74

E)#(*&#/*0)#'6)#.,*-!8#+%&(',!&#9$!9)$-B#AB#"$,',&8#7!/)#(!.)4#56)#(-)*&)7'#*99$!*(6#,7#'!#($)*')
*#&)"#(-*77#'6*'#,&6)$,'7#A!'6 QDialog#*&. Ui::GoToCell-Dialog#*&.#'6*'#,/9-)/)&'7#'6)#/,77,&8
+%&(',!&*-,'B#1'6%7#9$!:,&8#'6)#*.*8)#'6*'#*&B#7!+'"*$)#9$!A-)/#(*&#A)#7!-:).#7,/9-B#AB#*..,&8
*&!'6)$#-*B)$#!+#,&.,$)(',!&34#H%$#&*/,&8#(!&:)&',!&#,7#'!#8,:)#'6,7#&)"#(-*77#'6)#7*/)#&*/)#*7#'6)
uicJ8)&)$*').#(-*77#A%'#",'6!%'#'6) Ui::#9$)+,G4

B$"6'(1*(/"20(".*&3$,="83*8Q"20("X$'<h?'(1*(/"<(+%"$62*$+A"F0(8Q"20("2&@"$'.('"@#"6'())*+,"B&@ K7,&8#*#')G'#).,'!$;#($)*')#*#+,-)#(*--). gotocelldialog.h#'6*'#(!&'*,&7#'6)#+!--!",&8#(!.)D


'(6(&2(.3#A"F3$)("20(".*&3$,"%)*+,"20("83$)("@%22$+"*+"20("2*23("@&'A

7&1("20(".*&3$,"&) gotocelldialog.ui"*+"&".*'(82$'#"8&33(. gotocell="&+."8'(&2("& main.cpp"!*3("*+"20( #ifndef GOTOCELLDIALOG_H


)&<(".*'(82$'#"%)*+,"&"63&*+"2(C2"(.*2$'L #define GOTOCELLDIALOG_H
#include <QDialog>
#include "ui_gotocelldialog.h"
#include <QApplication> class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
#include <QDialog> {
#include "ui_gotocelldialog.h" Q_OBJECT
int main(int argc, char *argv[]) public:
{ GoToCellDialog(QWidget *parent = 0);
QApplication app(argc, argv); private slots:
Ui::GoToCellDialog ui; void on_lineEdit_textChanged();
QDialog *dialog = new QDialog; };
ui.setupUi(dialog); #endif
dialog->show();
return app.exec();
}
56)#,/9-)/)&'*',!&#A)-!&87#,& gotocelldialog.cppD

!"#$%& qmake#'!#($)*')#* .pro#+,-)#*&.#*#/*0)+,-)#1qmake -project2 qmake goto-cell.pro34#56) qmake #include <QtGui>


'!!-#,7#7/*$'#)&!%86#'!#.)')('#'6)#%7)$#,&')$+*()#+,-) goto-celldialog.ui#*&.#'!#8)&)$*')#'6) #include "gotocelldialog.h"
*99$!9$,*')#/*0)+,-)#$%-)7#'!#,&:!0) uic;#<'=7#%7)$#,&')$+*()#(!/9,-)$4#56) uic#'!!-#(!&:)$'7 GoToCellDialog::GoToCellDialog(QWidget *parent)
gotocelldialog.ui#,&'!#>??#*&.#9%'7#'6)#$)7%-'#,& ui_gotocelldialog.h4 : QDialog(parent)
{
setupUi(this);
56)#8)&)$*'). ui_gotocelldialog.h#+,-)#(!&'*,&7#'6)#.)+,&,',!&#!+#'6) Ui::GoToCellDialog#(-*77;#"6,(6 QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
,7 *#>??#)@%,:*-)&'#!+#'6) gotocelldialog.ui#+,-)4#56)#(-*77#.)(-*$)7#/)/A)$#:*$,*A-)7#'6*'#7'!$) lineEdit->setValidator(new QRegExpValidator(regExp, this));
'6)#+!$/=7#(6,-.#",.8)'7#*&.#-*B!%'7;#*&.#* setupUi()#+%&(',!&#'6*'#,&,',*-,C)7#'6)#+!$/4#56) connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
8)&)$*').#(-*77#-!!07#-,0)#'6,7D connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
}
void GoToCellDialog::on_lineEdit_textChanged()
class Ui::GoToCellDialog {
okButton->setEnabled(lineEdit->hasAcceptableInput()); return app.exec();
} }

F&#'6)#(!&7'$%('!$;#")#(*-- setupUi()#'!#,&,',*-,C)#'6)#+!$/4#56*&07#'!#/%-',9-)#,&6)$,'*&();#")#(*& [)A%,-.#'6)#*99-,(*',!&#1qmake -project2 qmake gotocell.pro3#*&.#$%&#,'#*8*,&4#5B9)#NLRVN#,&#'6)#-,&)


*(()77 Ui::GoToCellDialog=7#/)/A)$7#.,$)('-B4#L+')$#($)*',&8#'6)#%7)$#,&')$+*(); setupUi()#",--#*-7! ).,';#*&.#&!',()#'6*'#'6)#HI#A%''!&#A)(!/)7#)&*A-).4#5$B#'B9,&8#7!/)#$*&.!/#')G'#'!#7))#6!"#'6)
*%'!/*',(*--B#(!&&)('#*&B#7-!'7#'6*'#+!--!"#'6)#&*/,&8#(!&:)&',!& on_objectName_signalName()#'! :*-,.*'!$#.!)7#,'7#Z!A4#>-,(0#>*&()-#'!#(-!7)#'6)#.,*-!84
'6)#(!$$)79!&.,&8 objectName=7 signalName()#7,8&*-4#F&#!%$#)G*/9-);#'6,7#/)*&7#'6*' setupUi()#",--
)7'*A-,76#'6)#+!--!",&8#7,8&*-7-!'#(!&&)(',!&D H&)#!+#'6)#A)*%',)7#!+#%7,&8 !"#$%&'($)#,7#'6*'#,'#*--!"7#9$!8$*//)$7#8$)*'#+$)).!/#'!#/!.,+B
'6),$#+!$/#.)7,8&7#",'6!%'#A),&8#+!$().#'!#(6*&8)#'6),$#7!%$()#(!.)4#E6)&#B!%#.):)-!9#*#+!$/
9%$)-B#AB#"$,',&8#>??#(!.);#(6*&8)7#'!#'6)#.)7,8&#(*&#A)#@%,')#',/)J(!&7%/,&84#E,'6 !
connect(lineEdit, SIGNAL(textChanged(const QString &)), #$%&'($);#&!#',/)#,7#-!7'#7,&() uic#7,/9-B#$)8)&)$*')7#'6)#7!%$()#(!.)#+!$#*&B#+!$/7#'6*'#6*:)
this, SLOT(on_lineEdit_textChanged())); (6*&8).4#56)#.,*-!8=7#%7)$#,&')$+*()#,7#7*:).#,&#* .ui#+,-)#1*&#\]^JA*7).#+,-)#+!$/*'3;#"6,-)#(%7'!/
+%&(',!&*-,'B#,7#,/9-)/)&').#AB#7%A(-*77,&8#'6) uicJ8)&)$*').#(-*774

L-7!#,&#'6)#(!&7'$%('!$;#")#7)'#%9#*#:*-,.*'!$#'!#$)7'$,('#'6)#$*&8)#!+#'6)#,&9%'4#<'#9$!:,.)7#'6$))
A%,-'J,&#:*-,.*'!$#(-*77)7D QIntValidator; QDoubleValidator;#*&. QRegExpValidator4#M)$)#")#%7)#*
QRegExpValidator#",'6#'6)#$)8%-*$#)G9$)77,!&#NOLJP*JCQORJSQOTJSQUT;VWN;#"6,(6#/)*&7D#L--!"#!&)
%99)$(*7)#!$#-!")$(*7)#-)'')$;#+!--!").#AB#!&)#.,8,'#,&#'6)#$*&8)#R#'!#S;#+!--!").#AB#C)$!;#!&);#!$
'"!#.,8,'7#)*(6#,&#'6)#$*&8)#T#'!#S4#1X!$#*&#,&'$!.%(',!&#'!#$)8%-*$#)G9$)77,!&7;#7))#'6) QRegExp#(-*77 Shape-Changing Dialogs
.!(%/)&'*',!&43
E)#6*:)#7))&#6!"#'!#($)*')#.,*-!87#'6*'#*-"*B7#76!"#'6)#7*/)#",.8)'7#"6)&):)$#'6)B#*$)#%7).4#F&
YB#9*77,&8 this#'!#'6) QRegExpValidator#(!&7'$%('!$;#")#/*0)#,'#*#(6,-.#!+#'6) GoToCellDialog 7!/)#(*7)7;#,'#,7#.)7,$*A-)#'!#9$!:,.)#.,*-!87#'6*'#(*&#(6*&8)#76*9)4#56)#'"!#/!7'#(!//!&#0,&.7#!+
!AZ)('4#YB#.!,&8#7!;#")#.!&='#6*:)#'!#"!$$B#*A!%'#.)-)',&8#'6) QRegExpValidator#-*')$2#,'#",--#A) 76*9)J(6*&8,&8#.,*-!87#*$) $*!$(%&+(",&-.+'%#*&. /0.!&12-'$",&-.+'%4#Y!'6#'B9)7#!+#.,*-!8#(*&
.)-)').#*%'!/*',(*--B#"6)&#,'7#9*$)&'#,7#.)-)').4 A)#,/9-)/)&'). ,&#<';#),'6)$#9%$)-B#,&#(!.)#!$#%7,&8 !"#$%&'($)4

<'=7#9*$)&'(6,-.#/)(6*&,7/#,7#,/9-)/)&').#,& QObject4#E6)&#")#($)*')#*&#!AZ)('#1*#",.8)'; _G')&7,!&#.,*-!87#%7%*--B#9$)7)&'#*#7,/9-)#*99)*$*&()#A%'#6*:)#*#'!88-)#A%''!&#'6*'#*--!"7#'6)#%7)$


:*-,.*'!$;#!$#*&B#!'6)$#0,&.3#",'6#*#9*$)&';#'6)#9*$)&'#*..7#'6)#!AZ)('#'!#'6)#-,7'#!+#,'7#(6,-.$)&4 '!#7",'(6#A)'"))&#'6)#.,*-!8=7#7,/9-)#*&.#)G')&.).#*99)*$*&()74#_G')&7,!&#.,*-!87#*$)#(!//!&-B
E6)&#'6)#9*$)&'#,7#.)-)').;#,'#"*-07#'6$!%86#,'7#-,7'#!+#(6,-.$)&#*&.#.)-)')7#)*(6#(6,-.4#56)#(6,-.$)& %7).#+!$#*99-,(*',!&7#'6*'#*$)#'$B,&8#'!#(*')$#+!$#A!'6#(*7%*-#*&.#9!")$#%7)$7;#6,.,&8#'6)#*.:*&().
'6)/7)-:)7#'6)&#.)-)')#*--#!+#'6),$#(6,-.$)&;#*&. 7!#!&#$)(%$7,:)-B#%&',-#&!&)#$)/*,&4 !9',!&7#%&-)77#'6)#%7)$#)G9-,(,'-B#*707#'!#7))#'6)/4#F&#'6,7#7)(',!&;#")#",--#%7) !"#$%&'($)#'!
($)*')#'6)#)G')&7,!&#.,*-!8#76!"&#,& X,8%$)#V4RT4
56)#9*$)&'(6,-.#/)(6*&,7/#8$)*'-B#7,/9-,+,)7#/)/!$B#/*&*8)/)&';#$).%(,&8#'6)#$,70#!+#/)/!$B
-)*074#56)#!&-B#!AZ)('7#")#/%7'#.)-)')#)G9-,(,'-B#*$)#'6)#!AZ)('7#")#($)*')#",'6 new#*&.#'6*'#6*:)#&! !"#$%&'()*(&+,%&-.$/&0!12."&3!/,&4!562%&170&%8/%70%0&166%1$179%4
9*$)&'4#L&.#,+#")#.)-)') *#(6,-.#!AZ)('#A)+!$)#,'7#9*$)&';#<'#",--#*%'!/*',(*--B#$)/!:)#'6*'#!AZ)('
+$!/#'6)#9*$)&'=7#-,7'#!+#(6,-.$)&4 [View full size image]

X!$#",.8)'7;#'6)#9*$)&'#6*7#*&#*..,',!&*-#/)*&,&8D#>6,-.#",.8)'7#*$)#76!"&#",'6,&#'6)#9*$)&'=7
*$)*4#E6)&#")#.)-)')#'6)#9*$)&'#",.8)';#&!'#!&-B#.!)7#'6)#(6,-.#:*&,76#+$!/#/)/!$B;#,'#*-7!
:*&,76)7#+$!/#'6)#7($))&4

L'#'6)#)&.#!+#'6)#(!&7'$%('!$;#")#(!&&)('#'6)#HI#A%''!&#'! QDialog=7 accept()#7-!'#*&.#'6)#>*&()-


A%''!&#'!#'6) reject()#7-!'4#Y!'6#7-!'7#(-!7)#'6)#.,*-!8;#A%' accept()#7)'7#'6)#.,*-!8=7#$)7%-'#:*-%)#'!
QDialog::Accepted#1"6,(6#)@%*-7#R3;#*&. reject()#7)'7#'6)#:*-%)#'! QDialog::Rejected#1"6,(6#)@%*-7
T34#E6)&#")#%7)#'6,7#.,*-!8;#")#(*&#%7)#'6)#$)7%-'#:*-%)#'!#7))#,+#'6)#%7)$#(-,(0).#HI#*&.#*('
*((!$.,&8-B4

56) on_lineEdit_textChanged()#7-!'#)&*A-)7#!$#.,7*A-)7#'6)#HI#A%''!&;#*((!$.,&8#'!#"6)'6)$#'6)#-,&)
).,'#(!&'*,&7#*#:*-,.#()--#-!(*',!&4 QLineEdit::hasAcceptableInput()#%7)7#'6)#:*-,.*'!$#")#7)'#,&#'6)
(!&7'$%('!$4

56,7#(!/9-)')7#'6)#.,*-!84#E)#(*&#&!"#$)"$,') main.cpp#'!#%7)#,'D

#include <QApplication> 56)#.,*-!8#,7#*#`!$'#.,*-!8#,&#* 79$)*.76))'#*99-,(*',!&;#"6)$)#'6)#%7)$#(*&#7)-)('#!&)#!$#7):)$*-


#include "gotocelldialog.h" (!-%/&7#'!#7!$'#!&4#56)#.,*-!8=7#7,/9-)#*99)*$*&()#*--!"7#'6)#%7)$#'!#)&')$#*#7,&8-)#7!$'#0)B;#*&.#,'7
int main(int argc, char *argv[]) )G')&.).#*99)*$*&()#9$!:,.)7#+!$#'"!#)G'$*#7!$'#0)B74#L#]!$)#A%''!&#-)'7#'6)#%7)$#7",'(6#A)'"))&
{
'6)#7,/9-)#*&.#)G')&.).#*99)*$*&()74
QApplication app(argc, argv);
GoToCellDialog *dialog = new GoToCellDialog;
dialog->show(); E)#",--#($)*')#'6)#",.8)'#",'6#,'7#)G')&.).#*99)*$*&()#,& !"#$%&'($);#*&.#6,.)#'6)#7)(!&.*$B#*&.
')$',*$B#0)B7#*'#$%&J',/)#*7#&)).).4#56)#",.8)'#-!!07#(!/9-,(*').;#A%'#,'=7#+*,$-B#)*7B#'!#.!#,& !
#$%&'($)4#56)#'$,(0#,7#'!#.!#'6)#9$,/*$B#0)B#9*$'#+,$7';#'6)&#.%9-,(*')#,'#'",()#'!#!A'*,&#'6)
7)(!&.*$B#*&.#')$',*$B#0)B7D

R4 >-,(0#X,-)a )"#X!$/#*&.#(6!!7)#'6)#Nb,*-!8#",'6#Y%''!&7#[,86'N#')/9-*')4
V4 >$)*')#'6)#]!$)#A%''!&#*&.#.$*8#,'#,&'!#'6)#:)$',(*-#-*B!%';#A)-!"#'6)#:)$',(*-#79*()$4#`)'#'6)
]!$)#A%''!&=7 text#9$!9)$'B#'!#Nc]!$)N;#*&.#,'7 checkable#9$!9)$'B#'!#N'$%)N4 `)'#'6)#HI
A%''!&=7 default#9$!9)$'B#'!#N'$%)N4
d4 >$)*')#*#8$!%9#A!G;#'"!#-*A)-7;#'"!#(!/A!A!G)7;#*&.#!&)#6!$,C!&'*-#79*()$;#*&.#9%'#'6)/
*&B"6)$)#!&#'6) +!$/4
e4 b$*8#'6)#A!''!/#$,86'#(!$&)$#!+#'6)#8$!%9#A!G#'!#/*0)#,'#-*$8)$4#56)&#/!:)#'6)#!'6)$
",.8)'7#,&'!#'6)#8$!%9#A!G#*&.#9!7,',!&#'6)/#*99$!G,/*')-B#*7#76!"&#,& X,8%$)#V4RR#1*34

!"#$%&'())(&:1;!7"&.#/&/,%&"$.#6&<.8=4&9,!20$%7&!7&1&"$!0

Of,)"#+%--#7,C)#,/*8)Q

h4 >-,(0#'6)#+!$/#'!#.)7)-)('#*&B#7)-)(').#",.8)'7;#'6)&#(-,(0#X!$/a^*B#H%'#,&#*#l$,.4 56)#+!$/
76!%-.#&!"#/*'(6 X,8%$)#V4RV#1A34
j4 `)'#'6)#'"!#:)$',(*-#79*()$#,')/7= sizeHint#9$!9)$'B#'!#OVT;#TQ4

56)#$)7%-',&8#8$,.#-*B!%'#6*7#'"!#(!-%/&7#*&.#+!%$#$!"7;#8,:,&8#*#'!'*-#!+#),86'#()--74#56)#i$,/*$B
I)B#8$!%9#A!G;#'6)#-)+'/!7'#:)$',(*-#79*()$#,')/;#'6)#`)(!&.*$B#I)B#8$!%9#A!G;#*&.#'6)#5)$',*$B
g4 b$*8#'6)#$,86'#).8)#!+#'6)#7)(!&.#(!/A!A!G#'!#/*0)#,'#*A!%'#'",()#*7#",.)#*7#'6)#+,$7' I)B#8$!%9#A!G#)*(6#!((%9B#*#7,&8-)#()--4#56)#:)$',(*-#-*B!%'#'6*'#(!&'*,&7#'6)#HI;#>*&()-;#*&.#]!$)
(!/A!A!G4 A%''!&7#!((%9,)7#'"!#()--74#56*'#-)*:)7#'"!#)/9'B#()--7#,&#'6)#A!''!/J$,86'#!+#'6)#.,*-!84#F+#'6,7#,7&='
"6*'#B!%#6*:);#%&.!#'6)#-*B!%';#$)9!7,',!&#'6)#",.8)'7;#*&.#'$B#*8*,&4
h4 `)'#'6)#8$!%9#A!G=7 title#9$!9)$'B#'!#Nci$,/*$B#I)BN;#'6)#+,$7'#-*A)-=7 text#9$!9)$'B#'!
N>!-%/&DN;#*&.#'6)#7)(!&.#-*A)-=7 text#9$!9)$'B#'!#NH$.)$DN4
j4 [,86'J(-,(0#'6)#+,$7'#(!/A!A!G#*&.#(6!!7)#_.,'#F')/7#+$!/#'6)#(!&')G'#/)&%#'!#9!9#%9 ! [)&*/)#'6)#+!$/#N`!$'b,*-!8N#*&.#(6*&8)#'6)#",&.!"#','-)#'!#N`!$'N4#`)'#'6)#&*/)7#!+#'6)#(6,-.
#$%&'($)=7#(!/A!A!G ).,'!$4 >$)*')#!&)#,')/#",'6#'6)#')G'#N !&)N4 ",.8)'7#'!#'6!7)#76!"&#,& X,8%$)#V4Rd4
k4 [,86'J(-,(0#'6)#7)(!&.#(!/A!A!G#*&.#(6!!7)#_.,'#F')/74#>$)*')#*&#NL7()&.,&8N#,')/#*&.#*
Nb)7()&.,&8N#,')/4 !"#$%&'()?(&@15!7"&/,%&>.$5=4&3!0"%/4
S4 >-,(0#'6)#8$!%9#A!G;#'6)&#(-,(0#X!$/a^*B#H%'#,&#*#l$,.4#>-,(0#'6)#8$!%9#A!G#*8*,&#*&.#(-,(0
X!$/aL.Z%7'#`,C)4 56,7#",--#9$!.%()#'6)#-*B!%'#76!"&#,& X,8%$)#V4RR#1A34 [View full size image]

F+#*#-*B!%'#.!)7&='#'%$&#!%'#@%,')#$,86'#!$#,+#B!%#/*0)#*#/,7'*0);#B!%#(*&#*-"*B7#(-,(0#_.,'aK&.!#!$
X!$/aY$)*0#^*B!%';#'6)&#$)9!7,',!&#'6)#",.8)'7#*&.#'$B#*8*,&4

E)#",--#&!"#*..#'6)#`)(!&.*$B#I)B#*&.#5)$',*$B#I)B#8$!%9#A!G)7D

R4 ]*0)#'6)#.,*-!8#",&.!"#'*--#)&!%86#+!$#'6)#)G'$*#9*$'74
V4 M!-.#.!"&#'6)#>'$-#0)B#1L-'#!&#'6)#]*(3#*&.#(-,(0#'6)#i$,/*$B#I)B#8$!%9#A!G#'!#($)*')#*#(!9B
!+#'6)#8$!%9#A!G#1*&.#,'7#(!&')&'73#!&#'!9#!+#'6)#!$,8,&*-4#b$*8#'6)#(!9B#A)-!"#'6)#!$,8,&*-
8$!%9#A!G;#"6,-)#7',--#9$)77,&8#>'$-#1!$#L-'34#[)9)*'#'6,7#9$!()77#'!#($)*')#*#'6,$.#8$!%9#A!G;
.$*88,&8#,'#A)-!"#'6)#7)(!&.#8$!%9#A!G4
d4 >6*&8)#'6),$ title#9$!9)$',)7#'!#Nc`)(!&.*$B#I)BN#*&.#Nc5)$',*$B#I)BN4
e4 >$)*')#!&)#:)$',(*-#79*()$#*&.#9-*()#,'#A)'"))&#'6)#9$,/*$B#0)B#8$!%9#A!G#*&.#'6)
7)(!&.*$B#0)B#8$!%9#A!G4
g4 L$$*&8)#'6)#",.8)'7#,&#'6)#8$,.J-,0)#9*'')$&#76!"&#,& X,8%$)#V4RV#1*34

!"#$%&'()'(&:1;!7"&.#/&/,%&>.$5=4&9,!20$%7 !7&1&"$!0

Of,)"#+%--#7,C)#,/*8)Q

>-,(0#_.,'a_.,'#5*A#H$.)$4#>-,(0#)*(6#(!/A!A!G#,&#'%$&#+$!/#'!9/!7'#'!#A!''!//!7';#'6)&#(-,(0#'6)
HI;#>*&()-;#*&.#]!$)#A%''!&7#!&#'6)#$,86'#7,.)4#>-,(0#_.,'a_.,'#E,.8)'7#'!#-)*:)#'*A#!$.)$#/!.)4

!"#'6*'#'6)#+!$/#6*7#A))&#.)7,8&).;#")#*$)#$)*.B#'!#/*0)#,'#+%&(',!&*-#AB#7)'',&8#%9#7!/)
7,8&*-7-!'#(!&&)(',!&74 !"#$%&'($)#*--!"7#%7#'!#)7'*A-,76#(!&&)(',!&7#A)'"))&#",.8)'7#'6*'#*$)#9*$'
!+#'6)#7*/)#+!$/4#E)#&)).#'!#)7'*A-,76#'"!#(!&&)(',!&74

>-,(0#_.,'a_.,'#`,8&*-7m`-!'7#'!#)&')$ !"#$%&'($)=7#(!&&)(',!&#/!.)4#>!&&)(',!&7#*$)#$)9$)7)&').
AB#A-%)#*$$!"7#A)'"))&#'6)#+!$/=7#",.8)'74#Y)(*%7)#") (6!7)#'6)#Nb,*-!8#",'6#Y%''!&7#[,86'N
')/9-*');#'6)#HI#*&.#>*&()-#A%''!&7#*$)#*-$)*.B#(!&&)(').#'! QDialog=7 accept()#*&. reject()
7-!'74#>!&&)(',!&7#*$)#*-7!#-,7').#,& !"#$%&'($)=7#7,8&*-m7-!'#).,'!$#",&.!"4

5!#)7'*A-,76#*#(!&&)(',!&#A)'"))&#'"!#",.8)'7;#(-,(0#'6)#7)&.)$#",.8)'#*&.#.$*8#'6)#$).#*$$!"#-,&)
'!#'6)#$)(),:)$#",.8)';#'6)&#$)-)*7)4#56,7#9!97#%9#*#.,*-!8#'6*'#*--!"7#B!%#'!#(6!!7)#'6)#7,8&*-#*&.
'6)#7-!'#'!#(!&&)('4

!"#$%&'()A(&B.77%9/!7"&/,%&>.$5=4&3!0"%/4

56)#7)(!&.#(!&&)(',!&#,7#A)'"))&#'6) moreButton=7 toggled(bool)#7,8&*-#*&.#'6) tertiaryGroupBox=7


setVisible(bool)#7-!'4#H&()#'6)#(!&&)(',!&7#6*:)#A))&#/*.);#(-,(0#_.,'a_.,'#E,.8)'7#'!#-)*:)
(!&&)(',!&#/!.)4

`*:)#'6)#.,*-!8#*7 sortdialog.ui#,&#*#.,$)('!$B#(*--). sort4#5!#*..#(!.)#'!#'6)#+!$/;#")#",--#%7)#'6)


7*/)#/%-',9-)#,&6)$,'*&()#*99$!*(6#'6*'#")#%7).#+!$#'6)#l!J'!J>)--#.,*-!8#,&#'6)#9$):,!%7#7)(',!&4

X,$7';#($)*')#* sortdialog.h#+,-)#",'6#'6)#+!--!",&8#(!&')&'7D

#ifndef SORTDIALOG_H
#define SORTDIALOG_H
#include <QDialog>
#include "ui_sortdialog.h"
class SortDialog : public QDialog, public Ui::SortDialog
{
Q_OBJECT
public:
SortDialog(QWidget *parent = 0);
void setColumnRange(QChar first, QChar last);
};
#endif

56)&#($)*') sortdialog.cppD

56)#+,$7'#(!&&)(',!&#'!#)7'*A-,76#,7#A)'"))&#'6) moreButton#*&.#'6) secondary-GroupBox4#b$*8#'6)#$). 1 #include <QtGui>


*$$!"#-,&)#A)'"))&#'6)7)#'"!#",.8)'7;#'6)&#(6!!7) toggled(bool)#*7#'6)#7,8&*-#*&. 2 #include "sortdialog.h"
setVisible(bool)#*7#'6)#7-!'4#YB#.)+*%-'; !"#$%&'($)#.!)7&='#-,7' setVisible(bool)#,&#'6)#-,7'#!+ 3 SortDialog::SortDialog(QWidget *parent)
7-!'7;#A%'#,'#",--#*99)*$#,+#B!%#)&*A-)#'6)#`6!"#*--#7,8&*-7#*&.#7-!'7#!9',!&4 4 : QDialog(parent)
5 {
6 setupUi(this);
!"#$%&'()C( !"#$%&'($)=4&9.77%9/!.7&%0!/.$ 7 secondaryGroupBox->hide();
8 tertiaryGroupBox->hide();
[View full size image]
9 layout()->setSizeConstraint(QLayout::SetFixedSize);
10 setColumnRange('A', 'Z');
11 }
12 void SortDialog::setColumnRange(QChar first, QChar last)
13 {
14 primaryColumnCombo->clear();
15 secondaryColumnCombo->clear();
16 tertiaryColumnCombo->clear();
17 secondaryColumnCombo->addItem(tr("None"));
18 tertiaryColumnCombo->addItem(tr("None")); • L QtreeWidget#(*&#A)#%7).#",'6#* QStackedWidget#,&#*#7,/,-*$#"*B#'!#* QListWidget4
19 primaryColumnCombo->setMinimumSize(
20 secondaryColumnCombo->sizeHint());
56) QStackedWidget#(-*77#,7#(!:)$).#,& >6*9')$#h#1^*B!%'#]*&*8)/)&'34
21 QChar ch = first;
22 while (ch <= last) {
23 primaryColumnCombo->addItem(QString(ch));
24 secondaryColumnCombo->addItem(QString(ch));
25 tertiaryColumnCombo->addItem(QString(ch)); Dynamic Dialogs
26 ch = ch.unicode() + 1;
27 } bB&*/,(#.,*-!87#*$)#.,*-!87#'6*'#*$)#($)*').#+$!/ !"#$%&'($) .ui#+,-)7#*'#$%&J',/)4#F&7')*.#!+
28 } (!&:)$',&8#'6) .ui#+,-)#'!#>??#(!.)#%7,&8 uic;#")#(*&#-!*.#'6)#+,-)#*'#$%&J',/)#%7,&8#'6) QUiLoader
(-*77D

56)#(!&7'$%('!$#6,.)7#'6)#7)(!&.*$B#*&.#')$',*$B#9*$'7#!+#'6)#.,*-!84#F'#*-7!#7)'7#'6) sizeConstraint
9$!9)$'B#!+#'6)#+!$/=7#-*B!%'#'! QLayout::SetFixedSize;#/*0,&8#'6)#.,*-!8#&!&J$)7,C*A-)#AB#'6)#%7)$4 QUiLoader uiLoader;
56)#-*B!%'#'6)&#'*0)7#!:)$#'6)#$)79!&7,A,-,'B#+!$#$)7,C,&8;#*&.#$)7,C)7#'6)#.,*-!8#*%'!/*',(*--B#"6)& QFile file("sortdialog.ui");
(6,-.#",.8)'7#*$)#76!"&#!$#6,..)&;#)&7%$,&8#'6*'#'6)#.,*-!8#,7#*-"*B7#.,79-*B).#*'#,'7#!9',/*-#7,C)4 QWidget *sortDialog = uiLoader.load(&file);
if (sortDialog) {
...
56) setColumnRange()#7-!'#,&,',*-,C)7#'6)#(!&')&'7#!+#'6)#(!/A!A!G)7#A*7).#!&#'6)#7)-)(').#(!-%/&7 }
,&#'6)#79$)*.76))'4#E)#,&7)$'#*#N !&)N#,')/#,&#'6)#(!/A!A!G)7#+!$#'6)#1!9',!&*-3#7)(!&.*$B#*&.
')$',*$B#0)B74

E)#(*&#*(()77#'6)#+!$/=7#(6,-.#",.8)'7#%7,&8 QObject::findChild<T>()D
^,&)7#RS#*&.#VT#9$)7)&'#*#7%A'-)#-*B!%'#,.,!/4#56) QWidget::sizeHint()#+%&(',!&#$)'%$&7#*#",.8)'=7
N,.)*-N#7,C);#"6,(6#'6)#-*B!%'#7B7')/#'$,)7#'!#6!&!$4#56,7#)G9-*,&7#"6B#.,++)$)&'#0,&.7#!+#",.8)'7;#!$
7,/,-*$#",.8)'7#",'6#.,++)$)&'#(!&')&'7;#/*B#A)#*77,8&).#.,++)$)&'#7,C)7#AB#'6)#-*B!%'#7B7')/4#X!$
QComboBox *primaryColumnCombo =
(!/A!A!G)7;#'6,7#/)*&7#'6*'#'6)#7)(!&.*$B#*&.#')$',*$B#(!/A!A!G)7;#"6,(6#(!&'*,&#N !&)N;#)&.#%9 sortDialog->findChild<QComboBox *>("primaryColumnCombo");
-*$8)$#'6*&#'6)#9$,/*$B#(!/A!A!G;#"6,(6#(!&'*,&7#!&-B#7,&8-)J-)'')$#)&'$,)74#5!#*:!,.#'6,7 if (primaryColumnCombo) {
,&(!&7,7')&(B;#")#7)'#'6)#9$,/*$B#(!/A!A!G=7#/,&,/%/#7,C)#'!#'6) %$3+(,-)4#(!/A!A!G=7#,.)*- ...
7,C)4 }

M)$)#,7#* main()#')7'#+%&(',!&#'6*'#7)'7#'6)#$*&8)#'!#,&(-%.)#(!-%/&7#=>=#'!#=X= *&.#'6)&#76!"7#'6)


.,*-!8D 56) findChild<T>()#+%&(',!&#,7#*#')/9-*')#/)/A)$#+%&(',!&#'6*'#$)'%$&7#'6)#(6,-.#!AZ)('#'6*'
/*'(6)7#'6)#8,:)&#&*/)#*&.#'B9)4#Y)(*%7)#!+#*#(!/9,-)$#-,/,'*',!&;#,'#,7#&!'#*:*,-*A-)#+!$#]`f>#h4#F+
B!%#&)).#'!#%7)#'6)#]`f>#h#(!/9,-)$;#(*--#'6) qFindChild<T>()#8-!A*-#+%&(',!&#,&7')*.;#"6,(6#"!$07
#include <QApplication>
)G*('-B#'6)#7*/)#"*B4
#include "sortdialog.h"
int main(int argc, char *argv[])
{ 56) QUiLoader#(-*77#,7#-!(*').#,&#*#7)9*$*')#-,A$*$B4#5!#%7) QUiLoader#+$!/#*#<'#*99-,(*',!&;#")#/%7'
QApplication app(argc, argv); *..#'6,7#-,&)#'!#'6)#*99-,(*',!&=7 .pro#+,-)D
SortDialog *dialog = new SortDialog;
dialog->setColumnRange('C', 'F');
dialog->show(); CONFIG += uitools
return app.exec();
}
bB&*/,(#.,*-!87#/*0)#,'#9!77,A-)#'!#(6*&8)#'6)#-*B!%'#!+#*#+!$/#",'6!%'#$)(!/9,-,&8#'6)#*99-,(*',!&4
56)B#(*&#*-7!#A) %7).#'!#($)*')#'6,&J(-,)&'#*99-,(*',!&7;#"6)$)#'6)#)G)(%'*A-)#/)$)-B#6*7#*#+$!&'J
56*'#(!/9-)')7#'6)#)G')&7,!&#.,*-!84#L7#'6)#)G*/9-)#,--%7'$*')7;#*&#)G')&7,!&#.,*-!8#,7&='#/%(6#/!$) )&.#+!$/#A%,-'J,&#*&.#*--#!'6)$#+!$/7#*$)#($)*').#*7#$)@%,$).4
.,++,(%-'#'!#.)7,8&#'6*&#*#9-*,&#.,*-!8D#L--#")#&)).).#"*7#*#'!88-)#A%''!&;#*#+)"#)G'$*#7,8&*-7-!'
(!&&)(',!&7;#*&.#*#&!&J$)7,C*A-)#-*B!%'4#F&#9$!.%(',!&#*99-,(*',!&7;#,'#,7#@%,')#(!//!&#+!$#'6)
A%''!&#'6*'#(!&'$!-7#'6)#)G')&7,!&#'!#76!"#'6)#')G'#L.:*&().#nnn#"6)&#!&-B#'6)#A*7,(#.,*-!8#,7
:,7,A-)#*&.#L.:*&().#ooo#"6)&#'6)#)G')&7,!&#,7#76!"&4#56,7#,7#)*7B#'!#*(6,):)#,&#<'#AB#(*--,&8 Built-in Widget and Dialog Classes
setText()#!&#'6) QPushButton#"6)&):)$#,'#,7#(-,(0).4
<'#9$!:,.)7#*#(!/9-)')#7)'#!+#A%,-'J,&#",.8)'7#*&.#(!//!&#.,*-!87#'6*'#(*')$#+!$#/!7'#7,'%*',!&74#F&
56)#!'6)$#(!//!&#'B9)#!+#76*9)J(6*&8,&8#.,*-!87;#/%-',J9*8)#.,*-!87;#*$)#):)&#)*7,)$#'!#($)*')#,& '6,7#7)(',!&;#")#9$)7)&'#7($))&76!'7#!+#*-/!7'#*--#!+#'6)/4#L#+)"#79)(,*-,C).#",.8)'7#*$)#.)+)$$).
<';#),'6)$#,&#(!.)#!$#%7,&8 !"#$%&'($)4 `%(6#.,*-!87#(*&#A)#A%,-'#,&#/*&B#.,++)$)&'#"*B74 %&',-#-*')$D#]*,&#",&.!"#",.8)'7#7%(6#*7 QMenuBar; QToolBar;#*&. QStatusBar#*$)#(!:)$).#,& >6*9')$
d;#*&.#-*B!%'J$)-*').#",.8)'7#7%(6#*7 QSplitter#*&. QScrollArea#*$)#(!:)$).#,& >6*9')$#h4#]!7'#!+
• L QTabWidget#(*&#A)#%7).#,&#,'7#!"&#$,86'4#F'#9$!:,.)7#*#'*A#A*$#*-!&8#'6)#'!9#'6*'#(!&'$!-7#* '6)#A%,-'J,&#",.8)'7#*&.#.,*-!87#*$)#%7).#,&#'6)#)G*/9-)7#9$)7)&').#,&#'6,7#A!!04#F&#'6)#7($))&76!'7
A%,-'J,& QStackedWidget4 A)-!";#'6)#",.8)'7#*$)#76!"&#%7,&8#'6)#i-*7',@%)#7'B-)4
• L QListWidget#*&.#* QStackedWidget#(*&#A)#%7).#'!8)'6)$;#",'6#'6) QList-Widget=7#(%$$)&'
,')/#.)')$/,&,&8#"6,(6#9*8)#'6) QStackedWidget#76!"7;#AB#(!&&)(',&8#'6) !"#$%&'()D(&E/=4&<#//.7&3!0"%/4
QListWidget::currentRowChanged()#7,8&*-#'!#'6) QStackedWidget::setCurrentIndex()#7-!'4
<'#9$!:,.)7#+!%$#0,&.7#!+#NA%''!&7ND QPushButton; QToolButton; QCheckBox;#*&. QRadioButton4
QPushButton#*&. QToolButton#*$)#/!7'#(!//!&-B#%7).#'!#,&,',*')#*&#*(',!&#"6)&#'6)B#*$)#(-,(0).;
A%'#'6)B#(*&#*-7!#A)6*:)#-,0)#'!88-)#A%''!&7#1(-,(0#'!#9$)77#.!"&;#(-,(0#'!#$)7'!$)34 QCheckBox#(*&#A)
%7).#+!$#,&.)9)&.)&'#!&m!++#!9',!&7;#"6)$)*7 QRadioButton7#*$)#&!$/*--B#/%'%*--B#)G(-%7,:)4

!"#$%&'()F(&E/=4&4!7"2%G61"%&9.7/1!7%$&3!0"%/4
[View full size image]

56)#,')/#:,)"7#*$)#!9',/,C).#+!$#6*&.-,&8#-*$8)#*/!%&'7#!+#.*'*#*&.#!+')&#%7)#7($!--#A*$74#56)#7($!--
A*$#/)(6*&,7/#,7#,/9-)/)&').#,& QAbstractScrollArea;#*#A*7)#(-*77#+!$#,')/#:,)"7#*&.#!'6)$#0,&.7
!+#7($!--*A-)#",.8)'74

<'#9$!:,.)7#*#+)"#",.8)'7#'6*'#*$)#%7).#9%$)-B#+!$#.,79-*B,&8#,&+!$/*',!&4 QLabel#,7#'6)#/!7'
,/9!$'*&'#!+#'6)7);#*&.#,'#(*&#A)#%7).#+!$#76!",&8#$,(6#')G'#1%7,&8#*#7,/9-)#M5]^J-,0)#7B&'*G3#*&.
,/*8)74

<'=7#(!&'*,&)$#",.8)'7#*$)#",.8)'7#'6*'#(!&'*,&#!'6)$#",.8)'74 QFrame#(*&#*-7!#A)#%7).#!&#,'7#!"&#'! QTextBrowser#,7#*#$)*.J!&-B QTextEdit#7%A(-*77#'6*'#6*7#A*7,(#M5]^#7%99!$'#,&(-%.,&8#-,7'7;#'*A-)7;


7,/9-B#.$*"#-,&)7#*&.#,7#,&6)$,').#AB#/*&B#!'6)$#",.8)'#(-*77)7;#,&(-%.,&8 QToolBox#*&. QLabel4 ,/*8)7;#*&.#6B9)$')G'#-,&074 !"5%%&%!-(!#%7)7 QTextBrowser#'!#9$)7)&'#.!(%/)&'*',!&#'!#'6)#%7)$4

!"#$%&'()H(&E/=4&5#2/!G61"%&9.7/1!7%$&3!0"%/4 !"#$%&'('*(&E/=4&0!4621;&3!0"%/4
[View full size image]

QTabWidget#*&. QToolBox#*$)#/%-',J9*8)#",.8)'74#_*(6#9*8)#,7#*#(6,-.#",.8)';#*&.#'6)#9*8)7#*$)
&%/A)$).#+$!/#T4

!"#$%&'()I(&E/=4&!/%5&J!%3&3!0"%/4
[View full size image]

<'#9$!:,.)7#7):)$*-#",.8)'7 +!$#.*'*#)&'$B4 QLineEdit#(*&#$)7'$,('#,'7#,&9%'#%7,&8#*&#,&9%'#/*70#!$#*


[View full size image]
:*-,.*'!$4 QTextEdit#,7#* QAbstractScrollArea#7%A(-*77#(*9*A-)#!+#).,',&8#-*$8)#*/!%&'7#!+#')G'4

!"#$%&'(')(&E/=4&!76#/&3!0"%/4

<'#9$!:,.)7#*#:)$7*',-)#/)77*8)#A!G#*&.#*&#)$$!$#.,*-!8#'6*'#$)/)/A)$7#"6,(6#/)77*8)7#,'#6*7
76!"&4#56)#9$!8$)77#!+#',/)J(!&7%/,&8#!9)$*',!&7#(*&#A)#,&.,(*').#%7,&8 QProgressDialog#!$#%7,&8
'6) QProgressBar#76!"&#)*$-,)$4 QInputDialog#,7#:)$B#(!&:)&,)&'#"6)&#*#7,&8-)#-,&)#!+#')G'#!$#*#7,&8-)
&%/A)$#,7#$)@%,$).#+$!/#'6)#%7)$4

L#-!'#!+#$)*.BJ'!J%7)#+%&(',!&*-,'B#,7#9$!:,.).#AB#'6)#A%,-'J,&#",.8)'7#*&.#(!//!&#.,*-!874#]!$)
79)(,*-,C).#$)@%,$)/)&'7#(*&#!+')&#A)#7*',7+,).#AB#7)'',&8#",.8)'#9$!9)$',)7;#!$#AB#(!&&)(',&8#7,8&*-7
'!#7-!'7#*&.#,/9-)/)&',&8#(%7'!/#A)6*:,!$#,&#'6)#7-!'74

!"#$%&'('A(&E/=4&>%%0<19K&0!12."4
[View full size image]

<'#9$!:,.)7#'6)#7'*&.*$.#7)'#!+#(!//!&#.,*-!87#'6*'#/*0)#,'#)*7B#'!#*70#'6)#%7)$#'!#7)-)('#*#(!-!$;
+!&';#!$#+,-);#!$#'!#9$,&'#*#.!(%/)&'4

!"#$%&'(''(&E/=4&9.2.$&0!12."&170&>.7/&0!12."
[View full size image]

F&#7!/)#7,'%*',!&7;#,'#/*B#A)#.)7,$*A-)#'!#($)*')#*#(%7'!/#",.8)'#+$!/#7($*'(64#<'#/*0)7#'6,7
7'$*,86'+!$"*$.;#*&.#(%7'!/#",.8)'7#(*&#*(()77#*--#'6)#7*/)#9-*'+!$/J,&.)9)&.)&'#.$*",&8
+%&(',!&*-,'B#*7#<'=7#A%,-'J,&#",.8)'74#>%7'!/#",.8)'7#(*&#):)&#A)#,&')8$*').#",'6 !"#$%&'($)#7!
'6*'#'6)B#(*&#A)#%7).#,&#'6)#7*/)#"*B#*7#<'=7#A%,-'J,&#",.8)'74 >6*9')$#g#)G9-*,&7#6!"#'!#($)*')
(%7'!/#",.8)'74
H&#E,&.!"7#*&.#]*(#H`#\;#<'#%7)7#'6)#&*',:)#.,*-!87#$*'6)$#'6*&#,'7#!"&#(!//!&#.,*-!87#"6)&
9!77,A-)4

!"#$%&'('?(&E/=4&>!2%&170&6$!7/&0!12."4
Subclassing QMainWindow
Chapter 3. Creating Main Windows L&#*99-,(*',!&=7#/*,&#",&.!"#,7#($)*').#AB#7%A(-*77,&8 QMainWindow4#]*&B#!+#'6)#')(6&,@%)7#")#7*"
,& >6*9')$#V#+!$#($)*',&8#.,*-!87#*$)#*-7!#$)-):*&'#+!$#($)*',&8#/*,&#",&.!"7;#7,&()#A!'6 QDialog#*&.
QMainWindow#,&6)$,'#+$!/ QWidget4
• 6073.-%%&('" 8-&(9&(,+:
• ;)$-!&('"8$(0%"-(,"<++.7-)%
]*,&#",&.!"7#(*&#A)#($)*').#%7,&8 !"#$%&'($);#A%'#,&#'6,7#(6*9')$#") ",--#.!#):)$B'6,&8#,&#(!.)
• 6$!!&('"=2"!>$"6!-!0%"?-)
'!#.)/!&7'$*')#6!"#,'=7#.!&)4#F+#B!%#9$)+)$#'6)#/!$)#:,7%*-#*99$!*(6;#7))#'6)#N>$)*',&8#]*,&
• @/2.$/$(!&('"!>$"A&.$"8$(0
E,&.!"7#,& !"#$%&'($)N#(6*9')$#,& !"#$%&'($)=7#!&-,&)#/*&%*-4
• =%&('"#&-.+'%
• 6!+)&('"6$!!&('%
• 80.!&2.$"#+30/$(!% 56)#7!%$()#(!.)#+!$#'6)#`9$)*.76))'#*99-,(*',!&=7#/*,&#",&.!"#,7#79$)*. *($!77 mainwindow.h#*&.
• 62.-%>"63)$$(% mainwindow.cpp4#^)'=7#7'*$'#",'6#'6)#6)*.)$#+,-)D

56,7#(6*9')$#",--#')*(6#B!%#6!"#'!#($)*')#/*,&#",&.!"7#%7,&8#<'4#YB#'6)#)&.;#B!%#",--#A)#*A-)#'!
#ifndef MAINWINDOW_H
A%,-.#*&#*99-,(*',!&=7#)&',$)#%7)$#,&')$+*();#(!/9-)')#",'6#/)&%7;#'!!-A*$7;#7'*'%7#A*$;#*&.#*7#/*&B
#define MAINWINDOW_H
.,*-!87#*7#'6)#*99-,(*',!&#$)@%,$)74 #include <QMainWindow>
class QAction;
L&#*99-,(*',!&=7#/*,&#",&.!"#9$!:,.)7#'6)#+$*/)"!$0#%9!&#"6,(6#'6)#*99-,(*',!&=7#%7)$#,&')$+*()#,7 class QLabel;
A%,-'4#56)#/*,&#",&.!"#+!$#'6)#`9$)*.76))'#*99-,(*',!&#76!"&#,& X,8%$)#d4R#",--#+!$/#'6)#A*7,7#!+ class FindDialog;
'6,7#(6*9')$4#56)#`9$)*.76))'#*99-,(*',!&#/*0)7#%7)#!+#'6)#X,&.;#l!J'!J>)--;#*&.#`!$'#.,*-!87#'6*' class Spreadsheet;
")#($)*').#,& >6*9')$#V4 class MainWindow : public QMainWindow
{
Q_OBJECT
!"#$%&?()(&-6$%104,%%/&1662!91/!.7 public:
[View full size image]
MainWindow();
protected:
void closeEvent(QCloseEvent *event);

E)#.)+,&)#'6)#(-*77 MainWindow#*7#*#7%A(-*77#!+ QMainWindow4#F'#(!&'*,&7#'6) Q_OBJECT#/*($!#7,&()#,'


9$!:,.)7#,'7#!"&#7,8&*-7#*&.#7-!'74

56) closeEvent()#+%&(',!&#,7#*#:,$'%*-#+%&(',!&#,& QWidget#'6*'#,7#*%'!/*',(*--B#(*--).#"6)&#'6)#%7)$


(-!7)7#'6)#",&.!"4#F'#,7#$),/9-)/)&').#,& MainWindow#7!#'6*'#")#(*&#*70#'6)#%7)$#'6)#7'*&.*$.
@%)7',!&#Nb!#B!%#"*&'#'!#7*:)#B!%$#(6*&8)7pN#*&.#'!#7*:)#%7)$#9$)+)$)&()7#'!#.,704

private slots:
void newFile();
void open();
bool save();
bool saveAs();
void find();
void goToCell();
void sort();
void about();

`!/)#/)&%#!9',!&7;#-,0)#X,-)a )"#*&.#M)-9aLA!%';#*$)#,/9-)/)&').#*7#9$,:*')#7-!'7#,& MainWindow4


]!7'#7-!'7#6*:) void#*7#'6),$#$)'%$&#:*-%);#A%' save()#*&. saveAs()#$)'%$&#* bool4#56)#$)'%$&#:*-%)#,7
,8&!$).#"6)&#*#7-!'#,7#)G)(%').#,&#$)79!&7)#'!#*#7,8&*-;#A%'#"6)&#")#(*--#*#7-!'#*7#*#+%&(',!&#'6)
$)'%$&#:*-%)#,7#*:*,-*A-)#'!#%7#Z%7'#*7#,'#,7#"6)&#")#(*--#*&B#!$.,&*$B#>??#+%&(',!&4

Y)6,&.#/!7'#lKF#*99-,(*',!&7#-,)7#*#A!.B#!+#(!.)#'6*'#9$!:,.)7#'6)#%&.)$-B,&8#+%&(',!&*-,'B+!$
)G*/9-);#(!.)#'!#$)*.#*&.#"$,')#+,-)7#!$#'!#9$!()77#'6)#.*'*#9$)7)&').#,&#'6)#%7)$#,&')$+*()4#F& void openRecentFile();
>6*9')$#e;#")#",--#7))#6!"#'!#,/9-)/)&'#7%(6#+%&(',!&*-,'B;#*8*,&#%7,&8#'6)#`9$)*.76))'#*99-,(*',!& void updateStatusBar();
*7#!%$#)G*/9-)4 void spreadsheetModified();
private:
void createActions();
void createMenus(); createActions();
void createContextMenu(); createMenus();
void createToolBars(); createContextMenu();
void createStatusBar(); createToolBars();
void readSettings(); createStatusBar();
void writeSettings(); readSettings();
bool okToContinue(); findDialog = 0;
bool loadFile(const QString &fileName); setWindowIcon(QIcon(":/images/icon.png"));
bool saveFile(const QString &fileName); setCurrentFile("");
void setCurrentFile(const QString &fileName); }
void updateRecentFileActions();
QString strippedName(const QString &fullFileName);
F&#'6)#(!&7'$%('!$;#")#A)8,&#AB#($)*',&8#* Spreadsheet#",.8)'#*&.#7)'',&8#,'#'!#A)#'6)#/*,&#",&.!"=7
()&'$*-#",.8)'4#56)#()&'$*-#",.8)'#!((%9,)7#'6)#/,..-)#!+#'6)#/*,&#",&.!"#17)) X,8%$)#d4V34#56)
56)#/*,&#",&.!"#&)).7#7!/)#/!$)#9$,:*')#7-!'7#*&.#7):)$*-#9$,:*')#+%&(',!&7#'!#7%99!$'#'6)#%7)$ Spreadsheet#(-*77#,7#* QTableWidget#7%A(-*77#",'6#7!/)#79$)*.76))'#(*9*A,-,',)7;#7%(6#*7#7%99!$'#+!$
,&')$+*()4 79$)*.76))'#+!$/%-*74 E)#",--#,/9-)/)&'#,'#,& >6*9')$#e4

Spreadsheet *spreadsheet;
!"#$%&?('( QMainWindow=4&1$%14
FindDialog *findDialog;
QLabel *locationLabel;
QLabel *formulaLabel;
QStringList recentFiles;
QString curFile;
enum { MaxRecentFiles = 5 };
QAction *recentFileActions[MaxRecentFiles];
QAction *separatorAction;
QMenu *fileMenu;
QMenu *editMenu;
...
QToolBar *fileToolBar;
QToolBar *editToolBar;
QAction *newAction;
QAction *openAction;
...
QAction *aboutQtAction;
};
#endif E)#(*--#'6)#9$,:*')#+%&(',!&7 createActions(); createMenus(); createContext-Menu();
createToolBars();#*&. createStatusBar()#'!#7)'#%9#'6)#$)7'#!+#'6)#/*,&#",&.!"4#E)#*-7!#(*--#'6)
9$,:*')#+%&(',!& readSettings()#'!#$)*.#'6)#*99-,(*',!&=7#7'!$).#7)'',&874
F&#*..,',!&#'!#,'7#9$,:*')#7-!'7#*&.#9$,:*')#+%&(',!&7; MainWindow#*-7!#6*7#-!'7#!+#9$,:*')#:*$,*A-)74#L--
!+#'6)7)#",--#A)#)G9-*,&).#*7#") %7)#'6)/4 E)#,&,',*-,C)#'6) findDialog#9!,&')$#'!#A)#*#&%--#9!,&')$2#'6)#+,$7'#',/) MainWindow::find()#,7#(*--).;
")#",--#($)*')#'6) FindDialog#!AZ)('4
E)#",--#&!"#$):,)"#'6)#,/9-)/)&'*',!&D
L'#'6)#)&.#!+#'6)#(!&7'$%('!$;#")#7)'#'6)#",&.!"=7#,(!&#'! icon.png;#*#i l#+,-)4#<' 7%99!$'7#/*&B
,/*8)#+!$/*'7;#,&(-%.,&8#Y]i;#lFX;OqQ#ri_l;#i l;#i ];#\Y];#*&.#\i]4#>*--,&8
#include <QtGui> QWidget::setWindowIcon()#7)'7#'6)#,(!&#76!"&#,&#'6)#'!9J-)+'#(!$&)$#!+#'6)#",&.!"4#K&+!$'%&*')-B;
#include "finddialog.h" '6)$)#,7#&!#9-*'+!$/J,&.)9)&.)&'#"*B#!+#7)'',&8#'6)#*99-,(*',!&#,(!&#'6*'#*99)*$7#!&#'6)#.)70'!94
#include "gotocelldialog.h" i-*'+!$/J79)(,+,(#9$!().%$)7#*$)#)G9-*,&).#*' 6''9Dmm.!(4'$!--')(64(!/me4Rm*99,(!&46'/-4
#include "mainwindow.h"
#include "sortdialog.h" [*]
GIF support is disabled in Qt by default because the decompression algorithm used by GIF files was patented in some countries
#include "spreadsheet.h" where software patents are recognized. We believe that this patent has now expired worldwide. To enable GIF support in Qt, pass
the -qt-gif command-line option to the configure script or set the appropriate option in the Qt installer.

E)#,&(-%.)#'6) <QtGui>#6)*.)$#+,-);#"6,(6#(!&'*,&7#'6)#.)+,&,',!&#!+#*--#'6)#<'#(-*77)7#%7).#,&#!%$ lKF#*99-,(*',!&7#8)&)$*--B#%7)#/*&B#,/*8)74#56)$)#*$)#7):)$*-#/)'6!.7#+!$#9$!:,.,&8#,/*8)7#'!#'6)


7%A(-*774#E)#*-7!#,&(-%.)#7!/)#(%7'!/#6)*.)$#+,-)7;#&!'*A-B finddialog.h; gotocelldialog.h;#*&. *99-,(*',!&4 56)#/!7'#(!//!&#*$)D
sortdialog.h#+$!/ >6*9')$#V4
• `'!$,&8#,/*8)7#,&#+,-)7#*&.#-!*.,&8#'6)/#*'#$%&J',/)4
• F&(-%.,&8#\i]#+,-)7#,&#'6)#7!%$()#(!.)4#156,7#"!$07#A)(*%7)#\i]#+,-)7#*$)#*-7!#:*-,.#>??
MainWindow::MainWindow() +,-)743
{ • K7,&8#<'=7#$)7!%$()#/)(6*&,7/4
spreadsheet = new Spreadsheet;
setCentralWidget(spreadsheet); M)$)#")#%7)#<'=7#$)7!%$()#/)(6*&,7/#A)(*%7)#,'#,7#/!$)#(!&:)&,)&'#'6*&#-!*.,&8#+,-)7#*'#$%&J',/);
*&.#,'#"!$07#",'6#*&B#7%99!$').#,/*8)#+,-)#+!$/*'4#E)#6*:)#(6!7)&#'!#7'!$)#'6)#,/*8)7#,&#'6) newAction = new QAction(tr("&New"), this);
7!%$()#'$))#,&#*#7%A.,$)('!$B#(*--). images4 newAction->setIcon(QIcon(":/images/new.png"));
newAction->setShortcut(tr("Ctrl+N"));
newAction->setStatusTip(tr("Create a new spreadsheet file"));
5!#/*0)#%7)#!+#<'=7#$)7!%$()#7B7')/;#")#/%7'#($)*')#*#$)7!%$()#+,-)#*&.#*..#*#-,&)#'!#'6) .pro#+,-) connect(newAction, SIGNAL(triggered()), this, SLOT(newFile()));
'6*'#,.)&',+,)7#'6)#$)7!%$()#+,-)4#F&#'6,7#)G*/9-);#")#6*:)#(*--).#'6)#$)7!%$()#+,-) spreadsheet.qrc;#7!
")#9%'#'6)#+!--!",&8#-,&)#,&#'6) .pro#+,-)D

56)# )"#*(',!&#6*7#*&#*(()-)$*'!$#1 )"3;#*#9*$)&'#1'6)#/*,&#",&.!"3;#*&#,(!&#1new.png3;#*#76!$'(%'


RESOURCES = spreadsheet.qrc 0)B#1>'$-? 3;#*&.#*#7'*'%7#',94#E)#(!&&)('#'6)#*(',!&=7 triggered()#7,8&*-#'!#'6)#/*,&#",&.!"=7
9$,:*') newFile()#7-!';#"6,(6#")#",--#,/9-)/)&'#,&#'6)#&)G'#7)(',!&4#56,7#(!&&)(',!&#)&7%$)7#'6*'
"6)&#'6)#%7)$#(6!!7)7#'6)#X,-)a )"#/)&%#,')/;#(-,(07#'6)# )"#'!!-A*$#A%''!&;#!$#9$)77)7#>'$-? ;
'6) newFile()#7-!'#,7#(*--).4
56)#$)7!%$()#+,-)#,'7)-+#%7)7#*#7,/9-)#\]^#+!$/*'4#M)$)=7#*&#)G'$*('#+$!/#'6)#!&)#")#6*:)#%7).D

56)#H9)&;#`*:);#*&.#`*:)#L7#*(',!&7#*$)#:)$B#7,/,-*$#'!#'6)# )"#*(',!&;#7!#")#",--#70,9#.,$)('-B#'!
<!DOCTYPE RCC><RCC version="1.0"> '6)#N$)()&'-B#!9)&).#+,-)7N 9*$'#!+#'6)#X,-)#/)&%D
<qresource>
<file>images/icon.png</file>
... ...
<file>images/gotocell.png</file> for (int i = 0; i < MaxRecentFiles; ++i) {
</qresource> recentFileActions[i] = new QAction(this);
</RCC> recentFileActions[i]->setVisible(false);
connect(recentFileActions[i], SIGNAL(triggered()),
this, SLOT(openRecentFile()));
}
[)7!%$()#+,-)7#*$)#(!/9,-).#,&'!#'6)#*99-,(*',!&=7#)G)(%'*A-);#7!#'6)B#(*&='#8)'#-!7'4#E6)&#")#$)+)$
'!#$)7!%$()7;#")#%7)#'6)#9*'6#9$)+,G :/#1(!-!&#7-*763;#"6,(6#,7#"6B#'6)#,(!&#,7#79)(,+,).#*7
:/images/icon.png4#[)7!%$()7#(*&#A)#*&B#0,&.#!+#+,-)#1&!'#Z%7'#,/*8)73;#*&.#")#(*&#%7)#'6)/#,&
E)#9!9%-*')#'6) recentFileActions#*$$*B#",'6#*(',!&74#_*(6#*(',!&#,7#6,..)&#*&.#(!&&)(').#'!#'6)
/!7'#9-*()7#"6)$)#<'#)G9)('7#*#+,-)#&*/)4 56)B#*$)#(!:)$).#,&#/!$)#.)'*,-#,& >6*9')$#RV4
openRecentFile()#7-!'4#^*')$#!&;#")#",--#7))#6!"#'6)#$)()&'#+,-)#*(',!&7#*$)#/*.)#:,7,A-)#*&.#%7).4

Creating Menus and Toolbars E)#(*&#&!"#70,9#'!#'6)#`)-)('#L--#*(',!&D

]!7'#/!.)$&#lKF#*99-,(*',!&7#9$!:,.)#/)&%7;#(!&')G'#/)&%7;#*&.#'!!-A*$74#56)#/)&%7#)&*A-)
%7)$7#'!#)G9-!$)#'6)#*99-,(*',!&#*&.#-)*$&#6!"#'!#.!#&)"#'6,&87;#"6,-)#'6)#(!&')G'#/)&%7#*&. ...
'!!-A*$7#9$!:,.)#@%,(0#*(()77#'!#+$)@%)&'-B#%7).#+%&(',!&*-,'B4 selectAllAction = new QAction(tr("&All"), this);
selectAllAction->setShortcut(tr("Ctrl+A"));
selectAllAction->setStatusTip(tr("Select all the cells in the "
!"#$%&?(?(&+,%&-6$%104,%%/&1662!91/!.7=4&5%7#4 "spreadsheet"));
connect(selectAllAction, SIGNAL(triggered()),
[View full size image]
spreadsheet, SLOT(selectAll()));

56) selectAll()#7-!'#,7#9$!:,.).#AB#!&)#!+ QTableWidget=7#*&()7'!$7; QAbstractItemView;#7!#")#.!


&!'#6*:)#'!#,/9-)/)&'#,'#!%$7)-:)74

^)'=7#70,9#+%$'6)$#'!#'6)#`6!"#l$,.#*(',!&#,&#'6)#H9',!&7#/)&%D

...
<'#7,/9-,+,)7#'6)#9$!8$*//,&8#!+#/)&%7#*&.#'!!-A*$7#'6$!%86#,'7#*(',!&#(!&()9'4#L& -3!&+(#,7#*& showGridAction = new QAction(tr("&Show Grid"), this);
,')/#'6*'#(*&#A)#*..).#'!#*&B#&%/A)$#!+#/)&%7#*&.#'!!-A*$74 >$)*',&8#/)&%7#*&.#'!!-A*$7#,&#<' showGridAction->setCheckable(true);
,&:!-:)7#'6)7)#7')97D showGridAction->setChecked(spreadsheet->showGrid());
showGridAction->setStatusTip(tr("Show or hide the spreadsheet's "
"grid"));
• >$)*')#*&.#7)'#%9#'6)#*(',!&74 connect(showGridAction, SIGNAL(toggled(bool)),
• >$)*') /)&%7#*&.#9!9%-*')#'6)/#",'6#'6)#*(',!&74 spreadsheet, SLOT(setShowGrid(bool)));
• >$)*')#'!!-A*$7#*&.#9!9%-*')#'6)/#",'6#'6)#*(',!&74

F&#'6)#`9$)*.76))'#*99-,(*',!&;#*(',!&7#*$)#($)*').#,& createActions()D `6!"#l$,.#,7#*#(6)(0*A-)#*(',!&4#F'#,7#$)&.)$).#",'6#*#(6)(0/*$0#,&#'6)#/)&%#*&.#,/9-)/)&').#*7#*


'!88-)#A%''!&#,&#'6)#'!!-A*$4#E6)&#'6)#*(',!&#,7#'%$&).#!&;#'6) Spreadsheet#(!/9!&)&'#.,79-*B7#*
8$,.4#E)#,&,',*-,C)#'6)#*(',!&#",'6#'6)#.)+*%-'#+!$#'6) Spreadsheet#(!/9!&)&';#7!#'6*'#'6)B#*$)
void MainWindow::createActions()
{ 7B&(6$!&,C).#*'#7'*$'%94#56)&#")#(!&&)('#'6)#`6!"#l$,.#*(',!&=7 toggled(bool)#7,8&*-#'!#'6)
Spreadsheet#(!/9!&)&'=7 setShowGrid(bool)#7-!';#"6,(6#,'#,&6)$,'7#+$!/ QTableWidget4#H&()#'6,7 E)#7'*$'#AB#($)*',&8#'6)#X,-)#/)&%#*&.#'6)&#*..#'6)# )";#H9)&;#`*:);#*&.#`*:)#L7#*(',!&7#'!#,'4
*(',!&#,7#*..).#'!#*#/)&%#!$#'!!-A*$;#'6)#%7)$#(*&#'!88-)#'6)#8$,.#!&#*&.#!++4 E)#,&7)$'#*#7)9*$*'!$#'!#:,7%*--B#8$!%9#(-!7)-B#$)-*').#,')/7#'!8)'6)$4#E)#%7)#* for#-!!9#'!#*..#'6)
1,&,',*--B#6,..)&3#*(',!&7#+$!/#'6) recentFileActions#*$$*B;#*&.#'6)&#*..#'6) exitAction#*(',!&#*'
56)#`6!"#l$,.#*&.#L%'!J[)(*-(%-*')#*(',!&7#*$)#,&.)9)&.)&'#(6)(0*A-)#*(',!&74#<'#*-7!#7%99!$'7 '6)#)&.4
/%'%*--B#)G(-%7,:)#*(',!&7#'6$!%86#'6) QActionGroup#(-*774
E)#6*:)#0)9'#*#9!,&')$#'!#!&)#!+#'6)#7)9*$*'!$74#56,7#",--#*--!"#%7#'!#6,.)#'6)#7)9*$*'!$#1,+#'6)$)#*$)
&!#$)()&'#+,-)73#!$#'!#76!"#,';#7,&()#")#.!#&!'#"*&'#'!#76!"#'"!#7)9*$*'!$7#",'6#&!'6,&8#,&#A)'"))&4
...
aboutQtAction = new QAction(tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show the Qt library's About box")); editMenu = menuBar()->addMenu(tr("&Edit"));
editMenu->addAction(cutAction);
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); editMenu->addAction(copyAction);
}
editMenu->addAction(pasteAction);
editMenu->addAction(deleteAction);
selectSubMenu = editMenu->addMenu(tr("&Select"));
X!$#'6)#LA!%'#<'#*(',!&;#")#%7)#'6) QApplication#!AZ)('=7 aboutQt()#7-!';#*(()77,A-)#'6$!%86#'6) qApp
selectSubMenu->addAction(selectRowAction);
8-!A*-#:*$,*A-)4
selectSubMenu->addAction(selectColumnAction);
selectSubMenu->addAction(selectAllAction);
!"#$%&?(A(&L<.#/&E/ editMenu->addSeparator();
editMenu->addAction(findAction);
[View full size image] editMenu->addAction(goToCellAction);

!"#")#($)*')#'6)#_.,'#/)&%;#*..,&8#*(',!&7#",'6 QMenu::addAction()#*7#")#.,.#+!$#'6)#X,-)#/)&%;
*&.#*..,&8#'6)#7%A/)&%#",'6 QMenu::addMenu()#*'#'6)#9!7,',!&#"6)$)#")#"*&'#,'#'!#*99)*$4#56)
7%A/)&%;#-,0)#'6)#/)&%#,'#A)-!&87#'!;#,7#* QMenu4

toolsMenu = menuBar()->addMenu(tr("&Tools"));
toolsMenu->addAction(recalculateAction);
toolsMenu->addAction(sortAction);
optionsMenu = menuBar()->addMenu(tr("&Options"));
optionsMenu->addAction(showGridAction);
optionsMenu->addAction(autoRecalcAction);
menuBar()->addSeparator();
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAction);
helpMenu->addAction(aboutQtAction);
}

!"#'6*'#")#6*:)#($)*').#'6)#*(',!&7;#")#(*&#/!:)#!&#'!#A%,-.,&8#*#/)&%#7B7')/#(!&'*,&,&8#'6)/D
E)#($)*')#'6)#5!!-7;#H9',!&7;#*&.#M)-9#/)&%7#,&#*#7,/,-*$#+*76,!&4#E)#,&7)$'#*#7)9*$*'!$#A)'"))&
'6)#H9',!&7#*&.#M)-9#/)&%4#F&#]!',+#*&.#>b_#7'B-)7;#'6)#7)9*$*'!$#9%76)7#'6)#M)-9#/)&%#'!#'6)
$,86'2#,&#!'6)$#7'B-)7;#'6)#7)9*$*'!$#,7#,8&!$).4
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File")); !"#$%&?(C(&M%7#&<1$&!7&M./!>&170&N!70.34&4/;2%4
fileMenu->addAction(newAction);
fileMenu->addAction(openAction);
fileMenu->addAction(saveAction);
fileMenu->addAction(saveAsAction);
separatorAction = fileMenu->addSeparator();
for (int i = 0; i < MaxRecentFiles; ++i)
fileMenu->addAction(recentFileActions[i]);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
void MainWindow::createContextMenu()
{
spreadsheet->addAction(cutAction);
F&#<';#/)&%7#*$)#,&7'*&()7#!+ QMenu4#56) addMenu()#+%&(',!&#($)*')7#* QMenu#",.8)'#",'6#'6) spreadsheet->addAction(copyAction);
79)(,+,).#')G'#*&.#*..7#,'#'!#'6)#/)&%#A*$4#56) QMainWindow::menuBar()#+%&(',!&#$)'%$&7#*#9!,&')$#'! spreadsheet->addAction(pasteAction);
* QMenuBar4#56)#/)&%#A*$#,7#($)*').#'6)#+,$7'#',/) menuBar()#,7#(*--).4 spreadsheet->setContextMenuPolicy(Qt::ActionsContextMenu);
}
void MainWindow::createStatusBar()
{
L&B#<'#",.8)'#(*&#6*:)#*#-,7'#!+ QAction7#*77!(,*').#",'6#,'4#5!#9$!:,.)#*#(!&')G'#/)&%#+!$#'6) locationLabel = new QLabel(" W999 ");
*99-,(*',!&;#")#*..#'6)#.)7,$).#*(',!&7#'!#'6) Spreadsheet#",.8)'#*&.#7)'#'6*'#",.8)'=7#(!&')G' locationLabel->setAlignment(Qt::AlignHCenter);
/)&%#9!-,(B#'!#76!"#*#(!&')G'#/)&%#",'6#'6)7)#*(',!&74#>!&')G'#/)&%7#*$)#,&:!0).#AB#$,86'J locationLabel->setMinimumSize(locationLabel->sizeHint());
(-,(0,&8#*#",.8)'#!$#AB#9$)77,&8#*#9-*'+!$/J79)(,+,(#0)B4 formulaLabel = new QLabel;
formulaLabel->setIndent(3);
!"#$%&?(D(&+,%&-6$%104,%%/&1662!91/!.7=4&9.7/%8/&5%7# statusBar()->addWidget(locationLabel);
statusBar()->addWidget(formulaLabel, 1);
connect(spreadsheet, SIGNAL(currentCellChanged(int, int, int, int)),
this, SLOT(updateStatusBar()));
connect(spreadsheet, SIGNAL(modified()),
this, SLOT(spreadsheetModified()));
updateStatusBar();
}

56) QMainWindow::statusBar()#+%&(',!&#$)'%$&7#*#9!,&')$#'!#'6)#7'*'%7#A*$4#156)#7'*'%7#A*$#,7#($)*').
L#/!$)#7!96,7',(*').#"*B#!+#9$!:,.,&8#(!&')G'#/)&%7#,7#'!#$),/9-)/)&'#'6) '6)#+,$7' ',/) statusBar()#,7#(*--).43#56)#7'*'%7#,&.,(*'!$7#*$)#7,/9-B QLabel7#"6!7)#')G'#")#(6*&8)
QWidget::contextMenuEvent()#+%&(',!&;#($)*')#* QMenu#",.8)';#9!9%-*')#,'#",'6#'6)#.)7,$).#*(',!&7; "6)&):)$#&)()77*$B4#E)#6*:)#*..).#*&#,&.)&'#'!#'6) formulaLabel#7!#'6*'#'6)#')G'#76!"&#,&#,'#,7
*&.#(*-- exec()#!&#,'4 !++7)'#7-,86'-B#+$!/#'6)#-)+'#).8)4#E6)&#'6) QLabel7#*$)#*..).#'!#'6)#7'*'%7#A*$;#'6)B#*$)
*%'!/*',(*--B#$)9*$)&').#'!#/*0)#'6)/#(6,-.$)&#!+#'6)#7'*'%7#A*$4

void MainWindow::createToolBars() X,8%$)#d4k#76!"7#'6*'#'6)#'"!#-*A)-7#6*:)#.,++)$)&'#79*()#$)@%,$)/)&'74#56)#()--#-!(*',!&#,&.,(*'!$


{ $)@%,$)7#:)$B#-,''-)#79*();#*&.#"6)&#'6)#",&.!"#,7#$)J7,C).;#*&B#)G'$*#79*()#76!%-.#8!#'!#'6)#()--
fileToolBar = addToolBar(tr("&File")); +!$/%-*#,&.,(*'!$#!&#'6)#$,86'4#56,7#,7#*(6,):).#AB#79)(,+B,&8#*#7'$)'(6#+*('!$#!+#R#,&#'6)#+!$/%-*
fileToolBar->addAction(newAction); -*A)-=7 QStatusBar::addWidget()#(*--4#56)#-!(*',!&#,&.,(*'!$#6*7#'6)#.)+*%-'#7'$)'(6#+*('!$#!+#T;
fileToolBar->addAction(openAction); /)*&,&8#'6*'#,'#9$)+)$7#&!'#'!#A)#7'$)'(6).4
fileToolBar->addAction(saveAction);
editToolBar = addToolBar(tr("&Edit"));
editToolBar->addAction(cutAction); !"#$%&?(H(&+,%&-6$%104,%%/&1662!91/!.7=4&4/1/#4&<1$
editToolBar->addAction(copyAction);
editToolBar->addAction(pasteAction);
editToolBar->addSeparator();
editToolBar->addAction(findAction);
editToolBar->addAction(goToCellAction);
}

>$)*',&8#'!!-A*$7#,7#:)$B#7,/,-*$#'!#($)*',&8#/)&%74#E)#($)*')#*#X,-)#'!!-A*$#*&.#*&#_.,'#'!!-A*$4#r%7'
-,0)#*#/)&%;#*#'!!-A*$#(*&#6*:)#7)9*$*'!$74

!"#$%&?(F( +,%&-6$%104,%%/&1662!91/!.7=4&/..2<1$4 E6)& QStatusBar#-*B7#!%'#,&.,(*'!$#",.8)'7;#,'#'$,)7#'!#$)79)('#)*(6#",.8)'=7#,.)*-#7,C)#*7#8,:)&#AB


QWidget::sizeHint()#*&.#'6)&#7'$)'(6)7#*&B#7'$)'(6*A-)#",.8)'7#'!#+,--#'6)#*:*,-*A-)#79*()4#L
",.8)'=7#,.)*-#7,C)#,7#,'7)-+#.)9)&.)&'#!&#'6)#",.8)'=7#(!&')&'7#*&.#:*$,)7#*7#")#(6*&8)#'6)
(!&')&'74#5!#*:!,.#(!&7'*&'#$)7,C,&8#!+#'6)#-!(*',!&#,&.,(*'!$;#")#7)'#,'7#/,&,/%/#7,C)#'!#A)#",.)
)&!%86#'!#(!&'*,&#'6)#-*$8)7'#9!77,A-)#')G'#1NESSSN3;#",'6#*#-,''-)#)G'$*#79*()4#E)#*-7!#7)'#,'7
*-,8&/)&'#'! Qt::AlignHCenter#'!#6!$,C!&'*--B#()&')$#'6)#')G'4

)*$#'6)#)&.#!+#'6)#+%&(',!&;#")#(!&&)('#'"!#!+ Spreadsheet=7#7,8&*-7#'!#'"!#!+ MainWindow=7#7-!'7D


Setting Up the Status Bar updateStatusBar()#*&. spreadsheetModified()4

E,'6#'6)#/)&%7#*&.#'!!-A*$7#(!/9-)');#")#*$)#$)*.B#'!#'*(0-)#'6)#`9$)*.76))'#*99-,(*',!&=7#7'*'%7 void MainWindow::updateStatusBar()


A*$4 {
locationLabel->setText(spreadsheet->currentLocation());
F&#,'7#&!$/*-#7'*');#'6)#7'*'%7#A*$#(!&'*,&7#'"!#,&.,(*'!$7D#'6)#(%$$)&'#()--=7#-!(*',!&#*&.#'6)#(%$$)&' formulaLabel->setText(spreadsheet->currentFormula());
()--=7#+!$/%-*4#56)#7'*'%7#A*$#,7#*-7!#%7).#'!#.,79-*B#7'*'%7#',97#*&.#!'6)$#')/9!$*$B#/)77*8)74 }

56) MainWindow#(!&7'$%('!$#(*--7 createStatusBar()#'!#7)'#%9#'6)#7'*'%7#A*$D


56) updateStatusBar()#7-!'#%9.*')7#'6)#()--#-!(*',!&#*&.#'6)#()--#+!$/%-*#,&.,(*'!$74#F'#,7#(*--).
"6)&):)$#'6)#%7)$#/!:)7#'6)#()--#(%$7!$#'!#*#&)"#()--4#56)#7-!'#,7#*-7!#%7).#*7#*&#!$.,&*$B#+%&(',!&
*'#'6)#)&.#!+ createStatusBar()#'!#,&,',*-,C)#'6)#,&.,(*'!$74#56,7#,7#&)()77*$B#A)(*%7) Spreadsheet =& okToContinue(),(9%("1%">('1%(*'-'%(!0('1% windowModified(6/!6%/'<4(=0(.'(.* true,(9%( .*63-<('1%
.!)7&='#)/,'#'6) currentCellChanged()#7,8&*-#*'#7'*$'%94 $%**-;%(:!?(*1!9&(.& @.;#/%(A4B4(51%($%**-;%(:!?(1-*(-()%*,(-(C!,(-& (-(2-&"%3(:#''!&4 51%
QMessageBox::Default($! .0.%/($->%*()%*('1%( %0-#3'(:#''!&4(51% QMessageBox::Escape($! .0.%/
$->%*('1%(D*"(>%<(-(*<&!&<$(0!/(2-&"%34
void MainWindow::spreadsheetModified()
{
setWindowModified(true); !"#$%&'()(&*+,&-,#&./01&1,&2/3%&-,#$&45/0"%26*
updateStatusBar();
}

56) spreadsheetModified()#7-!'#7)'7#'6) windowModified#9$!9)$'B#'! true;#%9.*',&8#'6)#','-)#A*$4#56)


+%&(',!&#*-7!#%9.*')7#'6)#-!(*',!&#*&.#+!$/%-*#,&.,(*'!$7#7!#'6*'#'6)B#$)+-)('#'6)#(%$$)&'#7'*')#!+
*++*,$74

Implementing the File Menu


51%("-33('! warning()($-<(3!!>(-(:.'(.&'.$. -'.&;(-'(0./*'(*.;1',(:#'('1%(;%&%/-3(*<&'-?(.*
F&#'6,7#7)(',!&;#")#",--#,/9-)/)&'#'6)#7-!'7#*&.#9$,:*')#+%&(',!&7#&)()77*$B#'!#/*0)#'6)#X,-)#/)&% *'/-.;1'0!/9-/ E
!9',!&7#"!$0#*&.#'!#/*&*8)#'6)#$)()&'-B#!9)&).#+,-)7#-,7'4

QMessageBox::warning(parent, title, message, button0, button1, ...);


void MainWindow::newFile()
{
if (okToContinue()) {
spreadsheet->clear(); QMessageBox(-3*!(6/!8. %* information(), question(),(-& critical(), %-"1(!0(91."1(1-*(.'*(!9&
setCurrentFile(""); 6-/'."#3-/(."!&4
}
} !"#$%&'(78(&9%22/"%&:,;&!4,02

56) newFile()#7-!'#,7#(*--).#"6)&#'6)#%7)$#(-,(07#'6)#X,-)a )"#/)&%#!9',!&#!$#(-,(07#'6)# )"#'!!-A*$


A%''!&4#56) okToContinue()#9$,:*')#+%&(',!&#*707#'6)#%7)$#Nb!#B!%#"*&'#'!#7*:)#B!%$#(6*&8)7pN#,+
'6)$)#*$)#%&7*:).#(6*&8)74#F'#$)'%$&7 true#,+#'6)#%7)$#(6!!7)7#),'6)$#s)7#!$# !#17*:,&8#'6)
!"#$%&'(!&()%*+,(-& (.'(/%'#/&* false(.0('1%(#*%/("1!!*%*(2-&"%34(51% Spreadsheet::clear()
0#&"'.!&("3%-/*(-33('1%(*6/%- *1%%'7*("%33*(-& (0!/$#3-*4(51% setCurrentFile()(6/.8-'%(0#&"'.!&
#6 -'%*('1%(9.& !9('.'3%('!(.& ."-'%('1-'(-&(#&'.'3% ( !"#$%&'(.*(:%.&;(% .'% ,(.&(- .'.!&('!(*%''.&; void MainWindow::open()
'1% curFile(6/.8-'%(8-/.-:3%(-& (#6 -'.&;('1%(/%"%&'3<(!6%&% (0.3%*(3.*'4 {
if (okToContinue()) {
QString fileName = QFileDialog::getOpenFileName(this,
bool MainWindow::okToContinue() tr("Open Spreadsheet"), ".",
{ tr("Spreadsheet files (*.sp)"));
if (isWindowModified()) { if (!fileName.isEmpty())
int r = QMessageBox::warning(this, tr("Spreadsheet"), loadFile(fileName);
tr("The document has been modified.\n" }
"Do you want to save your changes?"), }
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No,
QMessageBox::Cancel | QMessageBox::Escape);
if (r == QMessageBox::Yes) { 51% open()(*3!'("!//%*6!& *('!(@.3%FG6%&4(H.>% newFile(),(.'(0./*'("-33* okToContinue()('!(1-& 3%(-&<
return save(); #&*-8% ("1-&;%*4(51%&(.'(#*%*('1%(*'-'."("!&8%&.%&"%(0#&"'.!& QFileDialog::getOpenFileName()('!
} else if (r == QMessageBox::Cancel) { !:'-.&(-(&%9(0.3%(&-$%(0/!$('1%(#*%/4(51%(0#&"'.!&(6!6*(#6(-(0.3%( .-3!;,(3%'*('1%(#*%/("1!!*%(-(0.3%,
return false; -& (/%'#/&*('1%(0.3%(&-$%!/(-&(%$6'<(*'/.&;(.0('1%(#*%/("3.">% (2-&"%34
}
} 51%(0./*'(-/;#$%&'('! QFileDialog::getOpenFileName()(.*('1%(6-/%&'(9. ;%'4(51%(6-/%&'"1.3
return true; /%3-'.!&*1.6( !%*&7'($%-&('1%(*-$%('1.&;(0!/( .-3!;*(-*(0!/(!'1%/(9. ;%'*4(I( .-3!;(.*(-39-<*(-
}
9.& !9(.&(.'*(!9&(/.;1',(:#'(.0(.'(1-*(-(6-/%&',(.'(.*("%&'%/% (!&('!6(!0('1%(6-/%&'(:<( %0-#3'4(I("1.3
.-3!;(-3*!(*1-/%*(.'*(6-/%&'7*('-*>:-/(%&'/<4
51%(*%"!& (-/;#$%&'(.*('1%('.'3%('1%( .-3!;(*1!#3 (#*%4(51%('1./ (-/;#$%&'('%33*(.'(91."1( ./%"'!/<(.' saveAs()4
*1!#3 (*'-/'(0/!$,(.&(!#/("-*%('1%("#//%&'( ./%"'!/<4

51%(0!#/'1(-/;#$%&'(*6%".0.%*('1%(0.3%(0.3'%/*4(I(0.3%(0.3'%/("!&*.*'*(!0(-( %*"/.6'.8%('%?'(-& (-(9.3 "-/ bool MainWindow::saveAs()


6-''%/&4(J- (9%(*#66!/'% ("!$$-K*%6-/-'% (8-3#%*(0.3%*(-& (H!'#*(LKMKA(0.3%*(.&(- .'.!&('! {
N6/%- *1%%'7*(&-'.8%(0.3%(0!/$-',(9%(9!#3 (1-8%(#*% ('1%(0!33!9.&;(0.3'%/E QString fileName = QFileDialog::getSaveFileName(this,
tr("Save Spreadsheet"), ".",
tr("Spreadsheet files (*.sp)"));
if (fileName.isEmpty())
tr("Spreadsheet files (*.sp)\n"
return false;
"Comma-separated values files (*.csv)\n"
return saveFile(fileName);
"Lotus 1-2-3 files (*.wk1 *.wks)")
}

51% loadFile()(6/.8-'%(0#&"'.!&(9-*("-33% (.& open()('!(3!- ('1%(0.3%4(O%($->%(.'(-&(.& %6%& %&'


51% saveAs()(*3!'("!//%*6!& *('!(@.3%FN-8%(I*4(O%("-33 QFileDialog::getSaveFile-Name()('!(!:'-.&(-
0#&"'.!&(:%"-#*%(9%(9.33(&%% ('1%(*-$%(0#&"'.!&-3.'<('!(3!- (/%"%&'3<(!6%&% (0.3%*E
0.3%(&-$%(0/!$('1%(#*%/4(=0('1%(#*%/("3.">*(2-&"%3,(9%(/%'#/& false,(91."1(.*(6/!6-;-'% (#6('!(.'*
"-33%/(Qsave()(!/ okToContinue()+4
bool MainWindow::loadFile(const QString &fileName)
{ =0('1%(0.3%(-3/%- <(%?.*'*,('1% getSaveFileName()(0#&"'.!&(9.33(-*>('1%(#*%/('!("!&0./$('1-'('1%<(9-&'
if (!spreadsheet->readFile(fileName)) { '!(!8%/9/.'%4(51.*(:%1-8.!/("-&(:%("1-&;% (:<(6-**.&; QFileDialog::DontConfirmOverwrite(-*(-&
statusBar()->showMessage(tr("Loading canceled"), 2000); - .'.!&-3(-/;#$%&'('! getSaveFile-Name()4
return false;
}
setCurrentFile(fileName); void MainWindow::closeEvent(QCloseEvent *event)
statusBar()->showMessage(tr("File loaded"), 2000); {
return true; if (okToContinue()) {
} writeSettings();
event->accept();
} else {
O%(#*% Spreadsheet::readFile()('!(/%- ('1%(0.3%(0/!$( .*>4(=0(3!- .&;(.*(*#""%**0#3,(9%("-33 event->ignore();
setCurrentFile()('!(#6 -'%('1%(9.& !9('.'3%P(!'1%/9.*%, Spread-sheet::readFile()(9.33(1-8%(-3/%- <
}
}
&!'.0.% ('1%(#*%/(!0('1%(6/!:3%$('1/!#;1(-($%**-;%(:!?4(=&(;%&%/-3,(.'(.*(;!! (6/-"'."%('!(3%'('1%
3!9%/K3%8%3("!$6!&%&'*(.**#%(%//!/($%**-;%*,(*.&"%('1%<("-&(6/!8. %('1%(6/%".*%( %'-.3*(!0(91-'
9%&'(9/!&;4
O1%&('1%(#*%/("3.">*(@.3%FD?.'(!/("3.">*('1%("3!*%(:#''!&(.&('1%(9.& !97*('.'3%(:-/,('1%
=&(:!'1("-*%*,(9%( .*63-<(-($%**-;%(.&('1%(*'-'#*(:-/(0!/(M(*%"!& *(QMRRR($.33.*%"!& *+('!(>%%6('1% QWidget::close()(*3!'(.*("-33% 4(51.*(*%& *(-(S"3!*%S(%8%&'('!('1%(9. ;%'4(T<(/%.$63%$%&'.&;
#*%/(.&0!/$% (-:!#'(91-'('1%(-663."-'.!&(.*( !.&;4 QWidget::closeEvent(),(9%("-&(.&'%/"%6'(-''%$6'*('!("3!*%('1%($-.&(9.& !9(-& ( %". %(91%'1%/(9%
9-&'('1%(9.& !9('!(-"'#-33<("3!*%(!/(&!'4

bool MainWindow::save() =0('1%/%(-/%(#&*-8% ("1-&;%*(-& ('1%(#*%/("1!!*%*(2-&"%3,(9%(S.;&!/%S('1%(%8%&'(-& (3%-8%('1%


{ 9.& !9(#&-00%"'% (:<(.'4(=&('1%(&!/$-3("-*%,(9%(-""%6'('1%(%8%&',(/%*#3'.&;(.&(U'(1. .&;('1%(9.& !94
if (curFile.isEmpty()) { O%(-3*!("-33('1%(6/.8-'%(0#&"'.!& writeSettings()('!(*-8%('1%(-663."-'.!&7*("#//%&'(*%''.&;*4
return saveAs();
} else {
O1%&('1%(3-*'(9.& !9(.*("3!*% ,('1%(-663."-'.!&('%/$.&-'%*4(=0(&%% % ,(9%("-&( .*-:3%('1.*(:%1-8.!/
return saveFile(curFile);
} :<(*%''.&; QApplication7* quitOnLastWindowClosed(6/!6%/'<('! false,(.&(91."1("-*%('1%(-663."-'.!&
} >%%6*(/#&&.&;(#&'.3(9%("-33 QApplication::quit()4
bool MainWindow::saveFile(const QString &fileName)
{
if (!spreadsheet->writeFile(fileName)) { void MainWindow::setCurrentFile(const QString &fileName)
statusBar()->showMessage(tr("Saving canceled"), 2000); {
return false; curFile = fileName;
} setWindowModified(false);
setCurrentFile(fileName); QString shownName = "Untitled";
statusBar()->showMessage(tr("File saved"), 2000); if (!curFile.isEmpty()) {
return true; shownName = strippedName(curFile);
} recentFiles.removeAll(curFile);
recentFiles.prepend(curFile);
updateRecentFileActions();
}
51% save()(*3!'("!//%*6!& *('!(@.3%FN-8%4(=0('1%(0.3%(-3/%- <(1-*(-(&-$%(:%"-#*%(.'(9-*(!6%&% setWindowTitle(tr("%1[*] - %2").arg(shownName)
:%0!/%(!/(1-*(-3/%- <(:%%&(*-8% , save()("-33* saveFile()(9.'1('1-'(&-$%P(!'1%/9.*%,(.'(*.$63<("-33* .arg(tr("Spreadsheet")));
}
QString MainWindow::strippedName(const QString &fullFileName) separatorAction->setVisible(!recentFiles.isEmpty());
{ }
return QFileInfo(fullFileName).fileName();
}
O%(:%;.&(:<(/%$!8.&;(-&<(0.3%*('1-'(&!(3!&;%/(%?.*'(#*.&;(-(]-8-K*'<3%(.'%/-'!/4(N!$%(0.3%*($.;1'
1-8%(:%%&(#*% (.&(-(6/%8.!#*(*%**.!&,(:#'(1-8%(*.&"%(:%%&( %3%'% 4(51% recentFiles(8-/.-:3%(.*(!0
=& setCurrentFile(),(9%(*%'('1% curFile(6/.8-'%(8-/.-:3%('1-'(*'!/%*('1%(&-$%(!0('1%(0.3%(:%.&; '<6% QStringList(Q3.*'(!0 QString*+4 21-6'%/(LL(%?63-.&*("!&'-.&%/("3-**%*(*#"1(-* QStringList(.&
% .'% 4(T%0!/%(9%(*1!9('1%(0.3%(&-$%(.&('1%('.'3%(:-/,(9%(/%$!8%('1%(0.3%7*(6-'1(9.'1 strippedName() %'-.3,(*1!9.&;(1!9('1%<(/%3-'%('!('1%(2^^(N'-& -/ (5%$63-'%(H.:/-/<(QN5H+,(-& ('1%(#*%(!0(U'7*
'!($->%(.'($!/%(#*%/K0/.%& 3<4 ]-8-K*'<3%(.'%/-'!/("3-**%*4

D8%/< QWidget(1-*(- windowModified(6/!6%/'<('1-'(*1!#3 (:%(*%'('! TRue(.0('1%(9.& !97*( !"#$%&' O%('1%&(;!('1/!#;1('1%(3.*'(!0(0.3%*(-;-.&,('1.*('.$%(#*.&;(-//-<K*'<3%(.& %?.&;4(@!/(%-"1(0.3%,(9%


1-*(#&*-8% ("1-&;%*,(-& ('! false(!'1%/9.*%4(G&(V-"(GN(W,(#&*-8% ( !"#$%&'*(-/%(.& ."-'% (:<(- "/%-'%(-(*'/.&;("!&*.*'.&;(!0(-&(-$6%/*-& ,(-( .;.'(Q j(^(L+,(-(*6-"%,(-& ('1%(0.3%(&-$%(Q9.'1!#'(.'*
!'(.&('1%("3!*%(:#''!&(!0('1%(9.& !97*('.'3%(:-/P(!&(!'1%/(63-'0!/$*,('1%<(-/%(.& ."-'% (:<(-& 6-'1+4(O%(*%'('1%("!//%*6!& .&;(-"'.!&('!(#*%('1.*('%?'4(@!/(%?-$63%,(.0('1%(0./*'(0.3%(9-* C:\My
-*'%/.*>(0!33!9.&;('1%(0.3%(&-$%4(U'('->%*("-/%(!0('1.*(:%1-8.!/(-#'!$-'."-33<,(-*(3!&;(-*(9%(>%%6('1% Documents\tab04.sp,('1%(0./*'(-"'.!&7*('%?'(9!#3 (:%(S_L('-:R`4*6S4
windowModified(6/!6%/'<(#6K'!K -'%(-& (63-"%('1%($-/>%/(SXYZS(.&('1%(9.& !9('.'3%(91%/%(9%(9-&'
'1%(-*'%/.*>('!(-66%-/(91%&(.'(.*(/%[#./% 4
!"#$%&'(77(& !<%&=%0#&.!15&$%4%01<-&,>%0%?&@!<%2
51%('%?'(9%(6-**% ('!('1% setWindowTitle()(0#&"'.!&(9-* [View full size image]

tr("%1[*] - %2").arg(shownName)
.arg(tr("Spreadsheet"))

51% QString::arg()(0#&"'.!&(/%63-"%*('1%(3!9%*'K&#$:%/% (S\ S(6-/-$%'%/(9.'1(.'*(-/;#$%&'(-&


/%'#/&*('1%(/%*#3'.&;(*'/.&;4(=&('1.*("-*%, arg()(.*(#*% (9.'1('9!(S\ S(6-/-$%'%/*4(51%(0./*'("-33('!
arg()(/%63-"%*(S\LSP('1%(*%"!& ("-33(/%63-"%*(S\MS4(=0('1%(0.3% &-$%(.*(S:# ;%'4*6S(-& (&!
'/-&*3-'.!&(0.3%(.*(3!- % ,('1%(/%*#3'.&;(*'/.&;(9!#3 (:%(S:# ;%'4*6XYZ K(N6/%- *1%%'S4='(9!#3 (1-8%
:%%&(%-*.%/('!(9/.'%

setWindowTitle(shownName + tr("[*] - Spreadsheet"));

:#'(#*.&; arg()(6/!8. %*($!/%(03%?.:.3.'<(0!/('/-&*3-'!/*4


D8%/<(-"'.!&("-&(1-8%(-&(-**!".-'% (S -'-S(.'%$(!0('<6% QVariant4(51% QVariant('<6%("-&(1!3 (8-3#%*
!0($-&<(2^^(-& (U'('<6%*P(.'(.*("!8%/% (.& 21-6'%/(LL4(J%/%,(9%(*'!/%('1%(0#33(&-$%(!0('1%(0.3%(.&
=0('1%/%(.*(-(0.3%(&-$%,(9%(#6 -'% recentFiles,('1%(-663."-'.!&7*(/%"%&'3<(!6%&% (0.3%*(3.*'4(O%("-33
'1%(-"'.!&7*(S -'-S(.'%$(*!('1-'(9%("-&(%-*.3<(/%'/.%8%(.'(3-'%/4(O%(-3*!(*%'('1%(-"'.!&('!(:%(8.*.:3%4
removeAll()('!(/%$!8%(-&<(!""#//%&"%*(!0('1%(0.3%(&-$%(.&('1%(3.*',('!(-8!. ( #63."-'%*P('1%&(9%("-33
prepend()('!(- ('1%(0.3%(&-$%(-*('1%(0./*'(.'%$4(I0'%/(#6 -'.&;('1%(3.*',(9%("-33('1%(6/.8-'%(0#&"'.!&
=0('1%/%(-/%($!/%(0.3%(-"'.!&*('1-&(/%"%&'(0.3%*,(9%(*.$63<(1. %('1%(%?'/-(-"'.!&*4(@.&-33<,(.0('1%/%(.*(-'
updateRecentFileActions()('!(#6 -'%('1%(%&'/.%*(.&('1%(@.3%($%&#4
3%-*'(!&%(/%"%&'(0.3%,(9%(*%'('1%(*%6-/-'!/('!(:%(8.*.:3%4

void MainWindow::updateRecentFileActions()
void MainWindow::openRecentFile()
{
{
QMutableStringListIterator i(recentFiles);
if (okToContinue()) {
while (i.hasNext()) {
QAction *action = qobject_cast<QAction *>(sender());
if (!QFile::exists(i.next()))
if (action)
i.remove();
loadFile(action->data().toString());
}
}
for (int j = 0; j < MaxRecentFiles; ++j) {
}
if (j < recentFiles.count()) {
QString text = tr("&%1 %2")
.arg(j + 1)
.arg(strippedName(recentFiles[j])); O1%&('1%(#*%/("1!!*%*(-(/%"%&'(0.3%,('1% openRecentFile()(*3!'(.*("-33% 4(51% okToContinue()(0#&"'.!&
recentFileActions[j]->setText(text); .*(#*% (.&("-*%('1%/%(-/%(-&<(#&*-8% ("1-&;%*,(-& (6/!8. .&;('1%(#*%/( . (&!'("-&"%3,(9%(0.& (!#'
recentFileActions[j]->setData(recentFiles[j]); 91."1(6-/'."#3-/(-"'.!&(.&8!>% ('1%(*3!'(#*.&; QObject::sender()4
recentFileActions[j]->setVisible(true);
} else {
recentFileActions[j]->setVisible(false); 51% qobject_cast<T>()(0#&"'.!&(6%/0!/$*(-( <&-$."("-*'(:-*% (!&('1%($%'-K.&0!/$-'.!&(;%&%/-'%
} :< moc,(U'7*($%'-K!:a%"'("!$6.3%/4(='(/%'#/&*(-(6!.&'%/(!0('1%(/%[#%*'% QObject(*#:"3-**,(!/(R(.0('1%
} !:a%"'("-&&!'(:%("-*'('!('1-'('<6%4(b&3.>%('1%(N'-& -/ (2^^ dynamic_cast<T>(),(U'7*
qobject_cast<T>()(9!/>*("!//%"'3<(-"/!**( <&-$."(3.:/-/<(:!#& -/.%*4(=&(!#/(%?-$63%,(9%(#*% -/%(6!**.:3%E
qobject_cast<T>()('!("-*'(- QObject(6!.&'%/('!(- QAction(6!.&'%/4(=0('1%("-*'(.*(*#""%**0#3(Q.'(*1!#3
:%+,(9%("-33 loadFile()(9.'1('1%(0#33(0.3%(&-$%('1-'(9%(%?'/-"'(0/!$('1%(-"'.!&7*( -'-4 • 51.*(.*('1%(0./*'('.$%('1%(#*%/(1-*(.&8!>% ('1%(@.& ( .-3!;4
• 51%(@.& ( .-3!;(9-*(.&8!>% (:%0!/%,(:#'('1%(#*%/("3!*% (.'4
=&". %&'-33<,(*.&"%(9%(>&!9('1-'('1%(*%& %/(.*(- QAction,('1%(6/!;/-$(9!#3 (*'.33(9!/>(.0(9%(#*% • 51%(@.& ( .-3!;(9-*(.&8!>% (:%0!/%(-& (.*(*'.33(8.*.:3%4
static_cast<T>()(!/(-('/- .'.!&-3(2K*'<3%("-*'(.&*'%- 4(c%0%/('!('1%(S5<6%(2!&8%/*.!&*S(*%"'.!&(!0
I66%& .?(T(0!/(-&(!8%/8.%9(!0('1%( .00%/%&'(2^^("-*'*4 =0('1%(@.& ( .-3!;( !%*&7'(-3/%- <(%?.*',(9%("/%-'%(.'(-& ("!&&%"'(.'* findNext()(-& findPrevious()
*.;&-3*('!('1%("!//%*6!& .&; Spreadsheet(*3!'*4(O%("!#3 (-3*!(1-8%("/%-'% ('1%( .-3!;(.&('1%
MainWindow("!&*'/#"'!/,(:#'( %3-<.&;(.'*("/%-'.!&($->%*(*'-/'#6(0-*'%/4(I3*!,(.0('1%( .-3!;(.*(&%8%/
#*% ,(.'(.*(&%8%/("/%-'% ,(*-8.&;(:!'1('.$%(-& ($%$!/<4

51%&(9%("-33 show()(-& activateWindow()('!(%&*#/%('1-'('1%(9.& !9(.*(8.*.:3%(-& (-"'.8%4(I("-33('!


Using Dialogs show()(-3!&%(.*(*#00.".%&'('!($->%(-(1. %&(9.& !9(8.*.:3%(-& (-"'.8%,(:#'('1%(@.& ( .-3!;($-<(:%
.&8!>% (91%&(.'*(9.& !9(.*(-3/%- <(8.*.:3%,(.&(91."1("-*% show()( !%*(&!'1.&;(-& activateWindow()
=&('1.*(*%"'.!&,(9%(9.33(%?63-.&(1!9('!(#*%( .-3!;*(.&(U'1!9('!("/%-'%(-& (.&.'.-3.d%('1%$,(/#&('1%$, .*(&%"%**-/<('!($->%('1%(9.& !9(-"'.8%4(I&(-3'%/&-'.8%(9!#3 (1-8%(:%%&('!(9/.'%
-& (/%*6!& ('!("1!."%*($- %(:<('1%(#*%/(.&'%/-"'.&;(9.'1('1%$4(O%(9.33($->%(#*%(!0('1%(@.& ,(e!K
'!K2%33,(-& (N!/'( .-3!;*('1-'(9%("/%-'% (.& 21-6'%/(M4(O%(9.33(-3*!("/%-'%(-(*.$63%(I:!#'(:!?4
if (findDialog->isHidden()) {
findDialog->show();
!"#$%&'(7A(&B5%&C>$%/?25%%1&/>><!4/1!,0D2& !0?&?!/<," } else {
findDialog->activateWindow();
}

91."1(.*('1%(6/!;/-$$.&;(%[#.8-3%&'(!0(3!!>.&;(:!'1(9-<*(:%0!/%("/!**.&;(-(!&%K9-<(*'/%%'4

O%(9.33(&!9(3!!>(-'('1%(e!K'!K2%33( .-3!;4(O%(9-&'('1%(#*%/('!(6!6(.'(#6,(#*%(.',(-& ("3!*%(.'(9.'1!#'


:%.&;(-:3%('!(*9.'"1('!(-&<(!'1%/(9.& !9(.&('1%(-663."-'.!&4(51.*($%-&*('1-'('1%(e!K'!K2%33( .-3!;
$#*'(:%($! -34(I !"#'%(9.& !9(.*(-(9.& !9('1-'(6!6*(#6(91%&(.&8!>% (-& (:3!">*('1%(-663."-'.!&,
6/%8%&'.&;(-&<(!'1%/(6/!"%**.&;(!/(.&'%/-"'.!&*(0/!$('->.&;(63-"%(#&'.3('1%(9.& !9(.* "3!*% 4(51%(0.3%
.-3!;*(-& ($%**-;%(:!?%*(9%(#*% (%-/3.%/(9%/%($! -34

O%(9.33(:%;.&(9.'1('1%(@.& ( .-3!;4(N.&"%(9%(9-&'('1%(#*%/('!(:%(-:3%('!(*9.'"1(:%'9%%&('1%($-.& !"#$%&'(7'(&B5%&C>$%/?25%%1&/>><!4/1!,0D2&E,F1,FG%<<&?!/<,"


N6/%- *1%%'(9.& !9(-& ('1%(@.& ( .-3!;(-'(9.33,('1%(@.& ( .-3!;($#*'(:%($! %3%**4(I !"#$%$&&
9.& !9(.*(!&%('1-'(/#&*(.& %6%& %&'3<(!0(-&<(!'1%/(9.& !9*(.&('1%(-663."-'.!&4

O1%&($! %3%**( .-3!;*(-/%("/%-'% ,'1%<(&!/$-33<(1-8%('1%./(*.;&-3*("!&&%"'% ('!(*3!'*('1-'(/%*6!&


'!('1%(#*%/7*(.&'%/-"'.!&*4

void MainWindow::find()
{
if (!findDialog) {
findDialog = new FindDialog(this);
connect(findDialog, SIGNAL (findNext(const QString &,
Qt::CaseSensitivity)), I( .-3!;(.*($! %3%**(.0(.'7*(.&8!>% (#*.&; show()(Q#&3%**(9%("-33 setModal()(:%0!/%1-& ('!($->%(.'
spreadsheet, SLOT (findNext(const QString &, $! -3+P(.'(.*($! -3(.0(.'7*(.&8!>% (#*.&; exec()4
Qt::CaseSensitivity)));
connect(findDialog, SIGNAL(findPrevious(const QString &,
Qt::CaseSensitivity)), void MainWindow::goToCell()
spreadsheet, SLOT(findPrevious(const QString &, {
Qt::CaseSensitivity))); GoToCellDialog dialog(this);
} if (dialog.exec()) {
findDialog->show(); QString str = dialog.lineEdit->text().toUpper();
findDialog->activateWindow(); spreadsheet->setCurrentCell(str.mid(1).toInt() - 1,
} str[0].unicode() - 'A');
}
}
51%(@.& ( .-3!;(.*(-(9.& !9('1-'(%&-:3%*('1%(#*%/('!(*%-/"1(0!/('%?'(.&('1%(*6/%- *1%%'4(51% find()
*3!'(.*("-33% (91%&('1%(#*%/("3.">*(D .'F@.& ('!(6!6(#6('1%(@.& ( .-3!;4 I'('1-'(6!.&',(*%8%/-3(*"%&-/.!*
51% QDialog::exec()(0#&"'.!&(/%'#/&*(-('/#%(8-3#%(QQDialog::Accepted+(.0('1%( .-3!;(.*(-""%6'% ,(-&
-(0-3*%(8-3#%(QQDialog::Rejected+ !'1%/9.*%4(c%"-33('1-'(91%&(9%("/%-'% ('1%(e!K'!K2%33( .-3!;(#*.&; SpreadsheetCompare compare;
()*+$&,- $.(.& 21-6'%/(M,(9%("!&&%"'% (Gf('! accept()(-& (2-&"%3('! reject()4(=0('1%(#*%/("1!!*%* compare.keys[0] =
Gf,(9%(*%'('1%("#//%&'("%33('!('1%(8-3#%(.&('1%(3.&%(% .'!/4 dialog.primaryColumnCombo->currentIndex();
compare.keys[1] =
dialog.secondaryColumnCombo->currentIndex() - 1;
51% QTableWidget::setCurrentCell()(0#&"'.!&(%?6%"'*('9!(-/;#$%&'*E(-(/!9(.& %?(-& (-("!3#$& compare.keys[2] =
.& %?4(=&('1%(N6/%- *1%%'(-663."-'.!&,("%33(IL(.*("%33(QR,(R+(-& ("%33(TMg(.*("%33(QMh,(L+4(5!(!:'-.&('1% dialog.tertiaryColumnCombo->currentIndex() - 1;
/!9(.& %?(0/!$('1% QString(/%'#/&% (:< QLineEdit::text(),(9%(%?'/-"'('1%(/!9(&#$:%/(#*.&; compare.ascending[0] =
QString::mid()(Q91."1(/%'#/&*(-(*#:*'/.&;(0/!$('1%(*'-/'(6!*.'.!&('!('1%(%& (!0('1%(*'/.&;+,("!&8%/'(.' (dialog.primaryOrderCombo->currentIndex() == 0);
'!(-& int(#*.&; QString::toInt(),(-& (*#:'/-"'(L4(@!/('1%("!3#$&(&#$:%/,(9%(*#:'/-"'('1%(&#$%/." compare.ascending[1] =
8-3#%(!0(7I7(0/!$('1%(&#$%/."(8-3#%(!0('1%(*'/.&;7*(#66%/"-*% (0./*'("1-/-"'%/4(O%(>&!9('1-'('1% (dialog.secondaryOrderCombo->currentIndex() == 0);
*'/.&;(9.33(1-8%('1%("!//%"'(0!/$-'(:%"-#*%('1% QRegExpValidator(9%("/%-'% (0!/('1%( .-3!;(!&3< compare.ascending[2] =
(dialog.tertiaryOrderCombo->currentIndex() == 0);
-33!9*('1%(Gf(:#''!&('!(:%(%&-:3% (.0(9%(1-8%(-(3%''%/(0!33!9% (:<(#6('!('1/%%( .;.'*4
spreadsheet->sort(compare);
}
51% goToCell()(0#&"'.!&( .00%/*(0/!$(-33('1%("! %(*%%&(*!(0-/(.&('1-'(.'("/%-'%*(-(9. ;%'(Q- }
GoToCellDialog+(-*(-(8-/.-:3%(!&('1%(*'-">4(I'('1%("!*'(!0(!&%(%?'/-(3.&%,(9%("!#3 (a#*'(-*(%-*.3<(1-8%
#*% new(-& deleteE
51%("! %(.& sort()(0!33!9*(-(*.$.3-/(6-''%/&('!('1-'(#*% (0!/ goToCell()E
void MainWindow::goToCell()
{ • O%("/%-'%('1%( .-3!;(!&('1%(*'-">(-& (.&.'.-3.d%(.'4
GoToCellDialog *dialog = new GoToCellDialog(this); • O%(6!6(#6('1%( .-3!;(#*.&; exec()4
if (dialog->exec()) { • =0('1%(#*%/("3.">*(Gf,(9%(%?'/-"'('1%(8-3#%*(%&'%/% (:<('1%(#*%/(0/!$('1%( .-3!;7*(9. ;%'*(-&
QString str = dialog->lineEdit->text().toUpper(); $->%(#*%(!0('1%$4
spreadsheet->setCurrentCell(str.mid(1).toInt() - 1,
str[0].unicode() - 'A'); 51% setColumnRange()("-33(*%'*('1%("!3#$&*(-8-.3-:3%(0!/(*!/'.&;('!('1%("!3#$&*('1-'(-/%(*%3%"'% 4
} @!/(%?-$63%,(#*.&;('1%(*%3%"'.!&(*1!9&(.& @.;#/%(A4L`, range.leftColumn()(9!#3 (<.%3 (R,(;.8.&;(7I7
delete dialog;
^(R(i(7I7,(-& range.rightColumn()(9!#3 (<.%3 (M,(;.8.&;(7I7(^(M(i(7274
}

51% compare(!:a%"'(*'!/%*('1%(6/.$-/<,(*%"!& -/<,(-& ('%/'.-/<(*!/'(>%<*(-& ('1%./(*!/'(!/ %/*4(QO%


9.33(*%%('1%( %0.&.'.!&(!0('1% SpreadsheetCompare("3-**(.&('1%(&%?'("1-6'%/4+(51%(!:a%"'(.*(#*% (:<
2/%-'.&;($! -3( .-3!;*(Q-& ("!&'%?'($%&#*(.& QWidget::contextMenuEvent()(/%.$63%$%&'-'.!&*+(!&
Spreadsheet::sort()('!("!$6-/%('9!(/!9*4(51% keys(-//-<(*'!/%*('1%("!3#$&(&#$:%/*(!0('1%(>%<*4
'1%(*'-">(.*(-("!$$!&(6/!;/-$$.&;(6-''%/&(*.&"%(9%(#*#-33<( !&7'(&%% ('1%( .-3!;(Q!/($%&#+(-0'%/
@!/(%?-$63%,(.0('1%(*%3%"'.!&(%?'%& *(0/!$(2M('!(Dj,("!3#$&(2(1-*(6!*.'.!&(R4(51% ascending(-//-<
9%(1-8%(#*% (.',(-& (.'(9.33(-#'!$-'."-33<(:%( %*'/!<% (-'('1%(%& (!0('1%(%&"3!*.&;(*"!6%4
*'!/%*('1%(!/ %/(-**!".-'% (9.'1(%-"1(>%<(-*(- bool4 QComboBox::current-Index()(/%'#/&*('1%(.& %?(!0
'1%("#//%&'3<(*%3%"'% (.'%$,(*'-/'.&;(-'(R4(@!/('1%(*%"!& -/<(-& ('%/'.-/<(>%<*,(9%(*#:'/-"'(!&%(0/!$
O%(9.33(&!9('#/&('!('1%(N!/'( .-3!;4(51%(N!/'( .-3!;(.*(-($! -3( .-3!;('1-'(-33!9*('1%(#*%/('!(*!/'('1%
'1%("#//%&'(.'%$('!(-""!#&'(0!/('1%(SC!&%S(.'%$4
"#//%&'3<(*%3%"'% (-/%-(:<('1%("!3#$&*('1%<(*6%".0<4 @.;#/%(A4L`(*1!9*(-&(%?-$63%(!0(*!/'.&;,(9.'1
"!3#$&(T(-*('1%(6/.$-/<(*!/'(>%<(-& ("!3#$&(I(-*('1%(*%"!& -/<(*!/'(>%<(Q:!'1(-*"%& .&;+4
51% sort()(0#&"'.!&( !%*('1%(a!:,(:#'(.'(.*(-(:.'(0/-;.3%4(='(-**#$%*('1-'('1%(N!/'( .-3!;(.*
.$63%$%&'% .&(-(6-/'."#3-/(9-<,(9.'1("!$:!:!?%*(-& (SC!&%S(.'%$*4(51.*($%-&*('1-'(.0(9%
!"#$%&'(7H(&C,$1!0"&15%&2>$%/?25%%1D2&2%<%41%?&/$%/ /% %*.;&('1%(N!/'( .-3!;,(9%($-<(-3*!(&%% ('!(/%9/.'%('1.*("! %4(O1.3%('1.*(-66/!-"1(.*(- %[#-'%(0!/
[View full size image]
-( .-3!;('1-'(.*(!&3<("-33% (0/!$(!&%(63-"%,(.'(!6%&*('1%( !!/('!($-.&'%&-&"% &.;1'$-/%*(.0('1%( .-3!;
.*(#*% (.&(*%8%/-3(63-"%*4

I($!/%(/!:#*'(-66/!-"1(.*('!($->%('1% SortDialog("3-**(*$-/'%/(:<(1-8.&;(.'("/%-'%(-
SpreadsheetCompare(!:a%"'(.'*%30,(91."1("-&('1%&(:%(-""%**% (:<(.'*("-33%/4(51.*(*.$63.0.%*
MainWindow::sort()(*.;&.0."-&'3<E

void MainWindow::sort()
{
SortDialog dialog(this);
QTableWidgetSelectionRange range = spreadsheet->selectedRange();
dialog.setColumnRange('A' + range.leftColumn(),
'A' + range.rightColumn());
if (dialog.exec())
void MainWindow::sort() spreadsheet->performSort(dialog.comparisonObject());
{ }
SortDialog dialog(this);
QTableWidgetSelectionRange range = spreadsheet->selectedRange();
dialog.setColumnRange('A' + range.leftColumn(), 51.*(-66/!-"1(3%- *('!(3!!*%3<("!#63% ("!$6!&%&'*(-& (.*(-3$!*'(-39-<*('1%(/.;1'("1!."%(0!/( .-3!;*
'A' + range.rightColumn());
if (dialog.exec()) {
'1-'(9.33(:%("-33% (0/!$($!/%('1-&(!&%(63-"%4

I($!/%(/- ."-3(-66/!-"1(9!#3 (:%('!(6-** -(6!.&'%/('!('1% Spreadsheet(!:a%"'(91%&(.&.'.-3.d.&;('1%


SortDialog(!:a%"'(-& ('!(-33!9('1%( .-3!;('!(!6%/-'%( ./%"'3<(!&('1% Spreadsheet4(51.*($->%*('1%
SortDialog($#"1(3%**(;%&%/-3,(*.&"%(.'(9.33(!&3<(9!/>(!&(-("%/'-.&('<6%(!0(9. ;%',(:#'(.'(*.$63.0.%* '1%
"! %(%8%&(0#/'1%/(:<(%3.$.&-'.&;('1% SortDialog::setColumnRange()(0#&"'.!&4(51% MainWindow::sort()
0#&"'.!&('1%&(:%"!$%*

void MainWindow::sort()
{
SortDialog dialog(this);
dialog.setSpreadsheet(spreadsheet);
dialog.exec();
}

51.*(-66/!-"1($.//!/*('1%(0./*'E(=&*'%- (!0('1%("-33%/(&%% .&;(.&'.$-'%(>&!93% ;%(!0('1%( .-3!;,('1%


.-3!;(&%% *(.&'.$-'%(>&!93% ;%(!0('1%( -'-(*'/#"'#/%*(*#663.% (:<('1%("-33%/4(51.*(-66/!-"1($-<(:% N!(0-/(9%(1-8%(#*% (*%8%/-3("!&8%&.%&"%(*'-'."(0#&"'.!&*(0/!$(:!'1 QMessageBox(-& QFileDialog4
#*%0#3(91%/%('1%( .-3!;(&%% *('!(-663<("1-&;%*(3.8%4(T#'(a#*'(-*('1%("-33%/("! %(.*(0/-;.3%(#*.&;('1% 51%*%(0#&"'.!&*("/%-'%(-( .-3!;,(.&.'.-3.d%(.',(-& ("-33 exec()(!&(.'4(='(.*(-3*!(6!**.:3%,(-3'1!#;1(3%**
0./*'(-66/!-"1,('1.*('1./ (-66/!-"1(:/%->*(.0('1%( -'-(*'/#"'#/%*("1-&;%4 "!&8%&.%&',('!("/%-'%(- QMessageBox(!/(- QFileDialog(9. ;%'(3.>%(-&<(!'1%/(9. ;%'(-& (%?63.".'3<("-33
exec(),(!/(%8%& show(),(!&(.'4
N!$%( %8%3!6%/*("1!!*%(a#*'(!&%(-66/!-"1('!(#*.&;( .-3!;*(-& (*'.">(9.'1('1-'4(51.*(1-*('1%(:%&%0.'
!0(0-$.3.-/.'<(-& (*.$63.".'<(*.&"%(-33('1%./( .-3!;(#*-;%*(0!33!9('1%(*-$%(6-''%/&,(:#'(.'(-3*!($.**%*
'1%(:%&%0.'*(!0('1%(-66/!-"1%*('1-'(-/%(&!'(#*% 4(= %-33<,('1%(-66/!-"1('!(#*%(*1!#3 (:%( %". % (!&
-(6%/K .-3!;(:-*.*4 Storing Settings
O%(9.33(/!#& (!00('1.*(*%"'.!&(9.'1('1%(I:!#'(:!?4(O%("!#3 ("/%-'%(-("#*'!$( .-3!;(3.>%(9%( . (0!/ =&('1% MainWindow("!&*'/#"'!/,(9%("-33% readSettings()('!(3!- ('1%(-663."-'.!&7*(*'!/% (*%''.&;*4
'1%(@.& (!/(e!K'!K2%33( .-3!;*('!(6/%*%&'('1%(.&0!/$-'.!&(-:!#'('1%(-663."-'.!&,(:#'(*.&"%($!*'(I:!#' N.$.3-/3<,(.& closeEvent(),(9%("-33% writeSettings()('!(*-8%('1%(*%''.&;*4(51%*%('9!(0#&"'.!&*(-/%
:!?%*(-/%(1.;13<(*'<3.d% ,(U'(6/!8. %*(-(*.$63%/(*!3#'.!&4 '1%(3-*' MainWindow($%$:%/(0#&"'.!&*('1-'(&%% ('!(:%(.$63%$%&'% 4

void MainWindow::about() void MainWindow::writeSettings()


{ {
QMessageBox::about(this, tr("About Spreadsheet"), QSettings settings("Software Inc.", "Spreadsheet");
tr("<h2>Spreadsheet 1.1</h2>" settings.setValue("geometry", geometry());
"<p>Copyright &copy; 2006 Software Inc." settings.setValue("recentFiles", recentFiles);
"<p>Spreadsheet is a small application that " settings.setValue("showGrid", showGridAction->isChecked());
"demonstrates QAction, QMainWindow, QMenuBar, " settings.setValue("autoRecalc", autoRecalcAction->isChecked());
"QStatusBar, QTableWidget, QToolBar, and many other " }
"Qt classes."));
}
51% writeSettings()(0#&"'.!&(*-8%*('1%($-.&(9.& !97*(;%!$%'/<(Q6!*.'.!&(-& (*.d%+,('1%(3.*'(!0
/%"%&'3<(!6%&% (0.3%*,(-& ('1%(N1!9(e/. (-& (I#'!Kc%"-3"#3-'%(!6'.!&*4
51%(I:!#'(:!?(.*(!:'-.&% (:<("-33.&; QMessageBox::about(),(-(*'-'."("!&8%&.%&"%(0#&"'.!&4(51%
0#&"'.!&(.*(8%/<(*.$.3-/('! QMessageBox::warning(),(%?"%6'('1-'(.'(#*%*('1%(6-/%&'(9.& !97*(."!& T<( %0-#3', QSettings(*'!/%*('1%(-663."-'.!&7*(*%''.&;*(.&(63-'0!/$K*6%".0."(3!"-'.!&*4(G&(O.& !9*,(.'
.&*'%- (!0('1%(*'-& -/ (S9-/&.&;S(."!&4
#*%*('1%(*<*'%$(/%;.*'/<P(!&(b&.?,(.'(*'!/%*('1%( -'-(.&('%?'(0.3%*P(!&(V-"(GN(W,(.'(#*%*('1%(2!/%
@!#& -'.!&(k/%0%/%&"%*(Ik=4
!"#$%&'(7I(&J:,#1&C>$%/?25%%1
51%("!&*'/#"'!/(-/;#$%&'*(*6%".0<('1%(!/;-&.d-'.!&7*(&-$%(-& ('1%(-663."-'.!&7*(&-$%4(51.*
.&0!/$-'.!&(.*(#*% (.&(-(63-'0!/$K*6%".0."(9-<('!(0.& (-(3!"-'.!&(0!/('1%(*%''.&;*4

QSettings(*'!/%*(*%''.&;*(-* /$01'%2$(6-./*4(51% /$0(.*(*.$.3-/('!(-(0.3%(*<*'%$(6-'14(N#:>%<*("-&


:%(*6%".0.% (#*.&;(-(6-'1K3.>%(*<&'-?(Q0!/(%?-$63%, findDialog/matchCase+(!/(#*.&; beginGroup()(-&
endGroup()E

settings.beginGroup("findDialog");
settings.setValue("matchCase", caseCheckBox->isChecked());
settings.setValue("searchBackward", backwardCheckBox->isChecked());
settings.endGroup();
51% 1'%2$("-&(:%(-& int,(- bool,(- double,(- QString,(- QStringList,(!/(-&<(!'1%/('<6%(*#66!/'% (:< 51.* main()(0#&"'.!&(.*(-(3.''3%(:.'( .00%/%&'(0/!$('1!*%(9%(1-8%(9/.''%&(*!(0-/E(O%(1-8%("/%-'% ('1%
QVariant,(.&"3# .&;(/%;.*'%/% ("#*'!$('<6%*4 MainWindow(.&*'-&"%(-*(-(8-/.-:3%(!&('1%(*'-">(.&*'%- (!0(#*.&; new4(51% MainWindow(.&*'-&"%(.*('1%&
-#'!$-'."-33<( %*'/!<% (91%&('1%(0#&"'.!&('%/$.&-'%*4

void MainWindow::readSettings() O.'1('1% main()(0#&"'.!&(*1!9&(-:!8%,('1%(N6/%- *1%%'(-663."-'.!&(6/!8. %*(-(*.&;3%($-.&(9.& !9


{ -& ("-&(!&3< 1-& 3%(!&%( !"#$%&'(-'(-('.$%4(=0(9%(9-&'('!(% .'($#3'.63%( !"#$%&'*(-'('1%(*-$%
QSettings settings("Software Inc.", "Spreadsheet"); '.$%,(9%("!#3 (*'-/'($#3'.63%(.&*'-&"%*(!0('1%(N6/%- *1%%'(-663."-'.!&4(T#'('1.*(.*&7'(-*("!&8%&.%&'
QRect rect = settings.value("geometry",
0!/(#*%/*(-*(1-8.&;(-(*.&;3%(.&*'-&"%(!0('1%(-663."-'.!&(6/!8. .&;($#3'.63%($-.&(9.& !9*,(a#*'(-*(!&%
QRect(200, 200, 400, 400)).toRect();
.&*'-&"%(!0(-(9%:(:/!9*%/("-&(6/!8. %($#3'.63%(:/!9*%/(9.& !9*(*.$#3'-&%!#*3<4
move(rect.topLeft());
resize(rect.size());
recentFiles = settings.value("recentFiles").toStringList(); O%(9.33($! .0<('1%(N6/%- *1%%'(-663."-'.!&(*!('1-'(.'("-&(1-& 3%($#3'.63%( !"#$%&'*4 @./*',(9%(&%%
updateRecentFileActions(); -(*3.;1'3<( .00%/%&'(@.3%($%&#E
bool showGrid = settings.value("showGrid", true).toBool();
showGridAction->setChecked(showGrid); • @.3%FC%9("/%-'%* -(&%9($-.&(9.& !9(9.'1(-&(%$6'<( !"#$%&',(.&*'%- (!0(/%#*.&;('1%
%?.*'.&;($-.&(9.& !94
bool autoRecalc = settings.value("autoRecalc", true).toBool(); • @.3%F23!*%("3!*%*('1%("#//%&'($-.&(9.& !94
autoRecalcAction->setChecked(autoRecalc);
• @.3%FD?.'("3!*%*(-33(9.& !9*4
}

=&('1%(!/.;.&-3(8%/*.!&(!0('1%(@.3%($%&#,('1%/%(9-*(&!(23!*%(!6'.!&(:%"-#*%('1-'(9!#3 (1-8%(:%%&
'1%(*-$%(-*(D?.'4
51% readSettings()(0#&"'.!&(3!- *('1%(*%''.&;*('1-'(9%/%(*-8% (:< writeSettings()4(51%(*%"!&
-/;#$%&'('!('1% value()(0#&"'.!&(*6%".0.%*(-( %0-#3'(8-3#%,(.&("-*%('1%/%(-/%(&!(*%''.&;*(-8-.3-:3%4
51%( %0-#3'(8-3#%*(-/%(#*% ('1%(0./*'('.$%('1%(-663."-'.!&(.*(/#&4(N.&"%(&!(*%"!& (-/;#$%&'(.*(;.8%&
!"#$%&'(7K(&B5%&0%.& !<%&=%0#
0!/('1%(/%"%&'(0.3%*(3.*',(.'(9.33(:%(*%'('!(-&(%$6'<(3.*'(!&('1%(0./*'(/#&4

U'(6/!8. %*(- QWidget::setGeometry()(0#&"'.!&('!("!$63%$%&' QWidget::geometry(),(:#'(.'( !%*&7'


-39-<*(9!/>(-*(9%(9!#3 (%?6%"'(!&(WLL(:%"-#*%(!0(3.$.'-'.!&*(.&($-&<(9.& !9($-&-;%/*4(@!/('1-'
/%-*!&,(9%(#*% move()(-& resize()(.&*'%- 4(QN%% 1''6Ell !"4'/!33'%"14"!$l`4Ll;%!$%'/<41'$3(0!/(-
%'-.3% (%?63-&-'.!&4+

51%(-//-&;%$%&'(9%(!6'% (0!/(.& MainWindow,(9.'1(-33('1% QSettingsK/%3-'% ("! %(.& readSettings()


-& writeSettings(),(.*(a#*'(!&%(!0($-&<(6!**.:3%(-66/!-"1%*4(I QSettings(!:a%"'("-&(:%("/%-'% ('!
[#%/<(!/($! .0<(*!$%(*%''.&;(-'(-&<('.$%( #/.&;('1%(%?%"#'.!&(!0('1%(-663."-'.!&(-& (0/!$(-&<91%/%
.&('1%("! %4

O%(1-8%(&!9("!$63%'% ('1%(N6/%- *1%%'7* MainWindow(.$63%$%&'-'.!&4(=&('1%(0!33!9.&;(*%"'.!&*,(9%


9.33( .*"#**(1!9('1%(N6/%- *1%%'(-663."-'.!&("-&(:%($! .0.% ('!(1-& 3%($#3'.63%( !"#$%&'*(-& (1!9
'!(.$63%$%&'(-(*63-*1(*"/%%&4(O%(9.33("!$63%'%(.'*(0#&"'.!&-3.'<,(.&"3# .&;(1-& 3.&;(0!/$#3-*(-&
*!/'.&;,(.&('1%(&%?'("1-6'%/4 51.*(.*('1%(&%9 main()(0#&"'.!&E

int main(int argc, char *argv[])


{
QApplication app(argc, argv);
MainWindow *mainWin = new MainWindow;
Multiple Documents mainWin->show();
return app.exec();
O%(-/%(&!9(/%- <('!("! %('1%(N6/%- *1%%'(-663."-'.!&7* main()(0#&"'.!&E }

include <QApplication> O.'1($#3'.63%(9.& !9*,(.'(&!9($->%*(*%&*%('!("/%-'% MainWindow(9.'1 new,(:%"-#*%('1%&(9%("-&(#*%


include "mainwindow.h" delete(!&(-($-.&(9.& !9(91%&(9%(1-8%(0.&.*1% (9.'1(.'('!(*-8%($%$!/<4
int main(int argc, char *argv[])
{
QApplication app(argc, argv); 51.*(.*('1%(&%9 MainWindow::newFile()(*3!'E
MainWindow mainWin;
mainWin.show();
return app.exec(); void MainWindow::newFile()
} {
MainWindow *mainWin = new MainWindow; foreach (QWidget *win, QApplication::topLevelWidgets()) {
mainWin->show(); if (MainWindow *mainWin = qobject_cast<MainWindow *>(win))
} mainWin->updateRecentFileActions();
}

O%(*.$63<("/%-'%(-(&%9 MainWindow(.&*'-&"%4(='($-<(*%%$(! ('1-'(9%( !&7'(>%%6(-&<(6!.&'%/('!('1%


&%9(9.& !9,(:#'('1-'(.*&7'(-(6/!:3%$(*.&"%(U'(>%%6*('/-">(!0(-33('1%(9.& !9*(0!/(#*4 51%("! %(#*%*(U'7* foreach("!&*'/#"'(Q%?63-.&% (.& 21-6'%/(LL+('!(.'%/-'%(!8%/(-33('1%(-663."-'.!&7*
9.& !9*(-& ("-33* updateRecentFileActions()(!&(-33(9. ;%'*(!0('<6% MainWindow4(N.$.3-/("! %("-&(:%
51%*%(-/%('1%(-"'.!&*(0!/(23!*%(-& (D?.'E #*% (0!/(*<&"1/!&.d.&;('1%(N1!9(e/. (-& (I#'!Kc%"-3"#3-'%(!6'.!&*,(!/('!($->%(*#/%('1-'('1%(*-$%
0.3%(.*&7'(3!- % ('9."%4

void MainWindow::createActions() I663."-'.!&*('1-'(6/!8. %(!&%( !"#$%&'(6%/($-.&(9.& !9(-/%(*-. ('!(:%(Nm=(Q*.&;3%( !"#$%&'


{ .&'%/0-"%+(-663."-'.!&*4(I("!$$!&(-3'%/&-'.8%(!&(O.& !9*(.*(Vm=(Q$#3'.63%( !"#$%&'(.&'%/0-"%+,
... 91%/%('1%(-663."-'.!&(1-*(-(*.&;3%($-.&(9.& !9('1-'($-&-;%*($#3'.63%( !"#$%&'(9.& !9*(9.'1.&(.'*
closeAction = new QAction(tr("&Close"), this); "%&'/-3(-/%-4(U'("-&(:%(#*% ('!("/%-'%(:!'1(Nm=(-& (Vm=(-663."-'.!&*(!&(-33(.'*(*#66!/'% (63-'0!/$*4
closeAction->setShortcut(tr("Ctrl+W")); @.;#/%(A4Lg *1!9*('1%(N6/%- *1%%'(-663."-'.!&(#*.&;(:!'1(-66/!-"1%*4(Vm=(.*(%?63-.&% (.& 21-6'%/(h
closeAction->setStatusTip(tr("Close this window")); QH-<!#'(V-&-;%$%&'+4
connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcut(tr("Ctrl+Q")); !"#$%&'(7L(&C+M&3%$2#2&9+M
exitAction->setStatusTip(tr("Exit the application"));
connect(exitAction, SIGNAL(triggered()), [View full size image]

qApp, SLOT(closeAllWindows()));
...
}

51% QApplication::closeAllWindows()(*3!'("3!*%*(-33(!0('1%(-663."-'.!&7*(9.& !9*,(#&3%**(!&%(!0('1%$


/%a%"'*('1%("3!*%(%8%&'4(51.*(.*(%?-"'3<('1%(:%1-8.!/(9%(&%% (1%/%4(O%( !&7'(1-8%('!(9!//<(-:!#'
#&*-8% ("1-&;%*(:%"-#*%('1-'7*(1-& 3% (.& MainWindow::closeEvent()(91%&%8%/(-(9.& !9(.*("3!*% 4

='(3!!>*(-*(.0(9%(1-8%(0.&.*1% ($->.&;('1%(-663."-'.!&("-6-:3%(!0(1-& 3.&;($#3'.63%(9.& !9*4


b&0!/'#&-'%3<,('1%/%(.*(-(1. %&(6/!:3%$(3#/>.&;E(=0('1%(#*%/(>%%6*("/%-'.&;(-& ("3!*.&;($-.&
9.& !9*,('1%($-"1.&%($.;1'(%8%&'#-33<(/#&(!#'(!0($%$!/<4(51.*(.*(:%"-#*%(9%(>%%6("/%-'.&;
MainWindow(9. ;%'*(.& newFile()(:#'(9%(&%8%/( %3%'%('1%$4(O1%&('1%(#*%/("3!*%*(-($-.&(9.& !9,
'1%( %0-#3'(:%1-8.!/(.*('!(1. %(.',(*!(.'(*'.33(/%$-.&*(.&($%$!/<4(O.'1($-&<($-.&(9.& !9*,('1.*("-&
:%(-(6/!:3%$4
Splash Screens
51%(*!3#'.!&(.*('!(*%'('1% Qt::WA_DeleteOnClose(-''/.:#'%(.&('1%("!&*'/#"'!/E
V-&<(-663."-'.!&*(6/%*%&'(-(*63-*1(*"/%%&(-'(*'-/'#64(N!$%( %8%3!6%/*(#*%(-(*63-*1(*"/%%&('!
.*;#.*%(-(*3!9(*'-/'#6,(91.3%(!'1%/*( !(.'('!(*-'.*0<('1%./($-/>%'.&;( %6-/'$%&'*4(I .&;(-(*63-*1
*"/%%&('!(U'(-663."-'.!&*(.*(8%/<(%-*<(#*.&;('1% QSplashScreen("3-**4
MainWindow::MainWindow()
{
... 51% QSplashScreen("3-**(*1!9*(-&(.$-;%(:%0!/%('1%($-.&(9.& !9(-66%-/*4(='("-&(-3*!(9/.'%
setAttribute(Qt::WA_DeleteOnClose); $%**-;%*(!&('1%(.$-;%('!(.&0!/$('1%(#*%/(-:!#'('1%(6/!;/%**(!0('1%(-663."-'.!&7*(.&.'.-3.d-'.!&
... 6/!"%**4(5<6."-33<,('1%(*63-*1(*"/%%&("! %(.*(3!"-'% (.& main(),(:%0!/%('1%("-33('!
} QApplication::exec()4

C%?'(.*(-&(%?-$63% main()(0#&"'.!&('1-'(#*%* QSplashScreen('!(6/%*%&'(-(*63-*1(*"/%%&(.&(-&


51.*('%33*(U'('!( %3%'%('1%(9.& !9(91%&(.'(.*("3!*% 4(51% Qt::WA_DeleteOnClose(-''/.:#'%(.*(!&%(!0 -663."-'.!&('1-'(3!- *($! #3%*(-& (%*'-:3.*1%*(&%'9!/>("!&&%"'.!&*(-'(*'-/'#64
$-&<(03-;*('1-'("-&(:%(*%'(!&(- QWidget('!(.&03#%&"%(.'*(:%1-8.!/4

V%$!/<(3%->.&;(.*&7'('1%(!&3<(6/!:3%$('1-'(9%($#*'( %-3(9.'14(G#/(!/.;.&-3(-663."-'.!&( %*.;& int main(int argc, char *argv[])


.&"3# % (-&(.$63.% (-**#$6'.!&('1-'(9%(9!#3 (!&3<(1-8%(!&%($-.&(9.& !94(O.'1($#3'.63%(9.& !9*, {
%-"1($-.&(9.& !9(1-*(.'*(!9&(/%"%&'3<(!6%&% (0.3%*(3.*'(-& (.'*(!9&(!6'.!&*4(23%-/3<,('1%(/%"%&'3< QApplication app(argc, argv);
!6%&% (0.3%*(3.*'(*1!#3 (:%(;3!:-3('!('1%(91!3%(-663."-'.!&4(O%("-&(-"1.%8%('1.*([#.'%(%-*.3<(:< QSplashScreen *splash = new QSplashScreen;
splash->setPixmap(QPixmap(":/images/splash.png"));
%"3-/.&;('1% recentFiles(8-/.-:3%(*'-'.",(*!('1-'(!&3<(!&%(.&*'-&"%(!0(.'(%?.*'*(0!/('1%(91!3%
splash->show();
-663."-'.!&4(T#'('1%&(9%($#*'(%&*#/%('1-'(91%/%8%/(9%("-33% updateRecentFileActions()('!(#6 -'% Qt::Alignment topRight = Qt::AlignRight | Qt::AlignTop;
'1%(@.3%($%&#,(9%($#*'("-33(.'(!&(-33($-.&(9.& !9*4(J%/%7*('1%("! %('!(-"1.%8%('1.*E splash->showMessage(QObject::tr("Setting up the main window..."),
topRight, Qt::white);
MainWindow mainWin;
splash->showMessage(QObject::tr("Loading modules..."),
topRight, Qt::white);
loadModules();
splash->showMessage(QObject::tr("Establishing connections..."),
Chapter 4. Implementing Application
topRight, Qt::white);
establishConnections(); Functionality
mainWin.show();
splash->finish(&mainWin);
• !"#$"%&'()#*+,-"&
delete splash;
• ./01)(22+%-#3 (0)"*+,-"&
return app.exec();
} • 45(,+%-#(%,#.(6+%-
• 789)"8"%&+%-#&!"#:,+&#;"%/
• 789)"8"%&+%-#&!"#<&!"'#;"%/2
• ./01)(22+%-#3 (0)"*+,-"&7&"8
!"#$%&'(7N(&J&2></25&24$%%0
=&('1%(6/%8.!#*('9!("1-6'%/*,(9%(%?63-.&% (1!9('!("/%-'%('1%(N6/%- *1%%'(-663."-'.!&7*(#*%/
.&'%/0-"%4(=&('1.*("1-6'%/,(9%(9.33("!$63%'%('1%(6/!;/-$(:<("! .&;(.'*(#& %/3<.&;(0#&"'.!&-3.'<4
I$!&;(!'1%/('1.&;*,(9%(9.33(*%%(1!9('!(3!- (-& (*-8%(0.3%*,(1!9('!(*'!/%( -'-(.&($%$!/<,(1!9('!
.$63%$%&'("3.6:!-/ (!6%/-'.!&*,(-& (1!9('!(- (*#66!/'(0!/(*6/%- *1%%'(0!/$#3-*('! QTableWidget4

The Central Widget


51%("%&'/-3(-/%-(!0(- QMainWindow("-&(:%(!""#6.% (:<(-&<(>.& (!0(9. ;%'4 J%/%7*(-&(!8%/8.%9(!0('1%
6!**.:.3.'.%*E

L4 O2%&/&21/0?/$?&P1&.!?"%1(

I(*'-& -/ (9. ;%'(3.>% QTableWidget(!/ QTextEdit("-&(:%(#*% (-*(-("%&'/-3(9. ;%'4(=&('1.*


"-*%,('1%(-663."-'.!&7*(0#&"'.!&-3.'<,(*#"1(-*(3!- .&;(-& (*-8.&;(0.3%*,($#*'(:%(.$63%$%&'%
%3*%91%/%(Q0!/(%?-$63%,(.&(- QMainWindow(*#:"3-**+4

M4 O2%&/&4#21,=&.!?"%1(

N6%".-3.d% (-663."-'.!&*(!0'%&(&%% ('!(*1!9( -'-(.&(-("#*'!$(9. ;%'4(@!/(%?-$63%,(-&(."!&


% .'!/(6/!;/-$(9!#3 (1-8%(-& IconEditor(9. ;%'(-*(.'*("%&'/-3(9. ;%'4 21-6'%/(j(%?63-.&*
O%(1-8%(&!9("!$63%'% ('1%(N6/%- *1%%'(-663."-'.!&7*(#*%/(.&'%/0-"%4(=&('1%(&%?'("1-6'%/,(9%(9.33 1!9('!(9/.'%("#*'!$(9. ;%'*(.&(U'4
"!$63%'%('1%(-663."-'.!&(:<(.$63%$%&'.&;('1%("!/%(*6/%- *1%%'(0#&"'.!&-3.'<4
A4 O2%&/&></!0&PQ!?"%1&.!15&/&</-,#1&=/0/"%$(

N!$%'.$%*('1%(-663."-'.!&7*("%&'/-3(-/%-(.*(!""#6.% (:<($-&<(9. ;%'*4(51.*("-&(:%( !&%(:<


#*.&;(- QWidget(-*('1%(6-/%&'(!0(-33('1%(!'1%/(9. ;%'*,(-& (#*.&;(3-<!#'($-&-;%/*('!(*.d%(-&
6!*.'.!&('1%("1.3 (9. ;%'*4

`4 O2%&/&2><!11%$(

I&!'1%/(9-<(!0(#*.&;($#3'.63%(9. ;%'*('!;%'1%/(.*('!(#*%(- QSplitter4(51% QSplitter(-//-&;%*


.'*("1.3 (9. ;%'*(1!/.d!&'-33<(!/(8%/'."-33<,(9.'1(*63.''%/(1-& 3%*('!(;.8%(*!$%(*.d.&;("!&'/!3('!
'1%(#*%/4(N63.''%/*("-&("!&'-.&(-33(>.& *(!0(9. ;%'*,(.&"3# .&;(!'1%/(*63.''%/*4

j4 O2%&/0&9+M&.,$R2>/4%(

=0('1%(-663."-'.!&(#*%*(Vm=,('1%("%&'/-3(-/%-(.*(!""#6.% (:<(- QWorkspace(9. ;%',(-& (%-"1(!0


'1%(Vm=(9.& !9*(.*(-("1.3 (!0('1-'(9. ;%'4

H-<!#'*,(*63.''%/*,(-& (Vm=(9!/>*6-"%*("-&(:%("!$:.&% (9.'1(*'-& -/ (U'(9. ;%'*(!/(9.'1("#*'!$


9. ;%'*4 21-6'%/(h("!8%/*('1%*%("3-**%*(.&( %6'14

@!/('1%(N6/%- *1%%'(-663."-'.!&,(- QTableWidget(*#:"3-**(.*(#*% (-*('1%("%&'/-3(9. ;%'4(51%


QTableWidget("3-**(-3/%- <(6/!8. %*($!*'(!0('1%(*6/%- *1%%'("-6-:.3.'<(9%(&%% ,(:#'(.'( !%*&7' =& 21-6'%/(A,(9%(/%3.% (!&(*!$%(6#:3."(0#&"'.!&*(.& Spreadsheet(91%&(9%(.$63%$%&'% MainWindow4
*#66!/'("3.6:!-/ (!6%/-'.!&*(-& ( !%*&7'(#& %/*'-& (*6/%- *1%%'(0!/$#3-*(3.>%(SiIL^IM^IAS4(O% @!/(%?-$63%,(9%("-33% clear()(0/!$ MainWindow::newFile()('!(/%*%'('1%(*6/%- *1%%'4(O%(-3*!(#*%
9.33(.$63%$%&'('1.*($.**.&;(0#&"'.!&-3.'<(.&('1% Spreadsheet("3-**4 *!$%(0#&"'.!&*(.&1%/.'% (0/!$ QTableWidget,(&!'-:3< setCurrentCell()(-& setShowGrid()4

Subclassing QTableWidget public slots:


void cut();
51% Spreadsheet("3-**(.&1%/.'*(0/!$ QTableWidget4(I QTableWidget(.*(%00%"'.8%3<(-(;/. ('1-'(/%6/%*%&'* void copy();
-('9!K .$%&*.!&-3(*6-/*%(-//-<4(='( .*63-<*(91."1%8%/("%33*('1%(#*%/(*"/!33*('!,(9.'1.&(.'*(*6%".0.% void paste();
.$%&*.!&*4(O1%&('1%(#*%/(%&'%/*(*!$%('%?'(.&'!(-&(%$6'<("%33, QTableWidget(-#'!$-'."-33<("/%-'%* void del();
void selectCurrentRow();
- QTableWidgetItem('!(*'!/%('1%('%?'4
void selectCurrentColumn();
void recalculate();
H%'7*(*'-/'(.$63%$%&'.&; Spreadsheet,(:%;.&&.&;(9.'1('1%(1%- %/(0.3%E void setAutoRecalculate(bool recalc);
void findNext(const QString &str, Qt::CaseSensitivity cs);
void findPrevious(const QString &str, Qt::CaseSensitivity cs);
#ifndef SPREADSHEET_H signals:
#define SPREADSHEET_H void modified();
#include <QTableWidget>
class Cell;
class SpreadsheetCompare;
Spreadsheet(6/!8. %*($-&<(*3!'*('1-'(.$63%$%&'(-"'.!&*(0/!$('1%(D .',(5!!3*,(-& (G6'.!&*($%&#*,
-& (.'(6/!8. %*(!&%(*.;&-3, modified(),('!(-&&!#&"%(-&<("1-&;%('1-'(1-*(!""#//% 4

51%(1%- %/(*'-/'*(9.'1(0!/9-/ ( %"3-/-'.!&*(0!/('1% Cell(-& SpreadsheetCom-pare("3-**%*4


private slots:
!"#$%&H(7(&M05%$!1/04%&1$%%2&@,$ Spreadsheet&/0? Cell void somethingChanged();

O%( %0.&%(!&%(6/.8-'%(*3!'(#*% (.&'%/&-33<(:<('1% Spreadsheet("3-**4

private:
enum { MagicNumber = 0x7F51C883, RowCount = 999, ColumnCount = 26 };
Cell *cell(int row, int column) const;
QString text(int row, int column) const;
QString formula(int row, int column) const;
void setFormula(int row, int column, const QString &formula);
bool autoRecalc;
};
51%(-''/.:#'%*(!0(- QTableWidget("%33,(*#"1(-*(.'*('%?'(-& (.'*(-3.;&$%&',(-/%(*'!/% (.&(-
QTableWidgetItem4(b&3.>% QTableWidget, QTableWidgetItem(.*&7'(-(9. ;%'("3-**P(.'(.*(-(6#/%( -'-("3-**4
51% Cell("3-**(.&1%/.'* QTableWidgetItem(-& (.*(%?63-.&% (91%&(.'*(.$63%$%&'-'.!&(.*(*1!9&(.&('1.*
=&('1%("3-**7*(6/.8-'%(*%"'.!&,(9%( %"3-/%('1/%%("!&*'-&'*,(0!#/(0#&"'.!&*,(-& (!&%(8-/.-:3%4
"1-6'%/7*(3-*'(*%"'.!&4

class SpreadsheetCompare
class Spreadsheet : public QTableWidget
{
{
public:
Q_OBJECT
bool operator()(const QStringList &row1,
public:
const QStringList &row2) const;
Spreadsheet(QWidget *parent = 0);
enum { KeyCount = 3 };
bool autoRecalculate() const { return autoRecalc; }
int keys[KeyCount];
QString currentLocation() const;
bool ascending[KeyCount];
QString currentFormula() const;
};
QTableWidgetSelectionRange selectedRange() const;
#endif
void clear();
bool readFile(const QString &fileName);
bool writeFile(const QString &fileName);
void sort(const SpreadsheetCompare &compare); !"#!"$%"&#'()"#"*%+#,(-!#-!" SpreadsheetCompare#.)$++#%"'(*(-(/*0#1"#,())#"23)$(*#-!(+#,!"*#,"
&"4(", Spreadsheet::sort()0

51% autoRecalculate()(0#&"'.!&(.*(.$63%$%&'% (.&3.&%(*.&"%(.'(a#*'(/%'#/&*(91%'1%/(!/(&!'(-#'!K 1"#,())#*/,#)//5#$-#-!"#(63)"6"*-$-(/*7


/%"-3"#3-'.!&(.*(.&(0!/"%4
#include <QtGui>
#include "cell.h"
#include "spreadsheet.h"
Spreadsheet::Spreadsheet(QWidget *parent)
: QTableWidget(parent)
{
autoRecalc = true;
setItemPrototype(new Cell);
setSelectionMode(ContiguousSelection);
connect(this, SIGNAL(itemChanged(QTableWidgetItem *)),
this, SLOT(somethingChanged()));
clear();
}

8/&6$))9:#,!"*#-!"#;+"&#"*-"&+#+/6"#-"2-#/*#$*#"63-9#.")):#-!" QTableWidget#,())#$;-/6$-(.$))9
.&"$-"#$ QTableWidgetItem#-/#!/)%#-!"#-"2-0#<*#/;&#+3&"$%+!""-:#,"#,$*- Cell#(-"6+#-/#="#.&"$-"%
(*+-"$%0# !(+#(+#$.!("4"%#=9#-!" setItemPrototype()#.$))#(*#-!"#./*+-&;.-/&0#<*-"&*$))9: QTableWidget 2/-$!."&34/4&4+&5/%6+
.)/*"+#-!"#(-"6#3$++"%#$+#$#3&/-/-93"#"4"&9#-(6"#$#*",#(-"6#(+#&">;(&"%0
<*#-!"#R3&"$%+!""-#$33)(.$-(/*:#"4"&9#*/*S"63-9#."))#(+#+-/&"%#(*#6"6/&9#$+#$*
?)+/#(*#-!"#./*+-&;.-/&:#,"#+"-#-!"#+")".-(/*#6/%"#-/ QAbstractItemView::ContiguousSelection#-/ (*%(4(%;$) QTableWidgetItem#/=T".-0#R-/&(*@#%$-$#$+#(-"6+#(+#$*#$33&/$.!#-!$-#(+#$)+/
$))/,#$#+(*@)"#&".-$*@;)$&#+")".-(/*0#1"#./**".-#-!"#-$=)"#,(%@"-A+ itemChanged()#+(@*$)#-/#-!" ;+"%#=9 QListWidget#$*% QTReeWidget:#,!(.!#/3"&$-"#/* QListWidgetItem+#$*%
3&(4$-" somethingChanged()#+)/-B#-!(+#"*+;&"+#-!$-#,!"*#-!"#;+"&#"%(-+#$#.")):#-!" somethingChanged() QTReeWidgetItem+0
+)/-#(+#.$))"%0#C(*$))9:#,"#.$)) clear()#-/#&"+(D"#-!"#-$=)"#$*%#-/#+"-#-!"#./);6*#!"$%(*@+0
U-A+#(-"6#.)$++"+#.$*#="#;+"%#/;-#/'#-!"#=/2#$+#%$-$#!/)%"&+0#C/&#"2$63)":#$
QTableWidgetItem#$)&"$%9#+-/&"+#$#'",#$--&(=;-"+:#(*.);%(*@#$#+-&(*@:#'/*-:#./)/&:#$*%
void Spreadsheet::clear() (./*:#$*%#$#3/(*-"&#=$.5#-/#-!" QTableWidget0# !"#(-"6+#.$*#$)+/#!/)%#%$-$#FQVariant+J:
{ (*.);%(*@#&"@(+-"&"%#.;+-/6#-93"+:#$*%#=9#+;=.)$++(*@#-!"#(-"6 .)$++#,"#.$*#3&/4(%"
setRowCount(0); $%%(-(/*$)#';*.-(/*$)(-90
setColumnCount(0);
setRowCount(RowCount); V-!"&#-//)5(-+#3&/4(%"#$ void#3/(*-"&#(*#-!"(&#(-"6#.)$++"+#-/#+-/&"#.;+-/6#%$-$0#<*#U-:
setColumnCount(ColumnCount);
-!"#6/&"#*$-;&$)#$33&/$.!#(+#-/#;+" setData()#,(-!#$ QVariant:#=;-#('#$ void#3/(*-"&#(+
for (int i = 0; i < ColumnCount; ++i) {
QTableWidgetItem *item = new QTableWidgetItem; &">;(&"%:#(-#.$*#="#-&(4($))9#$.!("4"%#=9#+;=.)$++(*@#$*#(-"6#.)$++#$*%#$%%(*@#$ void
item->setText(QString(QChar('A' + i))); 3/(*-"&#6"6="&#4$&($=)"0
setHorizontalHeaderItem(i, item);
} C/&#6/&"#.!$))"*@(*@#%$-$#!$*%)(*@#&">;(&"6"*-+:#+;.!#$+#)$&@"#%$-$#+"-+:#./63)"2#%$-$
setCurrentCell(0, 0); (-"6+:#%$-$=$+"#(*-"@&$-(/*:#$*%#6;)-(3)"#%$-$#4(",+:#U-#3&/4(%"+#$#+"-#/'#6/%")W4(",
} .)$++"+#-!$-#+"3$&$-"#-!"#%$-$#'&/6#-!"(&#4(+;$)#&"3&"+"*-$-(/*0# !"+"#$&"#./4"&"%#(*
Q!$3-"&#OE0

!" clear()#';*.-(/*#(+#.$))"%#'&/6#-!" Spreadsheet#./*+-&;.-/&#-/#(*(-($)(D"#-!"#+3&"$%+!""-0#<-#(+


$)+/#.$))"%#'&/6 MainWindow::newFile()0 Cell *Spreadsheet::cell(int row, int column) const
{
1"#./;)%#!$4"#;+"% QTableWidget::clear()#-/#.)"$&#$))#-!"#(-"6+#$*%#$*9#+")".-(/*+:#=;-#-!$-#,/;)% return static_cast<Cell *>(item(row, column));
!$4"#)"'-#-!"#!"$%"&+#$-#-!"(&#.;&&"*-#+(D"0#<*+-"$%:#,"#&"+(D"#-!"#-$=)"#%/,*#-/#E#2#E0# !(+#.)"$&+ }
-!"#"*-(&"#+3&"$%+!""-:#(*.);%(*@#-!"#!"$%"&+0#1"#-!"*#&"+(D"#-!"#-$=)"#-/ ColumnCount#2 RowCount
FGH#2#IIIJ#$*%#3/3;)$-"#-!"#!/&(D/*-$)#!"$%"&#,(-! QTableWidgetItem+#./*-$(*(*@#-!"#./);6*#*$6"+
K?K:#KLK:#M:#KNK0#1"#%/*A-#*""%#-/#+"-#-!"#4"&-(.$)#!"$%"&#)$=")+:#=".$;+"#-!"+"#%"'$;)-#-/#KOK:#KGK: !" cell()#3&(4$-"#';*.-(/*#&"-;&*+#-!" Cell#/=T".-#'/&#$#@(4"*#&/,#$*%#./);6*0#<-#(+#$)6/+-#-!"
M:#KIIIK0#?-#-!"#"*%:#,"#6/4"#-!"#."))#.;&+/&#-/#."))#?O0 +$6"#$+ QTableWidget::item():#"2."3-#-!$-#(-#&"-;&*+#$ Cell#3/(*-"&#(*+-"$%#/'#$ QTableWidgetItem
3/(*-"&0
? QTableWidget#(+#./63/+"%#/'#+"4"&$)#.!()%#,(%@"-+0#<-#!$+#$#!/&(D/*-$) QHeaderView#$-#-!"#-/3:#$
4"&-(.$) QHeaderView#/*#-!"#)"'-:#$*%#-,/ QScrollBar+0# !"#$&"$#(*#-!"#6(%%)"#(+#/..;3("%#=9#$#+3".($)
,(%@"-#.$))"%#-!" !"#$%&':#/*#,!(.! QTableWidget#%&$,+#-!"#."))+0# !"#%(''"&"*-#.!()%#,(%@"-+#$&" QString Spreadsheet::text(int row, int column) const
$.."++(=)"#-!&/;@!#';*.-(/*+#(*!"&(-"%#'&/6 QTableView#$*% QAbstractScrollArea#F+"" C(@;&"#P0GJ0 {
Cell *c = cell(row, column);
QAbstractScrollArea#3&/4(%"+#$#+.&/))$=)"#4(",3/&-#$*%#-,/#+.&/))#=$&+:#,!(.!#.$*#="#-;&*"%#/*#$*%
if (c) {
/''0#<-+ QScrollArea#+;=.)$++#(+#./4"&"%#(* Q!$3-"&#H0 return c->text();
} else {
!"#$%&'()( QTableWidget*+&,-.+/!/#%./&0!1"%/+ return "";
}
}
!" currentLocation()#';*.-(/*#&"-;&*+#-!"#.;&&"*-#."))A+#)/.$-(/*#(*#-!"#;+;$)#+3&"$%+!""-#'/&6$-#/'
!" text()#3&(4$-"#';*.-(/*#&"-;&*+#-!"#-"2-#'/&#$#@(4"*#."))0#<' cell()#&"-;&*+#$#*;))#3/(*-"&:#-!"#.")) ./);6*#)"--"&#'/))/,"%#=9#&/,#*;6="&0 MainWindow::updateStatusBar()#;+"+#(-#-/ +!/,#-!"#)/.$-(/*#(*
(+#"63-9:#+/#,"#&"-;&*#$*#"63-9#+-&(*@0 -!"#+-$-;+#=$&0

QString Spreadsheet::formula(int row, int column) const QString Spreadsheet::currentFormula() const


{ {
Cell *c = cell(row, column); return formula(currentRow(), currentColumn());
if (c) { }
return c->formula();
} else {
return "";
!" currentFormula()#';*.-(/*#&"-;&*+#-!"#.;&&"*-#."))A+#'/&6;)$0#<-#(+#.$))"%#'&/6
}
} MainWindow::updateStatusBar()0

void Spreadsheet::somethingChanged()
!" formula()#';*.-(/*#&"-;&*+#-!"#."))A+#'/&6;)$0#<*#6$*9#.$+"+:#-!"#'/&6;)$#$*%#-!"#-"2-#$&"#-!" {
+$6"B#'/&#"2$63)":#-!"#'/&6;)$#KX"))/K#"4$);$-"+#-/#-!"#+-&(*@#KX"))/K:#+/#('#-!"#;+"&#-93"+#KX"))/K if (autoRecalc)
(*-/#$#."))#$*%#3&"++"+#Y*-"&:#-!$-#."))#,())#+!/,#-!"#-"2-#KX"))/K0 L;-#-!"&"#$&"#$#'",#"2."3-(/*+7 recalculate();
emit modified();
• <'#-!"#'/&6;)$#(+#$#*;6="&:#(-#(+#(*-"&3&"-"%#$+#+;.!0#C/&#"2$63)":#-!"#'/&6;)$#KO0ZEK }
"4$);$-"+#-/#-!" double#4$);"#O0Z:#,!(.!#(+#&"*%"&"%#$+#$#&(@!-S$)(@*"%#KO0ZK#(*#-!"
+3&"$%+!""-0
• <'#-!"#'/&6;)$#+-$&-+#,(-!#$#+(*@)"#>;/-":#-!"#&"+-#/'#-!"#'/&6;)$#(+#(*-"&3&"-"%#$+#-"2-0 C/& !" somethingChanged()#3&(4$-"#+)/-#&".$).;)$-"+#-!"#,!/)"#+3&"$%+!""-#('#K$;-/S&".$).;)$-"K#(+
"2$63)":#-!"#'/&6;)$ K#AOG[PZK#"4$);$-"+#-/#-!"#+-&(*@#KOG[PZK0 "*$=)"%0 <-#$)+/#"6(-+#-!" modified()#+(@*$)0
• <'#-!"#'/&6;)$#+-$&-+#,(-!#$*#">;$)+#+(@*#FA\AJ:#-!"#'/&6;)$#(+#(*-"&3&"-"%#$+#$*#$&(-!6"-(.
'/&6;)$0#C/&#"2$63)":#('#."))#?O#./*-$(*+#KOGK#$*%#."))#?G#./*-$(*+#KHK:#-!"#'/&6;)$#K\?O]?GK
"4$);$-"+#-/#O^0 Loading and Saving
!"#-$+5 /'#./*4"&-(*@#$#'/&6;)$#(*-/#$#4$);"#(+#3"&'/&6"%#=9#-!" Cell#.)$++0#C/&#-!"#6/6"*-:#-!" 1"#,())#*/,#(63)"6"*-#-!"#)/$%(*@#$*%#+$4(*@#/'#R3&"$%+!""-#'()"+#;+(*@#$#.;+-/6#=(*$&9#'/&6$-0
-!(*@#-/#="$&#(*#6(*%#(+#-!$-#-!"#-"2-#+!/,*#(*#-!"#."))#(+#-!"#&"+;)-#/'#"4$);$-(*@#-!"#'/&6;)$:#*/-#-!" 1"#,())#%/#-!(+#;+(*@ QFile#$*% QDataStream:#,!(.!#-/@"-!"&#3&/4(%"#3)$-'/&6S(*%"3"*%"*-#=(*$&9
'/&6;)$#(-+")'0 <WV0

1"#,())#+-$&-#,(-!#,&(-(*@#$#R3&"$%+!""-#'()"7
void Spreadsheet::setFormula(int row, int column,
const QString &formula)
{ bool Spreadsheet::writeFile(const QString &fileName)
Cell *c = cell(row, column); {
if (!c) { QFile file(fileName);
c = new Cell; if (!file.open(QIODevice::WriteOnly)) {
setItem(row, column, c); QMessageBox::warning(this, tr("Spreadsheet"),
} tr("Cannot write file %1:\n%2.")
c->setFormula(formula); .arg(file.fileName())
} .arg(file.errorString()));
return false;
}
!" setFormula()#3&(4$-"#';*.-(/*#+"-+#-!"#'/&6;)$#'/&#$#@(4"*#."))0#<'#-!"#."))#$)&"$%9#!$+#$ Cell QDataStream out(&file);
/=T".-:#,"#&";+"#(-0#V-!"&,(+":#,"#.&"$-"#$#*", Cell#/=T".-#$*%#.$)) QTableWidget::setItem()#-/ out.setVersion(QDataStream::Qt_4_1);
out << quint32(MagicNumber);
(*+"&-#(-#(*-/#-!"#-$=)"0#?-#-!"#"*%:#,"#.$))#-!"#."))A+#/,* setFormula()#';*.-(/*:#,!(.!#,())#.$;+"#-!"
QApplication::setOverrideCursor(Qt::WaitCursor);
."))#-/#=" &"3$(*-"%#('#(-A+#+!/,*#/*#+.&""*0#1"#%/*A-#*""%#-/#,/&&9#$=/;-#%")"-(*@#-!" Cell#/=T".- for (int row = 0; row < RowCount; ++row) {
)$-"&#/*B QTableWidget#-$5"+#/,*"&+!(3#/'#-!"#."))#$*%#,())#%")"-"#(-#$;-/6$-(.$))9#$-#-!"#&(@!-#-(6"0 for (int column = 0; column < ColumnCount; ++column) {
QString str = formula(row, column);
if (!str.isEmpty())
QString Spreadsheet::currentLocation() const out << quint16(row) << quint16(column) << str;
{ }
return QChar('A' + currentColumn()) }
+ QString::number(currentRow() + 1); QApplication::restoreOverrideCursor();
} return true;
}
!" writeFile()#';*.-(/*#(+#.$))"%#'&/6 MainWindow::saveFile()#-/#,&(-"#-!"#'()"#-/#%(+50#<-#&"-;&*+ bool Spreadsheet::readFile(const QString &fileName)
{
true#/*#+;.."++: false#/*#"&&/&0
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
1"#.&"$-"#$ QFile#/=T".-#,(-!#-!"#@(4"*#'()"#*$6"#$*%#.$)) open()#-/#/3"*#-!"#'()"#'/&#,&(-(*@0#1"#$)+/ QMessageBox::warning(this, tr("Spreadsheet"),
.&"$-"#$ QDataStream#/=T".-#-!$-#/3"&$-"+#/*#-!" QFile#$*%#;+"#(-#-/#,&(-"#/;-#-!"#%$-$0 tr("Cannot read file %1:\n%2.")
.arg(file.fileName())
_;+-#="'/&"#,"#,&(-"#-!"#%$-$:#,"#.!$*@"#-!"#$33)(.$-(/*A+#.;&+/&#-/#-!"#+-$*%$&%#,$(-#.;&+/& .arg(file.errorString()));
F;+;$))9#$*#!/;&@)$++J#$*%#&"+-/&"#-!"#*/&6$)#.;&+/&#/*."#$))#-!"#%$-$#(+#,&(--"*0#?-#-!"#"*%#/'#-!" return false;
}
';*.-(/*:#-!"#'()"#(+#$;-/6$-(.$))9#.)/+"%#=9 QFileA+#%"+-&;.-/&0
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_1);
QDataStream#+;33/&-+#=$+(.#Q]]#-93"+#$+#,"))#$+#6$*9#/'#U-A+#-93"+0# !"#+9*-$2#(+#6/%")"%#$'-"& quint32 magic;
-!"#R-$*%$&%#Q]] <iostream>#.)$++"+0#C/&#"2$63)": in >> magic;
if (magic != MagicNumber) {
QMessageBox::warning(this, tr("Spreadsheet"),
out << x << y << z; tr("The file is not a Spreadsheet file."));
return false;
}
clear();
,&(-"+#-!"#4$&($=)"+ x: y:#$*% z#-/#$#+-&"$6:#$*% quint16 row;
quint16 column;
QString str;
in >> x >> y >> z; QApplication::setOverrideCursor(Qt::WaitCursor);
while (!in.atEnd()) {
in >> row >> column >> str;
setFormula(row, column, str);
&"$%+#-!"6#'&/6#$#+-&"$60#L".$;+"#-!"#Q]]#=$+(.#-93"+ char: short: int: long:#$*% long long#6$9 }
!$4"#%(''"&"*-#+(D"+#/*#%(''"&"*-#3)$-'/&6+:#(-#(+#+$'"+-#-/#.$+-#-!"+"#4$);"+#-/#/*"#/' qint8: quint8: QApplication::restoreOverrideCursor();
qint16: quint16: qint32: quint32: qint64:#$*% quint64:#,!(.!#$&"#@;$&$*-""%#-/#="#/'#-!"#+(D"#-!"9 return true;
$%4"&-(+"#F(*#=(-+J0 }

!"#R3&"$%+!""-#$33)(.$-(/*A+#'()"#'/&6$-#(+#'$(&)9#+(63)"0#?#R3&"$%+!""-#'()"#+-$&-+#,(-!#$#[GS=(-
*;6="&#-!$-#(%"*-('("+#-!"#'()"#'/&6$-#FMagicNumber:#%"'(*"%#$+ 0x7F51C883#(* spreadsheet.h:#$* !" readFile()#';*.-(/*#(+#4"&9#+(6()$&#-/ writeFile()0#1"#;+" QFile#-/#&"$%#(*#-!"#'()":#=;-#-!(+#-(6"
$&=(-&$&9#&$*%/6#*;6="&0J# !"*#./6"+#$#+"&("+#/'#=)/.5+:#"$.!#/'#,!(.!#./*-$(*+#$#+(*@)"#."))A+#&/,: ;+(*@#-!" QIODevice::ReadOnly#')$@#&$-!"&#-!$* QIODevice:: WriteOnly0# !"*#,"#+"-#-!" QDataStream
./);6*:#$*%#'/&6;)$0# /#+$4"#+3$.":#,"#%/*A-#,&(-"#/;-#"63-9#."))+0 4"&+(/*#-/#a0# !"#'/&6$-#'/&#&"$%(*@#6;+-#$),$9+#="#-!"#+$6"#$+#'/&#,&(-(*@0

!"#$%&'(7( 89%&2:$%41+9%%/&;!<%&;-$64/ <'#-!"#'()"#!$+#-!"#./&&".-#6$@(.#*;6="&#$-#-!"#="@(**(*@:#,"#.$)) clear()#-/#=)$*5#/;-#$))#-!"#."))+#(*


-!"#+3&"$%+!""-:#$*%#,"#&"$%#(*#-!"#."))#%$-$0#R(*."#-!"#'()"#/*)9#./*-$(*+#-!"#%$-$#'/&#*/*S"63-9
."))+:#$*%#(-#(+#4"&9#;*)(5")9#-!$-#"4"&9#."))#(*#-!"#+3&"$%+!""-#,())#="#+"-:#,"#6;+-#"*+;&"#-!$-#$))
."))+#$&"#.)"$&"%#="'/&"#&"$%(*@0

Implementing the Edit Menu


!"#3&".(+"#=(*$&9#&"3&"+"*-$-(/*#/'#-!"#%$-$#-93"+#(+#%"-"&6(*"%#=9 QData-Stream0#C/&#"2$63)":#$
1"#$&"#*/,#&"$%9#-/#(63)"6"*-#-!"#+)/-+#-!$-#./&&"+3/*%#-/#-!"#$33)(.$-(/*A+#Y%(-#6"*;0
quint16#(+#+-/&"%#$+#-,/#=9-"+#(*#=(@S"*%($*#/&%"&:#$*%#$ QString#$+#-!"#+-&(*@A+#)"*@-!#'/))/,"%#=9
-!"#`*(./%"#.!$&$.-"&+0
void Spreadsheet::cut()
!"#=(*$&9#&"3&"+"*-$-(/*#/'#U-#-93"+#!$+#"4/)4"%#>;(-"#$#)/-#+(*."#U-#O0E0#<-#(+#)(5")9#-/#./*-(*;" {
"4/)4(*@#(*#';-;&"#U-#&")"$+"+#-/#5""3#3$."#,(-!#-!"#"4/);-(/*#/'#"2(+-(*@#-93"+#$*%#-/#$))/,#'/&#*", copy();
U-#-93"+0#L9#%"'$;)-: QDataStream#;+"+#-!"#6/+-#&"."*-#4"&+(/*#/'#-!"#=(*$&9#'/&6$-#F4"&+(/*#a#(*#U- del();
P0OJ:#=;-#(-#.$*#="#+"-#-/#&"$%#/)%"&#4"&+(/*+0# /#$4/(%#$*9#./63$-(=()(-9#3&/=)"6+#('#-!"#$33)(.$-(/* }
(+#&"./63()"%#)$-"&#;+(*@#$#*","&#U-#&")"$+":#,"#"23)(.(-)9#-")) QDataStream#-/#;+"#4"&+(/*#a
(&&"+3".-(4"#/'#-!"#4"&+(/*#/'#U-#,"#$&"#./63()(*@#$@$(*+-0#F QDataStream::Qt_4_1#(+#$#./*4"*("*."
./*+-$*-#-!$-#">;$)+#a0J !" cut()#+)/-#./&&"+3/*%+#-/#Y%(-bQ;-0# !"#(63)"6"*-$-(/*#(+#+(63)"#+(*."#Q;-#(+#-!"#+$6"#$+#Q/39
'/))/,"%#=9#c")"-"0
QDataStream#(+#4"&9#4"&+$-()"0#<-#.$*#="#;+"%#/*#$ QFile:#$*%#$)+/#/*#$ QBuffer:#$ QProcess:#$
QTcpSocket:#/&#$ QUdpSocket0#U-#$)+/#/''"&+#$ QTextStream#.)$++#-!$-#.$*#="#;+"%#(*+-"$%#/' !"#$%&'('(&89%&2:$%41+9%%/&4::<!,4/!-.*+&=1!/&6%.#
QDataStream#'/&#&"$%(*@#$*%#,&(-(*@#-"2-#'()"+0 Q!$3-"&#OG#"23)$(*+#-!"+"#.)$++"+#(*#%"3-!:#$*%#$)+/
%"+.&(="+#4$&(/;+#$33&/$.!"+#-/#!$*%)(*@#%(''"&"*- QDataStream#4"&+(/*+0
QTableWidgetSelectionRange Spreadsheet::selectedRange() const
{
QList<QTableWidgetSelectionRange> ranges = selectedRanges();
if (ranges.isEmpty())
return QTableWidgetSelectionRange();
return ranges.first();
}

<'#-!"&"#(+#$#+")".-(/*#$-#$)):#,"#+(63)9#&"-;&*#-!"#'(&+-#F$*%#/*)9J#/*"0# !"#.$+"#,!"&"#-!"&"#(+#*/
+")".-(/*#+!/;)%#*"4"&#!$33"*#+(*."#-!" ContiguousSelection#6/%"#-&"$-+#-!"#.;&&"*-#."))#$+#="(*@
+")".-"%0#L;-#-/#3&/-".-#$@$(*+-#-!"#3/++(=()(-9#/'#$#=;@#(*#/;&#3&/@&$6#-!$-#6$5"+#*/#."))#.;&&"*-:
,"#!$*%)"#-!(+#.$+"0

void Spreadsheet::paste()
void Spreadsheet::copy()
{
{
QTableWidgetSelectionRange range = selectedRange();
QTableWidgetSelectionRange range = selectedRange();
QString str = QApplication::clipboard()->text();
QString str;
QStringList rows = str.split('\n');
for (int i = 0; i < range.rowCount(); ++i) {
int numRows = rows.count();
if (i > 0)
int numColumns = rows.first().count('\t') + 1;
str += "\n";
if (range.rowCount() * range.columnCount() != 1
for (int j = 0; j < range.columnCount(); ++j) {
&& (range.rowCount() != numRows
if (j > 0)
|| range.columnCount() != numColumns)) {
str += "\t";
QMessageBox::information(this, tr("Spreadsheet"),
str += formula(range.topRow() + i, range.leftColumn() + j);
tr("The information cannot be pasted because the copy "
}
"and paste areas aren't the same size."));
}
return;
QApplication::clipboard()->setText(str);
}
}
for (int i = 0; i < numRows; ++i) {
QStringList columns = rows[i].split('\t');
for (int j = 0; j < numColumns; ++j) {
!" copy()#+)/-#./&&"+3/*%+#-/#Y%(-bQ/390#<-#(-"&$-"+#/4"&#-!"#.;&&"*-#+")".-(/*#F,!(.!#(+#+(63)9#-!" int row = range.topRow() + i;
.;&&"*-#."))#('#-!"&"#(+#*/#"23)(.(-#+")".-(/*J0#Y$.!#+")".-"%#."))A+#'/&6;)$#(+#$%%"%#-/#$ QString:#,(-! int column = range.leftColumn() + j;
&/,+#+"3$&$-"%#=9#*",)(*"#.!$&$.-"&+#$*%#./);6*+#+"3$&$-"%#=9#-$=#.!$&$.-"&+0 if (row < RowCount && column < ColumnCount)
setFormula(row, column, columns[j]);
}
!"#+9+-"6#.)(3=/$&%#(+#$4$()$=)"#(*#U-#-!&/;@!#-!" QApplication::clipboard()#+-$-(.#';*.-(/*0#L9 }
.$))(*@ QClipboard::setText():#,"#6$5"#-!"#-"2-#$4$()$=)"#/*#-!"#.)(3=/$&%:#=/-!#-/#-!(+#$33)(.$-(/* somethingChanged();
$*%#-/#/-!"&#$33)(.$-(/*+#-!$-#+;33/&-#3)$(*#-"2-0#V;&#'/&6$-#,(-!#-$=#$*%#*",)(*"#.!$&$.-"&+#$+ }
+"3$&$-/&+#(+#;*%"&+-//%#=9#$#4$&("-9#/'#$33)(.$-(/*+:#(*.);%(*@#d(.&/+/'-#Y2.")0

!"#$%&'(>(&?-:@!."&4&+%<%,/!-.&-./-&/9%&,<!:A-4$1 !" paste()#+)/-#./&&"+3/*%+#-/#Y%(-be$+-"0#1"#'"-.!#-!"#-"2-#/*#-!"#.)(3=/$&%#$*%#.$))#-!"#+-$-(.


';*.-(/* QString::split()#-/#=&"$5#-!"#+-&(*@#(*-/#$ QStringList0#Y$.!#&/,#="./6"+#/*"#+-&(*@#(*
-!"#)(+-0

8"2-:#,"#%"-"&6(*"#-!"#%(6"*+(/*#/'#-!"#./39#$&"$0# !"#*;6="&#/'#&/,+#(+#-!"#*;6="&#/'#+-&(*@+#(*
-!" QStringListB#-!"#*;6="&#/'#./);6*+#(+#-!"#*;6="&#/'#-$=#.!$&$.-"&+#(*#-!"#'(&+-#&/,:#3);+#O0#<'
/*)9#/*"#."))#(+#+")".-"%:#,"#;+"#-!$-#."))#$+#-!"#-/3S)"'-#./&*"&#/'#-!"#3$+-"#$&"$B#/-!"&,(+":#,"#;+"
-!"#.;&&"*-#+")".-(/*#$+#-!"#3$+-"#$&"$0

/#3"&'/&6#-!"#3$+-":#,"#(-"&$-"#/4"&#-!"#&/,+#$*%#+3)(-#"$.!#/'#-!"6#(*-/#."))+#=9#;+(*@
QString::split()#$@$(*:#=;-#-!(+#-(6"#;+(*@#-$=#$+#-!"#+"3$&$-/&0 C(@;&"#P0H#());+-&$-"+#-!"#+-"3+0

!"#$%&'(B(&C4+/!."&,<!:A-4$1&/%D/&!./-&/9%&+:$%41+9%%/
!" QTableWidget::selectedRanges()#';*.-(/*#&"-;&*+#$#)(+-#/'#+")".-(/*#&$*@"+0#1"#5*/,#-!"&"
.$**/-#="#6/&"#-!$*#/*"#=".$;+"#,"#+"-#-!"#+")".-(/*#6/%"#-/
QAbstractItemView::ContiguousSelection#(*#-!"#./*+-&;.-/&0#C/&#/;&#./*4"*("*.":#,"#%"'(*"#$
selectedRange()#';*.-(/*#-!$-#&"-;&*+#-!"#+")".-(/*#&$*@"7
}
QApplication::beep();
}

!" findNext()#+)/-#(-"&$-"+#-!&/;@!#-!"#."))+#+-$&-(*@#'&/6#-!"#."))#-/#-!"#&(@!-#/'#-!"#.;&+/&#$*%
6/4(*@#&(@!-#;*-()#-!"#)$+-#./);6*#(+#&"$.!"%:#-!"*#./*-(*;"+#'&/6#-!"#'(&+-#./);6*#(*#-!"#&/,#=")/,:
$*%#+/#/*#;*-()#-!"#-"2-#(+#'/;*%#/&#;*-()#-!"#4"&9 )$+-#."))#(+#&"$.!"%0#C/&#"2$63)":#('#-!"#.;&&"*-#."))
(+#."))#QGP:#,"#+"$&.!#cGP:#YGP:#M:#NGP:#-!"*#?GZ:#LGZ:#QGZ:#M:#NGZ:#$*%#+/#/*#;*-()#NIII0#<'#,"
'(*%#$#6$-.!:#,"#.)"$&#-!"#.;&&"*-#+")".-(/*:#6/4"#-!"#."))#.;&+/&#-/#-!"#."))#-!$-#6$-.!"%:#$*%#6$5"
-!"#,(*%/,#-!$-#./*-$(*+#-!" Spreadsheet#$.-(4"0#<'#*/#6$-.!#(+#'/;*%:#,"#6$5"#-!"#$33)(.$-(/*#=""3
-/#(*%(.$-"#-!$-#-!"#+"$&.!#'(*(+!"%#;*+;.."++';))90

void Spreadsheet::findPrevious(const QString &str,


Qt::CaseSensitivity cs)
{
int row = currentRow();
void Spreadsheet::del() int column = currentColumn() - 1;
{ while (row >= 0) {
foreach (QTableWidgetItem *item, selectedItems()) while (column >= 0) {
delete item; if (text(row, column).contains(str, cs)) {
} clearSelection();
setCurrentCell(row, column);
activateWindow();
!" del()#+)/-#./&&"+3/*%+#-/#Y%(-bc")"-"0#<-#(+#+;''(.("*-#-/#;+" delete#/*#"$.!#/'#-!" Cell#/=T".-+#(* return;
-!"#+")".-(/*#-/#.)"$&#-!"#."))+0# !" QTableWidget#*/-(."+#,!"*#(-+ QTableWidgetItem+#$&"#%")"-"%#$*% }
--column;
$;-/6$-(.$))9#&"3$(*-+#(-+")'#('#$*9#/'#-!"#(-"6+#,"&"#4(+(=)"0#<'#,"#.$)) cell()#,(-!#-!"#)/.$-(/*#/'#$ }
%")"-"%#.")):#(-#,())#&"-;&*#$#*;))#3/(*-"&0 column = ColumnCount - 1;
--row;
}
void Spreadsheet::selectCurrentRow() QApplication::beep();
{ }
selectRow(currentRow());
}
void Spreadsheet::selectCurrentColumn()
{ !" findPrevious()#+)/-#(+#+(6()$&#-/ findNext():#"2."3-#-!$-#(-#(-"&$-"+#=$.5,$&%#$*%#+-/3+#$-#."))
selectColumn(currentColumn()); ?O0
}

!" selectCurrentRow()#$*% selectCurrentColumn()#';*.-(/*+#./&&"+3/*%#-/#-!"#Y%(-bR")".-bf/,#$*%


Implementing the Other Menus
Y%(-bR")".-bQ/);6*#6"*;#/3-(/*+0# !"#(63)"6"*-$-(/*+#&")9#/* QTableWidgetA+ selectRow()#$*%
selectColumn()#';*.-(/*+0#1"#%/#*/-#*""%#-/#(63)"6"*-#-!"#';*.-(/*$)(-9#="!(*%#Y%(-bR")".-b?)):
1"#,())#*/,#(63)"6"*-#-!"#+)/-+#'/&#-!"# //)+#$*%#V3-(/*+#6"*;+0
+(*."#-!$-#(+#3&/4(%"%#=9 QTableWidgetA+#(*!"&(-"%#';*.-(/* QAbstractItemView::selectAll()0
!"#$%&'(E(&89%&2:$%41+9%%/&4::<!,4/!-.*+&8--<+&4.1&F:/!-.+&6%.#+

void Spreadsheet::findNext(const QString &str, Qt::CaseSensitivity cs)


{
int row = currentRow();
int column = currentColumn() + 1;
while (row < RowCount) {
while (column < ColumnCount) {
if (text(row, column).contains(str, cs)) {
clearSelection();
setCurrentCell(row, column); void Spreadsheet::recalculate()
activateWindow(); {
return; for (int row = 0; row < RowCount; ++row) {
} for (int column = 0; column < ColumnCount; ++column) {
++column; if (cell(row, column))
} cell(row, column)->setDirty();
column = 0; }
++row; }
viewport()->update(); &$-!"&#-!$*#=9#4$);"0#U-A+#+-$*%$&%#$)@/&(-!6+#$*%#%$-$#+-&;.-;&"+#$&"#./4"&"%#(* Q!$3-"&#OO
} FQ/*-$(*"&#Q)$++"+J0

!"#$%&'(G(&2/-$!."&/9%&+%<%,/!-.&4+&4&<!+/&-;&$-0+
!" recalculate()#+)/-#./&&"+3/*%+#-/# //)+bf".$).;)$-"0#<-#(+#$)+/#.$))"%#$;-/6$-(.$))9#=9
Spreadsheet#,!"*#*"."++$&90 [View full size image]

1"#(-"&$-"#/4"&#$))#-!"#."))+#$*%#.$)) setDirty()#/*#"4"&9#."))#-/#6$&5#"$.!#/*"#$+#&">;(&(*@
&".$).;)$-(/*0# !"#*"2-#-(6" QTableWidget#.$))+ text()#/*#$ Cell#-/#/=-$(*#-!"#4$);"#-/#+!/,#(*#-!"
+3&"$%+!""-:#-!"#4$);"#,())#="#&".$).;)$-"%0

!"*#,"#.$)) update()#/*#-!"#4(",3/&-#-/#&"3$(*-#-!"#,!/)"#+3&"$%+!""-0# !"#&"3$(*-#./%"#(*


QTableWidget#-!"*#.$))+ text()#/*#"$.!#4(+(=)"#."))#-/#/=-$(*#-!"#4$);"#-/#%(+3)$90#L".$;+"#,"#.$))"%
setDirty()#/*#"4"&9#.")):#-!"#.$))+#-/ text()#,())#;+"#$#'&"+!)9#.$).;)$-"% 4$);"0# !"#.$).;)$-(/*#6$9
&">;(&"#*/*S4(+(=)"#."))+#-/#="#&".$).;)$-"%:#.$+.$%(*@#-!"#.$).;)$-(/*#;*-()#"4"&9#."))#-!$-#*""%+#-/#=" !" qStableSort()#';*.-(/*#$.."3-+#$#="@(*#(-"&$-/&:#$*#"*%#(-"&$-/&:#$*%#$#./63$&(+/*#';*.-(/*0# !"
&".$).;)$-"%#-/#%(+3)$9#-!"#./&&".-#-"2-#(*#-!"#4(",3/&-#!$+#=""*#'&"+!)9#.$).;)$-"%0# !"#.$).;)$-(/*#(+ ./63$&(+/*#';*.-(/*#(+#$#';*.-(/*#-!$-#-$5"+#-,/#$&@;6"*-+#F-,/ QStringList+J#$*%#-!$-#&"-;&*+ true
3"&'/&6"%#=9#-!" Cell#.)$++0 ('#-!"#'(&+-#$&@;6"*-#(+#K)"++#-!$*K#-!"#+"./*%#$&@;6"*-: false#/-!"&,(+"0# !" compare#/=T".-#,"
3$++#$+#-!"#./63$&(+/*#';*.-(/*#(+*A-#&"$))9#$#';*.-(/*:#=;-#(-#.$*#="#;+"%#$+#/*":#$+#,"#,())#+""
+!/&-)90
void Spreadsheet::setAutoRecalculate(bool recalc)
{
autoRecalc = recalc;
!"#$%&'(H(&C#//!."&/9%&14/4&A4,I&!./-&/9%&/4A<%&4;/%$&+-$/!."
if (autoRecalc) [View full size image]
recalculate();
}

!" setAutoRecalculate()#+)/-#./&&"+3/*%+#-/#V3-(/*+b?;-/Sf".$).;)$-"0#<'#-!"#'"$-;&"#(+#="(*@
-;&*"%#/*:#,"#&".$).;)$-" -!"#,!/)"#+3&"$%+!""-#(66"%($-")9#-/#6$5"#+;&"#-!$-#(-A+#;3#-/#%$-"B
$'-"&,$&%: recalculate()#(+#.$))"%#$;-/6$-(.$))9#'&/6 somethingChanged()0

1"#%/*A-#*""%#-/#(63)"6"*-#$*9-!(*@#'/&#V3-(/*+bR!/,#g&(%#=".$;+" QTableWidget#$)&"$%9#!$+#$
?'-"&#3"&'/&6(*@#-!" qStableSort():#,"#6/4"#-!"#%$-$#=$.5#(*-/#-!"#-$=)":#.)"$&#-!"#+")".-(/*:#$*%
setShowGrid()#+)/-: ,!(.!#(-#(*!"&(-+#'&/6#(-+#=$+"#.)$++ QTable-View0#?))#-!$-#&"6$(*+#(+
.$)) somethingChanged()0
Spreadsheet::sort():#,!(.!#(+#.$))"%#'&/6 MainWindow::sort()7

<* spreadsheet.h:#-!" SpreadsheetCompare#.)$++#,$+#%"'(*"%#)(5"#-!(+7


void Spreadsheet::sort(const SpreadsheetCompare &compare)
{
QList<QStringList> rows; class SpreadsheetCompare
QTableWidgetSelectionRange range = selectedRange(); {
int i; public:
for (i = 0; i < range.rowCount(); ++i) { bool operator()(const QStringList &row1,
QStringList row; const QStringList &row2) const;
for (int j = 0; j < range.columnCount(); ++j) enum { KeyCount = 3 };
row.append(formula(range.topRow() + i, int keys[KeyCount];
range.leftColumn() + j)); bool ascending[KeyCount];
rows.append(row); };
}
qStableSort(rows.begin(), rows.end(), compare);
for (i = 0; i < range.rowCount(); ++i) {
!" SpreadsheetCompare#.)$++#(+#+3".($)#=".$;+"#(-#(63)"6"*-+#$ ()#/3"&$-/&0# !(+#$))/,+#;+#-/#;+"
for (int j = 0; j < range.columnCount(); ++j)
setFormula(range.topRow() + i, range.leftColumn() + j, -!"#.)$++#$+#('#(-#,"&"#$#';*.-(/*0#R;.!#.)$++"+#$&"#.$))"%#';*.-(/*#/=T".-+:#/&#';*.-/&+0# /#;*%"&+-$*%
rows[i][j]); !/,#';*.-/&+#,/&5:#,"#,())#+-$&- ,(-!#$#+(63)"#"2$63)"7
}
clearSelection();
somethingChanged(); class Square
} {
public:
int operator()(int x) const { return x * x; }
}
R/&-(*@#/3"&$-"+#/*#-!"#.;&&"*-#+")".-(/*#$*%#&"/&%"&+#-!"#&/,+#$../&%(*@#-/#-!"#+/&-#5"9+#$*%#+/&-
/&%"&+#+-/&"%#(*#-!" compare#/=T".-0#1"#&"3&"+"*-#"$.!#&/, /'#%$-$#,(-!#$ QStringList#$*%#+-/&"#-!"
+")".-(/*#$+#$#)(+-#/'#&/,+0#1"#;+"#U-A+ qStableSort()#$)@/&(-!6:#$*%#'/&#+(63)(.(-9#+/&-#=9#'/&6;)$
+-())#3&"."%" row2#(*#-!"#&"+;)-0# !(+#(+#,!$-#%(+-(*@;(+!"+ qStableSort()#'&/6#(-+#;*+-$=)"#./;+(*
!" Square#.)$++#3&/4(%"+#/*"#';*.-(/*: operator()(int):#-!$-#&"-;&*+#-!"#+>;$&"#/'#(-+#3$&$6"-"&0 qSort()0
L9#*$6(*@#-!"#';*.-(/* operator()(int)#&$-!"&#-!$*:#+$9: compute(int):#,"#@$(*#-!"#.$3$=()(-9#/'
;+(*@#$*#/=T".-#/'#-93" Square#$+#('#(-#,"&"#$#';*.-(/*7 1"#!$4"#*/,#./63)"-"%#-!" Spreadsheet#.)$++0#<*#-!"#*"2-#+".-(/*:#,"#,())#&"4(",#-!" Cell#.)$++0
!(+#.)$++#(+#;+"%#-/#!/)%#."))#'/&6;)$+#$*%#3&/4(%"+#$#&"(63)"6"*-$-(/*#/'#-!"
QTableWidgetItem::data()#';*.-(/*#-!$- Spreadsheet#.$))+#(*%(&".-)9:#-!&/;@!#-!"
Square square; QTableWidgetItem::text()#';*.-(/*:#-/#%(+3)$9#-!"#&"+;)-#/'#.$).;)$-(*@#$#."))A+#'/&6;)$0
int y = square(5);

8/,#)"-A+#+""#$*#"2$63)"#(*4/)4(*@ SpreadsheetCompare7

Subclassing QTableWidgetItem
QStringList row1, row2;
QSpreadsheetCompare compare; !" Cell#.)$++#(*!"&(-+#'&/6 QTableWidgetItem0# !"#.)$++#(+#%"+(@*"%#-/#,/&5#,"))#,(-! Spreadsheet:
...
=;-#(-#!$+#*/#+3".('(.#%"3"*%"*.("+#/*#-!$-#.)$++#$*%#./;)%#(*#-!"/&9#="#;+"%#(*#$*9 QTableWidget0
if (compare(row1, row2)) {
// row1 is less than row2 X"&"A+#-!"#!"$%"&#'()"7
}

#ifndef CELL_H
#define CELL_H
!" compare#/=T".-#.$*#="#;+"%#T;+-#$+#('#(-#!$%#=""*#$#3)$(* compare()#';*.-(/*0#?%%(-(/*$))9:#(-+ #include <QTableWidgetItem>
(63)"6"*-$-(/*#.$*#$.."++#$))#-!"#+/&-#5"9+#$*%#+/&-#/&%"&+:#,!(.!#$&"#+-/&"%#$+#6"6="&#4$&($=)"+0 class Cell : public QTableWidgetItem
{
?*#$)-"&*$-(4"#-/#-!(+#+.!"6"#,/;)%#!$4"#=""*#-/#+-/&"#-!"#+/&-#5"9+#$*%#+/&-#/&%"&+#(*#@)/=$) public:
4$&($=)"+#$*%#;+"#$#3)$(* compare()#';*.-(/*0#X/,"4"&:#./66;*(.$-(*@#-!&/;@!#@)/=$)#4$&($=)"+#(+ Cell();
(*")"@$*-#$*%#.$*#)"$%#-/#+;=-)"#=;@+0#C;*.-/&+#$&"#$#6/&"#3/,"&';)#(%(/6#'/&#(*-"&'$.(*@#,(-! QTableWidgetItem *clone() const;
void setData(int role, const QVariant &value);
-"63)$-"#';*.-(/*+#+;.!#$+ qStableSort()0
QVariant data(int role) const;
void setFormula(const QString &formula);
X"&"#(+#-!"#(63)"6"*-$-(/*#/'#-!"#';*.-(/*#-!$-#(+#;+"%#-/#./63$&"#-,/#+3&"$%+!""-#&/,+7 QString formula() const;
void setDirty();
private:
bool SpreadsheetCompare::operator()(const QStringList &row1, QVariant value() const;
const QStringList &row2) const QVariant evalExpression(const QString &str, int &pos) const;
{ QVariant evalTerm(const QString &str, int &pos) const;
for (int i = 0; i < KeyCount; ++i) { QVariant evalFactor(const QString &str, int &pos) const;
int column = keys[i]; mutable QVariant cachedValue;
if (column != -1) { mutable bool cacheIsDirty;
if (row1[column] != row2[column]) { };
if (ascending[i]) { #endif
return row1[column] < row2[column];
} else {
return row1[column] > row2[column];
} !" Cell#.)$++#"2-"*%+ QTableWidgetItem#=9#$%%(*@#-,/#3&(4$-"#4$&($=)"+7
}
} • cachedValue#.$.!"+#-!"#."))A+#4$);"#$+#$ QVariant0
} • cacheIsDirty#(+ true#('#-!"#.$.!"%#4$);"#(+*A-#;3#-/#%$-"0
return false;
} 1"#;+" QVariant#=".$;+"#+/6"#."))+#!$4"#$ double#4$);":#,!()"#/-!"&+#!$4"#$ QString#4$);"0

!" cachedValue#$*% cacheIsDirty#4$&($=)"+#$&"#%".)$&"%#,(-!#-!"#Q]] mutable#5"9,/&%0# !(+#$))/,+


!"#/3"&$-/&#&"-;&*+ TRue#('#-!"#'(&+-#&/,#(+#)"++#-!$*#-!"#+"./*%#&/,B#/-!"&,(+":#(-#&"-;&*+ false0 ;+#-/#6/%('9#-!"+"#4$&($=)"+#(*#./*+-#';*.-(/*+0#?)-"&*$-(4")9:#,"#./;)%#&".$).;)$-"#-!"#4$);"#"$.!
!" qStableSort()#';*.-(/*#;+"+#-!"#&"+;)-#/'#-!(+#';*.-(/*#-/#3"&'/&6#-!"#+/&-0 -(6" text()#(+#.$))"%:#=;-#-!$-#,/;)%#="#*""%)"++)9#(*"''(.("*-0

!" SpreadsheetCompare#/=T".-A+ keys#$*% ascending#$&&$9+#$&"#3/3;)$-"%#(*#-!" MainWindow::sort() 8/-(."#-!$-#-!"&"#(+#*/ Q_OBJECT 6$.&/#(*#-!"#.)$++#%"'(*(-(/*0 Cell#(+#$#3)$(*#Q]]#.)$++:#,(-!#*/


';*.-(/*#F+!/,*#(* Q!$3-"&#GJ0#Y$.!#5"9#!/)%+#$#./);6*#(*%"2:#/& SO#FK8/*"KJ0 +(@*$)+#/&#+)/-+0#<*#'$.-:#=".$;+" QTableWidgetItem#%/"+*A-#(*!"&(-#'&/6 QObject:#,"#.$**/-#!$4"
+(@*$)+#$*%#+)/-+#(* Cell#$+#(-#+-$*%+0#U-A+#(-"6#.)$++"+#%/*A-#(*!"&(-#'&/6 QObject#-/#5""3 -!"(&
1"#./63$&"#-!"#./&&"+3/*%(*@#."))#"*-&("+#(*#-!"#-,/#&/,+#'/&#"$.!#5"9#(*#/&%"&0#?+#+//*#$+#,"#'(*% /4"&!"$%#-/#-!"#=$&"+-#6(*(6;60#<'#+(@*$)+#$*%#+)/-+#$&"#*""%"%:#-!"9#.$*#="#(63)"6"*-"%#(*#-!"
$#%(''"&"*.":#,"#&"-;&*#$*#$33&/3&($-" true#/& false#4$);"0#<'#$))#-!"#./63$&(+/*+#-;&*#/;-#-/#=" ,(%@"-#-!$-#./*-$(*+#-!"#(-"6+#/&:#"2."3-(/*$))9:#;+(*@#6;)-(3)"#(*!"&(-$*."#,(-! QObject0
">;$):#,"#&"-;&* false0# !" qStableSort()#';*.-(/*#;+"+#-!"#/&%"&#="'/&"#-!"#+/&-#-/#&"+/)4"#-("
+(-;$-(/*+B#(' row1#3&"."%"% row2#/&(@(*$))9#$*%#*"(-!"&#./63$&"+#$+#K)"++#-!$*K#-!"#/-!"&: row1#,())
X"&"A+#-!"#+-$&-#/' cell.cpp7

<'#,"#!$4"#$#*",#'/&6;)$:#,"#+"- cacheIsDirty#-/ true#-/#"*+;&"#-!$-#-!"#."))#(+#&".$).;)$-"%#-!"


#include <QtGui> *"2-#-(6" text()#(+#.$))"%0
#include "cell.h"
Cell::Cell()
{ !"&"#(+#*/ text()#';*.-(/*#%"'(*"%#(* Cell:#$)-!/;@!#,"#.$)) text()#/* Cell#(*+-$*."+#(*
setDirty(); Spreadsheet::text()0# !" text()#';*.-(/*#(+#$#./*4"*("*."#';*.-(/*#3&/4(%"%#=9 QTableWidgetItemB#(-
} (+#-!"#">;(4$)"*-#/'#.$))(*@ data(Qt::Display-Role).toString()0

<*#-!"#./*+-&;.-/&:#,"#/*)9#*""%#-/#+"-#-!"#.$.!"#$+#%(&-90# !"&"#(+#*/#*""%#-/#3$++#$#3$&"*-B#,!"* void Cell::setDirty()


{
-!"#."))#(+#(*+"&-"%#(*-/#$ QTableWidget#,(-! setItem():#-!" QTableWidget#,())#$;-/6$-(.$))9#-$5"
cacheIsDirty = true;
/,*"&+!(3#/'#(-0 }

Y4"&9 QTableWidgetItem#.$*#!/)%#+/6"#%$-$:#;3#-/#/*" QVariant#'/&#"$.!#%$-$#K&/)"K0# !"#6/+-


./66/*)9#;+"%#&/)"+#$&" Qt::EditRole#$*% Qt::DisplayRole0# !"#"%(-#&/)"#(+#;+"%#'/&#%$-$#-!$-#(+#-/
!" setDirty()#';*.-(/*#(+#.$))"%#-/#'/&."#$#&".$).;)$-(/*#/'#-!"#."))A+#4$);"0#<-#+(63)9#+"-+
="#"%(-"%:#$*%#-!"#%(+3)$9#&/)"#(+#'/&#%$-$#-!$-#(+#-/#="#%(+3)$9"%0#V'-"*#-!"#%$-$#'/&#=/-!#(+#-!"
cacheIsDirty#-/ true:#6"$*(*@#-!$- cachedValue#(+#*/#)/*@"&#;3#-/#%$-"0# !"#&".$).;)$-(/*#(+*A-
+$6":#=;-#(* Cell#-!"#"%(-#&/)"#./&&"+3/*%+#-/#-!"#."))A+#'/&6;)$#$*%#-!"#%(+3)$9#&/)"#./&&"+3/*%+#-/
3"&'/&6"%#;*-()#(-#(+#*"."++$&90
-!"#."))A+#4$);"#F-!"#&"+;)-#/'#"4$);$-(*@#-!"#'/&6;)$J0

QVariant Cell::data(int role) const


QTableWidgetItem *Cell::clone() const
{
{
if (role == Qt::DisplayRole) {
return new Cell(*this);
if (value().isValid()) {
}
return value().toString();
} else {
return "####";
!" clone()#';*.-(/*#(+#.$))"%#=9 QTableWidget#,!"*#(-#*""%+#-/#.&"$-"#$#*",#."))'/&#"2$63)":#,!"* }
-!"#;+"&#+-$&-+#-93(*@#(*-/#$*#"63-9#."))#-!$-#!$+#*/-#=""*#;+"%#="'/&"0# !"#(*+-$*."#3$++"%#-/ } else if (role == Qt::TextAlignmentRole) {
QTableWidget::setItemPrototype()#(+#-!"#(-"6#-!$-#(+ .)/*"%0#R(*."#6"6="&S,(+"#./39(*@#(+#+;''(.("*- if (value().type() == QVariant::String) {
'/& Cell:#,"#$&"#&")9(*@#/*#-!"#%"'$;)-#./39#./*+-&;.-/&#$;-/6$-(.$))9#.&"$-"%#=9#Q]]#-/#.&"$-"#*", return int(Qt::AlignLeft | Qt::AlignVCenter);
} else {
Cell#(*+-$*."+#(*#-!" clone()#';*.-(/*0
return int(Qt::AlignRight | Qt::AlignVCenter);
}
} else {
void Cell::setFormula(const QString &formula) return QTableWidgetItem::data(role);
{ }
setData(Qt::EditRole, formula); }
}

!" data()#';*.-(/*#(+#&"(63)"6"*-"%#'&/6 QTableWidgetItem0#<-#&"-;&*+#-!"#-"2-#-!$-#+!/;)%#="


!" setFormula()#';*.-(/*#+"-+#-!"#."))A+#'/&6;)$0#<-#(+#+(63)9#$#./*4"*("*."#';*.-(/*#'/&#.$))(*@ +!/,*#(*#-!"#+3&"$%+!""-#('#.$))"%#,(-! Qt::DisplayRole:#$*%#-!"#'/&6;)$#('#.$))"%#,(-! Qt::EditRole0
setData()#,(-!#-!"#"%(-#&/)"0#<-#(+#.$))"%#'&/6 Spreadsheet::setFormula()0 <-#&"-;&*+#$#+;(-$=)"#$)(@*6"*-#('#.$))"%#,(-! Qt::TextAlignmentRole0#<*#-!" DisplayRole#.$+":#(-#&")("+
/* value()#-/#./63;-"#-!"#."))A+#4$);"0#<'#-!"#4$);"#(+#(*4$)(%#F=".$;+"#-!"#'/&6;)$#(+#,&/*@J:#,"
&"-;&*#KiiiiK0
QString Cell::formula() const
{
return data(Qt::EditRole).toString(); !" Cell::value()#';*.-(/*#;+"%#(* data()#&"-;&*+#$ QVariant0#? QVariant#.$*#+-/&"#4$);"+#/'
} %(''"&"*-#-93"+:#+;.!#$+ double#$*% QString:#$*%#3&/4(%"+#';*.-(/*+#-/#./*4"&-#-!"#4$&($*-#-/#/-!"&
-93"+0#C/&#"2$63)":#.$))(*@ toString()#/*#$#4$&($*-#-!$-#!/)%+#$ double#4$);"#3&/%;."+#$#+-&(*@
&"3&"+"*-$-(/*#/'#-!" double0#? QVariant#./*+-&;.-"%#;+(*@#-!"#%"'$;)-#./*+-&;.-/&#(+#$*#K(*4$)(%K
!" formula()#';*.-(/*#(+#.$))"%#'&/6 Spreadsheet::formula()0#h(5" setFormula()#(-#(+#$#./*4"*("*." 4$&($*-0
';*.-(/*:#-!(+#-(6"#&"-&("4(*@#-!"#(-"6A+ EditRole#%$-$0
const QVariant Invalid;
QVariant Cell::value() const
void Cell::setData(int role, const QVariant &value) {
{ if (cacheIsDirty) {
QTableWidgetItem::setData(role, value); cacheIsDirty = false;
if (role == Qt::EditRole) QString formulaStr = formula();
setDirty(); if (formulaStr.startsWith('\'')) {
} cachedValue = formulaStr.mid(1);
} else if (formulaStr.startsWith('=')) { $+#/*"#/&#6/&"#'$.-/&+#+"3$&$-"%#=9#AjA#/&#AWA#/3"&$-/&+0#L9#=&"$5(*@#%/,*#"23&"++(/*+#(*-/#-"&6+
cachedValue = Invalid; $*%#-"&6+#(*-/#'$.-/&+:#,"#"*+;&"#-!$-#-!"#/3"&$-/&+#$&"#$33)("%#,(-!#-!"#./&&".-#3&"."%"*."0
QString expr = formulaStr.mid(1);
expr.replace(" ", "");
C/&#"2$63)":#KGjQZ]cHK#(+#$*#"23&"++(/*#,(-!#KGjQZK#$+#(-+#'(&+-#-"&6#$*%#KcHK#$+#(-+#+"./*%#-"&60
expr.append(QChar::Null);
int pos = 0; !"#-"&6#KGjQZK#!$+#KGK#$+#(-+#'(&+-#'$.-/&#$*%#KQZK#$+#(-+#+"./*%#'$.-/&:#$*%#-!"#-"&6#KcHK#./*+(+-+
cachedValue = evalExpression(expr, pos); /'#-!"#+(*@)"#'$.-/&#KcHK0#?#'$.-/&#.$*#="#$#*;6="&#FKGKJ:#$#."))#)/.$-(/*#FKQZKJ:#/&#$*#"23&"++(/*#(*
if (expr[pos] != QChar::Null) 3$&"*-!"+"+:#/3-(/*$))9#3&"."%"%#=9#$#;*$&9#6(*;+0
cachedValue = Invalid;
} else { !"#+9*-$2#/'#+3&"$%+!""-#"23&"++(/*+#(+#%"'(*"%#(* C(@;&"#P0OE0#C/&#"$.!#+96=/)#(*#-!"#@&$66$&
bool ok; F()$&"**!%+,-."&/:#$*% 012'%&J:#-!"&"#(+#$#./&&"+3/*%(*@#6"6="&#';*.-(/*#-!$-#3$&+"+#(-#$*%
double d = formulaStr.toDouble(&ok); ,!/+"#+-&;.-;&"#.)/+")9#'/))/,+#-!"#@&$66$&0#e$&+"&+#,&(--"*#-!(+#,$9#$&"#.$))"%#&".;&+(4"S%"+."*-
if (ok) { 3$&+"&+0
cachedValue = d;
} else {
cachedValue = formulaStr; !"#$%&'(JK( 2@./4D&1!4"$46&;-$&+:$%41+9%%/&%D:$%++!-.+
}
}
}
return cachedValue;
}

!" value()#3&(4$-"#';*.-(/*#&"-;&*+#-!"#."))A+#4$);"0#<' cacheIsDirty#(+ true:#,"#*""%#-/#&".$).;)$-"


-!"#4$);"0

<'#-!"#'/&6;)$#+-$&-+#,(-!#$#+(*@)"#>;/-"#F'/&#"2$63)":#K#AOG[PZKJ:#-!"#+(*@)"#>;/-"#/..;3("+#3/+(-(/*
E#$*%#-!"#4$);"#(+#-!"#+-&(*@#'&/6#3/+(-(/*#O#-/#-!"#"*%0 h"-A+#+-$&-#,(-! evalExpression():#-!"#';*.-(/*#-!$-#3$&+"+#$* ()$&"**!%+7

<'#-!"#'/&6;)$#+-$&-+#,(-!#$*#">;$)+#+(@*#FA\AJ:#,"#-$5"#-!"#+-&(*@#'&/6#3/+(-(/*#O#$*%#&"6/4"#$*9
+3$."+#(-#6$9#./*-$(*0# !"*#,"#.$)) evalExpression()#-/#./63;-"#-!"#4$);"#/'#-!"#"23&"++(/*0# !" QVariant Cell::evalExpression(const QString &str, int &pos) const
pos#$&@;6"*-#(+#3$++"%#=9#&"'"&"*."B#(-#(*%(.$-"+#-!"#3/+(-(/*#/'#-!"#.!$&$.-"&#,!"&"#3$&+(*@#+!/;)% {
="@(*0#?'-"&#-!"#.$))#-/ evalExpression():#-!"#.!$&$.-"&#$-#3/+(-(/* pos#+!/;)%#="#-!" QChar::Null QVariant result = evalTerm(str, pos);
.!$&$.-"&#,"#$33"*%"%:#('#(-#,$+#+;.."++';))9#3$&+"%0#<'#-!"#3$&+"#'$()"%#="'/&"#-!"#"*%:#,"#+"- while (str[pos] != QChar::Null) {
QChar op = str[pos];
cachedValue#-/#=" Invalid0
if (op != '+' && op != '-')
return result;
<'#-!"#'/&6;)$#%/"+*A-#="@(*#,(-!#$#+(*@)"#>;/-"#/&#$*#">;$)+#+(@*:#,"#$--"63-#-/#./*4"&-#(-#-/#$ ++pos;
')/$-(*@S3/(*-#4$);"#;+(*@ toDouble()0#<'#-!"#./*4"&+(/*#,/&5+:#,"#+"- cachedValue#-/#="#-!" QVariant term = evalTerm(str, pos);
&"+;)-(*@#*;6="&B#/-!"&,(+":#,"#+"- cachedValue#-/#="#-!"#'/&6;)$#+-&(*@0#C/&#"2$63)":#$#'/&6;)$#/' if (result.type() == QVariant::Double
KO0ZEK#.$;+"+ toDouble()#-/#+"- ok#-/ true#$*%#&"-;&*#O0Z:#,!()"#$#'/&6;)$#/'#K1/&)%#e/3;)$-(/*K && term.type() == QVariant::Double) {
.$;+"+ toDouble()#-/#+"- ok#-/ false#$*%#&"-;&*#E0E0 if (op == '+') {
result = result.toDouble() + term.toDouble();
} else {
L9#@(4(*@ toDouble()#$#3/(*-"&#-/#$ bool:#,"#$&"#$=)"#-/#%(+-(*@;(+!#="-,""*#-!"#./*4"&+(/*#/'#$ result = result.toDouble() - term.toDouble();
+-&(*@#-!$-#&"3&"+"*-+#-!"#*;6"&(.#4$);"#E0E#$*%#$#./*4"&+(/*#"&&/&#F,!"&"#E0E#(+#$)+/#&"-;&*"%#=;- }
-!" bool (+#+"-#-/ falseJ0#R/6"-(6"+#-!"#&"-;&*(*@#/'#$#D"&/#4$);"#/*#./*4"&+(/*#'$();&"#(+#"2$.-)9 } else {
,!$-#,"#*""%:#(*#,!(.!#.$+"#,"#%/#*/-#=/-!"&#3$++(*@#$#3/(*-"&#-/#$ bool0#C/&#3"&'/&6$*."#$*% result = Invalid;
3/&-$=()(-9#&"$+/*+:#U-#*"4"&#;+"+#Q]]#"2."3-(/*+#-/#&"3/&-#'$();&"0# !(+#%/"+*A-#3&"4"*-#9/;#'&/6 }
;+(*@#-!"6#(*#U-#3&/@&$6+:#3&/4(%(*@#9/;&#./63()"&#+;33/&-+#-!"60 }
return result;
}
!" value()#';*.-(/*#(+#%".)$&"%#./*+-0#1"#!$%#-/#%".)$&" cachedValue#$*% cacheIsValid#$+#6;-$=)"
4$&($=)"+#+/#-!$-#-!"#./63()"&#,())#$))/,#;+#-/#6/%('9#-!"6#(*#./*+-#';*.-(/*+0#<-#6(@!-#="#-"63-(*@
-/#6$5" value()#*/*S./*+-#$*%#&"6/4"#-!" mutable#5"9,/&%+:#=;-#-!$-#,/;)%#*/-#./63()"#=".$;+"
,"#.$)) value()#'&/6 data():#$#./*+-#';*.-(/*0 C(&+-:#,"#.$)) evalTerm()#-/#@"-#-!"#4$);"#/'#-!"#'(&+-#-"&60#<'#-!"#'/))/,(*@#.!$&$.-"&#(+#A]A#/&#A]SSA:
,"#./*-(*;"#=9#.$))(*@ evalTerm()#$#+"./*%#-(6"B#/-!"&,(+":#-!"#"23&"++(/*#./*+(+-+#/'#$#+(*@)"
1"#!$4"#*/,#./63)"-"%#-!"#R3&"$%+!""-#$33)(.$-(/*:#$3$&-#'&/6#3$&+(*@#'/&6;)$+0# !"#&"+-#/'#-!(+ -"&6:#$*%#,"#&"-;&*#(-+#4$);"#$+#-!"#4$);"#/'#-!"#,!/)"#"23&"++(/*0#?'-"&#,"#!$4"#-!"#4$);"#/'#-!"
+".-(/*#./4"&+ evalExpression()#$*%#-!"#-,/#!")3"&#';*.-(/*+ evalTerm()#$*% evalFactor()0# !"#./%" '(&+-#-,/#-"&6+:#,"#./63;-"#-!"#&"+;)-#/'#-!"#/3"&$-(/*:#%"3"*%(*@#/*#-!"#/3"&$-/&0#<'#=/-!#-"&6+
(+#$#=(-#./63)(.$-"%:#=;-#(-#(+#(*.);%"%#!"&"#-/#6$5"#-!"#$33)(.$-(/*#./63)"-"0#R(*."#-!"#./%"#(+#*/- "4$);$-"%#-/#$ double:#,"#./63;-"#-!"#&"+;)-#$+#$ doubleB#/-!"&,(+":#,"#+"-#-!"#&"+;)-#-/#="
&")$-"%#-/#g`<#3&/@&$66(*@:#9/;#.$* +$'")9#+5(3#(-#$*%#./*-(*;"#&"$%(*@#'&/6 Q!$3-"&#Z0 Invalid0

!" evalExpression()#';*.-(/*#&"-;&*+#-!"#4$);"#/'#$#+3&"$%+!""-#"23&"++(/*0#?*#"23&"++(/*#(+ 1"#./*-(*;"#)(5"#-!(+#;*-()#-!"&"#$&"#*/#6/&"#-"&6+0# !(+#,/&5+#./&&".-)9#=".$;+"#$%%(-(/*#$*%


%"'(*"%#$+#/*"#/&#6/&"#-"&6+#+"3$&$-"%#=9#A]A#/&#A]SSA#/3"&$-/&+0# !"#-"&6+#-!"6+")4"+#$&"#%"'(*"%
+;=-&$.-(/*#$&"#)"'-S$++/.($-(4"B#-!$-#(+:#KOSGS[K#6"$*+#KFOSGJS[K:#*/-#KOSFGS[JK0 } else {
result = 0.0;
}
QVariant Cell::evalTerm(const QString &str, int &pos) const } else {
{ bool ok;
QVariant result = evalFactor(str, pos); result = token.toDouble(&ok);
while (str[pos] != QChar::Null) { if (!ok)
QChar op = str[pos]; result = Invalid;
if (op != '*' && op != '/') }
return result; }
++pos; if (negative) {
QVariant factor = evalFactor(str, pos); if (result.type() == QVariant::Double) {
if (result.type() == QVariant::Double result = -result.toDouble();
&& factor.type() == QVariant::Double) { } else {
if (op == '*') { result = Invalid;
result = result.toDouble() * factor.toDouble(); }
} else { }
if (factor.toDouble() == 0.0) { return result;
result = Invalid; }
} else {
result = result.toDouble() / factor.toDouble();
} !" evalFactor()#';*.-(/*#(+#$#=(-#6/&"#./63)(.$-"%#-!$* evalExpression()#$*% evalTerm()0#1"#+-$&-
} =9#*/-(*@#,!"-!"&#-!"#'$.-/&#(+#*"@$-"%0#1"#-!"*#+""#('#(-#="@(*+#,(-!#$*#/3"*#3$&"*-!"+(+0#<'#(-
} else {
%/"+:#,"#"4$);$-"#-!"#./*-"*-+#/'#-!"#3$&"*-!"+"+#$+#$*#"23&"++(/*#=9#.$))(*@ evalExpression()0
result = Invalid;
} 1!"*#3$&+(*@#$#3$&"*-!"+(D"%#"23&"++(/*: evalExpression()#.$))+ evalTerm():#,!(.!#.$))+ eval-
} Factor():#,!(.!#.$))+ evalExpression()#$@$(*0# !(+#(+#,!"&"#&".;&+(/*#/..;&+#(*#-!"#3$&+"&0
return result;
} <'#-!"#'$.-/&#(+*A-#$#*"+-"%#"23&"++(/*:#,"#"2-&$.-#-!"#*"2-#-/5"*:#,!(.!#+!/;)%#="#$#."))#)/.$-(/*#/&#$
*;6="&0#<'#-!"#-/5"*#6$-.!"+#-!" QRegExp:#,"#-$5"#(-#-/#="#$#."))#&"'"&"*."#$*%#,"#.$)) value()#/*
-!"#."))#$-#-!"#@(4"*#)/.$-(/*0# !"#."))#./;)%#="#$*9,!"&"#(*#-!"#+3&"$%+!""-:#$*%#(-#./;)%#!$4"
!" evalTerm()#';*.-(/*#(+#4"&9#+(6()$&#-/ evalExpression():#"2."3-#-!$-#(-#%"$)+#,(-!#6;)-(3)(.$-(/* %"3"*%"*.("+#/*#/-!"&#."))+0# !"#%"3"*%"*.("+#$&"#*/-#$#3&/=)"6B#-!"9#,())#+(63)9#-&(@@"&#6/&"
$*%#%(4(+(/*0# !"#/*)9#+;=-)"-9#(* evalTerm()#(+#-!$-#,"#6;+-#$4/(%#%(4(+(/*#=9#D"&/:#+(*."#(-#(+#$* value()#.$))+#$*%#F'/&#K%(&-9K#."))+J 6/&"#3$&+(*@#;*-()#$))#-!"#%"3"*%"*-#."))#4$);"+#$&"#.$).;)$-"%0#<'
"&&/&#/*#+/6"#3&/."++/&+0#1!()"#(-#(+#@"*"&$))9#(*$%4(+$=)"#-/#-"+-#')/$-(*@S3/(*-#4$);"+#'/&#">;$)(-9 -!"#-/5"*#(+*A-#$#."))#)/.$-(/*:#,"#-$5"#(-#-/#="#$#*;6="&0
=".$;+"#/'#&/;*%(*@#"&&/&+:#(-#(+#+$'"#-/#-"+-#'/&#">;$)(-9#$@$(*+-#E0E#-/#3&"4"*-#%(4(+(/*#=9#D"&/0
1!$-#!$33"*+#('#."))#?O#./*-$(*+#-!"#'/&6;)$#K\?OKk#V&#('#."))#?O#./*-$(*+#K\?GK#$*%#."))#?G
./*-$(*+#K\?OKk#?)-!/;@!#,"#!$4"#*/-#,&(--"*#$*9#+3".($)#./%"#-/#%"-".-#.(&.;)$&#%"3"*%"*.("+:#-!"
QVariant Cell::evalFactor(const QString &str, int &pos) const 3$&+"&#!$*%)"+#-!"+"#.$+"+#@&$."';))9#=9#&"-;&*(*@#$*#(*4$)(% QVariant0# !(+#,/&5+#=".$;+"#,"#+"-
{ cacheIsDirty#-/ false#$*% cachedValue#-/ Invalid#(* value()#="'/&"#,"#.$)) evalExpression()0#<'
QVariant result; evalExpression()#&".;&+(4")9#.$))+ value()#/*#-!"#+$6"#.")):#(-#&"-;&*+ Invalid#(66"%($-")9:#$*%#-!"
bool negative = false; ,!/)"#"23&"++(/*#-!"*#"4$);$-"+#-/ Invalid0
if (str[pos] == '-') {
negative = true;
++pos; 1"#!$4"#*/,#./63)"-"%#-!"#'/&6;)$#3$&+"&0#<-#,/;)%#="#+-&$(@!-'/&,$&%#-/#"2-"*%#(-#-/#!$*%)"
} 3&"%"'(*"%#+3&"$%+!""-#';*.-(/*+:#)(5"#K+;6FJK#$*%#K$4@FJK:#=9#"2-"*%(*@#-!"#@&$66$-(.$)#%"'(*(-(/*
if (str[pos] == '(') { /' 012'%&0#?*/-!"&#"$+9#"2-"*+(/*#(+#-/#(63)"6"*-#-!"#A]A#/3"&$-/&#,(-!#+-&(*@#/3"&$*%+#F$+
++pos; ./*.$-"*$-(/*JB#-!(+#&">;(&"+#*/#.!$*@"+#-/#-!"#@&$66$&0
result = evalExpression(str, pos);
if (str[pos] != ')')
result = Invalid;
++pos;
} else {
QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
QString token;
while (str[pos].isLetterOrNumber() || str[pos] == '.') {
token += str[pos];
++pos;
}
if (regExp.exactMatch(token)) {
int column = token[0].toUpper().unicode() - 'A';
int row = token.mid(1).toInt() - 1;
Cell *c = static_cast<Cell *>(
tableWidget()->item(row, column));
if (c) {
result = c->value();
{
setRange(0, 255);
Chapter 5. Creating Custom Widgets }
validator = new QRegExpValidator(QRegExp("[0-9A-Fa-f]{1,8}"), this);

• !"#$%&'&()*+#*,&-).#"
• /!0123""&() +,&-).#
1"#+"-#-!"#%"'$;)-#&$*@"#-/#="#E#-/#GZZ#F0x00#-/ 0xFFJ:#,!(.!#(+#6/&"#$33&/3&($-"#'/&#$#!"2$%".(6$)
• 4(#.)53#&()* !"#$%*,&-).#"*6&#7*+#*8."&)(.5
+3(*#=/2#-!$* QSpinBoxA+#%"'$;)-#/'#E#-/#II0
• 8$!02.*9!::.5&()

!"#;+"&#.$*#6/%('9#$#+3(*#=/2A+#.;&&"*-#4$);"#"(-!"&#=9#.)(.5(*@#(-+#;3#$*%#%/,*#$&&/,+#/&#=9
!(+#.!$3-"&#"23)$(*+#!/,#-/#%"4")/3#.;+-/6#,(%@"-+#;+(*@#U-0#Q;+-/6#,(%@"-+#.$*#="#.&"$-"%#=9
-93(*@#$#4$);"#(*-/#-!"#+3(*#=/2A+#)(*"#"%(-/&0#<*#-!"#)$--"&#.$+":#,"#,$*-#-/#&"+-&(.-#-!"#;+"&A+#(*3;-
+;=.)$++(*@#$*#"2(+-(*@#U-#,(%@"-#/&#=9#+;=.)$++(*@ QWidget#%(&".-)90#1"#,())#%"6/*+-&$-"#=/-!
-/#)"@(-(6$-"#!"2$%".(6$)#*;6="&+0# /#$.!("4"#-!(+:#,"#;+"#$ QRegExpValidator#-!$-#$.."3-+
$33&/$.!"+:#$*%#,"#,())#$)+/#+""#!/,#-/#(*-"@&$-"#$#.;+-/6#,(%@"-#,(-! 3'-4"*!5+"&#+/#-!$-#(-#.$*
="-,""*#/*"#$*%#"(@!-#.!$&$.-"&+:#"$.!#/'#,!(.!#6;+-#="#(*#/*"#/'#-!"#+"-+:#AEA#-/#AIA:#A?A#-/#ACA:#$*%
="#;+"%#T;+-#)(5"#$#=;()-S(*#U-#,(%@"-0#1"#,())#&/;*%#/''#-!"#.!$3-"&#=9#3&"+"*-(*@#$#.;+-/6#,(%@"-
A$A#-/#A'A0
-!$-#;+"+#%/;=)"#=;''"&(*@:#$#3/,"&';)#-".!*(>;"#'/&#!(@!S+3""%#%&$,(*@0

Customizing Qt Widgets QValidator::State HexSpinBox::validate(QString &text, int &pos) const


{
return validator->validate(text, pos);
<*#+/6"#.$+"+:#,"#'(*%#-!$-#$#U-#,(%@"-#&">;(&"+#6/&"#.;+-/6(D$-(/*#-!$*#(+#3/++(=)"#=9#+"--(*@#(-+ }
3&/3"&-("+#(* 3'-4"*!5+"&#/&#=9#.$))(*@#(-+#';*.-(/*+0#?#+(63)"#$*%#%(&".-#+/);-(/*#(+#-/#+;=.)$++#-!"
&")"4$*-#,(%@"-#.)$++#$*%#$%$3-#(-#-/#+;(-#/;&#*""%+0

!(+#';*.-(/*#(+#.$))"%#=9 QSpinBox#-/#+""#('#-!"#-"2-#"*-"&"%#+/#'$&#(+#4$)(%0# !"&"#$&"#-!&""#3/++(=)"


!"#$%&>(J(&89% HexSpinBox&0!1"%/ &"+;)-+7 Invalid#F-!"#-"2-#%/"+*A-#6$-.!#-!"#&"@;)$&#"23&"++(/*J: Intermediate#F-!"#-"2-#(+#$
3)$;+(=)"#3$&-#/'#$#4$)(%#4$);"J:#$*% Acceptable#F-!"#-"2-#(+#4$)(%J0# !" QRegExpValidator#!$+#$
+;(-$=)" validate()#';*.-(/*:#+/#,"#+(63)9#&"-;&*#-!"#&"+;)-#/'#.$))(*@#(-0#<*#-!"/&9:#,"#+!/;)%#&"-;&*
Invalid#/& Intermediate#'/&#4$);"+#-!$-#)("#/;-+(%"#-!"#+3(*#=/2A+#&$*@":#=;- QSpinBox#(+#+6$&-
"*/;@!#-/#%"-".-#-!$-#./*%(-(/*#,(-!/;-#$*9#!")30

QString HexSpinBox::textFromValue(int value) const


<*#-!(+#+".-(/*:#,"#,())#%"4")/3#$#!"2$%".(6$)#+3(*#=/2#-/#+!/,#!/,#-!(+#,/&5+0 QSpinBox#/*)9
{
+;33/&-+#%".(6$)#(*-"@"&+:#=;-#=9#+;=.)$++(*@#(-A+#>;(-"#"$+9#-/#6$5"#(-#$.."3-#$*%#%(+3)$9 return QString::number(value, 16).toUpper();
!"2$%".(6$)#4$);"+0 }

#ifndef HEXSPINBOX_H
#define HEXSPINBOX_H !" textFromValue()#';*.-(/*#./*4"&-+#$*#(*-"@"&#4$);"#-/#$#+-&(*@0 QSpinBox#.$))+#(-#-/#;3%$-"#-!"
#include <QSpinBox> "%(-/&#3$&-#/'#-!"#+3(*#=/2#,!"*#-!"#;+"&#3&"++"+#-!"#+3(*#=/2A+#;3#/&#%/,*#$&&/,+0#1"#;+"#-!"
class QRegExpValidator; +-$-(.#';*.-(/* QString::number()#,(-!#$#+"./*%#$&@;6"*-#/'#OH#-/#./*4"&-#-!"#4$);"#-/#)/,"&.$+"
class HexSpinBox : public QSpinBox !"2$%".(6$):#$*%#.$)) QString::toUpper()#/*#-!"#&"+;)-#-/#6$5"#(-#;33"&.$+"0
{
Q_OBJECT
public: int HexSpinBox::valueFromText(const QString &text) const
HexSpinBox(QWidget *parent = 0); {
protected: bool ok;
QValidator::State validate(QString &text, int &pos) const; return text.toInt(&ok, 16);
int valueFromText(const QString &text) const; }
QString textFromValue(int value) const;
private:
QRegExpValidator *validator;
}; !" valueFromText()#';*.-(/*#3"&'/&6+#-!" &"4"&+"#./*4"&+(/*:#'&/6#$#+-&(*@#-/#$*#(*-"@"&#4$);"0#<-
#endif (+#.$))"%#=9 QSpinBox#,!"*#-!"#;+"&#-93"+#$#4$);"#(*-/#-!"#"%(-/&#3$&-#/'#-!"#+3(*#=/2#$*%#3&"++"+
Y*-"&0#1"#;+"#-!" QString::toInt()#';*.-(/*#-/#$--"63-#-/#./*4"&-#-!"#.;&&"*-#-"2-#-/#$*#(*-"@"&
4$);":#$@$(*#;+(*@#=$+"#OH0#<'#-!"#+-&(*@#(+#*/-#4$)(%#!"2$%".(6$): ok#(+#+"-#-/ false#$*% toInt()
!" HexSpinBox#(*!"&(-+#6/+-#/'#(-+#';*.-(/*$)(-9#'&/6 QSpinBox0#<-#3&/4(%"+#$#-93(.$)#./*+-&;.-/&#$*% &"-;&*+#E0#X"&":#,"#%/*A-#!$4"#-/#./*+(%"&#-!(+#3/++(=()(-9#=".$;+"#-!"#4$)(%$-/&#/*)9#3"&6(-+#4$)(%
&"(63)"6"*-+#-!&""#4(&-;$)#';*.-(/*+#'&/6 QSpinBox0 !"2$%".(6$)#+-&(*@+#-/#="#"*-"&"%0#<*+-"$%#/'#3$++(*@#-!" $%%&"++#/'#$#%;669#4$&($=)"#FokJ:#,"
./;)%#(*+-"$%#3$++#$#*;))#3/(*-"&#$+#-!"#'(&+-#$&@;6"*-#-/ toInt()0

#include <QtGui> 1"#!$4"#*/,#'(*(+!"%#-!"#!"2$%".(6$)#+3(*#=/20#Q;+-/6(D(*@#/-!"&#U-#,(%@"-+#'/))/,+#-!"#+$6"


#include "hexspinbox.h" 3$--"&*7#e(.5#$#+;(-$=)"#U-#,(%@"-:#+;=.)$++#(-:#$*%#&"(63)"6"*-#+/6"#4(&-;$)#';*.-(/*+#-/#.!$*@"#(-+
HexSpinBox::HexSpinBox(QWidget *parent) ="!$4(/&0
: QSpinBox(parent)
h"-A+#="@(*#=9#&"4(",(*@#-!"#!"$%"&#'()"0

Subclassing QWidget #ifndef ICONEDITOR_H


#define ICONEDITOR_H
d$*9#.;+-/6#,(%@"-+#$&"#+(63)9#$#./6=(*$-(/*#/'#"2(+-(*@#,(%@"-+:#,!"-!"&#-!"9#$&"#=;()-S(*#U- #include <QColor>
,(%@"-+#/&#/-!"&#.;+-/6#,(%@"-+#+;.!#$+ HexSpinBox0#Q;+-/6#,(%@"-+#-!$-#$&"#=;()-#=9#./63/+(*@ #include <QImage>
#include <QWidget>
"2(+-(*@#,(%@"-+#.$*#;+;$))9#="#%"4")/3"%#(* 3'-4"*!5+"&7
class IconEditor : public QWidget
{
• Q&"$-"#$#*",#'/&6#;+(*@#-!"#K1(%@"-K#-"63)$-"0 Q_OBJECT
• ?%%#-!"#*"."++$&9#,(%@"-+#-/#-!"#'/&6: $*%#)$9#-!"6#/;-0 Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
• R"-#;3#-!"#+(@*$)+#$*%#+)/-+#./**".-(/*+0 Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
• <'#="!$4(/&#="9/*%#,!$-#.$*#="#$.!("4"%#-!&/;@!#+(@*$)+#$*%#+)/-+#(+#&">;(&"%:#,&(-"#-!" Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
*"."++$&9#./%"#(*#$#.)$++#-!$-#(*!"&(-+#=/-! QWidget#$*%#-!" uicS@"*"&$-"%#.)$++0 public:
IconEditor(QWidget *parent = 0);
void setPenColor(const QColor &newColor);
8$-;&$))9:#./6=(*(*@#"2(+-(*@#,(%@"-+#.$*#$)+/#="#%/*"#"*-(&")9#(*#./%"0#1!(.!"4"&#$33&/$.!#(+
QColor penColor() const { return curColor; }
-$5"*:#-!"#&"+;)-(*@#.)$++#(*!"&(-+#%(&".-)9#'&/6 QWidget0
void setZoomFactor(int newZoom);
<'#-!"#,(%@"-#!$+#*/#+(@*$)+#$*%#+)/-+#/'#(-+#/,*#$*%#%/"+*A-#&"(63)"6"*-#$*9#4(&-;$)#';*.-(/*+:#(-#(+ int zoomFactor() const { return zoom; }
"4"*#3/++(=)"#-/#+(63)9 $++"6=)"#-!"#,(%@"-#=9#./6=(*(*@#"2(+-(*@#,(%@"-+#,(-!/;-#$#+;=.)$++0 void setIconImage(const QImage &newImage);
!$-A+#-!"#$33&/$.!#,"#;+"%#(* Q!$3-"&#O#-/#.&"$-"#-!"#?@"#$33)(.$-(/*:#,(-!#$ QWidget:#$ QSpinBox: QImage iconImage() const { return image; }
$*%#$ QSlider0#Y4"*#+/:#,"#./;)%#T;+-#$+#"$+()9#!$4"#+;=.)$++"% QWidget#$*%#.&"$-"%#-!" QSpinBox QSize sizeHint() const;
$*% QSlider#(*#-!"#+;=.)$++A+#./*+-&;.-/&0

1!"*#*/*"#/'#U-A+#,(%@"-+#$&"#+;(-$=)"#'/&#-!"#-$+5#$-#!$*%:#$*%#,!"*#-!"&"A+#*/#,$9#-/#./6=(*"#/& !" IconEditor#.)$++#;+"+#-!" Q_PROPERTY()#6$.&/#-/#%".)$&"#-!&""#.;+-/6#3&/3"&-("+7 penColor:


$%$3-#"2(+-(*@#,(%@"-+#-/#/=-$(*#-!"#%"+(&"%#&"+;)-:#,"#.$*#+-())#.&"$-"#-!"#,(%@"-#,"#,$*-0# !(+#(+ iconImage:#$*% zoomFactor0#Y$.!#3&/3"&-9#!$+#$#%$-$#-93":#$#K&"$%K#';*.-(/*:#$*%#$*#/3-(/*$)#K,&(-"K
$.!("4"%#=9#+;=.)$++(*@ QWidget#$*%#&"(63)"6"*-(*@#$#'",#"4"*-#!$*%)"&+#-/#3$(*-#-!"#,(%@"-#$*%#-/ ';*.-(/*0#C/&#"2$63)":#-!" penColor#3&/3"&-9#(+#/'#-93" QColor#$*%#.$*#="#&"$%#$*%#,&(--"*#;+(*@#-!"
&"+3/*%#-/#6/;+"#.)(.5+0# !(+#$33&/$.!#@(4"+#;+#./63)"-"#'&""%/6#-/#%"'(*"#$*%#./*-&/)#=/-!#-!" penColor()#$*% setPenColor()#';*.-(/*+0
$33"$&$*."#$*%#-!"#="!$4(/&#/'#/;&#,(%@"-0#U-A+#=;()-S(*#,(%@"-+:#)(5" QLabel: QPushButton:#$*%
QTableWidget:#$&"#(63)"6"*-"%#-!(+#,$90#<'#-!"9#%(%*A-#"2(+-#(*#U-:#(-#,/;)%#+-())#="#3/++(=)"#-/#.&"$-" 1!"*#,"#6$5"#;+"#/'#-!"#,(%@"-#(* 3'-4"*!5+"&:#.;+-/6#3&/3"&-("+#$33"$&#(* 3'-4"*!5+"&A+
-!"6#/;&+")4"+#;+(*@#-!"#3;=)(.#';*.-(/*+#3&/4(%"%#=9 QWidget#(*#$#./63)"-")9#3)$-'/&6S(*%"3"*%"*- 3&/3"&-9#"%(-/&#=")/,#-!"#3&/3"&-("+#(*!"&(-"%#'&/6 QWidget0#e&/3"&-("+#6$9#="#/'#$*9#-93"
6$**"&0 +;33/&-"%#=9 QVariant0# !" Q_OBJECT#6$.&/#(+#*"."++$&9#'/&#.)$++"+#-!$-#%"'(*"#3&/3"&-("+0

/#%"6/*+-&$-"#!/,#-/#,&(-"#$#.;+-/6#,(%@"-#;+(*@#-!(+#$33&/$.!:#,"#,())#.&"$-"#-!" IconEditor
,(%@"-#+!/,*#(* C(@;&"#Z0G0# !" IconEditor#(+#$#,(%@"-#-!$-#./;)%#="#;+"%#(*#$*#(./*#"%(-(*@ protected:
3&/@&$60 void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
!"#$%&>()(&89% IconEditor&0!1"%/ private:
void setImagePixel(const QPoint &pos, bool opaque);
QRect pixelRect(int i, int j) const;
QColor curColor;
QImage image;
int zoom;
};
#endif

IconEditor#&"(63)"6"*-+#-!&""#3&/-".-"%#';*.-(/*+#'&/6 QWidget#$*%#!$+#$#'",#3&(4$-"#';*.-(/*+#$*%
4$&($=)"+0# !"#-!&""#3&(4$-"#4$&($=)"+#!/)%#-!"#4$);"+#/'#-!"#-!&""#3&/3"&-("+0

!"#(63)"6"*-$-(/*#'()"#="@(*+#,(-!#-!" IconEditorA+#./*+-&;.-/&7

#include <QtGui>
#include "iconeditor.h"
IconEditor::IconEditor(QWidget *parent)
: QWidget(parent)
{
setAttribute(Qt::WA_StaticContents);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); }
curColor = Qt::black;
zoom = 8;
image = QImage(16, 16, QImage::Format_ARGB32);
image.fill(qRgba(0, 0, 0, 0)); !" sizeHint()#';*.-(/*#(+#&"(63)"6"*-"%#'&/6 QWidget#$*%#&"-;&*+#-!"#(%"$)#+(D"#/'#$#,(%@"-0#X"&":
} ,"#-$5"#-!"#(6$@"#+(D"#6;)-(3)("%#=9#-!"#D//6#'$.-/&:#,(-!#/*"#"2-&$#3(2")#(*#"$.!#%(&".-(/*#-/
$../66/%$-"#$#@&(%#('#-!"#D//6#'$.-/&#(+#[#/&#6/&"0#F1"#%/*A-#+!/,#$#@&(%#('#-!"#D//6#'$.-/&#(+#G#/&
O:#=".$;+"#-!"#@&(%#,/;)%#-!"*#!$&%)9#)"$4"#$*9#&//6#'/&#-!"#(./*A+#3(2")+0J
!"#./*+-&;.-/&#!$+#+/6"#+;=-)"#$+3".-+#+;.!#$+#-!" Qt::WA_StaticContents#$--&(=;-"#$*%#-!"
?#,(%@"-A+#+(D"#!(*-#(+#6/+-)9#;+"';)#(*#./*T;*.-(/*#,(-!#)$9/;-+0#U-A+#)$9/;-#6$*$@"&+#-&9#$+#6;.!
setSizePolicy()#.$))0#1"#,())#%(+.;++#-!"6#+!/&-)90
$+#3/++(=)"#-/#&"+3".-#$#,(%@"-A+#+(D"#!(*-#,!"*#-!"9#)$9#/;-#$#'/&6A+#.!()%#,(%@"-+0#C/& IconEditor
-/#="#$#@//%#)$9/;-#.(-(D"*:#(-#6;+-#&"3/&-#$#.&"%(=)"#+(D"#!(*-0
!"#3"*#./)/&#(+#+"-#-/#=)$.50# !"#D//6#'$.-/&#(+#+"-#-/#^:#6"$*(*@ -!$-#"$.!#3(2")#(*#-!"#(./*#,())#="
&"*%"&"%#$+#$*#^#2#^#+>;$&"0
<*#$%%(-(/*#-/#-!"#+(D"#!(*-:#,(%@"-+#!$4"#$#+(D"#3/)(.9#-!$-#-"))+#-!"#)$9/;-#+9+-"6#,!"-!"&#-!"9#)(5"
-/#="#+-&"-.!"%#$*%#+!&;*50#L9#.$))(*@ setSizePolicy()#(*#-!"#./*+-&;.-/& ,(-! QSizePolicy::Minimum
!"#(./*#%$-$#(+#+-/&"%#(*#-!" image#6"6="&#4$&($=)"#$*%#.$*#="#$.."++"%#-!&/;@!#-!" $+#!/&(D/*-$)#$*%#4"&-(.$)#3/)(.("+:#,"#-"))#$*9#)$9/;-#6$*$@"&#-!$-#(+#&"+3/*+(=)"#'/&#-!(+#,(%@"-#-!$-
setIconImage()#$*% iconImage()#';*.-(/*+0#?*#(./*#"%(-/&#3&/@&$6#,/;)%#-93(.$))9#.$)) -!"#,(%@"-A+#+(D"#!(*-#(+#&"$))9#(-+#6(*(6;6#+(D"0#<*#/-!"&#,/&%+:#-!"#,(%@"-#.$*#="#+-&"-.!"%#('
setIconImage()#,!"* -!"#;+"&#/3"*+#$*#(./*#'()"#$*% icon-Image()#-/#&"-&("4"#-!"#(./*#,!"*#-!"#;+"& &">;(&"%:#=;-#(-#+!/;)%#*"4"&#+!&(*5#=")/,#-!"#+(D"#!(*-0# !(+#.$*#="#/4"&&(%%"*#(* 3'-4"*!5+"&#=9
,$*-+#-/#+$4"#(-0# !" image#4$&($=)"#(+#/'#-93" QImage0#1"#(*(-($)(D"#(-#-/#OH#2#OH#3(2")+#$*%#[GS=(- +"--(*@#-!"#,(%@"-A+ sizePolicy#3&/3"&-90# !"#6"$*(*@#/'#-!"#4$&(/;+#+(D"#3/)(.("+#(+#"23)$(*"%#(*
?fgL#'/&6$-:#$#'/&6$-#-!$-#+;33/&-+#+"6(S-&$*+3$&"*.90#1"#.)"$&#-!"#(6$@" %$-$#=9#'())(*@#(-#,(-!#$ Q!$3-"&#H#Fh$9/;-#d$*$@"6"*-J0
-&$*+3$&"*-#./)/&0

!" QImage#.)$++#+-/&"+#$*#(6$@"#(*#$#!$&%,$&"S(*%"3"*%"*-#'$+!(/*0#<-#.$*#="#+"-#-/#;+"#$#OS=(-:#^S void IconEditor::setPenColor(const QColor &newColor)


=(-:#/&#[GS=(-#%"3-!0#?*#(6$@"#,(-!#[GS=(-#%"3-!#;+"+#^#=(-+#'/&#"$.!#/'#-!"#&"%:#@&""*:#$*%#=);" {
./63/*"*-+#/'#$#3(2")0# !"#&"6$(*(*@#^#=(-+#+-/&"#-!"#3(2")A+#$)3!$#./63/*"*-#F/3$.(-9J0#C/& curColor = newColor;
"2$63)":#$#3;&"#&"%#./)/&A+#&"%:#@&""*:#=);":#$*%#$)3!$#./63/*"*-+#!$4"#-!"#4$);"+#GZZ:#E:#E:#$*% }
GZZ0#<*#U-:#-!(+#./)/&#.$*#="#+3".('("%#$+

!" setPenColor()#';*.-(/*#+"-+#-!"#.;&&"*-#3"*#./)/&0# !"#./)/&#,())#="#;+"%#'/&#*",)9#%&$,*#3(2")+0


QRgb red = qRgba(255, 0, 0, 255);

void IconEditor::setIconImage(const QImage &newImage)


/&:#+(*."#-!"#./)/&#(+#/3$>;":#$+ {
if (newImage != image) {
image = newImage.convertToFormat(QImage::Format_ARGB32);
QRgb red = qRgb(255, 0, 0); update();
updateGeometry();
}
}
QRgb#(+#+(63)9#$#-93"%"'#'/& unsigned int:#$*% qRgb()#$*% qRgba()#$&"#(*)(*"#';*.-(/*+#-!$-#./6=(*"
-!"(&#$&@;6"*-+#(*-/#/*"#[GS=(-#(*-"@"&#4$);"0#<-#(+#$)+/#3/++(=)"#-/#,&(-"
!" setIconImage()#';*.-(/*#+"-+#-!"#(6$@"#-/#"%(-0#1"#.$)) convertToFormat()#-/#6$5"#-!"#(6$@"
[GS=(-#,(-!#$*#$)3!$#=;''"&:#('#(-#(+*A-#$)&"$%90#Y)+",!"&"#(*#-!"#./%":#,"#,())#$++;6"#-!$-#-!"#(6$@"
QRgb red = 0xFFFF0000;
%$-$#(+#+-/&"%#$+#[GS=(-#?fgL#4$);"+0

?'-"&#+"--(*@#-!" image#4$&($=)":#,"#.$)) QWidget::update()#-/#'/&."#$#&"3$(*-(*@#/'#-!"#,(%@"-#;+(*@


,!"&"#-!"#'(&+- FF#./&&"+3/*%+#-/#-!"#$)3!$#./63/*"*-#$*%#-!"#+"./*% FF#-/#-!"#&"%#./63/*"*-0#<* -!"#*",#(6$@"0#8"2-:#,"#.$)) QWidget::updateGeometry()#-/#-"))#$*9#)$9/;-#-!$-#./*-$(*+#-!"#,(%@"-
-!" IconEditor#./*+-&;.-/&:#,"#'())#-!" QImage#,(-!#$#-&$*+3$&"*-#./)/&#=9#;+(*@#E#$+#-!"#$)3!$ -!$-#-!"#,(%@"-A+#+(D"#!(*-#!$+#.!$*@"%0# !"#)$9/;-#,())#-!"*#$;-/6$-(.$))9#$%$3-#-/#-!"#*",#+(D"
./63/*"*-0 !(*-0

U-#3&/4(%"+#-,/#-93"+#'/&#+-/&(*@#./)/&+7 QRgb#$*% QColor0#1!()" QRgb#(+#/*)9#$#-93"%"'#;+"%#(* QImage


-/#+-/&"#[GS=(-#3(2")#%$-$: QColor#(+#$#.)$++#,(-!#6$*9#;+"';)#';*.-(/*+#$*%#(+#,(%")9#;+"%#(*#U-#-/ void IconEditor::setZoomFactor(int newZoom)
+-/&"#./)/&+0#<*#-!" IconEditor#,(%@"-:#,"#/*)9#;+" QRgb#,!"*#%"$)(*@#,(-!#-!" QImageB#,"#;+" {
QColor#'/&#"4"&9-!(*@#")+":#(*.);%(*@#-!" penColor#3&/3"&-90 if (newZoom < 1)
newZoom = 1;
if (newZoom != zoom) {
zoom = newZoom;
QSize IconEditor::sizeHint() const
update();
{
updateGeometry();
QSize size = zoom * image.size();
}
if (zoom >= 3)
}
size += QSize(1, 1);
return size;
?#.$))#-/ QPainter::drawLine()#!$+#-!"#'/))/,(*@#+9*-$27
!" setZoomFactor()#';*.-(/*#+"-+#-!"#D//6#'$.-/&#'/&#-!"#(6$@"0# /#3&"4"*-#%(4(+(/*#=9#D"&/
")+",!"&":#,"#./&&".-#$*9#4$);"#=")/,#O0#?@$(*:#,"#.$)) update()#$*% updateGeometry()#-/#&"3$(*-
-!"#,(%@"-#$*%#-/#*/-('9#$*9#6$*$@(*@#)$9/;-#$=/;-#-!"#+(D"#!(*-#.!$*@"0 painter.drawLine(x1, y1, x2, y2);

!" penColor(): iconImage():#$*% zoomFactor()#';*.-(/*+#$&"#(63)"6"*-"%#$+#(*)(*"#';*.-(/*+#(*#-!"


!"$%"&#'()"0 ,!"&"#Fx1: y1J#(+#-!"#3/+(-(/*#/'#/*"#"*%#/'#-!"#)(*"#$*%#Fx2: y2J#(+#-!"#3/+(-(/*#/'#-!"#/-!"&#"*%0
!"&"#(+#$)+/#$*#/4"&)/$%"%#4"&+(/*#/'#-!"#';*.-(/*#-!$-#-$5"+#-,/ QPoint+#(*+-"$%#/'#'/;& int+0
1"#,())#*/,#&"4(",#-!"#./%"#'/&#-!" paintEvent()#';*.-(/*0# !(+#';*.-(/*#(+ IconEditorA+#6/+-
(63/&-$*-#';*.-(/*0#<-#(+#.$))"%#,!"*"4"&#-!"#,(%@"-#*""%+#&"3$(*-(*@0# !"#%"'$;)-#(63)"6"*-$-(/*#(* !"#-/3S)"'-#3(2")#/'#$#U-#,(%@"-#(+#)/.$-"%#$-#3/+(-(/*#FE:#EJ:#$*%#-!"#=/--/6S&(@!-#3(2")#(+#)/.$-"%#$-
QWidget#%/"+#*/-!(*@:#)"$4(*@#-!"#,(%@"-#=)$*50 Fwidth() S#O: height() S#OJ0# !(+#(+#+(6()$&#-/#-!"#./*4"*-(/*$)#Q$&-"+($*#.//&%(*$-"#+9+-"6:#=;-
;3+(%"#%/,*0#1"#.$*#.!$*@" QPainterA+#.//&%(*$-"#+9+-"6#=9#;+(*@#-&$*+'/&6$-(/*+:#+;.!#$+
_;+-#)(5" closeEvent():#,!(.!#,"#6"-#(* Q!$3-"&#[: paintEvent()#(+#$*#"4"*-#!$*%)"&0#U-#!$+#6$*9 -&$*+)$-(/*:#+.$)(*@:#&/-$-(/*:#$*%#+!"$&(*@0# !(+#(+#./4"&"%#(* Q!$3-"&#^#FGc#$*%#[c#g&$3!(.+J0
/-!"&#"4"*-#!$*%)"&+:#"$.!#/'#,!(.!#./&&"+3/*%+#-/#$#%(''"&"*-#-93"#/'#"4"*-0 Q!$3-"&#a#./4"&+#"4"*-
3&/."++(*@#(*#%"3-!0 !"#$%&>(7( 3$40!."&4&<!.%&#+!." QPainter

!"&"#$&"#6$*9#+(-;$-(/*+#,!"*#$#3$(*-#"4"*-#(+#@"*"&$-"%#$*% paintEvent()#(+#.$))"%7

• 1!"*#$#,(%@"-#(+#+!/,*#'/&#-!"#'(&+-#-(6":#-!"#+9+-"6#$;-/6$-(.$))9#@"*"&$-"+#$#3$(*-#"4"*-
-/#'/&."#-!"#,(%@"-#-/#3$(*-#(-+")'0
• 1!"*#$#,(%@"-#(+#&"+(D"%:#-!"#+9+-"6#@"*"&$-"+#$#3$(*-#"4"*-0
• <'#-!"#,(%@"-#(+#/=+.;&"%#=9#$*/-!"&#,(*%/,#$*%#-!"*#&"4"$)"%#$@$(*:#$#3$(*-#"4"*-#(+
@"*"&$-"%#'/&#-!"#$&"$#-!$-#,$+#!(%%"*#F;*)"++#-!"#,(*%/,#+9+-"6#+-/&"%#-!"#$&"$J0

1"#.$*#$)+/#'/&."#$#3$(*-#"4"*-#=9#.$))(*@ QWidget::update()#/& QWidget::re-paint()0# !"#%(''"&"*."


="-,""*#-!"+"#-,/#';*.-(/*+#(+#-!$- repaint()#'/&."+#$*#(66"%($-"#&"3$(*-:#,!"&"$+ update()#+(63)9
+.!"%;)"+#$#3$(*-#"4"*-#'/&#,!"*#U-#*"2-#3&/."++"+#"4"*-+0#FL/-!#';*.-(/*+#%/#*/-!(*@#('#-!"#,(%@"-
(+*A-#4(+(=)"#/*#+.&""*0J#<' update()#(+#.$))"%#6;)-(3)"#-(6"+:#U-#./63&"++"+#-!"#./*+".;-(4"#3$(*-
"4"*-+#(*-/#$#+(*@)"#3$(*-#"4"*-#-/#$4/(%#')(.5"&0#<* IconEditor:#,"#$),$9+#;+" update()0

X"&"A+#-!"#./%"7
L"'/&"#,"#.$)) drawLine()#/*#-!" QPainter:#,"#+"-#-!"#)(*"A+#./)/&#;+(*@ setPen()0#1"#./;)%#!$&%S
./%"#$#./)/&:#)(5"#=)$.5#/&#@&$9:#=;-#$#="--"&#$33&/$.!#(+#-/#;+"#-!"#,(%@"-A+#3$)"--"0
void IconEditor::paintEvent(QPaintEvent *event)
{ Y4"&9#,(%@"-#(+#">;(33"%#,(-!#$#3$)"--"#-!$-#+3".('("+#,!(.!#./)/&+#+!/;)%#="#;+"%#'/&#,!$-0#C/&
QPainter painter(this); "2$63)":#-!"&"#(+#$#3$)"--"#"*-&9#'/&#-!"#=$.5@&/;*%#./)/&#/'#,(%@"-+#F;+;$))9#)(@!-#@&$9J#$*%#/*"#'/&
if (zoom >= 3) { -!"#./)/&#/'#-"2-#/*#-!$-#=$.5@&/;*%#F;+;$))9#=)$.5J0#L9#%"'$;)-:#$#,(%@"-A+#3$)"--"#$%/3-+#-!"
painter.setPen(palette().foreground().color()); ,(*%/,#+9+-"6A+#./)/&#+.!"6"0#L9#;+(*@#./)/&+#'&/6#-!"#3$)"--":#,"#"*+;&"#-!$- IconEditor#&"+3".-+
for (int i = 0; i <= image.width(); ++i) -!"#;+"&A+#3&"'"&"*."+0
painter.drawLine(zoom * i, 0,
zoom * i, zoom * image.height());
for (int j = 0; j <= image.height(); ++j) ?#,(%@"-A+#3$)"--"#./*+(+-+#/'#-!&""#./)/&#@&/;3+7#$.-(4":#(*$.-(4":#$*%#%(+$=)"%0#1!(.!#./)/&#@&/;3
painter.drawLine(0, zoom * j, +!/;)%#="#;+"%#%"3"*%+#/*#-!"#,(%@"-A+#.;&&"*-#+-$-"7
zoom * image.width(), zoom * j);
} • !" Active#@&/;3#(+#;+"%#'/&#,(%@"-+#(*#-!"#.;&&"*-)9 $.-(4"#,(*%/,0
for (int i = 0; i < image.width(); ++i) { • !" Inactive#@&/;3#(+#;+"%#'/&#,(%@"-+#(*#-!"#/-!"&#,(*%/,+0
for (int j = 0; j < image.height(); ++j) { • !" Disabled#@&/;3#(+#;+"%#'/&#%(+$=)"%#,(%@"-+#(*#$*9#,(*%/,0
QRect rect = pixelRect(i, j);
if (!event->region().intersect(rect).isEmpty()) {
QColor color = QColor::fromRgba(image.pixel(i, j)); !" QWidget::palette()#';*.-(/*#&"-;&*+#-!"#,(%@"-A+#3$)"--"#$+#$ QPalette#/=T".-0#Q/)/&#@&/;3+#$&"
painter.fillRect(rect, color); +3".('("%#$+#"*;6+#/'#-93" QPalette::ColorGroup0
}
} 1!"*#,"#,$*-#-/#@"-#$*#$33&/3&($-"#=&;+!#/&#./)/&#'/&#%&$,(*@:#-!"#./&&".-#$33&/$.!#(+#-/#;+"#-!"
} .;&&"*-#3$)"--":#/=-$(*"%#'&/6 QWidget::palette():#$*%#-!"#&">;(&"%#&/)":#'/&#"2$63)":
} QPalette::foreground()0#Y$.!#&/)"#';*.-(/*#&"-;&*+#$#=&;+!:#,!(.!#(+#*/&6$))9#,!$-#,"#,$*-:#=;-#('
,"#T;+-#*""%#-!"#./)/&#,"#.$*#"2-&$.-#(-#'&/6#-!"#=&;+!:#$+#,"#%(%#(*#-!" paintEvent()0#L9#%"'$;)-:
-!"#=&;+!"+#&"-;&*"%#$&"#-!/+"#$33&/3&($-"#-/#-!"#,(%@"-A+#+-$-":#+/#,"#%/#*/-#*""%#-/#+3".('9#$
1"#+-$&-#=9#./*+-&;.-(*@#$ QPainter#/=T".-#/*#-!"#,(%@"-0#<'#-!"#D//6#'$.-/&#(+#[#/&#6/&":#,"#%&$, ./)/&#@&/;30
-!"#!/&(D/*-$)#$*%#4"&-(.$)#)(*"+#-!$-#'/&6#-!"#@&(%#;+(*@#-!" QPainter::drawLine()#';*.-(/*0
!" paintEvent()#';*.-(/*#'(*(+!"+#=9#%&$,(*@#-!"#(6$@"#(-+")'0# !"#.$))#-/ IconEditor::pixelRect()
&"-;&*+#$ QRect#-!$-#%"'(*"+#-!"#&"@(/*#-/#&"3$(*-0#?+#$*#"$+9#/3-(6(D$-(/*:#,"#%/*A-#&"%&$,#3(2")+
-!$-#'$))#/;-+(%"#-!(+#&"@(/*0 6/;+"#=;--/*:#,"#$)+/#.$)) setImagePixel():#=;-#3$++ false#-/#.)"$&#-!"#3(2")0

!"#$%&>('(&3$40!."&4&<!.%&#+!." QPainter
void IconEditor::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
setImagePixel(event->pos(), true);
} else if (event->buttons() & Qt::RightButton) {
setImagePixel(event->pos(), false);
}
}

!" mouseMoveEvent()#!$*%)"+#K6/;+"#6/4"K#"4"*-+0#L9#%"'$;)-:#-!"+"#"4"*-+#$&"#/*)9#@"*"&$-"%
,!"*#-!"#;+"&#(+#!/)%(*@#%/,*#$#=;--/*0#<-#(+#3/++(=)"#-/#.!$*@"#-!(+#="!$4(/&#=9#.$))(*@
QWidget::setMouseTracking():#=;-#,"#%/*A-#*""%#-/#%/#+/#'/&#-!(+#"2$63)"0

_;+-#$+#3&"++(*@#-!"#)"'-#/&#&(@!-#6/;+"#=;--/*#+"-+#/&#.)"$&+#$#3(2"):#5""3(*@#(-#3&"++"%#$*%#!/4"&(*@
/4"&#$#3(2")#(+#$)+/#"*/;@!#-/#+"-#/&#.)"$&#$#3(2")0#R(*."#(-A+#3/++(=)"#-/#!/)%#6/&"#-!$*#/*"#=;--/*
3&"++"%#%/,*#$-#$#-(6":#-!" 4$);"#&"-;&*"%#=9 QMouseEvent::buttons()#(+#$#=(-,(+"#Vf#/'#-!"#6/;+"
1"#.$)) QPainter::fillRect()#-/#%&$,#$#D//6"%#3(2")0 QPainter::fillRect()#-$5"+#$ QRect#$*%#$ =;--/*+0#1"#-"+-#,!"-!"&#$#."&-$(*#=;--/*#(+#3&"++"%#%/,*#;+(*@#-!" &#/3"&$-/&:#$*%#('#-!(+#(+#-!"
QBrush0#L9#3$++(*@#$ QColor#$+#-!"#=&;+!:#,"#/=-$(*#$#+/)(%#'())#3$--"&*0
.$+"#,"#.$)) setImagePixel()0

QRect IconEditor::pixelRect(int i, int j) const void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
{ {
if (zoom >= 3) { int i = pos.x() / zoom;
return QRect(zoom * i + 1, zoom * j + 1, zoom - 1, zoom - 1); int j = pos.y() / zoom;
} else { if (image.rect().contains(i, j)) {
return QRect(zoom * i, zoom * j, zoom, zoom); if (opaque) {
} image.setPixel(i, j, penColor().rgba());
} } else {
image.setPixel(i, j, qRgba(0, 0, 0, 0));
}
!" pixelRect()#';*.-(/*#&"-;&*+#$ QRect#+;(-$=)"#'/& QPainter::fillRect()0# !" i#$*% j#3$&$6"-"&+ update(pixelRect(i, j));
$&"#3(2")#.//&%(*$-"+#(*#-!" QImage*/-#(*#-!"#,(%@"-0#<'#-!"#D//6#'$.-/&#(+#O:#-!"#-,/#.//&%(*$-" }
+9+-"6+#./(*.(%"#"2$.-)90 }

!" QRect#./*+-&;.-/&#!$+#-!"#+9*-$2 QRect(x, y, width, height):#,!"&"#Fx: yJ#(+#-!"#3/+(-(/*#/'#-!"


-/3S)"'-#./&*"&#/'#-!"#&".-$*@)"#$*% width#2 height#(+#-!"#+(D"#/'#-!"#&".-$*@)"0#<'#-!"#D//6#'$.-/&#(+#[ !" setImagePixel()#';*.-(/*#(+#.$))"%#'&/6 mousePressEvent()#$*% mouseMove-Event()#-/#+"-#/&#.)"$&
/&#6/&":#,"#&"%;."#-!"#+(D"#/'#-!"#&".-$*@)"#=9#/*"#3(2")#!/&(D/*-$))9#$*%#4"&-(.$))9#+/#-!$-#-!"#'()) $#3(2")0# !" pos#3$&$6"-"&#(+#-!"#3/+(-(/*#/'#-!"#6/;+"#/*#-!"#,(%@"-0
%/"+#*/-#%&$,#/4"&#-!"#@&(%#)(*"+0
!"#'(&+-#+-"3#(+#-/#./*4"&-#-!"#6/;+"#3/+(-(/*#'&/6#,(%@"-#.//&%(*$-"+#-/#(6$@"#.//&%(*$-"+0# !(+#(+
%/*"#=9#%(4(%(*@#-!" x()#$*% y()#./63/*"*-+#/'#-!"#6/;+"#3/+(-(/*#=9#-!"#D//6#'$.-/&0#8"2-:#,"
void IconEditor::mousePressEvent(QMouseEvent *event) .!".5#,!"-!"&#-!"#3/(*-#(+#,(-!(*#-!"#./&&".-#&$*@"0# !"#.!".5#(+#"$+()9#6$%"#;+(*@ QImage::rect()
{ $*% QRect::contains()B#-!(+#"''".-(4")9#.!".5+#-!$- i#(+#="-,""*#E#$*% image.width() S#O#$*%#-!$- j
if (event->button() == Qt::LeftButton) { (+#="-,""*#E#$*% image.height() S#O0
setImagePixel(event->pos(), true);
} else if (event->button() == Qt::RightButton) {
setImagePixel(event->pos(), false); c"3"*%(*@#/*#-!" opaque#3$&$6"-"&:#,"#+"-#/&#.)"$&#-!"#3(2")#(*#-!"#(6$@"0#Q)"$&(*@#$#3(2")#(+#&"$))9
} +"--(*@#(-#-/#=" -&$*+3$&"*-0#1"#6;+-#./*4"&-#-!"#3"* QColor#-/#$*#[GS=(-#?fgL#4$);"#'/&#-!"
} QImage::setPixel()#.$))0#?-#-!"#"*%:#,"#.$)) update()#,(-!#$ QRect#/'#-!"#$&"$#-!$-#*""%+#-/#="
&"3$(*-"%0

1!"*#-!"#;+"&#3&"++"+#$#6/;+"#=;--/*:#-!"#+9+-"6#@"*"&$-"+#$#K6/;+"#3&"++K#"4"*-0#L9 8/,#-!$-#,"#!$4"#&"4(","%#-!"#6"6="&#';*.-(/*+:#,"#,())#&"-;&*#-/#-!" Qt:: WA_StaticContents


&"(63)"6"*-(*@ QWidget::mousePressEvent():#,"#.$*#&"+3/*%#-/#-!(+#"4"*-#$*%#+"-#/&#.)"$&#-!" $--&(=;-"#-!$-#,"#;+"%#(*#-!"#./*+-&;.-/&0# !(+#$--&(=;-"#-"))+#U-#-!$-#-!"#,(%@"-A+#./*-"*-#%/"+*A-
(6$@"#3(2")#;*%"&#-!"#6/;+"#.;&+/&0 .!$*@"#,!"*#-!"#,(%@"-#(+#&"+(D"%#$*%#-!$-#-!"#./*-"*-#+-$9+#&//-"%#-/#-!"#,(%@"-A+#-/3S)"'-#./&*"&0
U-#;+"+#-!(+#(*'/&6$-(/*#-/#$4/(% *""%)"++)9#&"3$(*-(*@#$&"$+#-!$-#$&"#$)&"$%9#+!/,*#,!"*#&"+(D(*@
-!"#,(%@"-0
<'#-!"#;+"&#3&"++"%#-!"#)"'-#6/;+"#=;--/*:#,"#.$))#-!"#3&(4$-"#';*.-(/* setImagePixel()#,(-! true#$+
-!"#+"./*%#$&@;6"*-:#-"))(*@#(-#-/#+"-#-!"#3(2")#-/#-!"#.;&&"*-#3"*#./)/&0#<'#-!"#;+"&#3&"++"%#-!"#&(@!-
8/&6$))9:#,!"*#$#,(%@"-#(+#&"+(D"%:#U-#@"*"&$-"+#$#3$(*-#"4"*-#'/&#-!"#,(%@"-A+#"*-(&"#4(+(=)"#$&"$0
L;-#('#-!"#,(%@"-#(+#.&"$-"%#,(-!#-!" Qt::WA_StaticContents#$--&(=;-":#-!"#3$(*-#"4"*-A+#&"@(/*#(+
&"+-&(.-"%#-/#-!"#3(2")+#-!$-#,"&"#*/-#3&"4(/;+)9#+!/,*0# !(+#(63)("+#-!$-#('#-!"#,(%@"-#(+#&"+(D"%#-/#$
+6$))"&#+(D":#*/#3$(*-#"4"*-#(+#@"*"&$-"%#$-#$))0

!"#$%&>(>(&L%+!M!."&4 Qt::WA_StaticContents !"#$%&

!"#&34$D4,@)#+2#(!"#.3+-+(%+*#4..3+4,!#43"#(!4(#.3+."3(%")#(!4(#43"#).",%2%,#(+#(!"#,7)(+-#$%&'"(
!" IconEditor#$%&'"(#%)#*+$#,+-./"("0#1)%*'#(!"#%*2+3-4(%+*#4*&#"54-./")#23+-#"43/%"3#,!4.("3)6
43"*K(#4,,"))%D/"#%* !"#$%&'($)#4*&#(!4(#(!"#$%&'"(#%)*K(#3"*&"3"&#4)#%()"/20#?+(!#(!")"#.3+D/"-)
$"#,+7/&#$3%("#,+&"#(!4(#7)")#(!" IconEditor#4)#4#$%*&+$#%*#%()#+$*#3%'!(6#4)#4#,"*(34/#$%&'"(#%*#4 ,4*#D"#)+/I"&#D8#7)%*'#(!"#./7'%*#4..3+4,!0
QMainWindow6#4)#4#,!%/&#$%&'"(#%*)%&"#4#/48+7(6#+3#4)#4#,!%/&#$%&'"(#%*)%&"#4 QScrollArea#9.0#:;<=0#>*
(!"#*"5(#)",(%+*6#$"#$%//#)""#!+$#(+#%*("'34("#%(#$%(! !"#$%&'($)0
!"#./7'%*#4..3+4,!#3"A7%3")#(!"#,3"4(%+*#+2#4#./7'%*#/%D3438#(!4( !"#$%&'($)#,4*#/+4&#4(#37*E(%-"
4*&#7)"#(+#,3"4("#%*)(4*,")#+2#(!"#$%&'"(0# !"#3"4/#$%&'"(#%)#(!"*#7)"&#D8 !"#$%&'($)#$!"*
"&%(%*'#(!"#2+3-#4*&#2+3#.3"I%"$%*'6#4*&#(!4*@)#(+#F(K)#-"(4E+DV",(#)8)("-6 !"#$%&'($)#,4*
&8*4-%,4//8#+D(4%*#(!"#/%)(#+2#%()#.3+."3(%")0# +#)!+$#!+$#(!%)#$+3@)6#$"#$%//#%*("'34("#(!"
IconEditor#23+-#(!"#.3"I%+7)#)",(%+*#4)#4#./7'%*0

Integrating Custom Widgets with Qt Designer Q%3)(6#$"#-7)(#)7D,/4)) QDesignerCustomWidgetInterface#4*&#3"%-./"-"*(#)+-"#I%3(74/#27*,(%+*)0


O"#$%//#4))7-"#(!4(#(!"#./7'%*#)+73,"#,+&"#%)#/+,4("&#%*#4#&%3",(+38#,4//"& iconeditorplugin#4*&#(!4(
?"2+3"#$"#,4*#7)"#,7)(+-#$%&'"()#%* !"#$%&'($)6#$"#-7)(#-4@" !"#$%&'($)#4$43"#+2#(!"-0 (!" IconEditor#)+73,"#,+&"#%)#/+,4("&#%*#4#.434//"/#&%3",(+38#,4//"& iconeditor0
!"3"#43"#($+#(",!*%A7")#2+3#&+%*'#(!%)B#(!"#C.3+-+(%+*C#4..3+4,!#4*&#(!"#./7'%*#4..3+4,!0
J"3"K)#(!"#,/4))#&"2%*%(%+*B
!"#.3+-+(%+*#4..3+4,!#%)#(!"#A7%,@")(#4*&#"4)%")(0#>(#,+*)%)()#+2#,!++)%*'#4#D7%/(E%*#F(#$%&'"(#(!4(
!4)#4#)%-%/43#GH>#(+#(!"#+*"#$"#$4*(#+73#,7)(+-#$%&'"(#(+#!4I"#4*&#,+-./"(%*'#4#&%4/+'#D+5#%* !
#$%&'($)#$%(!#)+-"#%*2+3-4(%+*#4D+7(#(!"#,7)(+-#$%&'"(0# !"#$%&'"(#,4*#(!"*#D"#7)"&#%*#2+3-) #include <QDesignerCustomWidgetInterface>
&"I"/+."&#$%(! !"#$%&'($)6#4/(!+7'!#%(#$%//#D"#3".3")"*("&#D8#(!"#4))+,%4("&#D7%/(E%*#F(#$%&'"( class IconEditorPlugin : public QObject,
$!%/"#(!"#2+3-#%)#"&%("&#+3#.3"I%"$"&0 public QDesignerCustomWidgetInterface
{
J"3"K)#!+$#(+#%*)"3(#4 HexSpinBox#$%&'"(#%*(+#4#2+3-#7)%*'#(!%)#4..3+4,!B Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
:0 L3"4("#4 QSpinBox#D8#&34''%*'#%(#23+- !"#$%&'($)K)#$%&'"(#D+5#+*(+#(!"#2+3-0
IconEditorPlugin(QObject *parent = 0);
M0 N%'!(E,/%,@#(!"#).%*#D+5#4*&#,!++)"#H3+-+("#(+#L7)(+-#O%&'"(#23+-#(!"#,+*("5(#-"*70 QString name() const;
P0 Q%//#%*#(!"#&%4/+'#(!4(#.+.)#7.#$%(!#CJ"5R.%*?+5C#4)#(!"#,/4))#*4-"#4*&#C!"5).%*D+50!C#4) QString includeFile() const;
(!"#!"4&"3#2%/"0 QString group() const;
QIcon icon() const;
S+%/TU# !"#,+&"#'"*"34("&#D8 uic#$%//#%*,/7&" hexspinbox.h#%*)("4&#+2 <QSpinBox>#4*&#%*)(4*(%4("#4 QString toolTip() const;
HexSpinBox0#>* !"#$%&'($)6#(!" HexSpinBox#$%&'"(#$%//#D"#3".3")"*("&#D8#4 QSpinBox6#4//+$%*'#7)#(+ QString whatsThis() const;
)"(#4//#(!"#.3+."3(%")#+2#4 QSpinBox#92+3#"54-./"6#(!"#34*'"#4*&#(!"#,733"*(#I4/7"=0 bool isContainer() const;
QWidget *createWidget(QWidget *parent);
};
'"$()% *+,+ !"#$%&'($)-. /(.&01 !"#$%& #"230$

!" IconEditorPlugin#)7D,/4))#%)#4#24,(+38#,/4))#(!4(#"*,4.)7/4(")#(!" IconEditor#$%&'"(0#>(#%*!"3%()


D+(! QObject#4*& QDesignerCustomWidgetIterface#4*&#7)")#(!" Q_INTERFACES()#-4,3+#(+#("// moc#(!4(
(!"#)",+*&#D4)"#,/4))#%)#4#./7'%*#%*("324,"0# !"#27*,(%+*)#43"#7)"&#D8 !"#$%&'($)#(+#,3"4("
%*)(4*,")#+2#(!"#,/4))#4*&#(+#+D(4%*#%*2+3-4(%+*#4D+7(#%(0

IconEditorPlugin::IconEditorPlugin(QObject *parent)
: QObject(parent)
{
}
!"#,+*)(37,(+3#%)#(3%I%4/0 !" whatsThis()#27*,(%+*#3"(73*)#(!"#CO!4(K)# !%)WC#("5(#2+3 !"#$%&'($)#(+#&%)./480

QString IconEditorPlugin::name() const bool IconEditorPlugin::isContainer() const


{ {
return "IconEditor"; return false;
} }

!" name()#27*,(%+*#3"(73*)#(!"#*4-"#+2#(!"#$%&'"(#.3+I%&"&#D8#(!"#./7'%*0 !" isContainer()#27*,(%+*#3"(73*) true#%2#(!"#$%&'"(#,4*#,+*(4%*#+(!"3#$%&'"()X#+(!"3$%)"6#%(


3"(73*) false0#Q+3#"54-./"6 QFrame#%)#4#$%&'"(#(!4(#,4*#,+*(4%*#+(!"3#$%&'"()0#>*#'"*"34/6#4*8#F(
$%&'"(#,4*#,+*(4%*#+(!"3#$%&'"()6#D7( !"#$%&'($)#&%)4//+$)#(!%)#$!"* isContainer()#3"(73*) false0
QString IconEditorPlugin::includeFile() const
{
return "iconeditor.h"; QWidget *IconEditorPlugin::createWidget(QWidget *parent)
} {
return new IconEditor(parent);
}
!" includeFile()#27*,(%+*#3"(73*)#(!"#*4-"#+2#(!"#!"4&"3#2%/"#2+3#(!"#).",%2%"&#$%&'"(#"*,4.)7/4("&
D8#(!"#./7'%*0# !"#!"4&"3#2%/"#%)#%*,/7&"&#%*#(!"#,+&"#'"*"34("&#D8#(!" uic#(++/0
!" create()#27*,(%+*#%)#,4//"&#D8 !"#$%&'($)#(+#,3"4("#4*#%*)(4*,"#+2#4#$%&'"(#,/4))#$%(!#(!"
'%I"*#.43"*(0
QString IconEditorPlugin::group() const
{
return tr("Image Manipulation Widgets"); Q_EXPORT_PLUGIN2(iconeditorplugin, IconEditorPlugin)
}

G(#(!"#"*&#+2#(!"#)+73,"#2%/"#(!4(#%-./"-"*()#(!"#./7'%*#,/4))6#$"#-7)(#7)"#(!" Q_EXPORT_PLUGIN2()
!" group()#27*,(%+*#3"(73*)#(!"#*4-"#+2#(!"#$%&'"(#D+5#'3+7.#(!%)#,7)(+-#$%&'"(#)!+7/&#D"/+*'#(+0 -4,3+#(+#-4@"#(!"#./7'%*#4I4%/4D/"#(+ !"#$%&'($)0# !"#2%3)(#43'7-"*(#%)#(!"#*4-"#$"#$4*(#(+#'%I"
>2#(!"#*4-"#%)*K(#4/3"4&8 %*#7)"6 !"#$%&'($)#$%//#,3"4("#4#*"$#'3+7.#2+3#(!"#$%&'"(0 (!"#./7'%*X#(!"#)",+*&#43'7-"*(#%)#(!"#*4-"#+2#(!"#,/4))#(!4(#%-./"-"*()#%(0

!" .pro#2%/"#2+3#D7%/&%*'#(!"#./7'%*#/++@)#/%@"#(!%)B
QIcon IconEditorPlugin::icon() const
{
return QIcon(":/images/iconeditor.png");
} TEMPLATE = lib
CONFIG += designer plugin release
HEADERS = ../iconeditor/iconeditor.h \
iconeditorplugin.h
!" icon()#27*,(%+*#3"(73*)#(!"#%,+*#(+#7)"#(+#3".3")"*(#(!"#,7)(+-#$%&'"(#%* !"#$%&'($)K)#$%&'"( SOURCES = ../iconeditor/iconeditor.cpp \
D+50#J"3"6#$"#4))7-"#(!4(#(!" IconEditorPlugin#!4)#4*#4))+,%4("&#F(#3")+73,"#2%/"#$%(!#4#)7%(4D/" iconeditorplugin.cpp
"*(38#2+3#(!"#%,+*#"&%(+3#%-4'"0 RESOURCES = iconeditorplugin.qrc
DESTDIR = $(QTDIR)/plugins/designer

QString IconEditorPlugin::toolTip() const


{ !" .pro#2%/"#4))7-")#(!4(#(!" QtdIR#"*I%3+*-"*(#I43%4D/"#%)#)"(#(+#(!"#&%3",(+38#$!"3"#F(#%)
return tr("An icon editor widget"); %*)(4//"&0#O!"*#8+7#(8." make#+3 nmake#(+#D7%/&#(!"#./7'%*6#%(#$%//#47(+-4(%,4//8#%*)(4//#%()"/2#%* !
}
#$%&'($)K) plugins#&%3",(+380#Y*,"#(!"#./7'%*#%)#D7%/(6#(!" IconEditor#$%&'"(#,4*#D"#7)"&#%* !
#$%&'($)#%*#(!"#)4-"#$48#4)#4*8#+2#F(K)#D7%/(E%*#$%&'"()0

!" toolTip()#27*,(%+*#3"(73*)#(!"#(++/(%.#(+#)!+$#$!"*#(!"#-+7)"#!+I"3)#+I"3#(!"#,7)(+-#$%&'"( >2#8+7#$4*(#(+#%*("'34("#)"I"34/#,7)(+-#$%&'"()#$%(! !"#$%&'($)6#8+7#,4*#"%(!"3#,3"4("#+*"#./7'%*


%* !"#$%&'($)K)#$%&'"(#D+50 2+3#"4,!#+*"#+2#(!"-#+3#,+-D%*"#(!"-#%*(+#4#)%*'/"#./7'%*#D8#&"3%I%*'#23+-
QDesignerCustomWidgetCollectionInterface0

QString IconEditorPlugin::whatsThis() const


{
return tr("This widget is presented in Chapter 5 of <i>C++ GUI "
"Programming with Qt 4</i> as an example of a custom Qt "
"widget.");
}
class Plotter : public QWidget
{
Q_OBJECT
public:
Double Buffering Plotter(QWidget *parent = 0);
void setPlotSettings(const PlotSettings &settings);
void setCurveData(int id, const QVector<QPointF> &data);
Z+7D/"#D722"3%*'#%)#4#[1>#.3+'34--%*'#(",!*%A7"#(!4(#,+*)%)()#+2#3"*&"3%*'#4#$%&'"(#(+#4*#+22E void clearCurve(int id);
),3""*#.%5-4.#4*&#,+.8%*'#(!"#.%5-4.#+*(+#(!"#&%)./480#O%(!#"43/%"3#I"3)%+*)#+2#F(6#(!%)#(",!*%A7" QSize minimumSizeHint() const;
$4)#23"A7"*(/8#7)"&#(+#"/%-%*4("#2/%,@"3#4*&#(+#.3+I%&"#4#)*4..%"3#7)"3#%*("324,"0 QSize sizeHint() const;
public slots:
>*#F(#;6 QWidget#!4*&/")#(!%)#47(+-4(%,4//86#)+#$"#343"/8#*""&#(+#$+338#4D+7(#$%&'"()#2/%,@"3%*'0 void zoomIn();
void zoomOut();
R(%//6#"5./%,%(#&+7D/"#D722"3%*'#3"-4%*)#D"*"2%,%4/#%2#(!"#$%&'"(K)#3"*&"3%*'#%)#,+-./"5#4*&#*""&"&
3"."4("&/80#O"#,4*#(!"*#)(+3"#4#.%5-4.#."3-4*"*(/8#$%(!#(!"#$%&'"(6#4/$48)#3"4&8#2+3#(!"#*"5(
.4%*(#"I"*(6#4*&#,+.8#(!"#.%5-4.#(+#(!"#$%&'"(#$!"*"I"3#$"#3","%I"#4#.4%*(#"I"*(0#>(#%)#").",%4//8
!"/.27/#$!"*#$"#$4*(#(+#&+#)-4//#-+&%2%,4(%+*)6#)7,!#4)#&34$%*'#4#37DD"3#D4*&6#$%(!+7( O"#)(43(#D8#%*,/7&%*'#(!"#!"4&"3#2%/")#2+3#(!"#F(#,/4))")#(!4(#43"#7)"&#%*#(!"#./+(("3#2%/"K)#!"4&"36#4*&
3",+-.7(%*'#(!"#$!+/"#$%&'"(K)#3"*&"3%*'#+I"3#4*&#+I"30 2+3$43&#&",/43%*'#(!"#,/4))")#(!4(#!4I"#.+%*("3)#+3#3"2"3"*,")#%*#(!"#!"4&"30

O"#$%//#3+7*&#+22#(!%)#,!4.("3#D8#3"I%"$%*'#(!" Plotter#,7)(+-#$%&'"(0# !%)#$%&'"(#7)")#&+7D/" >*#(!" Plotter#,/4))6#$"#.3+I%&"#(!3""#.7D/%,#27*,(%+*)#2+3#)"((%*'#7.#(!"#./+(6#4*&#($+#.7D/%,#)/+()


D722"3%*'#4*&#4/)+#&"-+*)(34(")#)+-"#+(!"3#4).",()#+2#F(#.3+'34--%*'6#%*,/7&%*'#@"8D+43&#"I"*( 2+3#\++-%*'#%*#4*&#+7(0#O"#4/)+#3"%-./"-"*( minimum-SizeHint()#4*& sizeHint()#23+- QWidget0#O"
!4*&/%*'6#-4*74/#/48+7(6#4*&#,++3&%*4("#)8)("-)0 )(+3"#4#,73I"K)#.+%*()#4)#4 QVector<QPointF>6#$!"3" QPointF#%)#4#2/+4(%*'E.+%*(#I"3)%+*#+2 QPoint0

!" Plotter#$%&'"(#&%)./48)#+*"#+3#-+3"#,73I")#).",%2%"&#4)#I",(+3)#+2#,++3&%*4(")0# !"#7)"3#,4*


&34$#4#37DD"3#D4*&#+*#(!"#%-4'"6#4*&#(!" Plotter#$%//#\++-#%*#+*#(!"#43"4#"*,/+)"&#D8#(!"#37DD"3 protected:
D4*&0# !"#7)"3#&34$)#(!"#37DD"3#D4*&#D8#,/%,@%*'#4#.+%*(#+*#(!"#'34.!6#&34''%*'#(!"#-+7)"#(+ void paintEvent(QPaintEvent *event);
4*+(!"3#.+)%(%+*#$%(!#(!"#/"2(#-+7)"#D7((+*#!"/&#&+$*6#4*&#3"/"4)%*'#(!"#-+7)"#D7((+*0 void resizeEvent(QResizeEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
'"$()% *+4+ 5001"6$ "6 06 &7% Plotter !"#$%& void mouseReleaseEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
[View full size image] void wheelEvent(QWheelEvent *event);

>*#(!"#.3+(",("&#)",(%+*#+2#(!"#,/4))6#$"#&",/43"#4//#(!" QWidget#"I"*(#!4*&/"3)#(!4(#$"#$4*(#(+
3"%-./"-"*(0

private:
void updateRubberBandRegion();
void refreshPixmap();
void drawGrid(QPainter *painter);
void drawCurves(QPainter *painter);
enum { Margin = 50 };
QToolButton *zoomInButton;
!"#7)"3#,4*#\++-#%*#3"."4("&/8#D8#&34$%*'#4#37DD"3#D4*&#-7/(%./"#(%-")6#\++-%*'#+7(#7)%*'#(!" QToolButton *zoomOutButton;
]++-#Y7(#D7((+*6#4*&#(!"*#\++-%*'#D4,@#%*#7)%*'#(!"#]++-#>*#D7((+*0# !"#]++-#>*#4*&#]++-#Y7( QMap<int, QVector<QPointF> > curveMap;
D7((+*)#4.."43#(!"#2%3)(#(%-"#(!"8#D",+-"#4I4%/4D/"6#)+#(!4(#(!"8#&+*K(#,/7(("3#(!"#&%)./48#%2#(!"#7)"3 QVector<PlotSettings> zoomStack;
&+")*K(#\++-#(!"#'34.!0 int curZoom;
bool rubberBandIsShown;
!" Plotter#$%&'"(#,4*#!+/&#(!"#&4(4#2+3#4*8#*7-D"3#+2#,73I")0#>(#4/)+#-4%*(4%*)#4#)(4,@#+2 QRect rubberBandRect;
QPixmap pixmap;
PlotSettings#+DV",()6#"4,!#+2#$!%,!#,+33").+*&)#(+#4#.43(%,7/43#\++-#/"I"/0
};

^"(K)#3"I%"$#(!"#,/4))6#)(43(%*'#$%(! plotter.hB
>*#(!"#.3%I4("#)",(%+*#+2#(!"#,/4))6#$"#&",/43"#4#2"$#27*,(%+*)#2+3#.4%*(%*'#(!"#$%&'"(6#4#,+*)(4*(6
4*&#)"I"34/#-"-D"3#I43%4D/")0# !" Margin#,+*)(4*(#%)#7)"&#(+#.3+I%&"#)+-"#).4,%*'#43+7*&#(!"
#ifndef PLOTTER_H
#define PLOTTER_H '34.!0
#include <QMap>
#include <QPixmap> G-+*'#(!"#-"-D"3#I43%4D/")#%) pixmap#+2#(8." QPixmap0# !%)#I43%4D/"#!+/&)#4#,+.8#+2#(!"#$!+/"
#include <QVector> $%&'"(K)#3"*&"3%*'6#%&"*(%,4/#(+#$!4(#%)#)!+$*#+*#),3""*0# !"#./+(#%)#4/$48)#&34$*#+*(+#(!%)#+22E
#include <QWidget> ),3""*#.%5-4.#2%3)(X#(!"*#(!"#.%5-4.#%)#,+.%"&#+*(+#(!"#$%&'"(0
class QToolButton;
class PlotSettings;
(!"-#$%(! std::#92+3#"54-./"6 floor()#%*)("4&#+2 std::floor()=0
class PlotSettings
{
public: Plotter::Plotter(QWidget *parent)
PlotSettings(); : QWidget(parent)
{
void scroll(int dx, int dy); setBackgroundRole(QPalette::Dark);
void adjust(); setAutoFillBackground(true);
double spanX() const { return maxX - minX; } setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
double spanY() const { return maxY - minY; } setFocusPolicy(Qt::StrongFocus);
rubberBandIsShown = false;
double minX;
double maxX; zoomInButton = new QToolButton(this);
int numXTicks; zoomInButton->setIcon(QIcon(":/images/zoomin.png"));
double minY; zoomInButton->adjustSize();
double maxY; connect(zoomInButton, SIGNAL(clicked()), this, SLOT(zoomIn()));
int numYTicks;
zoomOutButton = new QToolButton(this);
private: zoomOutButton->setIcon(QIcon(":/images/zoomout.png"));
static void adjustAxis(double &min, double &max, int &numTicks); zoomOutButton->adjustSize();
}; connect(zoomOutButton, SIGNAL(clicked()), this, SLOT(zoomOut()));
#endif
setPlotSettings(PlotSettings());
}
!" PlotSettings#,/4))#).",%2%")#(!"#34*'"#+2#(!" *#4*& +#45")#4*&#(!"#*7-D"3#+2#(%,@)#2+3#(!")"
45")0 Q%'73"#_0<#)!+$)#(!"#,+33").+*&"*,"#D"($""*#4 PlotSettings#+DV",(#4*&#4 Plotter#$%&'"(0
!" setBackgroundRole()#,4//#("//) QWidget#(+#7)"#(!"#C&43@C#,+-.+*"*(#+2#(!"#.4/"(("#4)#(!"#,+/+3#2+3
'"$()% *+8+ PlotSettings-. 1%19%) :2)"293%. "34)%*'#(!"#$%&'"(6#%*)("4&#+2#(!"#C$%*&+$C#,+-.+*"*(0# !%)#'%I")#F(#4#&"247/(#,+/+3#(!4(#%(#,4*#7)"
(+#2%//#4*8#*"$/8#3"I"4/"&#.%5"/)#$!"*#(!"#$%&'"(#%)#3")%\"&#(+#4#/43'"3#)%\"6#D"2+3" paintEvent()#"I"*
!4)#(!"#,!4*,"#(+#.4%*(#(!"#*"$#.%5"/)0#O"#4/)+#*""&#(+#,4// setAutoFillBackground(true)#(+#"*4D/"
(!%)#-",!4*%)-0#9?8#&"247/(6#,!%/&#$%&'"()#%*!"3%(#(!"#D4,@'3+7*&#23+-#(!"%3#.43"*(#$%&'"(0=

!" setSizePolicy()#,4//#)"()#(!"#$%&'"(K)#)%\"#.+/%,8#(+ QSizePolicy::Expanding#%*#D+(!#&%3",(%+*)0


!%)#("//)#4*8#/48+7(#-4*4'"3#(!4(#%)#3").+*)%D/"#2+3#(!"#$%&'"(#(!4(#(!"#$%&'"(#%)#").",%4//8#$%//%*'
(+#'3+$6#D7(#,4*#4/)+#)!3%*@0# !%)#)"((%*'#%)#(8.%,4/#2+3#$%&'"()#(!4(#,4*#(4@"#7.#4#/+(#+2#),3""*
).4,"0# !"#&"247/(#%) QSizePolicy::Preferred#%*#D+(!#&%3",(%+*)6#$!%,!#-"4*)#(!4(#(!"#$%&'"(#.3"2"3)
(+#D"#(!"#)%\"#+2#%()#)%\"#!%*(6#D7(#%(#,4*#D"#)!37*@#&+$*#(+#%()#-%*%-7-#)%\"#!%*(#+3#"5.4*&"&
%*&"2%*%("/8#%2#*","))4380

!" setFocusPolicy(Qt::StrongFocus)#,4//#-4@")#(!"#$%&'"(#4,,".(#2+,7)#D8#,/%,@%*'#+3#D8#.3"))%*'
4D0#O!"*#(!" Plotter#!4)#2+,7)6#%(#$%//#3","%I"#"I"*()#2+3#@"8#.3"))")0# !" Plotter#$%&'"(
7*&"3)(4*&)#4#2"$#@"8)B#b#(+#\++-#%*X E#(+#\++-#+7(X#4*&#(!"#433+$#@"8)#(+#),3+//#7.6#&+$*6#/"2(6
4*&#3%'!(0

'"$()% *+;+ </)033"6$ &7% Plotter !"#$%&


[View full size image]

?8#,+*I"*(%+*6 numXTicks#4*& numYTicks#43"#+22#D8#+*"X#%2 numXTicks#%)#_6 Plotter#$%//#4,(74//8#&34$#`


(%,@#-43@)#+*#(!" *#45%)0# !%)#)%-./%2%")#(!"#,4/,7/4(%+*)#/4("3#+*0

a+$#/"(K)#3"I%"$#(!"#%-./"-"*(4(%+*#2%/"B

#include <QtGui>
#include <cmath>

#include "plotter.h"

O"#%*,/7&"#(!"#"5.",("&#!"4&"3#2%/")#4*&#%-.+3(#4//#(!" std#*4-").4,"K)#)8-D+/)#%*(+#(!"#'/+D4/
R(%//#%*#(!"#,+*)(37,(+36#$"#,3"4("#($+ QToolButton)6#"4,!#$%(!#4*#%,+*0# !")"#D7((+*)#4//+$#(!"#7)"3
*4-").4,"0# !%)#4//+$)#7)#(+#4,,"))#(!"#27*,(%+*)#(!4(#43"#&",/43"&#%* <cmath>#$%(!+7(#.3"2%5%*'
(+#\++-#%*#4*&#+7(0# !"#D7((+*K)#%,+*)#43"#)(+3"&#%*#4#3")+73,"#2%/"6#)+#4*8#4../%,4(%+*#(!4(#7)")#(!"
Plotter#$%&'"(#$%//#*""&#(!%)#"*(38#%*#%() .pro#2%/"B zoomInButton->show();
refreshPixmap();
}
RESOURCES = plotter.qrc }

!"#3")+73,"#2%/"#%)#)%-%/43#(+#(!"#+*"#$"#!4I"#7)"&#2+3#(!"#R.3"4&)!""(#4../%,4(%+*B !" zoomOut()#)/+(#\++-)#+7(#%2#(!"#'34.!#%)#\++-"&#%*0#>(#&",3"-"*()#(!"#,733"*(#\++-#/"I"/#4*&


"*4D/")#(!"#]++-#Y7(#D7((+*#&"."*&%*'#+*#$!"(!"3#(!"#'34.!#,4*#D"#\++-"&#+7(#4*8#-+3"#+3#*+(0
!"#]++-#>*#D7((+*#%)#"*4D/"&#4*&#)!+$*6#4*&#(!"#&%)./48#%)#7.&4("&#$%(!#4#,4//#(+ refreshPixmap()0
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/zoomin.png</file> void Plotter::zoomIn()
<file>images/zoomout.png</file> {
</qresource> if (curZoom < zoomStack.count() - 1) {
</RCC> ++curZoom;
zoomInButton->setEnabled(curZoom < zoomStack.count() - 1);
zoomOutButton->setEnabled(true);
zoomOutButton->show();
!" adjustSize()#,4//)#+*#(!"#D7((+*)#)"(#(!"%3#)%\")#(+#D"#(!4(#+2#(!"%3#)%\"#!%*()0# !"#D7((+*)#43" refreshPixmap();
*+(#.7(#%*#4#/48+7(X#%*)("4&6#$"#$%//#.+)%(%+*#(!"-#-4*74//8#%*#(!" PlotterK)#3")%\"#"I"*(0#R%*,"#$" }
43"#*+(#7)%*'#4*8#/48+7()6#$"#-7)(#).",%28#(!"#D7((+*)K#.43"*(#"5./%,%(/8#D8#.4))%*' this#(+#(!" }
QPushButton#,+*)(37,(+30

!"#,4//#(+ setPlotSettings()#4(#(!"#"*&#,+-./"(")#(!"#%*%(%4/%\4(%+*0 >2#(!"#7)"3#!4)#.3"I%+7)/8#\++-"&#%*#4*&#(!"*#+7(#4'4%*6#(!" PlotSettings#2+3#(!"#*"5(#\++-#/"I"/


$%//#D"#%*#(!"#\++-#)(4,@6#4*&#$"#,4*#\++-#%*0#9Y(!"3$%)"6#%(#%)#)(%//#.+))%D/"#(+#\++-#%*#7)%*'#4
37DD"3#D4*&0=
void Plotter::setPlotSettings(const PlotSettings &settings)
{
!"#)/+(#%*,3"-"*() curZoom#(+#-+I"#+*"#/"I"/#&""."3#%*(+#(!"#\++-#)(4,@6#)"()#(!"#]++-#>*#D7((+*
zoomStack.clear();
"*4D/"&#+3#&%)4D/"&#&"."*&%*'#+*#$!"(!"3#%(K)#.+))%D/"#(+#\++-#%*#4*8#273(!"36#4*&#"*4D/")#4*&
zoomStack.append(settings);
curZoom = 0; )!+$)#(!"#]++-#Y7(#D7((+*0#G'4%*6#$"#,4// refreshPixmap()#(+#-4@"#(!"#./+(("3#7)"#(!"#/4(")(#\++-
zoomInButton->hide(); )"((%*')0
zoomOutButton->hide();
refreshPixmap();
} void Plotter::setCurveData(int id, const QVector<QPointF> &data)
{
curveMap[id] = data;
refreshPixmap();
!" setPlotSettings() 27*,(%+*#%)#7)"&#(+#).",%28#(!" PlotSettings#(+#7)"#2+3#&%)./48%*'#(!"#./+(0#>( }
%)#,4//"&#D8#(!" Plotter#,+*)(37,(+3#4*&#,4*#D"#,4//"&#D8#7)"3)#+2#(!"#,/4))0# !"#./+(("3#)(43()#+7(#4(
%()#&"247/(#\++-#/"I"/0#c4,!#(%-"#(!"#7)"3#\++-)#%*6#4#*"$ PlotSettings %*)(4*,"#%)#,3"4("&#4*&#.7(
+*(+#(!"#\++-#)(4,@0 !"#\++-#)(4,@#%)#3".3")"*("&#D8#($+#-"-D"3#I43%4D/")B
!" setCurveData()#27*,(%+*#)"()#(!"#,73I"#&4(4#2+3#4#'%I"*#,73I"#>Z0#>2#4#,73I"#$%(!#(!"#)4-"#>Z
4/3"4&8#"5%)()#%* curveMap6#%(#%)#3"./4,"&#$%(!#(!"#*"$#,73I"#&4(4X#+(!"3$%)"6#(!"#*"$#,73I"#%)#)%-./8
• zoomStack#!+/&)#(!"#&%22"3"*(#\++-#)"((%*')#4)#4 QVector<PlotSettings>0
%*)"3("&0# !" curveMap#-"-D"3#I43%4D/"#%)#+2#(8." QMap<int, QVector<QPointF> >0
• curZoom#!+/&)#(!"#,733"*( PlotSettingsK)#%*&"5#%*#(!" zoomStack0

G2("3#(!"#,4// (+ setPlotSettings()6#(!"#\++-#)(4,@#,+*(4%*)#+*/8#+*"#"*(386#4*&#(!"#]++-#>*#4*& void Plotter::clearCurve(int id)


]++-#Y7(#D7((+*)#43"#!%&&"*0# !")"#D7((+*)#$%//#*+(#D"#)!+$*#7*(%/#$"#,4// show()#+*#(!"-#%*#(!" {
zoomIn()#4*& zoomOut()#)/+()0#9a+3-4//86#%(#%)#)722%,%"*(#(+#,4// show()#+*#(!"#(+.E/"I"/#$%&'"(#(+#)!+$ curveMap.remove(id);
4//#(!"#,!%/&3"*0#?7(#$!"*#$"#"5./%,%(/8#,4// hide()#+*#4#,!%/&#$%&'"(6#%(#%)#!%&&"*#7*(%/#$"#,4// show() refreshPixmap();
+*#%(0= }

!"#,4//#(+ refreshPixmap()#%)#*","))438#(+#7.&4("#(!"#&%)./480#1)74//86#$"#$+7/&#,4// update()6#D7(


!"3"#$"#&+#(!%*')#)/%'!(/8#&%22"3"*(/8#D",47)"#$"#$4*(#(+#@"".#4 QPixmap#7.#(+#&4("#4(#4//#(%-")0 !" clearCurve()#27*,(%+*#3"-+I")#(!"#).",%2%"&#,73I"#23+-#(!"#,73I"#-4.0
G2("3#3"'"*"34(%*'#(!"#.%5-4.6 refreshPixmap()#,4//) update()#(+#,+.8#(!"#.%5-4.#+*(+#(!"#$%&'"(0

QSize Plotter::minimumSizeHint() const


void Plotter::zoomOut() {
{ return QSize(6 * Margin, 4 * Margin);
if (curZoom > 0) { }
--curZoom;
zoomOutButton->setEnabled(curZoom > 0);
zoomInButton->setEnabled(true);
this);
!" minimumSizeHint()#27*,(%+*#%)#)%-%/43#(+ sizeHint()X#V7)(#4) sizeHint()#).",E%2%")#4#$%&'"(K)#%&"4/
)%\"6 minimumSizeHint()#).",%2%")#4#$%&'"(K)#%&"4/#-%*%-7-#)%\"0#G#/48+7(#*"I"3#3")%\") 4#$%&'"(
D"/+$#%()#-%*%-7-#)%\"#!%*(0 +3#$"#,4*#7)"#4 QStylePainter#%*)("4&#+2#4#*+3-4/ QPainter6#4)#$"#!4I"#&+*"#%* Plotter6#4*&#.4%*(
-+3"#,+*I"*%"*(/8#7)%*'#(!4(0
!"#I4/7"#$"#3"(73*#%)#Pdd#5#Mdd#9)%*," Margin#"A74/)#_d=#(+#4//+$#2+3#(!"#-43'%*#+*#4//#2+73#)%&")
4*&#)+-"#).4,"#2+3#(!"#./+(#%()"/20#?"/+$#(!4(#)%\"6#(!"#./+(#$+7/&#D"#(++#)-4//#(+#D"#7)"27/0 !" QWidget::style()#27*,(%+*#3"(73*)#(!"#)(8/"#(!4(#)!+7/&#D"#7)"&#(+#&34$#(!"#$%&'"(0#>*#F(6#4
$%&'"(#)(8/"#%)#4#)7D,/4))#+2 QStyle0# !"#D7%/(E%*#)(8/")#%*,/7&" QWindowsStyle6 QWindowsXPStyle6
QMotifStyle6 QCDEStyle6 QMacStyle6#4*& QPlastiqueStyle0#c4,!#+2#(!")"#)(8/")#3"%-./"-"*()#(!"
QSize Plotter::sizeHint() const I%3(74/#27*,(%+*)#%* QStyle#(+#."32+3-#(!"#&34$%*'#%*#(!"#,+33",(#$48#2+3#(!"#./4(2+3-#(!"#)(8/"#%)
{ "-7/4(%*'0 QStylePainterK) drawPrimitive()#27*,(%+*#,4//)#(!" QStyle#27*,(%+*#+2#(!"#)4-"#*4-"6
return QSize(12 * Margin, 8 * Margin); $!%,!#,4*#D"#7)"&#2+3#&34$%*'#C.3%-%(%I"#"/"-"*()C#/%@"#.4*"/)6#D7((+*)6#4*&#2+,7)#3",(4*'/")0# !"
}
$%&'"(#)(8/"#%)#7)74//8#(!"#)4-"#2+3#4//#$%&'"()#%*#4*#4../%,4(%+*#9 QApplication::style()=6#D7(#%(#,4*
D"#+I"33%&&"*#+*#4#."3E$%&'"(#D4)%)#7)%*' QWidget::setStyle()0

>* sizeHint()6#$"#3"(73*#4*#C%&"4/C#)%\"#%*#.3+.+3(%+*#(+#(!" Margin#,+*)(4*(#4*&#$%(!#(!"#)4-" ?8#)7D,/4))%*' QStyle6#%(#%)#.+))%D/"#(+#&"2%*"#4#,7)(+-#)(8/"0# !%)#,4*#D"#&+*"#(+#'%I"#4#&%)(%*,(%I"


./"4)%*'#PBM#4).",(#34(%+#$"#7)"&#2+3#(!" minimumSizeHint()0 /++@#(+#4*#4../%,4(%+*#+3#4#)7%("#+2#4../%,4(%+*)0#O!%/"#%(#%)#'"*"34//8#4&I%)4D/"#(+#7)"#(!"#(43'"(
./4(2+3-K)#*4(%I"#/++@#4*&#2""/6#F(#+22"3)#4#/+(#+2#2/"5%D%/%(8#%2#8+7#$4*(#(+#D"#4&I"*(73+7)0
!%)#2%*%)!")#(!"#3"I%"$#+2#(!" PlotterK)#.7D/%,#27*,(%+*)#4*&#)/+()0#a+$#/"(K)#3"I%"$#(!"#.3+(",("&
"I"*(#!4*&/"3)0 F(K)#D7%/(E%*#$%&'"()#3"/8#4/-+)(#"5,/7)%I"/8#+* QStyle#(+#.4%*(#(!"-)"/I")0# !%)#%)#$!8#(!"8#/++@#/%@"
*4(%I"#$%&'"()#+*#4//#./4(2+3-)#)7..+3("&#D8#F(0#L7)(+-#$%&'"()#,4*#D"#-4&"#)(8/"E4$43"#"%(!"3#D8
7)%*' QStyle#(+#.4%*(#(!"-)"/I")#+3#D8#7)%*'#D7%/(E%*#F(#$%&'"()#4)#,!%/&#$%&'"()0#Q+3 Plotter6#$"
void Plotter::paintEvent(QPaintEvent * /* event */)
7)"#4#,+-D%*4(%+*#+2#D+(!#4..3+4,!")B# !"#2+,7)#3",(4*'/"#%)#&34$*#7)%*' QStyle#9I%4#4
{
QStylePainter=6#4*&#(!"#]++-#>*#4*&#]++-#Y7(#D7((+*) 43"#D7%/(E%*#F(#$%&'"()0
QStylePainter painter(this);
painter.drawPixmap(0, 0, pixmap);
if (rubberBandIsShown) {
painter.setPen(palette().light().color()); void Plotter::resizeEvent(QResizeEvent * /* event */)
painter.drawRect(rubberBandRect.normalized() {
.adjusted(0, 0, -1, -1)); int x = width() - (zoomInButton->width()
} + zoomOutButton->width() + 10);
if (hasFocus()) { zoomInButton->move(x, 5);
QStyleOptionFocusRect option; zoomOutButton->move(x + zoomInButton->width() + 5, 5);
option.initFrom(this); refreshPixmap();
option.backgroundColor = palette().dark().color(); }
painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
}
} O!"*"I"3#(!" Plotter#$%&'"(#%)#3")%\"&6#F(#'"*"34(")#4#C3")%\"C#"I"*(0#J"3"6#$"#3"%-./"-"*(
resizeEvent()#(+#./4,"#(!"#]++-#>*#4*&#]++-#Y7(#D7((+*)#4(#(!"#(+.#3%'!(#+2#(!" Plotter#$%&'"(0

a+3-4//86 paintEvent()#%)#(!"#./4,"#$!"3"#$"#."32+3-#4//#(!"#&34$%*'0#?7(#!"3"#4//#(!"#./+(#&34$%*' O"#-+I"#(!"#]++-#>*#D7((+*#4*&#(!"#]++-#Y7(#D7((+*#(+#D"#)%&"#D8#)%&"6#)".434("&#D8#4#_E.%5"/


%)#&+*"#D"2+3"!4*&#%* refreshPixmap()6#)+#$"#,4*#3"*&"3#(!"#"*(%3"#./+(#)%-./8#D8#,+.8%*'#(!" '4.#4*&#$%(!#4#_E.%5"/#+22)"(#23+-#(!"#(+.#4*&#3%'!(#"&'")#+2#(!"#.43"*(#$%&'"(0
.%5-4.#+*(+#(!"#$%&'"(#4(#.+)%(%+*#9d6#d=0
>2#$"#$4*("&#(!"#D7((+*)#(+#)(48#3++("&#(+#(!"#(+.E/"2(#,+3*"36#$!+)"#,++3&%*4(")#43"#9d6#d=6#$"
>2#(!"#37DD"3#D4*&#%)#I%)%D/"6#$"#&34$#%(#+*#(+.#+2#(!"#./+(0#O"#7)"#(!"#C/%'!(C#,+-.+*"*(#23+-#(!" $+7/&#)%-./8 !4I"#-+I"&#(!"-#(!"3"#%*#(!" Plotter#,+*)(37,(+30#?7(#$"#$4*(#(+#(34,@#(!"#(+.E3%'!(
$%&'"(K)#,733"*(#,+/+3#'3+7.#4)#(!"#."*#,+/+3#(+#"*)73" '++&#,+*(34)(#$%(!#(!"#C&43@C#D4,@'3+7*&0 ,+3*"36#$!+)"#,++3&%*4(")#&"."*&#+*#(!"#)%\"#+2#(!"#$%&'"(0#?",47)"#+2#(!%)6#%(K)#*","))438#(+
a+(%,"#(!4(#$"#&34$#&%3",(/8#+*#(!"#$%&'"(6#/"4I%*'#(!"#+22E),3""*#.%5-4.#7*(+7,!"&0#1)%*' 3"%-./"-"*( resizeEvent()#4*&#(+#)"(#(!"#D7((+*)K#.+)%(%+*#(!"3"0
QRect::normalized()#"*)73")#(!4(#(!"#37DD"3#D4*&#3",(4*'/"#!4)#.+)%(%I"#$%&(!#4*&#!"%'!(#9)$4.E
.%*'#,++3&%*4(")#%2#*","))438=6#4*& adjusted()#3"&7,")#(!"#)%\"#+2#(!"#3",(4*'/"#D8#+*"#.%5"/#(+#4//+$ O"#&%&*K( )"(#4*8#.+)%(%+*)#2+3#(!"#D7((+*)#%*#(!" Plotter#,+*)(37,(+30# !%)#%)*K(#4#.3+D/"-6#)%*,"#F(
2+3#%()#+$*#:E.%5"/E$%&"#+7(/%*"0 4/$48)#'"*"34(")#4#3")%\"#"I"*(#D"2+3"#4#$%&'"(#%)#)!+$*#2+3#(!"#2%3)(#(%-"0

>2#(!" Plotter#!4)#2+,7)6#4#2+,7)#3",(4*'/"#%)#&34$*#7)%*'#(!"#$%&'"(#)(8/"K) draw-Primitive() G*#4/("3*4(%I"#(+#3"%-./"-"*(%*' resizeEvent()#4*&#/48%*'#+7(#(!"#,!%/&#$%&'"()#-4*74//8#$+7/&


27*,(%+*#$%(! QStyle::PE_FrameFocusRect#4)#%()#2%3)(#43'7-"*(#4*&#4 QStyleOptionFocusRect#+DV",(#4) !4I"#D""*#(+#7)"#4#/48+7(#-4*4'"3#92+3#"54-./"6 QGridLayout=0#1)%*'#4#/48+7(#$+7/&#!4I"#D""*#4
%()#)",+*&#43'7-"*(0# !"#2+,7)#3",(4*'/"K)#&34$%*'#+.(%+*)#43"#%*!"3%("&#23+-#(!" Plotter#$%&'"( /%((/"#-+3"#,+-./%,4("&#4*&#$+7/&#!4I"#,+*)7-"&#-+3"#3")+73,")X#+*#(!"#+(!"3#!4*&6#%(#$+7/&
9D8#(!" initFrom()#,4//=0# !"#D4,@'3+7*&#,+/+3#-7)(#D"#).",%2%"&#"5./%,%(/80 '34,"27//8#!4*&/"#3%'!(E(+E/"2(#/48+7()6#*","))438#2+3#/4*'74'")#)7,!#4)#G34D%,#4*&#J"D3"$0

O!"*#$"#$4*(#(+#.4%*(#7)%*'#(!"#,733"*(#)(8/"6#$"#,4*#"%(!"3#,4//#4 QStyle#27*,(%+*#&%3",(/86#2+3 G(#(!"#"*&6#$"#,4// refreshPixmap()#(+#3"&34$#(!"#.%5-4.#4(#(!"#*"$#)%\"0


"54-./"6

void Plotter::mousePressEvent(QMouseEvent *event)


style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, {
QRect rect(Margin, Margin, {
width() - 2 * Margin, height() - 2 * Margin); if ((event->button() == Qt::LeftButton) && rubberBandIsShown) {
if (event->button() == Qt::LeftButton) { rubberBandIsShown = false;
if (rect.contains(event->pos())) { updateRubberBandRegion();
rubberBandIsShown = true; unsetCursor();
rubberBandRect.setTopLeft(event->pos()); QRect rect = rubberBandRect.normalized();
rubberBandRect.setBottomRight(event->pos()); if (rect.width() < 4 || rect.height() < 4)
updateRubberBandRegion(); return;
setCursor(Qt::CrossCursor); rect.translate(-Margin, -Margin);
} PlotSettings prevSettings = zoomStack[curZoom];
} PlotSettings settings;
} double dx = prevSettings.spanX() / (width() - 2 * Margin);
double dy = prevSettings.spanY() / (height() - 2 * Margin);
settings.minX = prevSettings.minX + dx * rect.left();
settings.maxX = prevSettings.minX + dx * rect.right();
O!"*#(!"#7)"3#.3"))")#(!"#/"2(#-+7)"#D7((+*6#$"#)(43(#&%)./48%*'#4#37DD"3#D4*&0# !%)#%*I+/I") settings.minY = prevSettings.maxY - dy * rect.bottom();
)"((%*' rubberBandIsShown#(+ true6#%*%(%4/%\%*'#(!" rubber-BandRect#-"-D"3#I43%4D/"#$%(!#(!"#,733"*( settings.maxY = prevSettings.maxY - dy * rect.top();
-+7)"#.+%*("3#.+)%(%+*6#),!"&7/%*'#4#.4%*(#"I"*(#(+#.4%*(#(!"#37DD"3#D4*&6#4*&#,!4*'%*'#(!"#-+7)" settings.adjust();
,73)+3#(+#!4I"#4#,3+))!4%3#)!4."0 zoomStack.resize(curZoom + 1);
zoomStack.append(settings);
!" rubberBandRect#I43%4D/"#%)#+2#(8." QRect0#G QRect#,4*#D"#&"2%*"&#"%(!"3#4)#4*#9*,"+,"-&.!/, zoomIn();
/$&'/!=#A74&37./"$!"3"#9*,"+=#%)#(!"#.+)%(%+*#+2#(!"#(+.E/"2(#,+3*"3#4*& -&.!/#5 /$&'/!#%)#(!"#)%\" }
+2#(!"#3",(4*'/"+3#4)#4#(+.E/"2(#4*&#4#D+((+-E3%'!(#,++3&%*4("#.4%30#J"3"6#$"#!4I"#7)"&#(!" }
,++3&%*4("#.4%3#3".3")"*(4(%+*0#O"#)"(#(!"#.+%*(#$!"3"#(!"#7)"3#,/%,@"&#4)#D+(!#(!"#(+.E/"2(#,+3*"3
4*&#4)#(!"#D+((+-E3%'!(#,+3*"30# !"*#$"#,4// updateRubberBandRegion()#(+#2+3,"#4#3".4%*(#+2#(!"
9(%*8=#43"4#,+I"3"&#D8#(!"#37DD"3#D4*&0 O!"*#(!"#7)"3#3"/"4)")#(!"#/"2(#-+7)"#D7((+*6#$"#"34)"#(!"#37DD"3#D4*&#4*&#3")(+3"#(!"#)(4*&43&
433+$#,73)+30#>2#(!"#37DD"3#D4*&#%)#4(#/"4)(#;#5#;6#$"#."32+3-#(!"#\++-0#>2#(!"#37DD"3#D4*&#%)
F(#.3+I%&")#($+#-",!4*%)-)#2+3#,+*(3+//%*'#(!"#-+7)"#,73)+3K)#)!4."B )-4//"3#(!4*#(!4(6#%(K)#/%@"/8#(!4(#(!"#7)"3#,/%,@"&#(!"#$%&'"(#D8 -%)(4@"#+3#(+#'%I"#%(#2+,7)6#)+#$"#&+
*+(!%*'0
• QWidget::setCursor()#)"()#(!"#,73)+3#)!4."#(+#7)"#$!"*#(!"#-+7)"#!+I"3)#+I"3#4#.43(%,7/43
$%&'"(0#>2#*+#,73)+3#%)#)"(#2+3#4#$%&'"(6#(!"#.43"*(#$%&'"(K)#,73)+3#%)#7)"&0# !"#&"247/(#2+3 !"#,+&"#(+#."32+3-#(!"#\++-#%)#4#D%(#,+-./%,4("&0# !%)#%)#D",47)"#$"#&"4/#$%(!#$%&'"(#,++3&%*4(")
(+.E/"I"/#$%&'"()#%)#4*#433+$#,73)+30 4*&#./+(("3#,++3&%*4(")#4(#(!"#)4-"#(%-"0#e+)(#+2#(!"#$+3@#$"#."32+3-#!"3"#%)#(+#,+*I"3(#(!"
• QApplication::setOverrideCursor()#)"()#(!"#,73)+3#)!4."#2+3#(!"#"*(%3"#4../%,4(%+*6 rubberBandRect#23+-#$%&'"(#,++3&%*4(")#(+#./+(("3#,++3&%*4(")0#Y*,"#$"#!4I"#&+*"#(!"#,+*I"3)%+*6
+I"33%&%*'#(!"#,73)+3)#)"(#D8#%*&%I%&74/#$%&'"()#7*(%/ restore-OverrideCursor()#%)#,4//"&0 $"#,4// PlotSettings::adjust()#(+#3+7*&#(!"#*7-D"3)#4*&#2%*&#4#)"*)%D/"#*7-D"3#+2#(%,@)#2+3#"4,!
45%)0 Q%'73")#_0:d#4*& _0::#&".%,(#(!"#)%(74(%+*0
>* L!4.("3#;6#$"#,4//"& QApplication::setOverrideCursor()#$%(! Qt::WaitCursor#(+#,!4*'"#(!"
4../%,4(%+*K)#,73)+3#(+#(!"#)(4*&43&#$4%(#,73)+30 '"$()% *+=>+ ?06:%)&"6$ &7% )(99%) 926# @)01 !"#$%& &0 A30&&%) /00)#"62&%.

void Plotter::mouseMoveEvent(QMouseEvent *event)


{
if (rubberBandIsShown) {
updateRubberBandRegion();
rubberBandRect.setBottomRight(event->pos());
updateRubberBandRegion();
}
}

O!"*#(!"#7)"3 -+I")#(!"#-+7)"#,73)+3#$!%/"#!+/&%*'#(!"#/"2(#D7((+*6#$"#2%3)(#,4//
updateRubberBandRegion()#(+#),!"&7/"#4#.4%*(#"I"*(#(+#3".4%*(#(!"#43"4#$!"3"#(!"#37DD"3#D4*&#$4)6
(!"*#$"#3",+-.7(" rubberBandRect#(+#4,,+7*(#2+3#(!"#-+7)"#-+I"6#4*&#2%*4//8#$"#,4//
updateRubberBandRegion()#4#)",+*&#(%-"#(+#3".4%*(#(!"#43"4#$!"3"#(!"#37DD"3#D4*&#!4)#-+I"&#(+0
!%)#"22",(%I"/8#"34)")#(!"#37DD"3#D4*&#4*&#3"&34$)#%(#4(#(!"#*"$#,++3&%*4(")0 '"$()% *+==+ B#C(.&"6$ A30&&%) /00)#"62&%. 26# D001"6$ "6 06 &7% )(99%)
926#
>2#(!"#7)"3#-+I")#(!"#-+7)"#7.$43&#+3#/"2($43&6#%(K)#/%@"/8#(!4( rubberBandRectK)#*+-%*4/#D+((+-E
3%'!(#,+3*"3#$%//#"*&#7.#4D+I"#+3#(+#(!"#/"2(#+2#%()#(+.E/"2(#,+3*"30#>2#(!%)#+,,73)6#(!" QRect#$%//#!4I"#4 [View full size image]

*"'4(%I"#$%&(!#+3#!"%'!(0#O"#7)"& QRect::normalized()#%* paintEvent()#(+#"*)73"#(!4(#(!"#(+.E/"2(


4*&#D+((+-E3%'!(#,++3&%*4(")#43"#4&V7)("&#(+#+D(4%*#4#*+**"'4(%I"#$%&(!#4*&#!"%'!(0

void Plotter::mouseReleaseEvent(QMouseEvent *event)


refreshPixmap();
}

O!""/#"I"*()#+,,73#$!"*#4#-+7)"#$!""/#%)#(73*"&0#e+)(#-%,"#+*/8#.3+I%&"#4#I"3(%,4/#$!""/6#D7(
)+-"#4/)+#!4I"#4#!+3%\+*(4/#$!""/0#F(#)7..+3()#D+(!#@%*&)#+2#$!""/0#O!""/#"I"*()#'+#(+#(!"#$%&'"(
(!4(#!4)#(!"#2+,7)0# !" delta()#27*,(%+*#3"(73*)#(!"#&%)(4*,"#(!"#$!""/#$4)#3+(4("&#%*#"%'!(!)#+2#4
&"'3""0#e%,"#(8.%,4//8#$+3@#%*#)(".)#+2#:_#&"'3"")0#J"3"6#$"#),3+//#D8#(!"#3"A7")("&#*7-D"3#+2#(%,@)
D8#-+&%28%*'#(!"#(+.-+)(#%("-#+*#(!"#\++-#)(4,@#4*&#7.&4("#(!"#&%)./48#7)%*' refreshPixmap()0

!"#-+)(#,+--+*#7)"#+2#(!"#$!""/#-+7)"#%)#(+#),3+//#4#),3+//#D430#O!"*#$"#7)" QScrollArea
9,+I"3"&#%* L!4.("3#`=#(+#.3+I%&"#),3+//#D43)6 QScrollArea#!4*&/")#(!"#$!""/#-+7)"#"I"*()
47(+-4(%,4//86#)+#$"#&+*K(#*""&#(+#3"%-./"-"*( wheelEvent()#+73)"/I")0
!"*#$"#."32+3-#(!"#\++-0# !"#\++-#%)#4,!%"I"&#D8#.7)!%*'#(!"#*"$ PlotSettings#(!4(#$"#!4I"
V7)(#,4/,7/4("&#+*#(+.#+2#(!"#\++-#)(4,@#4*&#,4//%*' zoomIn()#(+#&+#(!"#V+D0 !%)#2%*%)!")#(!"#%-./"-"*(4(%+*#+2#(!"#"I"*(#!4*&/"3)0#a+$#/"(K)#3"I%"$#(!"#.3%I4("#27*,(%+*)0

void Plotter::keyPressEvent(QKeyEvent *event) void Plotter::updateRubberBandRegion()


{ {
switch (event->key()) { QRect rect = rubberBandRect.normalized();
case Qt::Key_Plus: update(rect.left(), rect.top(), rect.width(), 1);
zoomIn(); update(rect.left(), rect.top(), 1, rect.height());
break; update(rect.left(), rect.bottom(), rect.width(), 1);
case Qt::Key_Minus: update(rect.right(), rect.top(), 1, rect.height());
zoomOut(); }
break;
case Qt::Key_Left:
zoomStack[curZoom].scroll(-1, 0);
refreshPixmap(); !" updateRubberBand()#27*,(%+*#%)#,4//"&#23+- mousePressEvent()6 mouseMove-Event()6#4*&
break; mouseReleaseEvent()#(+#"34)"#+3#3"&34$#(!"#37DD"3#D4*&0#>(#,+*)%)()#+2#2+73#,4//)#(+ update()#(!4(
case Qt::Key_Right: ),!"&7/"#4#.4%*(#"I"*(#2+3#(!"#2+73#)-4//#3",(4*'7/43#43"4)#(!4(#43"#,+I"3"&#D8#(!"#37DD"3#D4*&#9($+
zoomStack[curZoom].scroll(+1, 0); I"3(%,4/#4*&#($+#!+3%\+*(4/#/%*")=0#F(#.3+I%&")#(!" QRubberBand#,/4))#2+3#&34$%*'#37DD"3#D4*&)6#D7(
refreshPixmap(); !"3"6#!4*&E,+&%*'#.3+I%&"&#2%*"3#,+*(3+/0
break;
case Qt::Key_Down:
zoomStack[curZoom].scroll(0, -1); void Plotter::refreshPixmap()
refreshPixmap(); {
break; pixmap = QPixmap(size());
case Qt::Key_Up: pixmap.fill(this, 0, 0);
zoomStack[curZoom].scroll(0, +1); QPainter painter(&pixmap);
refreshPixmap(); painter.initFrom(this);
break; drawGrid(&painter);
default: drawCurves(&painter);
QWidget::keyPressEvent(event); update();
} }
}

!" refreshPixmap()#27*,(%+*#3"&34$)#(!"#./+(#+*(+#(!"#+22E),3""*#.%5-4.#4*&#7.&4(")#(!"#&%)./480
O!"*#(!"#7)"3#.3"))")#4#@"8#4*&#(!" Plotter#$%&'"(#!4)#2+,7)6#(!" keyPress-Event()#27*,(%+*#%) O"#3")%\"#(!"#.%5-4.#(+#!4I"#(!"#)4-"#)%\"#4)#(!"#$%&'"(#4*&#2%//#%(#$%(!#(!"#$%&'"(K)#"34)"#,+/+30
,4//"&0#O"#3"%-./"-"*(#%(#!"3"#(+#3").+*&#(+#)%5#@"8)B#b6 E6#1.6#Z+$*6#^"2(6#4*&#N%'!(0#>2#(!"#7)"3 !%)#,+/+3#%)#(!"#C&43@C#,+-.+*"*(#+2#(!"#.4/"(("6#D",47)"#+2#(!"#,4//#(+ setBackgroundRole()#%*#(!"
.3"))"&#4#@"8#(!4(#$"#43"#*+(#!4*&/%*'6#$"#,4//#(!"#D4)" ,/4))#%-./"-"*(4(%+*0#Q+3#)%-./%,%(86#$" Plotter#,+*)(37,(+30#>2#(!"#D4,@'3+7*&#%)#4#*+*E)+/%&#D37)!6 QPixmap::fill()#*""&)#(+#@*+$#(!"
%'*+3"#(!"#R!%2(6#L(3/6#4*&#G/(#-+&%2%"3#@"8)6#$!%,!#43"#4I4%/4D/"#(!3+7'! QKeyEvent::modifiers()0 +22)"(#%*#(!"#$%&'"(#$!"3"#(!"#.%5-4.#$%//#"*&#7.#(+#4/%'*#(!"#D37)!#.4(("3*#,+33",(/80#J"3"6#(!"
.%5-4.#,+33").+*&)#(+#(!"#"*(%3"#$%&'"(6#)+#$"#).",%28#.+)%(%+*#9d6#d=0
void Plotter::wheelEvent(QWheelEvent *event)
{ !"*#$"#,3"4("#4 QPainter#(+#&34$#+*#(!"#.%5-4.0# !" initFrom()#,4//#)"()#(!"#.4%*("3K)#."*6
int numDegrees = event->delta() / 8; D4,@'3+7*&6#4*&#2+*(#(+#(!"#)4-"#+*")#4)#(!" Plotter#$%&'"(0#a"5(#$"#,4// drawGrid()#4*&
int numTicks = numDegrees / 15; drawCurves()#(+#."32+3-#(!"#&34$%*'0#G( (!"#"*&6#$"#,4// update()#(+#),!"&7/"#4#.4%*(#"I"*(#2+3#(!"
if (event->orientation() == Qt::Horizontal) { $!+/"#$%&'"(0# !"#.%5-4.#%)#,+.%"&#(+#(!"#$%&'"(#%*#(!" paintEvent()#27*,(%+*#9.0#:MP=0
zoomStack[curZoom].scroll(numTicks, 0);
} else {
zoomStack[curZoom].scroll(0, numTicks); void Plotter::drawGrid(QPainter *painter)
} {
QRect rect(Margin, Margin, width() - 2 * Margin, height() - 2 * Margin);
width() - 2 * Margin, height() - 2 * Margin); if (!rect.isValid())
if (!rect.isValid()) return;
return; painter->setClipRect(rect.adjusted(+1, +1, -1, -1));
PlotSettings settings = zoomStack[curZoom]; QMapIterator<int, QVector<QPointF> > i(curveMap);
QPen quiteDark = palette().dark().color().light(); while (i.hasNext()) {
QPen light = palette().light().color(); i.next();
for (int i = 0; i <= settings.numXTicks; ++i) { int id = i.key();
int x = rect.left() + (i * (rect.width() - 1) const QVector<QPointF> &data = i.value();
/ settings.numXTicks); QPolygonF polyline(data.count());
double label = settings.minX + (i * settings.spanX() for (int j = 0; j < data.count(); ++j) {
/ settings.numXTicks); double dx = data[j].x() - settings.minX;
painter->setPen(quiteDark); double dy = data[j].y() - settings.minY;
painter->drawLine(x, rect.top(), x, rect.bottom()); double x = rect.left() + (dx * (rect.width() - 1)
painter->setPen(light); / settings.spanX());
painter->drawLine(x, rect.bottom(), x, rect.bottom() + 5); double y = rect.bottom() - (dy * (rect.height() - 1)
painter->drawText(x - 50, rect.bottom() + 5, 100, 15, / settings.spanY());
Qt::AlignHCenter | Qt::AlignTop, polyline[j] = QPointF(x, y);
QString::number(label)); }
} painter->setPen(colorForIds[uint(id) % 6]);
for (int j = 0; j <= settings.numYTicks; ++j) { painter->drawPolyline(polyline);
int y = rect.bottom() - (j * (rect.height() - 1) }
/ settings.numYTicks); }
double label = settings.minY + (j * settings.spanY()
/ settings.numYTicks);
painter->setPen(quiteDark);
painter->drawLine(rect.left(), y, rect.right(), y); !" drawCurves()#27*,(%+*#&34$)#(!"#,73I")#+*#(+.#+2#(!"#'3%&0#O"#)(43(#D8#,4//%*' setClipRect()#(+
painter->setPen(light); )"(#(!" QPainterK)#,/%.#3"'%+*#(+#(!"#3",(4*'/"#(!4(#,+*(4%*)#(!"#,73I")#9"5,/7&%*'#(!"#-43'%*)#4*&
painter->drawLine(rect.left() - 5, y, rect.left(), y); (!"#234-"#43+7*&#(!"#'34.!=0 QPainter#$%//#(!"*#%'*+3"#&34$%*'#+."34(%+*)#+*#.%5"/)#+7()%&"#(!"
painter->drawText(rect.left() - Margin, y - 10, Margin - 5, 20, 43"40
Qt::AlignRight | Qt::AlignVCenter,
QString::number(label)); a"5(6#$"#%("34("#+I"3#4//#(!"#,73I")#7)%*'#4#f4I4E)(8/"#%("34(+36#4*&#2+3#"4,!#,73I"6#$"#%("34("#+I"3
} %()#,+*)(%(7"*( QPointF)0# !" key()#27*,(%+*#'%I")#(!"#,73I"K)#>Z6#4*&#(!" value()#27*,(%+*#'%I")#(!"
painter->drawRect(rect.adjusted(0, 0, -1, -1));
,+33").+*&%*'#,73I"#&4(4#4) 4 QVector<QPointF>0# !"#%**"3 for#/++.#,+*I"3()#"4,! QPointF#23+-
}
./+(("3#,++3&%*4(")#(+#$%&'"(#,++3&%*4(")#4*&#)(+3")#(!"-#%*#(!" polyline#I43%4D/"0

Y*,"#$"#!4I"#,+*I"3("&#4//#(!"#.+%*()#+2#4#,73I"#(+#$%&'"(#,++3&%*4(")6#$"#)"(#(!"#."*#,+/+3#2+3#(!"
!" drawGrid()#27*,(%+*#&34$)#(!"#'3%&#D"!%*&#(!"#,73I")#4*&#(!"#45")0# !"#43"4#+*#$!%,!#$"#&34$
,73I"#97)%*'#+*"#+2#4#)"(#+2#.3"&"2%*"&#,+/+3)=#4*&#,4// drawPolyline()#(+#&34$#4#/%*"#(!4(#'+")
(!"#'3%&#%)#).",%2%"&#D8 rect0#>2#(!"#$%&'"(#%)*K(#/43'"#"*+7'!#(+#4,,+--+&4("#(!"#'34.!6#$"#3"(73* (!3+7'!#4//#(!"#,73I"K)#.+%*()0
%--"&%4("/80
!%)#%)#(!"#,+-./"(" Plotter#,/4))0#G//#(!4(#3"-4%*)#43"#4#2"$#27*,(%+*)#%* PlotSettings0
!"#2%3)( for#/++.#&34$)#(!"#'3%&K)#I"3(%,4/#/%*")#4*&#(!"#(%,@)#4/+*'#(!" *#45%)0# !"#)",+*& for#/++.
&34$)#(!"#'3%&K)#!+3%\+*(4/#/%*")#4*&#(!"#(%,@)#4/+*'#(!" +#45%)0#G(#(!"#"*&6#$"#&34$#4#3",(4*'/"
4/+*'#(!"#-43'%*)0# !" drawText()#27*,(%+*#%)#7)"&#(+#&34$#(!"#*7-D"3)#,+33").+*&%*'#(+#(!"#(%,@ PlotSettings::PlotSettings()
-43@)#+*#D+(!#45")0 {
minX = 0.0;
!"#,4//)#(+ drawText()#!4I"#(!"#2+//+$%*'#)8*(45B maxX = 10.0;
numXTicks = 5;
minY = 0.0;
painter->drawText(x, y, width, height, alignment, text); maxY = 10.0;
numYTicks = 5;
}

$!"3"#9x6 y6 width6 height=#&"2%*"#4#3",(4*'/"6 alignment#(!"#.+)%(%+*#+2#(!"#("5(#$%(!%*#(!4(


3",(4*'/"6#4*& text#(!"#("5(#(+#&34$0
!" PlotSettings#,+*)(37,(+3#%*%(%4/%\")#D+(!#45")#(+#(!"#34*'"#d#(+#:d#$%(!#_#(%,@#-43@)0

void Plotter::drawCurves(QPainter *painter)


{ void PlotSettings::scroll(int dx, int dy)
static const QColor colorForIds[6] = { {
double stepX = spanX() / numXTicks;
Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow
}; minX += dx * stepX;
maxX += dx * stepX;
PlotSettings settings = zoomStack[curZoom];
QRect rect(Margin, Margin, double stepY = spanY() / numYTicks;
minY += dy * stepY;
maxY += dy * stepY; Mdd#2+3#(!"#)(".#)%\"#%*#(!%)#"54-./"0
}
>(K)#24%3/8#"4)8#(+#&"3%I" numTicks6 min6#4*& max#23+-#(!"#)(".#I4/7"0# !"#*"$ min#I4/7"#%)#+D(4%*"&
D8#3+7*&%*'#(!"#+3%'%*4/ min#&+$*#(+#(!"#*"43")(#-7/(%./"#+2#(!"#)(".6#4*&#(!"#*"$ max#I4/7"#%)
!" scroll()#27*,(%+*#%*,3"-"*()#9+3#&",3"-"*()= minX6 maxX6 minY6#4*& maxY#D8#(!"#%*("3I4/#D"($""* +D(4%*"&#D8#3+7*&%*'#7.#(+#(!"#*"43")(#-7/(%./"#+2#(!"#)(".0# !"#*"$ numTicks#%)#(!"#*7-D"3#+2
($+#(%,@)#(%-")#4#'%I"*#*7-D"30# !%)#27*,(%+*#%)#7)"&#(+#%-./"-"*(#),3+//%*'#%* %*("3I4/)#D"($""*#(!"#3+7*&"& min#4*& max#I4/7")0#Q+3#"54-./"6#%2 min#%)#M;d#4*& max#%)#::<;#7.+*
Plotter::keyPressEvent()0 "*("3%*'#(!"#27*,(%+*6#(!"#*"$#34*'"#D",+-")#gMdd6#:Mddh6#$%(!#_#(%,@#-43@)0

!%)#4/'+3%(!-#$%//#'%I"#)7D+.(%-4/#3")7/()%*#)+-"#,4)")0#G#-+3"#)+.!%)(%,4("&#4/'+3%(!-#%)
void PlotSettings::adjust() &"),3%D"&#%*#H47/#R0#J",@D"3(K)#43(%,/"#Ca%,"#a7-D"3)#2+3#[34.!#^4D"/)C#.7D/%)!"&#%* 0)12/&3%
{ 0$4%#9>R?a#dE:MEM<`:``EP=0
adjustAxis(minX, maxX, numXTicks);
adjustAxis(minY, maxY, numYTicks);
} !%)#,!4.("3#!4)#D3+7'!(#7)#(+#(!"#"*&#+2 H43(#>0#>(#!4)#"5./4%*"&#!+$#(+#,7)(+-%\"#4*#"5%)(%*'#F(
$%&'"(#4*&#!+$#(+#D7%/&#4#$%&'"(#23+-#(!"#'3+7*&#7.#7)%*' QWidget#4)#(!"#D4)"#,/4))0#O"#!4I"
4/3"4&8#)""*#!+$#(+#,+-.+)"#4#$%&'"(#23+-#"5%)(%*' $%&'"()#%* L!4.("3#M6#4*&#$"#$%//#"5./+3"#(!"
(!"-"#273(!"3#%* L!4.("3#`0
!" adjust()#27*,(%+*#%)#,4//"&#23+- mouseReleaseEvent()#(+#3+7*&#(!" minX6 maxX6 minY6#4*& maxY
I4/7")#(+#C*%,"C#I4/7")#4*&#(+#&"("3-%*"#(!"#*7-D"3#+2#(%,@)#4..3+.3%4("#2+3#"4,!#45%)0# !"#.3%I4("
G(#(!%)#.+%*(6#$"#@*+$#"*+7'!#(+#$3%("#,+-./"("#[1>#4../%,4(%+*)#7)%*'#F(0#>* H43()#>>#4*& >>>6#$"
27*,(%+* adjustAxis()#&+")#%()#$+3@#+*"#45%)#4(#4#(%-"0
$%//#"5./+3"#F(#%*#'3"4("3#&".(!#)+#(!4(#$"#,4*#-4@"#27//#7)"#+2#F(K)#.+$"30

void PlotSettings::adjustAxis(double &min, double &max,


int &numTicks)
{
const int MinTicks = 4;
double grossStep = (max - min) / MinTicks;
double step = pow(10.0, floor(log10(grossStep)));
if (5 * step < grossStep) {
step *= 5;
} else if (2 * step < grossStep) {
step *= 2;
}
numTicks = int(ceil(max / step) - floor(min / step));
if (numTicks < MinTicks)
numTicks = MinTicks;
min = floor(min / step) * step;
max = ceil(max / step) * step;
}

!" adjustAxis()#27*,(%+*#,+*I"3()#%() min#4*& max#.434-"("3)#%*(+#C*%,"C#*7-D"3)#4*&#)"()#%()


numTicks#.434-"("3#(+#(!"#*7-D"3#+2#(%,@)#%(#,4/,7/4(")#(+#D"#4..3+.3%4("#2+3#(!"#'%I"*#g min6 maxh
34*'"0#?",47)" adjustAxis()#*""&)#(+#-+&%28#(!"#4,(74/#I43%4D/")#9minX6 maxX6 numXTicks6#"(,0=#4*&
*+(#V7)(#,+.%")6#%()#.434-"("3)#43"#*+*E,+*)(#3"2"3"*,")0

e+)(#+2#(!"#,+&"#%* adjustAxis()#)%-./8#4(("-.()#(+#&"("3-%*"#4*#4..3+.3%4("#I4/7"#2+3#(!"#%*("3I4/
D"($""*#($+#(%,@)#9(!"#C)(".C=0# +#+D(4%*#*%,"#*7-D"3)#4/+*'#(!"#45%)6#$"#-7)(#)"/",(#(!"#)(".#$%(!
,43"0#Q+3#"54-./"6#4#)(".#I4/7"#+2#P0<#$+7/&#/"4&#(+#4*#45%)#$%(!#-7/(%./")#+2#P0<6#$!%,!#%)#&%22%,7/(
2+3#."+./"#(+#3"/4("#(+0#Q+3#45")#/4D"/"&#%*#&",%-4/#*+(4(%+*6#C*%,"C#)(".#I4/7")#43"#*7-D"3)#+2#(!"
2+3-#:d(6#Mi:d(6#+3#_i:d(0

O"#)(43(#D8#,+-.7(%*'#(!"#C'3+))#)(".C6#4#@%*&#+2#-45%-7-#2+3#(!"#)(".#I4/7"0# !"*#$"#2%*&#(!"
,+33").+*&%*'#*7-D"3#+2#(!"#2+3-#:d (#(!4(#%)#)-4//"3#(!4*#+3#"A74/#(+#(!"#'3+))#)(".0#O"#&+#(!%)#D8
(4@%*'#(!"#&",%-4/#/+'43%(!-#+2#(!"#'3+))#)(".6#3+7*&%*'#(!4( I4/7"#&+$*#(+#4#$!+/"#*7-D"36#(!"*
34%)%*'#:d#(+#(!"#.+$"3#+2#(!%)#3+7*&"&#*7-D"30#Q+3#"54-./"6#%2#(!"#'3+))#)(".#%)#MP`6#$"#,+-.7("
/+'#MP`#j#M0PkMl:mX#(!"*#$"#3+7*&#%(#&+$*#(+#M#4*&#+D(4%*#:d M#j#:dd#4)#(!"#,4*&%&4("#)(".#I4/7"
+2#(!"#2+3-#:d(0

Y*,"#$"#!4I"#(!"#2%3)(#,4*&%&4("#)(".#I4/7"6#$"#,4*#7)"#%(#(+#,4/,7/4("#(!"#+(!"3#($+#,4*&%&4(")B
Mi:d(#4*&#_i:d(0#Q+3#(!"#"54-./"#4D+I"6#(!"#($+#+(!"3#,4*&%&4(")#43"#Mdd#4*&#_dd0# !"#_dd
,4*&%&4("#%)#/43'"3#(!4*#(!"#'3+))#)(".6#)+#$"#,4*K(#7)"#%(0#?7(#Mdd#%)#)-4//"3#(!4*#MP`6#)+#$"#7)"
Part II: Intermediate Qt Chapter 6. Layout Management
L!4.("3#`0 #^48+7(#e4*4'"-"*( • *+,&('"-.!"/&0'$!%"1("+"21)3
• 4!+56$0"*+,1.!%
• 478&!!$)%
L!4.("3#k0 #cI"*(#H3+,"))%*'
• 45)188&('"9)$+%
• #156"/&0'$!%"+(0":118;+)%
L!4.("3#<0 #MZ#4*&#PZ#[34.!%,) • <.8!&78$"#15.3$(!"=(!$)>+5$

L!4.("3#l0 #Z34'#4*&#Z3+. cI"38#$%&'"(#(!4(#%)#./4,"&#+*#4#2+3-#-7)(#D"#'%I"*#4*#4..3+.3%4("#)%\"#4*&#.+)%(%+*0#F(#.3+I%&")


)"I"34/#,/4))")#(!4(#/48#+7(#$%&'"()#+*#4#2+3-B QHBoxLayout6 QVBoxLayout6 QGridLayout6#4*&
L!4.("3#:d0 #>("-#S%"$#L/4))") QStackLayout0# !")"#,/4))")#43"#)+#,+*I"*%"*(#4*&#"4)8#(+#7)"#(!4(#4/-+)(#"I"38#F(#&"I"/+."3#7)")
(!"-6#"%(!"3#&%3",(/8#%*#)+73,"#,+&"#+3#(!3+7'! !"#$%&'($)0
L!4.("3#::0 #L+*(4%*"3#L/4))")
G*+(!"3#3"4)+*#(+#7)"#F(K)#/48+7(#,/4))")#%)#(!4(#(!"8#"*)73"#(!4(#2+3-)#4&4.(#47(+-4(%,4//8#(+
L!4.("3#:M0 #>*.7(nY7(.7( &%22"3"*(#2+*()6#/4*'74'")6#4*&#./4(2+3-)0#>2#(!"#7)"3#,!4*'")#(!"#)8)("-K)#2+*(#)"((%*')6#(!"
4../%,4(%+*K)#2+3-)#$%//#3").+*&#%--"&%4("/86#3")%\%*'#(!"-)"/I")#%2#*","))4380#G*&#%2#8+7#(34*)/4("
L!4.("3#:P0 #Z4(4D4)") (!"#4../%,4(%+*K)#7)"3#%*("324,"#(+#+(!"3#/4*'74'")6#(!"#/48+7(#,/4))") (4@"#%*(+#,+*)%&"34(%+*#(!"
$%&'"()K#(34*)/4("&#,+*("*()#(+#4I+%&#("5(#(37*,4(%+*0
L!4.("3#:;0 #a"($+3@%*'
Y(!"3#,/4))")#(!4(#."32+3-#/48+7(#-4*4'"-"*(#%*,/7&" QSplitter6 QScrollArea6 QMainWindow6#4*&
L!4.("3#:_0 #oe^ QWorkspace0#O!4(#(!")"#,/4))")#!4I"#%*#,+--+*#%)#(!4(#(!"8#.3+I%&"#4#2/"5%D/"#/48+7(#(!4(#(!"#7)"3
,4*#-4*%.7/4("0#Q+3#"54-./"6 QSplitter#.3+I%&")#4#)./%(("3#D43#(!4(#(!"#7)"3#,4*#&34'#(+#3")%\"
L!4.("3#:`0 #H3+I%&%*'#Y*/%*"#J"/. $%&'"()6#4*& QWorkspace#.3+I%&")#)7..+3(#2+3#eZ>#9-7/(%./"#&+,7-"*(#%*("324,"=6#4#-"4*)#+2
)!+$%*'#-4*8#&+,7-"*()#)%-7/(4*"+7)/8#$%(!%*#4*#4../%,4(%+*K)#-4%*#$%*&+$0#?",47)"#(!"8#43"
+2("*#7)"&#4)#4/("3*4(%I")#(+#(!"#/48+7(#,/4))")#.3+."36#(!"8#43"#,+I"3"&#%*#(!%)#,!4.("30

Laying Out Widgets on a Form


!"3"#43"#(!3""#D4)%,#$48)#+2#-4*4'%*'#(!"#/48+7(#+2#,!%/&#$%&'"()#+*#4#2+3-B#4D)+/7("
.+)%(%+*%*'6-4*74/#/48+7(6#4*&#/48+7(#-4*4'"3)0#O"#$%//#/++@#4(#"4,!#+2#(!")"#4..3+4,!")#%*#(73*6
7)%*'#(!"#Q%*&#Q%/"#&%4/+'#)!+$*#%* Q%'73"#`0:#4)#+73#"54-./"0

'"$()% ,+=+ E7% '"6# '"3% #"230$


helpButton->setGeometry(171 + extraWidth, 149 + extraHeight, 85,
GD)+/7("#.+)%(%+*%*'#%)#(!"#,37&")(#$48#+2#/48%*'#+7(#$%&'"()0#>(#%)#4,!%"I"&#D8#4))%'*%*'#!43&E,+&"& 32);
}
)%\")#4*& .+)%(%+*)#(+#(!"#2+3-K)#,!%/&#$%&'"()#4*&#4#2%5"&#)%\"#(+#(!"#2+3-0#J"3"K)#$!4(#(!"
FindFileDialog#,+*)(37,(+3#/++@)#/%@"#7)%*'#4D)+/7("#.+)%(%+*%*'B

>*#(!" FindFileDialog#,+*)(37,(+36#$"#)"(#(!"#2+3-K)#-%*%-7-#)%\"#(+#M`_#5#:ld#4*&#(!"#%*%(%4/#)%\"
FindFileDialog::FindFileDialog(QWidget *parent) (+#P`_#5#M;d0#>*#(!" resizeEvent()#!4*&/"36#$"#'%I"#4*8#"5(34#).4,"#(+#(!"#$%&'"()#(!4(#$"#$4*( (+
: QDialog(parent) '3+$0# !%)#"*)73")#(!4(#(!"#2+3-#),4/")#)-++(!/8#$!"*#(!"#7)"3#3")%\")#%(0
{
...
namedLabel->setGeometry(9, 9, 50, 25); '"$()% ,+F+ G%."D"6$ 2 )%."D293% #"230$
namedLineEdit->setGeometry(65, 9, 200, 25); [View full size image]
lookInLabel->setGeometry(9, 40, 50, 25);
lookInLineEdit->setGeometry(65, 40, 200, 25);
subfoldersCheckBox->setGeometry(9, 71, 256, 23);
tableWidget->setGeometry(9, 100, 256, 100);
messageLabel->setGeometry(9, 206, 256, 25);
findButton->setGeometry(271, 9, 85, 32);
stopButton->setGeometry(271, 47, 85, 32);
closeButton->setGeometry(271, 84, 85, 32);
helpButton->setGeometry(271, 199, 85, 32);
setWindowTitle(tr("Find Files or Folders"));
setFixedSize(365, 240);
}

f7)(#/%@"#4D)+/7("#.+)%(%+*%*'6#-4*74/#/48+7(#3"A7%3")#4#/+(#+2#!43&E,+&"&#,+*)(4*()#(+#D"#,4/,7/4("&
GD)+/7("#.+)%(%+*%*'#!4)#-4*8#&%)4&I4*(4'")B D8#(!"#.3+'34--"30#O3%(%*'#,+&"#/%@"#(!%)#%)#(%3")+-"6#").",%4//8#%2#(!"#&")%'*#,!4*'")0#G*&#(!"3"#%)
)(%//#(!"#3%)@#+2#("5(#(37*,4(%+*0#O"#,4*#4I+%&#(!%)#3%)@#D8#(4@%*'#4,,+7*(#+2#(!"#,!%/&#$%&'"()K#)%\"
• !"#7)"3#,4**+(#3")%\"#(!"#$%*&+$0 !%*()6#D7(#(!4(#$+7/&#,+-./%,4("#(!"#,+&"#"I"*#273(!"30
• R+-"#("5(#-48#D"#(37*,4("&#%2#(!"#7)"3#,!++)")#4*#7*7)74//8#/43'"#2+*(#+3#%2#(!"#4../%,4(%+*
%)#(34*)/4("&#%*(+#4*+(!"3#/4*'74'"0 !"#-+)(#,+*I"*%"*(#)+/7(%+*#2+3#/48%*'#+7(#$%&'"()#+*#4#2+3-#%)#(+#7)"#F(K)#/48+7(#-4*4'"3)0# !"
• !"#$%&'"()#-%'!(#!4I"#%*4..3+.3%4("#)%\")#2+3#)+-"#)(8/")0 /48+7(#-4*4'"3)#.3+I%&"#)"*)%D/"#&"247/()#2+3#"I"38#(8."#+2#$%&'"(#4*&#(4@"#%*(+#4,,+7*(#"4,!
• !"#.+)%(%+*)#4*&#)%\")#-7)(#D"#,4/,7/4("&#-4*74//80# !%)#%)#("&%+7)#4*&#"33+3E.3+*"6#4*& $%&'"(K)#)%\"#!%*(6#$!%,!#%*#(73*#(8.%,4//8#&"."*&)#+*#(!"#$%&'"(K)#2+*(6#)(8/"6#4*&#,+*("*()0#^48+7(
-4@")#-4%*("*4*,"#.4%*27/0 -4*4'"3)#4/)+#3").",(#-%*%-7-#4*&#-45%-7-#)%\")6#4*&#47(+-4(%,4//8#4&V7)(#(!"#/48+7(#%*
3").+*)"#(+#2+*(#,!4*'")6#,+*("*(#,!4*'")6#4*&#$%*&+$#3")%\%*'0
G*#4/("3*4(%I"#(+#4D)+/7("#.+)%(%+*%*'#%)#-4*74/#/48+7(0#O%(! -4*74/#/48+7(6#(!"#$%&'"()#43"#)(%//
'%I"*#4D)+/7("#.+)%(%+*)6#D7(#(!"%3#)%\")#43"#-4&"#.3+.+3(%+*4/#(+#(!"#)%\"#+2#(!"#$%*&+$#34(!"3#(!4* !"#(!3""#-+)(#%-.+3(4*(#/48+7(#-4*4'"3)#43" QHBoxLayout6 QVBoxLayout6#4*& QGridLayout0# !")"
D"%*'#"*(%3"/8#!43&E,+&"&0# !%)#,4*#D"#4,!%"I"&#D8#3"%-./"-"*(%*'#(!"#2+3-K) resizeEvent() ,/4))")#%*!"3%( QLayout6#$!%,!#.3+I%&")#(!"#D4)%,#234-"$+3@#2+3#/48+7()0#G//#(!3""#,/4))")#43"#27//8
27*,(%+*#(+#)"(#%()#,!%/& $%&'"()K#'"+-"(3%")B )7..+3("&#D8 !"#$%&'($)#4*&#,4*#4/)+#D"#7)"&#&%3",(/8#%*#,+&"0

J"3"K)#(!" FindFileDialog#,+&"#7)%*'#/48+7(#-4*4'"3)B
FindFileDialog::FindFileDialog(QWidget *parent)
: QDialog(parent)
{
... FindFileDialog::FindFileDialog(QWidget *parent)
setMinimumSize(265, 190); : QDialog(parent)
resize(365, 240); {
} ...
void FindFileDialog::resizeEvent(QResizeEvent * /* event */) QGridLayout *leftLayout = new QGridLayout;
{ leftLayout->addWidget(namedLabel, 0, 0);
int extraWidth = width() - minimumWidth(); leftLayout->addWidget(namedLineEdit, 0, 1);
int extraHeight = height() - minimumHeight(); leftLayout->addWidget(lookInLabel, 1, 0);
namedLabel->setGeometry(9, 9, 50, 25); leftLayout->addWidget(lookInLineEdit, 1, 1);
namedLineEdit->setGeometry(65, 9, 100 + extraWidth, 25); leftLayout->addWidget(subfoldersCheckBox, 2, 0, 1, 2);
lookInLabel->setGeometry(9, 40, 50, 25); leftLayout->addWidget(tableWidget, 3, 0, 1, 2);
lookInLineEdit->setGeometry(65, 40, 100 + extraWidth, 25); leftLayout->addWidget(messageLabel, 4, 0, 1, 2);
subfoldersCheckBox->setGeometry(9, 71, 156 + extraWidth, 23); QVBoxLayout *rightLayout = new QVBoxLayout;
tableWidget->setGeometry(9, 100, 156 + extraWidth, rightLayout->addWidget(findButton);
50 + extraHeight); rightLayout->addWidget(stopButton);
messageLabel->setGeometry(9, 156 + extraHeight, 156 + extraWidth, rightLayout->addWidget(closeButton);
25); rightLayout->addStretch();
findButton->setGeometry(171 + extraWidth, 9, 85, 32); rightLayout->addWidget(helpButton);
stopButton->setGeometry(171 + extraWidth, 47, 85, 32); QHBoxLayout *mainLayout = new QHBoxLayout;
closeButton->setGeometry(171 + extraWidth, 84, 85, 32); mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout); )%(74(%+*0# !"#)4-"#4../%")#%2#$"#,4// hide()#+3 show()#+*#4#,!%/&#$%&'"(0#>2#4#,!%/&#$%&'"(K)#)%\"#!%*(
setLayout(mainLayout); ,!4*'")6#(!"#/48+7(#$%//#D"#47(+-4(%,4//8#3"&+*"6#(4@%*'#%*(+#4,,+7*(#(!"#*"$#)%\"#!%*(0#G/)+6#/48+7(
setWindowTitle(tr("Find Files or Folders")); -4*4'"3)#47(+-4(%,4//8#)"(#4#-%*%-7-#)%\"#2+3#(!"#2+3-#4)#4#$!+/"6#D4)"&#+*#(!"#2+3-K)#,!%/&
} $%&'"()K#-%*%-7-#)%\")#4*&#)%\"#!%*()0

>*#(!"#"54-./")#.3")"*("&#)+#2436#$"#!4I"#)%-./8#.7(#$%&'"()#%*(+#/48+7()#4*&#7)"&#).4,"3#%("-)
!"#/48+7(#%)#!4*&/"&#D8#+*" QHBoxLayout6#+*" QGridLayout6#4*&#+*" QVBoxLayout0# !" QGridLayout 9)(3"(,!")=#(+#,+*)7-"#4*8#"5,"))#).4,"0#>*#)+-"#,4)")6#(!%)#%)*K(#)722%,%"*(#(+#-4@"#(!"#/48+7(#/++@
+*#(!"#/"2(#4*&#(!" QVBoxLayout#+*#(!"#3%'!(#43"#./4,"&#)%&"#D8#)%&"#D8#(!"#+7("3 QHBoxLayout0# !" "54,(/8#(!"#$48#$"#$4*(0#>*#(!")"#)%(74(%+*)6#$"#,4*#4&V7)(#(!"#/48+7(#D8#,!4*'%*'#(!"#)%\"#.+/%,%")
-43'%*#43+7*&#(!"#&%4/+'#4*&#(!"#).4,%*'#D"($""*#(!"#,!%/&#$%&'"()#43"#)"(#(+#&"247/(#I4/7")#D4)"& 4*&#)%\"#!%*()#+2#(!"#$%&'"()#D"%*'#/4%&#+7(0
+*#(!"#,733"*(#$%&'"(#)(8/"X#(!"8#,4*#D"#,!4*'"&#7)%*' QLayout::setMargin()#4*&
QLayout::setSpacing()0 G#$%&'"(K)#)%\"#.+/%,8#("//)#(!"#/48+7(#)8)("-#!+$#%(#)!+7/&#)(3"(,!#+3#)!3%*@0#F(#.3+I%&")#)"*)%D/"
&"247/(#)%\"#.+/%,%")#2+3#4//#%()#D7%/(E%*#$%&'"()6#D7(#)%*,"#*+#)%*'/"#&"247/(#,4*#4,,+7*(#2+3#"I"38
!"#)4-"#&%4/+'#,+7/&#D"#,3"4("&#I%)74//8#%* !"#$%&'($)#D8#./4,%*'#(!"#,!%/&#$%&'"()#%*#(!"%3 .+))%D/"#/48+7(6#%(#%)#)(%//#,+--+*#2+3#&"I"/+."3)#(+#,!4*'"#(!"#)%\"#.+/%,%")#2+3#+*"#+3#($+#$%&'"()
4..3+5%-4("#.+)%(%+*)X#)"/",(%*'#(!+)"#(!4(#*""&#(+#D"#/4%&#+7(#(+'"(!"3X#4*&#,/%,@%*'#Q+3-p^48#Y7( +*#4#2+3-0#G QSizePolicy#!4)#D+(!#4#!+3%\+*(4/#4*&#4#I"3(%,4/#,+-.+*"*(0 J"3"#43"#(!"#-+)(#7)"27/
J+3%\+*(4//86#Q+3-p^48#Y7(#S"3(%,4//86#+3#Q+3-p^48#Y7(#%*#4#[3%&0#O"#7)"&#(!%)#4..3+4,!#%* L!4.("3 I4/7")B
M#2+3 ,3"4(%*'#(!"#R.3"4&)!""(#4../%,4(%+*K)#[+E(+EL"//#4*&#R+3(#&%4/+')0
• Fixed#-"4*)#(!4(#(!"#$%&'"(#,4**+(#'3+$#+3#)!3%*@0# !"#$%&'"(#4/$48)#)(48)#4(#(!"#)%\"#+2#%()
'"$()% ,+H+ E7% '"6# '"3% #"230$-. 32I0(& )%\"#!%*(0
• Minimum#-"4*)#(!4(#(!"#$%&'"(K)#)%\"#!%*(#%)#%()#-%*%-7-#)%\"0# !"#$%&'"(#,4**+(#)!3%*@
[View full size image]
D"/+$#(!"#)%\"#!%*(6#D7(#%(#,4*#'3+$#(+#2%//#4I4%/4D/"#).4,"#%2#*","))4380
• Maximum#-"4*)#(!4(#(!"#$%&'"(K)#)%\"#!%*(#%)#%()#-45%-7-#)%\"0# !"#$%&'"(#,4*#D"#)!37*@
&+$*#(+#%()#-%*%-7-#)%\"#!%*(0
• Preferred#-"4*)#(!4(#(!"#$%&'"(K)#)%\"#!%*(#%)#%()#.3"2"33"&#)%\"6#D7(#(!4(#(!"#$%&'"(#,4*#)(%//
)!3%*@#+3#'3+$#%2#*","))4380
• Expanding#-"4*)#(!4(#(!"#$%&'"(#,4*#)!3%*@#+3#'3+$#4*&#(!4(#%(#%)#").",%4//8#$%//%*'#(+#'3+$0

Q%'73"#`0;#)7--43%\")#(!"#-"4*%*'#+2#(!"#&%22"3"*(#)%\"#.+/%,%")6#7)%*'#4 QLabel#)!+$%*'#(!"#("5(
CR+-"# "5(C#4)#4*#"54-./"0

'"$()% ,+J+ E7% 1%26"6$ 0@ &7% #"@@%)%6& ."D% A03"/"%.


[View full size image]

1)%*' QHBoxLayout#4*& QVBoxLayout#%)#24%3/8#)(34%'!(2+3$43&6#D7(#7)%*' QGrid-Layout#%)#4#D%(#-+3"


%*I+/I"&0 QGridLayout#$+3@)#+*#4#($+E&%-"*)%+*4/#'3%&#+2#,"//)0# !" QLabel#%*#(!"#(+.E/"2(#,+3*"3#+2
(!"#/48+7(#%)#4(#.+)%(%+*#9d6#d=6#4*&#(!"#,+33").+*&%*' QLineEdit#%)#4(#.+)%(%+*#9d6#:=0# !" QCheckBox
).4*)#($+#,+/7-*)X#%(#+,,7.%")#(!"#,"//)#%*#.+)%(%+*)#9M6#d=#4*&#9M6#:=0# !" QtreeWidget#4*&#(!"
QLabel#D"*"4(!#%(#4/)+#).4*#($+#,+/7-*)0# !"#,4//)#(+ addWidget()#!4I"#(!"#2+//+$%*'#)8*(45B

layout->addWidget(widget, row, column, rowSpan, columnSpan);


>*#(!"#2%'73"6 Preferred#4*& Expanding#43"#&".%,("&#(!"#)4-"#$480#R+#$!4(#%)#(!"#&%22"3"*,"W#O!"*
4#2+3-#(!4(#,+*(4%*)#D+(! Preferred#4*& Expanding#$%&'"()#%)#3")%\"&6#"5(34#).4,"#%)#'%I"*#(+#(!"
Expanding#$%&'"()6#$!%/"#(!" Preferred#$%&'"()#)(48#4(#(!"%3#)%\"#!%*(0
J"3"6 widget#%)#(!"#,!%/&#$%&'"(#(+#%*)"3(#%*(+#(!"#/48+7(6#9row6 column=#%)#(!"#(+.E/"2(#,"//#+,,7.%"&#D8
(!"#$%&'"(6 rowSpan#%)#(!"#*7-D"3#+2#3+$)#+,,7.%"&#D8#(!"#$%&'"(6#4*& columnSpan#%)#(!" *7-D"3#+2
!"3"#43"#($+#+(!"3#)%\"#.+/%,%")B MinimumExpanding#4*& Ignored0# !"#2+3-"3 $4)#*","))438#%*#4#2"$
,+/7-*)#+,,7.%"&#D8#(!"#$%&'"(0#>2#+-%(("&6#(!" rowSpan#4*& columnSpan#.434-"("3)#&"247/(#(+#:0
343"#,4)")#%*#+/&"3#I"3)%+*)#+2#F(6#D7(#%(#%)*K(#7)"27/#4*8-+3"X#(!"#.3"2"33"&#4..3+4,!#%)#(+#7)"
Expanding#4*&#3"%-./"-"*( minimumSizeHint()#4..3+.3%4("/80# !"#/4(("3#%)#)%-%/43#(+ Expanding6
!" addStretch()#,4//#("//)#(!"#/48+7(#-4*4'"3#(+#,+*)7-"#).4,"#4(#(!4(#.+%*(#%*#(!"#/48+7(0#?8 "5,".(#(!4(#%(#%'*+3")#(!"#$%&'"(K)#)%\"#!%*(#4*&#-%*%-7-#)%\"#!%*(0
4&&%*'#4#)(3"(,!#%("-6#$"#!4I"#(+/&#(!"#/48+7(#-4*4'"3#(+#.7(#4*8#"5,"))#).4,"#D"($""*#(!"#L/+)"
D7((+*#4*&#(!"#J"/.#D7((+*0#>* !"#$%&'($)6#$"#,4*#4,!%"I"#(!"#)4-"#"22",(#D8#%*)"3(%*'#4#).4,"30
>*#4&&%(%+*#(+#(!"#)%\"#.+/%,8K)#!+3%\+*(4/#4*&#I"3(%,4/#,+-.+*"*()6(!" QSizePolicy#,/4))#)(+3")#4
R.4,"3)#4.."43#%* !"#$%&'($)#4)#D/7"#C).3%*')C0
!+3%\+*(4/#4*&#4#I"3(%,4/#)(3"(,!#24,(+30# !")"#)(3"(,!#24,(+3)#,4*#D"#7)"&#(+#%*&%,4("#(!4(#&%22"3"*(
,!%/&#$%&'"()#)!+7/&#'3+$#4(#&%22"3"*(#34(")#$!"*#(!"#2+3-#"5.4*&)0#Q+3#"54-./"6#%2#$"#!4I"#4
1)%*'#/48+7(#-4*4'"3)#.3+I%&")#4&&%(%+*4/#D"*"2%()#(+#(!+)"#$"#!4I"#&%),7))"&#)+#2430#>2#$"#4&&#4 QtreeWidget#4D+I"#4 QTextEdit#4*&#$"#$4*(#(!" QTextEdit#(+#D"#($%,"#4)#(4//#4)#(!" QtreeWidget6#$"
$%&'"(#(+#4#/48+7(#+3#3"-+I"#4#$%&'"(#23+-#4#/48+7(6#(!"#/48+7(#$%//#47(+-4(%,4//8#4&4.(#(+#(!"#*"$
,4*#)"(#(!" QTextEditK)#I"3(%,4/#)(3"(,!#24,(+3#(+#M#4*&#(!" QtreeWidgetK)#I"3(%,4/#)(3"(,!#24,(+3#(+#:0
!"#$%&'('(&)*+&,-"%.&+/&01%&2$%/%$%34%.&5!-6+"
q"(#4*+(!"3#$48#+2#%*2/7"*,%*'#4#/48+7(#%)#(+#)"(#4#-%*%-7-#)%\"6#4#-45%-7-#)%\"6#+3#4#2%5"&#)%\"#+*
(!"#,!%/&#$%&'"()0# !"#/48+7(#-4*4'"3#$%//#3").",(#(!")"#,+*)(34%*()#$!"*#/48%*'#+7(#(!"#$%&'"()0 [View full size image]

G*&#%2#(!%)#%)*K(#)722%,%"*(6#$"#,4*#4/$48)#&"3%I"#23+-#(!"#,!%/&#$%&'"(K)#,/4))#4*&#3"%-./"-"*(
sizeHint()#(+#+D(4%*#(!"#)%\"#!%*(#$"#*""&0

Stacked Layouts
!" QStackedLayout#,/4))#/48)#+7(#4 )"(#+2#,!%/&#$%&'"()6#+3#C.4'")C6#4*&#)!+$)#+*/8#+*"#4(#4#(%-"6
!%&%*'#(!"#+(!"3)#23+-#(!"#7)"30# !" QStackedLayout#%()"/2#%)#%*I%)%D/"#4*&#.3+I%&")#*+#%*(3%*)%,#-"4*)
2+3#(!"#7)"3#(+#,!4*'"#.4'"0# !"#)-4//#433+$)#4*&#(!"#&43@#'348#234-"#%* Q%'73"#`0_#43"#.3+I%&"&#D8
!"#$%&'($)#(+#-4@"#(!"#/48+7(#"4)%"3#(+#&")%'*#$%(!0#Q+3#,+*I"*%"*,"6#F(#4/)+#%*,/7&")
QStackedWidget6#$!%,!#.3+I%&")#4 QWidget#$%(!#4#D7%/(E%* QStackedLayout0

'"$()% ,+*+ QStackedLayout


B"#3("%7"#% QListWidget#%)-#$/$*5%7"#47#647!#7!"#$%&"#)%+"'1# !")#6"#3("%7"#% QStackedLayout#%)-
3%55 addWidget()#./(#"%3!#$%&"1#B"#3/))"37#7!"#54'7#64-&"7@' currentRowChanged(int)#'4&)%5#7/#7!"
'7%32"-#5%C/*7@' setCurrentIndex(int)#7/#4+$5"+")7#7!"#$%&"#'6473!4)&#%)-#3%55 setCurrentRow()#/)
7!"#54'7#64-&"7#%7#7!"#")-#/.#7!"#3/)'7(*37/(#7/#'7%(7#/)#$%&"#01

;/(+'#542"#7!4'#%("#%5'/#8"(C#"%'C#7/#3("%7"#*'4)& !"#$%&'($)A

D1 E("%7"#%#)"6#./(+#,%'"-#/)#7!"#FG4%5/&F#/(#7!"#FB4-&"7F#7"+$5%7"1
H1 I--#% QListWidget#%)-#% QStackedWidget#7/#7!"#./(+1
J1 ;455#"%3!#$%&"#647!#3!45-#64-&"7'#%)-#5%C/*7'1

K /#3("%7"#%#)"6#$%&"9#(4&!7L35432#%)-#3!//'"#M)'"(7#:%&"N#7/#'6473!#$%&"'9#35432#7!"#74)C#5".7
!"#$%&"'#%("#)*+,"("-#.(/+#01# /#+%2"#%#'$"34.43#3!45-#64-&"7#84'4,5"9#6"#3%)#3%55 /(#(4&!7#%((/6#5/3%7"-#%7#7!"#7/$L(4&!7#/.#7!" QStackedWidget1O
setCurrentIndex()#647!#%#$%&"#)*+,"(1# !"#$%&"#)*+,"(#./(#%#3!45-#64-&"7#4'#%8%45%,5"#*'4)&
indexOf()1 P1 Q%C#7!"#64-&"7'#/*7#'4-"#,C#'4-"#*'4)&#%#!/(4R/)7%5#5%C/*71
S1 E/))"37#7!"#54'7#64-&"7@' currentRowChanged(int)#'4&)%5#7/#7!"#'7%32"-#64-&"7@'
!"#:("."(")3"'#-4%5/&#'!/6)#4) ;4&*("#<1<#4'#%)#"=%+$5"#7!%7#*'"' QStacked-Layout1# !"#-4%5/& setCurrentIndex(int)#'5/71
3/)'4'7'#/.#% QListWidget#/)#7!"#5".7#%)-#% QStackedLayout#/)#7!"#(4&!71#>%3!#47"+#4)#7!" QListWidget <1 T"7#7!"#8%5*"#/.#7!"#54'7#64-&"7@' currentRow#$(/$"(7C#7/#01
3/(("'$/)-'#7/#%#-4.."(")7#$%&"#4)#7!" QStackedLayout1#?"("@'#7!"#("5"8%)7#3/-"#.(/+#7!"#-4%5/&@'
3/)'7(*37/(A T4)3"#6"#!%8"#4+$5"+")7"-#$%&"#'6473!4)&#*'4)&#$("-".4)"-#'4&)%5'#%)-#'5/7'9#7!"#-4%5/&#6455#"=!4,47
7!"#3/(("37#,"!%84/( 6!")#$("84"6"-#4) !"#$%&'($)1

PreferenceDialog::PreferenceDialog(QWidget *parent)
: QDialog(parent) Splitters
{
... I QSplitter#4'#%#64-&"7#7!%7#3/)7%4)'#/7!"(#64-&"7'1# !"#64-&"7'#4)#%#'$5477"(#%("#'"$%(%7"-#,C
listWidget = new QListWidget;
'$5477"(#!%)-5"'1#U'"('#3%)#3!%)&"#7!"#'4R"'#/.#%#'$5477"(@'#3!45-#64-&"7'#,C#-(%&&4)&#7!"#!%)-5"'1
listWidget->addItem(tr("Appearance"));
listWidget->addItem(tr("Web Browser")); T$5477"('#3%)#/.7")#,"#*'"-#%'#%)#%57"()%748"#7/#5%C/*7#+%)%&"('9#7/#&48"#+/("#3/)7(/5#7/#7!"#*'"(1
listWidget->addItem(tr("Mail & News"));
listWidget->addItem(tr("Advanced")); !"#3!45-#64-&"7'#/.#% QSplitter#%("#%*7/+%743%55C#$5%3"-#'4-"#,C#'4-"#K/(#/)"#,"5/6#7!"#/7!"(O#4)
stackedLayout = new QStackedLayout; 7!"#/(-"(#4)#6!43!#7!"C#%("#3("%7"-9#647!#'$5477"(#,%('#,"76"")#%-V%3")7#64-&"7'1#?"("@'#7!"#3/-"#./(
stackedLayout->addWidget(appearancePage); 3("%74)&#7!"#64)-/6#-"$437"-#4) ;4&*("#<1WA
stackedLayout->addWidget(webBrowserPage);
stackedLayout->addWidget(mailAndNewsPage);
stackedLayout->addWidget(advancedPage); int main(int argc, char *argv[])
connect(listWidget, SIGNAL(currentRowChanged(int)), {
stackedLayout, SLOT(setCurrentIndex(int))); QApplication app(argc, argv);
... QTextEdit *editor1 = new QTextEdit;
listWidget->setCurrentRow(0); QTextEdit *editor2 = new QTextEdit;
} QTextEdit *editor3 = new QTextEdit;
QSplitter splitter(Qt::Horizontal);
splitter.addWidget(editor1);
splitter.addWidget(editor2);
splitter.addWidget(editor3);
...
splitter.show();
return app.exec();
}

!"#$%&'(7(&)1%&8,6!00%$&-,,6!4-0!+3
[View full size image]

!"#"=%+$5"#3/)'4'7'#/.#7!("" QTextEdit'#5%4-#/*7#!/(4R/)7%55C#,C#% QSplitter#64-&"71#U)542" 5%C/*7


+%)%&"('9#6!43!#'4+$5C#5%C#/*7#%#./(+@'#3!45-#64-&"7'#%)-#!%8"#)/#84'*%5#("$("'")7%74/)9 QSplitter
4)!"(47'#.(/+ QWidget#%)-#3%)#,"#*'"-#542"#%)C#/7!"(#64-&"71
?"("@'#7!"#3/-"#4)#7!"#3/)'7(*37/(#/.#7!"#X%45#E54")7#%$$543%74/)@' QMainWindow#'*,35%''A
!"#$%&'(9(&)1%&8,6!00%$&-,,6!4-0!+3:.&*!5"%0.
MailClient::MailClient()
{
...

rightSplitter = new QSplitter(Qt::Vertical);


rightSplitter->addWidget(messagesTreeWidget);
rightSplitter->addWidget(textEdit);
rightSplitter->setStretchFactor(1, 1);
mainSplitter = new QSplitter(Qt::Horizontal);
mainSplitter->addWidget(foldersTreeWidget);
mainSplitter->addWidget(rightSplitter);
mainSplitter->setStretchFactor(1, 1);
setCentralWidget(mainSplitter);
E/+$5"=#5%C/*7'#3%)#,"#%3!4"8"-#,C#)"'74)&#!/(4R/)7%5#%)-#8"(743%5 QSplitter'1#;/(#"=%+$5"9#7!" setWindowTitle(tr("Mail Client"));
X%45#E54")7#%$$543%74/)#'!/6)#4) ;4&*("#<1Y#3/)'4'7'#/.#%#!/(4R/)7%5 QSplitter#7!%7#3/)7%4)'#%#8"(743%5 readSettings();
QSplitter#/)#47'#(4&!7#'4-"1
}

!"#$%&'(;(&)1%&<-!6&=6!%30&-,,6!4-0!+3&+3&<-4&>8&?
I.7"(#3("%74)&#7!"#7!(""#64-&"7'#7!%7#6"#6%)7#7/#-4'$5%C9#6"#3("%7"#%#8"(743%5#'$5477"(9 rightSplitter9
[View full size image] %)-#%--#7!"#76/#64-&"7'#6"#6%)7#/)#7!"#(4&!71# !")#6"#3("%7"#%#!/(4R/)7%5#'$5477"(9 mainSplitter9
%)-#%--#7!"#64-&"7#6"#6%)7#47#7/#-4'$5%C#/)#7!"#5".7#%)- rightSplitter#6!/'"#64-&"7'#6"#6%)7
'!/6)#/)#7!"#(4&!71#B"#+%2" mainSplitter#7!" QMainWindow@'#3")7(%5#64-&"71

B!")#7!"#*'"(#("'4R"'#%#64)-/69 QSplitter#)/(+%55C#-4'7(4,*7"'#7!"#'$%3"#'/#7!%7#7!"#("5%748"#'4R"'
/.#7!"#3!45-#64-&"7'#'7%C#7!"#'%+"1#M)#7!"#X%45#E54")7#"=%+$5"9#6"#-/)@7#6%)7#7!4'#,"!%84/(N#4)'7"%-9
6"#6%)7#7!" QtreeWidget#%)-#7!" QTableWidget#7/#2""$#7!"4(#'4R"'#%)-#6"#6%)7#7/#&48"#%)C#"=7(%
'$%3"#7/#7!" QTextEdit1# !4'#4'#%3!4"8"-#,C#7!"#76/ setStretchFactor()#3%55'1# !"#.4('7#%(&*+")7#4'
7!"#0L,%'"-#4)-"=#/.#7!"#'$5477"(@'#3!45-#64-&"79#%)-#7!"#'"3/)-#%(&*+")7#4'#7!"#'7("73!#.%37/(#6"
6%)7#7/#'"7N#7!"#-".%*57#4'#01

!"#$%&'(@A(&)1%&<-!6&=6!%30:.&.,6!00%$&!35%B!3"
Scrolling Areas
!" QScrollArea#35%''#$(/84-"'#%#'3(/55%,5"#84"6$/(7#%)-#76/#'3(/55#,%('1#M.#6"#6%)7#7/#%--#'3(/55
,%(' 7/#%#64-&"79#47#4'#+*3!#'4+$5"(#7/#*'"#% QScrollArea#7!%)#7/#4)'7%)74%7"#/*(#/6) QScrollBar'
%)-#4+$5"+")7#7!"#'3(/554)&#.*)374/)%547C#/*('"58"'1

!"#$%&'(@@( QScrollArea:.&4+3.0!0#%30&*!5"%0.

!"#.4('7 setStretchFactor()#3%55#4'#/) rightSplitter9#%)-#47#'"7'#7!"#64-&"7#%7#$/'474/)#D#KtextEditO


7/#!%8"#%#'7("73!#.%37/(#/.#D1# !"#'"3/)- setStretchFactor()#3%55#4'#/) mainSplitter9#%)-#47#'"7'#7!"
64-&"7#%7#$/'474/)#D#KrightSplitterO#7/#!%8"#%#'7("73!#.%37/(#/.#D1# !4'#")'*("'#7!%7#7!" textEdit#6455
&"7#%)C#%--474/)%5#'$%3"#7!%7#4'#%8%45%,5"1

B!")#7!"#%$$543%74/)#4'#'7%(7"-9 QSplitter#&48"'#7!"#3!45-#64-&"7'#%$$(/$(4%7"#'4R"'#,%'"-#/)#7!"4(
4)474%5#'4R"'#K/(#,%'"-#/)#7!"4(#'4R"#!4)7#4.#)/#4)474%5#'4R"#4'#'$"34.4"-O1#B"#3%)#+/8"#7!"#'$5477"(
!%)-5"'#$(/&(%++%743%55C#,C#3%554)& QSplitter::setSizes()1# !" QSplitter#35%''#%5'/#$(/84-"'#%
+"%)'#/.#'%84)&#%)-#("'7/(4)&#47'#'7%7"#7!"#)"=7#74+"#7!"#%$$543%74/)#4'#(*)1#?"("@'#7!"
writeSettings()#.*)374/)#7!%7#'%8"'#7!"#X%45#E54")7@'#'"774)&'A !"#6%C#7/#*'" QScrollArea#4'#7/#3%55 setWidget()#647!#7!"#64-&"7#6"#6%)7#7/#%--#'3(/55#,%('#7/1
QScrollArea#%*7/+%743%55C#("$%(")7'#7!"#64-&"7#7/#+%2"#47#%#3!45-#/.#7!"#84"6$/(7#K%33"''4,5"
7!(/*&! QScrollArea::viewport()O#4.#47#4')@7#%5("%-C1#;/(#"=%+$5"9#4.#6"#6%)7#'3(/55#,%('#%(/*)-#7!"
void MailClient::writeSettings() IconEditor#64-&"7#6"#-"8"5/$"-#4) E!%$7"(#S9#6"#3%)#6(47"#7!4'A
{
QSettings settings("Software Inc.", "Mail Client");
settings.beginGroup("mainWindow"); int main(int argc, char *argv[])
settings.setValue("size", size()); {
settings.setValue("mainSplitter", mainSplitter->saveState()); QApplication app(argc, argv);
settings.setValue("rightSplitter", rightSplitter->saveState()); IconEditor *iconEditor = new IconEditor;
settings.endGroup(); iconEditor->setIconImage(QImage(":/images/mouse.png"));
} QScrollArea scrollArea;
scrollArea.setWidget(iconEditor);
scrollArea.viewport()->setBackgroundRole(QPalette::Dark);
?"("@'#7!"#3/(("'$/)-4)& readSettings()#.*)374/)A scrollArea.viewport()->setAutoFillBackground(true);
scrollArea.setWindowTitle(QObject::tr("Icon Editor"));
scrollArea.show();
return app.exec();
void MailClient::readSettings() }
{
QSettings settings("Software Inc.", "Mail Client");
settings.beginGroup("mainWindow");
resize(settings.value("size", QSize(480, 360)).toSize()); !" QScrollArea#$("'")7'#7!"#64-&"7#%7#47'#3*((")7#'4R"#/(#*'"'#7!"#'4R"#!4)7#4.#7!"#64-&"7#!%')@7#,"")
mainSplitter->restoreState( ("'4R"-#C"71#]C#3%554)& setWidgetResizable(true)9#6"#3%)#7"55 QScrollArea#7/#%*7/+%743%55C#("'4R"#7!"
settings.value("mainSplitter").toByteArray()); 64-&"7#7/#7%2"#%-8%)7%&"#/.#%)C#"=7(%#'$%3"#,"C/)-#47'#'4R"#!4)71
rightSplitter->restoreState(
settings.value("rightSplitter").toByteArray());
]C#-".%*579#7!"#'3(/55#,%('#%("#/)5C#-4'$5%C"-#6!")#7!"#84"6$/(7#4'#'+%55"(#7!%)#7!"#3!45-#64-&"71#B"
settings.endGroup();
} 3%)#./(3"#7!"#'3(/55#,%('#7/ %56%C'#,"#'!/6)#,C#'"774)&#'3(/55#,%(#$/5434"'A

scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
QSplitter#4'#.*55C#'*$$/(7"-#,C !"#$%&'($)1# /#$*7#64-&"7'#4)7/#%#'$5477"(9#$5%3"#7!"#3!45-#64-&"7' scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
%$$(/=4+%7"5C#4)#7!"4(#-"'4("-#$/'474/)'9#'"5"37#7!"+9#%)-#35432#;/(+ZQ%C#[*7#?/(4R/)7%55C#4)#T$5477"(
/(#;/(+ZQ%C#[*7#\"(743%55C#4)#T$5477"(1
!"#$%&'(@C(&D%.!E!3"&- QScrollArea
>8"(C#-/32#64-&"7#!%'#47'#/6)#7475"#,%(9#"8")#6!")#47#4'#-/32"-1#U'"('#3%)#+/8"#-/32#64)-/6'#.(/+
/)"#-/32#%("%#7/#%)/7!"(#,C#-(%&&4)&#7!"#7475"#,%(1# !"C#3%)#%5'/#-"7%3!#%#-/32#64)-/6#.(/+#%)
%("%#%)-#5"7#7!"#-/32#64)-/6#.5/%7#%'#%)#4)-"$")-")7#64)-/6#,C#-(%&&4)&#7!"#-/32#64)-/6#/*7'4-"
/.#%)C#-/32#%("%1#;(""L.5/%74)&#-/32#64)-/6'#%("#%56%C'#F/)#7/$F#/.#7!"4(#+%4)#64)-/61#U'"('#3%)
35/'"#% QDockWidget#,C#354324)&#7!"#35/'"#,*77/)#4)#7!"#64-&"7@'#7475"#,%(1#I)C#3/+,4)%74/)#/.#7!"'"
."%7*("'#3%)#,"#-4'%,5"-#,C#3%554)& QDockWidget::setFeatures()1

M)#"%(54"(#8"('4/)'#/.#^79#7//5,%('#6"("#7("%7"-#542"#-/32#64-&"7'#%)-#'!%("-#7!"#'%+"#-/32#%("%'1
T7%(74)&#647!#^7#P9#7//5,%('#/33*$C#7!"4(#/6)#%("%'#%(/*)-#7!"#3")7(%5#64-&"7#K%'#'!/6)#4) ;4&*("
<1DPO#%)-#3%)@7#,"#*)-/32"-1#M.#%#.5/%74)&#7//5,%(#4'#("_*4("-9#6"#3%)#'4+$5C#$*7#47#4)'4-"#%
QDockWindow1

!"#$%&'(@I( QMainWindow:.&5+4H&-35&0++6J-$&-$%-.

QScrollArea#4)!"(47'#+*3!#/.#47'#.*)374/)%547C#.(/+ QAbstractScrollArea1#E5%''"'#542" QTextEdit#%)-


QAbstractItemView#K7!"#,%'"#35%''#/.#^7@'#47"+#84"6#35%''"'O#-"(48"#.(/+ QAbstractScrollArea9#'/#6"
-/)@7#)""-#7/#6(%$#7!"+#4)#% QScrollArea#7/#&"7#'3(/55#,%('1

Dock Widgets and Toolbars


G/32#64-&"7'#%("#64-&"7'#7!%7#3%)#,"#-/32"-#4)'4-"#% QMainWindow#/(#.5/%7"-#%'#4)-"$")-")7
64)-/6'1 QMainWindow#$(/84-"'#./*(#-/32#64-&"7#%("%'A#/)"#%,/8"9#/)"#,"5/69#/)"#7/#7!"#5".79#%)-
/)"#7/#7!"#(4&!7#/.#7!"#3")7(%5#64-&"71#I$$543%74/)'#542"#X43(/'/.7#\4'*%5#T7*-4/#%)- !"*&('+&%!
+%2"#"=7")'48"#*'"#/.#-/32#64)-/6'#7/#$(/84-"#%#8"(C#.5"=4,5"#*'"(#4)7"(.%3"1#M)#^79#-/32#64-&"7'
%("#4)'7%)3"'#/. QDockWidget1

!"#$%&'(@F(&G QMainWindow&*!01&-&5+4H&*!5"%0
[View full size image]

!"#3/()"('#4)-43%7"-#647!#-/77"-#54)"'#3%)#,"5/)&#7/#"47!"(#/.#7!"4(#76/#%-V/4)4)&#-/32#%("%'1#;/(
"=%+$5"9#6"#3/*5-#+%2"#7!"#7/$L5".7#3/()"(#,"5/)&#7/#7!"#5".7#-/32#%("%#,C#3%554)&
QMainWindow::setCorner(Qt::TopLeftCorner, Qt:: LeftDockWidgetArea)1

!"#./55/64)&#3/-"#')4$$"7#'!/6'#!/6#7/#6(%$#%)#"=4'74)&#64-&"7#K4)#7!4'#3%'"9#% QtreeWidgetO#4)#%
QDockWidget#%)-#4)'"(7#47#4)7/#7!"#(4&!7#-/32#%("%A

QDockWidget *shapesDockWidget = new QDockWidget(tr("Shapes"));


shapesDockWidget->setWidget(treeWidget);
shapesDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea
| Qt::RightDockWidgetArea);
addDockWidget(Qt::RightDockWidgetArea, shapesDockWidget);
Multiple Document Interface
!" setAllowedAreas()#3%55#'$"34.4"'#3/)'7(%4)7'#/)#6!43!#-/32#%("%'#3%)#%33"$7#7!"#-/32#64)-/61
I$$543%74/)'#7!%7#$(/84-"#+*574$5"#-/3*+")7'#647!4)#7!"#+%4)#64)-/6@'#3")7(%5#%("%#%("#3%55"-
?"("9#6"#/)5C#%55/6#7!"#*'"(#7/#-(%&#7!"#-/32#64-&"7#4)7/#7!"#5".7#%)-#(4&!7 -/32#%("%'9#6!"("#7!"("
+*574$5"#-/3*+")7#4)7"(.%3"#%$$543%74/)'9#/(#XGM#%$$543%74/)'1#M)#^79#%)#XGM#%$$543%74/)#4'#3("%7"-
4'#")/*&!#8"(743%5#'$%3"#./(#47#7/#,"#-4'$5%C"-#'")'4,5C1#M.#)/#%55/6"-#%("%'#%("#"=$543475C#'"79#7!"
,C#*'4)&#7!" QWorkspace#35%''#%'#7!"#3")7(%5#64-&"7#%)-#,C#+%24)&#"%3!#-/3*+")7#64)-/6#%#3!45-#/.
*'"(#3%)#-(%&#7!"#-/32#64-&"7#7/#%)C#/.#7!"#./*(#%("%'1
7!" QWorkspace1
?"("@'#!/6#7/#3("%7"#%#7//5,%(#3/)7%4)4)&#% QComboBox9#% QSpinBox9#%)-#%#."6 QToolButton'#.(/+#%
M7#4'#3/)8")74/)%5#./(#XGM#%$$543%74/)'#7/#$(/84-"#%#B4)-/6#+")*#7!%7#4)35*-"'#'/+"#3/++%)-'#./(
QMainWindow#'*,35%''@'#3/)'7(*37/(A
+%)%&4)&#7!"#64)-/6'#%)-#7!"#54'7#/.#64)-/6'1# !"#%3748"#64)-/6#4'#4-")74.4"-#647!#%#3!"32+%(21
!"#*'"(#3%)#+%2"#%)C#64)-/6#%3748"#,C#354324)&#47'#")7(C#4)#7!"#B4)-/6#+")*1
QToolBar *fontToolBar = new QToolBar(tr("Font"));
fontToolBar->addWidget(familyComboBox); M)#7!4'#'"374/)9#6"#6455#-"8"5/$#7!"#XGM#>-47/(#%$$543%74/)#'!/6)#4) ;4&*("#<1D<#7/#-"+/)'7(%7"#!/6
fontToolBar->addWidget(sizeSpinBox); 7/#3("%7"#%)#XGM#%$$543%74/)#%)-#!/6#7/#4+$5"+")7#47'#B4)-/6#+")*1
fontToolBar->addAction(boldAction);
fontToolBar->addAction(italicAction); !"#$%&'(@'(&)1%&<MN&O5!0+$&-,,6!4-0!+3
fontToolBar->addAction(underlineAction);
fontToolBar->setAllowedAreas(Qt::TopToolBarArea [View full size image]

| Qt::BottomToolBarArea);
addToolBar(fontToolBar);

M.#6"#6%)7#7/#'%8"#7!"#$/'474/)#/.#%55#7!"#-/32#64-&"7'#%)-#7//5,%('#'/#7!%7#6"#3%)#("'7/("#7!"+#7!"
)"=7#74+"#7!"#%$$543%74/)#4'#(*)9#6"#3%)#6(47"#3/-"#7!%7#4'#'4+45%(#7/#7!"#3/-"#6"#*'"-#7/#'%8"#%
QSplitter@'#'7%7"9#*'4)& QMainWindow@' saveState()#%)- restoreState()#.*)374/)'A

void MainWindow::writeSettings()
{
QSettings settings("Software Inc.", "Icon Editor");
settings.beginGroup("mainWindow");
settings.setValue("size", size());
settings.setValue("state", saveState());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("Software Inc.", "Icon Editor");
settings.beginGroup("mainWindow");
resize(settings.value("size").toSize());
restoreState(settings.value("state").toByteArray());
settings.endGroup();
}

;4)%55C9 QMainWindow#$(/84-"'#%#3/)7"=7#+")*#7!%7#54'7'#%55#7!"#-/32#64)-/6'#%)-#7//5,%('1# !"#*'"(


3%)#35/'"#%)-#("'7/("#-/32#64)-/6'#%)-#!4-"#%)-#("'7/("#7//5,%('#*'4)&#7!4'#+")*1 !"#%$$543%74/)#3/)'4'7'#/.#76/#35%''"'A MainWindow#%)- Editor1# !"#3/-"#4'#/)#7!"#EG9#%)-#'4)3"
+/'7#/.#47#4'#7!"#'%+"#/(#'4+45%(#7/#7!"#T$("%-'!""7#%$$543%74/)#.(/+ :%(7#M9#6"#6455#/)5C#$("'")7#7!"
)"6#3/-"1
!"#$%&'(@K(&G QMainWindow&4+30%B0&L%3#
!"#$%&'(@7(&)1%&<MN&O5!0+$&-,,6!4-0!+3:.&L%3#.
[View full size image]
!" createEditor()#.*)374/)#3("%7"'#%) Editor#64-&"7#%)-#'"7'#*$#76/#'4&)%5'5/7#3/))"374/)'1# !"'"
3/))"374/)'#")'*("#7!%7#>-47ZE*7#%)-#>-47ZE/$C#%("#")%,5"-#/(#-4'%,5"-#-"$")-4)&#/)#6!"7!"(#7!"("
4'#%)C#'"5"37"-#7"=71

]"3%*'"#6"#%("#*'4)&#XGM9#47#4'#$/''4,5"#7!%7#7!"("#6455#,"#+*574$5" Editor#64-&"7'#4)#*'"1# !4'#4'#%


3/)3"()#'4)3"#6"#%("#/)5C 4)7"("'7"-#4)#("'$/)-4)&#7/#7!" copyAvailable(bool)#'4&)%5#.(/+#7!"#%3748"
Editor#64)-/69#)/7#.(/+#7!"#/7!"('1#]*7#7!"'"#'4&)%5'#3%)#/)5C#"8"(#,"#"+477"-#,C#7!"#%3748"
64)-/69#'/#7!4'#4')@7#%#$(/,5"+#4)#$(%3743"1

[)3"#6"#!%8"#'"7#*$#7!" Editor9#6"#%--#% QAction#("$("'")74)&#7!"#64)-/6#7/#7!"#B4)-/6#+")*1


!"#%374/)#4'#$(/84-"-#,C#7!" Editor#35%''9#6!43!#6"#6455#3/8"(#4)#%#+/+")71#B"#%5'/#%--#7!"#%374/)
Q"7@'#'7%(7#647!#7!" MainWindow#35%''1 7/#% QActionGroup#/,V"371# !" QActionGroup#")'*("'#7!%7#/)5C#/)"#B4)-/6#+")*#47"+#4'#3!"32"-#%7#%
74+"1

MainWindow::MainWindow()
{ void MainWindow::open()
workspace = new QWorkspace; {
setCentralWidget(workspace); Editor *editor = createEditor();
connect(workspace, SIGNAL(windowActivated(QWidget *)), if (editor->open()) {
this, SLOT(updateMenus())); editor->show();
createActions(); } else {
createMenus(); editor->close();
createToolBars(); }
createStatusBar(); }
setWindowTitle(tr("MDI Editor"));
setWindowIcon(QPixmap(":/images/icon.png"));
} !" open()#.*)374/)#3/(("'$/)-'#7/#;45"Z[$")1#M7#3("%7"'#%) Editor#./(#7!"#)"6#-/3*+")7#%)-#3%55'
open()#/)#7!" Editor1#M7#+%2"'#+/("#'")'"#7/#4+$5"+")7#7!"#.45"#/$"(%74/)'#4)#7!" Editor#35%''#7!%)
4)#7!" MainWindow#35%''9#,"3%*'"#"%3! Editor#)""-'#7/#+%4)7%4)#47'#/6)#4)-"$")-")7#'7%7"1
M)#7!" MainWindow#3/)'7(*37/(9#6"#3("%7"#% QWorkspace#64-&"7#%)-#+%2"#47#7!"#3")7(%5#64-&"71#B"
3/))"37#7!" QWorkspace@' windowActivated()#'4&)%5#7/#7!"#'5/7#6"#6455#*'"#7/#2""$#7!"#64)-/6#+")* M.#7!" open()#.%45'9#6"#'4+$5C#35/'"#7!"#"-47/(#'4)3"#7!"#*'"(#6455#!%8"#%5("%-C#,"")#)/74.4"-#/.#7!"
*$#7/#-%7"1 "((/(1#B"#-/)@7#)""-#7/#"=$543475C#-"5"7"#7!" Editor#/,V"37#/*('"58"'N#7!4'#4'#-/)"#%*7/+%743%55C#,C
Editor#7!(/*&!#7!" Qt::WA_DeleteOn-Close#64-&"7#%77(4,*7"9#6!43!#4'#'"7#4)#7!" Editor#3/)'7(*37/(1

void MainWindow::newFile()
{ void MainWindow::save()
Editor *editor = createEditor(); {
editor->newFile(); if (activeEditor())
editor->show(); activeEditor()->save();
} }

!" newFile()#'5/7#3/(("'$/)-'#7/#7!"#;45"Z`"6#+")*#/$74/)1#M7#-"$")-'#/)#7!" createEditor() !" save()#'5/7#3%55' Editor::save()#/)#7!"#%3748"#"-47/(9#4.#7!"("#4'#/)"1#I&%4)9#7!"#3/-"#7!%7


$(48%7"#.*)374/)#7/#3("%7"#%#3!45- Editor#64-&"71 $"(./(+'#7!"#("%5#6/(2#4'#5/3%7"-#4)#7!" Editor#35%''1

Editor *MainWindow::createEditor() Editor *MainWindow::activeEditor()


{ {
Editor *editor = new Editor; return qobject_cast<Editor *>(workspace->activeWindow());
connect(editor, SIGNAL(copyAvailable(bool)), }
cutAction, SLOT(setEnabled(bool)));
connect(editor, SIGNAL(copyAvailable(bool)),
copyAction, SLOT(setEnabled(bool)));
workspace->addWindow(editor); !" activeEditor()#$(48%7"#.*)374/)#("7*()'#7!"#%3748"#3!45-#64)-/6#%'#%) Editor#$/4)7"(9#/(#%#)*55
windowMenu->addAction(editor->windowMenuAction()); $/4)7"(#4.#7!"("#4')@7#/)"1
windowActionGroup->addAction(editor->windowMenuAction());
return editor;
} void MainWindow::cut()
{
if (activeEditor())
activeEditor()->cut();
} void MainWindow::closeEvent(QCloseEvent *event)
{
workspace->closeAllWindows();
if (activeEditor()) {
!" cut()#'5/7#3%55' Editor::cut()#/)#7!"#%3748"#"-47/(1#B"#-/)@7#'!/6#7!" copy()#%)- paste()#'5/7' event->ignore();
,"3%*'"#7!"C#./55/6#7!"#'%+"#$%77"()1 } else {
event->accept();
}
void MainWindow::updateMenus() }
{
bool hasEditor = (activeEditor() != 0);
bool hasSelection = activeEditor()
&& activeEditor()->textCursor().hasSelection(); !" closeEvent()#.*)374/)#4'#("4+$5"+")7"-#7/#35/'"#%55#3!45-#64)-/6'9#3%*'4)&#"%3!#3!45-#7/#("3"48"
saveAction->setEnabled(hasEditor); %#35/'"#"8")71#M.#/)"#/.#7!"#3!45-#64-&"7'#F4&)/("'F#47'#35/'"#"8")7#K,"3%*'"#7!" *'"(#3%)3"5"-#%)
saveAsAction->setEnabled(hasEditor); F*)'%8"-#3!%)&"'F#+"''%&"#,/=O9#6"#4&)/("#7!"#35/'"#"8")7#./(#7!" MainWindowN#/7!"(64'"9#6"
pasteAction->setEnabled(hasEditor); %33"$7#479#("'*574)&#4)#^7#35/'4)&#7!"#")74("#64)-/61#M.#6"#-4-)@7#("4+$5"+")7 closeEvent()#4)
cutAction->setEnabled(hasSelection); MainWindow9#7!"#*'"(#6/*5-#)/7#,"#&48")#7!"#/$$/(7*)47C#7/#'%8"#*)'%8"-#3!%)&"'1
copyAction->setEnabled(hasSelection);
closeAction->setEnabled(hasEditor);
B"#!%8"#)/6#.4)4'!"-#/*(#("84"6#/. MainWindow9#'/#6"#3%)#+/8"#/)#7/#7!" Editor#4+$5"+")7%74/)1
closeAllAction->setEnabled(hasEditor);
tileAction->setEnabled(hasEditor); !" Editor#35%''#("$("'")7'#/)"#3!45-#64)-/61#M7#4)!"(47' QTextEdit9#6!43!#$(/84-"'#7!"#7"=7#"-474)&
cascadeAction->setEnabled(hasEditor); .*)374/)%547C1#a*'7#%'#%)C#^7#64-&"7#3%)#,"#*'"-#%'#%#'7%)-L%5/)"#64)-/69#%)C#^7#64-&"7#3%)#,"
nextAction->setEnabled(hasEditor); *'"-#%'#%#3!45-#64)-/6#4)#%)#XGM#6/(2'$%3"1
previousAction->setEnabled(hasEditor);
separatorAction->setVisible(hasEditor); ?"("@'#7!"#35%''#-".4)474/)A
if (activeEditor())
activeEditor()->windowMenuAction()->setChecked(true);
} class Editor : public QTextEdit
{
Q_OBJECT
!" updateMenus()#'5/7#4'#3%55"-#6!")"8"(#%#64)-/6#4'#%3748%7"-#K%)-#6!")#7!"#5%'7#64)-/6#4' public:
35/'"-O#7/#*$-%7"#7!"#+")*#'C'7"+9#-*"#7/#7!"#'4&)%5'5/7#3/))"374/)#6"#$*7#4)#7!" MainWindow Editor(QWidget *parent = 0);
void newFile();
3/)'7(*37/(1
bool open();
bool openFile(const QString &fileName);
X/'7#+")*#/$74/)'#/)5C#+%2"#'")'"#4.#7!"("#4'#%)#%3748"#64)-/69#'/#6"#-4'%,5"#7!"+#4.#7!"("#4')@7 bool save();
/)"1#I7#7!"#")-9#6"#3%55 setChecked()#/)#7!" QAction#("$("'")74)&#7!"#%3748"#64)-/61# !%)2'#7/#7!" bool saveAs();
QActionGroup9#6"#-/)@7#)""-#7/#"=$543475C#*)3!"32#7!"#$("84/*'5C#%3748"#64)-/61 QSize sizeHint() const;
QAction *windowMenuAction() const { return action; }
protected:
void MainWindow::createMenus() void closeEvent(QCloseEvent *event);
{ private slots:
... void documentWasModified();
windowMenu = menuBar()->addMenu(tr("&Window")); private:
windowMenu->addAction(closeAction); bool okToContinue();
windowMenu->addAction(closeAllAction); bool saveFile(const QString &fileName);
windowMenu->addSeparator(); void setCurrentFile(const QString &fileName);
windowMenu->addAction(tileAction); bool readFile(const QString &fileName);
windowMenu->addAction(cascadeAction); bool writeFile(const QString &fileName);
windowMenu->addSeparator(); QString strippedName(const QString &fullFileName);
windowMenu->addAction(nextAction); QString curFile;
windowMenu->addAction(previousAction); bool isUntitled;
windowMenu->addAction(separatorAction); QString fileFilters;
... QAction *action;
} };

!" createMenus()#$(48%7"#.*)374/)#.455'#7!"#B4)-/6#+")*#647!#%374/)'1# !"#%374/)'#%("#%55#7C$43%5#/. ;/*(#/.#7!"#$(48%7"#.*)374/)'#7!%7#6"("#4)#7!"#T$("%-'!""7#%$$543%74/)@' Main-Window#35%''#K$1#SWO#%("


'*3!#+")*'#%)-#%("#"%'45C#4+$5"+")7"-#*'4)& QWorkspace@' closeActiveWindow()9 closeAllWindows()9 %5'/#$("'")7#4)#7!" Editor#35%''A okToContinue()9 save-File()9 setCurrentFile()9#%)- strippedName()1
tile()9#%)- cascade()#'5/7'1#>8"(C#74+"#7!"#*'"(#/$")'#%#)"6#64)-/69#47#4'#%--"-#7/#7!"#B4)-/6
+")*@'#54'7#/.#%374/)'1#K !4'#4'#-/)"#4)#7!" createEditor()#.*)374/)#7!%7#6"#'%6#/)#$%&"#DSP1O#B!")
7!"#*'"(#35/'"'#%)#"-47/(#64)-/69#47'#%374/)#4)#7!"#B4)-/6#+")*#4'#-"5"7"-#K'4)3"#7!"#%374/)#4' Editor::Editor(QWidget *parent)
: QTextEdit(parent)
/6)"-#,C#7!"#"-47/(#64)-/6O9#%)-#'/#7!"#%374/)#4'#%*7/+%743%55C#("+/8"-#.(/+#7!"#B4)-/6#+")*1
{
action = new QAction(this);
action->setCheckable(true);
connect(action, SIGNAL(triggered()), this, SLOT(show())); !" open()#.*)374/)#7(4"'#7/#/$")#%)#"=4'74)&#.45"#*'4)& openFile()1
connect(action, SIGNAL(triggered()), this, SLOT(setFocus()));
isUntitled = true;
fileFilters = tr("Text files (*.txt)\n"
"All files (*)"); bool Editor::save()
connect(document(), SIGNAL(contentsChanged()), {
this, SLOT(documentWasModified())); if (isUntitled) {
setWindowIcon(QPixmap(":/images/document.png")); return saveAs();
setAttribute(Qt::WA_DeleteOnClose); } else {
} return saveFile(curFile);
}
}

;4('79#6"#3("%7"#% QAction#("$("'")74)&#7!"#"-47/(#4)#7!"#%$$543%74/)@'#B4)-/6#+")*#%)-#3/))"37#7!%7
%374/)#7/#7!" show()#%)- setFocus()#'5/7'1
!" save()#.*)374/)#*'"'#7!" isUntitled#8%(4%,5"#7/#-"7"(+4)"#6!"7!"(#47#'!/*5-#3%55 saveFile()#/(
saveAs()1
T4)3"#6"#%55/6#*'"('#7/#3("%7"#%)C#)*+,"(#/.#"-47/(#64)-/6'9#6"#+*'7#+%2"#'/+"#$(/84'4/)#./(
)%+4)&#7!"+#'/#7!%7#7!"C#3%)#,"#-4'74)&*4'!"-#,"./("#7!"C#!%8"#,"")#'%8"-#./(#7!"#.4('7#74+"1#[)"
3/++/)#6%C#/.#!%)-54)&#7!4'#4'#7/#%55/3%7"#)%+"'#7!%7#4)35*-"#%#)*+,"(#K./(#"=%+$5"9 void Editor::closeEvent(QCloseEvent *event)
document1.txtO1#B"#*'"#7!" isUntitled#8%(4%,5"#7/#-4'74)&*4'!#,"76"")#)%+"'#'*$$54"-#,C#7!"#*'"( {
%)-#)%+"'#6"#!%8"#3("%7"-#$(/&(%++%743%55C1 if (okToContinue()) {
event->accept();
B"#3/))"37#7!"#7"=7#-/3*+")7@' contentsChanged()#'4&)%5#7/#7!"#$(48%7" documentWasModified()#'5/71 } else {
!4'#'5/7#'4+$5C#3%55' setWindowModified(true)1 event->ignore();
}
}
;4)%55C9#6"#'"7#7!" Qt::WA_DeleteOnClose#%77(4,*7"#7/#$("8")7#+"+/(C#5"%2'#6!")#7!"#*'"(#35/'"'#%)
Editor#64)-/61

!" closeEvent()#.*)374/)#4'#("4+$5"+")7"-#7/#%55/6#7!"#*'"(#7/#'%8"#*)'%8"-#3!%)&"'1# !"#5/&43#4'


I.7"(#7!"#3/)'7(*37/(9#6"#"=$"37#"47!"( newFile()#/( open()#7/#,"#3%55"-1
3/-"-#4)#7!" okToContinue()#.*)374/)9#6!43!#$/$'#*$#%#+"''%&"#,/=#7!%7#%'2'9#FG/#C/*#6%)7#7/#'%8"
C/*(#3!%)&"'gF#M. okToContinue()#("7*()' TRue9#6"#%33"$7#7!"#35/'"#"8")7N#/7!"(64'"9#6"#F4&)/("F#47
%)-#5"%8"#7!"#64)-/6#*)%.."37"-#,C#471
void Editor::newFile()
{
static int documentNumber = 1;
curFile = tr("document%1.txt").arg(documentNumber); void Editor::setCurrentFile(const QString &fileName)
setWindowTitle(curFile + "[*]"); {
action->setText(curFile); curFile = fileName;
isUntitled = true; isUntitled = false;
++documentNumber; action->setText(strippedName(curFile));
}
document()->setModified(false);
setWindowTitle(strippedName(curFile) + "[*]");
setWindowModified(false);
!" newFile()#.*)374/)#&")"(%7"'#%#)%+"#542" document1.txt#./(#7!"#)"6#-/3*+")71# !"#3/-" }
,"5/)&'#4) newFile()9#(%7!"(#7!%)#7!"#3/)'7(*37/(9#,"3%*'"#6"#-/)@7#6%)7#7/#3/)'*+"#)*+,"('#6!")
6"#3%55 open()#7/#/$")#%)#"=4'74)&#-/3*+")7#4)#%#)"65C#3("%7"- Editor1#T4)3" documentNumber#4'
-"35%("-#'7%7439#47#4'#'!%("-#%3(/''#%55 Editor#4)'7%)3"'1 !" setCurrentFile()#.*)374/)#4'#3%55"-#.(/+ openFile()#%)- saveFile()#7/#*$-%7"#7!" curFile#%)-
isUntitled#8%(4%,5"'9#7/#'"7#7!"#64)-/6#7475"#%)-#%374/)#7"=79#%)-#7/#'"7#7!"#-/3*+")7@'#F+/-4.4"-F
!"#FbcdF#+%(2"(#4)#7!"#64)-/6#7475"#4'#%#$5%3"#+%(2"(#./(#6!"("#6"#6%)7#7!"#%'7"(4'2#7/#%$$"%( .5%&#7/ false1#B!")"8"(#7!"#*'"(#+/-4.4"'#7!"#7"=7#4)#7!"#"-47/(9#7!"#*)-"(5C4)& QTexTDocument#"+47'
6!")#7!"#.45"#!%'#*)'%8"-#3!%)&"'#/)#$5%7./(+'#/7!"(#7!%)#X%3#[T#e1#B"#3/8"("-#7!4'#$5%3"#+%(2"( 7!" contents-Changed()#'4&)%5#%)-#'"7'#47'#4)7"()%5#F+/-4.4"-F#.5%&#7/ true1
4) E!%$7"(#J#K$1#SfO1

QSize Editor::sizeHint() const


bool Editor::open() {
{ return QSize(72 * fontMetrics().width('x'),
QString fileName = 25 * fontMetrics().lineSpacing());
QFileDialog::getOpenFileName(this, tr("Open"), ".", }
fileFilters);
if (fileName.isEmpty())
return false;
return openFile(fileName); !" sizeHint()#.*)374/)#("7*()'#%#'4R"#,%'"-#/)#7!"#64-7!#/.#7!"#5"77"(#@=@#%)-#7!"#!"4&!7#/.#%#7"=7
}
54)"1 QWorkspace#*'"'#7!"#'4R"#!4)7#7/#&48"#%)#4)474%5#'4R"#7/#7!"#64)-/61

?"("@'#7!"#XGM#>-47/(#%$$543%74/)@' main.cpp#.45"A Chapter 7. Event Processing


• !"#$%!#!&'"&()*+!&'),-&.%!/0
#include <QApplication> • 1&0'-%%"&()*+!&')2"%'!/0
#include "mainwindow.h" • 3'-4"&() !0$5&0"+!)67/"&()1&'!&0"+!)8/59!00"&(
int main(int argc, char *argv[])
{
QApplication app(argc, argv); >8")7'#%("#&")"(%7"-#,C#7!"#64)-/6#'C'7"+#/(#,C#^7#47'"5.#4)#("'$/)'"#7/#8%(4/*'#/33*((")3"'1
QStringList args = app.arguments(); B!")#7!"#*'"(#$("''"'#/(#("5"%'"'#%#2"C#/(#+/*'"#,*77/)9#%#2"C#/(#+/*'"#"8")7#4'#&")"(%7"-N#6!")
MainWindow mainWin; %#64)-/6#4'#'!/6)#./(#7!"#.4('7#74+"9#%#$%4)7#"8")7#4'#&")"(%7"-#7/#7"55#7!"#)"65C 84'4,5"#64)-/6#7!%7
if (args.count() > 1) { 47#)""-'#7/#-(%6#47'"5.1#X/'7#"8")7'#%("#&")"(%7"-#4)#("'$/)'"#7/#*'"(#%374/)'9#,*7#'/+"9#542"#74+"(
for (int i = 1; i < args.count(); ++i) "8")7'9#%("#&")"(%7"-#4)-"$")-")75C#,C#7!"#'C'7"+1
mainWin.openFile(args[i]);
} else { B!")#6"#$(/&(%+#647!#^79#6"#'"5-/+#)""-#7/#7!4)2#%,/*7#"8")7'9#,"3%*'"#^7#64-&"7'#"+47#'4&)%5'
mainWin.newFile(); 6!")#'/+"7!4)&#'4&)4.43%)7#/33*('1#>8")7'#,"3/+"#*'".*5#6!")#6"#6(47"#/*(#/6)#3*'7/+#64-&"7'#/(
}
6!")#6"#6%)7#7/#+/-4.C#7!"#,"!%84/(#/.#"=4'74)&#^7#64-&"7'1
mainWin.show();
return app.exec();
} >8")7'#'!/*5-#)/7#,"#3/).*'"-#647!#'4&)%5'1#I'#%#(*5"9#'4&)%5'#%("#*'".*5#6!") +%&('#%#64-&"79
6!"("%'#"8")7'#%("#*'".*5#6!") &,-.$,$(!&('#%#64-&"71#;/(#"=%+$5"9#6!")#6"#%("#*'4)&
QPushButton9#6"#%("#+/("#4)7"("'7"-#4)#47' clicked()#'4&)%5#7!%)#4)#7!"#5/6L5"8"5#+/*'"#/(#2"C
"8")7'#7!%7#3%*'"-#7!"#'4&)%5#7/#,"#"+477"-1#]*7#4.#6"#%("#4+$5"+")74)&#%#35%''#542" QPushButton9#6"
M.#7!"#*'"(#'$"34.4"'#%)C#.45"'#/)#7!"#3/++%)-#54)"9#6"#%77"+$7#7/#5/%-#7!"+1#[7!"(64'"9#6"#'7%(7
)""-#7/#6(47"#3/-"#7/#!%)-5"#+/*'"#%)-#2"C#"8")7'#%)-#"+47#7!" clicked()#'4&)%5#6!")#)"3"''%(C1
647!#%)#"+$7C#-/3*+")71#^7L'$"34.43#3/++%)-L54)"#/$74/)'9#'*3!#%' -style#%)- -font9#%("
%*7/+%743%55C#("+/8"-#.(/+#7!"#%(&*+")7#54'7#,C#7!" QApplication#3/)'7(*37/(1#T/#4.#6"#6(47"

mdieditor -style motif readme.txt


D%!L,6%L%30!3"&OP%30&Q-356%$.

/)#7!"#3/++%)-#54)"9 QApplication::arguments()#("7*()'#% QStringList#3/)7%4)4)&#76/#47"+' M)#^79#%)#"8")7#4'#%)#/,V"37#7!%7#4)!"(47' QEvent1#^7#!%)-5"'#+/("#7!%)#%#!*)-("-#7C$"'#/.#"8")79


KF+-4"-47/(F#%)-#F("%-+"17=7FO9#%)-#7!"#XGM#>-47/(#%$$543%74/)#'7%(7'#*$#647!#7!"#-/3*+")7 "%3!#4-")74.4"-#,C#%)#")*+#8%5*"1#;/(#"=%+$5"9 QEvent::type()#("7*()' QEvent::MouseButtonPress#./(
readme.txt1 +/*'"#$("''#"8")7'1

XGM#4'#/)"#6%C#/.#!%)-54)&#+*574$5"#-/3*+")7'#'4+*57%)"/*'5C1#[)#X%3#[T#e9#7!"#$("."(("- X%)C#"8")7#7C$"'#("_*4("#+/("#4)./(+%74/)#7!%)#3%)#,"#'7/("-#4)#%#$5%4) QEvent#/,V"37N#./(#"=%+$5"9


%$$(/%3!#4'#7/#*'"#+*574$5"#7/$L5"8"5#64)-/6'1# !4'#%$$(/%3!#4'#3/8"("-#4)#7!"#FX*574$5"#G/3*+")7'F +/*'"#$("''#"8")7'#)""-#7/#'7/("#6!43!#+/*'"#,*77/)#7(4&&"("-#7!"#"8")7#%'#6"55#%'#6!"(" 7!"
'"374/)#/. E!%$7"(#J1 +/*'"#$/4)7"(#6%'#$/'474/)"-#6!")#7!"#"8")7#/33*(("-1# !4'#%--474/)%5#4)./(+%74/)#4'#'7/("-#4)
-"-43%7"- QEvent#'*,35%''"'9#'*3!#%' QMouseEvent1

>8")7'#%("#)/74.4"-#7/#/,V"37'#7!(/*&!#7!"4( event()#.*)374/)9#4)!"(47"-#.(/+ QObject1# !" event()


4+$5"+")7%74/)#4) QWidget#./(6%(-'#7!"#+/'7#3/++/)#7C$"'#/.#"8")7#7/#'$"34.43#"8")7#!%)-5"('9
'*3!#%' mousePressEvent()9 keyPress-Event()9#%)- paintEvent()1

B"#!%8"#%5("%-C#'"")#+%)C#"8")7#!%)-5"('#6!")#4+$5"+")74)& MainWindow9 IconEditor9#%)- Plotter


4)#"%(54"(#3!%$7"('1# !"("#%("#+%)C#/7!"(#7C$"'#/.#"8")7#54'7"-#4)#7!" QEvent#("."(")3"
-/3*+")7%74/)9#%)-#47#4'#%5'/#$/''4,5"#7/#3("%7"#3*'7/+#"8")7#7C$"'#%)-#7/#-4'$%73!#"8")7'
/*('"58"'1#?"("9#6"#6455#("84"6#76/#3/++/)#"8")7#7C$"'#7!%7#-"'"(8"#+/("#"=$5%)%74/)A#2"C#"8")7'
%)-#74+"(#"8")7'1

h"C#"8")7'#%("#!%)-5"-#,C#("4+$5"+")74)& keyPressEvent()#%)- keyRelease-Event()1# !" Plotter


64-&"7#("4+$5"+")7' keyPressEvent()1#`/(+%55C9#6"#/)5C#)""-#7/#("4+$5"+")7 keyPressEvent()
'4)3"#7!"#/)5C#2"C'#./(#6!43!#("5"%'"#4'#4+$/(7%)7#%("#7!"#+/-4.4"(#2"C'#E7(59#T!4.79#%)-#I579#%)-
7!"'"#3%)#,"#3!"32"-#./(#4)#% keyPressEvent()#*'4)& QKeyEvent::modifiers()1#;/(#"=%+$5"9#4.#6"
6"("#4+$5"+")74)&#% CodeEditor#64-&"79#47'#'7(4$$"-L-/6) keyPressEvent()#7!%7#-4'74)&*4'!"'
,"76"")#?/+"#%)-#E7(5i?/+"#6/*5-#5//2#542"#7!4'A

void CodeEditor::keyPressEvent(QKeyEvent *event)


{
switch (event->key()) {
case Qt::Key_Home: 3/++%)-'#-/)@7#%$$"%(#4)#7!"#*'"(#4)7"(.%3"9#7!" QAction#/,V"37'#3/*5-#,"#("$5%3"-#647!#% QShortcut
if (event->modifiers() & Qt::ControlModifier) { /,V"379#7!"#35%''#*'"-#,C QAction#4)7"()%55C#7/#'*$$/(7#2"C#,4)-4)&'1
goToBeginningOfDocument();
} else {
goToBeginningOfLine(); ]C#-".%*579#2"C#,4)-4)&'#'"7#*'4)& QAction#/( QShortcut#/)#%#64-&"7#%("#")%,5"-#6!")"8"(#7!"
} 64)-/6#7!%7#3/)7%4)'#7!"#64-&"7#4'#%3748"1# !4'#3%)#,"#3!%)&"-#*'4)& QAction::setShortcutContext()
break; /( QShortcut::setContext()1
case Qt::Key_End:
... I)/7!"(#3/++/)#7C$"#/.#"8")7#4'#7!"#74+"(#"8")71#B!45"#+/'7#/7!"(#"8")7#7C$"'#/33*(#%'#%#("'*57#/.
default: %#*'"(#%374/)9#74+"(#"8")7'#%55/6#%$$543%74/)'#7/#$"(./(+#$(/3"''4)&#%7#("&*5%(#74+"#4)7"(8%5'1# 4+"(
QWidget::keyPressEvent(event); "8")7'#3%)#,"#*'"-#7/#4+$5"+")7#,54)24)&#3*('/('#%)-#/7!"(#%)4+%74/)'9#/(#'4+$5C#7/#(".("'!#7!"
} -4'$5%C1
}

/#-"+/)'7(%7"#74+"(#"8")7'9#6"#6455#4+$5"+")7#% Ticker#64-&"71# !4'#64-&"7#'!/6'#%#7"=7#,%))"(


7!%7#'3(/55'#5".7#,C#/)"#$4="5#"8"(C#J0#+4554'"3/)-'1#M.#7!"#64-&"7#4'#64-"(#7!%)#7!"#7"=79#7!"#7"=7#4'
!"# %,#%)-#]%327%,#KT!4.7i %,O#2"C'#%("#'$"34%5#3%'"'1# !"C#%("#!%)-5"-#,C QWidget::event() ("$"%7"-#%'#/.7")#%'#)"3"''%(C#7/#.455#7!"#")74("#64-7!#/.#7!"#64-&"71
,"./("#47#3%55' keyPressEvent()9#647!#7!"#'"+%)743#/.#$%''4)&#7!"#./3*'#7/#7!"#)"=7#/(#$("84/*'#64-&"7
4)#7!"#./3*'#3!%4)1# !4'#,"!%84/(#4'#*'*%55C#6!%7#6"#6%)79#,*7#4)#% CodeEditor#64-&"79#6"#+4&!7
$("."(#7/#+%2"# %,#4)-")7#%#54)"1# !" event()#("4+$5"+")7%74/)#6/*5-#7!")#5//2#542"#7!4'A
!"#$%&7(@(&)1% Ticker&*!5"%0

bool CodeEditor::event(QEvent *event)


{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) { ?"("@'#7!"#!"%-"(#.45"A
insertAtCurrentPosition('\t');
return true;
} #ifndef TICKER_H
} #define TICKER_H
return QWidget::event(event); #include <QWidget>
} class Ticker : public QWidget
{
Q_OBJECT
M.#7!"#"8")7#4'#%#2"C#$("''9#6"#3%'7#7!" QEvent#/,V"37#7/#% QKeyEvent#%)-#3!"32#6!43!#2"C#6%' Q_PROPERTY(QString text READ text WRITE setText)
$("''"-1#M.#7!"#2"C#4'# %,9#6"#-/#'/+"#$(/3"''4)&#%)-#("7*() true#7/#7"55#^7#7!%7#6" !%8"#!%)-5"- public:
Ticker(QWidget *parent = 0);
7!"#"8")71#M.#6"#("7*()"- false9#^7#6/*5-#$(/$%&%7"#7!"#"8")7#7/#7!"#$%(")7#64-&"71
void setText(const QString &newText);
QString text() const { return myText; }
I#!4&!"(L5"8"5#%$$(/%3!#./(#4+$5"+")74)&#2"C#,4)-4)&'#4'#7/#*'"#% QAction1#;/(#"=%+$5"9#4. QSize sizeHint() const;
goToBeginningOfLine()#%)- goToBeginningOfDocument()#%("#$*,543#'5/7'#4)#7!" CodeEditor#64-&"79#%)- protected:
7!" CodeEditor#4'#*'"-#%'#7!"#3")7(%5#64-&"7#4)#% MainWindow#35%''9#6"#3/*5-#%--#7!"#2"C#,4)-4)&' void paintEvent(QPaintEvent *event);
647!#7!"#./55/64)&#3/-"A void timerEvent(QTimerEvent *event);
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
MainWindow::MainWindow() private:
{ QString myText;
editor = new CodeEditor; int offset;
setCentralWidget(editor); int myTimerId;
goToBeginningOfLineAction = };
new QAction(tr("Go to Beginning of Line"), this); #endif
goToBeginningOfLineAction->setShortcut(tr("Home"));
connect(goToBeginningOfLineAction, SIGNAL(activated()),
editor, SLOT(goToBeginningOfLine())); B"#("4+$5"+")7#./*(#"8")7#!%)-5"('#4) Ticker9#7!(""#/.#6!43!#6"#!%8"#)/7#'"")#,"./("A
goToBeginningOfDocumentAction = timerEvent()9 showEvent()9#%)- hideEvent()1
new QAction(tr("Go to Beginning of Document"), this);
goToBeginningOfDocumentAction->setShortcut(tr("Ctrl+Home"));
connect(goToBeginningOfDocumentAction, SIGNAL(activated()), `/6#5"7@'#("84"6#7!"#4+$5"+")7%74/)A
editor, SLOT(goToBeginningOfDocument()));
...
} #include <QtGui>
#include "ticker.h"
Ticker::Ticker(QWidget *parent)
: QWidget(parent)
!4'#+%2"'#47#"%'C#7/#%--#7!"#3/++%)-'#7/#%#+")*#/(#%#7//5,%(9#%'#6"#'%6#4) E!%$7"(#J1#M.#7!"
{
offset = 0; !" showEvent()#.*)374/)#'7%(7'#%#74+"(1# !"#3%55#7/ QObject::startTimer()#("7*()'#%)#MG#)*+,"(9
myTimerId = 0;
6!43!#6"#3%)#*'"#5%7"(#7/#4-")74.C#7!"#74+"(1 QObject#'*$$/(7'#+*574$5"#4)-"$")-")7#74+"('9#"%3!
}
647!#47'#/6)#74+"#4)7"(8%51#I.7"(#7!"#3%55#7/ startTimer()9#^7#6455#&")"(%7" %#74+"(#"8")7
%$$(/=4+%7"5C#"8"(C#J0#+4554'"3/)-'N#7!"#%33*(%3C#-"$")-'#/)#7!"#*)-"(5C4)&#/$"(%74)&#'C'7"+1

!"#3/)'7(*37/(#4)474%54R"'#7!" offset#8%(4%,5"#7/#01# !" /#3//(-4)%7"#%7#6!43!#7!"#7"=7#4'#-(%6)#4'


B"#3/*5-#!%8"#3%55"- startTimer()#4)#7!" Ticker#3/)'7(*37/(9#,*7#6"#'%8"#'/+"#("'/*(3"'#,C#!%84)&
-"(48"-#.(/+#7!" offset#8%5*"1# 4+"(#MG'#%("#%56%C'#)/)LR"(/9#'/#6"#*'"#0#7/#4)-43%7"#7!%7#)/#74+"( ^7#&")"(%7"#74+"(#"8")7'#/)5C#6!")#7!"#64-&"7#4'#%37*%55C#84'4,5"1
!%'#,"")#'7%(7"-1

void Ticker::timerEvent(QTimerEvent *event)


void Ticker::setText(const QString &newText) {
{ if (event->timerId() == myTimerId) {
myText = newText; ++offset;
update(); if (offset >= fontMetrics().width(text()))
updateGeometry(); offset = 0;
} scroll(-1, 0);
} else {
QWidget::timerEvent(event);
!" setText()#.*)374/)#'"7'#7!"#7"=7#7/#-4'$5%C1#M7#3%55' update()#7/#("_*"'7#%#("$%4)7#%)- }
updateGeometry()#7/#)/74.C#%)C#5%C/*7#+%)%&"(#("'$/)'4,5"#./(#7!" Ticker#64-&"7#%,/*7#%#'4R"#!4)7 }
3!%)&"1

!" timerEvent()#.*)374/)#4'#3%55"-#%7#4)7"(8%5'#,C#7!"#'C'7"+1#M7#4)3("+")7' offset#,C#D#7/#'4+*5%7"


QSize Ticker::sizeHint() const +/8"+")79#6(%$$4)&#%7#7!"#64-7!#/.#7!"#7"=71# !")#47#'3(/55'#7!"#3/)7")7'#/.#7!"#64-&"7#/)"#$4="5#7/
{ 7!"#5".7#*'4)& QWidget::scroll()1#M7#6/*5-#!%8"#,"")#'*..434")7#7/#3%55 update()#4)'7"%-#/. scroll()9
return fontMetrics().size(0, text()); ,*7 scroll()#4'#+/("#"..434")7#,"3%*'"#47#'4+$5C#+/8"'#7!"#"=4'74)&#$4="5'#/)#'3("")#%)-#/)5C
} &")"(%7"'#%#$%4)7#"8")7#./(#7!"#64-&"7@'#)"65C#("8"%5"-#%("%#K%#DL$4="5L64-"#'7(4$#4)#7!4'#3%'"O1

M.#7!"#74+"(#"8")7#4')@7#./(#7!"#74+"(#6"#%("#4)7"("'7"-#4)9#6"#$%''#47#/)#7/#/*(#,%'"#35%''1
!" sizeHint()#.*)374/)#("7*()'#7!"#'$%3"#)""-"-#,C#7!"#7"=7#%'#7!"#64-&"7@'#4-"%5#'4R"1
QWidget::fontMetrics()#("7*()'#% QFontMetrics#/,V"37#7!%7#3%)#,"#_*"(4"-#7/#/,7%4)#4)./(+%74/)
("5%74)&#7/#7!"#64-&"7@'#./)71#M)#7!4'#3%'"9#6"#%'2#./(#7!"#'4R"#("_*4("-#,C#7!"#&48")#7"=71#K !"#.4('7 void Ticker::hideEvent(QHideEvent * /* event */)
%(&*+")7#7/ QFontMetrics::size()#4'#%#.5%&#7!%7#4')@7#)""-"-#./(#'4+$5"#'7(4)&'9#'/#6"#V*'7#$%''#01O {
killTimer(myTimerId);
}
void Ticker::paintEvent(QPaintEvent * /* event */)
{
QPainter painter(this); !" hideEvent()#.*)374/)#3%55' QObject::killTimer()#7/#'7/$#7!"#74+"(1
int textWidth = fontMetrics().width(text());
if (textWidth < 1)
return; 4+"(#"8")7'#%("#5/6#5"8"59#%)-#4.#6"#)""-#+*574$5"#74+"('9#47#3%)#,"3/+"#3*+,"('/+"#7/#2""$#7(%32
int x = -offset; /.#%55#7!"#74+"(#MG'1#M)#'*3!#'47*%74/)'9#47#4'#*'*%55C#"%'4"(#7/#3("%7"#% QTimer#/,V"37#./(#"%3!#74+"(1
while (x < width()) { QTimer#"+47'#7!" timeout()#'4&)%5#%7#"%3!#74+"#4)7"(8%51 QTimer#%5'/#$(/84-"'#%#3/)8")4")7#4)7"(.%3"
painter.drawText(x, 0, textWidth, height(), ./(#'4)&5"L'!/7#74+"('#K74+"('#7!%7#74+"#/*7#V*'7#/)3"O1
Qt::AlignLeft | Qt::AlignVCenter, text());
x += textWidth;
}
}

!" paintEvent()#.*)374/)#-(%6'#7!"#7"=7#*'4)& QPainter::drawText()1#M7#*'"' fontMetrics()#7/ N3.0-66!3"&OP%30& !60%$.


%'3"(7%4)#!/6#+*3!#!/(4R/)7%5#'$%3"#7!"#7"=7#("_*4("'9#%)-#7!")#-(%6'#7!"#7"=7#%'#+%)C#74+"'#%'
)"3"''%(C#7/#.455#7!"#")74("#64-7!#/.#7!"#64-&"79#7%24)& offset#4)7/#%33/*)71 [)"#("%55C#$/6"(.*5#."%7*("#/.#^7@'#"8")7#+/-"5#4'#7!%7#% QObject#4)'7%)3"#3%)#,"#'"7#7/#+/)47/(#7!"
"8")7'#/.#%)/7!"( QObject#4)'7%)3"#,"./("#7!"#5%77"(#/,V"37#"8")#'""'#7!"+1

void Ticker::showEvent(QShowEvent * /* event */) Q"7@'#'*$$/'"#7!%7#6"#!%8"#% CustomerInfoDialog#64-&"7#3/+$/'"-#/.#'"8"(%5 QLineEdit'#%)-#7!%7


{ 6"#6%)7#7/#*'"#7!"#T$%3"#2"C#7/#+/8"#7!"#./3*'#7/#7!"#)"=7 QLineEdit1# !4'#)/)L'7%)-%(-#,"!%84/(
myTimerId = startTimer(30); +4&!7#,"#%$$(/$(4%7"#./(#%)#4)L!/*'"#%$$543%74/)#6!/'"#*'"('#%("#7(%4)"-#4)#47'#*'"1#I
} '7(%4&!7./(6%(-#'/5*74/)#4'#7/#'*,35%'' QLineEdit#%)-#("4+$5"+")7 keyPressEvent()#7/#3%55
focusNextChild()9#542"#7!4'A
;4('79#6"#3!"32#7/#'""#4.#7!"#7%(&"7#64-&"7#4'#/)"#/.#7!" QLineEdit'1#M.#7!"#"8")7#6%'#%#2"C#$("''9#6"
3%'7#47#7/ QKeyEvent#%)-#3!"32#6!43!#2"C#6%'#$("''"-1#M.#7!"#$("''"-#2"C#6%'#T$%3"9#6"#3%55
void MyLineEdit::keyPressEvent(QKeyEvent *event) focusNextChild()#7/#$%''#./3*'#/)#7/#7!"#)"=7#64-&"7#4)#7!"#./3*'#3!%4)9#%)-#6"#("7*() true#7/#7"55
{ ^7#7!%7#6"#!%8"#!%)-5"-#7!"#"8")71#M.#6"#("7*()"- false9#^7#6/*5-#'")-#7!"#"8")7#7/#47'#4)7")-"-
if (event->key() == Qt::Key_Space) {
7%(&"79#("'*574)&#4)#%#'$*(4/*'#'$%3"#,"4)&#4)'"(7"-#4)7/#7!" QLineEdit1
focusNextChild();
} else {
QLineEdit::keyPressEvent(event); M.#7!"#7%(&"7#64-&"7#4')@7#% QLineEdit9#/(#4.#7!"#"8")7#4')@7#%#T$%3"#2"C#$("''9#6"#$%''#3/)7(/5#7/#7!"
} ,%'"#35%''@'#4+$5"+")7%74/)#/. eventFilter()1# !"#7%(&"7#64-&"7#3/*5-#%5'/#,"#'/+"#64-&"7#7!%7#7!"
} ,%'" 35%''9 QDialog9#4'#+/)47/(4)&1#KM)#^7#P1D9#7!4'#4'#)/7#7!"#3%'"#./( QDialog1#?/6"8"(9#/7!"(#^7
64-&"7#35%''"'9#'*3!#%' QScrollArea9#-/#+/)47/(#'/+"#/.#7!"4(#3!45-#64-&"7'#./(#8%(4/*'#("%'/)'1O

!4'#%$$(/%3!#!%'#/)"#+%4)#-4'%-8%)7%&"A#M.#6"#*'"#'"8"(%5#-4.."(")7#24)-'#/.#64-&"7'#4)#7!"#./(+ ^7#/.."('#.48"#5"8"5'#%7#6!43!#"8")7'#3%)#,"#$(/3"''"-#%)-#.457"("-A
K./(#"=%+$5"9 QComboBox"'#%)- QSpinBox"'O9#6"#+*'7#%5'/#'*,35%''#7!"+#7/#+%2"#7!"+#"=!4,47#7!"
'%+"#,"!%84/(1#I#,"77"(#'/5*74/)#4'#7/#+%2" CustomerInfoDialog#+/)47/(#47'#3!45-#64-&"7'@#2"C#$("'' D1 R%&4-3&$%!L,6%L%30&-&.,%4!/!4&%P%30&1-356%$(
"8")7'#%)-#4+$5"+")7#7!"#("_*4("-#,"!%84/(#4)#7!"#+/)47/(4)&#3/-"1# !4'#3%)#,"#%3!4"8"-#*'4)&
"8")7#.457"('1#T"774)&#*$#%)#"8")7#.457"(#4)8/58"'#76/#'7"$'A j"4+$5"+")74)&#"8")7#!%)-5"('#'*3!#%' mousePressEvent()9 keyPress-Event()9#%)-
paintEvent()#4'#,C#.%(#7!"#+/'7#3/++/)#6%C#7/#$(/3"''#"8")7'1 B"#!%8"#%5("%-C#'"")#+%)C
@( j"&4'7"(#7!"#+/)47/(4)&#/,V"37#647!#7!"#7%(&"7#/,V"37#,C#3%554)& install-EventFilter()#/)#7!" "=%+$5"'#/.#7!4'1
7%(&"71
H1 R%&4-3&$%!L,6%L%30 S>JT%40UU%P%30VW(
C( ?%)-5"#7!"#7%(&"7#/,V"37@'#"8")7'#4)#7!"#+/)47/(@' eventFilter()#.*)374/)1
]C#("4+$5"+")74)&#7!" event()#.*)374/)9#6"#3%)#$(/3"''#"8")7'#,"./("#7!"C#("%3!#7!"#'$"34.43
"8")7#!%)-5"('1# !4'#%$$(/%3!#4'#+/'75C#)""-"-#7/#/8"((4-"#7!"#-".%*57#+"%)4)&#/.#7!"# %,
I#&//-#$5%3"#7/#("&4'7"(#7!"#+/)47/(4)&#/,V"37#4'#4)#7!" CustomerInfoDialog#3/)'7(*37/(A 2"C9#%'#'!/6)#"%(54"(#K$1#D<PO1# !4'#4'#%5'/#*'"-#7/#!%)-5"#(%("#7C$"'#/.#"8")7#./(#6!43!#)/
'$"34.43#"8")7#!%)-5"(#"=4'7'#K./(#"=%+$5"9 QEvent::HoverEnterO1#B!")#6"#("4+$5"+")7
event()9#6"#+*'7#3%55#7!"#,%'"#35%''@' event()#.*)374/)#./(#!%)-54)&#7!"#3%'"'#6"#-/)@7
CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) "=$543475C#!%)-5"1
: QDialog(parent)
{ J1 R%&4-3&!3.0-66&-3&%P%30&/!60%$&+3&-&.!3"6%&S>JT%40(
...
firstNameEdit->installEventFilter(this); [)3"#%)#/,V"37#!%'#,"")#("&4'7"("-#*'4)& installEventFilter()9#%55#7!"#"8")7'#./(#7!"#7%(&"7
lastNameEdit->installEventFilter(this);
/,V"37#%("#.4('7#'")7#7/#7!"#+/)47/(4)&#/,V"37@' event-Filter()#.*)374/)1#M.#+*574$5"#"8")7
cityEdit->installEventFilter(this);
phoneNumberEdit->installEventFilter(this); .457"('#%("#4)'7%55"-#/)#7!"#'%+"#/,V"379#7!"#.457"('#%("#%3748%7"-#4)#7*()9#.(/+#7!"#+/'7
} ("3")75C#4)'7%55"-#,%32#7/#7!"#.4('7#4)'7%55"-1

P1 R%&4-3&!3.0-66&-3&%P%30&/!60%$&+3&01%&SG,,6!4-0!+3&+JT%40(
[)3"#7!"#"8")7#.457"(#4'#("&4'7"("-9#7!"#"8")7'#7!%7#%("#'")7#7/#7!" firstName-Edit9 lastNameEdit9
cityEdit9#%)- phoneNumberEdit#64-&"7'#%("#.4('7#'")7#7/#7!" CustomerInfoDialog@' eventFilter() [)3"#%)#"8")7#.457"(#!%'#,"")#("&4'7"("-#./( qApp#K7!"#*)4_*" QApplication#/,V"37O9#"8"(C
.*)374/)#,"./("#7!"C#%(" '")7#/)#7/#7!"4(#4)7")-"-#-"'74)%74/)1 "8")7#./( "8"(C#/,V"37#4)#7!"#%$$543%74/)#4'#'")7#7/#7!" event-Filter()#.*)374/)#,"./("#47#4'
'")7#7/#%)C#/7!"(#"8")7#.457"(1# !4'#%$$(/%3!#4'#+/'75C#*'".*5#./(#-",*&&4)&1#M7#3%)#%5'/#,"
*'"-#7/#!%)-5"#+/*'"#"8")7'#'")7#7/#-4'%,5"-#64-&"7'9#6!43! QApplication#)/(+%55C#-4'3%(-'1
?"("@'#7!" eventFilter()#.*)374/)#7!%7#("3"48"'#7!"#"8")7'A

S1 R%&4-3&.#J46-..&SG,,6!4-0!+3&-35&$%!L,6%L%30&3+0!/XVW(
bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)
{ ^7#3%55' QApplication::notify()#7/#'")-#/*7#%)#"8")71#j"4+$5"+")74)&#7!4'#.*)374/)#4'#7!"
if (target == firstNameEdit || target == lastNameEdit /)5C#6%C#7/#&"7#%55#7!"#"8")7'9#,"./("#%)C#"8")7#.457"('#&"7#7!"#/$$/(7*)47C#7/#5//2#%7#7!"+1
|| target == cityEdit || target == phoneNumberEdit) { >8")7#.457"('#%("#&")"(%55C#+/("#*'".*59#,"3%*'"#7!"("#3%)#,"#%)C#)*+,"(#/.#3/)3*((")7#"8")7
if (event->type() == QEvent::KeyPress) { .457"('9#,*7#/)5C#/)" notify()#.*)374/)1
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Space) {
focusNextChild(); X%)C#"8")7#7C$"'9#4)35*-4)&#+/*'"#%)-#2"C#"8")7'9#3%)#,"#$(/$%&%7"-1#M.#7!"#"8")7#!%'#)/7#,"")
return true; !%)-5"-#/)#7!"#6%C#7/#47'#7%(&"7#/,V"37#/(#,C#7!"#7%(&"7#/,V"37#47'"5.9#7!"#6!/5"#"8")7#$(/3"''4)&
} $(/3"''#4'#("$"%7"-9#,*7#7!4'#74+"#647!#7!"#7%(&"7#/,V"37@'#$%(")7#%'#7!"#)"6#7%(&"71# !4'#3/)74)*"'9
} &/4)&#.(/+#$%(")7#7/#$%(")79#*)745#"47!"(#7!"#"8")7#4'#!%)-5"-#/(#7!"#7/$L5"8"5#/,V"37#4'#("%3!"-1
}
return QDialog::eventFilter(target, event); ;4&*("#W1H#'!/6'#!/6#%#2"C#$("''#"8")7#4'#$(/$%&%7"-#.(/+#3!45-#7/#$%(")7#4)#%#-4%5/&1#B!")#7!"
} *'"(#$("''"'#%#2"C9#7!"#"8")7#4'#.4('7#'")7#7/#7!"#64-&"7#7!%7#!%'#./3*'9#4)#7!4'#3%'"#7!"#,/77/+L(4&!7
QCheckBox1#M.#7!" QCheckBox#-/"')@7#!%)-5"#7!"#"8")79#^7#'")-'#47#7/#7!" QGroupBox9#%)-#.4)%55C#7/#7!"
QDialog#/,V"371
[)"#-%)&"(#647!#7!4'#%$$(/%3!#4'#7!%7#7!"#*'"(#+4&!7#35/'"#7!"#+%4)#64)-/6#6!45"#7!"#%$$543%74/)#4'
!"#$%&7(C(&OP%30&,$+,-"-0!+3&!3&-&5!-6+" '7455#'%84)&9#/(#"8")#35432#;45"ZT%8"#%#'"3/)-#74+"9#("'*574)&#4)#*)-".4)"-#,"!%84/(1# !"#"%'4"'7
'/5*74/)#7/#7!4'#$(/,5"+#4'#7/#("$5%3"

qApp->processEvents();

647!

qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

7"554)&#^7#7/#4&)/("#+/*'"#%)-#2"C#"8")7'1

[.7")9#6"#6%)7#7/#'!/6#% QProgressDialog#6!45"#%#5/)&L(*))4)&#/$"(%74/)#4'#7%24)&#$5%3"1
QProgressDialog#!%'#%#$(/&("''#,%(#7!%7#2""$'#7!"#*'"(#4)./(+"-#%,/*7#7!"#$(/&("''#,"4)&#+%-"#,C
7!"#%$$543%74/)1 QProgressDialog#%5'/#$(/84-"'#%#E%)3"5#,*77/)#7!%7#%55/6'#7!"#*'"(#7/#%,/(7#7!"
/$"(%74/)1#?"("@'#7!"#3/-"#./(#'%84)&#%#T$("%-'!""7#.45"#*'4)&#7!4'#%$$(/%3!A
Staying Responsive During Intensive Processing
B!")#6"#3%55 QApplication::exec()9#6"#'7%(7#^7@'#"8")7#5//$1#^7#4''*"'#%#."6#"8")7'#/)#'7%(7*$#7/ bool Spreadsheet::writeFile(const QString &fileName)
'!/6#%)-#$%4)7#7!"#64-&"7'1#I.7"( 7!%79#7!"#"8")7#5//$#4'#(*))4)&9#3/)'7%)75C#3!"324)&#7/#'""#4.#%)C {
"8")7'#!%8"#/33*(("-#%)-#-4'$%73!4)&#7!"'"#"8")7'#7/ QObject'#4)#7!"#%$$543%74/)1 QFile file(fileName);
...
B!45"#/)"#"8")7#4'#,"4)&#$(/3"''"-9%--474/)%5#"8")7'#+%C#,"#&")"(%7"-#%)-#%$$")-"-#7/#^7@'#"8")7 QProgressDialog progress(this);
progress.setLabelText(tr("Saving %1").arg(fileName));
_*"*"1#M. 6"#'$")-#7//#+*3!#74+"#$(/3"''4)&#%#$%(743*5%(#"8")79#7!"#*'"(#4)7"(.%3"#6455#,"3/+"
progress.setRange(0, RowCount);
*)("'$/)'48"1#;/(#"=%+$5"9#%)C#"8")7'#&")"(%7"-#,C#7!"#64)-/6#'C'7"+#6!45"#7!"#%$$543%74/)#4'
progress.setModal(true);
'%84)&#%#.45"#7/#-4'2#6455#)/7#,"#$(/3"''"-#*)745#7!"#.45"#4'#'%8"-1#G*(4)&#7!"#'%8"9#7!"#%$$543%74/)#6455 for (int row = 0; row < RowCount; ++row) {
)/7#("'$/)-#7/#("_*"'7'#.(/+#7!"#64)-/6#'C'7"+#7/#("$%4)7#47'"5.1 progress.setValue(row);
qApp->processEvents();
[)"#'/5*74/)#4'#7/#*'"#+*574$5"#7!("%-'A#/)"#7!("%-#./(#7!"#%$$543%74/)@'#*'"(#4)7"(.%3"#%)-#%)/7!"( if (progress.wasCanceled()) {
7!("%-#7/#$"(./(+#.45"#'%84)&#K/(#%)C#/7!"(#74+"L3/)'*+4)& /$"(%74/)O1# !4'#6%C9#7!"#%$$543%74/)@' file.remove();
*'"(#4)7"(.%3"#6455#'7%C#("'$/)'48"#6!45"#7!"#.45"#4'#,"4)&#'%8"-1#B"#6455#'""#!/6#7/#%3!4"8"#7!4'#4) return false;
E!%$7"(#Df1 }
for (int column = 0; column < ColumnCount; ++column) {
QString str = formula(row, column);
I#'4+$5"(#'/5*74/)#4'#7/#+%2"#.("_*")7#3%55'#7/ QApplication::processEvents()#4)#7!"#.45"#'%84)&#3/-"1
if (!str.isEmpty())
!4'#.*)374/)#7"55'#^7#7/#$(/3"''#%)C#$")-4)&#"8")7'9#%)-#7!")#("7*()'#3/)7(/5#7/#7!"#3%55"(1#M)#.%379 out << quint16(row) << quint16(column) << str;
QApplication::exec()#4'#54775"#+/("#7!%)#% while#5//$#%(/*)-#% processEvents()#.*)374/)#3%551 }
}
?"("@'#%)#"=%+$5"#/.#!/6#6"#3%)#2""$#7!"#*'"(#4)7"(.%3"#("'$/)'48"#*'4)& processEvents()9#,%'"- return true;
/)#7!"#.45"#'%84)&#3/-"#./( Spreadsheet#K$1#f0OA }

bool Spreadsheet::writeFile(const QString &fileName) B"#3("%7"#% QProgressDialog#647! NumRows#%'#7!"#7/7%5#)*+,"(#/.#'7"$'1# !")9#./(#"%3!#(/69#6"#3%55


{ setValue()#7/#*$-%7"#7!"#$(/&("''#,%(1 QProgressDialog#%*7/+%743%55C#3/+$*7"'#%#$"(3")7%&"#,C
QFile file(fileName); -484-4)&#7!"#3*((")7#$(/&("''#8%5*"#,C#7!"#7/7%5#)*+,"(#/.#'7"$'1#B"#3%55
...
QApplication::processEvents()#7/#$(/3"''#%)C#("$%4)7#"8")7'#/(#%)C#*'"(#35432'#/(#2"C#$("''"'#K./(
for (int row = 0; row < RowCount; ++row) {
for (int column = 0; column < ColumnCount; ++column) { "=%+$5"9#7/#%55/6#7!"#*'"(#7/#35432#E%)3"5O1#M.#7!"#*'"(#35432'#E%)3"59#6"#%,/(7#7!"#'%8"#%)-#("+/8"
QString str = formula(row, column); 7!"#.45"1
if (!str.isEmpty())
out << quint16(row) << quint16(column) << str; B"#-/)@7#3%55 show()#/)#7!" QProgressDialog#,"3%*'"#$(/&("''#-4%5/&'#-/#7!%7#./(#7!"+'"58"'1#M.#7!"
} /$"(%74/)#7*()'#/*7#7/#,"#'!/(79#$("'*+%,5C#,"3%*'"#7!"#.45"#7/#'%8"#4'#'+%55#/(#,"3%*'"#7!"#+%3!4)"
qApp->processEvents(); 4'#.%'79 QProgressDialog#6455#-"7"37#7!4'#%)-#6455#)/7#'!/6#47'"5.#%7#%551
}
return true;
} M)#%--474/)#7/#+*5747!("%-4)&#%)-#*'4)& QProgressDialog9#7!"("#4'#%#3/+$5"7"5C#-4.."(")7#6%C#/.
-"%54)&#647!#5/)&L(*))4)&#/$"(%74/)'A#M)'7"%-#/.#$"(./(+4)&#7!"#$(/3"''4)&#6!")#7!"#*'"(#("_*"'7'9
6"#3%)#-"."(#7!"#$(/3"''4)&#*)745#7!"#%$$543%74/)#4'#4-5"1# !4'#3%)#6/(2#4.#7!"#$(/3"''4)&#3%)#,"#'%."5C
4)7"((*$7"-#%)-#("'*+"-9#'4)3"#6"#3%))/7#$("-437#!/6#5/)&#7!"#%$$543%74/)#6455#,"#4-5"1
Chapter 8. 2D and 3D Graphics
M)#^79#7!4'#%$$(/%3!#3%)#,"#4+$5"+")7"-#,C#*'4)&#%#0L+4554'"3/)-#74+"(1# !"'"#74+"('#74+"#/*7
6!")"8"(#7!"("#%("#)/#$")-4)&#"8")7'1#?"("@'#%)#"=%+$5" timerEvent()#4+$5"+")7%74/)#7!%7#'!/6' • 8-"&'"&():"';)<8-"&'!/
7!"#4-5"#$(/3"''4)&#%$$(/%3!A • 8-"&'!/)=/-&0>5/#-'"5&0
• ,"(;?<7-%"'4) !&.!/"&():"';)<1#-(!
• 8/"&'"&(
void Spreadsheet::timerEvent(QTimerEvent *event) • @/-$;"90):"';)A$!&@B
{
if (event->timerId() == myTimerId) {
while (step < MaxStep && !qApp->hasPendingEvents()) { ^7@'#HG#&(%$!43'#")&4)"#4'#,%'"-#/)#7!" QPainter#35%''1 QPainter#3%)#-(%6#&"/+"7(43#'!%$"'#K$/4)7'9
performStep(step); 54)"'9#("37%)&5"'9#"554$'"'9#%(3'9#3!/(-'9#$4"#'"&+")7'9#$/5C&/)'9#%)-#]kR4"(#3*(8"'O9#%'#6"55#%'
++step; $4=+%$'9#4+%&"'9#%)-#7"=71#;*(7!"(+/("9 QPainter#'*$$/(7'#%-8%)3"-#."%7*("'#'*3!#%'#%)74%54%'4)&
} K./(#7"=7#%)-#'!%$"#"-&"'O9#%5$!%#,5")-4)&9#&(%-4")7#.4554)&9#%)-#8"37/(#$%7!'1 QPainter#%5'/#'*$$/(7'
} else { 7(%)'./(+%74/)'9#6!43!#+%2"'#47#$/''4,5"#7/#-(%6#("'/5*74/)L4)-"$")-")7#HG#&(%$!43'1
QTableWidget::timerEvent(event);
}
QPainter#3%)#,"#*'"-#7/#-(%6#/)#%#F$%4)7#-"843"F9#'*3!#%'#% QWidget9#% QPixmap9#/(#% QImage1#M7#4'
}
*'".*5#6!")#6"#6(47"#3*'7/+#64-&"7'#/(#3*'7/+#47"+#35%''"'#647!#7!"4(#/6)#5//2#%)-#.""51 QPainter
3%)#%5'/#,"#*'"-#4)#3/)V*)374/)#647! QPrinter#./(#$(4)74)&#%)-#./(#&")"(%74)&#:G;'1# !4'#+"%)'#7!%7
6"#3%)#/.7")#*'"#7!"#'%+"#3/-"#7/#-4'$5%C#-%7%#/)#'3("")#%)-#7/#$(/-*3"#$(4)7"-#("$/(7'1
M. hasPendingEvents()#("7*()' true9#6"#'7/$#$(/3"''4)&#%)-#&48"#3/)7(/5#,%32#7/#^71# !"#$(/3"''4)&
6455#("'*+"#6!")#^7#!%'#!%)-5"-#%55#47'#$")-4)&#"8")7'1
I)#%57"()%748"#7/ QPainter#4'#7/#*'"#[$")lQ1#[$")lQ#4'#%#'7%)-%(-#54,(%(C#./(#-(%64)&#HG#%)-#JG
&(%$!43'1# !" !0-$(1* !"#$%& !'(&) *+ ,&-. &'). +" */+&0-'+& 12&/34 5"#& */+" 6+ '22%*5'+*"/)7

Painting with QPainter


8" )+'-+ 2'*/+*/0 +" ' 2'*/+ #&,*5& 9+.2*5'%%. ' :*#0&+;< :& )*!2%. 5-&'+& ' QPainter '/# 2')) '
2"*/+&- +" +=& #&,*5&7 >"- &?'!2%&@

void MyWidget::paintEvent(QPaintEvent *event)


{
QPainter painter(this);
...
}

A& 5'/ #-': ,'-*"$) )='2&) $)*/0 QPainterB) draw...() C$/5+*"/)7 >*0$-& D7E %*)+) +=& !")+
*!2"-+'/+ "/&)7 8=& :'. +=& #-':*/0 *) 2&-C"-!&# *) */C%$&/5&# F. QPainterB) )&++*/0)7 G"!& "C
+=&)& '-& '#"2+&# C-"! +=& #&,*5&< "+=&-) '-& */*+*'%*H&# +" #&C'$%+ ,'%$&)7 8=& +=-&& !'*/ 2'*/+&-
)&++*/0) '-& +=& 2&/< +=& F-$)=< '/# +=& C"/+@

• 8=& !" *) $)&# C"- #-':*/0 %*/&) '/# )='2& "$+%*/&)7 I+ 5"/)*)+) "C ' 5"%"-< ' :*#+=< ' %*/&
)+.%&< ' 5'2 )+.%&< '/# ' J"*/ )+.%&7
• 8=& #$%&' *) +=& 2'++&-/ $)&# C"- C*%%*/0 0&"!&+-*5 )='2&)7 I+ /"-!'%%. 5"/)*)+) "C ' 5"%"- '/#
' )+.%&< F$+ 5'/ '%)" F& ' +&?+$-& 9' 2*?!'2 +='+ *) -&2&'+&# */C*/*+&%.; "- ' 0-'#*&/+7
• 8=& ()"* *) $)&# C"- #-':*/0 +&?+7 K C"/+ =') !'/. '++-*F$+&)< */5%$#*/0 ' C'!*%. '/# ' 2"*/+
)*H&7

!"#$%&'()( QPainter*+&,-+.&/$%0#%1.23&#+%4 draw...()&/#15.!-1+


!"#$%&'(;(&<%1&+.32%+

!"#$%&'(=(&<$%4%/!1%4&>$#+?&+.32%+
[View full size image]

8=&)& )&++*/0) 5'/ F& !"#*C*&# '+ '/. +*!& F. 5'%%*/0 setPen()< setBrush()< '/# setFont() :*+= '
QPen< QBrush< "- QFont "FJ&5+7

!"#$%&'(6(&789&814&:-!1&+.32%+

4&+B) )&& ' C&: &?'!2%&) */ 2-'5+*5&7 L&-&B) +=& 5"#& +" #-': +=& &%%*2)& )=":/ */ >*0$-& D7M 9';@

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, 12, Qt::DashDotLine, Qt::RoundCap));
painter.setBrush(QBrush(Qt::green, Qt::SolidPattern)); )&5+*"/ 5"!F*/&) '%% +=-&& +.2&) "C 0-'#*&/+) */ ' )*/0%& :*#0&+ +" !'(& *+ %""( %*(& +=& -&'% +=*/07
painter.drawEllipse(80, 80, 400, 240);
• +,"!-$./$-0,!"*& '-& #&C*/&# F. +:" 5"/+-"% 2"*/+) '/# F. ' )&-*&) "C V5"%"- )+"2)V "/ +=&
%*/& +='+ 5"//&5+) +=&)& +:" 2"*/+)7 >"- &?'!2%&< +=& %*/&'- 0-'#*&/+ "C >*0$-& D7W *) 5-&'+&#
!"#$%&'(@(&A%-,%.$!5&+?89%&%B8,92%+ $)*/0 +=& C"%%":*/0 5"#&@

[View full size image]
• QLinearGradient gradient(50, 100, 300, 350);
• gradient.setColorAt(0.0, Qt::white);
• gradient.setColorAt(0.2, Qt::green);
• gradient.setColorAt(1.0, Qt::black);

!"#$%&'(C( QPainter*+&"$84!%1.&>$#+?%+
[View full size image]

8=& setRenderHint() 5'%% &/'F%&) '/+*'%*')*/0< +&%%*/0 QPainter +" $)& #*CC&-&/+ 5"%"- */+&/)*+*&) "/ +=&
&#0&) +" -&#$5& +=& ,*)$'% #*)+"-+*"/ +='+ /"-!'%%. "55$-) :=&/ +=& &#0&) "C ' )='2& '-& 5"/,&-+&#
*/+" 2*?&%)7 8=& -&)$%+ *) )!""+=&- &#0&) "/ 2%'+C"-!) '/# #&,*5&) +='+ )$22"-+ +=*) C&'+$-&7

L&-&B) +=& 5"#& +" #-': +=& 2*& )&0!&/+ )=":/ */ >*0$-& D7M 9F;@

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, 15, Qt::SolidLine, Qt::RoundCap,
Qt::MiterJoin));
painter.setBrush(QBrush(Qt::blue, Qt::DiagCrossPattern));
painter.drawPie(80, 80, 400, 240, 60 * 16, 270 * 16);

8=& %')+ +:" '-0$!&/+) +" drawPie() '-& &?2-&))&# */ )*?+&&/+=) "C ' #&0-&&7

L&-&B) +=& 5"#& +" #-': +=& 5$F*5 NOH*&- 5$-,& )=":/ */ >*0$-& D7M 95;@

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true); A& )2&5*C. +=-&& 5"%"-) '+ +=-&& #*CC&-&/+ 2")*+*"/) F&+:&&/ +=& +:" 5"/+-"% 2"*/+)7 Q")*+*"/)
QPainterPath path; '-& )2&5*C*&# ') C%"'+*/0R2"*/+ ,'%$&) F&+:&&/ X '/# E< :=&-& X 5"--&)2"/#) +" +=& C*-)+
path.moveTo(80, 320); 5"/+-"% 2"*/+ '/# E +" +=& )&5"/# 5"/+-"% 2"*/+7 Y"%"-) F&+:&&/ +=& )2&5*C*&# )+"2) '-&
path.cubicTo(200, 80, 320, 80, 480, 320); */+&-2"%'+&#7
painter.setPen(QPen(Qt::black, 8));
painter.drawPath(path); • 1-0,-2./$-0,!"*& '-& #&C*/&# F. ' 5&/+&- 2"*/+ 935<45;< ' -'#*$) $< '/# ' C"5'% 2"*/+ 93C<4C;<
*/ '##*+*"/ +" +=& 5"%"- )+"2)7 8=& 5&/+&- 2"*/+ '/# +=& -'#*$) )2&5*C. ' 5*-5%&7 8=& 5"%"-)
)2-&'# "$+:'-# C-"! +=& C"5'% 2"*/+< :=*5= 5'/ F& +=& 5&/+&- 2"*/+ "- '/. "+=&- 2"*/+ */)*#&
8=& QPainterPath 5%')) 5'/ )2&5*C. '-F*+-'-. ,&5+"- )='2&) F. 5"//&5+*/0 F')*5 0-'2=*5'% &%&!&/+) +=& 5*-5%&7
+"0&+=&-@ )+-'*0=+ %*/&)< &%%*2)&)< 2"%.0"/)< '-5)< P$'#-'+*5 '/# 5$F*5 NOH*&- 5$-,&)< '/# "+=&- • 5)",6-2./$-0,!"*& '-& #&C*/&# F. ' 5&/+&- 2"*/+ 935<45; '/# '/ '/0%& 7 8=& 5"%"-) )2-&'#
2'*/+&- 2'+=)7 Q'*/+&- 2'+=) '-& +=& $%+*!'+& #-':*/0 2-*!*+*,& */ +=& )&/)& +='+ '/. )='2& "- '-"$/# +=& 5&/+&- 2"*/+ %*(& +=& ):&&2 "C ' :'+5=B) )&5"/#) ='/#7
5"!F*/'+*"/ "C )='2&) 5'/ F& &?2-&))&# ') ' 2'+=7
G" C'- :& =',& !&/+*"/&# QPainterB) 2&/< F-$)=< '/# C"/+ )&++*/0)7 I/ '##*+*"/ +" +=&)&< QPainter
K 2'+= )2&5*C*&) '/ "$+%*/&< '/# +=& '-&' #&)5-*F&# F. +=& "$+%*/& 5'/ F& C*%%&# $)*/0 ' F-$)=7 I/ +=& =') "+=&- )&++*/0) +='+ */C%$&/5& +=& :'. )='2&) '/# +&?+ '-& #-':/@
&?'!2%& "C >*0$-& D7M 95;< :& #*#/B+ )&+ ' F-$)=< )" "/%. +=& "$+%*/& *) #-':/7
• 8=& #-67/$)%"0.#$%&' *) $)&# +" C*%% +=& F'5(0-"$/# "C 0&"!&+-*5 )='2&) 9$/#&-/&'+= +=&
8=& +=-&& &?'!2%&) 'F",& $)& F$*%+R*/ F-$)= 2'++&-/) 9Qt::SolidPattern< Qt:: DiagCrossPattern< F-$)= 2'++&-/;< +&?+< "- F*+!'2) :=&/ +=& #-67/$)%"0.8)0! *) Qt::OpaqueMode 9+=& #&C'$%+
'/# Qt::NoBrush;7 I/ !"#&-/ '22%*5'+*"/)< 0-'#*&/+ C*%%) '-& ' 2"2$%'- '%+&-/'+*,& +" !"/"5=-"!& C*%% *) Qt::transparentMode;7
2'++&-/)7 3-'#*&/+) -&%. "/ 5"%"- */+&-2"%'+*"/ +" "F+'*/ )!""+= +-'/)*+*"/) F&+:&&/ +:" "- !"-& • 8=& #$%&'.)$,/," *) +=& )+'-+*/0 2"*/+ C"- F-$)= 2'++&-/)< /"-!'%%. +=& +"2R%&C+ 5"-/&- "C +=&
5"%"-)7 8=&. '-& C-&P$&/+%. $)&# +" 2-"#$5& ST &CC&5+)U C"- &?'!2%&< +=& Q%')+*P$& )+.%& $)&) :*#0&+7
0-'#*&/+) +" -&/#&- QPushButton)7 • 8=& 62, .$!/,)" *) +=& '-&' "C +=& #&,*5& +='+ 5'/ F& 2'*/+&#7 Q'*/+*/0 "$+)*#& +=& 5%*2 -&0*"/
=') /" &CC&5+7
6+ )$22"-+) +=-&& +.2&) "C 0-'#*&/+)@ %*/&'-< 5"/*5'%< '/# -'#*'%7 8=& 1,&/ 8*!&- &?'!2%& */ +=& /&?+ • 8=& 9,!: )$*;.:,"0):< '/# :)$20.8-*$,3 #&+&-!*/& =": %"0*5'% QPainter 5""-#*/'+&) !'2
+" 2=.)*5'% 2'*/+ #&,*5& 5""-#*/'+&)7 N. #&C'$%+< +=&)& '-& )&+ $2 )" +='+ +=& %"0*5'% '/# 2=.)*5'% 5""-#*/'+&)7 8=& :*/#": )2&5*C*&) +=& )'!& -&5+'/0%&< F$+ */ %"0*5'% 5""-#*/'+&)7 A=&/ :&
2=.)*5'% 5""-#*/'+& ).)+&!) 5"*/5*#&7 Y""-#*/'+& ).)+&!) '-& 5",&-&# */ +=& /&?+ )&5+*"/7 #" +=& 2'*/+*/0< :& )2&5*C. 2"*/+) */ %"0*5'% 5""-#*/'+&)< '/# +=")& 5""-#*/'+&) '-& 5"/,&-+&# */+"
• 8=& 6)8 )&,*,)".8)0! )2&5*C*&) =": +=& /&:%. #-':/ 2*?&%) )="$%# */+&-'5+ :*+= +=& 2*?&%) 2=.)*5'% 5""-#*/'+&) */ ' %*/&'- '%0&F-'*5 !'//&-< F')&# "/ +=& 5$--&/+ :*/#":,*&:2"-+ )&++*/0)7
'%-&'#. 2-&)&/+ "/ +=& 2'*/+ #&,*5&7 8=& #&C'$%+ *) V)"$-5& ",&-V< :=&-& #-':/ 2*?&%) '-&
#-':/ "/ +"2 "C &?*)+*/0 2*?&%)7 8=*) *) )$22"-+&# "/%. "/ 5&-+'*/ #&,*5&) '/# *) 5",&-&# %'+&- N. #&C'$%+< +=& ,*&:2"-+ '/# +=& :*/#": '-& )&+ +" +=& #&,*5&B) -&5+'/0%&7 >"- &?'!2%&< *C +=& #&,*5&
*/ +=*) 5='2+&-7 *) ' S_X ? _XX :*#0&+< F"+= +=& ,*&:2"-+ '/# +=& :*/#": '-& +=& )'!& S_X ? _XX -&5+'/0%& :*+= *+)
+"2R%&C+ 5"-/&- '+ 2")*+*"/ 9X< X;7 I/ +=*) 5')&< +=& %"0*5'% '/# 2=.)*5'% 5""-#*/'+& ).)+&!) '-& +=&
K+ '/. +*!&< :& 5'/ )',& +=& 5$--&/+ )+'+& "C ' 2'*/+&- "/ '/ */+&-/'% )+'5( F. 5'%%*/0 save() '/# )'!&7
-&)+"-& *+ %'+&- "/ F. 5'%%*/0 restore()7 8=*) 5'/ F& $)&C$% *C :& :'/+ +" +&!2"-'-*%. 5='/0& )"!&
2'*/+&- )&++*/0) '/# +=&/ -&)&+ +=&! +" +=&*- 2-&,*"$) ,'%$&)< ') :& :*%% )&& */ +=& /&?+ )&5+*"/7 8=& :*/#":,*&:2"-+ !&5='/*)! *) $)&C$% +" !'(& +=& #-':*/0 5"#& */#&2&/#&/+ "C +=& )*H& "-
-&)"%$+*"/ "C +=& 2'*/+ #&,*5&7 >"- &?'!2%&< *C :& :'/+ +=& %"0*5'% 5""-#*/'+&) +" &?+&/# C-"! 9RMX< R
MX; +" 9[MX< [MX;< :*+= 9X< X; */ +=& !*##%&< :& 5'/ )&+ +=& :*/#": ') C"%%":)@

painter.setWindow(-50, -50, 100, 100);


Painter Transformations
A*+= QPainterB) #&C'$%+ 5""-#*/'+& ).)+&!< +=& 2"*/+ 9X< X; *) %"5'+&# '+ +=& +"2R%&C+ 5"-/&- "C +=& 8=& 9RMX< RMX; 2'*- )2&5*C*&) +=& "-*0*/< '/# +=& 9EXX< EXX; 2'*- )2&5*C*&) +=& :*#+= '/# =&*0=+7 8=*)
2'*/+ #&,*5&U3 5""-#*/'+&) */5-&')& -*0=+:'-# '/# 4 5""-#*/'+&) */5-&')& #":/:'-#7 Z'5= 2*?&% !&'/) +='+ +=& %"0*5'% 5""-#*/'+&) 9RMX< RMX; /": 5"--&)2"/# +" +=& 2=.)*5'% 5""-#*/'+&) 9X< X;< '/#
"55$2*&) '/ '-&' "C )*H& E ? E */ +=& #&C'$%+ 5""-#*/'+& ).)+&!7 +=& %"0*5'% 5""-#*/'+&) 9[MX< [MX; 5"--&)2"/# +" +=& 2=.)*5'% 5""-#*/'+&) 9S_X< _XX;7 I/ +=*)
&?'!2%&< :& #*#/B+ 5='/0& +=& ,*&:2"-+7
1/& *!2"-+'/+ +=*/0 +" $/#&-)+'/# *) +='+ +=& 5&/+&- "C ' 2*?&% %*&) "/ V='%CR2*?&%V 5""-#*/'+&)7 >"-
&?'!2%&< +=& +"2R%&C+ 2*?&% 5",&-) +=& '-&' F&+:&&/ 2"*/+) 9X< X; '/# 9E< E;< '/# *+) 5&/+&- *) %"5'+&# !"#$%&'('(&7-1G%$.!1"&2-"!582&5--$4!18.%+&!1.-&9?3+!582&5--$4!18.%+
'+ 9X7M< X7M;7 IC :& ')( QPainter +" #-': ' 2*?&% '+< )'.< 9EXX< EXX;< *+ :*%% '22-"?*!'+& +=& -&)$%+ F.
)=*C+*/0 +=& 5""-#*/'+& F. [X7M */ F"+= #*-&5+*"/)< -&)$%+*/0 */ +=& 2*?&% 5&/+&-&# '+ 9EXX7M< EXX7M;
F&*/0 #-':/7

8=*) #*)+*/5+*"/ !'. )&&! -'+=&- '5'#&!*5 '+ C*-)+< F$+ *+ =') *!2"-+'/+ 5"/)&P$&/5&) */ 2-'5+*5&7
>*-)+< +=& )=*C+*/0 F. [X7M "/%. "55$-) *C '/+*'%*')*/0 *) #*)'F%&# 9+=& #&C'$%+;U *C '/+*'%*')*/0 *)
&/'F%&# '/# :& +-. +" #-': ' 2*?&% '+ 9EXX< EXX; */ F%'5(< QPainter :*%% '5+$'%%. 5"%"- +=& C"$- 2*?&%)
9\\7M< \\7M;< 9\\7M< EXX7M;< 9EXX7M< \\7M;< '/# 9EXX7M< EXX7M; %*0=+ 0-'.< +" 0*,& +=& *!2-&))*"/ "C '
2*?&% %.*/0 &?'5+%. '+ +=& !&&+*/0 2"*/+ "C +=& C"$- 2*?&%)7 IC +=*) &CC&5+ *) $/#&)*-'F%&< :& 5'/ ',"*# *+
F. )2&5*C.*/0 ='%CR2*?&% 5""-#*/'+&)< C"- &?'!2%&< 9EXX7M< EXX7M;7

A=&/ #-':*/0 )='2&) )$5= ') %*/&)< -&5+'/0%&)< '/# &%%*2)&)< )*!*%'- -$%&) '22%.7 >*0$-& D7] )=":)
=": +=& -&)$%+ "C ' drawRect(2, 2, 6, 5) 5'%% ,'-*&) '55"-#*/0 +" +=& 2&/B) :*#+=< :=&/ '/+*'%*')*/0
*) "CC7 I/ 2'-+*5$%'-< *+ *) *!2"-+'/+ +" /"+*5& +='+ ' W ? M -&5+'/0%& #-':/ :*+= ' 2&/ :*#+= "C E ^": 5"!&) +=& :"-%# !'+-*?7 8=& :"-%# !'+-*? *) ' +-'/)C"-!'+*"/ !'+-*? +='+ *) '22%*&# */ '##*+*"/
&CC&5+*,&%. 5",&-) '/ '-&' "C )*H& ] ? W7 8=*) *) #*CC&-&/+ C-"! "%#&- +""%(*+)< */5%$#*/0 &'-%*&- ,&-)*"/) +" +=& :*/#":,*&:2"-+ 5"/,&-)*"/7 I+ '%%":) $) +" +-'/)%'+&< )5'%&< -"+'+&< "- )=&'- +=& *+&!) :& '-&
"C 6+< F$+ *+ *) &))&/+*'% C"- !'(*/0 +-$%. )5'%'F%&< -&)"%$+*"/R*/#&2&/#&/+ ,&5+"- 0-'2=*5) 2"))*F%&7 #-':*/07 >"- &?'!2%&< *C :& :'/+&# +" #-': +&?+ '+ ' `Ma '/0%&< :& :"$%# $)& +=*) 5"#&@

!"#$%&'(D(&E$8F!1"&8&C&B&@&$%5.81"2%&F!.?&1-&81.!82!8+!1" QMatrix matrix;


matrix.rotate(45.0);
painter.setMatrix(matrix);
painter.drawText(rect, Qt::AlignCenter, tr("Revenue"));

8=& %"0*5'% 5""-#*/'+&) :& 2')) +" drawText() '-& +-'/)C"-!&# F. +=& :"-%# !'+-*?< +=&/ !'22&# +"
2=.)*5'% 5""-#*/'+&) $)*/0 +=& :*/#":,*&:2"-+ )&++*/0)7

IC :& )2&5*C. !$%+*2%& +-'/)C"-!'+*"/)< +=&. '-& '22%*&# */ +=& "-#&- */ :=*5= +=&. '-& 0*,&/7 >"-
&?'!2%&< *C :& :'/+ +" $)& +=& 2"*/+ 9EX< _X; ') +=& -"+'+*"/B) 2*,"+ 2"*/+< :& 5'/ #" )" F.
+-'/)%'+*/0 +=& :*/#":< 2&-C"-!*/0 +=& -"+'+*"/< '/# +=&/ +-'/)%'+*/0 +=& :*/#": F'5( +" *+) "-*0*/'%
2")*+*"/@
^": +='+ :& $/#&-)+'/# +=& #&C'$%+ 5""-#*/'+& ).)+&!< :& 5'/ +'(& ' 5%")&- %""( '+ =": *+ 5'/ F&
5='/0&# $)*/0 QPainterB) ,*&:2"-+< :*/#":< '/# :"-%# !'+-*?7 9I/ +=*) 5"/+&?+< +=& +&-! V:*/#":V
#"&) /"+ -&C&- +" ' :*/#": */ +=& )&/)& "C ' +"2R%&,&% :*#0&+< '/# +=& V,*&:2"-+V =') /"+=*/0 +" #" QMatrix matrix;
:*+= QScrollAreaB) ,*&:2"-+7; matrix.translate(-10.0, -20.0);
matrix.rotate(45.0);
matrix.translate(+10.0, +20.0);
8=& ,*&:2"-+ '/# +=& :*/#": '-& +*0=+%. F"$/#7 8=& ,*&:2"-+ *) '/ '-F*+-'-. -&5+'/0%& )2&5*C*&# */ painter.setMatrix(matrix);
painter.drawText(rect, Qt::AlignCenter, tr("Revenue")); mousePressEvent()7

K )*!2%&- :'. +" )2&5*C. +-'/)C"-!'+*"/) *) +" $)& QPainterB) translate()< scale()< rotate()< '/# const double DegreesPerMinute = 7.0;
shear() 5"/,&/*&/5& C$/5+*"/)@ const double DegreesPerSecond = DegreesPerMinute / 60;
const int MaxMinutes = 45;
const int MaxSeconds = MaxMinutes * 60;
const int UpdateInterval = 1;
painter.translate(-10.0, -20.0);
painter.rotate(45.0);
painter.translate(+10.0, +20.0);
painter.drawText(rect, Qt::AlignCenter, tr("Revenue")); A& )+'-+ F. #&C*/*/0 ' C&: 5"/)+'/+) +='+ 5"/+-"% +=& ",&/ +*!&-B) %""( '/# C&&%7

N$+ *C :& :'/+ +" $)& +=& )'!& +-'/)C"-!'+*"/) -&2&'+&#%.< *+B) !"-& &CC*5*&/+ +" )+"-& +=&! */ ' OvenTimer::OvenTimer(QWidget *parent)
: QWidget(parent)
QMatrix "FJ&5+ '/# )&+ +=& :"-%# !'+-*? "/ +=& 2'*/+&- :=&/&,&- +=& +-'/)C"-!'+*"/) '-& /&&#&#7
{
finishTime = QDateTime::currentDateTime();
8" *%%$)+-'+& 2'*/+&- +-'/)C"-!'+*"/)< :& :*%% -&,*&: +=& 5"#& "C +=& OvenTimer :*#0&+ )=":/ */ updateTimer = new QTimer(this);
>*0$-& D7\7 8=& OvenTimer :*#0&+ *) !"#&%&# 'C+&- +=& (*+5=&/ +*!&-) +='+ :&-& $)&# F&C"-& *+ :') connect(updateTimer, SIGNAL(timeout()), this, SLOT(update()));
5"!!"/ +" =',& ",&/) :*+= 5%"5() F$*%+R*/7 8=& $)&- 5'/ 5%*5( ' /"+5= +" )&+ +=& #$-'+*"/7 8=& :=&&% finishTimer = new QTimer(this);
'$+"!'+*5'%%. +$-/) 5"$/+&-5%"5(:*)& $/+*% X *) -&'5=&#< '+ :=*5= 2"*/+ OvenTimer &!*+) +=& timeout() finishTimer->setSingleShot(true);
)*0/'%7 connect(finishTimer, SIGNAL(timeout()), this, SIGNAL(timeout()));
connect(finishTimer, SIGNAL(timeout()), updateTimer, SLOT(stop()));
}
!"#$%&'(H(&I?% OvenTimer&F!4"%.

I/ +=& 5"/)+-$5+"-< :& 5-&'+& +:" QTimer "FJ&5+)@ updateTimer *) $)&# +" -&C-&)= +=& '22&'-'/5& "C
+=& :*#0&+ &,&-. )&5"/#< '/# finishTimer &!*+) +=& :*#0&+B) timeout() )*0/'% :=&/ +=& ",&/ +*!&-
-&'5=&) X7 8=& finishTimer "/%. /&&#) +" +*!&"$+ "/5&< )" :& 5'%% setSingleShot(true)U F. #&C'$%+<
+*!&-) C*-& -&2&'+&#%. $/+*% +=&. '-& )+"22&# "- #&)+-".&#7 8=& %')+ connect() 5'%% *) '/ "2+*!*H'+*"/
+" )+"2 $2#'+*/0 +=& :*#0&+ &,&-. )&5"/# :=&/ +=& +*!&- *) */'5+*,&7

void OvenTimer::setDuration(int secs)


{
if (secs > MaxSeconds) {
secs = MaxSeconds;
} else if (secs <= 0) {
secs = 0;
}
finishTime = QDateTime::currentDateTime().addSecs(secs);
if (secs > 0) {
class OvenTimer : public QWidget
updateTimer->start(UpdateInterval * 1000);
{
finishTimer->start(secs * 1000);
Q_OBJECT
} else {
public:
updateTimer->stop();
OvenTimer(QWidget *parent = 0);
finishTimer->stop();
void setDuration(int secs);
}
int duration() const;
update();
void draw(QPainter *painter);
}
signals:
void timeout();
protected:
void paintEvent(QPaintEvent *event); 8=& setDuration() C$/5+*"/ )&+) +=& #$-'+*"/ "C +=& ",&/ +*!&- +" +=& 0*,&/ /$!F&- "C )&5"/#)7 A&
void mousePressEvent(QMouseEvent *event); 5"!2$+& +=& C*/*)= +*!& F. '##*/0 +=& #$-'+*"/ +" +=& 5$--&/+ +*!& 9"F+'*/&# C-"!
private: QDateTime::currentDateTime(); '/# )+"-& *+ */ +=& finishTime 2-*,'+& ,'-*'F%&7 K+ +=& &/#< :& 5'%%
QDateTime finishTime; update() +" -&#-': +=& :*#0&+ :*+= +=& /&: #$-'+*"/7
QTimer *updateTimer;
QTimer *finishTimer;
}; 8=& finishTime ,'-*'F%& *) "C +.2& QDateTime7 G*/5& +=& ,'-*'F%& ="%#) F"+= ' #'+& '/# ' +*!&< :&
',"*# ' :-'2R'-"$/# F$0 :=&/ +=& 5$--&/+ +*!& *) F&C"-& !*#/*0=+ '/# +=& C*/*)= +*!& *) 'C+&-
!*#/*0=+7
8=& OvenTimer 5%')) */=&-*+) QWidget '/# -&*!2%&!&/+) +:" ,*-+$'% C$/5+*"/)@ paintEvent() '/#
int OvenTimer::duration() const
{
int secs = QDateTime::currentDateTime().secsTo(finishTime);
if (secs < 0)
secs = 0;
return secs;
}

8=& duration() C$/5+*"/ -&+$-/) +=& /$!F&- "C )&5"/#) %&C+ F&C"-& +=& +*!&- *) #$& +" C*/*)=7 IC +=&
+*!&- *) */'5+*,&< :& -&+$-/ X7

void OvenTimer::mousePressEvent(QMouseEvent *event)


{
QPointF point = event->pos() - rect().center();
double theta = atan2(-point.x(), -point.y()) * 180 / 3.14159265359;
setDuration(duration() + int(theta / DegreesPerSecond));
update();
}

IC +=& $)&- 5%*5() +=& :*#0&+< :& C*/# +=& 5%")&)+ /"+5= $)*/0 ' )$F+%& F$+ &CC&5+*,& !'+=&!'+*5'%
C"-!$%'< '/# :& $)& +=& -&)$%+ +" )&+ +=& /&: #$-'+*"/7 8=&/ :& )5=&#$%& ' -&2'*/+7 8=& /"+5= +='+ IC :& ='# /"+ )&+ +=& ,*&:2"-+ +" F& ' )P$'-&< +=& ",&/ +*!&- :"$%# F& '/ &%%*2)& :=&/ +=& :*#0&+ *)
+=& $)&- 5%*5(&# :*%% /": F& '+ +=& +"2 '/# :*%% !",& 5"$/+&-5%"5(:*)& ') +*!& 2'))&) $/+*% X *) -&)*H&# +" ' /"/R)P$'-& -&5+'/0%&7 8" ',"*# )$5= #&C"-!'+*"/)< :& !$)+ )&+ +=& ,*&:2"-+ '/# +=&
-&'5=&#7 :*/#": +" -&5+'/0%&) :*+= +=& )'!& ')2&5+ -'+*"7

^": %&+B) %""( '+ +=& #-':*/0 5"#&@


void OvenTimer::paintEvent(QPaintEvent * /* event */)
{
QPainter painter(this); void OvenTimer::draw(QPainter *painter)
painter.setRenderHint(QPainter::Antialiasing, true); {
int side = qMin(width(), height()); static const int triangle[3][2] = {
painter.setViewport((width() - side) / 2, (height() - side) / 2, { -2, -49 }, { +2, -49 }, { 0, -47 }
side, side); };
painter.setWindow(-50, -50, 100, 100); QPen thickPen(palette().foreground(), 1.5);
draw(&painter); QPen thinPen(palette().foreground(), 0.5);
} QColor niceBlue(150, 150, 200);
painter->setPen(thinPen);
painter->setBrush(palette().foreground());
painter->drawPolygon(QPolygon(3, &triangle[0][0]));
I/ paintEvent()< :& )&+ +=& ,*&:2"-+ +" F& +=& %'-0&)+ )P$'-& '-&' +='+ C*+) */)*#& +=& :*#0&+< '/#
:& )&+ +=& :*/#": +" F& +=& -&5+'/0%& 9RMX< RMX< EXX< EXX;< +='+ *)< +=& EXX ? EXX -&5+'/0%&
&?+&/#*/0 C-"! 9RMX< RMX; +" 9[MX< [MX;7 8=& qMin() +&!2%'+& C$/5+*"/ -&+$-/) +=& %":&)+ "C *+) +:"
'-0$!&/+)7 8=&/ :& 5'%% +=& draw() C$/5+*"/ +" '5+$'%%. 2&-C"-! +=& #-':*/07 A& )+'-+ F. #-':*/0 +=& +*/. +-*'/0%& +='+ !'-() +=& X 2")*+*"/ '+ +=& +"2 "C +=& :*#0&+7 8=& +-*'/0%&
*) )2&5*C*&# F. +=-&& ='-#R5"#&# 5""-#*/'+&)< '/# :& $)& drawPolygon() +" -&/#&- *+7
!"#$%&'()J(&I?% OvenTimer&F!4"%.&8.&.?$%%&4!//%$%1.&+!K%+
A='+ *) )" 5"/,&/*&/+ 'F"$+ +=& :*/#":,*&:2"-+ !&5='/*)! *) +='+ :& 5'/ ='-#R5"#& +=&
5""-#*/'+&) :& $)& */ +=& #-': 5"!!'/#) '/# )+*%% 0&+ 0""# -&)*H*/0 F&=',*"-7

QConicalGradient coneGradient(0, 0, -90.0);


coneGradient.setColorAt(0.0, Qt::darkGray);
coneGradient.setColorAt(0.2, niceBlue);
coneGradient.setColorAt(0.5, Qt::white);
coneGradient.setColorAt(1.0, Qt::darkGray);
painter->setBrush(coneGradient);
painter->drawEllipse(-46, -46, 92, 92);

A& #-': +=& "$+&- 5*-5%& '/# C*%% *+ $)*/0 ' 5"/*5'% 0-'#*&/+7 8=& 0-'#*&/+B) 5&/+&- 2"*/+ *) %"5'+&# '+
9X< X;< '/# +=& '/0%& *) R\Xa7
if (i % 5 == 0) {
QRadialGradient haloGradient(0, 0, 20, 0, 0); painter->setPen(thickPen);
haloGradient.setColorAt(0.0, Qt::lightGray); painter->drawLine(0, -41, 0, -44);
haloGradient.setColorAt(0.8, Qt::darkGray); painter->drawText(-15, -41, 30, 25,
haloGradient.setColorAt(0.9, Qt::white); Qt::AlignHCenter | Qt::AlignTop,
haloGradient.setColorAt(1.0, Qt::black); QString::number(i));
painter->setPen(Qt::NoPen); } else {
painter->setBrush(haloGradient); painter->setPen(thinPen);
painter->drawEllipse(-20, -20, 40, 40); painter->drawLine(0, -42, 0, -44);
}
painter->restore();
}
A& C*%% +=& *//&- 5*-5%& $)*/0 ' -'#*'% 0-'#*&/+7 8=& 5&/+&- 2"*/+ '/# +=& C"5'% 2"*/+ "C +=& 0-'#*&/+
'-& %"5'+&# '+ 9X< X;7 8=& -'#*$) "C +=& 0-'#*&/+ *) _X7

K/"+=&- :'. "C *!2%&!&/+*/0 '/ ",&/ +*!&- :"$%# =',& F&&/ +" 5"!2$+& +=& 93;.4; 2")*+*"/)
QLinearGradient knobGradient(-7, -25, 7, -25); "$-)&%,&)< $)*/0 sin() '/# cos() +" C*/# +=& 2")*+*"/) '%"/0 +=& 5*-5%&7 N$+ +=&/ :& :"$%# )+*%% /&&#
knobGradient.setColorAt(0.0, Qt::black); +" $)& ' +-'/)%'+*"/ '/# ' -"+'+*"/ +" #-': +=& +&?+ '+ '/ '/0%&7
knobGradient.setColorAt(0.2, niceBlue);
knobGradient.setColorAt(0.3, Qt::lightGray);
knobGradient.setColorAt(0.8, Qt::white);
knobGradient.setColorAt(1.0, Qt::black);
painter->rotate(duration() * DegreesPerSecond);
painter->setBrush(knobGradient);
painter->setPen(thinPen);
High-Quality Rendering with QImage
painter->drawRoundRect(-7, -25, 14, 50, 150, 50);
for (int i = 0; i <= MaxMinutes; ++i) { A=&/ #-':*/0< :& !'. F& C'5&# :*+= ' +-'#&R"CC F&+:&&/ )2&&# '/# '55$-'5.7 >"- &?'!2%&< "/ bEE
if (i % 5 == 0) { '/# c'5 1G b< #-':*/0 "/ ' QWidget "- QPixmap -&%*&) "/ +=& 2%'+C"-!B) /'+*,& 2'*/+ &/0*/&7 1/ bEE<
painter->setPen(thickPen); +=*) &/)$-&) +='+ 5"!!$/*5'+*"/ :*+= +=& b )&-,&- *) (&2+ +" ' !*/*!$!U "/%. 2'*/+ 5"!!'/#) '-&
painter->drawLine(0, -41, 0, -44); )&/+ -'+=&- +='/ '5+$'% *!'0& #'+'7 8=& !'*/ #-':F'5( "C +=*) '22-"'5= *) +='+ 6+ *) %*!*+&# F. +=&
painter->drawText(-15, -41, 30, 25, 2%'+C"-!B) /'+*,& )$22"-+@
Qt::AlignHCenter | Qt::AlignTop,
QString::number(i));
} else { • 1/ bEE< C&'+$-&) )$5= ') '/+*'%*')*/0 '/# )$22"-+ C"- C-'5+*"/'% 5""-#*/'+&) '-& ','*%'F%& "/%.
painter->setPen(thinPen); *C +=& b d&/#&- &?+&/)*"/ *) 2-&)&/+ "/ +=& b )&-,&-7
painter->drawLine(0, -42, 0, -44); • 1/ c'5 1G b< +=& /'+*,& '%*')&# 0-'2=*5) &/0*/& $)&) #*CC&-&/+ '%0"-*+=!) C"- #-':*/0
} 2"%.0"/) +='/ bEE '/# A*/#":)< :*+= )%*0=+%. #*CC&-&/+ -&)$%+)7
painter->rotate(-DegreesPerMinute);
} A=&/ '55$-'5. *) !"-& *!2"-+'/+ +='/ &CC*5*&/5.< :& 5'/ #-': +" ' QImage '/# 5"2. +=& -&)$%+ "/+"
} +=& )5-&&/7 8=*) '%:'.) $)&) 6+B) ":/ */+&-/'% 2'*/+ &/0*/&< 0*,*/0 *#&/+*5'% -&)$%+) "/ '%% 2%'+C"-!)7
8=& "/%. -&)+-*5+*"/ *) +='+ +=& QImage "/ :=*5= :& 2'*/+ !$)+ F& 5-&'+&# :*+= '/ '-0$!&/+ "C &*+=&-
QImage::Format_RGB32 "- QImage::Format_ARGB32_Premultiplied7
A& 5'%% rotate() +" -"+'+& +=& 2'*/+&-B) 5""-#*/'+& ).)+&!7 I/ +=& "%# 5""-#*/'+& ).)+&!< +=& XR
!*/$+& !'-( :') "/ +"2U /":< +=& XR!*/$+& !'-( *) !",&# +" +=& 2%'5& +='+ *) '22-"2-*'+& C"- +=& 8=& 2-&!$%+*2%*&# Kd3NS_ C"-!'+ *) '%!")+ *#&/+*5'% +" +=& 5"/,&/+*"/'% Kd3NS_ C"-!'+
+*!& %&C+7 A& #-': +=& -&5+'/0$%'- (/"F ='/#%& 'C+&- +=& -"+'+*"/< )*/5& *+) "-*&/+'+*"/ #&2&/#) "/ 90xaarrggbb;< +=& #*CC&-&/5& F&*/0 +='+ +=& -&#< 0-&&/< '/# F%$& 5='//&%) '-& V2-&!$%+*2%*&#V :*+=
+=& -"+'+*"/ '/0%&7 +=& '%2=' 5='//&%7 8=*) !&'/) +='+ +=& d3N ,'%$&)< :=*5= /"-!'%%. -'/0& C-"! 0x00 +" 0xFF< '-&
)5'%&# C-"! 0x00 +" +=& '%2=' ,'%$&7 >"- &?'!2%&< ' MXeR+-'/)2'-&/+ F%$& 5"%"- *) -&2-&)&/+&# ')
I/ +=& for %""2< :& #-': +=& +*5( !'-() '%"/0 +=& "$+&- 5*-5%&B) &#0& '/# +=& /$!F&-) C"- &'5= 0x7F0000FF */ Kd3NS_ C"-!'+< F$+ 0x7F00007F */ 2-&!$%+*2%*&# Kd3NS_ C"-!'+< '/# )*!*%'-%. ' ]MeR
!$%+*2%& "C M !*/$+&)7 8=& +&?+ *) #-':/ */ '/ */,*)*F%& -&5+'/0%& $/#&-/&'+= +=& +*5( !'-(7 K+ +=& +-'/)2'-&/+ #'-( 0-&&/ "C 0x3F008000 */ Kd3NS_ C"-!'+ :"$%# F& 0x3F002000 */ 2-&!$%+*2%*&#
&/# "C &'5= *+&-'+*"/< :& -"+'+& +=& 2'*/+&- 5%"5(:*)& F. ]a< :=*5= 5"--&)2"/#) +" "/& !*/$+&7 8=& Kd3NS_ C"-!'+7
/&?+ +*!& :& #-': ' +*5( !'-(< *+ :*%% F& '+ ' #*CC&-&/+ 2")*+*"/ '-"$/# +=& 5*-5%&< &,&/ +="$0= +=&
5""-#*/'+&) :& 2')) +" +=& drawLine() '/# drawText() 5'%%) '-& '%:'.) +=& )'!&7 4&+B) )$22")& :& :'/+ +" $)& '/+*'%*')*/0 C"- #-':*/0 ' :*#0&+< '/# :& :'/+ +" "F+'*/ 0""# -&)$%+)
&,&/ "/ bEE ).)+&!) :*+= /" b d&/#&- &?+&/)*"/7 8=& "-*0*/'% paintEvent() ='/#%&-< :=*5= -&%*&) "/
8=& 5"#& */ +=& for %""2 )$CC&-) C-"! ' !*/"- C%':< :=*5= :"$%# P$*5(%. F&5"!& '22'-&/+ *C :& b d&/#&- C"- +=& '/+*'%*')*/0< !*0=+ %""( %*(& +=*)@
2&-C"-!&# !"-& *+&-'+*"/)7 Z'5= +*!& :& 5'%% rotate()< :& &CC&5+*,&%. !$%+*2%. +=& 5$--&/+ :"-%#
!'+-*? :*+= ' -"+'+*"/ !'+-*?< 2-"#$5*/0 ' /&: :"-%# !'+-*?7 8=& -"$/#*/0 &--"-) '))"5*'+&# :*+=
C%"'+*/0R2"*/+ '-*+=!&+*5 '## $2< -&)$%+*/0 */ '/ */5-&')*/0%. */'55$-'+& :"-%# !'+-*?7 L&-&B) "/& :'. void MyWidget::paintEvent(QPaintEvent *event)
+" -&:-*+& +=& 5"#& +" ',"*# +=*) *))$&< $)*/0 save() '/# restore() +" )',& '/# -&%"'# +=& "-*0*/'% {
+-'/)C"-!'+*"/ !'+-*? C"- &'5= *+&-'+*"/@ QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
draw(&painter);
for (int i = 0; i <= MaxMinutes; ++i) { }
painter->save();
painter->rotate(-i * DegreesPerMinute);
L&-&B) =": +" -&:-*+& +=& :*#0&+B) paintEvent() C$/5+*"/ +" $)& 6+B) 2%'+C"-!R*/#&2&/#&/+ 0-'2=*5)
&/0*/&@ 1/& *))$& +" F& ':'-& "C *) +='+ +=& QImage::CompositionMode_Xor "2&-'+*"/ '22%*&) +" +=& '%2='
5='//&%7 8=*) !&'/) +='+ *C :& b1d +=& 5"%"- :=*+& 9 0xFFFFFFFF; :*+= *+)&%C< :& "F+'*/ ' +-'/)2'-&/+
5"%"- 90x00000000;< /"+ F%'5( 90xFF000000;7
void MyWidget::paintEvent(QPaintEvent *event)
{
QImage image(size(), QImage::Format_ARGB32_Premultiplied);
QPainter imagePainter(&image);
imagePainter.initFrom(this);
imagePainter.setRenderHint(QPainter::Antialiasing, true);
imagePainter.eraseRect(rect()); Printing
draw(&imagePainter);
imagePainter.end(); Q-*/+*/0 */ 6+ *) )*!*%'- +" #-':*/0 "/ ' QWidget< QPixmap< "- QImage7 I+ 5"/)*)+) "C +=& C"%%":*/0
QPainter widgetPainter(this); )+&2)@
widgetPainter.drawImage(0, 0, image);
}
)( Y-&'+& ' QPrinter +" )&-,& ') +=& 2'*/+ #&,*5&7

A& 5-&'+& ' QImage "C +=& )'!& )*H& ') +=& :*#0&+ */ 2-&!$%+*2%*&# Kd3NS_ C"-!'+< '/# ' QPainter 6( Q"2 $2 ' QPrintDialog< '%%":*/0 +=& $)&- +" 5="")& ' 2-*/+&- '/# +" )&+ ' C&: "2+*"/)7
+" #-': "/ +=& *!'0&7 8=& initFrom() 5'%% */*+*'%*H&) +=& 2'*/+&-B) 2&/< F'5(0-"$/#< '/# C"/+ F')&#
"/ +=& :*#0&+7 A& 2&-C"-! +=& #-':*/0 $)*/0 +=& QPainter ') $)$'%< '/# '+ +=& &/# :& -&$)& +=& ;( Y-&'+& ' QPainter +" "2&-'+& "/ +=& QPrinter7
QPainter "FJ&5+ +" 5"2. +=& *!'0& "/+" +=& :*#0&+7
=( T-': ' 2'0& $)*/0 +=& QPainter7
8=*) '22-"'5= 2-"#$5&) *#&/+*5'% =*0=RP$'%*+. -&)$%+) "/ '%% 2%'+C"-!)< :*+= +=& &?5&2+*"/ "C C"/+
-&/#&-*/0< :=*5= #&2&/#) "/ +=& */)+'%%&# C"/+)7
@( Y'%% QPrinter::newPage() +" '#,'/5& +" +=& /&?+ 2'0&7
1/& 2'-+*5$%'-%. 2":&-C$% C&'+$-& "C 6+B) 0-'2=*5) &/0*/& *) *+) )$22"-+ C"- 5"!2")*+*"/ !"#&)7 8=&)&
)2&5*C. =": ' )"$-5& '/# ' #&)+*/'+*"/ 2*?&% '-& !&-0&# +"0&+=&- :=&/ #-':*/07 8=*) '22%*&) +" '%%
2'*/+*/0 "2&-'+*"/)< */5%$#*/0 2&/< F-$)=< 0-'#*&/+< '/# *!'0& #-':*/07 C( d&2&'+ )+&2) ` '/# M $/+*% '%% +=& 2'0&) '-& 2-*/+&#7

8=& #&C'$%+ 5"!2")*+*"/ !"#& *) QImage::CompositionMode_SourceOver< !&'/*/0 +='+ +=& )"$-5& 2*?&%
9+=& 2*?&% :& '-& #-':*/0; *) F%&/#&# "/ +"2 "C +=& #&)+*/'+*"/ 2*?&% 9+=& &?*)+*/0 2*?&%; */ )$5= ' 1/ A*/#":) '/# c'5 1G b< QPrinter $)&) +=& ).)+&!B) 2-*/+&- #-*,&-)7 1/ f/*?< *+ 0&/&-'+&)
:'. +='+ +=& '%2=' 5"!2"/&/+ "C +=& )"$-5& #&C*/&) *+) +-'/)%$5&/5.7 >*0$-& D7EE )=":) +=& -&)$%+ "C Q")+G5-*2+ '/# )&/#) *+ +" lp "- lpr 9"- +" +=& 2-"0-'! )&+ $)*/0 QPrinter::setPrintProgram();7
#-':*/0 ' )&!*R+-'/)2'-&/+ F$++&-C%. "/ +"2 "C ' 5=&5(&- 2'++&-/ :*+= +=& #*CC&-&/+ !"#&)7 QPrinter 5'/ '%)" F& $)&# +" 0&/&-'+& QT> C*%&) F. 5'%%*/0 setOutputFormat(QPrinter::PdfFormat)7

!"#$%&'())( QPainter*+&5-,9-+!.!-1&,-4%+ !"#$%&'()6(&<$!1.!1"&8 QImage


[View full size image]

Y"!2")*+*"/) !"#&) '-& )&+ $)*/0 QPainter::setCompositionMode()7 >"- &?'!2%&< =&-&B) =": +"
5-&'+& ' QImage 5"/+'*/*/0 +=& b1d "C +=& F$++&-C%. '/# +=& 5=&5(&- 2'++&-/@

QImage resultImage = checkerPatternImage;


QPainter painter(&resultImage);
painter.setCompositionMode(QPainter::CompositionMode_Xor);
painter.drawImage(0, 0, butterflyImage);
}

A& '))$!& +='+ +=& PrintWindow 5%')) =') ' !&!F&- ,'-*'F%& 5'%%&# printer "C +.2& QPrinter7 A&
5"$%# )*!2%. =',& 5-&'+&# +=& QPrinter "/ +=& )+'5( */ printImage()< F$+ +=&/ *+ :"$%# /"+
-&!&!F&- +=& $)&-B) )&++*/0) C-"! "/& 2-*/+ -$/ +" '/"+=&-7

A& 5-&'+& ' QPrintDialog '/# 5'%% exec() +" )=": *+7 I+ -&+$-/) true *C +=& $)&- 5%*5(&# +=& 1g
F$++"/U "+=&-:*)&< *+ -&+$-/) false7 KC+&- +=& 5'%% +" exec()< +=& QPrinter "FJ&5+ *) -&'#. +" $)&7 9I+ *)
'%)" 2"))*F%& +" 2-*/+ :*+="$+ $)*/0 ' QPrintDialog< F. #*-&5+%. 5'%%*/0 QPrinter !&!F&- C$/5+*"/) +"
)&+ +=*/0) $27;

^&?+< :& 5-&'+& ' QPainter +" #-': "/ +=& QPrinter7 A& )&+ +=& :*/#": +" +=& *!'0&B) -&5+'/0%& '/#
+=& ,*&:2"-+ +" ' -&5+'/0%& :*+= +=& )'!& ')2&5+ -'+*"< '/# :& #-': +=& *!'0& '+ 2")*+*"/ 9X< X;7

N. #&C'$%+< QPainterB) :*/#": *) */*+*'%*H&# )" +='+ +=& 2-*/+&- '22&'-) +" =',& ' )*!*%'- -&)"%$+*"/ ')
+=& )5-&&/ 9$)$'%%. )"!&:=&-& F&+:&&/ ]_ '/# EXX #"+) 2&- */5=;< !'(*/0 *+ &'). +" -&$)& :*#0&+
2'*/+*/0 5"#& C"- 2-*/+*/07 L&-&< *+ #*#/B+ !'++&-< F&5'$)& :& )&+ "$- ":/ :*/#":7

Q-*/+*/0 *+&!) +='+ +'(& $2 /" !"-& +='/ ' )*/0%& 2'0& *) )*!2%&< F$+ !'/. '22%*5'+*"/) /&&# +"
2-*/+ !$%+*2%& 2'0&)7 >"- +=")&< :& /&&# +" 2'*/+ "/& 2'0& '+ ' +*!& '/# 5'%% newPage() +" '#,'/5&
+" +=& /&?+ 2'0&7 8=*) -'*)&) +=& 2-"F%&! "C #&+&-!*/*/0 =": !$5= */C"-!'+*"/ :& 5'/ 2-*/+ "/
&'5= 2'0&7 8=&-& '-& +:" !'*/ '22-"'5=&) +" ='/#%*/0 !$%+*R2'0& #"5$!&/+) :*+= 6+@

• A& 5'/ 5"/,&-+ "$- #'+' +" L8c4 '/# -&/#&- *+ $)*/0 QTextdocument< 6+B) -*5= +&?+ &/0*/&7
• A& 5'/ 2&-C"-! +=& #-':*/0 '/# +=& 2'0& F-&'(*/0 F. ='/#7

A& :*%% -&,*&: F"+= '22-"'5=&) */ +$-/7 K) '/ &?'!2%&< :& :*%% 2-*/+ ' C%":&- 0$*#&@ ' %*)+ "C C%":&-
/'!&)< &'5= :*+= ' +&?+$'% #&)5-*2+*"/7 Z'5= &/+-. */ +=& 0$*#& *) )+"-&# ') ' )+-*/0 "C +=& C"-!'+
V"-8!@0!&6$, *,)"V< C"- &?'!2%&@

Miltonopsis santanae: A most dangerous orchid species.

G*/5& &'5= C%":&-B) #'+' *) -&2-&)&/+&# F. ' )*/0%& )+-*/0< :& 5'/ -&2-&)&/+ '%% +=& C%":&-) */ +=&
0$*#& $)*/0 "/& QStringList7 L&-&B) +=& C$/5+*"/ +='+ 2-*/+) ' C%":&- 0$*#& $)*/0 6+B) -*5= +&?+
&/0*/&@

void PrintWindow::printFlowerGuide(const QStringList &entries)


{
QString html;
foreach (QString entry, entries) {
4&+B) )+'-+ :*+= )"!& )*!2%& &?'!2%&) +='+ '%% 2-*/+ "/ ' )*/0%& 2'0&7 8=& C*-)+ &?'!2%& 2-*/+) ' QStringList fields = entry.split(": ");
QImage@ QString title = Qt::escape(fields[0]);
QString body = Qt::escape(fields[1]);
html += "<table width=\"100%\" border=1 cellspacing=0>\n"
"<tr><td bgcolor=\"lightgray\"><font size=\"+1\">"
void PrintWindow::printImage(const QImage &image)
"<b><i>" + title + "</i></b></font>\n<tr><td>" + body
{
+ "\n</table>\n<br>\n";
QPrintDialog printDialog(&printer, this);
}
if (printDialog.exec()) {
printHtml(html);
QPainter painter(&printer);
}
QRect rect = painter.viewport();
QSize size = image.size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), 8=& C*-)+ )+&2 *) +" 5"/,&-+ +=& QStringList */+" L8c47 Z'5= C%":&- F&5"!&) '/ L8c4 +'F%& :*+= +:"
size.width(), size.height()); 5&%%)7 A& $)& Qt::escape() +" -&2%'5& +=& )2&5*'% 5='-'5+&-) BhB< BiB< BjB :*+= +=& 5"--&)2"/#*/0 L8c4
painter.setWindow(image.rect()); &/+*+*&) 9Vh'!2UV< Vh%+UV< Vh0+UV;7 8=&/ :& 5'%% printHtml() +" 2-*/+ +=& +&?+7
painter.drawImage(0, 0, image);
}
&'5= QStringList ="%#*/0 +=& &/+-*&) C"- "/& 2'0&7 A& 2')) "/ +='+ -&)$%+ +" printPages()7
void PrintWindow::printHtml(const QString &html)
{
>"- &?'!2%&< %&+B) )$22")& +='+ +=& C%":&- 0$*#& 5"/+'*/) W &/+-*&)< :=*5= :& :*%% -&C&- +" ') <;.=;.5;
QPrintDialog printDialog(&printer, this);
if (printDialog.exec()) { >;.?< '/# @ ^": %&+B) )$22")& +='+ +=&-& *) -""! C"- < '/# = "/ +=& C*-)+ 2'0&U5;.>< '/# ? "/ +=&
QPainter painter(&printer); )&5"/# 2'0&U '/# @ "/ +=& +=*-# 2'0&7 8=& pages %*)+ :"$%# +=&/ =',& +=& %*)+ k<;.=l '+ */#&?
QTextDocument textDocument; 2")*+*"/ X< +=& %*)+ k5;.>;.?l '+ */#&? 2")*+*"/ E< '/# +=& %*)+ k@ l '+ */#&? 2")*+*"/ _7
textDocument.setHtml(html);
textDocument.print(&printer);
} void PrintWindow::paginate(QPainter *painter, QList<QStringList> *pages,
} const QStringList &entries)
{
QStringList currentPage;
int pageHeight = painter->window().height() - 2 * LargeGap;
8=& printHtml() C$/5+*"/ 2"2) $2 ' QPrintDialog '/# +'(&) 5'-& "C 2-*/+*/0 '/ L8c4 #"5$!&/+7 I+ int y = 0;
5'/ F& -&$)&# V') *)V */ '/. 6+ '22%*5'+*"/ +" 2-*/+ '-F*+-'-. L8c4 2'0&)7 foreach (QString entry, entries) {
int height = entryHeight(painter, entry);
!"#$%&'();(&<$!1.!1"&8&/2-F%$&"#!4%&#+!1" QTextdocument if (y + height > pageHeight && !currentPage.empty()) {
pages->append(currentPage);
[View full size image] currentPage.clear();
y = 0;
}
currentPage.append(entry);
y += height + MediumGap;
}
if (!currentPage.empty())
pages->append(currentPage);
}

8=& paginate() C$/5+*"/ #*)+-*F$+&) +=& C%":&- 0$*#& &/+-*&) */+" 2'0&)7 I+ -&%*&) "/ +=& entryHeight()
C$/5+*"/< :=*5= 5"!2$+&) +=& =&*0=+ "C "/& &/+-.7 I+ '%)" +'(&) */+" '55"$/+ +=& ,&-+*5'% 0'2) '+ +=&
+"2 '/# F"++"! "C +=& 2'0&< "C )*H& LargeGap7

A& *+&-'+& +=-"$0= +=& &/+-*&) '/# '22&/# +=&! +" +=& 5$--&/+ 2'0& $/+*% :& 5"!& +" '/ &/+-. +='+
#"&)/B+ C*+U +=&/ :& '22&/# +=& 5$--&/+ 2'0& +" +=& pages %*)+ '/# )+'-+ ' /&: 2'0&7

int PrintWindow::entryHeight(QPainter *painter, const QString &entry)


{
QStringList fields = entry.split(": ");
QString title = fields[0];
QString body = fields[1];
Y"/,&-+*/0 ' #"5$!&/+ +" L8c4 '/# $)*/0 QTextdocument +" 2-*/+ *+ *) F. C'- +=& !")+ 5"/,&/*&/+
'%+&-/'+*,& C"- 2-*/+*/0 -&2"-+) '/# "+=&- 5"!2%&? #"5$!&/+)7 I/ 5')&) :=&-& :& /&&# !"-& 5"/+-"%< int textWidth = painter->window().width() - 2 * SmallGap;
:& 5'/ #" +=& 2'0& %'."$+ '/# +=& #-':*/0 F. ='/#7 4&+B) /": )&& =": :& 5'/ $)& +=*) '22-"'5= +" int maxHeight = painter->window().height();
2-*/+ ' C%":&- 0$*#&7 L&-&B) +=& /&: printFlowerGuide() C$/5+*"/@ painter->setFont(titleFont);
QRect titleRect = painter->boundingRect(0, 0, textWidth, maxHeight,
Qt::TextWordWrap, title);
void PrintWindow::printFlowerGuide(const QStringList &entries) painter->setFont(bodyFont);
{ QRect bodyRect = painter->boundingRect(0, 0, textWidth, maxHeight,
QPrintDialog printDialog(&printer, this); Qt::TextWordWrap, body);
if (printDialog.exec()) { return titleRect.height() + bodyRect.height() + 4 * SmallGap;
}
QPainter painter(&printer);
QList<QStringList> pages;
paginate(&painter, &pages, entries);
8=& enTRyHeight() C$/5+*"/ $)&) QPainter::boundingRect() +" 5"!2$+& +=& ,&-+*5'% )2'5& /&&#&# F.
printPages(&painter, pages);
} "/& &/+-.7 >*0$-& D7E` )=":) +=& %'."$+ "C ' C%":&- &/+-. '/# +=& !&'/*/0 "C +=& SmallGap '/#
} MediumGap 5"/)+'/+)7

!"#$%&'()=(&L&/2-F%$&%1.$3*+&283-#.
KC+&- )&++*/0 $2 +=& 2-*/+&- '/# 5"/)+-$5+*/0 +=& 2'*/+&-< :& 5'%% +=& paginate() =&%2&- C$/5+*"/ +"
#&+&-!*/& :=*5= &/+-. )="$%# '22&'- "/ :=*5= 2'0&7 8=& -&)$%+ "C +=*) *) ' %*)+ "C QStringList)< :*+=
numCopies() C"- +=& )'(& "C )*!2%*5*+.7;

!"#$%&'()@(&<$!1.!1"&8&/2-F%$&"#!4%&#+!1" QPainter
[View full size image]

void PrintWindow::printPages(QPainter *painter,


const QList<QStringList> &pages)
{
int firstPage = printer.fromPage() - 1;
if (firstPage >= pages.size())
return;
if (firstPage == -1)
firstPage = 0;
int lastPage = printer.toPage() - 1;
if (lastPage == -1 || lastPage >= pages.size())
lastPage = pages.size() - 1;
8=& *//&- for %""2 *+&-'+&) +=-"$0= +=& 2'0&)7 IC +=& 2'0& *)/B+ +=& C*-)+ 2'0&< :& 5'%% newPage() +"
int numPages = lastPage - firstPage + 1;
for (int i = 0; i < printer.numCopies(); ++i) { C%$)= +=& "%# 2'0& '/# )+'-+ 2'*/+*/0 "/ ' C-&)= 2'0&7 A& 5'%% printPage() +" 2'*/+ &'5= 2'0&7
for (int j = 0; j < numPages; ++j) {
if (i != 0 || j != 0)
printer.newPage(); void PrintWindow::printPage(QPainter *painter,
int index; const QStringList &entries, int pageNumber)
if (printer.pageOrder() == QPrinter::FirstPageFirst) { {
index = firstPage + j; painter->save();
} else { painter->translate(0, LargeGap);
foreach (QString entry, entries) {
index = lastPage - j; QStringList fields = entry.split(": ");
} QString title = fields[0];
printPage(painter, pages[index], index + 1); QString body = fields[1];
} printBox(painter, title, titleFont, Qt::lightGray);
} printBox(painter, body, bodyFont, Qt::white);
} painter->translate(0, MediumGap);
}
painter->restore();
painter->setFont(footerFont);
8=& printPages() C$/5+*"/B) -"%& *) +" 2-*/+ &'5= 2'0& $)*/0 printPage() */ +=& 5"--&5+ "-#&- '/# +=& painter->drawText(painter->window(),
5"--&5+ '!"$/+ "C +*!&)7 f)*/0 +=& QPrintDialog< +=& $)&- !*0=+ -&P$&)+ )&,&-'% 5"2*&)< )2&5*C. ' Qt::AlignHCenter | Qt::AlignBottom,
2-*/+ -'/0&< "- -&P$&)+ +=& 2'0&) */ -&,&-)& "-#&-7 I+ *) "$- -&)2"/)*F*%*+. +" ="/"- +=&)& "2+*"/)"- +" QString::number(pageNumber));
#*)'F%& +=&! $)*/0 QPrintDialog::setEnabledOptions()7 }

A& )+'-+ F. #&+&-!*/*/0 +=& -'/0& +" 2-*/+7 QPrinterB) fromPage() '/# toPage() C$/5+*"/) -&+$-/ +=&
2'0& /$!F&-) )&%&5+&# F. +=& $)&-< "- X *C /" -'/0& :') 5=")&/7 A& )$F+-'5+ E F&5'$)& "$- pages 8=& printPage() C$/5+*"/ *+&-'+&) +=-"$0= '%% +=& C%":&- 0$*#& &/+-*&) '/# 2-*/+) +=&! $)*/0 +:" 5'%%)
%*)+ *) */#&?&# C-"! X< '/# )&+ firstPage '/# lastPage +" 5",&- +=& C$%% -'/0& *C +=& $)&- #*#/B+ )&+ +" printBox()@ "/& C"- +=& +*+%& 9+=& C%":&-B) /'!&; '/# "/& C"- +=& F"#. 9*+) #&)5-*2+*"/;7 I+ '%)"
'/. -'/0&7 #-':) +=& 2'0& /$!F&- 5&/+&-&# '+ +=& F"++"! "C +=& 2'0&7

8=&/ :& 2-*/+ &'5= 2'0&7 8=& "$+&- for %""2 *+&-'+&) ') !'/. +*!&) ') /&5&))'-. +" 2-"#$5& +=& !"#$%&'()C(&I?%&/2-F%$&"#!4%*+&98"%&283-#.
/$!F&- "C 5"2*&) -&P$&)+&# F. +=& $)&-7 c")+ 2-*/+&- #-*,&-) )$22"-+ !$%+*2%& 5"2*&)< )" C"- +=")&
QPrinter::numCopies() '%:'.) -&+$-/) E7 IC +=& 2-*/+&- #-*,&- 5'/B+ ='/#%& !$%+*2%& 5"2*&)<
numCopies() -&+$-/) +=& /$!F&- "C 5"2*&) -&P$&)+&# F. +=& $)&-< '/# +=& '22%*5'+*"/ *) -&)2"/)*F%&
C"- 2-*/+*/0 +='+ /$!F&- "C 5"2*&)7 9I/ +=& QImage &?'!2%& &'-%*&- */ +=*) )&5+*"/< :& *0/"-&#
8" )=": =": +=*) :"-()< :& :*%% -&,*&: +=& 5"#& "C +=& 8&+-'=&#-"/ '22%*5'+*"/ )=":/ */ >*0$-&
D7E]7 8=& '22%*5'+*"/ 2-&)&/+) ' ST +&+-'=&#-"/< "- C"$-R)*#&# #*&< :*+= &'5= C'5& #-':/ $)*/0 '
#*CC&-&/+ 5"%"-7 8=& $)&- 5'/ -"+'+& +=& +&+-'=&#-"/ F. 2-&))*/0 ' !"$)& F$++"/ '/# #-'00*/07 8=&
$)&- 5'/ )&+ +=& 5"%"- "C ' C'5& F. #"$F%&R5%*5(*/0 *+ '/# 5="")*/0 ' 5"%"- C-"! +=& QColorDialog +='+
2"2) $27

!"#$%&'()D(&I?%&I%.$8?%4$-1&8992!58.!-1

void PrintWindow::printBox(QPainter *painter, const QString &str,


const QFont &font, const QBrush &brush)
{
painter->setFont(font);
int boxWidth = painter->window().width();
int textWidth = boxWidth - 2 * SmallGap;
int maxHeight = painter->window().height();
QRect textRect = painter->boundingRect(SmallGap, SmallGap,
textWidth, maxHeight,
Qt::TextWordWrap, str);
int boxHeight = textRect.height() + 2 * SmallGap; class Tetrahedron : public QGLWidget
painter->setPen(QPen(Qt::black, 2, Qt::SolidLine)); {
painter->setBrush(brush); Q_OBJECT
painter->drawRect(0, 0, boxWidth, boxHeight); public:
painter->drawText(textRect, Qt::TextWordWrap, str); Tetrahedron(QWidget *parent = 0);
painter->translate(0, boxHeight); protected:
} void initializeGL();
void resizeGL(int width, int height);
void paintGL();
8=& printBox() C$/5+*"/ #-':) +=& "$+%*/& "C ' F"?< +=&/ #-':) +=& +&?+ */)*#& +=& F"?7 void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
private:
void draw();
int faceAtPosition(const QPoint &pos);
GLfloat rotationX;
Graphics with OpenGL GLfloat rotationY;
GLfloat rotationZ;
12&/34 *) ' )+'/#'-# KQI C"- -&/#&-*/0 _T '/# ST 0-'2=*5)7 6+ '22%*5'+*"/) 5'/ #-': ST 0-'2=*5) QColor faceColors[4];
QPoint lastPos;
F. $)*/0 +=& A*B !"C+ !"#$%&< :=*5= -&%*&) "/ +=& ).)+&!B) 12&/34 %*F-'-.7 8=*) )&5+*"/ '))$!&)
};
+='+ ."$ '-& C'!*%*'- :*+= 12&/347 IC 12&/34 *) /&: +" ."$< ' 0""# 2%'5& +" )+'-+ %&'-/*/0 *+ *)
=++2@mm:::7"2&/0%7"-0m7

T-':*/0 0-'2=*5) :*+= 12&/34 C-"! ' 6+ '22%*5'+*"/ *) )+-'*0=+C"-:'-#@ A& !$)+ )$F5%')) !" Tetrahedron#$%&''#()!"*(+'#,*-. QGLWidget/# !" initializeGL()0 resizeGL()0#&)1 paintGL()
QGLWidget< -&*!2%&!&/+ ' C&: ,*-+$'% C$/5+*"/)< '/# %*/( +=& '22%*5'+*"/ '0'*/)+ +=& A*B !"C+ '/# ,2)$+(-)'#&*"#*"(.3%".")+"1#,*-. QGLWidget/# !"#.-2'"#"4")+#!&)1%"*'#&*"#*"(.3%".")+"1#,*-.
12&/34 %*F-'-*&)7 N&5'$)& QGLWidget */=&-*+) C-"! QWidget< !")+ "C :='+ :& '%-&'#. (/": )+*%% QWidget#&' 2'2&%/
'22%*&)7 8=& !'*/ #*CC&-&/5& *) +='+ :& $)& )+'/#'-# 12&/34 C$/5+*"/) +" 2&-C"-! +=& #-':*/0
*/)+&'# "C QPainter7
Tetrahedron::Tetrahedron(QWidget *parent)
: QGLWidget(parent)
{ {
setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer)); static const GLfloat P1[3] = { 0.0, -1.0, +2.0 };
rotationX = -21.0; static const GLfloat P2[3] = { +1.73205081, -1.0, -1.0 };
rotationY = -57.0; static const GLfloat P3[3] = { -1.73205081, -1.0, -1.0 };
rotationZ = 0.0; static const GLfloat P4[3] = { 0.0, +2.0, 0.0 };
faceColors[0] = Qt::red; static const GLfloat * const coords[4][3] = {
faceColors[1] = Qt::green; { P1, P2, P3 }, { P1, P3, P4 }, { P1, P4, P2 }, { P2, P4, P3 }
faceColors[2] = Qt::blue; };
faceColors[3] = Qt::yellow; glMatrixMode(GL_MODELVIEW);
} glLoadIdentity();
glTranslatef(0.0, 0.0, -10.0);
glRotatef(rotationX, 1.0, 0.0, 0.0);
glRotatef(rotationY, 0.0, 1.0, 0.0);
5)#+!"#$-)'+*2$+-*0#6"#$&%% QGLWidget::setFormat()#+-#'3"$(,7#+!"#83")9:#1('3%&7#$-)+";+0#&)1#6" glRotatef(rotationZ, 0.0, 0.0, 1.0);
()(+(&%(<"#+!"#$%&''='#3*(4&+"#4&*(&>%"'/ for (int i = 0; i < 4; ++i) {
glLoadName(i);
glBegin(GL_TRIANGLES);
void Tetrahedron::initializeGL() qglColor(faceColors[i]);
{ for (int j = 0; j < 3; ++j) {
qglClearColor(Qt::black); glVertex3f(coords[i][j][0], coords[i][j][1],
glShadeModel(GL_FLAT); coords[i][j][2]);
glEnable(GL_DEPTH_TEST); }
glEnable(GL_CULL_FACE); glEnd();
} }
}

!" initializeGL()#,2)$+(-)#('#$&%%"1#?2'+#-)$"0#>",-*" paintGL()#('#$&%%"1/# !('#('#+!"#3%&$"#6!"*"


6"#$&)#'"+#23#+!"#83")9:#*")1"*()@#$-)+";+0#1",()"#1('3%&7#%('+'0#&)1#3"*,-*.#-+!"*#()(+(&%(<&+(-)'/ 5) draw()0#6"#1*&6#+!"#+"+*&!"1*-)0#+&B()@#()+-#&$$-2)+#+!" !"#0#&)1 $#*-+&+(-)'#&)1#+!"#$-%-*'
'+-*"1#()#+!" faceColors#&**&7/#E4"*7+!()@#('#'+&)1&*1#83")9:0#";$"3+#,-*#+!" qglColor()#$&%%/#F"
A%%#+!"#$-1"#('#'+&)1&*1#83")9:0#";$"3+#,-*#+!"#$&%%#+- QGLWidget=' qglClear-Color()#,2)$+(-)/#5,#6" $-2%1#!&4"#2'"1#-)"#-,#+!"#83")9:#,2)$+(-)' glColor3d()#-* glIndex()#()'+"&10#1"3")1()@#-)#+!"
6&)+"1#+-#'+($B#+-#'+&)1&*1#83")9:0#6"#6-2%1#$&%% glClearColor()#()#C9DA#.-1"#&)1 .-1"/
glClearIndex() ()#$-%-*#()1";#.-1"#()'+"&1/

void Tetrahedron::mousePressEvent(QMouseEvent *event)


void Tetrahedron::resizeGL(int width, int height) {
{ lastPos = event->pos();
glViewport(0, 0, width, height); }
glMatrixMode(GL_PROJECTION); void Tetrahedron::mouseMoveEvent(QMouseEvent *event)
glLoadIdentity(); {
GLfloat x = GLfloat(width) / height; GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0); GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
glMatrixMode(GL_MODELVIEW); if (event->buttons() & Qt::LeftButton) {
} rotationX += 180 * dy;
rotationY += 180 * dx;
updateGL();
} else if (event->buttons() & Qt::RightButton) {
!" resizeGL()#,2)$+(-)#('#$&%%"1#>",-*" paintGL()#('#$&%%"1#+!"#,(*'+#+(."0#>2+#&,+"* initializeGL()#(' rotationX += 180 * dy;
$&%%"1/#5+#('#&%'-#$&%%"1#6!")"4"*#+!"#6(1@"+#('#*"'(<"1/# !('#('#+!"#3%&$"#6!"*"#6"#$&)#'"+#23#+!" rotationZ += 180 * dx;
83")9:#4("63-*+0#3*-?"$+(-)0#&)1#&)7#-+!"*#'"++()@'#+!&+#1"3")1#-)#+!"#6(1@"+='#'(<"/ updateGL();
}
lastPos = event->pos();
void Tetrahedron::paintGL() }
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw(); !" mousePressEvent()#&)1 mouseMoveEvent()#,2)$+(-)'#&*"#*"(.3%".")+"1#,*-. QWidget#+-#&%%-6#+!"
}
2'"*#+-#*-+&+"#+!"#4("6#>7#$%($B()@#&)1#1*&@@()@/# !"#%",+#.-2'"#>2++-)#&%%-6'#+!"#2'"*#+-#*-+&+"
&*-2)1#+!" #&)1 ##&;"'0#+!"#*(@!+#.-2'"#>2++-)#&*-2)1#+!" #&)1 $#&;"'/

!" paintGL()#,2)$+(-)#('#$&%%"1#6!")"4"*#+!"#6(1@"+#)""1'#+-#>"#*"3&()+"1/# !(' ('#'(.(%&*#+- A,+"*#.-1(,7()@#+!" rotationX#4&*(&>%"0#&)1#"(+!"*#+!" rotationY#-*#+!" rotationZ#4&*(&>%"0#6"#$&%%


QWidget::paintEvent()0#>2+#()'+"&1#-, QPainter#,2)$+(-)'#6"#2'"#83")9:#,2)$+(-)'/# !"#&$+2&% updateGL()#+-#*"1*&6#+!"#'$")"/
1*&6()@#('#3"*,-*."1#>7#+!"#3*(4&+"#,2)$+(-) draw()/

void Tetrahedron::mouseDoubleClickEvent(QMouseEvent *event)


void Tetrahedron::draw() {
int face = faceAtPosition(event->pos()); tetrahedron.setWindowTitle(QObject::tr("Tetrahedron"));
if (face != -1) { tetrahedron.resize(300, 300);
QColor color = QColorDialog::getColor(faceColors[face], this); tetrahedron.show();
if (color.isValid()) { return app.exec();
faceColors[face] = color; }
updateGL();
}
}
} 5,#+!"#2'"*='#'7'+".#1-"')=+#'233-*+#83")9:0#6"#3*()+#&)#"**-*#."''&@"#+-#+!"#$-)'-%"#&)1#*"+2*)
(.."1(&+"%7/

-#%()B#+!"#&33%($&+(-)#&@&()'+#+!" %&'()*+,#.-12%"#&)1#+!"#'7'+".='#83")9:#%(>*&*70#+!" .pro#,(%"


!" mouseDoubleClickEvent()#('#*"(.3%".")+"1#,*-. QWidget#+-#&%%-6#+!"#2'"*#+-#'"+#+!"#$-%-*#-,#&
)""1'#+!('#")+*7M
+"+*&!"1*-)#,&$"#>7#1-2>%"G$%($B()@#(+/#F"#$&%%#+!"#3*(4&+"#,2)$+(-) faceAtPosition()#+-#1"+"*.()"
6!($!#,&$"0#(,#&)70#('#%-$&+"1#2)1"*#+!"#$2*'-*/#5,#&#,&$"#6&'#1-2>%"G$%($B"10#6"#$&%%
QColorDialog::getColor()#+-#->+&()#&#)"6#$-%-*#,-*#+!&+#,&$"/# !")#6"#231&+"#+!" faceColors#&**&7 QT += opengl
6(+!#+!"#)"6#$-%-*0#&)1#6"#$&%% updateGL()#+-#*"1*&6#+!"#'$")"/

int Tetrahedron::faceAtPosition(const QPoint &pos) !&+#$-.3%"+"'#+!"# "+*&!"1*-)#&33%($&+(-)/#N-*#.-*"#(),-*.&+(-)#&>-2+#+!" %&'()*+,#.-12%"0


{ '""#+!"#*","*")$"#1-$2.")+&+(-)#,-* QGLWidget0 QGLFormat0 QGLContext0 QGLColormap0#&)1
const int MaxSize = 512; QGLPixelBuffer/
GLuint buffer[MaxSize];
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glSelectBuffer(MaxSize, buffer);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix(GLdouble(pos.x()), GLdouble(viewport[3] - pos.y()),
5.0, 5.0, viewport);
GLfloat x = GLfloat(width()) / height();
glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
draw();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
if (!glRenderMode(GL_RENDER))
return -1;
return buffer[3];
}

!" faceAtPosition()#,2)$+(-)#*"+2*)'#+!"#)2.>"*#-,#+!"#,&$"#&+#&#$"*+&()#3-'(+(-)#-)#+!"#6(1@"+0#-*
GH#(,#+!"*"#('#)-#,&$"#&+#+!&+#3-'(+(-)/# !"#$-1"#,-*#1"+"*.()()@#+!('#()#83")9:#('#&#>(+#$-.3%($&+"1/
E''")+(&%%70#6!&+#6"#1-#('#*")1"*#+!"#'$")"#() GL_SELECT#.-1"#+-#+&B"#&14&)+&@"#-,#83")9:='
3($B()@#$&3&>(%(+("'#&)1#+!")#*"+*("4"#+!"#,&$"#)2.>"*#I(+'#J)&."JK#,*-.#+!"#83")9:#!(+#*"$-*1/

L"*"=' main.cppM

#include <QApplication>
#include <iostream>
#include "tetrahedron.h"
using namespace std;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!QGLFormat::hasOpenGL()) {
cerr << "This system has no OpenGL support" << endl;
return 1;
}
Tetrahedron tetrahedron;
&$$"3+'#+";+2&%#1*&@'#,*-.#-+!"*#&33%($&+(-)'0#&)1#(,#+!"#2'"*#1*-3'#&#,(%"#-)+-#(+0#(+#6(%%#()'"*+#+!"#,(%"
)&."#()+-#+!" +";+/#Q()$"#1*-3#"4")+'#&*"#3*-3&@&+"1#,*-.#$!(%1#+-#3&*")+0#>7#1('&>%()@#1*-33()@#-)
Chapter 9. Drag and Drop +!" QTextEdit#&)1#")&>%()@#(+#-)#+!"#.&()#6()1-60#6"#@"+#+!"#1*-3#"4")+'#,-*#+!"#6!-%"#6()1-6#()
MainWindow/

• !"#$%!&'()"&'"!*'()+,
• -.,,+)/%!&'0.1/+2'()"&'34,51
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
• 0$%,#+")*'6"!*$%!&
{
if (event->mimeData()->hasFormat("text/uri-list"))
O*&@#&)1#1*-3#('#&#.-1"*)#&)1#()+2(+(4"#6&7#-,#+*&)',"**()@#(),-*.&+(-)#6(+!()#&)#&33%($&+(-)#-* event->acceptProposedAction();
>"+6"")#1(,,"*")+#&33%($&+(-)'/#5+#('#-,+")#3*-4(1"1#()#&11(+(-)#+-#$%(3>-&*1#'233-*+#,-*#.-4()@#&)1 }
$-37()@#1&+&/

5)#+!('#$!&3+"*0#6"#6(%%#'""#!-6#+-#&11#1*&@#&)1#1*-3#'233-*+#+-#&)#&33%($&+(-)#&)1#!-6#+-#!&)1%" !" dragEnterEvent()#('#$&%%"1#6!")"4"*#+!"#2'"*#1*&@'#&)#->?"$+#-)+-#&#6(1@"+/#5,#6"#$&%%


$2'+-.#,-*.&+'/# !")#6"#6(%%#'!-6#!-6#+-#*"2'"#+!"#1*&@#&)1#1*-3#$-1"#+-#&11#$%(3>-&*1#'233-*+/ acceptProposedAction()#-)#+!"#"4")+0#6"#()1($&+"#+!&+#+!"#2'"*#$&)#1*-3#+!"#1*&@#->?"$+#-)#+!('
!('#$-1"#*"2'"#('#3-''(>%"#>"$&2'"#>-+!#."$!&)('.'#&*"#>&'"1#-) QMimeData0#&#$%&''#+!&+#$&) 6(1@"+/#D7#1",&2%+0#+!"#6(1@"+#6-2%1)=+#&$$"3+#+!"#1*&@/#P+#&2+-.&+($&%%7#$!&)@"'#+!"#$2*'-*#+-
3*-4(1"#1&+&#()#'"4"*&%#,-*.&+'/ ()1($&+"#+-#+!"#2'"*#6!"+!"*#-*#)-+#+!"#6(1@"+#('#&#%"@(+(.&+"#1*-3#'(+"/

Enabling Drag and Drop L"*"#6"#6&)+#+!"#2'"*#+-#>"#&%%-6"1#+-#1*&@#,(%"'#>2+#)-+!()@#"%'"/# -#1-#'-0#6"#$!"$B#+!"#R5RE


+73"#-,#+!"#1*&@/# !"#R5RE#+73" text/uri-list#('#2'"1#+-#'+-*"#&#%('+#-,#2)(4"*'&%#*"'-2*$"#(1")+(,("*'
ISC5'K0#6!($!#$&)#>"#,(%"#)&."'0#SC:'#I'2$!#&'#L T#-*#N T#3&+!'K0#-*#-+!"*#@%->&%#*"'-2*$"
O*&@#&)1#1*-3#()4-%4"'#+6-#1('+()$+#&$+(-)'M#1*&@@()@#&)1#1*-33()@/#P+#6(1@"+'#$&)#'"*4"#&'#1*&@
(1")+(,("*'/#Q+&)1&*1#R5RE#+73"'#&*"#1",()"1#>7#+!"#5)+"*)"+#A''(@)"1#U2.>"*'#A2+!-*(+7#I5AUAK/
'(+"'0#&'#1*-3#'(+"'0#-*#&'#>-+!/
!"7#$-)'('+#-,#&#+73"#&)1#&#'2>+73"#'"3&*&+"1#>7#&#'%&'!/#R5RE#+73"'#&*"#2'"1#>7#+!"#$%(3>-&*1
&)1#>7#+!"#1*&@#&)1#1*-3#'7'+".#+-#(1")+(,7#1(,,"*")+#+73"'#-,#1&+&/# !"#-,,($(&%#%('+#-,#R5RE#+73"'#('
82*#,(*'+#";&.3%"#'!-6'#!-6#+-#.&B"#&#P+#&33%($&+(-)#&$$"3+#&#1*&@#()(+(&+"1#>7#&)-+!"*#&33%($&+(-)/ &4&(%&>%"#&+ !++3MVV666/(&)&/-*@V&''(@).")+'V."1(&G+73"'V/
!"#P+#&33%($&+(-)#('#&#.&()#6()1-6#6(+!#& QTextEdit#&'#(+'#$")+*&%#6(1@"+/#F!")#+!"#2'"*#1*&@'#&
+";+#,(%"#,*-.#+!"#1"'B+-3#-*#,*-.#&#,(%"#";3%-*"*#&)1#1*-3'#(+#-)+-#+!"#&33%($&+(-)0#+!"#&33%($&+(-)
%-&1'#+!"#,(%"#()+-#+!" QTextEdit/ void MainWindow::dropEvent(QDropEvent *event)
{
L"*"='#+!"#1",()(+(-)#-,#+!"#";&.3%"=' MainWindow#$%&''M QList<QUrl> urls = event->mimeData()->urls();
if (urls.isEmpty())
return;
class MainWindow : public QMainWindow QString fileName = urls.first().toLocalFile();
{ if (fileName.isEmpty())
Q_OBJECT return;
public: if (readFile(fileName))
MainWindow(); setWindowTitle(tr("%1 - %2").arg(fileName)
protected: .arg(tr("Drag File")));
void dragEnterEvent(QDragEnterEvent *event); }
void dropEvent(QDropEvent *event);
private:
bool readFile(const QString &fileName); !" dropEvent()#('#$&%%"1#6!")#+!"#2'"*#1*-3'#&)#->?"$+#-)+-#+!"#6(1@"+/#F"#$&%% QMimeData::urls()
QTextEdit *textEdit;
+-#->+&()#&#%('+#-, QUrl'/# 73($&%%70#2'"*'#-)%7#1*&@#-)"#,(%"#&+#&#+(."0#>2+#(+#('#3-''(>%"#,-*#+!".#+-
};
1*&@#.2%+(3%"#,(%"'#>7#1*&@@()@#&#'"%"$+(-)/#5,#+!"*"='#.-*"#+!&+#-)"#SC:0#-*#(,#+!"#SC:#('#)-+#&#%-$&%
,(%"#)&."0#6"#*"+2*)#(.."1(&+"%7/

!" MainWindow#$%&''#*"(.3%".")+' dragEnterEvent()#&)1 dropEvent()#,*-. QWidget/#Q()$"#+!" QWidget#&%'-#3*-4(1"' dragMoveEvent()#&)1 dragLeaveEvent()0#>2+#,-*#.-'+#&33%($&+(-)'#+!"7#1-)=+


32*3-'"#-,#+!"#";&.3%"#('#+-#'!-6#1*&@#&)1#1*-30#.2$!#-,#+!"#,2)$+(-)&%(+7#6"#6-2%1#";3"$+#+-#>" )""1#+-#>"#*"(.3%".")+"1/
()#&#.&()#6()1-6#$%&''#!&'#>"")#-.(++"1/
!"#'"$-)1#";&.3%"#(%%2'+*&+"'#!-6 +-#()(+(&+"#&#1*&@#&)1#&$$"3+#&#1*-3/#F"#6(%%#$*"&+"#&
QListWidget#'2>$%&''#+!&+#'233-*+'#1*&@#&)1#1*-30#&)1#2'"#(+#&'#&#$-.3-)")+#()#+!"#T*-?"$+#W!--'"*
MainWindow::MainWindow()
{ &33%($&+(-)#'!-6)#() N(@2*"#X/H/
textEdit = new QTextEdit;
setCentralWidget(textEdit); !"#$%&'()(&*+%&,$-.%/0&1+--2%$&3445!/30!-6
textEdit->setAcceptDrops(false);
setAcceptDrops(true);
setWindowTitle(tr("Text Editor"));
}

5)#+!"#$-)'+*2$+-*0#6"#$*"&+"#& QTextEdit#&)1#'"+#(+#&'#+!"#$")+*&%#6(1@"+/#D7#1",&2%+0 QTextEdit


4&*(&>%"/#F"#$&%% QListWidget='#(.3%".")+&+(-)#-, mousePressEvent()#+-#")'2*"#+!&+#+!" QListWidget
!&'#+!"#-33-*+2)(+7#+-#3*-$"''#.-2'"#3*"''#"4")+'#&'#2'2&%/

void ProjectListWidget::mouseMoveEvent(QMouseEvent *event)


{
if (event->buttons() & Qt::LeftButton) {
int distance = (event->pos() - startPos).manhattanLength();
if (distance >= QApplication::startDragDistance())
startDrag();
}
QListWidget::mouseMoveEvent(event);
}

F!")#+!"#2'"*#.-4"'#+!"#.-2'"#$2*'-*#6!(%"#!-%1()@#+!"#%",+#.-2'"#>2++-)0#6"#$-)'(1"*#'+&*+()@#&
!"#T*-?"$+#W!--'"*#&33%($&+(-)#3*"'")+'#+!"#2'"*#6(+!#+6-#%('+#6(1@"+'0#3-32%&+"1#6(+!#)&."'/#E&$! 1*&@/#F"#$-.32+"#+!"#1('+&)$"#>"+6"")#+!"#$2**")+#.-2'"#3-'(+(-)#&)1#+!"#3-'(+(-)#6!"*"#+!"#%",+
%('+#6(1@"+#*"3*"'")+'#&#3*-?"$+/# !"#2'"*#$&)#1*&@#&)1#1*-3#+!"#)&."'#()#+!"#%('+#6(1@"+'#+-#.-4"#& .-2'"#>2++-)#6&'#3*"''"1/#5, +!"#1('+&)$"#('#%&*@"*#+!&) QApplication='#*"$-..")1"1#1*&@#'+&*+
3"*'-)#,*-.#-)"#3*-?"$+#+-#&)-+!"*/ 1('+&)$"#I)-*.&%%7#Y#3(;"%'K0#6"#$&%%#+!"#3*(4&+"#,2)$+(-) startDrag()#+-#'+&*+#1*&@@()@/# !('#&4-(1'
()(+(&+()@#&#1*&@#?2'+#>"$&2'"#+!"#2'"*='#!&)1#'!&B"'/
!"#1*&@#&)1#1*-3#$-1"#('#&%%#%-$&+"1#()#+!" QListWidget#'2>$%&''/#L"*"='#+!"#$%&''#1",()(+(-)M
void ProjectListWidget::startDrag()
{
class ProjectListWidget : public QListWidget QListWidgetItem *item = currentItem();
{ if (item) {
Q_OBJECT QMimeData *mimeData = new QMimeData;
public: mimeData->setText(item->text());
ProjectListWidget(QWidget *parent = 0); QDrag *drag = new QDrag(this);
protected: drag->setMimeData(mimeData);
void mousePressEvent(QMouseEvent *event); drag->setPixmap(QPixmap(":/images/person.png"));
void mouseMoveEvent(QMouseEvent *event); if (drag->start(Qt::MoveAction) == Qt::MoveAction)
void dragEnterEvent(QDragEnterEvent *event); delete item;
void dragMoveEvent(QDragMoveEvent *event); }
void dropEvent(QDropEvent *event); }
private:
void startDrag();
QPoint startPos;
}; 5) startDrag()0#6"#$*"&+"#&)#->?"$+#-,#+73" QDrag#6(+! this#&'#(+'#3&*")+/# !" QDrag#->?"$+#'+-*"'#+!"
1&+&#()#& QMimeData#->?"$+/#N-* +!('#";&.3%"0#6"#3*-4(1"#+!"#1&+&#&'#& text/plain#'+*()@#2'()@
QMimeData::setText()/ QMimeData#3*-4(1"'#'"4"*&%#,2)$+(-)'#,-*#!&)1%()@#+!"#.-'+#$-..-)#+73"'#-,
!" ProjectListWidget#$%&''#*"(.3%".")+'#,(4"#"4")+#!&)1%"*'#1"$%&*"1#() QWidget/ 1*&@'#I(.&@"'0#SC:'0#$-%-*'0#"+$/K#&)1#$&)#!&)1%"#&*>(+*&*7#R5RE#+73"'#*"3*"'")+"1#&' QByteArray'/
!"#$&%%#+- QDrag::setPixmap()#'"+'#+!"#($-)#+!&+#,-%%-6'#+!"#$2*'-*#6!(%"#+!"#1*&@#('#+&B()@#3%&$"/

ProjectListWidget::ProjectListWidget(QWidget *parent) !" QDrag::start()#$&%%#'+&*+'#+!"#1*&@@()@#-3"*&+(-)#&)1#>%-$B'#2)+(%#+!"#2'"*#1*-3'#-*#$&)$"%'#+!"


: QListWidget(parent) 1*&@/#5+#+&B"'#&#$-.>()&+(-)#-,#'233-*+"1#J1*&@#&$+(-)'J#&'#&*@2.")+#IQt::CopyAction0
{ Qt::MoveAction0#&)1 Qt::LinkActionK#&)1#*"+2*)'#+!"#1*&@#&$+(-)#+!&+#6&'#";"$2+"1#I-*
setAcceptDrops(true); Qt::IgnoreAction#(,#)-)"#6&'#";"$2+"1K/#F!($!#&$+(-)#('#";"$2+"1#1"3")1'#-)#6!&+#+!"#'-2*$"
}
6(1@"+#&%%-6'0#6!&+#+!"#+&*@"+#'233-*+'0#&)1#6!($!#.-1(,("*#B"7'#&*"#3*"''"1#6!")#+!"#1*-3#-$$2*'/
A,+"*#+!" start()#$&%%0#P+#+&B"'#-6)"*'!(3#-,#+!"#1*&@#->?"$+#&)1#6(%%#1"%"+"#(+#6!")#(+#('#)-#%-)@"*
*"Z2(*"1/
5)#+!"#$-)'+*2$+-*0#6"#")&>%"#1*-3'#-)#+!"#%('+#6(1@"+/

void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event)


void ProjectListWidget::mousePressEvent(QMouseEvent *event) {
{ ProjectListWidget *source =
if (event->button() == Qt::LeftButton) qobject_cast<ProjectListWidget *>(event->source());
startPos = event->pos(); if (source && source != this) {
QListWidget::mousePressEvent(event); event->setDropAction(Qt::MoveAction);
} event->accept();
}
}
F!")#+!"#2'"*#3*"''"'#+!"#%",+#.-2'"#>2++-)0#6"#'+-*"#+!"#.-2'"#3-'(+(-)#()#+!" startPos#3*(4&+"
$-)4"*+#-2*#1&+&#'+*2$+2*"#+-#& QByteArray#"4")#(,#+!"#1*&@#('#)-+#2%+(.&+"%7#&$$"3+"10#&)1#(,#6"
!" ProjectListWidget#6(1@"+#)-+#-)%7#-*(@()&+"'#1*&@'0#(+#&%'-#&$$"3+'#'2$!#1*&@'#(,#+!"7#$-."#,*-. 6&)+#+-#3*-4(1"#'"4"*&%#R5RE#+73"'#+-#()+"*&$+#)($"%7#6(+!#&#6(1"#*&)@"#-,#&33%($&+(-)'0#6"#)""1#+-
&)-+!"* ProjectListWidget#()#+!"#'&."#&33%($&+(-)/ QDragEnterEvent::source()#*"+2*)'#&#3-()+"*#+- '+-*"#+!"#1&+&#'"4"*&%#+(."'#I-)$"#3"*#R5RE#+73"K/#5,#+!"#1&+&#('#%&*@"0#+!('#$&)#'%-6#1-6)#+!"
+!"#6(1@"+#+!&+#()(+(&+"1#+!"#1*&@#(,#+!&+#6(1@"+#('#3&*+#-,#+!"#'&."#&33%($&+(-)[#-+!"*6('"0#(+#*"+2*)' &33%($&+(-)#)""1%"''%7/# !"#'"$-)1#&)1#+!(*1#&33*-&$!"'#$&)#&4-(1#-*#.()(.(<"#+!"'"#3*->%".'/
&#)2%%#3-()+"*/#F"#2'" qobject_cast<T>()#+-#")'2*"#+!&+#+!"#1*&@#$-."'#,*-.#& ProjectListWidget/#5, !"7#@(4"#2'#$-.3%"+"#$-)+*-%#&)1#$&)#>"#2'"1#+-@"+!"*/
&%%#('#$-**"$+0#6"#+"%%#P+#+!&+#6"#&*"#*"&17#+-#&$$"3+#+!"#&$+(-)#&'#&#.-4"#&$+(-)/
-#'!-6#!-6#+!"'"#&33*-&$!"'#6-*B0#6"#6(%%#'!-6#!-6#+-#&11#1*&@#&)1#1*-3#$&3&>(%(+("'#+-#&
QTableWidget/# !"#1*&@#6(%%#'233-*+#+!"#,-%%-6()@#R5RE#+73"'M text/plain0 text/html0#&)1 text/csv/
void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event) S'()@#+!"#,(*'+#&33*-&$!0#'+&*+()@#&#1*&@#%--B'#%(B"#+!('M
{
ProjectListWidget *source =
qobject_cast<ProjectListWidget *>(event->source()); void MyTableWidget::mouseMoveEvent(QMouseEvent *event)
if (source && source != this) { {
event->setDropAction(Qt::MoveAction); if (event->buttons() & Qt::LeftButton) {
event->accept(); int distance = (event->pos() - startPos).manhattanLength();
} if (distance >= QApplication::startDragDistance())
} startDrag();
}
QTableWidget::mouseMoveEvent(event);
!"#$-1"#() dragMoveEvent()#('#(1")+($&%#+-#6!&+#6"#1(1#() dragEnterEvent()/#5+#('#)"$"''&*7#>"$&2'" }
void MyTableWidget::startDrag()
6"#)""1#+-#-4"**(1" QListWidget='#I&$+2&%%70 QAbstractItem-View='K#(.3%".")+&+(-)#-,#+!"#,2)$+(-)/
{
QString plainText = selectionAsPlainText();
if (plainText.isEmpty())
void ProjectListWidget::dropEvent(QDropEvent *event) return;
{ QMimeData *mimeData = new QMimeData;
ProjectListWidget *source = mimeData->setText(plainText);
qobject_cast<ProjectListWidget *>(event->source()); mimeData->setHtml(toHtml(plainText));
if (source && source != this) { mimeData->setData("text/csv", toCsv(plainText).toUtf8());
addItem(event->mimeData()->text()); QDrag *drag = new QDrag(this);
event->setDropAction(Qt::MoveAction); drag->setMimeData(mimeData);
event->accept(); if (drag->start(Qt::CopyAction | Qt::MoveAction) == Qt::MoveAction)
} deleteSelection();
} }

5) dropEvent()0#6"#*"+*("4"#+!"#1*&@@"1#+";+#2'()@ QMimeData::text()#&)1#$*"&+"#&)#(+".#6(+!#+!&+ !" startDrag()#3*(4&+"#,2)$+(-)#('#$&%%"1#,*-. mouseMoveEvent()#+-#'+&*+#1*&@@()@#&#*"$+&)@2%&*


+";+/#F"#&%'-#)""1#+-#&$$"3+#+!"#"4")+#&'#&#J.-4"#&$+(-)J#+-#+"%%#+!"#'-2*$"#6(1@"+#+!&+#(+#$&)#)-6 '"%"$+(-)/#F"#'"+#+!" text/plain#&)1 text/html#R5RE#+73"'#2'()@ setText()#&)1 setHtml()0#&)1#6"
*".-4"#+!"#-*(@()&%#4"*'(-)#-,#+!"#1*&@@"1#(+"./ '"+#+!" text/csv#+73"#2'()@ set-Data()0#6!($!#+&B"'#&)#&*>(+*&*7#R5RE#+73"#&)1#& QByteArray/# !"
$-1"#,-*#+!" selectionAsString()#('#.-*"#-*#%"''#+!"#'&."#&'#+!" Spreadsheet::copy()#,2)$+(-)#,*-.
O*&@#&)1#1*-3#('#&#3-6"*,2%#."$!&)('.#,-*#+*&)',"**()@#1&+&#>"+6"")#&33%($&+(-)'/#D2+#()#'-." W!&3+"*#Y#I3/ ^]K/
$&'"'0(+='#3-''(>%"#+-#(.3%".")+#1*&@#&)1#1*-3#6(+!-2+#2'()@#P+='#1*&@#&)1#1*-3#,&$(%(+("'/#5,#&%%#6"
6&)+#+-#1-#('#+-#.-4"#1&+&#6(+!()#-)"#6(1@"+#()#-)"#&33%($&+(-)0#6"#$&)#-,+")#'(.3%7#*"(.3%".")+
mousePressEvent()#&)1 mouseReleaseEvent()/ QString MyTableWidget::toCsv(const QString &plainText)
{
QString result = plainText;
Supporting Custom Drag Types result.replace("\\", "\\\\");
result.replace("\"", "\\\"");
5)#+!"#";&.3%"'#'-#,&*0#6"#!&4"#*"%("1#-) QMimeData='#'233-*+#,-*#$-..-)#R5RE#+73"'/# !2'0#6" result.replace("\t", "\", \"");
$&%%"1 QMimeData::setText()#+-#$*"&+"#&#+";+#1*&@0#&)1#6"#2'"1 QMimeData:urls()#+-#*"+*("4"#+!" result.replace("\n", "\"\n\"");
result.prepend("\"");
$-)+")+'#-,#& text/uri-list#1*&@/ 5,#6"#6&)+#+-#1*&@#3%&()#+";+0#L R:#+";+0#(.&@"'0#SC:'0#-*#$-%-*'0
result.append("\"");
6"#$&)#2'" QMimeData#6(+!-2+#,-*.&%(+7/#D2+#(,#6"#6&)+#+-#1*&@#$2'+-.#1&+&0#6"#.2'+#$!--'" return result;
>"+6"")#+!"#,-%%-6()@#&%+"*)&+(4"'M }
QString MyTableWidget::toHtml(const QString &plainText)
H/ F"#$&)#3*-4(1"#&*>(+*&*7#1&+&#&'#& QByteArray#2'()@ QMimeData::setData()#&)1#";+*&$+#(+#%&+"* {
2'()@ QMimeData::data()/ QString result = Qt::escape(plainText);
\/ F"#$&)#'2>$%&'' QMimeData#&)1#*"(.3%".")+ formats()#&)1 retrieveData()#+-#!&)1%"#-2* result.replace("\t", "<td>");
$2'+-.#1&+&#+73"'/
result.replace("\n", "\n<tr><td>");
]/ N-*#1*&@#&)1#1*-3#-3"*&+(-)'#6(+!()#&#'()@%"#&33%($&+(-)0#6"#$&)#'2>$%&'' QMimeData#&)1#'+-*"
result.prepend("<table>\n<tr><td>");
+!"#1&+&#2'()@#&)7#1&+&#'+*2$+2*"#6"#6&)+/ result.append("\n</table>");
return result;
!"#,(*'+#&33*-&$!#1-"'#)-+#()4-%4"#&)7#'2>$%&''()@0#>2+#1-"'#!&4"#'-."#1*&6>&$B'M#F"#)""1#+- }
TableMimeData(const QTableWidget *tableWidget,
const QTableWidgetSelectionRange &range);
const QTableWidget *tableWidget() const { return myTableWidget; }
!" toCsv()#&)1 toHtml()#,2)$+(-)'#$-)4"*+#&#J+&>'#&)1#)"6%()"'J#'+*()@#()+-#&#WQ_#I$-..&G QTableWidgetSelectionRange range() const { return myRange; }
'"3&*&+"1#4&%2"'K#-*#&)#L R:#'+*()@/#N-*#";&.3%"0#+!"#1&+& QStringList formats() const;
protected:
QVariant retrieveData(const QString &format,
Red Green Blue QVariant::Type preferredType) const;
Cyan Yellow Magenta private:
static QString toHtml(const QString &plainText);
static QString toCsv(const QString &plainText);
QString text(int row, int column) const;
('#$-)4"*+"1#+-
QString rangeAsPlainText() const;
const QTableWidget *myTableWidget;
QTableWidgetSelectionRange myRange;
"Red", "Green", "Blue" QStringList myFormats;
"Cyan", "Yellow", "Magenta" };

-*#+- 5)'+"&1#-,#'+-*()@#&$+2&%#1&+&0#6"#'+-*"#& QTableWidgetSelectionRange#+!&+#'3"$G(,("'#6!($!#$"%%'#&*"


>"()@#1*&@@"1#&)1#B""3#&#3-()+"*#+-#+!" QTableWidget/# !" formats()#&)1 retrieveData()#,2)$+(-)'
&*"#*"(.3%".")+"1#,*-. QMimeData/
<table>
<tr><td>Red<td>Green<td>Blue
<tr><td>Cyan<td>Yellow<td>Magenta
</table> TableMimeData::TableMimeData(const QTableWidget *tableWidget,
const QTableWidgetSelectionRange &range)
{
myTableWidget = tableWidget;
!"#$-)4"*'(-)#('#3"*,-*."1#()#+!"#'(.3%"'+#6&7#3-''(>%"0#2'()@ QString::replace()/# -#"'$&3" myRange = range;
L R:#'3"$(&%#$!&*&$+"*'0#6"#2'" Qt::escape()/ myFormats << "text/csv" << "text/html" << "text/plain";
}

void MyTableWidget::dropEvent(QDropEvent *event)


{ 5)#+!"#$-)'+*2$+-*0#6"#()(+(&%(<"#+!"#3*(4&+"#4&*(&>%"'/
if (event->mimeData()->hasFormat("text/csv")) {
QByteArray csvData = event->mimeData()->data("text/csv");
QString csvText = QString::fromUtf8(csvData);
QStringList TableMimeData::formats() const
...
{
event->acceptProposedAction();
return myFormats;
} else if (event->mimeData()->hasFormat("text/plain")) {
}
QString plainText = event->mimeData()->text();
...
event->acceptProposedAction();
} !" formats()#,2)$+(-)#*"+2*)'#&#%('+#-,#R5RE#+73"'#3*-4(1"1#>7#+!"#R5RE#1&+&#->?"$+/# !"#3*"$('"
} -*1"*#-,#+!"#,-*.&+'#('#2'2&%%7#(**"%"4&)+0#>2+#(+='#@--1#3*&$+($"#+-#32+#+!"#J>"'+J#,-*.&+'#,(*'+/
A33%($&+(-)'#+!&+#'233-*+#.&)7#,-*.&+'#6(%%#'-."+(."'#2'"#+!"#,(*'+#-)"#+!&+#.&+$!"'/

A%+!-2@!#6"#3*-4(1"#+!"#1&+&#()#+!*""#1(,,"*")+#,-*.&+'0#6"#-)%7#&$$"3+#+6-#-,#+!".#() dropEvent()/
5,#+!"#2'"*#1*&@'#$"%%'#,*-.#& QTableWidget#+-#&)#L R:#"1(+-*0#6"#6&)+#+!"#$"%%'#+-#>"#$-)4"*+"1#()+- QVariant TableMimeData::retrieveData(const QString &format,
&)#L R:#+&>%"/#D2+#(,#+!"#2'"*#1*&@'#&*>(+*&*7#L R:#()+-#& QTableWidget0#6"#1-)=+#6&)+#+-#&$$"3+#(+/ QVariant::Type preferredType) const
{
if (format == "text/plain") {
-#.&B"#+!('#";&.3%"#6-*B0#6"#&%'-#)""1#+-#$&%% setAcceptDrops(true)#&)1 return rangeAsPlainText();
setSelectionMode(ContiguousSelection)#()#+!" MyTableWidget#$-)'+*2$+-*/ } else if (format == "text/csv") {
return toCsv(rangeAsPlainText());
F"#6(%%#)-6#*"1-#+!"#";&.3%"0#>2+#+!('#+(."#6"#6(%%#'2>$%&'' QMimeData#+-#3-'+3-)"#-*#&4-(1#+!" } else if (format == "text/html") {
I3-+")+(&%%7#";3")'(4"K#$-)4"*'(-)'#>"+6"") QTableWidget-Item'#&)1 QByteArray/#L"*"='#+!" return toHtml(rangeAsPlainText());
} else {
1",()(+(-)#-,#-2*#'2>$%&''M
return QMimeData::retrieveData(format, preferredType);
}
}
class TableMimeData : public QMimeData
{
Q_OBJECT
public: !" retrieveData()#,2)$+(-)#*"+2*)'#+!"#1&+&#,-*#&#@(4")#R5RE#+73"#&'#& QVariant/# !"#4&%2"#-,#+!"
format#3&*&."+"*#('#)-*.&%%7#-)"#-,#+!"#'+*()@'#*"+2*)"1#>7 formats()0#>2+#6"#$&))-+#&''2."#+!&+0 $%(3>-&*1#2'"#()#+!"#Q3*"&1'!""+#&33%($&+(-)#,*-. W!&3+"*#Y/
'()$"#)-+#&%%#&33%($&+(-)'#$!"$B#+!"#R5RE#+73"#&@&()'+ formats()/# !"#@"++"*#,2)$+(-)' text()0
html()0 urls()0 image-Data()0 colorData()0#&)1 data()#3*-4(1"1#>7 QMimeData#&*"#(.3%".")+"1#() N-*#'-."#&33%($&+(-)'0#+!"#>2(%+G()#,2)$+(-)&%(+7#.(@!+ )-+#>"#'2,,($(")+/#N-*#";&.3%"0#6"#.(@!+#6&)+
+"*.'#-, retrieveData()/ +-#3*-4(1"#1&+&#+!&+#(')=+#?2'+#+";+#-*#&)#(.&@"0#-*#6"#.(@!+#6&)+#+-#3*-4(1"#1&+&#()#.&)7#1(,,"*")+
,-*.&+'#,-*#.&;(.2.#()+"*-3"*&>(%(+7#6(+!#-+!"*#&33%($&+(-)'/# !"#(''2"#('#4"*7#'(.(%&*#+-#6!&+#6"
!" preferredType#3&*&."+"*#@(4"'#2'#&#!()+#&>-2+#6!($!#+73"#6"#'!-2%1#32+#()#+!" QVariant/#L"*"0 ")$-2)+"*"1#"&*%("*#6(+!#1*&@#&)1#1*-30#&)1#+!"#&)'6"*#('#&%'-#'(.(%&*M#F"#$&)#'2>$%&'' QMimeData
6"#(@)-*"#(+#&)1#+*2'+ QMimeData#+-#$-)4"*+#+!"#*"+2*)#4&%2"#()+-#+!"#1"'(*"1#+73"0#(,#)"$"''&*7/ &)1#*"(.3%".")+#&#,"6#4(*+2&%#,2)$+(-)'/

5,#-2*#&33%($&+(-)#'233-*+'#1*&@#&)1#1*-3#+!*-2@!#&#$2'+-. QMimeData#'2>$%&''0#6"#$&)#'(.3%7#*"2'"
void MyTableWidget::dropEvent(QDropEvent *event) +!" QMimeData#'2>$%&''#&)1#32+#(+#-)#+!"#$%(3>-&*1#2'()@#+!" setMimeData()#,2)$+(-)/# -#*"+*("4"#+!"
{ 1&+&0#6"#$&)#$&%% mimeData()#-)#+!"#$%(3>-&*1/
const TableMimeData *tableData =
qobject_cast<const TableMimeData *>(event->mimeData());
8)#`HH0#(+#('#2'2&%%7#3-''(>%"#+-#3&'+"#&#'"%"$+(-)#>7#$%($B()@#+!"#.(11%"#>2++-)#-,#&#+!*""G>2++-)
if (tableData) {
.-2'"/# !('#('#1-)"#2'()@#&#'"3&*&+"#J'"%"$+(-)J#$%(3>-&*1/#5,#7-2#6&)+#7-2*#6(1@"+'#+-#'233-*+#+!('
const QTableWidget *otherTable = tableData->tableWidget();
QTableWidgetSelectionRange otherRange = tableData->range(); B()1#-,#$%(3>-&*1#&'#6"%%#&'#+!"#'+&)1&*1#-)"0#7-2#.2'+#3&'' QClipboard::Selection#&'#&)#&11(+(-)&%
... &*@2.")+#+-#+!"#4&*(-2'#$%(3>-&*1#$&%%'/#N-*#";&.3%"0#!"*"='#!-6#6"#6-2%1#*"(.3%".")+
event->acceptProposedAction(); mouseReleaseEvent()#()#&#+";+#"1(+-*#+-#'233-*+#3&'+()@#2'()@#+!"#.(11%"#.-2'"#>2++-)M
} else if (event->mimeData()->hasFormat("text/csv")) {
QByteArray csvData = event->mimeData()->data("text/csv");
QString csvText = QString::fromUtf8(csvData); void MyTextEditor::mouseReleaseEvent(QMouseEvent *event)
... {
event->acceptProposedAction(); QClipboard *clipboard = QApplication::clipboard();
} else if (event->mimeData()->hasFormat("text/plain")) { if (event->button() == Qt::MidButton
QString plainText = event->mimeData()->text(); && clipboard->supportsSelection()) {
... QString text = clipboard->text(QClipboard::Selection);
event->acceptProposedAction(); pasteText(text);
} }
QTableWidget::mouseMoveEvent(event); }
}

8)#`HH0#+!" supportsSelection()#,2)$+(-)#*"+2*)' true/#8)#-+!"*#3%&+,-*.'0#(+#*"+2*)' false/


!" dropEvent()#,2)$+(-)#('#'(.(%&*#+-#+!"#-)"#6"#!&1#"&*%("*#()#+!('#'"$+(-)0#>2+#+!('#+(."#6"
-3+(.(<"#(+#>7#$!"$B()@#,(*'+#(,#6"#$&)#'&,"%7#$&'+#+!" QMimeData#->?"$+#+-#& TableMimeData/#5,#+!" 5,#6"#6&)+#+-#>"#)-+(,("1#6!")"4"* +!"#$%(3>-&*1='#$-)+")+'#$!&)@"0#6"#$&)#$-))"$+#+!"
qobject_cast<T>()#6-*B'0#+!('#."&)'#+!"#1*&@#6&'#-*(@()&+"1#>7#& MyTableWidget#()#+!"#'&." QClipboard::dataChanged()#'(@)&%#+-#&#$2'+-.#'%-+/
&33%($&+(-)0#&)1#6"#$&)#1(*"$+%7#&$$"''#+!"#+&>%"#1&+&#()'+"&1#-,#@-()@#+!*-2@! QMimeData='#AT5/#5,
+!"#$&'+#,&(%'0#6"#";+*&$+#+!"#1&+&#+!"#'+&)1&*1#6&7/

5)#+!('#";&.3%"0#6"#")$-1"1#+!"#WQ_#+";+#2'()@#+!"#S NG^#")$-1()@/#5,#6"#6&)+#+-#>"#$"*+&()#-,
2'()@#+!"#*(@!+#")$-1()@0#6"#$-2%1#2'"#+!" charset#3&*&."+"*#-,#+!" text/plain#R5RE#+73"#+-
'3"$(,7#&)#";3%($(+#")$-1()@/#L"*"#&*"#&#,"6#";&.3%"'M

text/plain;charset=US-ASCII
text/plain;charset=ISO-8859-1
text/plain;charset=Shift_JIS
text/plain;charset=UTF-8

Clipboard Handling
R-'+#&33%($&+(-)'#.&B"#2'"#-,#P+='#>2(%+G()#$%(3>-&*1#!&)1%()@#()#-)"#6&7#-*#&)-+!"*/#N-*#";&.3%"0
+!" QTextEdit#$%&''#3*-4(1"' cut()0 copy()0#&)1 paste()#'%-+'#&'#6"%%#&'#B"7>-&*1#'!-*+$2+'0#'-#%(++%"
-*#)-#&11(+(-)&%#$-1"#('#*"Z2(*"1/

F!")#6*(+()@#-2*#-6)#$%&''"'0#6"#$&)#&$$"''#+!"#$%(3>-&*1#+!*-2@! QApplication::clipboard()0
6!($!#*"+2*)'#&#3-()+"*#+-#+!"#&33%($&+(-)=' QClipboard#->?"$+/#L&)1%()@#+!"#'7'+".#$%(3>-&*1#('
"&'7M#W&%% setText()0 setImage()0#-* setPixmap()#+-#32+#1&+&#-)+-#+!"#$%(3>-&*10#&)1#$&%% text()0
image()0#-* pixmap()#+-#*"+*("4"#1&+&#,*-.#+!"#$%(3>-&*1/#F"#!&4"#&%*"&17#'"")#";&.3%"'#-,
Chapter 10. Item View Classes
• 71%!&'/85'9/52':%5;'0+!<5!%5!=5'0$"1151
• 71%!&'>)5*5?%!5*'@+*5$1
• 92,$525!/%!&'0.1/+2'@+*5$1
• 92,$525!/%!&'0.1/+2'(5$5&"/51

R&)7#&33%($&+(-)'#%"+#+!"#2'"*#'"&*$!0#4("60#&)1#"1(+#()1(4(12&%#(+".'#+!&+#>"%-)@#+-#&#1&+&#'"+/# !"
1&+&#.(@!+#>"#!"%1#()#,(%"'#-*#&$$"''"1#,*-.#&#1&+&>&'"#-*#&#)"+6-*B#'"*4"*/# !"#'+&)1&*1#&33*-&$!
+-#1"&%()@#6(+!#1&+&#'"+'#%(B"#+!('#('#+-#2'"#P+='#(+".#4("6#$%&''"'/ 5)#.&)7#'(+2&+(-)'0#6"#-)%7#)""1#+-#3*"'")+#*"%&+(4"%7#'.&%%#)2.>"*'#-,#(+".'#+-#+!"#2'"*/#5)#+!"'"
$-..-)#$&'"'0#6"#$&)#2'"#P+='#$-)4")(")$"#(+".#4("6#$%&''"'#I QListWidget0 QTableWidget0#&)1
5)#"&*%("*#4"*'(-)'#-,#P+0#+!" (+".#4("6#6(1@"+'#6"*"#3-32%&+"1#6(+!#+!"#")+(*"#$-)+")+'#-,#&#1&+& QTReeWidgetK#&)1#3-32%&+"#+!".#6(+!#(+".'#1(*"$+%7/# !"'"#$%&''"'#>"!&4"#()#&#'(.(%&*#6&7#+-#+!"
'"+[#+!"#2'"*'#6-2%1#3"*,-*.#&%%#+!"(*#'"&*$!"'#&)1#"1(+'#-)#+!"#1&+&#!"%1#()#+!"#6(1@"+0#&)1#&+ (+".#4("6#$%&''"'#3*-4(1"1#>7#"&*%("*#4"*'(-)'#-,#P+/# !"7#'+-*"#+!"(*#1&+&#()#J(+".'J#I,-*#";&.3%"0#&
'-."#3-()+#+!"#$!&)@"'#6-2%1#>"#6*(++")#>&$B#+-#+!"#1&+&#'-2*$"/#A%+!-2@!#'(.3%"#+-#2)1"*'+&)1 QTableWidget#$-)+&()' QTableWidgetItem'K/#5)+"*)&%%70#+!"#$-)4")(")$"#$%&''"'#2'"#$2'+-.#.-1"%'
&)1#2'"0#+!('#&33*-&$!#1-"')=+#'$&%"#6"%%#+-#4"*7#%&*@"#1&+&#'"+'#&)1#1-"')=+#%")1#(+'"%,#+-#'(+2&+(-)' +!&+#.&B"#+!"#(+".'#4('(>%"#+-#+!"#4("6'/
6!"*"#6"#6&)+#+-#1('3%&7#+!"#'&."#1&+&#'"+#()#+6-#-*#.-*"#1(,,"*")+#6(1@"+'/
N-*#%&*@"#1&+&#'"+'0#123%($&+()@#+!"#1&+&#('#-,+")#)-+#&)#-3+(-)/#5)#+!"'"#$&'"'0#6"#$&)#2'"#P+='
!"#Q.&%%+&%B#%&)@2&@"#3-32%&*(<"1#&#,%";(>%"#&33*-&$!#+-#4('2&%(<()@#%&*@"#1&+&#'"+'M 4("6'#IQListView0 QTableView0#&)1 QtreeViewK0#()#$-)?2)$+(-)#6(+!#&#1&+&#.-1"%0#6!($!#$&)#>"#&
.-1"%4("6$-)+*-%%"*#IR_WK/#5)#+!"#R_W#&33*-&$!0#+!" -./)0#*"3*"'")+'#+!"#1&+&#'"+#&)1#(' $2'+-.#.-1"%#-*#-)"#-,#P+='#3*"1",()"1#.-1"%'/#N-*#";&.3%"0#(,#+!"#1&+&#'"+#('#!"%1#()#&#1&+&>&'"0
*"'3-)'(>%"#,-*#,"+$!()@#+!"#1&+&#+!&+#('#)""1"1#,-*#4("6()@#&)1#,-*#6*(+()@#>&$B#&)7#$!&)@"'/#E&$! 6"#$&)#$-.>()"#& QTableView#6(+!#& QSqlTableModel/
+73"#-,#1&+&#'"+#!&'#(+'#-6)#.-1"%0#>2+#+!"#AT5#+!&+#+!"#.-1"%'#3*-4(1"#+-#+!"#4("6'#('#2)(,-*.#)-
.&++"*#6!&+#+!"#2)1"*%7()@#1&+&#'"+/# !" 12)3#3*"'")+'#+!"#1&+&#+-#+!"#2'"*/#F(+!#&)7#%&*@"#1&+&
'"+#-)%7#&#%(.(+"1#&.-2)+#-,#1&+&#6(%%#>"#4('(>%"#&+#&)7#-)"#+(."0#'-#+!&+#('#+!"#-)%7#1&+&#+!&+#+!"
4("6#&'B' ,-*/# !" 4.*&5.00)5#."1(&+"'#>"+6"")#+!"#2'"*#&)1#+!"#4("60#$-)4"*+()@#2'"*#&$+(-)'#()+- Using the Item View Convenience Classes
*"Z2"'+'#+-#)&4(@&+"#-*#"1(+#1&+&0#6!($!#+!"#4("6#+!")#+*&)'.(+'#+-#+!"#.-1"%#&'#)"$"''&*7/
S'()@#P+='#(+".#4("6#$-)4")(")$"#'2>$%&''"'#('#2'2&%%7#'(.3%"*#+!&)#1",()()@#&#$2'+-.#.-1"%#&)1#('
!"#$%&)7()(&8092&:-;%5<=!%>&3$/+!0%/0#$% &33*-3*(&+"#6!")#6"#1-)=+#)""1#+!"#>")",(+'#-,#'"3&*&+()@#+!"#.-1"%#&)1#+!"#4("6/#F"#2'"1#+!('
+"$!)(Z2"#() W!&3+"*#Y#6!")#6"#'2>$%&''"1 QTableWidget#&)1 QTableWidgetItem#+-#(.3%".")+
'3*"&1'!""+#,2)$+(-)&%(+7/

5)#+!('#'"$+(-)0#6"#6(%%#'!-6#!-6#+-#2'"#+!"#$-)4")(")$"#(+".#4("6#'2>$%&''"'#+-#1('3%&7#(+".'/# !"
,(*'+#";&.3%"#'!-6'#&#*"&1G-)%7 QListWidget0#+!"#'"$-)1#";&.3%"#'!-6'#&)#"1(+&>%" QTableWidget0
&)1#+!"#+!(*1#";&.3%"#'!-6'#&#*"&1G-)%7 QtreeWidget/

F"#>"@()#6(+!#&#'(.3%"#1(&%-@#+!&+#%"+'#+!"#2'"*#3($B#&#,%-6$!&*+#'7.>-%#,*-.#&#%('+/#E&$!#(+".
$-)'('+'#-,#&)#($-)0#&#+";+0#&)1#&#2)(Z2"#5O/

P+#3*-4(1"'#&#.-1"%V4("6#&*$!(+"$+2*"#()'3(*"1#>7#+!"#R_W#&33*-&$!/#5)#P+0#+!"#.-1"%#>"!&4"'#+!" !"#$%&)7(A(&*+%& 5->/+3$0&BC:D-5&,!/E%$&3445!/30!-6


'&."#&'#(+#1-"'#,-*#$%&''($#R_W/#D2+#()'+"&1#-,#&#$-)+*-%%"*0#P+#2'"'#&#'%(@!+%7#1(,,"*")+#&>'+*&$+(-)M
+!" /)0)67&)/# !"#1"%"@&+"#('#2'"1#+-#3*-4(1"#,()"#$-)+*-%#-4"*#!-6#(+".'#&*"#*")1"*"1#&)1#"1(+"1/
P+#3*-4(1"'#&#1",&2%+#1"%"@&+"#,-*#"4"*7#+73"#-,#4("6/# !('#('#'2,,($(")+#,-*#.-'+#&33%($&+(-)'0#'-#6"
2'2&%%7#1-)=+#)""1#+-#$&*"#&>-2+#(+/

S'()@#P+='#.-1"%V4("6#&*$!(+"$+2*"0#6"#$&)#2'"#.-1"%'#+!&+#-)%7#,"+$!#+!"#1&+&#+!&+#('#&$+2&%%7
)""1"1#,-*#1('3%&7#()#+!"#4("6/# !('#.&B"'#!&)1%()@#4"*7#%&*@"#1&+&#'"+'#.2$!#,&'+"*#&)1#%"''
.".-*7#!2)@*7#+!&)#*"&1()@#&%%#+!"#1&+&/#A)1#>7#*"@('+"*()@#&#.-1"%#6(+!#+6-#-*#.-*"#4("6'0#6"
$&)#@(4"#+!"#2'"*#+!"#-33-*+2)(+7#-,#4("6()@#&)1#()+"*&$+()@#6(+!#+!"#1&+&#()#1(,,"*")+#6&7'0#6(+!
%(++%"#-4"*!"&1/#P+#&2+-.&+($&%%7#B""3'#.2%+(3%"#4("6'#()#'7)$0#*",%"$+()@#$!&)@"'#+-#-)"#()#&%%#+!"
-+!"*'/#A)#&11(+(-)&%#>")",(+#-,#+!"#.-1"%V4("6#&*$!(+"$+2*"#('#+!&+#(,#6"#1"$(1"#+-#$!&)@"#!-6#+!"
2)1"*%7()@#1&+&#'"+#('#'+-*"10#6"#?2'+#)""1#+-#$!&)@"#+!"#.-1"%[#+!"#4("6'#6(%%#$-)+()2"#+-#>"!&4"
$-**"$+%7/

!"#$%&)7(?(&@6%&:-;%5&/36&2%$=%&:#50!45%&=!%>2
if (item)
:"+='#'+&*+#6(+!#&)#";+*&$+#,*-.#+!"#1(&%-@='#!"&1"*#,(%"M id = item->data(Qt::UserRole).toInt();
}
QDialog::done(result);
}
class FlowChartSymbolPicker : public QDialog
{
Q_OBJECT
public: !" done()#,2)$+(-)#('#*"(.3%".")+"1#,*-. QDialog/#5+#('#$&%%"1#6!")#+!"#2'"*#3*"''"'#8a#-*#W&)$"%/
FlowChartSymbolPicker(const QMap<int, QString> &symbolMap, 5,#+!"#2'"*#$%($B"1#8a0#6"#*"+*("4"#+!"#*"%"4&)+#(+".#&)1#";+*&$+#+!"#5O#2'()@#+!" data()#,2)$+(-)/#5,
QWidget *parent = 0); 6"#6"*"#()+"*"'+"1#()#+!"#(+".='#+";+0#6"#$-2%1#*"+*("4"#(+#>7#$&%%()@ item-
int selectedId() const { return id; } >data(Qt::DisplayRole).toString()#-*#.-*"#$-)4")(")+%70 item->text()/
void done(int result);
...
}; D7#1",&2%+0 QListWidget#('#*"&1G-)%7/#5,#6"#6&)+"1#+!"#2'"*#+-#"1(+#+!"#(+".'0#6"#$-2%1#'"+#+!"#4("6='
"1(+#+*(@@"*'#2'()@ QAbstractItemView::setEditTriggers()[#,-*#";&.3%"0#&#'"++()@#-,
QAbstractItemView::AnyKeyPressed#."&)'#+!&+#+!"#2'"*#$&)#>"@()#"1(+()@#&)#(+".#?2'+#>7#'+&*+()@#+-
+73"/#A%+"*)&+(4"%70#6"#$-2%1#3*-4(1"#&)#E1(+#>2++-)#I&)1#3"*!&3'#A11#&)1#O"%"+"#>2++-)'K#&)1
F!")#6"#$-)'+*2$+#+!"#1(&%-@0#6"#.2'+#3&''#(+#& QMap<int, QString>0 &)1#&,+"*#(+#!&'#";"$2+"1#6"
$-))"$+#+!".#+-#'%-+'#'-#+!&+#6"#$-2%1#!&)1%"#+!"#"1(+()@#-3"*&+(-)'#3*-@*&..&+($&%%7/
$&)#*"+*("4"#+!"#$!-'")#5O#I-* GH#(,#+!"#2'"*#1(1)=+#'"%"$+#&)7#(+".K#>7#$&%%()@ selectedId()/

U-6#+!&+#6"#!&4"#'"")#!-6#+-#2'"#&#$-)4")(")$"#(+".#4("6#$%&''#,-*#4("6()@#&)1#'"%"$+()@#1&+&0#6"
FlowChartSymbolPicker::FlowChartSymbolPicker( 6(%%#%--B#&+#&)#";&.3%"#6!"*"#6"#$&)#"1(+#1&+&/#A@&()#6"#&*"#2'()@#&#1(&%-@0#+!('#+(."#-)"#+!&+
const QMap<int, QString> &symbolMap, QWidget *parent) 3*"'")+'#&#'"+#-,#I !"#K#$--*1()&+"'#+!&+#+!"#2'"*#$&)#"1(+/
: QDialog(parent)
{ !"#$%&)7(F(&*+%&1--$;!630%&B%00%$&3445!/30!-6
id = -1;
listWidget = new QListWidget;
listWidget->setIconSize(QSize(60, 60));
QMapIterator<int, QString> i(symbolMap);
while (i.hasNext()) {
i.next();
QListWidgetItem *item = new QListWidgetItem(i.value(),
listWidget);
item->setIcon(iconForSymbol(i.value()));
item->setData(Qt::UserRole, i.key());
}
...
}

F"#()(+(&%(<" id#I+!"#%&'+#'"%"$+"1#5OK#+- GH/#U";+#6"#$-)'+*2$+#& QListWidget0#&#$-)4")(")$"#(+".


4("6#6(1@"+/#F"#(+"*&+"#-4"*#"&$!#(+".#()#+!"#,%-6$!&*+#'7.>-%#.&3#&)1#$*"&+"#& QListWidgetItem#+-
*"3*"'")+#"&$!#-)"/# !" QListWidget-Item#$-)'+*2$+-*#+&B"'#& QString#+!&+#*"3*"'")+'#+!"#+";+#+-
1('3%&70#,-%%-6"1#>7#+!"#3&*")+ QListWidget/

!")#6"#'"+#+!"#(+".='#($-)#&)1#6"#$&%% setData()#+-#'+-*"#-2*#&*>(+*&*7#5O#()#+!" QListWidgetItem/


!" iconForSymbol()#3*(4&+"#,2)$+(-)#*"+2*)'#& QIcon#,-*#&#@(4")#'7.>-%#)&."/

QListWidgetItem='#!&4"#'"4"*&%#*-%"'0#"&$!#-,#6!($!#!&'#&)#&''-$(&+"1 QVariant/# !"#.-'+#$-..-) A'#6(+!#+!"#3*"4(-2'#";&.3%"0#6"#6(%%#,-$2'#-)#+!"#(+".#4("6#*"%"4&)+#$-1"0#'+&*+()@#6(+!#+!"


*-%"'#&*" Qt::DisplayRole0 Qt::EditRole0#&)1 Qt::IconRole0#&)1#,-*#+!"'"#+!"*"#&*"#$-)4")(")$" $-)'+*2$+-*/
'"++"*#&)1#@"++"*#,2)$+(-)'#IsetText()0 setIcon()K0#>2+#+!"*"#&*"#'"4"*&%#-+!"*#*-%"'/#F"#$&)#&%'-
1",()"#$2'+-.#*-%"'#>7#'3"$(,7()@#&#)2."*($#4&%2"#-, Qt::UserRole#-*#!(@!"*/#5)#-2*#";&.3%"0#6"#2'"
CoordinateSetter::CoordinateSetter(QList<QPointF> *coords,
Qt::UserRole#+-#'+-*"#"&$!#(+".='#5O/
QWidget *parent)
: QDialog(parent)
!"#-.(++"1#3&*+#-,#+!"#$-)'+*2$+-*#('#$-)$"*)"1#6(+!#$*"&+()@#+!"#>2++-)'0#%&7()@#-2+#+!"#6(1@"+'0 {
&)1#'"++()@#+!"#6()1-6='#+(+%"/ coordinates = coords;
tableWidget = new QTableWidget(0, 2);
tableWidget->setHorizontalHeaderLabels(
void FlowChartSymbolPicker::done(int result) QStringList() << tr("X") << tr("Y"));
{ for (int row = 0; row < coordinates->count(); ++row) {
id = -1; QPointF point = coordinates->at(row);
if (result == QDialog::Accepted) { addRow();
QListWidgetItem *item = listWidget->currentItem(); tableWidget->item(row, 0)->setText(QString::number(point.x()));
tableWidget->item(row, 1)->setText(QString::number(point.y())); ,*-.#&)#&33%($&+(-)#+!&+#'!-6'#P+#&33%($&+(-)#'"++()@'#2'()@#& QTReeWidget/#C"&1G-)%7#('#+!"#1",&2%+
} ,-* QtreeWidget/
...
}
!"#$%&)7(G(&*+%&B%00!6"2&H!%>%$&3445!/30!-6

!" QTableWidget#$-)'+*2$+-*#+&B"'#+!"#()(+(&%#)2.>"*#-,#+&>%"#*-6'#&)1#$-%2.)'#+-#1('3%&7/#E4"*7
(+".#()#& QTableWidget#('#*"3*"'")+"1#>7#& QTableWidgetItem0#()$%21()@#!-*(<-)+&%#&)1#4"*+($&%#!"&1"*
(+".'/# !" setHorizontalHeaderLabels()#,2)$+(-)#'"+'#+!"#+";+#,-*#"&$!#!-*(<-)+&%#+&>%"#6(1@"+#(+".
+-#+!"#$-**"'3-)1()@#+";+#()#+!"#'+*()@#%('+#(+#('#3&''"1/#D7#1",&2%+0 QTableWidget#3*-4(1"'#&#4"*+($&%
!"&1"*#6(+!#*-6'#%&>"%"1#,*-.#H0#6!($!#('#";&$+%7#6!&+#6"#6&)+0#'-#6"#1-)=+#)""1#+-#'"+#+!"#4"*+($&%
!"&1"*#%&>"%'#.&)2&%%7/

8)$"#6"#!&4"#$*"&+"1#&)1#$")+"*"1#+!"#$-%2.)#%&>"%'0#6"#(+"*&+"#+!*-2@!#+!"#$--*1()&+"#1&+&#+!&+
6&'#3&''"1#()/#N-*#"4"*7#I !"#K#3&(*0#6"#$*"&+"#+6- QTableWidgetItem'#$-**"'3-)1()@#+-#+!" #&)1 #
$--*1()&+"'/# !"#(+".'#&*"#&11"1#+-#+!"#+&>%"#2'()@ QTableWidget::setItem()0#6!($!#+&B"'#&#*-6#&)1
&#$-%2.)#()#&11(+(-)#+-#+!"#(+"./

D7#1",&2%+0 QTableWidget#&%%-6'#"1(+()@/# !"#2'"*#$&)#"1(+#&)7#$"%%#()#+!"#+&>%"#>7#)&4(@&+()@#+-#(+#&)1


+!")#"(+!"*#3*"''()@#N\#-*#'(.3%7#>7#+73()@/#A%%#$!&)@"'#.&1"#>7#+!"#2'"*#()#+!"#4("6#6(%%#>"
&2+-.&+($&%%7#*",%"$+"1#()+-#+!" QTableWidgetItem'/# -#3*"4")+#"1(+()@0#6"#$&)#$&%%
setEditTriggers(QAbstractItemView:: NoEditTriggers)/

void CoordinateSetter::addRow()
{ L"*"='#&)#";+*&$+#,*-.#+!"#$-)'+*2$+-*M
int row = tableWidget->rowCount();
tableWidget->insertRow(row);
QTableWidgetItem *item0 = new QTableWidgetItem; SettingsViewer::SettingsViewer(QWidget *parent)
item0->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); : QDialog(parent)
tableWidget->setItem(row, 0, item0); {
QTableWidgetItem *item1 = new QTableWidgetItem; organization = "Trolltech";
item1->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); application = "Designer";
tableWidget->setItem(row, 1, item1); treeWidget = new QTreeWidget;
tableWidget->setCurrentItem(item0); treeWidget->setColumnCount(2);
} treeWidget->setHeaderLabels(
QStringList() << tr("Key") << tr("Value"));
treeWidget->header()->setResizeMode(0, QHeaderView::Stretch);
treeWidget->header()->setResizeMode(1, QHeaderView::Stretch);
!" addRow()#'%-+#('#()4-B"1#6!")#+!"#2'"*#$%($B'#+!"#A11#C-6#>2++-)/#F"#&33")1#&#)"6#*-6#2'()@ ...
insertRow()/#5,#+!"#2'"*#&++".3+'#+-#"1(+#&#$"%%#()#+!"#)"6#*-60#+!" QTableWidget#6(%%#&2+-.&+($&%%7 setWindowTitle(tr("Settings Viewer"));
$*"&+"#&#)"6 QTableWidgetItem/ readSettings();
}

void CoordinateSetter::done(int result)


{
-#&$$"''#&)#&33%($&+(-)='#'"++()@'0#& QSettings#->?"$+#.2'+#>"#$*"&+"1#6(+!#+!"#-*@&)(<&+(-)='#)&."
if (result == QDialog::Accepted) {
coordinates->clear(); &)1#+!"#&33%($&+(-)='#)&."#&'#3&*&."+"*'/#F"#'"+#1",&2%+#)&."' IJO"'(@)"*J#>7#J *-%%+"$!JK#&)1
for (int row = 0; row < tableWidget->rowCount(); ++row) { +!")#$-)'+*2$+#&#)"6 QtreeWidget/#A+#+!"#")10#6"#$&%%#+!" readSettings()#,2)$+(-)/
double x = tableWidget->item(row, 0)->text().toDouble();
double y = tableWidget->item(row, 1)->text().toDouble();
coordinates->append(QPointF(x, y)); void SettingsViewer::readSettings()
} {
} QSettings settings(organization, application);
QDialog::done(result); treeWidget->clear();
} addChildSettings(settings, 0, "");
treeWidget->sortByColumn(0);
treeWidget->setFocus();
setWindowTitle(tr("Settings Viewer - %1 by %2")
N()&%%70#6!")#+!"#2'"*#$%($B'#8a0#6"#$%"&*#+!"#$--*1()&+"'#+!&+#6"*"#3&''"1#()#+-#+!"#1(&%-@0#&)1 .arg(application).arg(organization));
$*"&+"#&#)"6#'"+#>&'"1#-)#+!"#$--*1()&+"'#()#+!" QTableWidget='#(+".'/ }

N-*#-2*#+!(*1#&)1#,()&%#";&.3%"#-,#P+='#$-)4")(")$"#(+".#4("6#6(1@"+'0#6"#6(%%#%--B#&+#'-."#')(33"+'
QDirModel E)$&3'2%&+"'#+!"#%-$&%#,(%"#'7'+".
A33%($&+(-)#'"++()@'#&*"#'+-*"1#()#&#!("*&*$!7#-,#B"7'#&)1#4&%2"'/# !" addChildSettings()#3*(4&+"
,2)$+(-)#+&B"'#&#'"++()@'#->?"$+0#&#3&*")+ QtreeWidgetItem0#&)1#+!"#$2**")+#J@*-23J/#A#@*-23#('#+!" QSqlQueryModel E)$&3'2%&+"'#&)#QP:#*"'2%+#'"+
QSettings#"Z2(4&%")+#-,#&#,(%"#'7'+".#1(*"$+-*7/# !" addChildSettings()#,2)$+(-)#$&)#$&%%#(+'"%,
*"$2*'(4"%7#+-#+*&4"*'"#&)#&*>(+*&*7#+*""#'+*2$+2*"/# !"#()(+(&%#$&%%#,*-.#+!" readSettings()#,2)$+(-) QSqlTableModel E)$&3'2%&+"'#&)#QP:#+&>%"
3&''"'#b#&'#+!"#3&*")+#(+".#+-#*"3*"'")+#+!"#*--+/
QSqlRelationalTableModel E)$&3'2%&+"'#&)#QP:#+&>%"#6(+!#,-*"(@)#B"7'
QSortFilterProxyModel Q-*+'#&)1V-*#,(%+"*'#&)-+!"*#.-1"%
void SettingsViewer::addChildSettings(QSettings &settings,
QTreeWidgetItem *parent, const QString &group)
{
QTreeWidgetItem *item; 5)#+!('#'"$+(-)0#6"#6(%%#%--B#&+#!-6#+-#2'"#+!" QStringListModel0#+!" QDirModel0#&)1#+!"
settings.beginGroup(group);
QSortFilterProxyModel/# !"#QP:#.-1"%'#&*"#$-4"*"1#() W!&3+"*#H]/
foreach (QString key, settings.childKeys()) {
if (parent) {
item = new QTreeWidgetItem(parent); :"+='#>"@()#6(+!#&#'(.3%"#1(&%-@#+!&+#2'"*'#$&)#2'"#+-#&110#1"%"+"0#&)1#"1(+#& QStringList0#6!"*"
} else { "&$!#'+*()@#*"3*"'")+'#&#+"&.#%"&1"*/
item = new QTreeWidgetItem(treeWidget);
}
item->setText(0, key);
!"#$%&)7(I(&*+%&*%3:&J%3;%$2&3445!/30!-6
item->setText(1, settings.value(key).toString());
}
foreach (QString group, settings.childGroups()) {
if (parent) {
item = new QTreeWidgetItem(parent);
} else {
item = new QTreeWidgetItem(treeWidget);
}
item->setText(0, group);
addChildSettings(settings, item, group);
}
settings.endGroup();
}

!" addChildSettings()#,2)$+(-)#('#2'"1#+-#$*"&+"#&%%#+!" QtreeWidgetItem'/#5+#(+"*&+"'#-4"*#&%%#+!"


B"7'#&+#+!"#$2**")+#%"4"%#()#+!"#'"++()@'#!("*&*$!7#&)1#$*"&+"'#-)" QTableWidgetItem#3"*#B"7/#5,#b
6&'#3&''"1#&'#+!" parent#(+".0#6"#$*"&+"#+!"#(+".#&'#&#$!(%1#-,#+!" QtreeWidget#(+'"%,#I.&B()@#(+#&
+-3G%"4"%#(+".K[#-+!"*6('"0#6"#$*"&+"#+!"#(+".#&'#&#$!(%1#-, parent/# !"#,(*'+#$-%2.)#('#'"+#+-#+!"
)&."#-,#+!"#B"7#&)1#+!"#'"$-)1#$-%2.)#+-#+!"#$-**"'3-)1()@#4&%2"/

U";+0#+!"#,2)$+(-)#(+"*&+"'#-4"*#"4"*7#@*-23#&+#+!"#$2**")+#%"4"%/#N-*#"&$!#@*-230#&#)"6 L"*"='#+!"#*"%"4&)+#";+*&$+#,*-.#+!"#$-)'+*2$+-*M
QtreeWidgetItem#('#$*"&+"1#6(+!#(+'#,(*'+#$-%2.)#'"+#+-#+!"#@*-23='#)&."/# !"#,2)$+(-)#+!")#$&%%'#(+'"%,
*"$2*'(4"%7#6(+!#+!"#@*-23#(+".#&'#+!"#3&*")+#+-#3-32%&+"#+!" QTReeWidget#6(+!#+!"#@*-23='#$!(%1
(+".'/ TeamLeadersDialog::TeamLeadersDialog(const QStringList &leaders,
QWidget *parent)
!"#(+".#4("6#6(1@"+'#'!-6)#()#+!('#'"$+(-)#&%%-6#2'#+-#2'"#&#'+7%"#-,#3*-@*&..()@#+!&+#('#4"*7 : QDialog(parent)
'(.(%&*#+-#+!&+#2'"1#()#"&*%("*#4"*'(-)'#-,#P+M#*"&1()@#&)#")+(*"#1&+&#'"+#()+-#&)#(+".#4("6#6(1@"+0 {
model = new QStringListModel(this);
2'()@#(+".#->?"$+'#+-#*"3*"'")+#1&+&#"%".")+'0#&)1#I(,#+!"#(+".'#&*"#"1(+&>%"K#6*(+()@#>&$B#+-#+!"
model->setStringList(leaders);
1&+&#'-2*$"/#5)#+!"#,-%%-6()@#'"$+(-)'0#6"#6(%%#@-#>"7-)1#+!('#'(.3%"#&33*-&$!#&)1#+&B"#,2%%
listView = new QListView;
&14&)+&@"#-,#P+='#.-1"%V4("6#&*$!(+"$+2*"/ listView->setModel(model);
listView->setEditTriggers(QAbstractItemView::AnyKeyPressed
| QAbstractItemView::DoubleClicked);
...
Using Predefined Models }

P+#3*-4(1"'#'"4"*&%#3*"1",()"1#.-1"%'#,-*#2'"#6(+!#+!"#4("6#$%&''"'M
F"#>"@()#>7#$*"&+()@#&)1#3-32%&+()@#& QStringListModel/#U";+#6"#$*"&+"#& QListView#&)1#'"+#(+'
QStringListModel Q+-*"'#&#%('+#-,#'+*()@' .-1"%#+-#+!"#-)"#6"#!&4"#?2'+#$*"&+"1/#F"#&%'-#'"+#'-."#"1(+()@#+*(@@"*'#+-#&%%-6#+!"#2'"*#+-#"1(+#&
'+*()@#'(.3%7#>7#'+&*+()@#+-#+73"#-)#(+#-*#>7#1-2>%"G$%($B()@#(+/#D7#1",&2%+0#)-#"1(+()@#+*(@@"*'#&*"#'"+
QStandardItemModel Q+-*"'#&*>(+*&*7#!("*&*$!($&%#1&+& -)#& QListView0#.&B()@#+!"#4("6#",,"$+(4"%7#*"&1G-)%7/
void TeamLeadersDialog::insert()
{
int row = listView->currentIndex().row();
model->insertRows(row, 1);
QModelIndex index = model->index(row);
listView->setCurrentIndex(index);
listView->edit(index);
}

F!")#+!"#2'"*#$%($B'#+!"#5)'"*+#>2++-)0#+!" insert()#'%-+#('#()4-B"1/# !"#'%-+#>"@()'#>7#*"+*("4()@#+!"


*-6#)2.>"*#,-*#+!"#%('+#4("6='#$2**")+#(+"./#E4"*7#1&+&#(+".#()#&#.-1"%#!&'#&#$-**"'3-)1()@#J.-1"%
()1";J0#6!($!#('#*"3*"'")+"1#>7#& QModelIndex#->?"$+/#F"#6(%%#%--B#&+#.-1"%#()1";"'#()#1"+&(%#()#+!"
)";+#'"$+(-)0#>2+#,-*#)-6#(+#('#'2,,($(")+#+-#B)-6#+!&+#&)#()1";#!&'#+!*""#.&()#$-.3-)")+'M#&#*-60#&
$-%2.)0#&)1#&#3-()+"*#+-#+!"#.-1"%#+- 6!($!#(+#>"%-)@'/#N-*#&#-)"G1(.")'(-)&%#%('+#.-1"%0#+!"
$-%2.)#('#&%6&7'#b/

8)$"#6"#!&4"#+!"#*-6#)2.>"*0#6"#()'"*+#-)"#)"6#*-6#&+#+!&+#3-'(+(-)/# !"#()'"*+(-)#('#3"*,-*."1
-)#+!"#.-1"%0#&)1#+!"#.-1"%#&2+-.&+($&%%7#231&+"'#+!"#%('+#4("6/#F"#+!")#'"+#+!"#%('+#4("6='#$2**")+ F"#6(%%#>"@()#>7#%--B()@#&+#+!"#$*"&+(-)#&)1#'"++()@#23#-,#+!"#.-1"%#&)1#+!"#4("6#()#+!"#O(*"$+-*7
()1";#+-#+!"#>%&)B#*-6#6"#?2'+#()'"*+"1/#N()&%%70#6"#'"+#+!"#%('+#4("6#+-#"1(+()@#.-1"#-)#+!"#)"6#*-60 _("6"*#1(&%-@='#$-)'+*2$+-*/
?2'+#&'#(,#+!"#2'"*#!&1#3*"''"1#&#B"7#-*#1-2>%"G$%($B"1#+-#()(+(&+"#"1(+()@/

DirectoryViewer::DirectoryViewer(QWidget *parent)
void TeamLeadersDialog::del() : QDialog(parent)
{ {
model->removeRows(listView->currentIndex().row(), 1); model = new QDirModel;
} model->setReadOnly(false);
model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name);
treeView = new QTreeView;
treeView->setModel(model);
5)#+!"#$-)'+*2$+-*0#+!"#O"%"+"#>2++-)=' clicked()#'(@)&%#('#$-))"$+"1#+-#+!" del()#'%-+/#Q()$"#6"#&*" treeView->header()->setStretchLastSection(true);
?2'+#1"%"+()@#+!"#$2**")+#*-60#6"#$&)#$&%% removeRows()#6(+!#+!"#$2**")+#()1";#3-'(+(-)#&)1#&#*-6 treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
$-2)+#-,#H/#c2'+#%(B"#6(+!#()'"*+(-)0#6"#*"%7#-)#+!"#.-1"%#+-#231&+"#+!"#4("6#&$$-*1()@%7/ treeView->header()->setSortIndicatorShown(true);
treeView->header()->setClickable(true);
QModelIndex index = model->index(QDir::currentPath());
QStringList TeamLeadersDialog::leaders() const treeView->expand(index);
{ treeView->scrollTo(index);
return model->stringList(); treeView->resizeColumnToContents(0);
} ...
}

N()&%%70#+!" leaders()#,2)$+(-)#3*-4(1"'#&#."&)'#-,#*"&1()@#>&$B#+!"#"1(+"1#'+*()@'#6!")#+!"#1(&%-@
('#$%-'"1/ 8)$"#+!"#.-1"%#!&'#>"")#$-)'+*2$+"10#6"#.&B"#(+#"1(+&>%"#&)1#'"+#4&*(-2'#()(+(&%#'-*+#-*1"*()@
&++*(>2+"'/#F"#+!")#$*"&+"#+!" QtreeView#+!&+#6(%%#1('3%&7#+!"#.-1"%='#1&+&/# !" QtreeView='#!"&1"*
TeamLeadersDialog#$-2%1#>"#.&1"#()+-#&#@")"*($#'+*()@#%('+#"1(+()@#1(&%-@#'(.3%7#>7#3&*&."+"*(<()@#(+' $&)#>"#2'"1#+-#3*-4(1"#2'"*G$-)+*-%%"1#'-*+()@/#D7#.&B()@#+!"#!"&1"*#$%($B&>%"0#+!"#2'"*#$&)#'-*+#>7
6()1-6#+(+%"/#A)-+!"*#@")"*($#1(&%-@#+!&+#('#-,+")#*"Z2(*"1#('#-)"#+!&+#3*"'")+'#&#%('+#-,#,(%"'#-* 6!($!"4"*#$-%2.)#!"&1"*#+!"7#$%($B0#6(+!#*"3"&+"1#$%($B'#&%+"*)&+()@#>"+6"")#&'$")1()@#&)1
1(*"$+-*("'#+-#+!"#2'"*/# !"#)";+#";&.3%"#2'"'#+!" QDirModel#$%&''0#6!($!#")$&3'2%&+"'#+!" 1"'$")1()@#-*1"*'/#8)$"#+!"#+*""#4("6='#!"&1"*#!&'#>"")#'"+#230#6"#@"+#+!"#.-1"%#()1";#-,#+!"
$-.32+"*='#,(%"#'7'+".#&)1#('#$&3&>%"#-,#'!-6()@#I&)1#!(1()@K#4&*(-2'#,(%"#&++*(>2+"'/# !('#.-1"%#$&) $2**")+#1(*"$+-*7#&)1#.&B"#'2*"#+!&+#+!('#1(*"$+-*7#('#4('(>%"#>7#";3&)1()@#(+'#3&*")+'#(,#)"$"''&*7
&33%7#&#,(%+"*#+-#*"'+*($+#+!"#B()1'#-,#,(%"#'7'+".#")+*("'#+!&+#&*"#'!-6)#&)1#$&)#-*1"*#+!"#")+*("'#() 2'()@ expand()0#&)1#'$*-%%()@#+-#(+#2'()@ scrollTo()/# !")#6"#.&B"#'2*"#+!&+#+!"#,(*'+#$-%2.)#('#6(1"
4&*(-2'#6&7'/ ")-2@!#+-#'!-6#&%%#(+'#")+*("'#6(+!-2+#2'()@#"%%(3'"'#IdK/

5)#+!"#3&*+#-,#+!"#$-)'+*2$+-*#$-1"#+!&+#(')=+ '!-6)#!"*"0#6"#$-))"$+"1#+!"#W*"&+"#O(*"$+-*7#&)1
!"#$%&)7(K(&*+%&L!$%/0-$C&H!%>%$&3445!/30!-6
C".-4"#>2++-)'#+-#'%-+'#+-#3"*,-*.#+!"'"#&$+(-)'/#F"#1-#)-+#)""1#&#C")&."#>2++-)#'()$"#2'"*'#$&)
[View full size image] *")&."#()G3%&$"#>7#3*"''()@#N\#&)1#+73()@/

void DirectoryViewer::createDirectory()
{
QModelIndex index = treeView->currentIndex();
if (!index.isValid())
return;
QString dirName = QInputDialog::getText(this,
tr("Create Directory"),
tr("Directory name"));
if (!dirName.isEmpty()) {
if (!model->mkdir(index, dirName).isValid())
QMessageBox::information(this, tr("Create Directory"),
tr("Failed to create the directory"));
}
}

5,#+!"#2'"*#")+"*'#&#1(*"$+-*7#)&."#()#+!"#()32+#1(&%-@0#6"#&++".3+ +-#$*"&+"#&#1(*"$+-*7#6(+!#+!('
)&."#&'#&#$!(%1#-,#+!"#$2**")+#1(*"$+-*7/# !" QDirModel::mkdir()#,2)$+(-)#+&B"'#+!"#3&*")+
1(*"$+-*7='#()1";#&)1#+!"#)&."#-,#+!"#)"6#1(*"$+-*70#&)1#*"+2*)'#+!"#.-1"%#()1";#-,#+!"#1(*"$+-*7#(+
$*"&+"1/#5,#+!"#-3"*&+(-)#,&(%'0#(+#*"+2*)'#&)#()4&%(1#.-1"%#()1";/

void DirectoryViewer::remove()
{
QModelIndex index = treeView->currentIndex();
if (!index.isValid())
return; L"*"='#&)#";+*&$+#,*-.#+!" ColorNamesDialog#$-)'+*2$+-*M
bool ok;
if (model->fileInfo(index).isDir()) {
ok = model->rmdir(index);
} else { ColorNamesDialog::ColorNamesDialog(QWidget *parent)
ok = model->remove(index); : QDialog(parent)
} {
if (!ok) sourceModel = new QStringListModel(this);
QMessageBox::information(this, tr("Remove"), sourceModel->setStringList(QColor::colorNames());
tr("Failed to remove %1").arg(model->fileName(index))); proxyModel = new QSortFilterProxyModel(this);
} proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterKeyColumn(0);
listView = new QListView;
listView->setModel(proxyModel);
5,#+!"#2'"*#$%($B'#C".-4"0#6"#&++".3+#+-#*".-4"#+!"#,(%"#-*#1(*"$+-*7#&''-$(&+"1#6(+!#+!"#$2**")+ ...
(+"./#F"#$-2%1#2'" QDir#+-#&$$-.3%('!#+!&+0#>2+ QDirModel#-,,"*'#$-)4")(")$"#,2)$+(-)'#+!&+#6-*B#-) syntaxComboBox = new QComboBox;
QModelIndex"'/ syntaxComboBox->addItem(tr("Regular expression"), QRegExp::RegExp);
syntaxComboBox->addItem(tr("Wildcard"), QRegExp::Wildcard);
syntaxComboBox->addItem(tr("Fixed string"), QRegExp::FixedString);
!"#%&'+#";&.3%"#()#+!('#'"$+(-)#'!-6'#!-6#+-#2'" QSortFilterProxyModel/#S)%(B"#+!"#-+!"*
...
3*"1",()"1#.-1"%'0 +!('#.-1"%#")$&3'2%&+"'#&)#";('+()@#.-1"%#&)1#.&)(32%&+"'#+!"#1&+&#+!&+#3&''"' }
>"+6"")#+!"#2)1"*%7()@#.-1"%#&)1#+!"#4("6/#5)#-2*#";&.3%"0#+!"#2)1"*%7()@#.-1"%#('#&
QStringListModel#()(+(&%(<"1#6(+!#+!"#%('+#-,#$-%-*#)&."'#*"$-@)(<"1#>7#P+#I->+&()"1#+!*-2@!
QColor::colorNames()K/# !"#2'"*#$&)#+73"#&#,(%+"*#'+*()@#()#& QLineEdit#&)1#'3"$(,7#!-6#+!('#'+*()@#('
+-#>"#()+"*3*"+"1#I&'#&#*"@2%&*#";3*"''(-)0#&#6(%1$&*1#3&++"*)0#-*#&#,(;"1#'+*()@K#2'()@#&#$-.>->-;/ !" QStringListModel#('#$*"&+"1#&)1#3-32%&+"1#()#+!"#2'2&%#6&7/# !('#('#,-%%-6"1#>7#+!"#$-)'+*2$+(-)
-,#+!" QSortFilterProxyModel/#F"#3&''#+!"#2)1"*%7()@#.-1"%#2'()@ setSourceModel()#&)1#+"%%#+!"
3*-;7#+-#,(%+"*#>&'"1#-)#$-%2.)#b#-,#+!"#-*(@()&%#.-1"%/# !" QComboBox::addItem()#,2)$+(-)#&$$"3+'
!"#$%&)7(M(&*+%&1-5-$&N3:%2&3445!/30!-6 &)#-3+(-)&%#J1&+&J#&*@2.")+#-,#+73" QVariant[#6"#2'"#+!('#+-#'+-*"#+!" QRegExp::PatternSyntax#4&%2"
+!&+#$-**"'3-)1'#+-#"&$!#(+".='#+";+/

void ColorNamesDialog::reapplyFilter()
{
QRegExp::PatternSyntax syntax =
QRegExp::PatternSyntax(syntaxComboBox->itemData(
syntaxComboBox->currentIndex()).toInt());
QRegExp regExp(filterLineEdit->text(), Qt::CaseInsensitive, syntax);
proxyModel->setFilterRegExp(regExp);
}

!" reapplyFilter()#'%-+#('#()4-B"1#6!")"4"*#+!"#2'"*#$!&)@"'#+!"#,(%+"*#'+*()@#-*#+!"#3&++"*)#'7)+&;
$-.>->-;/#F"#$*"&+"#& QRegExp#2'()@#+!"#+";+#()#+!"#%()"#"1(+/# !")#6"#'"+#(+'#3&++"*)#'7)+&;#+-#+!"
-)"#'+-*"1#()#+!"#'7)+&;#$-.>->-;='#$2**")+#(+".='#1&+&/#F!")#6"#$&%% setFilterRegExp()0#+!"#)"6
,(%+"*#>"$-."'#&$+(4"#&)1#+!"#4("6#('#&2+-.&+($&%%7#231&+"1/ !"#$%&)7()7(&*+%&1#$$%6/!%2&3445!/30!-6
[View full size image]

Implementing Custom Models


P+='#3*"1",()"1#.-1"%'#-,,"*#&#$-)4")(")+#."&)'#-,#!&)1%()@#&)1#4("6()@#1&+&/#L-6"4"*0#'-."#1&+&
'-2*$"'#$&))-+#>"#2'"1#",,($(")+%7#2'()@#+!"#3*"1",()"1#.-1"%'0#&)1#,-*#+!"'"#'(+2&+(-)'#(+#('
)"$"''&*7#+-#$*"&+"#$2'+-.#.-1"%'#-3+(.(<"1#,-*#+!"#2)1"*%7()@#1&+&#'-2*$"/

D",-*"#6"#".>&*B#-)#$*"&+()@#$2'+-.#.-1"%'0#%"+='#,(*'+#*"4("6#+!"#B"7#$-)$"3+'#2'"1#()#P+='
.-1"%V4("6#&*$!(+"$+2*"/#E4"*7#1&+&#"%".")+#()#&#.-1"%#!&'#&#.-1"%#()1";#&)1#&#'"+#-,#&++*(>2+"'0 !"#&33%($&+(-)#$-2%1#>"#(.3%".")+"1#2'()@#&#'(.3%"#+&>%"0#>2+#6"#6&)+#+-#2'"#&#$2'+-.#.-1"%#+-
$&%%"1#*-%"'0#+!&+#$&)#+&B"#&*>(+*&*7#4&%2"'/#F"#'&6#"&*%("*#()#+!"#$!&3+"*#+!&+#+!"#.-'+#$-..-)%7 +&B"#&14&)+&@"#-,#$"*+&()#3*-3"*+("'#-,#+!"#1&+&#+-#.()(.(<"#'+-*&@"/#5,#6"#6"*"#+-#'+-*"#+!"#He\
2'"1#*-%"'#&*" Qt::DisplayRole#&)1 Qt::EditRole/#8+!"*#*-%"'#&*"#2'"1#,-*#'233%".")+&*7#1&+&#I,-* $2**")+%7#+*&1"1#$2**")$("'#()#&#+&>%"0#6"#6-2%1#)""1#+-#'+-*"#He\#;#He\#f#\e#\YY#4&%2"'[#6(+!#+!"
";&.3%"0 Qt::ToolTipRole0 Qt::StatusTipRole0#&)1 Qt::WhatsThisRoleK0#&)1#7"+#-+!"*'#,-*#$-)+*-%%()@ $2'+-.#.-1"%#3*"'")+"1#>"%-60 6"#-)%7#)""1#+-#'+-*"#He\#4&%2"'#I+!"#4&%2"#-,#"&$!#$2**")$7#()
>&'($#1('3%&7#&++*(>2+"'#I'2$!#&' Qt::FontRole0 Qt:: TextAlignmentRole0 Qt::TextColorRole0#&)1 *"%&+(-)#+-#+!"#S/Q/#1-%%&*K/
Qt::BackgroundColorRoleK/
!" CurrencyModel#$%&''#6(%%#>"#2'"1#6(+!#&#'+&)1&*1 QTableView/# !" Currency-Model#('#3-32%&+"1
!"#$%&)7('(&B/+%:30!/&=!%>&-O&8092&:-;%52 6(+!#& QMap<QString,double>[#"&$!#B"7#('#&#$2**")$7#$-1"#&)1#"&$!#4&%2"#('#+!"#4&%2"#-,#+!"
$2**")$7#()#S/Q/#1-%%&*'/#L"*"='#&#$-1"#')(33"+#+!&+#'!-6'#!-6#+!"#.&3#('#3-32%&+"1#&)1#!-6#+!"
[View full size image]
.-1"%#('#2'"1M

QMap<QString, double> currencyMap;


currencyMap.insert("AUD", 1.3259);
currencyMap.insert("CHF", 1.2970);
...
currencyMap.insert("SGD", 1.6901);
currencyMap.insert("USD", 1.0000);
CurrencyModel currencyModel;
currencyModel.setCurrencyMap(currencyMap);
QTableView tableView;
tableView.setModel(&currencyModel);
tableView.setAlternatingRowColors(true);

U-6#6"#$&)#%--B#&+#+!"#(.3%".")+&+(-)#-,#+!"#.-1"%0#'+&*+()@#6(+!#(+'#!"&1"*M
N-*#&#%('+#.-1"%0#+!"#-)%7#*"%"4&)+#()1";#$-.3-)")+#('#+!"#*-6#)2.>"*0 &$$"''(>%"#,*-.
QModelIndex::row()/#N-*#&#+&>%"#.-1"%0#+!"#*"%"4&)+#()1";#$-.3-)")+'#&*"#+!"#*-6#&)1#$-%2.)
)2.>"*'0#&$$"''(>%"#,*-. QModelIndex::row()#&)1 QModelIndex::column()/#N-*#>-+!#%('+#&)1#+&>%" class CurrencyModel : public QAbstractTableModel
{
.-1"%'0#"4"*7#(+".='#3&*")+#('#+!"#*--+0#6!($!#('#*"3*"'")+"1#>7#&)#()4&%(1 QModelIndex/# !"#,(*'+#+6-
public:
";&.3%"'#()#+!('#'"$+(-)#'!-6#!-6#+-#(.3%".")+#$2'+-.#+&>%"#.-1"%'/ CurrencyModel(QObject *parent = 0);
void setCurrencyMap(const QMap<QString, double> &map);
A#+*""#.-1"%#('#'(.(%&*#+-#&#+&>%"#.-1"%0#6(+!#+!"#,-%%-6()@#1(,,"*")$"'/#:(B"#&#+&>%"#.-1"%0#+!" int rowCount(const QModelIndex &parent) const;
3&*")+#-,#+-3G%"4"%#(+".'#('#+!"#*--+#I&)#()4&%(1 QModelIndexK0#>2+#"4"*7#-+!"*#(+".='#3&*")+#('#'-." int columnCount(const QModelIndex &parent) const;
-+!"*#(+".#()#+!"#!("*&*$!7/#T&*")+'#&*"#&$$"''(>%"#,*-. QModelIndex::parent()/#E4"*7#(+".#!&'#(+' QVariant data(const QModelIndex &index, int role) const;
*-%"#1&+&0#&)1#<"*-#-*#.-*"#$!(%1*")0#"&$!#&)#(+".#()#(+'#-6)#*(@!+/#Q()$"#(+".'#$&)#!&4"#-+!"*#(+".' QVariant headerData(int section, Qt::Orientation orientation,
&'#$!(%1*")0#(+#('#3-''(>%"#+-#*"3*"'")+#*"$2*'(4"#I+*""G%(B"K#1&+&#'+*2$+2*"'0#&'#+!"#,()&%#";&.3%"#() int role) const;
+!('#'"$+(-)#6(%%#'!-6/ private:
QString currencyAt(int offset) const;
QMap<QString, double> currencyMap;
!"#,(*'+#";&.3%"#()#+!('#'"$+(-)#('#&#*"&1G-)%7#+&>%"#.-1"%#+!&+#'!-6'#$2**")$7#4&%2"'#()#*"%&+(-)#+- };
"&$!#-+!"*/

F"#!&4"#$!-'")#+-#'2>$%&'' QAbstractTableModel#,-*#-2*#.-1"%#'()$"#+!&+#.-'+#$%-'"%7#.&+$!"'#-2*
1&+&#'-2*$"/#P+#3*-4(1"'#'"4"*&%#.-1"%#>&'"#$%&''"'0#()$%21()@ QAbstractListModel0 return QString("%1").arg(amount, 0, 'f', 4);
QAbstractTableModel0#&)1 QAbstractItemModel/# !" QAbstractItemModel#$%&''#('#2'"1#+-#'233-*+#& }
6(1"#4&*("+7#-,#.-1"%'0#()$%21()@#+!-'"#+!&+#&*"#>&'"1#-)#*"$2*'(4"#1&+&#'+*2$+2*"'0#6!(%"#+!" return QVariant();
}
QAbstractListModel#&)1 QAbstractTableModel#$%&''"'#&*"#3*-4(1"1#,-*#$-)4")(")$"#6!")#2'()@#-)"G
1(.")'(-)&%#-*#+6-G1(.")'(-)&%#1&+&#'"+'/

!" data()#$%&'()*&#+"(%+&,#(!"#-./%"#*$#.&0#*$#.&#)("12,#+*/",3# !"#)("1#),#,4"')$)"5#.,#.


!"#$%&)7())(&P6+%$!036/%&0$%%&O-$&0+%&3D20$3/0&:-;%5&/5322%2
QModelIndex3#6*+#.#(.7/"#1*5"/8#(!"#)&("+",()&9#'*14*&"&(,#*$#. QModelIndex#.+"#)(,#+*:#.&5#'*/%1&
&%17"+8#.-.)/.7/"#%,)&9 row()#.&5 column()3

;$#(!"#+*/"#), Qt::TextAlignmentRole8#:"#+"(%+&#.&#./)9&1"&(#,%)(.7/"#$*+#&%17"+,3#;$#(!"#5),4/.0#+*/"
), Qt::DisplayRole8#:"#/**<#%4#(!"#-./%"#$*+#".'!#'%++"&'0#.&5#'./'%/.("#(!"#"='!.&9"#+.("3

>"#'*%/5#+"(%+&#(!"#'./'%/.("5#-./%"#.,#. double8#7%(#(!"&#:"#:*%/5#!.-"#&*#'*&(+*/#*-"+#!*:#1.&0
5"')1./#4/.'",#:"+"#,!*:&#?%&/",,#:"#%,"#.#'%,(*1#5"/"9.("@3#;&,(".58#:"#+"(%+&#(!"#-./%"#.,#.
,(+)&98#$*+1.(("5#.,#:"#:.&(3

N-*#&#*"&1G-)%7#+&>%"#.-1"%0#6"#.2'+#*"(.3%".")+#+!*""#,2)$+(-)'M rowCount()0 columnCount()0#&)1 QVariant CurrencyModel::headerData(int section,


data()/#5)#+!('#$&'"0#6"#!&4"#&%'-#*"(.3%".")+"1 header-Data()0#&)1#6"#3*-4(1"#&#,2)$+(-)#+- Qt::Orientation /* orientation */,
()(+(&%(<"#+!"#1&+&#IsetCurrencyMap()K/ int role) const
{
if (role != Qt::DisplayRole)
CurrencyModel::CurrencyModel(QObject *parent) return QVariant();
: QAbstractTableModel(parent) return currencyAt(section);
{ }
}

!" headerData()#$%&'()*&#),#'.//"5#70#(!"#-)":#(*#4*4%/.("#)(,#!*+)A*&(./#.&5#-"+()'./#!".5"+,3 !"


F"#1-#)-+#)""1#+-#1-#&)7+!()@#()#+!"#$-)'+*2$+-*0#";$"3+#3&''#+!" parent#3&*&."+"*#+-#+!"#>&'" section#4.+.1"("+#),#(!"#+*:#*+#'*/%1&#&%17"+#?5"4"&5)&9#*&#(!"#*+)"&(.()*&@3#B)&'"#(!"#+*:,#.&5
$%&''/ '*/%1&,#!.-"#(!"#,.1"#'%++"&'0#'*5",8#:"#5*#&*(#'.+"#.7*%(#(!"#*+)"&(.()*&#.&5#,)14/0#+"(%+&#(!"
'*5"#*$#(!"#'%++"&'0#$*+#(!"#9)-"&#,"'()*&#&%17"+3

int CurrencyModel::rowCount(const QModelIndex & /* parent */) const


{ void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
return currencyMap.count(); {
} currencyMap = map;
int CurrencyModel::columnCount(const QModelIndex & /* parent */) const reset();
{ }
return currencyMap.count();
}
!"#'.//"+#'.&#'!.&9"#(!"#'%++"&'0#1.4#%,)&9 setCurrencyMap()3# !" QAbstractItemModel::reset()
'.//#("//,#.&0#-)":,#(!.(#.+"#%,)&9#(!"#1*5"/#(!.(#.//#(!")+#5.(.#),#)&-./)5C#(!),#$*+'",#(!"1#(*#+"D%",(
N-*#+!('#+&>%"#.-1"%0#+!"#*-6#&)1#$-%2.)#$-2)+'#&*"#+!"#)2.>"*#-,#$2**")$("'#()#+!"#$2**")$7#.&3/ $+",!#5.(.#$*+#(!"#)("1,#(!.(#.+"#-),)7/"3
!" parent#3&*&."+"*#!&'#)-#."&)()@#,-*#&#+&>%"#.-1"%[#(+#('#+!"*"#>"$&2'" rowCount()#&)1
columnCount()#&*"#()!"*(+"1#,*-.#+!"#.-*"#@")"*($ QAbstractItemModel#>&'"#$%&''0#6!($!#'233-*+'
!("*&*$!("'/ QString CurrencyModel::currencyAt(int offset) const
{
return (currencyMap.begin() + offset).key();
QVariant CurrencyModel::data(const QModelIndex &index, int role) const }
{
if (!index.isValid())
return QVariant();
!" currencyAt()#$%&'()*&#+"(%+&,#(!"#<"0#?(!"#'%++"&'0#'*5"@#.(#(!"#9)-"&#*$$,"(#)&#(!"#'%++"&'0
if (role == Qt::TextAlignmentRole) {
return int(Qt::AlignRight | Qt::AlignVCenter); 1.43#>"#%,"#.&#B EF,(0/"#)("+.(*+#(*#$)&5#(!"#)("1#.&5#'.// key()#*&#)(3
} else if (role == Qt::DisplayRole) {
QString rowCurrency = currencyAt(index.row()); G,#:"#!.-"#H%,(#,""&8#)(#),#&*(#5)$$)'%/(#(*#'+".("#+".5F*&/0#1*5"/,8#.&5#5"4"&5)&9#*&#(!"#&.(%+"#*$
QString columnCurrency = currencyAt(index.column()); (!"#%&5"+/0)&9#5.(.8#(!"+"#.+"#4*("&()./ ,.-)&9,#)&#1"1*+0#.&5#,4""5#:)(!#.#:"//F5",)9&"5#1*5"/3
if (currencyMap.value(rowCurrency) == 0.0) !"#&"=(#"=.14/"8#(!"#I)()",#.44/)'.()*&8#),#./,*#(.7/"F7.,"58#7%(#(!),#()1"#.//#(!"#5.(.#),#"&("+"5#70
return "####"; (!"#%,"+3
double amount = currencyMap.value(columnCurrency)
/ currencyMap.value(rowCurrency);
!),#.44/)'.()*&#),#%,"5#(*#,(*+"#-./%",#)&5)'.()&9#(!"#5),(.&'"#7"(:""&#.&0#(:*#')()",3#E)<"#(!"
4+"-)*%,#"=.14/"8#:"#'*%/5#,)14/0#%,"#. QTableWidget#.&5#,(*+"#*&"#)("1#$*+#"-"+0#')(0#4.)+3 private:
J*:"-"+8#.#'%,(*1#1*5"/#'*%/5#7"#1*+"#"$$)')"&(8#7"'.%,"#(!"#5),(.&'"#$+*1#.&0#')(0 #(*#.&0 int offsetOf(int row, int column) const;
5)$$"+"&(#')(0 !#),#(!"#,.1"#:!"(!"+#(+.-"/)&9#$+*1 #(* !#*+#$+*1 !#(* 8#,*#(!"#)("1,#.+"#1)++*+"5 QStringList cities;
./*&9#(!"#1.)&#5).9*&./3 QVector<int> distances;
};
*#,""#!*:#.#'%,(*1#1*5"/#'*14.+",#:)(!#.#,)14/"#(.7/"8#/"(#%,#.,,%1"#(!.(#:"#!.-"#(!+""
')()",8 "#!8#.&5 $3#;$#:"#,(*+"#.#-./%"#$*+#"-"+0#'*17)&.()*&8#:"#:*%/5#&""5#(*#,(*+"#&)&"#-./%",3 G
'.+"$%//0#5",)9&"5#1*5"/#:*%/5#+"D%)+"#*&/0#(!"#(!+""#)("1,#? "#!@8#? "#$@8#.&5#?!"#$@3 6*+#(!),#1*5"/8#:"#.+"#%,)&9#(:*#5.(.#,(+%'(%+",K cities#*$#(04" QStringList#(*#!*/5#(!"#')(0#&.1",8
.&5 distances#*$#(04" QVector<int>#(*#!*/5#(!"#5),(.&'"#7"(:""&#".'!#%&)D%"#4.)+#*$#')()",3
!"#$%&'()'*)&+,%&-!.!%/&0112!30.!45
[View full size image]
CityModel::CityModel(QObject *parent)
: QAbstractTableModel(parent)
{
}

!"#'*&,(+%'(*+#5*",#&*(!)&9#7"0*&5#4.,,#*&#(!" parent#4.+.1"("+#(*#(!"#7.,"#'/.,,3

int CityModel::rowCount(const QModelIndex & /* parent */) const


{
return cities.count();
}
int CityModel::columnCount(const QModelIndex & /* parent */) const
{
return cities.count();
}

J"+"2,#!*:#:"#,"(#%4#.&5#%,"#(!"#1*5"/K B)&'"#:"#!.-"#.#,D%.+"#9+)5#*$#')()",8#(!"#&%17"+#*$#+*:,#.&5#'*/%1&,#),#(!"#&%17"+#*$#')()",#)&#*%+
/),(3

QStringList cities;
cities << "Arvika" << "Boden" << "Eskilstuna" << "Falun" QVariant CityModel::data(const QModelIndex &index, int role) const
<< "Filipstad" << "Halmstad" << "Helsingborg" << "Karlstad" {
<< "Kiruna" << "Kramfors" << "Motala" << "Sandviken" if (!index.isValid())
<< "Skara" << "Stockholm" << "Sundsvall" << "Trelleborg"; return QVariant();
CityModel cityModel; if (role == Qt::TextAlignmentRole) {
cityModel.setCities(cities); return int(Qt::AlignRight | Qt::AlignVCenter);
QTableView tableView; } else if (role == Qt::DisplayRole) {
tableView.setModel(&cityModel); if (index.row() == index.column())
tableView.setAlternatingRowColors(true); return 0;
int offset = offsetOf(index.row(), index.column());
return distances[offset];
}
>"#1%,(#+")14/"1"&(#(!"#,.1"#$%&'()*&, .,#:"#5)5#$*+#(!"#4+"-)*%,#"=.14/"3#;&#.55)()*&8#:"#1%,(
return QVariant();
./,*#+")14/"1"&( setData()#.&5 flags()#(*#1.<"#(!"#1*5"/#"5)(.7/"3#J"+"#),#(!"#'/.,,#5"$)&)()*&K
}

class CityModel : public QAbstractTableModel


{ !" data()#$%&'()*&#),#,)1)/.+#(*#:!.(#:"#5)5#)& CurrencyModel3#;(#+"(%+&,#L#)$#(!"#+*:#.&5#'*/%1&#.+"
Q_OBJECT (!"#,.1"8#7"'.%,"#(!.(#'*++",4*&5,#(*#(!"#'.,"#:!"+"#(!"#(:*#')()",#.+"#(!"#,.1"C#*(!"+:),"8#)(
public: $)&5,#(!"#"&(+0#$*+#(!"#9)-"&#+*:#.&5#'*/%1&#)&#(!" distances#-"'(*+#.&5#+"(%+&,#(!"#5),(.&'"#$*+
CityModel(QObject *parent = 0); (!.(#4.+()'%/.+#4.)+#*$#')()",3
void setCities(const QStringList &cityNames);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const; QVariant CityModel::headerData(int section,
QVariant data(const QModelIndex &index, int role) const; Qt::Orientation /* orientation */,
bool setData(const QModelIndex &index, const QVariant &value, int role) const
int role); {
QVariant headerData(int section, Qt::Orientation orientation, if (role == Qt::DisplayRole)
int role) const; return cities[section];
Qt::ItemFlags flags(const QModelIndex &index) const; return QVariant();
} distances.resize(cities.count() * (cities.count() - 1) / 2);
distances.fill(0);
reset();
}
!" headerData()#$%&'()*&#),#,)14/"#7"'.%,"#:"#!.-"#.#,D%.+"#(.7/"#:)(!#"-"+0#+*:#!.-)&9#.&
)5"&()'./#'*/%1&#!".5"+3#>"#,)14/0#+"(%+&#(!"#&.1"#*$#(!"#')(0#.(#(!"#9)-"&#*$$,"(#)&#(!" cities
,(+)&9#/),(3
;$#.#&":#/),(#*$#')()",#),#9)-"&8#:"#,"(#(!"#4+)-.(" QStringList#(*#(!"#&":#/),(8#+",)A"#.&5#'/".+#(!"
5),(.&'",#-"'(*+8#.&5#'.// QAbstractItemModel::reset()#(*#&*()$0#.&0#-)":,#(!.(#(!")+#-),)7/"#)("1,
bool CityModel::setData(const QModelIndex &index, 1%,(#7"#+"$"('!"53
const QVariant &value, int role)
{
if (index.isValid() && index.row() != index.column() int CityModel::offsetOf(int row, int column) const
&& role == Qt::EditRole) { {
int offset = offsetOf(index.row(), index.column()); if (row < column)
distances[offset] = value.toInt(); qSwap(row, column);
QModelIndex transposedIndex = createIndex(index.column(), return (row * (row - 1) / 2) + column;
index.row()); }
emit dataChanged(index, index);
emit dataChanged(transposedIndex, transposedIndex);
return true;
} !" offsetOf()#4+)-.("#$%&'()*&#'*14%(",#(!"#)&5"=#*$#.#9)-"&#')(0#4.)+#)&#(!" distances#-"'(*+3#6*+
return false; "=.14/"8#)$#:"#!.5#')()", "#!"#$8#.&5 %8#.&5#(!"#%,"+#%45.("5#+*:#N8#'*/%1&#O8!#(* %8#(!"#*$$,"(
} :*%/5#7"#N#=#?N F#O@PQ#R#O#S#T3#;$#(!"#%,"+#!.5#)&,(".5#%45.("5#+*: O8#'*/%1&#N8%#(* !8#(!.&<,#(*
(!" qSwap()8#"=.'(/0#(!"#,.1"#'./'%/.()*&#:*%/5#7"#4"+$*+1"5#.&5#.&#)5"&()'./#*$$,"(#:*%/5#7"
+"(%+&"53
!" setData()#$%&'()*&#),#'.//"5#:!"&#(!"#%,"+#"5)(,#.&#)("13#M+*-)5)&9#(!"#1*5"/#)&5"=#),#-./)58#(!"
(:*#')()",#.+"#5)$$"+"&(8#.&5#(!"#5.(.#"/"1"&(#(*#1*5)$0#),#(!" Qt::EditRole8#(!"#$%&'()*&#,(*+",#(!" !"#$%&'()'6)&+,% cities&057 distances&70.0&/.$#3.#$%/&057&.,%&.082%&947%2
-./%"#(!"#%,"+#"&("+"5#)&#(!" distances#-"'(*+3

!" createIndex()#$%&'()*&#),#%,"5#(*#9"&"+.("#.#1*5"/#)&5"=3#>"#&""5#)(#(*#9"(#(!"#1*5"/#)&5"=#*$
(!"#)("1#*&#(!"#*(!"+#,)5"#*$#(!"#1.)&#5).9*&./#(!.(#'*++",4*&5,#:)(!#(!"#)("1#7")&9#,"(8#,)&'"#7*(!
)("1,#1%,(#,!*:#(!"#,.1"#5.(.3# !" createIndex()#$%&'()*&#(.<",#(!"#+*:#7"$*+"#(!"#'*/%1&C#!"+"
:"#)&-"+(#(!"#4.+.1"("+,#(*#9"(#(!"#1*5"/#)&5"=#*$#(!"#5).9*&.//0#*44*,)("#)("1#(*#(!"#*&"#,4"')$)"5
70 index3

>"#"1)(#(!" dataChanged()#,)9&./#:)(!#(!"#1*5"/#)&5"=#*$#(!"#)("1#(!.(#:.,#'!.&9"53# !"#+".,*&


(!),#,)9&./#(.<",#(:*#1*5"/#)&5"=",#),#(!.(#)(#),#4*,,)7/"#$*+#.#'!.&9"#(*#.$$"'(#.#+"'(.&9%/.+#+"9)*&
*$#1*+"#(!.&#*&"#+*:#.&5#'*/%1&8#,*#(!"#)&5"=",#4.,,"5#.+"#(!"#)&5"=#*$#(!"#(*4#/"$(#.&5#7*((*1
+)9!(#)("1,#*$#(!*,"#(!.(#!.-"#'!.&9"53#>"#./,*#"1)(#(!" dataChanged()#,)9&./ $*+#(!"#(+.&,4*,"5 !"#/.,(#"=.14/"#)&#(!),#,"'()*&#),#.#1*5"/#(!.(#,!*:,#(!"#4.+,"#(+""#$*+#.#9)-"&#+"9%/.+#"=4+",,)*&3
)&5"=#(*#"&,%+"#(!.(#(!"#-)":#:)//#+"$+",!#(!"#)("13#6)&.//08#:"#+"(%+& true#*+ false#(*#)&5)'.(" G#+"9%/.+#"=4+",,)*&#'*&,),(,#*$#*&"#*+#1*+"#("+1,8#,"4.+.("5#70#2U2#'!.+.'("+,3# !%,8#(!"#+"9%/.+
:!"(!"+#*+#&*(#(!"#"5)(#,%''""5"53 "=4+",,)*&#V./4!.U7+.-*U'!.+/)"V#'*&(.)&,#(!+""#("+1,3#W.'!#("+1#),#.#,"D%"&'"#*$#*&"#*+#1*+"
$.'(*+,C#$*+#"=.14/"8#(!"#("+1#V7+.-*V#'*&,),(,#*$#$)-"#$.'(*+,#?".'!#/"(("+#),#.#$.'(*+@3# !"#$.'(*+,
'.&#7"#$%+(!"+#5"'*14*,"5#)&(*#.&#.(*1#.&5#.&#*4()*&./#D%.&()$)"+8#,%'!#.,#2X28#2R28#.&5#2Y23#B)&'"
Qt::ItemFlags CityModel::flags(const QModelIndex &index) const +"9%/.+#"=4+",,)*&,#'.&#!.-"#4.+"&(!",)A"5#,%7"=4+",,)*&,8#(!"0#'.&#!.-"#+"'%+,)-"#4.+,"#(+"",3
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
!"#+"9%/.+#"=4+",,)*&#,!*:&#)& 6)9%+"#OL3OT8#V.7U?'5@Y"V8#1.('!",#.&#2.2#$*//*:"5#70#.#2728#*+
if (index.row() != index.column())
./("+&.()-"/0#")(!"+#.#2'2#$*//*:"5#70#.#252#$*//*:"5#70#.&#2"28#*+#H%,(#.&#2"2#*&#)(,#*:&3#B*#)(#:)//#1.('!
flags |= Qt::ItemIsEditable;
return flags; V.7V#.&5#V'5"V8#7%(#&*(#V7'V#*+#V'5V3
}
!"#$%&'()':)&+,%&;%"%<1&=0$/%$&0112!30.!45

!" flags()#$%&'()*&#),#%,"5#70#(!"#1*5"/#(*#'*11%&)'.("#:!.(#'.&#7"#5*&"#:)(!#.&#)("1#?$*+
"=.14/"8#:!"(!"+#)(#),#"5)(.7/"@3# !"#5"$.%/(#)14/"1"&(.()*&#$+*1 QAbstractTableModel#+"(%+&,
Qt::ItemIsSelectable | Qt::ItemIsEnabled3#>"#.55#(!" Qt::ItemIsEditable#$/.9#$*+#.//#)("1,#"='"4(
(!*,"#/0)&9#*&#(!"#5).9*&./,#?:!)'!#.+"#./:.0,#L@3

void CityModel::setCities(const QStringList &cityNames)


{
cities = cityNames;
{
qDeleteAll(children);
}

!" qDeleteAll()#$%&'()*&#)("+.(",#*-"+#.#'*&(.)&"+#*$#4*)&("+,#.&5#'.//, delete#*&#".'!#*&"3#;(#5*",


&*(#,"(#(!"#4*)&("+,#(*#L8#,*#)$#)(#),#%,"5#*%(,)5"#*$#.#5",(+%'(*+#)(#),#'*11*&#(*#$*//*:#)(#:)(!#.#'.//#(*
clear()#*&#(!"#'*&(.)&"+#(!.(#!*/5,#(!"#4*)&("+,3

\*:#(!.(#:"#!.-"#5"$)&"5#*%+#5.(.#)("1,#?".'!#+"4+","&("5#70#. Node@8#:"#.+"#+".50#(*#'+".("#.
1*5"/K

class RegExpModel : public QAbstractItemModel


{
public:
RegExpModel(QObject *parent = 0);
~RegExpModel();
void setRootNode(Node *node);
QModelIndex index(int row, int column,
const QModelIndex &parent) const;
!"#Z"9"=4#M.+,"+#.44/)'.()*&#'*&,),(,#*$#$*%+#'/.,,",K
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent) const;
• RegExpWindow#),#.#:)&5*:#(!.(#/"(,#(!"#%,"+#"&("+#.#+"9%/.+#"=4+",,)*&#.&5#,!*:,#(!" int columnCount(const QModelIndex &parent) const;
'*++",4*&5)&9#4.+,"#(+""3 QVariant data(const QModelIndex &index, int role) const;
• RegExpParser#9"&"+.(",#.#4.+,"#(+""#$+*1#.#+"9%/.+#"=4+",,)*&3 QVariant headerData(int section, Qt::Orientation orientation,
• RegExpModel#),#.#(+""#1*5"/#(!.(#"&'.4,%/.(",#.#4.+,"#(+""3 int role) const;
• Node#+"4+","&(,#.&#)("1#)&#.#4.+,"#(+""3 private:
Node *nodeFromIndex(const QModelIndex &index) const;
Node *rootNode;
E"(2,#,(.+(#:)(!#(!" Node#'/.,,K };

class Node
{ !),#()1"#:"#!.-"#)&!"+)("5#$+*1 QAbstractItemModel#+.(!"+#(!.&#$+*1#)(,#'*&-"&)"&'"#,%7'/.,,
public: QAbstractTableModel8#7"'.%,"#:"#:.&(#(*#'+".("#.#!)"+.+'!)'./#1*5"/3# !"#",,"&()./#$%&'()*&,#(!.(
enum Type { RegExp, Expression, Term, Factor, Atom, Terminal }; :"#1%,(#+")14/"1"&(#+"1.)&#(!"#,.1"8#"='"4(#(!.(#:"#1%,(#./,*#)14/"1"&( index()#.&5 parent()3
Node(Type type, const QString &str = ""); *#,"(#(!"#1*5"/2,#5.(.8#:"#!.-"#. setRootNode()#$%&'()*&#(!.(#1%,(#7"#'.//"5#:)(!#.#4.+,"#(+""2,
~Node(); +**(#&*5"3
Type type;
QString str;
Node *parent; RegExpModel::RegExpModel(QObject *parent)
QList<Node *> children; : QAbstractItemModel(parent)
}; {
rootNode = 0;
}
W-"+0#&*5"#!.,#.#(04"8#.#,(+)&9#?:!)'!#1.0#7"#"14(0@8#.#4.+"&(#?:!)'!#1.0#7"#L@8#.&5#.#/),(#*$
'!)/5#&*5",#?:!)'!#1.0#7"#"14(0@3
;&#(!"#1*5"/2,#'*&,(+%'(*+8#:"#H%,(#&""5#(*#,"(#(!"#+**(#&*5"#(*#.#,.$"#&%//#-./%"#.&5#4.,,#*&#(!"
parent#(*#(!"#7.,"#'/.,,3
Node::Node(Type type, const QString &str)
{
this->type = type;
RegExpModel::~RegExpModel()
this->str = str;
{
parent = 0;
delete rootNode;
}
}

!"#'*&,(+%'(*+#,)14/0#)&)()./)A",#(!"#&*5"2,#(04"#.&5#,(+)&93#["'.%,"#.//#(!"#5.(.#),#4%7/)'8#'*5"#(!.(
;&#(!"#5",(+%'(*+#:"#5"/"("#(!"#+**(#&*5"3#;$#(!"#+**(#&*5"#!.,#'!)/5+"&8#".'!#*$#(!","#),#5"/"("58
%,", Node#'.&#1.&)4%/.("#(!"#(04"8#,(+)&98#4.+"&(8#.&5#'!)/5+"&#5)+"'(/03
.&5#,*#*&#+"'%+,)-"/08#70#(!" Node#5",(+%'(*+3

Node::~Node()
void RegExpModel::setRootNode(Node *node)
{
delete rootNode; !"#&%17"+#*$#+*:,#$*+#.#9)-"&#)("1#),#,)14/0#!*:#1.&0#'!)/5+"&#)(#!.,3
rootNode = node;
reset();
}
int RegExpModel::columnCount(const QModelIndex & /* parent */) const
{
return 2;
>!"&#.#&":#+**(#&*5"#),#,"(8#:"#7"9)&#70#5"/"()&9#.&0 4+"-)*%,#+**(#&*5"#?.&5#.//#*$#)(,#'!)/5+"&@3 }
!"&#:"#,"(#(!"#&":#+**(#&*5"#.&5#'.// reset()#(*#&*()$0#.&0#-)":,#(!.(#(!"0#1%,(#+"$"('!#(!"#5.(.
$*+#.&0#-),)7/"#)("1,3
!"#&%17"+#*$#'*/%1&,#),#$)="5#.(#Q3# !"#$)+,(#'*/%1&#!*/5,#(!"#&*5"#(04",C#(!"#,"'*&5#'*/%1&
!*/5,#(!"#&*5"#-./%",3
QModelIndex RegExpModel::index(int row, int column,
const QModelIndex &parent) const
{ QModelIndex RegExpModel::parent(const QModelIndex &child) const
if (!rootNode) {
return QModelIndex(); Node *node = nodeFromIndex(child);
Node *parentNode = nodeFromIndex(parent); if (!node)
return createIndex(row, column, parentNode->children[row]); return QModelIndex();
} Node *parentNode = node->parent;
if (!parentNode)
return QModelIndex();
!" index()#$%&'()*&#),#+")14/"1"&("5#$+*1 QAbstractItemModel3 ;(#),#'.//"5#:!"&"-"+#(!"#1*5"/#*+ Node *grandparentNode = parentNode->parent;
(!"#-)":#&""5,#(*#'+".("#. QModelIndex#$*+#.#4.+()'%/.+#'!)/5#)("1#?*+#.#(*4F/"-"/#)("1#)$ parent#),#.& if (!grandparentNode)
return QModelIndex();
)&-./)5 QModelIndex@3#6*+#(.7/"#.&5#/),(#1*5"/,8#:"#5*&2(#&""5#(*#+")14/"1"&(#(!),#$%&'()*&8#7"'.%,"
int row = grandparentNode->children.indexOf(parentNode);
QAbstractList-Model2,#.&5 QAbstractTableModel2,#5"$.%/(#)14/"1"&(.()*&,#&*+1.//0#,%$$)'"3
return createIndex(row, child.column(), parentNode);
}
;&#*%+ index()#)14/"1"&(.()*&8#)$#&*#4.+,"#(+""#),#,"(8#:"#+"(%+&#.&#)&-./)5 QModelIndex3#](!"+:),"8
:"#'+".("#. QModelIndex#:)(!#(!"#9)-"&#+*:#.&5#'*/%1&#.&5#:)(!#. Node *#$*+#(!"#+"D%",("5#'!)/53
6*+#!)"+.+'!)'./#1*5"/,8#<&*:)&9#(!"#+*:#.&5#'*/%1&#*$#.&#)("1#+"/.()-"#(*#)(,#4.+"&(#),#&*(#"&*%9!
Z"(+)"-)&9#(!"#4.+"&( QModelIndex#$+*1#.#'!)/5#),#.#7)(#1*+"#:*+<#(!.&#$)&5)&9#.#4.+"&(2,#'!)/53#>"
(*#%&)D%"/0#)5"&()$0#)(C#:"#1%,(#./,*#<&*: &'(#(!"#4.+"&(#),3# *#,*/-"#(!),8#:"#'.&#,(*+"#.#4*)&("+
'.&#".,)/0#+"(+)"-"#(!"#4.+"&(#&*5"#%,)&9 nodeFromIndex()#.&5#9*)&9#%4#%,)&9 (!" Node2,#4.+"&(
(*#(!"#)&("+&./#&*5"#)&#(!" QModelIndex3 QModelIndex#9)-",#%,#(!"#*4()*&#*$#,(*+)&9#. void *#*+#.& int
4*)&("+8#7%(#(*#*7(.)&#(!"#+*:#&%17"+#?(!"#4*,)()*&#*$#(!"#4.+"&(#.1*&9#)(,#,)7/)&9,@8#:"#&""5#(*#9*
)&#.55)()*&#(*#(!"#+*:#.&5#'*/%1&#&%17"+,3
7.'<#(*#(!"#9+.&54.+"&(#.&5#$)&5#(!"#4.+"&(2,#)&5"=#4*,)()*&#)&#)(,#4.+"&(2,#?(!.(#),8#(!"#'!)/52,
9+.&54.+"&(2,@#/),(#*$#'!)/5+"&3
!" Node *#$*+#(!"#'!)/5#),#*7(.)&"5#(!+*%9!#(!"#4.+"&(#&*5"2, children#/),(3# !"#4.+"&(#&*5"#),
"=(+.'("5#$+*1#(!" parent#1*5"/#)&5"=#%,)&9#(!" nodeFromIndex()#4+)-.("#$%&'()*&K
QVariant RegExpModel::data(const QModelIndex &index, int role) const
{
Node *RegExpModel::nodeFromIndex(const QModelIndex &index) const if (role != Qt::DisplayRole)
{ return QVariant();
if (index.isValid()) { Node *node = nodeFromIndex(index);
return static_cast<Node *>(index.internalPointer()); if (!node)
} else { return QVariant();
return rootNode; if (index.column() == 0) {
} switch (node->type) {
} case Node::RegExp:
return tr("RegExp");
case Node::Expression:
return tr("Expression");
!" nodeFromIndex()#$%&'()*&#'.,(,#(!"#9)-"&#)&5"=2, void *#(*#. Node *8#*+#+"(%+&,#(!"#+**(#&*5"#)$
case Node::Term:
(!"#)&5"=#),#)&-./)58#,)&'"#.&#)&-./)5#1*5"/#)&5"=#),#%,"5#(*#+"4+","&(#(!"#+**(#)&#.#1*5"/3 return tr("Term");
case Node::Factor:
return tr("Factor");
int RegExpModel::rowCount(const QModelIndex &parent) const case Node::Atom:
{ return tr("Atom");
Node *parentNode = nodeFromIndex(parent); case Node::Terminal:
if (!parentNode) return tr("Terminal");
return 0; default:
return parentNode->children.count(); return tr("Unknown");
} }
} else if (index.column() == 1) {
return node->str;
}
return QVariant(); Qt::BackgroundColorRole8#.&5#(!","#.+"#%,"5#70#(!"#5"$.%/(#5"/"9.("3#6*+#"=.14/"8#)&#(!"#I)()",#.&5
} I%++"&')",#"=.14/",#,!*:&#".+/)"+8#:"#!.&5/"5#(!" Qt::TextAlignmentRole#(*#9"(#+)9!(F./)9&"5
&%17"+,3

;& data()8#:"#+"(+)"-"#(!" Node *#$*+#(!"#+"D%",("5#)("1#.&5#:"#%,"#)(#(*#.''",,#(!"#%&5"+/0)&9#5.(.3 ;$#:"#:.&(#"-"&#9+".("+#'*&(+*/8#:"#'.&#'+".("#*%+#*:&#5"/"9.("#'/.,,#.&5#,"(#)(#*&#(!"#-)":,#(!.(


;$#(!"#'.//"+#:.&(,#.#-./%"#$*+#.&0#+*/"#"='"4( Qt:: DisplayRole#*+#)$#:"#'.&&*(#+"(+)"-"#. Node#$*+ :"#:.&(#(*#1.<"#%,"#*$#)(3# !"# +.'<#W5)(*+#5)./*9#,!*:&#7"/*:#1.<",#%,"#*$#.#'%,(*1#5"/"9.("3#;(
(!"#9)-"&#1*5"/#)&5"=8#:"#+"(%+&#.&#)&-./)5 QVariant3#;$#(!"#'*/%1&#),#L8#:"#+"(%+&#(!"#&.1"#*$#(!" ,!*:,#(!"#()(/",#*$#1%,)'#(+.'<,#.&5#(!")+#5%+.()*&,3# !"#5.(.#!"/5#70#(!"#1*5"/#:)//#7"#,)14/0
&*5"2,#(04"C#)$#(!"#'*/%1&#),#O8#:"#+"(%+&#(!"#&*5"2,#-./%"#?)(,#,(+)&9@3 QString,#?()(/",@#.&5 int,#?,"'*&5,@8#7%(#(!"#5%+.()*&,#:)//#7"#,"4.+.("5#)&(*#1)&%(",#.&5 ,"'*&5,
.&5#:)//#7"#"5)(.7/"#%,)&9#. QTimeEdit3

QVariant RegExpModel::headerData(int section, !"#$%&'()'>)&+,%&+$03?&@7!.4$&7!024"


Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
if (section == 0) {
return tr("Node");
} else if (section == 1) {
return tr("Value");
}
}
return QVariant();
}

;&#*%+ headerData()#+")14/"1"&(.()*&8#:"#+"(%+&#.44+*4+).("#!*+)A*&(./#!".5"+#/.7"/,3# !"


QTReeView#'/.,,8#:!)'!#),#%,"5#(*#-),%./)A"#!)"+.+'!)'./#1*5"/,8#!.,#&*#-"+()'./#!".5"+8#,*#:"#)9&*+"
(!.(#4*,,)7)/)(03

\*:#(!.(#:"#!.-"#'*-"+"5#(!" Node#.&5 RegExpModel#'/.,,",8#/"(2,#,""#!*:#(!"#+**(#&*5"#),#'+".("5


:!"&#(!"#%,"+#'!.&9",#(!"#("=(#)&#(!"#/)&"#"5)(K

!"# +.'<#W5)(*+#5)./*9#%,",#. QTableWidget8#.#'*&-"&)"&'"#)("1#-)":#,%7'/.,,#(!.(#*4"+.(",#*&


void RegExpWindow::regExpChanged(const QString &regExp) QTableWidgetItem,3# !"#5.(.#),#4+*-)5"5#.,#.#/),(#*$ track,K
{
RegExpParser parser;
Node *rootNode = parser.parse(regExp); class Track
regExpModel->setRootNode(rootNode); {
} public:
Track(const QString &title = "", int duration = 0);
QString title;
>!"&#(!"#%,"+#'!.&9",#(!"#("=(#)&#(!"#.44/)'.()*&2,#/)&"#"5)(8#(!"#1.)&#:)&5*:2, regExpChanged()#,/*( int duration;
};
),#'.//"53#;&#(!),#,/*(8#(!"#%,"+2,#("=(#),#4.+,"5#.&5#(!"#4.+,"+#+"(%+&,#.#4*)&("+#(*#(!"#+**(#&*5"#*$
(!"#4.+,"#(+""3

>"#!.-"#&*(#,!*:&#(!" RegExpParser#'/.,,#7"'.%,"#)(#),#&*(#+"/"-.&(#$*+#^_;#*+#1*5"/P-)": J"+"#),#.&#"=(+.'(#$+*1#(!"#'*&,(+%'(*+#(!.(#,!*:,#(!"#'+".()*&#.&5#4*4%/.()*&#*$#(!"#(.7/"#:)59"(K


4+*9+.11)&93# !"#$%//#,*%+'"#$*+#(!),#"=.14/"#),#*&#(!"#I`3

TrackEditor::TrackEditor(QList<Track> *tracks, QWidget *parent)


;&#(!),#,"'()*&8#:"#!.-"#,""&#!*:#(*#'+".("#(!+""#5)$$"+"&(#'%,(*1#1*5"/,3#a.&0#1*5"/,#.+"#1%'!
: QDialog(parent)
,)14/"+#(!.&#(!*,"#,!*:&#!"+"8#:)(!#*&"F(*F*&"#'*++",4*&5"&'",#7"(:""&#)("1,#.&5#1*5"/ {
)&5"=",3#6%+(!"+#1*5"/P-)":#"=.14/",#.+"#4+*-)5"5#:)(!#b(#)(,"/$8#./*&9#:)(!#"=("&,)-" this->tracks = tracks;
5*'%1"&(.()*&3 tableWidget = new QTableWidget(tracks->count(), 2);
tableWidget->setItemDelegate(new TrackDelegate(1));
tableWidget->setHorizontalHeaderLabels(
QStringList() << tr("Track") << tr("Duration"));
Implementing Custom Delegates for (int row = 0; row < tracks->count(); ++row) {
Track track = tracks->at(row);
;&5)-)5%./#)("1,#)&#-)":,#.+"#+"&5"+"5#.&5#"5)("5#%,)&9#5"/"9.(",3#;&#1*,(#'.,",8#(!"#5"$.%/( QTableWidgetItem *item0 = new QTableWidgetItem(track.title);
5"/"9.("#,%44/)"5#70#.#-)":#),#,%$$)')"&(3#;$#:"#:.&(#(*#!.-"#$)&"+#'*&(+*/#*-"+#(!"#+"&5"+)&9#*$ tableWidget->setItem(row, 0, item0);
QTableWidgetItem *item1
)("1,8#:"#'.&#*$("&#.'!)"-"#:!.(#:"#:.&(#,)14/0#70#%,)&9#.#'%,(*1#1*5"/K#;&#*%+ data()
= new QTableWidgetItem(QString::number(track.duration));
+")14/"1"&(.()*&#:"#'.&#!.&5/"#(!" Qt::FontRole8 Qt::TextAlignmentRole8 Qt::TextColorRole8#.&5 item1->setTextAlignment(Qt::AlignRight);
tableWidget->setItem(row, 1, item1); myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
} drawDisplay(painter, myOption, myOption.rect, text);
... drawFocus(painter, myOption, myOption.rect);
} } else{
QItemDelegate::paint(painter, option, index);
}
}
!"#'*&,(+%'(*+#'+".(",#.#(.7/"#:)59"(8#.&5#)&,(".5#*$#,)14/0#%,)&9#(!"#5"$.%/(#5"/"9.("8#:"#,"(#*%+
'%,(*1 TRackDelegate8#4.,,)&9#)(#(!"#'*/%1&#(!.(#!*/5,#()1"#5.(.3#>"#7"9)&#70#,"(()&9#(!"#'*/%1&
!".5)&9,8#.&5#(!"&#)("+.("#(!+*%9!#(!"#5.(.8#4*4%/.()&9#(!"#+*:,#:)(!#(!"#&.1"#.&5#5%+.()*&#*$
".'!#(+.'<3 B)&'"#:"#:.&(#(*#+"&5"+#(!"#5%+.()*&#)&#(!"#$*+1#V)*+,-./#K/.0(+1/V8#:"#!.-"#+")14/"1"&("5#(!"
paint()#$%&'()*&3# !" arg()#'.//,#(.<"#.&#)&("9"+#(*#+"&5"+#.,#.#,(+)&98#!*:#1.&0#'!.+.'("+,#(!"
!"#+",(#*$#(!"#'*&,(+%'(*+#.&5#(!"#+",(#*$#(!" TRackEditor#5)./*9#!*/5,#&*#,%+4+),",8#,*#:"#:)//#&*: ,(+)&9#,!*%/5#!.-"8#(!"#7.,"#*$#(!"#)&("9"+#?OL#$*+#5"')1./@8#.&5#(!"#4.55)&9#'!.+.'("+3
/**<#.(#(!" trackDelegate#(!.(#!.&5/",#(!"#+"&5"+)&9#.&5#"5)()&9#*$#(+.'<#5.(.3
*#+)9!(F./)9&#(!"#("=(8#:"#'*40#(!"#'%++"&(#,(0/"#*4()*&,#.&5#*-"+:+)("#(!"#5"$.%/(#./)9&1"&(3#>"
(!"&#'.// QItemDelegate::drawDisplay()#(*#5+.:#(!"#("=(8#$*//*:"5#70 QItemDelegate::drawFocus()8
class TrackDelegate : public QItemDelegate :!)'!#:)//#5+.:#.#$*'%,#+"'(.&9/"#)$#(!"#)("1#!.,#$*'%,#.&5#:)//#5*#&*(!)&9#*(!"+:),"3#_,)&9
{ drawDisplay()#),#-"+0#'*&-"&)"&(8#",4"').//0#:!"&#%,"5#:)(!#*%+#*:&#,(0/"#*4()*&,3#>"#'*%/5#./,*
Q_OBJECT 5+.:#%,)&9#(!"#4.)&("+#5)+"'(/03
public:
TrackDelegate(int durationColumn, QObject *parent = 0);
void paint(QPainter *painter, const QStyleOptionViewItem &option, QWidget *TrackDelegate::createEditor(QWidget *parent,
const QModelIndex &index) const; const QStyleOptionViewItem &option,
QWidget *createEditor(QWidget *parent, const QModelIndex &index) const
const QStyleOptionViewItem &option, {
const QModelIndex &index) const; if (index.column() == durationColumn) {
void setEditorData(QWidget *editor, const QModelIndex &index) const; QTimeEdit *timeEdit = new QTimeEdit(parent);
void setModelData(QWidget *editor, QAbstractItemModel *model, timeEdit->setDisplayFormat("mm:ss");
const QModelIndex &index) const; connect(timeEdit, SIGNAL(editingFinished()),
private slots: this, SLOT(commitAndCloseEditor()));
void commitAndCloseEditor(); return timeEdit;
private: } else {
int durationColumn; return QItemDelegate::createEditor(parent, option, index);
}; }
}

>"#%," QItemDelegate#.,#*%+#7.,"#'/.,,8#,*#(!.(#:"#7"&"$)(#$+*1#(!"#5"$.%/(#5"/"9.("
)14/"1"&(.()*&3#>"#'*%/5#./,*#!.-"#%,"5 QAbstractItemDelegate#)$#:"#!.5#:.&("5#(*#,(.+(#$+*1 >"#*&/0#:.&(#(*#'*&(+*/#(!"#"5)()&9#*$#(+.'<#5%+.()*&,8#/".-)&9#(!"#"5)()&9#*$#(+.'<#&.1",#(*#(!"
,'+.('!3# *#4+*-)5"#.#5"/"9.("#(!.(#'.&#"5)(#5.(.8#:"#1%,(#)14/"1"&( createEditor()8 5"$.%/(#5"/"9.("3#>"#.'!)"-"#(!),#70#'!"'<)&9#:!)'!#'*/%1&#(!"#5"/"9.("#!.,#7""&#.,<"5#(*#4+*-)5"
setEditorData()8#.&5 setModelData()3#>" ./,*#)14/"1"&( paint()#(*#'!.&9"#(!"#+"&5"+)&9#*$#(!" .&#"5)(*+#$*+3#;$#)(2,#(!"#5%+.()*&#'*/%1&8#:"#'+".("#. QTimeEdit8#,"(#(!"#5),4/.0#$*+1.(
5%+.()*&#'*/%1&3 .44+*4+).("/08.&5#'*&&"'(#)(, editingFinished()#,)9&./#(*#*%+ commitAndCloseEditor()#,/*(3#6*+#.&0
*(!"+#'*/%1&8#:"#4.,,#*&#(!"#"5)(#!.&5/)&9#(*#(!"#5"$.%/(#5"/"9.("3

TrackDelegate::TrackDelegate(int durationColumn, QObject *parent)


: QItemDelegate(parent) void TrackDelegate::commitAndCloseEditor()
{ {
this->durationColumn = durationColumn; QTimeEdit *editor = qobject_cast<QTimeEdit *>(sender());
} emit commitData(editor);
emit closeEditor(editor);
}
!" durationColumn#4.+.1"("+#(*#(!"#'*&,(+%'(*+#("//,#(!"#5"/"9.("#:!)'!#'*/%1&#!*/5,#(!"#(+.'<
5%+.()*&3
;$#(!"#%,"+#4+",,",#W&("+#*+#1*-",#(!"#$*'%,#*%(#*$#(!" QTimeEdit#?7%(#&*(#)$#(!"0#4+",,#W,'@8#(!"
editingFinished()#,)9&./#),#"1)(("5#.&5#(!" commitAndCloseEditor()#,/*(#),#'.//"53# !),#,/*(#"1)(,#(!"
void TrackDelegate::paint(QPainter *painter, commitData()#,)9&./#(*#)&$*+1#(!"#-)":#(!.(#(!"+"#),#"5)("5#5.(.#(*#+"4/.'"#"=),()&9#5.(.3#;(#./,*
const QStyleOptionViewItem &option, "1)(,#(!" closeEditor()#,)9&./#(*#&*()$0#(!"#-)":#(!.(#(!),#"5)(*+#),#&*#/*&9"+#+"D%)+"58#.(#:!)'!#4*)&(
const QModelIndex &index) const (!"#1*5"/#:)//#5"/"("#)(3# !"#"5)(*+#),#+"(+)"-"5#%,)&9 QObject::sender()8#:!)'!#+"(%+&,#(!"#*7H"'(
{ (!.(#"1)(("5#(!"#,)9&./#(!.(#(+)99"+"5#(!"#,/*(3#;$#(!"#%,"+#'.&'"/,#?70#4+",,)&9#W,'@8#(!"#-)":#:)//
if (index.column() == durationColumn) { ,)14/0#5"/"("#(!"#"5)(*+3
int secs = index.model()->data(index, Qt::DisplayRole).toInt();
QString text = QString("%1:%2")
.arg(secs / 60, 2, 10, QChar('0'))
.arg(secs % 60, 2, 10, QChar('0')); void TrackDelegate::setEditorData(QWidget *editor,
QStyleOptionViewItem myOption = option; const QModelIndex &index) const
{
if (index.column() == durationColumn) {
int secs = index.model()->data(index, Qt::DisplayRole).toInt();
QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);
Chapter 11. Container Classes
timeEdit->setTime(QTime(0, secs / 60, secs % 60));
} else { • !"#!$%&'()*+$%'&$!,-
QItemDelegate::setEditorData(editor, index); • .--+/&'%&0!)*+$%'&$!,-
} • 1!$!,&/).(2+,&%34-
} • %,&$2-5)67%!).,,'7-5)'$8)9',&'$%-

I*&(.)&"+#'/.,,",#.+"#9"&"+./F4%+4*,"#("14/.("#'/.,,",#(!.(#,(*+"#)("1,#*$#.#9)-"&#(04"#)&#1"1*+03
>!"&#(!"#%,"+#)&)().(",#"5)()&98#(!"#-)":#'.//, createEditor()#(*#'+".("#.&#"5)(*+8#.&5#(!"& IRR#./+".50#*$$"+,#1.&0#'*&(.)&"+,#.,#4.+(#*$#(!"#B(.&5.+5# "14/.("#E)7+.+0#?B E@8#:!)'!#),
setEditorData()#(*#)&)()./)A"#(!"#"5)(*+#:)(!#(!"#)("12,#'%++"&(#5.(.3#;$#(!"#"5)(*+#),#$*+#(!"#5%+.()*& )&'/%5"5#)&#(!"#B(.&5.+5#IRR#/)7+.+03
'*/%1&8#:"#"=(+.'(#(!"#(+.'<2,#5%+.()*&#)&#,"'*&5,#.&5#,"(#(!" QTimeEdit2,#()1"#(*#(!"#'*++",4*&5)&9
&%17"+#*$#1)&%(",#.&5#,"'*&5,C#*(!"+:),"8#:"#/"(#(!"#5"$.%/(#5"/"9.("#!.&5/"#(!"#)&)()./)A.()*&3 b(#4+*-)5",#)(,#*:&#'*&(.)&"+#'/.,,",8#,*#$*+#b(#4+*9+.1,#:"#'.&#%,"#7*(!#(!"#b(#.&5#(!"#B E
'*&(.)&"+,3# !"#1.)&#.5-.&(.9",#*$#(!"#b(#'*&(.)&"+,#.+"#(!.(#(!"0#7"!.-"#(!"#,.1"#*&#.//
4/.($*+1,#.&5#(!.(#(!"0#.+"#)14/)')(/0#,!.+"53#;14/)')(#,!.+)&98#*+#V'*40#*&#:+)("V8#),#.&#*4()1)A.()*&
void TrackDelegate::setModelData(QWidget *editor, (!.(#1.<",#)(#4*,,)7/"#(*#4.,, "&()+"#'*&(.)&"+,#.,#-./%",#:)(!*%(#.&0#,)9&)$)'.&(#4"+$*+1.&'"#'*,(3
QAbstractItemModel *model, !"#b(#'*&(.)&"+,#./,*#$".(%+"#".,0F(*F%,"#)("+.(*+#'/.,,",#)&,4)+"5#70#c.-.8#(!"0#'.&#7"#,(+".1"5
const QModelIndex &index) const %,)&9 QDataStream8#.&5#(!"0#%,%.//0#+",%/(#)&#/",,#'*5"#)&#(!"#"="'%(.7/"#(!.&#(!"#'*++",4*&5)&9#B E
{ '*&(.)&"+,3#6)&.//08#*&#,*1"#!.+5:.+"#4/.($*+1,#,%44*+("5#70#b(*4).#I*+"#?(!"#b(#-"+,)*&#$*+
if (index.column() == durationColumn) { 1*7)/"#5"-)'",@8#(!"#b(#'*&(.)&"+,#.+"#(!"#*&/0#*&",#.-.)/.7/"3
QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);
QTime time = timeEdit->time();
int secs = (time.minute() * 60) + time.second(); b(#*$$"+,#7*(!#,"D%"&()./#'*&(.)&"+,#,%'!#., QVector<T>8 QLinkedList<T>8#.&5 QList<T>8#.&5
model->setData(index, secs); .,,*').()-"#'*&(.)&"+,#,%'!#., QMap<K, T>#.&5 QHash<K, T>3#I*&'"4(%.//08#(!"#,"D%"&()./#'*&(.)&"+,
} else { ,(*+"#)("1,#*&"#.$("+#.&*(!"+8#:!"+".,#(!"#.,,*').()-"#'*&(.)&"+,#,(*+"#<"0-./%"#4.)+,3
QItemDelegate::setModelData(editor, model, index);
} b(#./,*#4+*-)5",#9"&"+)'#./9*+)(!1,#(!.(#4"+$*+1#*4"+.()*&,#*& .+7)(+.+0#'*&(.)&"+,3#6*+#"=.14/"8
} (!" qSort()#./9*+)(!1#,*+(,#.#,"D%"&()./#'*&(.)&"+8#.&5 qBinaryFind()#4"+$*+1,#.#7)&.+0#,".+'!#*&#.
,*+("5#,"D%"&()./#'*&(.)&"+3# !","#./9*+)(!1,#.+"#,)1)/.+#(*#(!*,"#*$$"+"5#70#(!"#B E3

;$#(!"#%,"+#'*14/"(",#(!"#"5)(#?$*+#"=.14/"8#70#/"$(F'/)'<)&9#*%(,)5"#(!"#"5)(*+#:)59"(8#*+#70#4+",,)&9 ;$#0*%#.+"#./+".50#$.1)/).+#:)(!#(!"#B E#'*&(.)&"+,#.&5#!.-"#B E#.-.)/.7/"#*&#0*%+#(.+9"(#4/.($*+1,8


W&("+#*+# .7@#+.(!"+#(!.&#'.&'"/)&9#)(8#(!"#1*5"/#1%,(#7"#%45.("5#:)(!#(!"#"5)(*+2,#5.(.3#;$#(!" 0*%#1)9!(#:.&(#(*#%,"#(!"1#)&,(".5#*$8#*+#)&#.55)()*&#(*8#(!"#b(#'*&(.)&"+,3#6*+#1*+"#)&$*+1.()*&
5%+.()*&#:.,#"5)("58#:"#"=(+.'(#(!"#1)&%(",#.&5#,"'*&5,#$+*1#(!" QTimeEdit8#.&5#,"(#(!"#5.(.#(* .7*%(#(!"#B E#'/.,,",#.&5#$%&'()*&,8#.#9**5#4/.'"#(*#,(.+(#),#B^;2,#B E#:"7#,)("K
(!"#'*++",4*&5)&9#&%17"+#*$#,"'*&5,3 !((4KPP:::3,9)3'*1P("'!P,(/P3

G/(!*%9!#&*(#&"'",,.+0#)&#(!),#'.,"8#)(#),#"&()+"/0#4*,,)7/"#(*#'+".("#.#'%,(*1#5"/"9.("#(!.(#$)&"/0 ;&#(!),#'!.4("+8#:"#:)//#./,*#/**<#.( QString8 QByteArray8#.&5 QVariant8#,)&'"#(!"0#!.-"#.#/*(#)&


'*&(+*/,#(!"#"5)()&9#.&5#+"&5"+)&9#*$#.&0#)("1#)&#.#1*5"/3#>"#!.-"#'!*,"&#(*#(.<"#'*&(+*/#*$#. '*11*&#:)(!#'*&(.)&"+,3 QString#),#.#OdF7)(#_&)'*5"#,(+)&9#%,"5#(!+*%9!*%(#b(2, GM;3 QByteArray#),
4.+()'%/.+#'*/%1&8#7%(#,)&'"#(!" QModelIndex#),#4.,,"5#(*#.//#(!" QItemDelegate#$%&'()*&,#(!.(#:" .&#.++.0#*$#eF7)( char,#%,"$%/#$*+#,(*+)&9#+.:#7)&.+0#5.(.3 QVariant#),#.#(04"#(!.(#'.&#,(*+"#1*,(
+")14/"1"&(8#:"#'.&#(.<"#'*&(+*/#70#'*/%1&8#+*:8#+"'(.&9%/.+#+"9)*&8#4.+"&(8#*+#.&0#'*17)&.()*&#*$ IRR#.&5#b(#-./%"#(04",3
(!","8#+)9!(#5*:&#(*#)&5)-)5%./#)("1,#)$#+"D%)+"53

;&#(!),#'!.4("+8#:"#!.-"#4+","&("5#.#7+*.5#*-"+-)":#*$#b(2,#1*5"/P-)":#.+'!)("'(%+"3#>"#!.-" Sequential Containers


,!*:&#!*:#(*#%,"#(!"#-)":#'*&-"&)"&'"#,%7'/.,,",8#!*:#(*#%,"#b(2,#4+"5"$)&"5#1*5"/,8#.&5#!*:#(*
'+".("#'%,(*1#1*5"/,#.&5#'%,(*1#5"/"9.(",3#[%(#(!"#1*5"/P-)":#.+'!)("'(%+"#),#,*#+)'!#(!.(#:" G QVector<T>#),#.&#.++.0F/)<"#5.(.#,(+%'(%+"#(!.(#,(*+",#)(,#)("1,#.(#.5H.'"&(#4*,)()*&,#)&#1"1*+03
!.-"#&*(#!.5#(!"#,4.'"#(*#'*-"+#.//#(!"#(!)&9,#)(#1.<",#4*,,)7/"3#6*+#"=.14/"8#:"#'*%/5#'+".("#. >!.(#5),()&9%),!",#.#-"'(*+#$+*1#.#4/.)&#IRR#.++.0#),#(!.(#.#-"'(*+#<&*:,#)(,#*:&#,)A"#.&5#'.&#7"
'%,(*1#-)":#(!.(#5*",#&*(#+"&5"+#)(,#)("1,#.,#.#/),(8#(.7/"8#*+#(+""3# !),#),#5*&"#70#(!"#I!.+( +",)A"53#G44"&5)&9#"=(+.#)("1,#(*#(!"#"&5#*$#.#-"'(*+#),#$.)+/0#"$$)')"&(8#:!)/"#)&,"+()&9#)("1,#.(#(!"
"=.14/"#/*'.("5#)&#b(2, examples/itemviews/chart#5)+"'(*+08#:!)'!#,!*:,#.#'%,(*1#-)":#(!.( $+*&(#*+#)&#(!"#1)55/"#*$#.#-"'(*+#'.&#7"#"=4"&,)-"3
+"&5"+,#1*5"/#5.(.#)&#(!"#$*+1#*$#.#4)"#'!.+(3
!"#$%&'')')&A&B%3.4$&4C double/
;(#),#./,*#4*,,)7/"#(*#%,"#1%/()4/"#-)":,#(*#-)":#(!"#,.1"#1*5"/#:)(!*%(#.&0#$*+1./)(03#G&0#"5)(,
1.5"#(!+*%9!#*&"#-)":#:)//#7"#.%(*1.()'.//0#.&5#)11"5).("/0#+"$/"'("5#)&#(!"#*(!"+#-)":,3# !),#<)&5
*$#$%&'()*&./)(0#),#4.+()'%/.+/0#%,"$%/#$*+#-)":)&9#/.+9"#5.(.#,"(,#:!"+"#(!"#%,"+#1.0#:),!#(*#,""
,"'()*&,#*$#5.(.#(!.(#.+"#/*9)'.//0#$.+#.4.+(3# !"#.+'!)("'(%+"#./,*#,%44*+(,#,"/"'()*&,K#>!"+"#(:*#*+
1*+"#-)":,#.+"#%,)&9#(!"#,.1"#1*5"/8#".'!#-)":#'.&#7"#,"(#(*#!.-"#)(,#*:&#)&5"4"&5"&(#,"/"'()*&,8
*+#(!"#,"/"'()*&,#'.&#7"#,!.+"5#.'+*,,#(!"#-)":,3

b(2,#*&/)&"#5*'%1"&(.()*&#4+*-)5",#'*14+"!"&,)-"#'*-"+.9"#*$#)("1#-)":#4+*9+.11)&9#.&5#(!"
;$#:"#<&*:#)&#.5-.&'"#!*:#1.&0#)("1,#:"#.+"#9*)&9#(*#&""58#:"#'.&#9)-"#(!"#-"'(*+#.&#)&)()./#,)A"
'/.,,",#(!.(#)14/"1"&(#)(3#B"" !((4KPP5*'3(+*//("'!3'*1PT3OP1*5"/F-)":3!(1/#$*+#.#/),(#*$#.//#(!"
+"/"-.&(#'/.,,",8#.&5 !((4KPP5*'3(+*//("'!3'*1PT3OP1*5"/F-)":F4+*9+.11)&93!(1/#$*+#.55)()*&./ :!"&#:"#5"$)&"#)(#.&5#%,"#(!" []#*4"+.(*+#(*#.,,)9&#.#-./%"#(*#(!"#)("1,C#*(!"+:),"8#:"#1%,(#")(!"+
)&$*+1.()*&#.&5#/)&<,#(*#(!"#+"/"-.&(#"=.14/",#)&'/%5"5#:)(!#b(3 +",)A"#(!"#-"'(*+#/.("+#*&#*+#.44"&5#)("1,3#J"+"2,#.&#"=.14/"#:!"+"#:"#,4"')$0#(!"#)&)()./#,)A"K
!" QList<T>#,"D%"&()./#'*&(.)&"+#),#.&#V.++.0F/),(V#(!.(#'*17)&",#(!"#1*,(#)14*+(.&(#7"&"$)(,#*$
QVector<double> vect(3); QVector<T>#.&5 QLinkedList<T>#)&#.#,)&9/"#'/.,,3#;(#,%44*+(,#+.&5*1#.''",,8#.&5#)(, )&("+$.'"#),
vect[0] = 1.0; )&5"=F7.,"5#/)<" QVector2,3#;&,"+()&9#*+#+"1*-)&9#.&#)("1#.(#")(!"+#"&5#*$#. QList<T>#),#-"+0#$.,(8
vect[1] = 0.540302;
.&5#)&,"+()&9#)&#(!"#1)55/"#),#$.,(#$*+#/),(,#:)(!#%4#(*#.7*%(#*&"#(!*%,.&5#)("1,3#_&/",,#:"#:.&(#(*
vect[2] = -0.416147;
4"+$*+1#)&,"+()*&,#)&#(!"#1)55/"#*$#!%9"#/),(,#*+#&""5#(!"#/),(2,#)("1,#(*#*''%40#'*&,"'%()-"
.55+",,",#)&#1"1*+08 QList<T>#),#%,%.//0#(!"#1*,(#.44+*4+).("#9"&"+./F4%+4*,"#'*&(.)&"+#'/.,,#(*
%,"3
J"+"2,#(!"#,.1"#"=.14/"8#(!),#()1"#,(.+()&9#:)(!#.&#"14(0#-"'(*+#.&5#%,)&9#(!" append()#$%&'()*&#(*
.44"&5#)("1,#.(#(!"#"&5K !" QStringList#'/.,,#),#.#,%7'/.,,#*$ QList<QString>#(!.(#),#:)5"/0#%,"5#)&#b(2,#GM;3#;&#.55)()*&#(*
(!"#$%&'()*&,#)(#)&!"+)(,#$+*1#)(,#7.,"#'/.,,8#)(#4+*-)5",#,*1"#"=(+.#$%&'()*&,#(!.(#1.<"#(!"#'/.,,
1*+"#-"+,.()/"#$*+#,(+)&9#!.&5/)&93 QStringList#),#5),'%,,"5#)&#(!"#/.,(#,"'()*&#*$#(!),#'!.4("+#?43
QVector<double> vect;
Qde@3
vect.append(1.0);
vect.append(0.540302);
vect.append(-0.416147); QStack<T>#.&5 QQueue<T>#.+"#(:*#1*+"#"=.14/",#*$ '*&-"&)"&'"#,%7'/.,,",3 QStack<T>#),#.#-"'(*+
(!.(#4+*-)5", push()8 pop()8#.&5 top()3 QQueue<T>#),#.#/),(#(!.(#4+*-)5", enqueue()8 dequeue()8#.&5
head()3
>"#'.&#./,*#%,"#(!" <<#*4"+.(*+#)&,(".5#*$ append()K
6*+#.//#(!"#'*&(.)&"+#'/.,,",#,""&#,*#$.+8#(!"#-./%"#(04" T#'.&#7"#.#7.,)'#(04"#/)<" int#*+ double8#.
4*)&("+#(04"8#*+#.#'/.,,#(!.(#!.,#.#5"$.%/(#'*&,(+%'(*+#?.#'*&,(+%'(*+#(!.(#(.<",#&*#.+9%1"&(,@8#.
vect << 1.0 << 0.540302 << -0.416147; '*40#'*&,(+%'(*+8#.&5#.&#.,,)9&1"&(#*4"+.(*+3#I/.,,",#(!.(#D%./)$0#)&'/%5" QByteArray8 QDateTime8
QRegExp8 QString8#.&5 QVariant3#b(#'/.,,",#(!.(#)&!"+)(#$+*1 QObject#5*#&*(#D%./)$08#7"'.%,"#(!"0
/.'<#.#'*40#'*&,(+%'(*+#.&5#.&#.,,)9&1"&(#*4"+.(*+3# !),#),#&*#4+*7/"1#)&#4+.'()'"8#,)&'"#:"#'.&
]&"#:.0#(*#)("+.("#*-"+#(!"#-"'(*+2,#)("1,#),#(*#%," []#.&5 count()K ,)14/0#,(*+"#4*)&("+,#(* QObject#(04",#+.(!"+#(!.&#(!"#*7H"'(,#(!"1,"/-",3

!"#-./%"#(04" T#'.&#./,*#7"#.#'*&(.)&"+8#)& :!)'!#'.,"#:"#1%,(#+"1"17"+#(*#,"4.+.("#'*&,"'%()-"


double sum = 0.0; .&9/"#7+.'<"(,#:)(!#,4.'",C#*(!"+:),"8#(!"#'*14)/"+#:)//#'!*<"#*&#:!.(#)(#(!)&<,#),#. >>#*4"+.(*+3#6*+
for (int i = 0; i < vect.count(); ++i) "=.14/"K
sum += vect[i];

QList<QVector<double> > list;


f"'(*+#"&(+)",#(!.(#.+"#'+".("5#:)(!*%(#7")&9#.,,)9&"5#.&#"=4/)')(#-./%"#.+"#)&)()./)A"5#%,)&9#(!"#)("1
'/.,,2,#5"$.%/(#'*&,(+%'(*+3#[.,)'#(04",#.&5#4*)&("+#(04",#.+"#)&)()./)A"5#(*#A"+*3
;&#.55)()*&#(*#(!"#(04",#H%,(#1"&()*&"58#.#'*&(.)&"+2,#-./%"#(04"#'.&#7"#.&0#'%,(*1#'/.,,#(!.(#1""(,
;&,"+()&9#)("1,#.(#(!"#7"9)&&)&9#*+#)&#(!"#1)55/"#*$#. QVector<T>8#*+#+"1*-)&9#)("1,#$+*1#(!"," (!"#'+)("+).#5",'+)7"5#".+/)"+3#J"+"#),#.&#"=.14/"#*$#,%'!#.#'/.,,K
4*,)()*&,8#'.&#7"#)&"$$)')"&(#$*+#/.+9"#-"'(*+,3#6*+#(!),#+".,*&8#b(#./,*#*$$"+, QLinkedList<T>8#.#5.(.
,(+%'(%+"#(!.(#,(*+",#)(,#)("1,#.(#&*&F.5H.'"&(#/*'.()*&,#)&#1"1*+03#_&/)<"#-"'(*+,8#/)&<"5#/),(,#5*&2(
,%44*+(#+.&5*1#.''",,8#7%(#(!"0#4+*-)5"#V'*&,(.&(#()1"V#)&,"+()*&,#.&5#+"1*-./,3 class Movie
{
public:
!"#$%&'')*) A&2!5?%7&2!/.&4C double/ Movie(const QString &title = "", int duration = 0);
void setTitle(const QString &title) { myTitle = title; }
QString title() const { return myTitle; }
void setDuration(int duration) { myDuration = duration; }
QString duration() const { return myDuration; }
private:
QString myTitle;
int myDuration;
};
E)&<"5#/),(,#5*#&*(#4+*-)5"#(!" []#*4"+.(*+8#,*#)("+.(*+,#1%,(#7"#%,"5#(*#(+.-"+,"#(!")+#)("1,3
;("+.(*+,#.+"#./,*#%,"5#(*#,4"')$0#(!"#4*,)()*&#*$#)("1,3#6*+#"=.14/"8#(!"#$*//*:)&9#'*5"#)&,"+(,#(!"
,(+)&9#V *("#J*,"&V#7"(:""&#VI/.,!V#.&5#VZ.1*&",VK !"#'/.,,#!.,#.#'*&,(+%'(*+#(!.(#+"D%)+",#&*#.+9%1"&(,#?./(!*%9!#)(#'.&#(.<"#%4#(*#(:*@3#;(#./,*#!.,
.#'*40#'*&,(+%'(*+#.&5#.&#.,,)9&1"&(#*4"+.(*+8#7*(!#)14/)')(/0#4+*-)5"5#70#IRR3#6*+#(!),#'/.,,8
1"17"+F70F1"17"+#'*40#),#,%$$)')"&(8#,*#(!"+"2,#&*#&""5#(*#)14/"1"&(#*%+#*:&#'*40#'*&,(+%'(*+
QLinkedList<QString> list; .&5#.,,)9&1"&(#*4"+.(*+3
list.append("Clash");
list.append("Ramones");
b(#4+*-)5",#(:*#'.("9*+)",#*$#)("+.(*+,#$*+#(+.-"+,)&9#(!"#)("1,#,(*+"5#)&#.#'*&(.)&"+K#c.-.F,(0/"
QLinkedList<QString>::iterator i = list.find("Ramones");
list.insert(i, "Tote Hosen"); )("+.(*+,#.&5#B EF,(0/"#)("+.(*+,3# !"#c.-.F,(0/"#)("+.(*+,#.+"#".,)"+#(*#%,"8#:!"+".,#(!"#B EF,(0/"
)("+.(*+,#'.&#7"#'*17)&"5#:)(!#b(2,#.&5#B E2,#9"&"+)'#./9*+)(!1,#.&5#.+"#1*+"#4*:"+$%/3

6*+#".'!#'*&(.)&"+#'/.,,8#(!"+"#.+"#(:*#c.-.F,(0/"#)("+.(*+#(04",K#.#+".5F*&/0#)("+.(*+#.&5#.#+".5F
>"#:)//#(.<"#.#1*+"#5"(.)/"5#/**<#.(#)("+.(*+,#/.("+#)&#(!),#,"'()*&3
:+)("#)("+.(*+3# !"#+".5F*&/0#)("+.(*+#'/.,,",#.+" QVectorIterator<T>8 QLinkedListIterator<T>8#.&5
QListIterator<T>3# !"#'*++",4*&5)&9#+".5F:+)("#)("+.(*+,#!.-" Mutable#)&#(!")+#&.1"#?$*+#"=.14/"8 QMutableListIterator<double> i(list);
QMutableVectorIterator<T>@3#;&#(!),#5),'%,,)*&8#:"#:)//#'*&'"&(+.("#*& QList2,#)("+.(*+,C#(!"#)("+.(*+,
while (i.hasNext()) {
if (i.next() < 0.0)
$*+#/)&<"5#/),(,#.&5#-"'(*+,#!.-"#(!"#,.1"#GM;3
i.remove();
}
!"#$%&'')6)&D02!7&14/!.!45/&C4$&E0B0F/.G2%&!.%$0.4$/

!" remove()#$%&'()*&#./:.0,#*4"+.(",#*&#(!"#/.,(#)("1#(!.(#:.,#H%14"5#*-"+3#;(#./,*#:*+<,#:!"&
)("+.()&9#7.'<:.+5K

QMutableListIterator<double> i(list);
i.toBack();
while (i.hasPrevious()) {
!"#$)+,(#(!)&9#(*#<""4#)&#1)&5#:!"&#%,)&9#c.-.F,(0/"#)("+.(*+,#),#(!.(#(!"0#5*&2(#4*)&(#5)+"'(/0#.( if (i.previous() < 0.0)
)("1,3#;&,(".58#(!"0#'.&#7"#/*'.("5#7"$*+"#(!"#$)+,(#)("18#.$("+#(!"#/.,(#)("18#*+#7"(:""&#(:*#)("1,3 i.remove();
G#(04)'./#)("+.()*&#/**4#/**<,#/)<"#(!),K }

QList<double> list; B)1)/.+/08#(!"#1%(.7/"#c.-.F,(0/"#)("+.(*+,#4+*-)5"#. setValue()#$%&'()*&#(!.(#1*5)$)",#(!"#/.,(#)("1


... QListIterator<double> i(list); (!.(#:.,#H%14"5#*-"+3#J"+"2,#!*:#:"#:*%/5#+"4/.'"#&"9.()-"#&%17"+,#:)(!#(!")+#.7,*/%("#-./%"K
while (i.hasNext()) {
do_something(i.next());
}
QMutableListIterator<double> i(list);
while (i.hasNext()) {
int val = i.next();
!"#)("+.(*+#),#)&)()./)A"5#:)(!#(!"#'*&(.)&"+#(*#(+.-"+,"3#G(#(!),#4*)&(8#(!"#)("+.(*+#),#/*'.("5#H%,( if (val < 0.0)
7"$*+"#(!"#$)+,(#)("13# !"#'.//#(* hasNext()#+"(%+&, true#)$#(!"+"#),#.&#)("1#(*#(!"#+)9!(#*$#(!"#)("+.(*+3 i.setValue(-val);
!" next()#$%&'()*&#+"(%+&,#(!"#)("1#(*#(!"#+)9!(#*$#(!"#)("+.(*+#.&5#.5-.&'",#(!"#)("+.(*+#(*#(!"#&"=( }
-./)5#4*,)()*&3

;("+.()&9#7.'<:.+5#),#,)1)/.+8#"='"4(#(!.(#:"#1%,(#$)+,(#'.// toBack()#(*#4*,)()*&#(!"#)("+.(*+#.$("+#(!" ;(#),#./,*#4*,,)7/"#(*#)&,"+(#.&#)("1#.(#(!"#'%++"&(#)("+.(*+#4*,)()*&#70#'.//)&9 insert()3# !"#)("+.(*+#),


/.,(#)("1K (!"&#.5-.&'"5#(*#4*)&(#7"(:""&#(!"#&":#)("1#.&5#(!"#$*//*:)&9#)("13

;&#.55)()*&#(*#(!"#c.-.F,(0/"#)("+.(*+,8#"-"+0 ,"D%"&()./#'*&(.)&"+#'/.,, C<T>#!.,#(:*#B EF,(0/"


QListIterator<double> i(list); )("+.(*+#(04",K C<T>::iterator#.&5 C<T>::const_iterator3# !"#5)$$"+"&'"#7"(:""&#(!"#(:*#),#(!.(
i.toBack(); const_iterator#5*",&2(#/"(#%,#1*5)$0#(!"#5.(.3
while (i.hasPrevious()) {
do_something(i.previous());
} G#'*&(.)&"+2, begin()#$%&'()*&#+"(%+&,#.&#B EF,(0/"#)("+.(*+#(!.(#+"$"+,#(*#(!"#$)+,(#)("1#)&#(!"
'*&(.)&"+#?$*+#"=.14/"8 list[0]@8#:!"+"., end()#+"(%+&,#.&#)("+.(*+#(*#(!"#V*&"#4.,(#(!"#/.,(V#)("1
?$*+#"=.14/"8 list[5]#$*+#.#/),(#*$#,)A"#g@3#;$#.#'*&(.)&"+#),#"14(08 begin()#"D%./, end()3# !),#'.&#7"
%,"5#(*#,""#)$#(!"#'*&(.)&"+#!.,#.&0#)("1,8#./(!*%9!#)(#),#%,%.//0#1*+"#'*&-"&)"&(#(*#'.// isEmpty()
!" hasPrevious()#$%&'()*&#+"(%+&, true#)$#(!"+"#),#.&#)("1#(*#(!"#/"$(#*$#(!"#)("+.(*+C previous()
$*+#(!),#4%+4*,"3
+"(%+&,#(!"#)("1#(*#(!"#/"$(#*$#(!"#)("+.(*+#.&5#1*-",#(!"#)("+.(*+#7.'<#70#*&"#4*,)()*&3#G&*(!"+#:.0
*$#(!)&<)&9#.7*%(#(!" next()#.&5 previous()#)("+.(*+,#),#(!.(#(!"0#+"(%+&#(!"#)("1#(!.(#(!"#)("+.(*+
!.,#H%,(#H%14"5#*-"+3 !"#$%&'')>)&D02!7&14/!.!45/&C4$&H+IF/.G2%&!.%$0.4$/

!"#$%&''):)&@CC%3.&4C previous()&057 next()&45&0&E0B0F/.G2%&!.%$0.4$

!"#B EF,(0/"#)("+.(*+#,0&(.=#),#1*5"/"5#.$("+#(!.(#*$#IRR#4*)&("+,#)&(*#.&#.++.03#>"#'.&#%,"#(!" ++
.&5 --#*4"+.(*+,#(*#1*-"#(*#(!"#&"=(#*+#4+"-)*%,#)("18#.&5#(!"#%&.+0 *#*4"+.(*+#(*#+"(+)"-"#(!"
'%++"&(#)("13#6*+ QVector<T>8#(!" iterator#.&5 const_iterator#(04",#.+"#1"+"/0#(04"5"$,#$*+ T *#.&5
a%(.7/"#)("+.(*+,#4+*-)5"#$%&'()*&,#(*#)&,"+(8#1*5)$08#.&5#+"1*-"#)("1,#:!)/"#)("+.()&93# !"#$*//*:)&9 const T *3#? !),#),#4*,,)7/"#7"'.%," QVector<T>#,(*+",#)(,#)("1,#)&#'*&,"'%()-"#1"1*+0#/*'.()*&,3@
/**4#+"1*-",#.//#(!"#&"9.()-"#&%17"+,#$+*1#.#/),(K
!"#$*//*:)&9#"=.14/"#+"4/.'",#".'!#-./%"#)&#. QList<double>#:)(!#)(,#.7,*/%("#-./%"K
{
QList<double>::iterator i = list.begin(); QVector<double> vect(360);
while (i != list.end()) { for (int i = 0; i < 360; ++i)
*i = qAbs(*i); vect[i] = sin(i / (2 * M_PI));
++i; return vect;
} }

G#$":#b(#$%&'()*&,#+"(%+&#.#'*&(.)&"+3#;$#:"#:.&(#(*#)("+.("#*-"+#(!"#+"(%+&#-./%"#*$#.#$%&'()*&#%,)&9 !"#'.//#(*#(!"#$%&'()*&#/**<,#/)<"#(!),K
.&#B EF,(0/"#)("+.(*+8#:"#1%,(#(.<"#.#'*40#*$#(!"#'*&(.)&"+#.&5#)("+.("#*-"+#(!"#'*403#6*+#"=.14/"8
(!"#$*//*:)&9#'*5"#),#(!"#'*++"'(#:.0#(*#)("+.("#*-"+#(!" QList<int>#+"(%+&"5#70 QSplitter::sizes()K
QVector<double> table = sineTable();

QList<int> list = splitter->sizes();


QList<int>::const_iterator i = list.begin(); B E8#)&#'*14.+),*&8#"&'*%+.9",#%,#(*#4.,,#(!"#-"'(*+#.,#.#&*&F'*&,(#+"$"+"&'"#(*#.-*)5#(!"#'*40
while (i != list.end()) {
(!.(#(.<",#4/.'"#:!"&#(!"#$%&'()*&2,#+"(%+&#-./%"#),#,(*+"5#)&#.#-.+).7/"K
do_something(*i);
++i;
}
using namespace std;
void sineTable(vector<double> &vect)
{
!"#$*//*:)&9 '*5"#),#:+*&9K vect.resize(360);
for (int i = 0; i < 360; ++i)
vect[i] = sin(i / (2 * M_PI));
// WRONG QList<int>::const_iterator i = splitter->sizes().begin(); }
while (i != splitter->sizes().end()) {
do_something(*i);
++i;
!"#'.//#(!"&#7"'*1",#1*+"#("5)*%,#(*#:+)("#.&5#/",,#'/".+#(*#+".5K
}

vector<double> table;
!),#),#7"'.%," QSplitter::sizes()#+"(%+&,#.#&": QList<int>#70#-./%"#"-"+0#()1"#)(#),#'.//"53#;$#:" sineTable(table);
5*&2(#,(*+"#(!"#+"(%+&#-./%"8#IRR#.%(*1.()'.//0#5",(+*0,#)(#7"$*+"#:"#!.-"#"-"&#,(.+("5#)("+.()&98
/".-)&9#%,#:)(!#.#5.&9/)&9#)("+.(*+3# *#1.<"#1.(("+,#:*+,"8#".'!#()1"#(!"#/**4#),#+%&8
QSplitter::sizes()#1%,(#9"&"+.("#.#&":#'*40#*$#(!"#/),(#7"'.%,"#*$#(!" splitter->sizes().end() b(#%,",#)14/)')(#,!.+)&9#$*+#.//#*$#)(,#'*&(.)&"+,#.&5#$*+#1.&0#*(!"+#'/.,,",8#)&'/%5)&9 QByteArray8
'.//3#;&#,%11.+0K#>!"&#%,)&9#B EF,(0/"#)("+.(*+,8#./:.0,#)("+.("#*&#.#'*40#*$#.#'*&(.)&"+#+"(%+&"5 QBrush8 QFont8 QImage8 QPixmap8#.&5 QString3# !),#1.<",#(!","#'/.,,",#-"+0#"$$)')"&(#(*#4.,,#70
70#-./%"3 -./%"8#7*(!#.,#$%&'()*&#4.+.1"("+,#.&5#.,#+"(%+&#-./%",3

>)(!#+".5F*&/0#c.-.F,(0/"#)("+.(*+,8#:"#5*&2(#&""5#(*#(.<"#.#'*403# !"#)("+.(*+#(.<",#.#'*40#$*+#%, ;14/)')(#,!.+)&9#),#.#9%.+.&(""#$+*1#b(#(!.(#(!"#5.(.#:*&2(#7"#'*4)"5#)$#:"#5*&2(#1*5)$0#)(3# *#9"(


7"!)&5#(!"#,'"&",8#"&,%+)&9#(!.(#:"#./:.0,#)("+.("#*-"+#(!"#5.(.#(!.(#(!"#$%&'()*&#$)+,(#+"(%+&"53#6*+ (!"#7",(#*%(#*$#)14/)')(#,!.+)&98#:"#'.&#.5*4(#.#'*%4/"#*$#&":#4+*9+.11)&9#!.7)(,3#]&"#!.7)(#),#(*
"=.14/"K
%,"#(!" at()#$%&'()*&#+.(!"+#(!.&#(!" []#*4"+.(*+#$*+#+".5F*&/0#.''",,#*&#.#?&*&F'*&,(@#-"'(*+#*+
/),(3#B)&'"#b(2,#'*&(.)&"+,#'.&&*(#("//#:!"(!"+ []#.44".+,#*&#(!"#/"$(#,)5"#*$#.&#.,,)9&1"&(#*+#&*(8#)(
.,,%1",#(!"#:*+,(#.&5#$*+'",#.#5""4#'*40#(*#*''%+:!"+"., at()#),&2(#.//*:"5#*&#(!"#/"$(#,)5"#*$#.&
QListIterator<int> i(splitter->sizes());
while (i.hasNext()) { .,,)9&1"&(3
do_something(i.next());
} G#,)1)/.+#),,%"#.+),",#:!"&#:"#)("+.("#*-"+#.#'*&(.)&"+#:)(!#B EF,(0/"#)("+.(*+,3#>!"&"-"+#:"#'.//
begin()#*+ end()#*&#.#&*&F'*&,(#'*&(.)&"+8#b(#$*+'",#.#5""4#'*40#(*#*''%+#)$#(!"#5.(.#),#,!.+"53# *
4+"-"&(#(!),#)&"$$)')"&'08#(!"#,*/%()*&#),#(* %," const_iterator8 constBegin()8#.&5 constEnd()
I*40)&9#.#'*&(.)&"+#/)<"#(!),#,*%&5,#"=4"&,)-"8#7%(#)(#),&2(8#(!.&<,#(*#.&#*4()1)A.()*&#'.//"5 *)23*0*- :!"&"-"+#4*,,)7/"3
/'45*+63# !),#1".&,#(!.(#'*40)&9#.#b(#'*&(.)&"+#),#.7*%(#.,#$.,(#.,#'*40)&9#.#,)&9/"#4*)&("+3#]&/0#)$
*&"#*$#(!"#'*4)",#),#'!.&9"5#),#5.(.#.'(%.//0#'*4)"5.&5#(!),#),#.//#!.&5/"5#.%(*1.()'.//0#7"!)&5#(!" b(#4+*-)5",#*&"#/.,(#1"(!*5#$*+#)("+.()&9#*-"+#)("1,#)&#.#,"D%"&()./#'*&(.)&"+K#(!" foreach#/**43#;(
,'"&",3#6*+#(!),#+".,*&8#)14/)')(#,!.+)&9#),#,*1"()1",#'.//"5#V'*40#*&#:+)("V3 /**<,#/)<"#(!),K

!"#7".%(0#*$#)14/)')(#,!.+)&9#),#(!.(#)(#),#.&#*4()1)A.()*&#(!.(#:"#5*&2(#&""5#(*#(!)&<#.7*%(C#)(
,)14/0#:*+<,8#:)(!*%(#+"D%)+)&9#.&0#4+*9+.11"+#)&("+-"&()*&3#G(#(!"#,.1"#()1"8#)14/)')(#,!.+)&9 QLinkedList<Movie> list;
"&'*%+.9",#.#'/".&#4+*9+.11)&9#,(0/"#:!"+"#*7H"'(,#.+"#+"(%+&"5#70#-./%"3#I*&,)5"+#(!"#$*//*:)&9 ...
foreach (Movie movie, list) {
$%&'()*&K
if (movie.title() == "Citizen Kane") {
cout << "Found Citizen Kane" << endl;
break;
QVector<double> sineTable() }
}
QSharedDataPointer#'/.,,",3

!" foreach#4,"%5*F<"0:*+5#),#)14/"1"&("5#)&#("+1,#*$#(!"#,(.&5.+5 for#/**43#G(#".'!#)("+.()*&#*$


(!"#/**48#(!"#)("+.()*&#-.+).7/"#?movie@#),#,"(#(*#.#&":#)("18#,(.+()&9#.(#(!"#$)+,(#)("1#)&#(!"#'*&(.)&"+ !" break#.&5 continue#/**4#,(.("1"&(,#.+"#,%44*+("53 ;$#(!"#7*50#'*&,),(,#*$#.#,)&9/"#,(.("1"&(8
.&5#4+*9+",,)&9#$*+:.+53# !" foreach#/**4#.%(*1.()'.//0#(.<",#.#'*40#*$#(!"#'*&(.)&"+#:!"&#(!" (!"#7+.'",#.+"#%&&"'",,.+03#c%,(#/)<"#. for#,(.("1"&(8#(!"#)("+.()*&#-.+).7/"#'.&#7"#5"$)&"5#*%(,)5"
/**4#),#"&("+"58#.&5#$*+#(!),#+".,*&#(!"#/**4#),#&*(#.$$"'("5#)$#(!"#'*&(.)&"+#),#1*5)$)"5#5%+)&9 (!"#/**48#/)<"#(!),K
)("+.()*&3

QLinkedList<Movie> list;
Movie movie;
How Implicit Sharing Works ...
foreach (movie, list) {
;14/)')(#,!.+)&9#:*+<,#.%(*1.()'.//0#7"!)&5#(!"#,'"&",8#,*#:"#5*&2(#!.-"#(*#5*#.&0(!)&9 if (movie.title() == "Citizen Kane") {
)&#*%+#'*5"#(*#1.<"#(!),#*4()1)A.()*&#!.44"&3#[%(#,)&'"#)(2,#&)'"#(*#<&*:#!*:#(!)&9, cout << "Found Citizen Kane" << endl;
:*+<8#:"#:)//#,(%50#.&#"=.14/"#.&5#,""#:!.(#!.44"&,#%&5"+#(!"#!**53# !"#"=.14/" break;
%,", QString8#*&"#*$#b(2,#1.&0#)14/)')(/0#,!.+"5#'/.,,",3 }
}

QString str1 = "Humpty";


QString str2 = str1; `"$)&)&9#(!"#)("+.()*&#-.+).7/"#*%(,)5"#(!"#/**4#),#(!"#*&/0#*4()*&#$*+#'*&(.)&"+,#(!.(#!*/5#5.(.#(04",
(!.(#'*&(.)&#.#'*11.#?$*+#"=.14/"8 QPair<QString,int>@3

>"#,"( str1#(*#VJ%14(0V#.&5 str2#(*#7"#"D%./#(* str13#G(#(!),#4*)&(8#7*(! QString


*7H"'(,#4*)&(#(*#(!"#,.1"#)&("+&./#5.(.#,(+%'(%+"#)&#1"1*+03#G/*&9#:)(!#(!"#'!.+.'("+
Associative Containers
5.(.8#(!"#5.(.#,(+%'(%+"#!*/5,#.#+"$"+"&'"#'*%&(#(!.(#)&5)'.(",#!*:#1.&0 QString,#4*)&(
(*#(!"#,.1"#5.(.#,(+%'(%+"3#B)&'"#7*(! str1#.&5 str2#4*)&(#(*#(!"#,.1"#5.(.8#(!" G&#.,,*').()-"#'*&(.)&"+#!*/5,#.&#.+7)(+.+0#&%17"+#*$#)("1,#*$#(!"#,.1"#(04"8#)&5"="5#70#.#<"03#b(
+"$"+"&'"#'*%&(#),#Q3 4+*-)5",#(:*#1.)&#.,,*').()-"#'*&(.)&"+#'/.,,",K QMap<K, T>#.&5 QHash<K, T>3

G QMap<K, T>#),#.#5.(.#,(+%'(%+"#(!.(#,(*+",#<"0-./%"#4.)+,#)&#.,'"&5)&9#<"0#*+5"+3# !),#.++.&9"1"&(


str2[0] = 'D'; 1.<",#)(#4*,,)7/"#(*#4+*-)5"#9**5#/**<%4#.&5#)&,"+()*&#4"+$*+1.&'"8#.&5#)&F*+5"+#)("+.()*&3
;&("+&.//08 QMap<K, T>#),#)14/"1"&("5#.,#.#,<)4F/),(3

>!"&#:"#1*5)$0 str28#)(#$)+,(#1.<",#.#5""4#'*40#*$#(!"#5.(.8#(*#"&,%+"#(!.( str1#.&5 !"#$%&'')J)&A&901&4C QString&.4 int


str2#4*)&(#(*#5)$$"+"&(#5.(.#,(+%'(%+",8#.&5#)(#(!"&#.44/)",#(!"#'!.&9"#(*#)(,#*:&#'*40#*$
(!"#5.(.3# !"#+"$"+"&'"#'*%&(#*$ str12,#5.(.#?VJ%14(0V@#7"'*1",#O8#.&5#(!"#+"$"+"&'"
'*%&(#*$ str22,#5.(.#?V`%14(0V@#),#,"(#(*#O3#G#+"$"+"&'"#'*%&(#*$#O#1".&,#(!.(#(!"#5.(.
),&2(#,!.+"53

str2.truncate(4);

;$#:"#1*5)$0 str2#.9.)&8#&*#'*40)&9#(.<",#4/.'"#7"'.%,"#(!"#+"$"+"&'"#'*%&(#*$ str22,


5.(.#),#O3# !" TRuncate()#$%&'()*&#*4"+.(",#5)+"'(/0#*& str22,#5.(.8#+",%/()&9#)&#(!"#,(+)&9
V`%14V3# !"#+"$"+"&'"#'*%&(#,(.0,#.(#O3
]&"#,)14/"#:.0#(*#)&,"+(#)("1,#)&(*#.#1.4#),#(*#'.// insert()K

str1 = str2;
QMap<QString, int> map;
map.insert("eins", 1);
>!"&#:"#.,,)9& str2#(* str18#(!"#+"$"+"&'"#'*%&(#$*+ str12,#5.(.#9*",#5*:&#(*#L8#:!)'! map.insert("sieben", 7);
1".&,#(!.(#&* QString#),#%,)&9#(!"#VJ%14(0V#5.(.#.&01*+"3# !"#5.(.#), (!"&#$+""5#$+*1 map.insert("dreiundzwanzig", 23);
1"1*+03#[*(! QString,#4*)&(#(*#V`%14V8#:!)'!#&*:#!.,#.#+"$"+"&'"#'*%&(#*$#Q3

`.(.#,!.+)&9#),#*$("&#5),+"9.+5"5#.,#.&#*4()*&#)&#1%/()(!+".5"5#4+*9+.1,8#7"'.%,"#*$ G/("+&.()-"/08#:"#'.&#,)14/0#.,,)9&#.#-./%"#(*#.#9)-"&#<"0#.,#$*//*:,K
+.'"#'*&5)()*&,#)&#(!"#+"$"+"&'"#'*%&()&93#>)(!#b(8#(!),#),#&*(#.&#),,%"3#;&("+&.//08#(!"
'*&(.)&"+#'/.,,",#%,"#.,,"17/0#/.&9%.9"#)&,(+%'()*&,#(*#4"+$*+1#.(*1)'#+"$"+"&'"
'*%&()&93# !),#("'!&*/*90#),#.-.)/.7/"#(*#b(#%,"+,#(!+*%9!#(!" QSharedData#.&5 map["eins"] = 1;
map["sieben"] = 7;
map["dreiundzwanzig"] = 23; (04",8 QChar8 QString8#.&5 QByteArray3

QHash<K, T>#.%(*1.()'.//0#.//*'.(",#.#4+)1"#&%17"+#*$#7%'<"(,#$*+#)(,#)&("+&./#!.,!#(.7/"#.&5#+",)A",
!" []#*4"+.(*+#'.&#7"#%,"5#$*+#7*(!#)&,"+()*&#.&5#+"(+)"-./3#;$ []#),#%,"5#(*#+"(+)"-"#.#-./%"#$*+#. (!),#.,#)("1,#.+"#)&,"+("5#*+#+"1*-"53#;(#),#./,*#4*,,)7/"#(*#$)&"F(%&"#4"+$*+1.&'"#70#'.//)&9
&*&F"=),("&(#<"0#)&#.#&*&F'*&,(#1.48#.#&":#)("1#:)//#7"#'+".("5#:)(!#(!"#9)-"&#<"0#.&5#.&#"14(0 reserve()#(*#,4"')$0#(!"#&%17"+#*$#)("1,#"=4"'("5#(*#7"#,(*+"5#)&#(!"#!.,!#.&5 squeeze()#(*#,!+)&<
-./%"3# *#.-*)5#.'')5"&(.//0#'+".()&9#"14(0#-./%",8#:"#'.&#%,"#(!" value()#$%&'()*&#(*#+"(+)"-"#)("1, (!"#!.,!#(.7/"#7.,"5#*&#(!"#'%++"&(#&%17"+#*$#)("1,3#G#'*11*&#)5)*1#),#(*#'.// reserve()#:)(!#(!"
)&,(".5#*$ []K 1.=)1%1#&%17"+#*$#)("1,#:"#"=4"'(8#(!"&#)&,"+(#(!"#5.(.8#.&5#$)&.//0#'.// squeeze()#(*#1)&)1)A"
1"1*+0#%,.9"#)$#(!"+"#:"+"#$":"+#)("1,#(!.&#"=4"'("53

int val = map.value("dreiundzwanzig"); J.,!",#.+"#&*+1.//0#,)&9/"F-./%"58#7%(#1%/()4/"#-./%",#'.&#7"#.,,)9&"5#(*#(!"#,.1"#<"0#%,)&9#(!"


insertMulti()#$%&'()*&#*+#(!" QMultiHash<K, T>#'*&-"&)"&'"#,%7'/.,,3

;$#(!"#<"0#5*",&2(#"=),(8#.#5"$.%/(#-./%"#),#+"(%+&"5#%,)&9#(!" -./%"#(04"2,#5"$.%/(#'*&,(+%'(*+8#.&5 [",)5", QHash<K, T>8#b(#./,*#4+*-)5",#. QCache<K, T>#'/.,,#(!.(#'.&#7"#%,"5#(*#'.'!"#*7H"'(,


&*#&":#)("1#),#'+".("53#6*+#7.,)'#.&5#4*)&("+#(04",8#A"+*#),#+"(%+&"53#>"#'.&#,4"')$0#.&*(!"+#5"$.%/( .,,*').("5#:)(!#.#<"08#.&5#. QSet<K>#'*&(.)&"+#(!.(#*&/0#,(*+",#<"0,3#;&("+&.//08#7*(!#+"/0#*&
-./%"#.,#,"'*&5#.+9%1"&(#(* value()8#$*+#"=.14/"K QHash<K, T>#.&5#7*(!#!.-"#(!"#,.1"#+"D%)+"1"&(,#$*+#(!" K#(04"#., QHash<K, T>3

!"#".,)",(#:.0#(*#)("+.("#(!+*%9!#.//#(!"#<"0-./%"#4.)+,#,(*+"5#)&#.&#.,,*').()-"#'*&(.)&"+#),#(*#%,"
int seconds = map.value("delay", 30); .#c.-.F,(0/"#)("+.(*+3#["'.%,"#(!"#)("+.(*+,#1%,(#9)-"#.''",,#(*#7*(!#.#<"0#.&5#.#-./%"8#(!"#c.-.F
,(0/"#)("+.(*+,#$*+#.,,*').()-"#'*&(.)&"+,#:*+<#,/)9!(/0#5)$$"+"&(/0#$+*1#(!")+#,"D%"&()./#'*%&("+4.+(,3
!"#1.)&#5)$$"+"&'"#),#(!.(#(!" next()#.&5 previous()#$%&'()*&,#+"(%+&#.&#*7H"'(#(!.(#+"4+","&(,#.
!),#),#"D%)-./"&(#(* <"0-./%"#4.)+8#+.(!"+#(!.&#,)14/0#.#-./%"3# !"#<"0#.&5#-./%"#'*14*&"&(,#.+"#.''",,)7/"#$+*1#(!),
*7H"'(#., key()#.&5 value()3#6*+#"=.14/"K

int seconds = 30;


if (map.contains("delay")) QMap<QString, int> map;
seconds = map.value("delay"); ...
int sum = 0;
QMapIterator<QString, int> i(map);
!" K#.&5 T#5.(.#(04",#*$#. QMap<K, T>#'.&#7"#7.,)'#5.(.#(04",#/)<" int#.&5 double8#4*)&("+#(04",8#*+ while (i.hasNext())
sum += i.next().value();
'/.,,",#(!.(#!.-"#.#5"$.%/(#'*&,(+%'(*+8#.#'*40#'*&,(+%'(*+8#.&5#.&#.,,)9&1"&(#*4"+.(*+3#;&#.55)()*&8
(!" K#(04"#1%,(#4+*-)5"#.& operator<()#,)&'" QMap<K, T>#%,",#(!),#*4"+.(*+#(*#,(*+"#(!"#)("1,#)&
.,'"&5)&9#<"0#*+5"+3
;$#:"#&""5#(*#.''",,#7*(!#(!"#<"0#.&5#(!"#-./%"8#:"#'.&#,)14/0#)9&*+"#(!"#+"(%+&#-./%"#*$ next()#*+
QMap<K, T>#!.,#.#'*%4/"#*$#'*&-"&)"&'"#$%&'()*&,8 keys()#.&5 values()8#(!.(#.+"#",4"').//0#%,"$%/ previous()#.&5#%,"#(!"#)("+.(*+2, key()#.&5 value()#$%&'()*&,8#:!)'!#*4"+.("#*&#(!"#/.,(#)("1#(!.(
:!"&#5"./)&9#:)(!#,1.//#5.(.#,"(,3# !"0#+"(%+& QList,#*$#.#1.42,#<"0,#.&5#-./%",3 :.,#H%14"5#*-"+K

a.4,#.+"#&*+1.//0#,)&9/"F-./%"5K#;$#.#&":#-./%"#),#.,,)9&"5#(*#.&#"=),()&9#<"08#(!"#*/5#-./%"#),
QMapIterator<QString, int> i(map);
+"4/.'"5#70#(!"#&":#-./%"8#"&,%+)&9#(!.(#&*#(:*#)("1,#,!.+"#(!"#,.1"#<"03#;(#),#4*,,)7/"#(* !.-"
while (i.hasNext()) {
1%/()4/"#<"0-./%"#4.)+,#:)(!#(!"#,.1"#<"0#70#%,)&9#(!" insertMulti()#$%&'()*&#*+#(!" QMultiMap<K, i.next();
T>#'*&-"&)"&'"#,%7'/.,,3 QMap<K, T>#!.,#. values(const K &)#*-"+/*.5#(!.(#+"(%+&,#. QList#*$#.//#(!" if (i.value() > largestValue) {
-./%",#$*+#.#9)-"&#<"03#6*+#"=.14/"K largestKey = i.key();
largestValue = i.value();
}
QMultiMap<int, QString> multiMap; }
multiMap.insert(1, "one");
multiMap.insert(1, "eins");
multiMap.insert(1, "uno");
a%(.7/"#)("+.(*+,#!.-"#. setValue()#$%&'()*&#(!.(#1*5)$)",#(!"#-./%"#.,,*').("5#:)(!#(!"#'%++"&(
QList<QString> vals = multiMap.values(1);
)("1K

G QHash<K, T>#),#.#5.(.#,(+%'(%+"#(!.(#,(*+",#<"0-./%"#4.)+,#)&#.#!.,!#(.7/"3#;(,#)&("+$.'"#),#./1*,( QMutableMapIterator<QString, int> i(map);


)5"&()'./#(*#(!.(#*$ QMap<K, T>8#7%(#)(#!.,#5)$$"+"&(#+"D%)+"1"&(,#$*+#(!" K#("14/.("#(04"#.&5#%,%.//0 while (i.hasNext()) {
4+*-)5",#1%'!#$.,("+#/**<%4,#(!.& QMap<K, T>#'.&#.'!)"-"3#G&*(!"+#5)$$"+"&'"#),#(!.( QHash<K, T>#), i.next();
%&*+5"+"53 if (i.value() < 0.0)
i.setValue(-i.value());
}
;&#.55)()*&#(*#(!"#,(.&5.+5#+"D%)+"1"&(,#*&#.&0#-./%"#(04"#,(*+"5#)&#.#'*&(.)&"+8#(!" K#(04"#*$#.
QHash<K, T>#&""5,#(*#4+*-)5"#.& operator==()#.&5#7"#,%44*+("5#70#.#9/*7./ qHash()#$%&'()*&#(!.(
+"(%+&,#.#!.,!#-./%"#$*+#.#<"03#b(#./+".50#4+*-)5", qHash()#$%&'()*&,#$*+#)&("9"+#(04",8#4*)&("+
B EF,(0/"#)("+.(*+,#./,*#4+*-)5" key()#.&5 value()#$%&'()*&,3#>)(!#(!"#&*&'*&,(#)("+.(*+#(04",8
value()#+"(%+&,#.#&*&F'*&,(#+"$"+"&'"8#.//*:)&9#%,#(*#'!.&9"#(!"#-./%"#.,#:"#)("+.("3#\*("#(!.(
./(!*%9!#(!","#)("+.(*+,#.+"#'.//"5#VB EF,(0/"V8#(!"0#5"-).("#,)9&)$)'.&(/0#$+*1#(!"#B E2, map<K, T>
)("+.(*+,8#:!)'!#.+"#7.,"5#*& pair<K, T>3 !" qCopy()#./9*+)(!1#'*4)",#-./%",#$+*1#*&"#'*&(.)&"+#(*#.&*(!"+K

!" foreach#/**4#./,*#:*+<,#*&#.,,*').()-"#'*&(.)&"+,8#7%(#*&/0#*&#(!"#-./%"#'*14*&"&(#*$#(!"
<"0-./%"#4.)+,3#;$#:"#&""5#7*(!#(!"#<"0#.&5#(!"#-./%"#'*14*&"&(,#*$#(!"#)("1,8#:"#'.&#'.//#(!" QVector<int> vect(list.count());
keys()#.&5 values(const K &)#$%&'()*&,#)&#&",("5 foreach#/**4,#.,#$*//*:,K qCopy(list.begin(), list.end(), vect.begin());

QMultiMap<QString, int> map; qCopy()#'.&#./,*#7"#%,"5#(*#'*40#-./%",#:)(!)&#(!"#,.1"#'*&(.)&"+8#.,#/*&9#.,#(!"#,*%+'"#+.&9"#.&5


... (!"#(.+9"(#+.&9"#5*&2(#*-"+/.43#;&#(!"#&"=(#'*5"#,&)44"(8#:"#%,"#)(#(*#*-"+:+)("#(!"#/.,(#(:*#)("1,#*$
foreach (QString key, map.keys()) { .#/),(#:)(!#(!"#$)+,(#(:*#)("1,K
foreach (int value, map.values(key)) {
do_something(key, value);
}
qCopy(list.begin(), list.begin() + 2, list.end() - 2);
}

Generic Algorithms !" qSort()#./9*+)(!1#,*+(,#(!"#'*&(.)&"+2,#)("1,#)&(*#.,'"&5)&9#*+5"+K

!" <QtAlgorithms>#!".5"+#5"'/.+",#.#,"(#*$#9/*7./#("14/.("#$%&'()*&,#(!.(#)14/"1"&(#7.,)'
./9*+)(!1,#*&#'*&(.)&"+,3#a*,(#*$#(!","#$%&'()*&,#*4"+.("#*&#B EF,(0/"#)("+.(*+,3 qSort(list.begin(), list.end());

!"#B E <algorithm>#!".5"+#4+*-)5",#.#1*+"#'*14/"("#,"(#*$#9"&"+)'#./9*+)(!1,3# !","#./9*+)(!1,


'.&#7"#%,"5#*&#b(#'*&(.)&"+,#.,#:"//#.,#B E#'*&(.)&"+,3#;$#B E#)14/"1"&(.()*&,#.+"#.-.)/.7/"#*&#.// [0#5"$.%/(8 qSort()#%,",#(!" <#*4"+.(*+#(*#'*14.+"#(!"#)("1,3# *#,*+(#)("1,#)&#5",'"&5)&9#*+5"+8
0*%+#4/.($*+1,8#(!"+"#),#4+*7.7/0#&*#+".,*&#(*#.-*)5#%,)&9#(!"#B E#./9*+)(!1,#:!"&#b(#/.'<,#.& 4.,, qGreater<T>()#.,#(!"#(!)+5#.+9%1"&(#?:!"+" T#),#(!"#'*&(.)&"+2,#-./%"#(04"@8#.,#$*//*:,K
"D%)-./"&(#./9*+)(!13#J"+"8#:"#:)//#)&(+*5%'"#(!"#1*,(#)14*+(.&(#b(#./9*+)(!1,3

!" qFind()#./9*+)(!1#,".+'!",#$*+#.#4.+()'%/.+#-./%"#)&#.#'*&(.)&"+3#;(#(.<",#.#V7"9)&V#.&5#.&#V"&5V qSort(list.begin(), list.end(), qGreater<int>());


)("+.(*+#.&5#+"(%+&,#.&#)("+.(*+#4*)&()&9#(*#(!"#$)+,(#)("1#(!.(#1.('!",8#*+#V"&5V#)$#(!"+"#),#&*#1.('!3
;&#(!"#$*//*:)&9#"=.14/"8 i#),#,"(#(* list.begin()#R#O8#:!"+"., j#),#,"(#(* list.end()3
>"#'.&#%,"#(!"#(!)+5#4.+.1"("+#(*#5"$)&"#'%,(*1#,*+(#'+)("+).3#6*+#"=.14/"8#!"+"2,#.#V/",,#(!.&V
'*14.+),*&#$%&'()*&#(!.(#'*14.+", QString,#)&#.#'.,"F)&,"&,)()-"#:.0K
QStringList list;
list << "Emma" << "Karl" << "James" << "Mariette";
QStringList::iterator i = qFind(list.begin(), list.end(), "Karl"); bool insensitiveLessThan(const QString &str1, const QString &str2)
QStringList::iterator j = qFind(list.begin(), list.end(), "Petra"); {
return str1.toLower() < str2.toLower();
}
!" qBinaryFind()#./9*+)(!1#4"+$*+1,#.#,".+'!#H%,(#/)<" qFind()8#"='"4(#(!.(#)(#.,,%1",#(!.(#(!"
)("1,#.+"#,*+("5#)&#.,'"&5)&9#*+5"+#.&5#%,",#$.,(#7)&.+0#,".+'!)&9#+.(!"+#(!.& qFind()2,#/)&".+
,".+'!)&93 !"#'.//#(* qSort()#(!"&#7"'*1",

!" qFill()#./9*+)(!1#4*4%/.(",#.#'*&(.)&"+#:)(!#.#4.+()'%/.+#-./%"K
QStringList list;
...
QLinkedList<int> list(10); qSort(list.begin(), list.end(), insensitiveLessThan);
qFill(list.begin(), list.end(), 1009);

!" qStableSort()#./9*+)(!1#),#,)1)/.+#(* qSort()8#"='"4(#)(#9%.+.&("",#(!.(#)("1,#(!.(#'*14.+"


E)<"#(!"#*(!"+#)("+.(*+F7.,"5#./9*+)(!1,8#:"#'.&#./,*#%," qFill()#*&#.#4*+()*&#*$#(!"#'*&(.)&"+#70 "D%./#.44".+#)&#(!"#,.1"#*+5"+#.$("+#(!"#,*+(#.,#7"$*+"3# !),#),#%,"$%/#)$#(!"#,*+(#'+)("+)*&#*&/0#(.<",
-.+0)&9#(!"#.+9%1"&(,3# !"#$*//*:)&9#'*5"#,&)44"(#)&)()./)A",#(!"#$)+,(#$)-"#)("1,#*$#.#-"'(*+#(*#OLLh )&(*#.''*%&(#4.+(,#*$#(!"#-./%"#.&5#(!"#+",%/(,#.+"#-),)7/"#(*#(!"#%,"+3#>"#%,"5 qStableSort()#)&
.&5#(!"#/.,(#$)-"#)("1,#(*#QLONK I!.4("+#T#(*#)14/"1"&(#,*+()&9#)&#(!"#B4+".5,!""(#.44/)'.()*& ?43#ee@3

!" qDeleteAll()#./9*+)(!1#'.//, delete#*&#"-"+0#4*)&("+#,(*+"5#)&#.#'*&(.)&"+3#;(#*&/0#1.<",#,"&,"


QVector<int> vect(10); *&#'*&(.)&"+,#:!*,"#-./%"#(04"#),#.#4*)&("+#(04"3#G$("+#(!"#'.//8#(!"#)("1,#.+"#,()//#4+","&( clear()
qFill(vect.begin(), vect.begin() + 5, 1009); *&#(!"#'*&(.)&"+3#6*+#"=.14/"K
qFill(vect.end() - 5, vect.end(), 2013);

qDeleteAll(list);
list.clear();
!),#$%&'()*&#,%44*+(,#(!"#,.1"#$*+1.(#,4"')$)"+,#.,#(!"#IRR#/)7+.+02, sprintf()#$%&'()*&3#;&#(!"
!" qSwap()#./9*+)(!1#"='!.&9",#(!"#-./%"#*$#(:*#-.+).7/",3#6*+#"=.14/"K "=.14/"#.7*-"8 str#),#.,,)9&"5#V4"+$"'(#'*14"()()*&#OLL3LkV3

l"(#.&*(!"+#:.0#*$#7%)/5)&9#.#,(+)&9#$+*1#*(!"+#,(+)&9,#*+#$+*1#&%17"+,#),#(*#%," arg()
int x1 = line.x1();
int x2 = line.x2();
if (x1 > x2) str = QString("%1 %2 (%3s-%4s)")
qSwap(x1, x2); .arg("permissive").arg("society").arg(1950).arg(1970);

6)&.//08#(!" <QtGlobal>#!".5"+8#:!)'!#),#)&'/%5"5#70#"-"+0#*(!"+#b(#!".5"+8#4+*-)5",#,"-"+./#%,"$%/ !"#$%&'#()*+,-(.#/01/#&'#2(,-*3(4#56#/,(2+&''&7(/.#/08/#&'#2(,-*3(4#56#/'93&($6/.#/0:/#&'#2(,-*3(4


5"$)&)()*&,8#)&'/%5)&9#(!" qAbs()#$%&'()*&8#(!.(#+"(%+&,#(!"#.7,*/%("#-./%"#*$#)(,#.+9%1"&(8#.&5#(!" 56#/1;<=/.#*"4#/0>/#&'#2(,-*3(4#56#/1;?=/@#A%(#2('B-$#&'#/,(2+&''&7(#'93&($6#C1;<='D1;?='E/@#A%(2(
qMin()#.&5 qMax()#$%&'()*&,8#(!.(#+"(%+&#(!"#1)&)1%1#*+#1.=)1%1#*$#(:*#-./%",3 *2( arg()#97(2-9*4'#$9#%*"4-(#7*2&9B'#4*$*#$6,('@#F9+(#97(2-9*4'#%*7(#()$2*#,*2*+($(2'#G92
39"$29--&"H#$%(#G&(-4#I&4$%.#$%(#"B+(2&3*-#5*'(.#92#$%(#G-9*$&"HD,9&"$#,2(3&'&9"@#!"#H("(2*-. arg()#&'#*
+B3%#5($$(2#'9-B$&9"#$%*" sprintf().#5(3*B'(#&$#&'#$6,(D'*G(.#GB--6#'B,,92$'#J"&394(.#*"4#*--9I'
$2*"'-*$92'#$9#2(924(2#$%(#/0 /#,*2*+($(2'@
Strings, Byte Arrays, and Variants
QString#3*"#39"7(2$#"B+5(2'#&"$9#'$2&"H'#B'&"H#$%( QString::number()#'$*$&3#GB"3$&9"
QString8 QByteArray8#.&5 QVariant#.+"#(!+""#'/.,,",#(!.(#!.-"#1.&0#(!)&9,#)&#'*11*&#:)(!
'*&(.)&"+,#.&5#(!.(#'.&#7"#%,"5#.,#./("+&.()-",#(*#'*&(.)&"+,#)&#,*1"#'*&("=(,3#G/,*8#/)<"#(!"
'*&(.)&"+,8#(!","#'/.,,",#%,"#)14/)')(#,!.+)&9#.,#.#1"1*+0#.&5#,4""5#*4()1)A.()*&3 str = QString::number(59.6);

>"#:)//#,(.+(#:)(! QString3#B(+)&9,#.+"#%,"5#70#"-"+0#^_;#4+*9+.18#&*(#*&/0#$*+#(!"#%,"+#)&("+$.'"
7%(#*$("&#./,*#.,#5.(.#,(+%'(%+",3#IRR#&.()-"/0#4+*-)5",#(:*#<)&5,#*$#,(+)&9,K#(+.5)()*&./#IF,(0/"#2iL2F K2#B'&"H#$%( setNum()#GB"3$&9"
("+1)&.("5#'!.+.'("+#.++.0,#.&5#(!" std::string#'/.,,3#_&/)<"#(!","8 QString#!*/5,#OdF7)(#_&)'*5"
-./%",3#_&)'*5"#'*&(.)&,#GBI;;#.&5#E.()&FO#.,#.#,%7,"(8#:)(!#(!")+#%,%./#&%1"+)'#-./%",3#[%(#,)&'"
QString#),#OdF7)(8#)(#'.&#+"4+","&(#(!*%,.&5,#*$#*(!"+#'!.+.'("+,#$*+#:+)()&9#1*,(#*$#(!"#:*+/52, str.setNum(59.6);
/.&9%.9",3#B"" I!.4("+#Oj#$*+#1*+"#)&$*+1.()*&#.7*%(#_&)'*5"3

>!"&#%,)&9 QString8#:"#5*&2(#&""5#(*#:*++0#.7*%(#,%'!#.+'.&"#5"(.)/,#.,#.//*'.()&9#"&*%9!#1"1*+0
A%(#2(7(2'(#39"7(2'&9".#G29+#*#'$2&"H#$9#*#"B+5(2.#&'#*3%&(7(4#B'&"H toInt(). toLongLong().
*+#"&,%+)&9#(!.(#(!"#5.(.#),#2iL2F("+1)&.("53#I*&'"4(%.//08 QString,#'.&#7"#(!*%9!(#*$#.,#.#-"'(*+#*$
toDouble().#*"4#'9#9"@#L92#()*+,-(
QChar,3#G QString#'.&#"17"5#2iL2#'!.+.'("+,3# !" length()#$%&'()*&#+"(%+&,#(!"#,)A"#*$#(!"#"&()+"
,(+)&98#)&'/%5)&9#"17"55"5#2iL2#'!.+.'("+,3
bool ok;
QString#4+*-)5",#.#7)&.+0 +#*4"+.(*+#(*#'*&'.("&.("#(:*#,(+)&9,#.&5#. +=#*4"+.(*+#(*#.44"&5#*&" double d = str.toDouble(&ok);
,(+)&9#(*#.&*(!"+3#["'.%," QString#.%(*1.()'.//0#4+".//*'.(",#1"1*+0#.(#(!"#"&5#*$#(!"#,(+)&9#5.(.8
7%)/5)&9#%4#.#,(+)&9#70#+"4".("5/0#.44"&5)&9#'!.+.'("+,#),#-"+0#$.,(3#J"+"2,#.&#"=.14/"#(!.(
'*17)&", +#.&5 +=K A%('(#GB"3$&9"'#*33(,$#*"#9,$&9"*-#,9&"$(2#$9#* bool#7*2&*5-(#*"4#'($#$%(#7*2&*5-(#$9 TRue#92 false
4(,("4&"H#9"#$%(#'B33(''#9G#$%(#39"7(2'&9"@#!G#$%(#39"7(2'&9"#G*&-'.#$%('(#GB"3$&9"'#2($B2"#M(29@
QString str = "User: ";
str += userName + "\n"; K"3(#I(#%*7(#*#'$2&"H.#I(#9G$("#I*"$#$9#()$2*3$#,*2$'#9G#&$@#A%( mid()#GB"3$&9"#2($B2"'#$%(#'B5'$2&"H
'$*2$&"H#*$#*#H&7("#,9'&$&9"#C$%(#G&2'$#*2HB+("$E#*"4#9G#B,#$9#*#H&7("#-("H$%#C$%(#'(39"4#*2HB+("$E@
L92#()*+,-(.#$%(#G9--9I&"H#394(#,2&"$' /,*6'/#$9#$%(#39"'9-( NOP

!"+"#),#./,*#. QString::append()#$%&'()*&#(!.(#5*",#(!"#,.1"#(!)&9#.,#(!" +=#*4"+.(*+K [*]


The convenient qDebug() << arg syntax used here requires the inclusion of the <QtDebug> header file, while the
qDebug("...", arg) syntax is available in any file that includes at least one Qt header.

str = "User: ";


str.append(userName); QString str = "polluter pays principle";
str.append("\n"); qDebug() << str.mid(9, 4);

G#'*14/"("/0#5)$$"+"&(#:.0#*$#'*17)&)&9#,(+)&9,#),#(*#%," QString2, sprintf()#$%&'()*&K !G#I(#9+&$#$%(#'(39"4#*2HB+("$. mid()#2($B2"'#$%(#'B5'$2&"H#'$*2$&"H#*$#$%(#H&7("#,9'&$&9"#*"4


("4&"H#*$#$%(#("4#9G#$%(#'$2&"H@#L92#()*+,-(.#$%(#G9--9I&"H#394(#,2&"$'#/,*6'#,2&"3&,-(/#$9#$%(
39"'9-(
str.sprintf("%s %.1f%%", "perfect competition", 100.0);

QString str = "polluter pays principle";


qDebug() << str.mid(9);
str.insert(2, "sunny");

A%(2(#*2(#*-'9 left()#*"4 right()#GB"3$&9"'#$%*$#,(2G92+#*#'&+&-*2#Q95@#R9$%#*33(,$#*#"B+5(2#9G


3%*2*3$(2'. .#*"4#2($B2"#$%(#G&2'$#92#-*'$ #3%*2*3$(2'#9G#$%(#'$2&"H@#L92 ()*+,-(.#$%(#G9--9I&"H#394( L&2'$.#I(#2(+97(#'&)#3%*2*3$(2'#'$*2$&"H#*$#,9'&$&9"#8.#2('B-$&"H#&"#$%(#'$2&"H#/*#4*6/#CI&$%#$I9
,2&"$'#/,9--B$(2#,2&"3&,-(/#$9#$%(#39"'9-( ',*3('E.#$%("#I(#&"'(2$#/'B""6/#*$#,9'&$&9"#8@

A%(2(#*2(#97(2-9*4(4#7(2'&9"'#9G replace()#$%*$#2(,-*3(#*--#933B22("3('#9G#$%(&2#G&2'$#*2HB+("$#I&$%
QString str = "polluter pays principle"; $%(&2#'(39"4#*2HB+("$@#L92#()*+,-(.#%(2(S'#%9I#$9#2(,-*3(#*--#933B22("3('#9G#/U/#I&$%#/U*+,V/#&"#*
'$2&"H

qDebug() << str.left(8) << " " << str.right(9);


str.replace("&", "&amp;");

!G#I(#I*"$#$9#G&"4#9B$#&G#*#'$2&"H#39"$*&"'#*#,*2$&3B-*2#3%*2*3$(2.#'B5'$2&"H.#92#2(HB-*2#(),2(''&9".#I(
3*"#B'(#9"(#9G QStringS' indexOf()#GB"3$&9"' K"(#7(26#G2(WB("$ "((4#&'#$9#'$2&,#$%(#I%&$(',*3(#C'B3%#*'#',*3('.#$*5'.#*"4#"(I-&"('E#G29+#*
'$2&"H@ QString#%*'#*#GB"3$&9"#$%*$#(-&+&"*$('#I%&$(',*3(#G29+#59$%#("4'#9G#*#'$2&"H

QString str = "the middle bit";


int i = str.indexOf("middle"); QString str = " BOB \t THE \nDOG \n";

A%&'#I&--#'($ i#$9#>@#A%( indexOf()#GB"3$&9"#2($B2"' D1#9"#G*&-B2(.#*"4#*33(,$'#*"#9,$&9"*-#'$*2$ qDebug() << str.trimmed();


,9'&$&9"#*"4#3*'(D'("'&$&7&$6#G-*H@

!G#I(#QB'$#I*"$#$9#3%(3T#I%($%(2#*#'$2&"H#'$*2$'#92#("4'#I&$%#'9+($%&"H.#I(#3*"#B'(#$%( F$2&"H str#3*"#5(#4(,&3$(4#*'


startsWith()#*"4 endsWith()#GB"3$&9"'

if (url.startsWith("http:") && url.endsWith(".png"))


... A%(#'$2&"H#2($B2"(4#56 trimmed()#&'

A%&'#&'#59$%#'&+,-(2#*"4#G*'$(2#$%*"#$%&'
X%("#%*"4-&"H#B'(2#&",B$.#I(#9G$("#*-'9#I*"$#$9#2(,-*3(#(7(26#'(WB("3(#9G#9"(#92#+92(#&"$(2"*-
I%&$(',*3(#3%*2*3$(2'#I&$%#'&"H-(#',*3('.#&"#*44&$&9"#$9#'$2&,,&"H#I%&$(',*3(#G29+#59$%#("4'@#A%&'#&'
if (url.left(5) == "http:" && url.right(4) == ".png") I%*$#$%( simplified()#GB"3$&9"#49('
...

QString str = " BOB \t THE \nDOG \n";


F$2&"H#39+,*2&'9"#I&$%#$%( ==#9,(2*$92#&'#3*'(#'("'&$&7(@#!G#I(#*2(#39+,*2&"H#B'(2D7&'&5-(#'$2&"H'. qDebug() << str.simplified();
localeAwareCompare()#&'#B'B*--6#$%(#2&H%$#3%9&3(.#*"4#&G#I(#I*"$#$9#+*T(#$%(#39+,*2&'9"'#3*'(D
&"'("'&$&7(.#I(#3*"#B'( toUpper()#92 toLower()@#L92#()*+,-(
A%(#'$2&"H#2($B2"(4#56 simplified()#&'

if (fileName.toLower() == "readme.txt")
...

Y#'$2&"H#3*"#5(#',-&$#&"$9#* QStringList#9G#'B5'$2&"H'#B'&"H QString::split()


!G#I(#I*"$#$9#2(,-*3(#*#3(2$*&"#,*2$#9G#*#'$2&"H#56#*"9$%(2#'$2&"H.#I(#3*"#B'( replace()
QString str = "polluter pays principle";
QStringList words = str.split(" ");
QString str = "a cloudy day";
str.replace(2, 6, "sunny");

!"#$%(#()*+,-(#*597(.#I(#',-&$#$%(#'$2&"H#/,9--B$(2#,*6'#,2&"3&,-(/#&"$9#$%2((#'B5'$2&"H' #/,9--B$(2/.
/,*6'/.#*"4#/,2&"3&,-(/@#A%( split()#GB"3$&9"#%*'#*"#9,$&9"*-#$%&24#*2HB+("$#$%*$#',(3&G&('#I%($%(2
A%(#2('B-$#&'#/* 'B""6#4*6/@#A%(#394(#3*"#5(#2(I2&$$("#$9#B'( remove()#*"4 insert()
(+,$6#'B5'$2&"H'#'%9B-4#5(#T(,$#C$%(#4(G*B-$E#92#4&'3*24(4@

str.remove(2, 6); A%(#&$(+'#&"#* QStringList#3*"#5(#Q9&"(4#$9#G92+#*#'&"H-(#'$2&"H#B'&"H join()@#A%(#*2HB+("$#$9


join()#&'#&"'(2$(4#5($I(("#(*3%#,*&2#9G#Q9&"(4#'$2&"H'@#L92#()*+,-(.#%(2(S'#%9I#$9#32(*$(#*#'&"H-(
'$2&"H#$%*$#&'#39+,9'(4#9G#*--#$%(#'$2&"H'#39"$*&"(4 &"#* QStringList#'92$(4#&"$9#*-,%*5($&3*-#924(2 5*'&3#[``#"B+(2&3#$6,('#-&T( double#*"4 int@#A%( QVariant#3-*''#3*"#*-'9#%9-4#39"$*&"(2'
*"4#'(,*2*$(4#56#"(I-&"(' QMap<QString,QVariant>. QStringList.#*"4 QList<QVariant>@

a*2&*"$'#*2(#B'(4#()$("'&7(-6#56#$%(#&$(+#7&(I#3-*''('.#$%(#4*$*5*'(#+94B-(.#*"4 QSettings.
words.sort(); *--9I&"H#B'#$9#2(*4#*"4#I2&$(#&$(+#4*$*.#4*$*5*'(#4*$*.#*"4#B'(2#,2(G(2("3('#G92#*"6 QVariantD
str = words.join("\n");
39+,*$&5-(#$6,(@#X(#%*7(#*-2(*46#'(("#*"#()*+,-(#9G#$%&'#&" [%*,$(2#:.#I%(2(#I(#,*''(4#* QRect.#*
QStringList.#*"4#*#39B,-(#9G bool'#*'#7*2&*"$'#$9 QSettings::setValue().#*"4#2($2&(7(4#$%(+#-*$(2#*'
7*2&*"$'@
X%("#4(*-&"H#I&$%#'$2&"H'.#I(#9G$("#"((4#$9#4($(2+&"(#I%($%(2#*#'$2&"H#&'#(+,$6#92#"9$@#A%&'#&'
49"(#56#3*--&"H isEmpty()#92#56#3%(3T&"H#I%($%(2 length()#&'#=@ !$#&'#,9''&5-(#$9#32(*$(#*25&$2*2&-6#39+,-()#4*$*#'$2B3$B2('#B'&"H QVariant#56#"('$&"H#7*-B('#9G
39"$*&"(2#$6,('
A%(#39"7(2'&9"#G29+ const char *#'$2&"H'#$9 QString#&'#*B$9+*$&3#&"#+9'$#3*'('.#G92#()*+,-(

QMap<QString, QVariant> pearMap;


str += " (1870)"; pearMap["Standard"] = 1.95;
pearMap["Organic"] = 2.25;
QMap<QString, QVariant> fruitMap;
fruitMap["Orange"] = 2.10;
Z(2(#I(#*44#* const char *#$9#* QString#I&$%9B$#G92+*-&$6@#A9#(),-&3&$-6#39"7(2$#* const char *#$9#*
fruitMap["Pineapple"] = 3.85;
QString.#'&+,-6#B'(#* QString#3*'$.#92#3*-- fromAscii()#92 fromLatin1()@#CF(( [%*,$(2#1?#G92#*" fruitMap["Pear"] = pearMap;
(),-*"*$&9"#9G#%*"4-&"H#-&$(2*-#'$2&"H'#&"#9$%(2#("394&"H'@E

A9#39"7(2$#* QString#$9#* const char *.#B'( toAscii()#92 toLatin1()@#A%('(#GB"3$&9"'#2($B2"#*


Z(2(#I(#%*7(#32(*$(4#*#+*,#I&$%#'$2&"H#T(6'#C,294B3$#"*+('E#*"4#7*-B('#$%*$#*2(#(&$%(2#G-9*$&"HD
QByteArray.#I%&3%#3*"#5(#39"7(2$(4#&"$9#* const char *#B'&"H QByteArray::data()#92
,9&"$#"B+5(2' C,2&3('E#92#+*,'@#A%(#$9,D-(7(-#+*,#39"$*&"'#$%2((#T(6' #/K2*"H(/.#/](*2/.#*"4
QByteArray::constData()@#L92#()*+,-( /]&"(*,,-(/@#A%(#7*-B(#*''93&*$(4#I&$%#$%(#/](*2/#T(6#&'#*#+*,#$%*$#39"$*&"'#$I9#T(6'#C/F$*"4*24/
*"4#/K2H*"&3/E@#X%("#&$(2*$&"H#97(2#*#+*,#$%*$#%9-4'#7*2&*"$#7*-B('.#I(#"((4#$9#B'( type()#$9#3%(3T
$%(#$6,(#$%*$#*#7*2&*"$#%9-4'#'9#$%*$#I(#3*"#2(',9"4#*,,29,2&*$(-6@
printf("User: %s\n", str.toAscii().data());
[2(*$&"H#4*$*#'$2B3$B2('#-&T(#$%&'#3*"#5(#7(26#'(4B3$&7(#'&"3(#I(#3*"#92H*"&M(#$%(#4*$*#&"#*"6#I*6
I(#-&T(@#RB$#$%(#39"7("&("3(#9G QVariant#39+('#*$#$%(#(),("'(#9G#(GG&3&("36#*"4#2(*4*5&-&$6@#Y'#*
L92#39"7("&("3(.#\$#,297&4('#$%( qPrintable()#+*329#$%*$#,(2G92+'#$%(#'*+(#*'#$%(#'(WB("3( 2B-(.#&$#&'#B'B*--6#I92$%#4(G&"&"H#*#,29,(2#[``#3-*''#$9#'$92(#9B2#4*$*#I%("(7(2#,9''&5-(@
toAscii().constData()
QVariant#&'#B'(4#56#\$S'#+($*D95Q(3$#'6'$(+#*"4#&'#$%(2(G92(#,*2$#9G#$%( !"#$%&#+94B-(@
b9"($%(-(''.#I%("#I(#-&"T#*H*&"'$#$%( !"'()#+94B-(. QVariant#3*"#'$92(#cJ!D2(-*$(4#$6,('#'B3%#*'
printf("User: %s\n", qPrintable(str));
QColor. QFont. QIcon. QImage.#*"4 QPixmap

X%("#I(#3*-- data()#92 constData()#9"#* QByteArray.#$%(#2($B2"(4#'$2&"H#&'#9I"(4#56#$%( QByteArray QIcon icon("open.png");


95Q(3$@#A%&'#+(*"'#$%*$#I(#49"S$#"((4#$9#I9226#*59B$#+(+926#-(*T'V#\$#I&--#2(3-*&+ $%(#+(+926#G92 QVariant variant = icon;
B'@#K"#$%(#9$%(2#%*"4.#I(#+B'$#5(#3*2(GB-#"9$#$9#B'(#$%(#,9&"$(2#G92#$99#-9"H@#!G#$%( QByteArray#&'
"9$#'$92(4#&"#*#7*2&*5-(.#&$#I&--#5(#*B$9+*$&3*--6#4(-($(4#*$#$%(#("4#9G#$%(#'$*$(+("$@
A9#2($2&(7(#$%(#7*-B(#9G#*#cJ!D2(-*$(4#$6,(#G29+#* QVariant.#I(#3*"#B'(#$%( QVariant::value<T>()
A%( QByteArray#3-*''#%*'#*#7(26#'&+&-*2#Y]!#$9 QString@#LB"3$&9"'#-&T( left(). right(). mid(). $(+,-*$(#+(+5(2#GB"3$&9"#*'#G9--9I'
toLower(). toUpper(). TRimmed().#*"4 simplified()#()&'$#&" QByteArray#I&$%#$%(#'*+(#'(+*"$&3'#*'
$%(&2 QString#39B"$(2,*2$'@ QByteArray#&'#B'(GB-#G92#'$92&"H#2*I#5&"*26#4*$*#*"4#^D5&$#("394(4#$()$
'$2&"H'@#!"#H("(2*-.#I(#2(39++("4#B'&"H QString#G92#'$92&"H#$()$#2*$%(2#$%*" QByteArray#5(3*B'( QIcon icon = variant.value<QIcon>();
QString#'B,,92$'#J"&394(@

L92#39"7("&("3(. QByteArray#*B$9+*$&3*--6#("'B2('#$%*$#$%(#/9"(#,*'$#$%(#-*'$/#56$(#&'#*-I*6'#S_=S. A%( value<T>()#GB"3$&9"#*-'9#I92T'#G92#39"7(2$&"H#5($I(("#"9"DcJ!#4*$*#$6,('#*"4 QVariant.#5B$#&"


+*T&"H#&$#(*'6#$9#,*''#* QByteArray#$9#*#GB"3$&9"#$*T&"H#* const char *@ QByteArray#*-'9#'B,,92$' ,2*3$&3(#I(#"92+*--6#B'(#$%( to...()#39"7(2'&9"#GB"3$&9"'#CG92#()*+,-(. toString()E#G92#"9"DcJ!
(+5(44(4#S_=S#3%*2*3$(2'.#*--9I&"H#B'#$9#B'(#&$#$9#'$92(#*25&$2*26#5&"*26#4*$*@ $6,('@

!"#'9+(#'&$B*$&9"'.#I(#"((4#$9#'$92(#4*$*#9G#4&GG(2("$#$6,('#&"#$%(#'*+(#7*2&*5-(@#K"(#*,,29*3%#&'#$9 QVariant#3*"#*-'9#5(#B'(4#$9#'$92(#3B'$9+#4*$*#$6,('.#*''B+&"H#$%(6#,297&4(#*#4(G*B-$#39"'$2B3$92
("394(#$%(#4*$*#*'#* QByteArray#92#* QString@#L92#()*+,-(.#*#'$2&"H#39B-4#%9-4#*#$()$B*-#7*-B(#92#* *"4#*#39,6#39"'$2B3$92@#L92#$%&'#$9#I92T.#I(#+B'$#G&2'$#2(H&'$(2#$%(#$6,(#B'&"H#$%(
"B+(2&3#7*-B(#&"#'$2&"H#G92+@#A%('(#*,,29*3%('#H&7(#39+,-($(#G-()&5&-&$6.#5B$#49#*I*6#I&$%#'9+(#9G Q_DECLARE_METATYPE()#+*329.#$6,&3*--6#&"#*#%(*4(2#G&-(#5(-9I#$%(#3-*''#4(G&"&$&9" W
[``S'#5("(G&$'.#&"#,*2$&3B-*2#$6,(#'*G($6#*"4#(GG&3&("36@#\$#,297&4('#*#+B3%#3-(*"(2#I*6#9G#%*"4-&"H
7*2&*5-('#$%*$#3*"#%9-4#4&GG(2("$#$6,(' QVariant@
Q_DECLARE_METATYPE(BusinessCard)
A%( QVariant#3-*''#3*"#%9-4#7*-B('#9G#+*"6#\$#$6,('.#&"3-B4&"H QBrush. QColor. QCursor. QDateTime.
QFont. QKeySequence. QPalette. QPen. QPixmap. QPoint. QRect. QRegion. QSize.#*"4 QString.#*'#I(--#*'
A%&'#("*5-('#B'#$9#I2&$(#394(#-&T(#$%&'
Chapter 12. Input/Output
BusinessCard businessCard;
• !"#$%&'"%#'()$*$%&'+$%"),'-"*"
QVariant variant = QVariant::fromValue(businessCard);
• !"#$%&'"%#'()$*$%&'.!/*
...
if (variant.canConvert<BusinessCard>()) { • .)"0!)1$%&'-$)!2*3)$!1
BusinessCard card = variant.value<BusinessCard>(); • 456!##$%&' !137)2!1
... • 8%*!)9:)32!11';3557%$2"*$3%
}
A%(#"((4#$9#2(*4#G29+#92#I2&$(#$9#G&-('#92#9$%(2#4(7&3('#&'#39++9"#$9#*-+9'$#(7(26#*,,-&3*$&9"@#\$
,297&4('#()3(--("$#'B,,92$#G92#!fK#$%29BH% QIODevice.#*#,9I(2GB-#*5'$2*3$&9"#$%*$#("3*,'B-*$('
R(3*B'(#9G#*#39+,&-(2#-&+&$*$&9".#$%('(#$(+,-*$(#+(+5(2#GB"3$&9"'#*2(#"9$#*7*&-*5-(#G92#dFa[#e@#!G /4(7&3('/#3*,*5-(#9G#2(*4&"H#*"4#I2&$&"H#5-93T'#9G#56$('@ \$#&"3-B4('#$%(#G9--9I&"H QIODevice
69B#"((4#$9#B'(#$%&'#39+,&-(2.#B'(#$%( qVariantFromValue(). qVariantValue<T>().#*"4 'B53-*''('
qVariantCanConvert<T>()#H-95*-#GB"3$&9"'#&"'$(*4@
QFile Y33(''('#G&-('#&"#$%(#-93*-#G&-(#'6'$(+#*"4#&"#(+5(44(4#2('9B23('
!G#$%(#3B'$9+#4*$*#$6,(#%*' <<#*"4 >>#9,(2*$92'#G92#I2&$&"H#$9#*"4#2(*4&"H#G29+#* QDataStream.#I(
3*"#2(H&'$(2#$%(+#B'&"H qRegisterMetaTypeStreamOperators<T>()@#A%&'#+*T('#&$#,9''&5-(#$9#'$92( QTemporaryFile [2(*$('#*"4#*33(''('#$(+,92*26#G&-('#&"#$%(#-93*-#G&-(#'6'$(+
,2(G(2("3('#9G#3B'$9+#4*$*#$6,('#B'&"H QSettings.#*+9"H 9$%(2#$%&"H'@#L92#()*+,-(
QBuffer g(*4'#4*$*#G29+#92#I2&$('#4*$*#$9#* QByteArray
QProcess gB"'#()$(2"*-#,29H2*+'#*"4#%*"4-('#&"$(2D,293(''#39++B"&3*$&9"
qRegisterMetaTypeStreamOperators<BusinessCard>("BusinessCard");
QTcpSocket A2*"'G(2'#*#'$2(*+#9G#4*$*#97(2#$%(#"($I92T#B'&"H#A[]
A%&'#3%*,$(2#%*'#G93B'(4#9"#$%(#\$#39"$*&"(2'.#*'#I(--#*'#9" QString. QByteArray.#*"4 QVariant@#!" QUdpSocket F("4'#92#2(3(&7('#Jh]#4*$*H2*+'#97(2#$%(#"($I92T
*44&$&9"#$9#$%('(#3-*''('.#\$#*-'9#,297&4('#*#G(I#9$%(2#39"$*&"(2'@#K"(#&' QPair<T1, T2>.#I%&3%
'&+,-6#'$92('#$I9#7*-B('#*"4#&'#'&+&-*2#$9 std::pair<T1, T2>@#Y"9$%(2#&' QBitArray.#I%&3%#I(#I&--#B'(
&"#$%(#G&2'$#'(3$&9"#9G [%*,$(2#1;@#L&"*--6.#$%(2(#&' QVarLengthArray<T,Prealloc>.#*#-9ID-(7(-
QProcess. QTcpSocket.#*"4 QUdpSocket#*2(#'(WB("$&*-#4(7&3('.#+(*"&"H#$%*$#$%(#4*$*#3*"#9"-6#5(
*-$(2"*$&7(#$9 QVector<T>@#R(3*B'(#&$#,2(*--93*$('#+(+926#9"#$%(#'$*3T#*"4#&'"S$#&+,-&3&$-6#'%*2(4.#&$'
*33(''(4#9"3(.#'$*2$&"H#G29+#$%(#G&2'$#56$(#*"4#,29H2(''&"H#'(2&*--6#$9#$%(#-*'$#56$(@ QFile.
97(2%(*4#&'#-(''#$%*"#$%*$#9G QVector<T>.#+*T&"H#&$#+92(#*,,29,2&*$(#G92#$&H%$#-99,'@
QTemporaryFile.#*"4 QBuffer#*2(#2*"49+D*33(''#4(7&3('.#'9#56$('#3*"#5(#2(*4#*"6#"B+5(2#9G#$&+('
G29+#*"6#,9'&$&9"V#$%(6#,297&4(#$%( QIODevice::seek()#GB"3$&9"#G92#2(,9'&$&9"&"H#$%(#G&-(#,9&"$(2@
\$S'#*-H92&$%+'.#&"3-B4&"H#*#G(I#"9$#397(2(4#%(2(#'B3%#*' qCopyBackward()#*"4 qEqual().#*2(
4('32&5(4#&"#\$S'#493B+("$*$&9"#*$ %$$, ff493@$29--$(3%@39+f>@1f*-H92&$%+'@%$+-@#Y"4#G92#+92(
!"#*44&$&9"#$9#$%(#4(7&3(#3-*''('.#\$#*-'9#,297&4('#$I9#%&H%(2D-(7(-#'$2(*+#3-*''('#$%*$#I(#3*"#B'(
4($*&-'#9G#\$S'#39"$*&"(2'.#&"3-B4&"H#&"G92+*$&9"#9"#$%(&2#$&+(#39+,-()&$6#*"4#H29I$%#'$2*$(H&('.#'((
$9#2(*4#G29+#*"4#I2&$(#$9#*"6#!fK#4(7&3( QDataStream#G92#5&"*26#4*$*#*"4 QTextStream#G92#$()$@
%$$, ff493@$29--$(3%@39+f>@1f39"$*&"(2'@%$+-@
A%('(#3-*''('#$*T(#3*2(#9G#&''B('#'B3%#*'#56$(#924(2&"H#*"4#$()$#("394&"H'.#("'B2&"H#$%*$#\$
*,,-&3*$&9"'#2B""&"H#9"#4&GG(2("$#,-*$G92+'#92#&"#4&GG(2("$#39B"$2&('#3*"#2(*4#*"4#I2&$(#(*3%#9$%(2S'
G&-('@#A%&'#+*T('#\$S'#!fK#3-*''('#+B3%#+92(#39"7("&("$#$%*"#$%(#3922(',9"4&"H#F$*"4*24#[``
3-*''('.#I%&3%#-(*7(#$%('(#&''B('#$9#$%(#*,,-&3*$&9"#,29H2*++(2@

QFile#+*T('#&$#(*'6#$9#*33(''#&"4&7&4B*-#G&-('.#I%($%(2#$%(6#*2(#&"#$%(#G&-(#'6'$(+#92#(+5(44(4#&"
$%(#*,,-&3*$&9"S'#()(3B$*5-(#*'#2('9B23('@#L92#*,,-&3*$&9"'#$%*$#"((4#$9#&4("$&G6#I%9-(#'($'#9G#G&-('#$9
I92T#9".#\$#,297&4('#$%( QDir *"4 QFileInfo#3-*''('.#I%&3%#%*"4-(#4&2(3$92&('#*"4#,297&4(
&"G92+*$&9"#*59B$#$%(#G&-('#&"'&4(#$%(+@

A%( QProcess#3-*''#*--9I'#B'#$9#-*B"3%#()$(2"*-#,29H2*+'#*"4#$9#39++B"&3*$(#I&$%#$%(+#$%29BH%
$%(&2#'$*"4*24#&",B$.#'$*"4*24#9B$,B$.#*"4#'$*"4*24#(2292#3%*""(-'#Ccin. cout.#*"4 cerrE@#X(#3*"#'($
$%(#("7&29"+("$#7*2&*5-('#*"4#I92T&"H#4&2(3$926#$%*$#$%(#()$(2"*-#*,,-&3*$&9"#I&--#B'(@#R6#4(G*B-$.
39++B"&3*$&9"#I&$%#$%(#,293(''#&'#*'6"3%29"9B'#C"9"D5-93T&"HE.#5B$#&$#&'#*-'9#,9''&5-(#$9#5-93T#9"
3(2$*&"#9,(2*$&9"'@

b($I92T&"H#*"4#2(*4&"H#*"4#I2&$&"H#idj#*2(#'B3%#'B5'$*"$&*-#$9,&3'#$%*$#$%(6#*2(#397(2(4
'(,*2*$(-6#&"#$%(&2#9I"#4(4&3*$(4#3%*,$(2'#C[%*,$(2#1>#*"4 [%*,$(2#1<E@
in >> n >> image >> map;

Reading and Writing Binary Data


A%( QDataStream#7(2'&9"#I(#B'(#G92#2(*4&"H#&'#$%(#'*+(#*'#$%(#9"(#I(#B'(4#G92#I2&$&"H@#A%&'#+B'$
A%(#'&+,-('$#I*6#$9#-9*4#*"4#'*7(#5&"*26#4*$*#I&$%#\$#&'#$9#&"'$*"$&*$(#* QFile.#$9#9,("#$%(#G&-(.#*"4 *-I*6'#5(#$%(#3*'(@#R6#%*24D394&"H#$%(#7(2'&9"#"B+5(2.#I(#HB*2*"$((#$%*$#$%(#*,,-&3*$&9"#3*"
$9#*33(''#&$#$%29BH%#* QDataStream#95Q(3$@ QDataStream#,297&4('#*#,-*$G92+D&"4(,("4("$#'$92*H( *-I*6'#2(*4#*"4#I2&$(#$%(#4*$*#C*''B+&"H#&$#&'#39+,&-(4#I&$%#\$#>@1#92#*"6#-*$(2#\$#7(2'&9"E@
G92+*$#$%*$#'B,,92$'#5*'&3#[``#$6,('#-&T( int#*"4 double.#*"4#+*"6#\$#4*$*#$6,('.#&"3-B4&"H
QByteArray. QFont. QImage. QPixmap. QString.#*"4 QVariant.#*'#I(--#*'#\$#39"$*&"(2#3-*''('#'B3%#*' QDataStream#'$92('#4*$*#&"#'B3%#*#I*6#$%*$#I(#3*"#2(*4#&$#5*3T#'(*+-(''-6@#L92#()*+,-(.#*
QList<T>#*"4 QMap<K, T>@ QByteArray#&'#2(,2('("$(4#*'#*#:8D5&$#56$(#39B"$#G9--9I(4#56#$%(#56$('#$%(+'(-7('@ QDataStream#3*"
*-'9#5(#B'(4#$9#2(*4#*"4#I2&$(#2*I#56$('.#I&$%9B$#*"6#56$(#39B"$#%(*4(2.#B'&"H readRawBytes()#*"4
Z(2(S'#%9I#I(#I9B-4#'$92(#*"#&"$(H(2.#* QImage.#*"4#* QMap<QString, QColor>#&"#* G&-(#3*--(4 writeRawBytes()@
facts.dat
k2292#%*"4-&"H#I%("#2(*4&"H#G29+#* QDataStream#&'#G*&2-6#(*'6@#A%(#'$2(*+#%*'#* status()#7*-B(#$%*$
3*"#5( QDataStream::Ok. QDataStream::ReadPastEnd.#92 QDataStream::ReadCorruptData@#K"3(#*"#(2292
QImage image("philip.png");
%*'#933B22(4.#$%( >>#9,(2*$92#*-I*6'#2(*4'#M(29#92#(+,$6#7*-B('@#A%&'#+(*"'#$%*$#I(#3*"#9G$("
QMap<QString, QColor> map;
map.insert("red", Qt::red); '&+,-6#2(*4#*"#("$&2(#G&-(#I&$%9B$#I9226&"H#*59B$#,9$("$&*-#(2292'#*"4#3%(3T#$%( status()#7*-B(#*$
map.insert("green", Qt::green); $%(#("4#$9#'((#&G#I%*$#I(#2(*4#I*'#7*-&4@
map.insert("blue", Qt::blue);
QFile file("facts.dat"); QDataStream#%*"4-('#*#7*2&($6#9G#[``#*"4#\$#4*$*#$6,('V#$%(#39+,-($(#-&'$#&'#*7*&-*5-(#*$
if (!file.open(QIODevice::WriteOnly)) { %$$, ff493@$29--$(3%@39+f>@1f4*$*'$2(*+G92+*$@%$+-@#X(#3*"#*-'9#*44#'B,,92$#G92#9B2#9I"#3B'$9+
cerr << "Cannot open file for writing: " $6,('#56#97(2-9*4&"H#$%( <<#*"4 >> 9,(2*$92'@#Z(2(S'#$%(#4(G&"&$&9"#9G#*#3B'$9+#4*$*#$6,(#$%*$#3*"#5(
<< qPrintable(file.errorString()) << endl; B'(4#I&$% QDataStream
return;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_1); class Painting
out << quint32(0x12345678) << image << map; {
public:
Painting() { myYear = 0; }
Painting(const QString &title, const QString &artist, int year) {
!G#I(#3*""9$#9,("#$%(#G&-(.#I(#&"G92+#$%(#B'(2#*"4#2($B2"@#A%( qPrintable()#+*329#2($B2"'#* const myTitle = title;
char *#G92#* QString@#CY"9$%(2#*,,29*3%#I9B-4#%*7(#5(("#$9#B'( QString::toStdString().#I%&3% myArtist = artist;
2($B2"'#* std::string.#G92#I%&3% <iostream>#%*'#* <<#97(2-9*4@E myYear = year;
}
void setTitle(const QString &title) { myTitle = title; }
!G#$%(#G&-(#&'#9,("(4#'B33(''GB--6.#I(#32(*$(#* QDataStream#*"4#'($#&$'#7(2'&9"#"B+5(2@#A%(#7(2'&9" QString title() const { return myTitle; }
"B+5(2#&'#*"#&"$(H(2#$%*$#&"G-B("3('#$%(#I*6#\$#4*$*#$6,('#*2(#2(,2('("$(4#C5*'&3#[``#4*$*#$6,(' ...
*2(#*-I*6'#2(,2('("$(4#$%(#'*+(#I*6E@#!"#\$#>@1.#$%(#+9'$#39+,2(%("'&7(#G92+*$#&'#7(2'&9"#?@#X( private:
3*"#(&$%(2#%*24D394(#$%( 39"'$*"$#?#92#B'(#$%( QDataStream::Qt_4_1#'6+59-&3#"*+(@ QString myTitle;
QString myArtist;
A9#("'B2(#$%*$#$%(#"B+5(2 0x12345678#&'#I2&$$("#*'#*"#B"'&H"(4#:8D5&$#&"$(H(2#9"#*--#,-*$G92+'.#I( int myYear;
3*'$#&$#$9 quint32.#*#4*$*#$6,(#$%*$#&'#HB*2*"$((4#$9#5(#()*3$-6#:8#5&$'@#A9#("'B2(#&"$(29,(2*5&-&$6. };
QDataStream &operator<<(QDataStream &out, const Painting &painting);
QDataStream#'$*"4*24&M('#9"#5&HD("4&*"#56#4(G*B-$V#$%&'#3*"#5(#3%*"H(4#56#3*--&"H setByteOrder()@
QDataStream &operator>>(QDataStream &in, Painting &painting);

X(#49"S$#"((4#$9#(),-&3&$-6#3-9'(#$%(#G&-(#'&"3(#$%&'#&'#49"(#*B$9+*$&3*--6#I%("#$%( QFile#7*2&*5-(
H9('#9B$#9G#'39,(@#!G#I(#I*"$#$9#7(2&G6#$%*$#$%(#4*$*#%*'#*3$B*--6#5(("#I2&$$(".#I(#3*"#3*-- flush()
Z(2(S'#%9I#I(#I9B-4#&+,-(+("$#$%( <<#9,(2*$92
*"4#3%(3T#&$'#2($B2"#7*-B(#Ctrue#9"#'B33(''E@

A%(#394(#$9#2(*4#5*3T#$%(#4*$*#+&2292'#$%(#394(#I(#B'(4#$9#I2&$(#&$ QDataStream &operator<<(QDataStream &out, const Painting &painting)


{
out << painting.title() << painting.artist()
quint32 n; << quint32(painting.year());
QImage image; return out;
QMap<QString, QColor> map; }
QFile file("facts.dat");
if (!file.open(QIODevice::ReadOnly)) {
cerr << "Cannot open file for reading: "
<< qPrintable(file.errorString()) << endl; A9#9B$,B$#* Painting.#I(#'&+,-6#9B$,B$#$I9 QString'#*"4#* quint32@#Y$#$%(#("4#9G#$%(#GB"3$&9".#I(
return; 2($B2"#$%(#'$2(*+@#A%&'#&'#*#39++9"#[``#&4&9+#$%*$#*--9I'#B'#$9#B'(#*#3%*&"#9G <<#9,(2*$92'#I&$%#*"
} 9B$,B$#'$2(*+@#L92#()*+,-(
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_1);
out << painting1 << painting2 << painting3;
CMagicNumber#&'#*#39"'$*"$#$%*$#B"&WB(-6#&4("$&G&('#$%(#G&-(#$6,(@E#A%&'#*,,29*3%#("'B2('#$%*$#I(
*-I*6'#I2&$(#$%(#4*$*#B'&"H#$%(#+9'$#2(3("$#7(2'&9"#9G QDataStream.#I%*$(7(2#$%*$#%*,,("'#$9#5(@
A%(#&+,-(+("$*$&9"#9G operator>>()#&'#'&+&-*2#$9#$%*$#9G operator<<() X%("#I(#39+(#$9#2(*4#$%(#G&-(.#I(#2(*4#$%(#'$2(*+#7(2'&9"

QDataStream &operator>>(QDataStream &in, Painting &painting) quint32 magic;


{ quint16 streamVersion;
QString title; QDataStream in(&file);
QString artist; in >> magic >> streamVersion;
quint32 year; if (magic != MagicNumber) {
in >> title >> artist >> year; cerr << "File is not recognized by this application" << endl;
painting = Painting(title, artist, year); } else if (streamVersion > in.version()) {
return in; cerr << "File is from a more recent version of the application"
} << endl;
return false;
}
in.setVersion(streamVersion);
A%(2(#*2(#'(7(2*-#5("(G&$'#$9#,297&4&"H#'$2(*+&"H#9,(2*$92'#G92#3B'$9+#4*$*#$6,('@#K"(#9G#$%(+#&'
$%*$#&$#*--9I'#B'#$9#'$2(*+#39"$*&"(2'#$%*$#B'(#$%(#3B'$9+#$6,(@#L92#()*+,-(

X(#3*"#2(*4#$%(#4*$*#*'#-9"H#*'#$%(#'$2(*+#7(2'&9"#&'#-(''#$%*"#92#(WB*-#$9#$%(#7(2'&9"#B'(4#56#$%(
QList<Painting> paintings = ...; *,,-&3*$&9"V#9$%(2I&'(.#I(#2(,92$#*"#(2292@

!G#$%(#G&-(#G92+*$#39"$*&"'#*#7(2'&9"#"B+5(2#9G#&$'#9I".#I(#3*"#B'(#&$#$9#4(4B3(#$%(#'$2(*+#7(2'&9"
out << paintings; "B+5(2#&"'$(*4#9G#'$92&"H#&$#(),-&3&$-6@#L92#()*+,-(.#-($S'#'B,,9'(#$%*$#$%(#G&-(#G92+*$#&'#G92#7(2'&9"
1@:#9G#9B2#*,,-&3*$&9"@#X(#+&H%$#$%("#I2&$(#$%(#4*$*#*'#G9--9I'

X(#3*"#2(*4#&"#39"$*&"(2'#QB'$#*'#(*'&-6
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_1);
out << quint32(MagicNumber) << quint16(0x0103);
QList<Painting> paintings;
in >> paintings;

X%("#I(#2(*4#&$#5*3T.#I(#4($(2+&"(#I%&3% QDataStream#7(2'&9"#$9#B'(#5*'(4#9"#$%(#*,,-&3*$&9"S'
7(2'&9"#"B+5(2
A%&'#I9B-4#2('B-$#&"#*#39+,&-(2#(2292#&G Painting#4&4"S$#'B,,92$ <<#92 >>@#Y"9$%(2#5("(G&$#9G#,297&4&"H
'$2(*+&"H#9,(2*$92'#G92#3B'$9+#$6,('#&'#$%*$#I(#3*"#'$92(#7*-B('#9G#$%('(#$6,('#*' QVariant'.#I%&3%
+*T('#$%(+#+92(#I&4(-6#B'*5-(.#G92#()*+,-(#56 QSettings@#A%&'#I92T'#,297&4(4#$%*$#I(#2(H&'$(2#$%(
QDataStream in(&file);
$6,(#B'&"H qRegisterMetaTypeStreamOperators<T>()#5(G92(%*"4.#*'#(),-*&"(4#&" [%*,$(2#11#C,@#8?=E@ in >> magic >> appVersion;
if (magic != MagicNumber) {
X%("#I(#B'( QDataStream.#\$#$*T('#3*2(#9G#2(*4&"H#*"4#I2&$&"H#(*3%#$6,(.#&"3-B4&"H#39"$*&"(2'#I&$% cerr << "File is not recognized by this application" << endl;
*"#*25&$2*26#"B+5(2#9G#&$(+'@#A%&'#2(-&(7('#B'#G29+#$%(#"((4#$9#'$2B3$B2(#I%*$#I(#I2&$(#*"4#G29+ return false;
,(2G92+&"H#*"6#T&"4#9G#,*2'&"H#9"#I%*$#I(#2(*4@#KB2#9"-6#95-&H*$&9"#&'#$9#("'B2(#$%*$#I(#2(*4#*-- } else if (appVersion > 0x0103) {
$%(#$6,('#&"#()*3$-6#$%(#'*+(#924(2#*'#I(#I29$(#$%(+.#-(*7&"H#\$#$9#%*"4-(#*--#$%(#4($*&-'@ cerr << "File is from a more recent version of the application"
<< endl;
return false;
QDataStream#&'#B'(GB-#59$%#G92#9B2#9I"#3B'$9+#*,,-&3*$&9"#G&-(#G92+*$'#*"4#G92#'$*"4*24#5&"*26
}
G92+*$'@#X(#3*"#2(*4#*"4#I2&$(#'$*"4*24#5&"*26#G92+*$'#B'&"H#$%(#'$2(*+&"H#9,(2*$92'#9"#5*'&3 if (appVersion < 0x0103) {
$6,('#C-&T( quint16#92 floatE#92#B'&"H readRawBytes()#*"4 writeRawBytes()@#!G#$%( QDataStream#&' in.setVersion(QDataStream::Qt_3_0);
5(&"H#B'(4#,B2(-6#$9#2(*4#*"4#I2&$(#5*'&3#[``#4*$*#$6,('.#I(#49"S$#(7("#"((4#$9#3*-- setVersion()@ } else {
in.setVersion(QDataStream::Qt_4_1);
F9#G*2.#I(#-9*4(4#*"4#'*7(4#4*$*#I&$%#$%(#'$2(*+S'#7(2'&9"#%*24D394(4#*' QDataStream::Qt_4_1@#A%&' }
*,,29*3%#&'#'&+,-(#*"4#'*G(.#5B$#&$#49('#%*7(#9"(#'+*--#42*I5*3T #X(#3*""9$#$*T(#*47*"$*H(#9G
"(I#92#B,4*$(4#G92+*$'@#L92#()*+,-(.#&G#*#-*$(2#7(2'&9"#9G#\$#*44(4#*#"(I#*$$2&5B$(#$9 QFont#C&"
*44&$&9"#$9#&$'#,9&"$#'&M(.#G*+&-6.#($3@E#*"4#I(#%*24D394(4#$%(#7(2'&9"#"B+5(2#$9 Qt_4_1.#$%*$ !"#$%&'#()*+,-(.#I(#',(3&G6#$%*$#*"6#G&-(#'*7(4#I&$%#7(2'&9"'#,2&92#$9#1@:#9G#$%(#*,,-&3*$&9"#B'('#4*$*
*$$2&5B$(#I9B-4"S$#5(#'*7(4#92#-9*4(4@#A%(2(#*2(#$I9#'9-B$&9"'@#A%(#G&2'$#*,,29*3%#&'#$9#(+5(4#$%( '$2(*+#7(2'&9"#>#CQt_3_0E.#*"4#$%*$#G&-('#'*7(4#I&$%#7(2'&9"#1@:#9G#$%(#*,,-&3*$&9"#B'(#4*$*#'$2(*+
QDataStream#7(2'&9"#"B+5(2#&"#$%(#G&-( 7(2'&9"#?#CQt_4_1E@

!"#'B++*26.#$%(2(#*2(#$%2((#,9-&3&('#G92#%*"4-&"H QDataStream#7(2'&9"' #%*24D394&"H#$%(#7(2'&9"


QDataStream out(&file); "B+5(2.#(),-&3&$-6#I2&$&"H#*"4#2(*4&"H#$%(#7(2'&9"#"B+5(2.#*"4#B'&"H#4&GG(2("$#%*24D394(4#7(2'&9"
out << quint32(MagicNumber) << quint16(out.version()); "B+5(2'#4(,("4&"H#9"#$%(#*,,-&3*$&9"S'#7(2'&9"@#Y"6#9G#$%('(#,9-&3&('#3*"#5(#B'(4#$9#("'B2(#$%*$
4*$*#I2&$$("#56#*"#9-4#7(2'&9"#9G#*"#*,,-&3*$&9"#3*"#5(#2(*4#56#*#"(I#7(2'&9".#(7("#&G#$%(#"(I
7(2'&9"#-&"T'#*H*&"'$#*#+92(#2(3("$#7(2'&9"#9G#\$@#K"3(#I(#%*7(#3%9'("#*#,9-&36#G92#%*"4-&"H QTextStream out(&file);
QDataStream#7(2'&9"'.#2(*4&"H#*"4#I2&$&"H#5&"*26#4*$*#B'&"H#\$#&'#59$%#'&+,-(#*"4#2(-&*5-(@ out << "Thomas M. Disch: " << 334 << endl;

!G#I(#I*"$#$9#2(*4#92#I2&$(#*#G&-(#&"#9"(#H9.#I(#3*"#*79&4#B'&"H QDataStream#*-$9H($%(2#*"4#&"'$(*4
B'( QIODeviceS' write()#*"4 readAll()#GB"3$&9"'@#L92#()*+,-( X2&$&"H#$()$#&'#7(26#(*'6.#5B$#2(*4&"H#$()$#3*"#5(#3%*--("H&"H.#5(3*B'(#$()$B*-#4*$*#CB"-&T(#5&"*26
4*$*#I2&$$("#B'&"H QDataStreamE#&'#GB"4*+("$*--6#*+5&HB9B'@#j($S'#39"'&4(2#$%(#G9--9I&"H#()*+,-(

bool copyFile(const QString &source, const QString &dest)


{ out << "Norway" << "Sweden";
QFile sourceFile(source);
if (!sourceFile.open(QIODevice::ReadOnly))
return false;
QFile destFile(dest); !G out#&'#* QTextStream.#$%(#4*$*#$%*$#*3$B*--6#H($'#I2&$$("#&'#$%(#'$2&"H#/b92I*6FI(4("/@#X(#3*"S$
if (!destFile.open(QIODevice::WriteOnly)) 2(*--6#(),(3$#$%(#G9--9I&"H#394(#$9#2(*4#5*3T#$%(#4*$*#3922(3$-6
return false;
destFile.write(sourceFile.readAll());
return sourceFile.error() == QFile::NoError in >> str1 >> str2;
&& destFile.error() == QFile::NoError;
}
!"#G*3$.#I%*$#%*,,("'#&'#$%*$ str1#H($'#$%(#I%9-(#I924#/b92I*6FI(4("/.#*"4 str2#H($'#"9$%&"H@
A%&'#,295-(+#49('"S$#933B2#I&$% QDataStream#5(3*B'(#&$#'$92('#$%(#-("H$%#9G#(*3%#'$2&"H#&"#G29"$#9G
!"#$%(#-&"(#I%(2( readAll()#&'#3*--(4.#$%(#("$&2(#39"$("$'#9G#$%(#&",B$#G&-(#&'#2(*4#&"$9#* QByteArray. $%(#3%*2*3$(2#4*$*@
I%&3%#&'#$%("#,*''(4#$9#$%( write()#GB"3$&9"#$9#5(#I2&$$("#$9#$%(#9B$,B$#G&-(@#Z*7&"H#*--#$%(#4*$*#&"#*
QByteArray#2(WB&2('#+92(#+(+926#$%*"#2(*4&"H#&$(+#56#&$(+.#5B$#&$#9GG(2'#'9+(#*47*"$*H('@#L92 L92#39+,-()#G&-(#G92+*$'.#*#GB--D5-9I"#,*2'(2#+&H%$#5(#2(WB&2(4@#FB3%#*#,*2'(2#+&H%$#I92T#56
()*+,-(.#I(#3*"#$%("#B'( qCompress()#*"4 qUncompress()#$9#39+,2(''#*"4#B"39+,2(''#$%(#4*$*@ 2(*4&"H#$%(#4*$*#3%*2*3$(2D56D3%*2*3$(2#B'&"H >>#9"#* QChar.#92#-&"(#56#-&"(#B'&"H
QTextStream::readLine()@#Y$#$%(#("4#9G#$%&'#'(3$&9".#I(#,2('("$#$I9#'+*--#()*+,-('.#9"(#$%*$#2(*4'
A%(2(#*2(#9$%(2#'3("*2&9'#I%(2(#*33(''&"H QIODevice#4&2(3$-6#&'#+92(#*,,29,2&*$(#$%*"#B'&"H *"#&",B$#G&-(#-&"(#56#-&"(.#*"4#*"9$%(2#$%*$#2(*4'#&$#3%*2*3$(2#56#3%*2*3$(2@#L92#,*2'(2'#$%*$#I92T#9"
QDataStream@ QIODevice#,297&4('#* peek()#GB"3$&9"#$%*$#2($B2"'#$%(#"()$#4*$*#56$('#I&$%9B$#+97&"H *"#("$&2(#$()$.#I(#39B-4#2(*4#$%(#39+,-($(#G&-(#&"#9"(#H9#B'&"H QTextStream::readAll()#&G#I(#*2(#"9$
$%(#4(7&3(#,9'&$&9" *'#I(--#*'#*" unget-Char()#GB"3$&9"#$%*$#/B"2(*4'/#*#56$(@#A%&'#I92T'#59$%#G92 39"3(2"(4#*59B$#+(+926#B'*H(.#92#&G#I(#T"9I#$%(#G&-(#I&--#5(#'+*--@
2*"49+D*33(''#4(7&3('#C'B3%#*'#G&-('E#*"4#G92#'(WB("$&*-#4(7&3('#C'B3%#*'#"($I92T#'93T($'E@#A%(2(#&'
*-'9#* seek()#GB"3$&9"#$%*$#'($'#$%(#4(7&3(#,9'&$&9".#G92#4(7&3('#$%*$#'B,,92$#2*"49+#*33(''@ R6#4(G*B-$. QTextStream#B'('#$%(#'6'$(+S'#-93*-#("394&"H#CG92#()*+,-(.#!FK#^^<;D1#92#!FK#^^<;D1<
&"#Y+(2&3*#*"4#+B3%#9G#kB29,(E#G92#2(*4&"H#*"4#I2&$&"H@#A%&'#3*"#5(#3%*"H(4#B'&"H setCodec()#*'
R&"*26#G&-(#G92+*$'#,297&4(#$%(#+9'$#7(2'*$&-(#*"4#+9'$#39+,*3$#+(*"'#9G#'$92&"H#4*$*.#*"4 G9--9I'
QDataStream#+*T('#*33(''&"H#5&"*26#4*$*#(*'6@#!"#*44&$&9"#$9#$%(#()*+,-('#&"#$%&'#'(3$&9".#I(#%*7(
*-2(*46#'(("#$%(#B'(#9G QDataStream#&" [%*,$(2#>#$9#2(*4#*"4#I2&$(#F,2(*4'%(($#G&-('.#*"4#I(#I&--
'((#&$#*H*&"#&" [%*,$(2#1;.#I%(2(#I(#B'(#&$#$9#2(*4#*"4#I2&$(#X&"49I'#3B2'92#G&-('@ stream.setCodec("UTF-8");

A%(#JALD^#("394&"H#B'(4#&"#$%(#()*+,-(#&'#*#,9,B-*2#YF[!!D39+,*$&5-(#("394&"H#$%*$#3*"#2(,2('("$
Reading and Writing Text $%(#("$&2(#J"&394(#3%*2*3$(2#'($@#L92#+92(#&"G92+*$&9"#*59B$#J"&394(#*"4 QTextStreamS'#'B,,92$#G92
("394&"H'.#'(( [%*,$(2#1?#C!"$(2D"*$&9"*-&M*$&9"E@
X%&-(#5&"*26#G&-(#G92+*$'#*2(#$6,&3*--6#+92(#39+,*3$#$%*"#$()$D5*'(4#G92+*$'.#$%(6#*2(#"9$#%B+*"D
2(*4*5-(#92#%B+*"D(4&$*5-(@#!"#3*'('#I%(2(#$%&'#&'#*"#&''B(.#I(#3*"#B'(#$()$#G92+*$'#&"'$(*4@#\$ QTextStream#%*'#7*2&9B'#9,$&9"'#+94(-(4#*G$(2#$%9'(#9GG(2(4#56 <iostream>@#A%('(#3*"#5(#'($#56
,297&4('#$%( QTextStream#3-*''#G92#2(*4&"H#*"4#I2&$&"H#,-*&"#$()$#G&-('#*"4#G92#G&-('#B'&"H#9$%(2#$()$ ,*''&"H#',(3&*-#95Q(3$'.#3*--(4 *"%&+,-,+ ).(/+"$%*.#9"#$%(#'$2(*+#$9#*-$(2#&$'#'$*$(@#A%(#G9--9I&"H
G92+*$'.#'B3%#*'#ZAdj.#idj.#*"4#'9B23(#394(@#Z*"4-&"H#idj#G&-('#&'#397(2(4#'(,*2*$(-6#&" [%*,$(2 ()*+,-(#'($'#$%( showbase. upper-casedigits.#*"4 hex#9,$&9"'#5(G92(#&$#9B$,B$'#$%(#&"$(H(2
1<@ 18:><e?^.#,294B3&"H#$%(#$()$#/=)R[e1>k/

QTextStream#$*T('#3*2(#9G#39"7(2$&"H#5($I(("#J"&394(#*"4#$%(#'6'$(+S'#-93*-#("394&"H#92#*"6#9$%(2
("394&"H.#*"4#$2*"',*2("$-6#%*"4-('#$%(#4&GG(2("$#-&"(D("4&"H#39"7("$&9"'#B'(4#56#4&GG(2("$ out << showbase << uppercasedigits << hex << 12345678;
9,(2*$&"H#'6'$(+'#C/_2_"/#9"#X&"49I'.#/_"/#9"#J"&)#*"4#d*3#KF#iE@ QTextStream#B'('#$%(#1eD5&$
QChar#$6,(#*'#&$'#GB"4*+("$*-#B"&$#9G#4*$*@#!"#*44&$&9"#$9#3%*2*3$(2'#*"4#'$2&"H'. QTextStream
'B,,92$'#[``S'#5*'&3#"B+(2&3#$6,('.#I%&3%#&$#39"7(2$'#$9#*"4#G29+#'$2&"H'@#L92#()*+,-(.#$%( K,$&9"'#3*"#*-'9#5(#'($#B'&"H#+(+5(2#GB"3$&9"'
G9--9I&"H#394(#I2&$('#/A%9+*'#d@#h&'3% #::>_"/#$9#$%(#G&-( sf-book.txt

out.setNumberFlags(QTextStream::ShowBase
QFile file("sf-book.txt"); | QTextStream::UppercaseDigits);
if (!file.open(QIODevice::WriteOnly)) { out.setIntegerBase(16);
cerr << "Cannot open file for writing: " out << 12345678;
<< qPrintable(file.errorString()) << endl;
return;
}
QTextStream out(&file);
!"#$%&'()')& #*+,!-*.&,-&.%, QTextStream/.&-0,!-*. for (int row = 0; row < RowCount; ++row) {
[View full size image]
for (int column = 0; column < ColumnCount; ++column) {
QString str = formula(row, column);
if (!str.isEmpty())
out << row << " " << column << " " << str << endl;
}
}

X(#%*7(#B'(4#*#'&+,-(#G92+*$.#I&$%#(*3%#-&"(#2(,2('("$&"H#9"(#3(--#*"4#I&$%#',*3('#5($I(("#$%(
29I#*"4#$%(#39-B+"#*"4#5($I(("#$%(#39-B+"#*"4#$%(#G92+B-*@#A%(#G92+B-*#3*"#39"$*&"#',*3('.#5B$
I(#3*"#*''B+(#$%*$#&$#39"$*&"'#"9#S_"S#CI%&3%#I(#B'(#$9#$(2+&"*$(#-&"('E@#b9I#-($S'#-99T#*$#$%(
3922(',9"4&"H#2(*4&"H#394(

QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
QStringList fields = line.split(' ');
if (fields.size() >= 3) {
int row = fields.takeFirst().toInt();
int column = fields.takeFirst().toInt();
setFormula(row, column, fields.join(' '));
}
}

X(#2(*4#&"#$%(#F,2(*4'%(($#4*$*#9"(#-&"(#*$#*#$&+(@#A%( readLine()#GB"3$&9"#2(+97('#$%(#$2*&-&"H
S_"S@ QString::split()#2($B2"'#*#'$2&"H#-&'$.#%*7&"H#',-&$#&$'#'$2&"H#I%(2(7(2#$%(#'(,*2*$92#&$#&'#H&7("
*,,(*2'@#L92#()*+,-(.#$%(#-&"(#/<#1;#A9$*-#7*-B(/#2('B-$'#&"#$%(#G9B2D&$(+#-&'$#N/</.#/1;/.#/A9$*-/.
/7*-B(/P@

!G#I(#%*7(#*$#-(*'$#$%2((#G&(-4'.#I(#*2(#2(*46#$9#()$2*3$#$%(#4*$*@#A%( QStringList::takeFirst()
GB"3$&9"#2(+97('#$%(#G&2'$#&$(+#&"#*#-&'$#*"4#2($B2"'#$%(#2(+97(4#&$(+@#X(#B'(#&$#$9#()$2*3$#$%(#29I
*"4#39-B+"#"B+5(2'@#X(#49"S$#,(2G92+#*"6#(2292#3%(3T&"HV#&G#I(#2(*4#*#"9"D&"$(H(2#29I#92#39-B+"
7*-B(. QString::toInt()#I&--#2($B2"#=@#X%("#I(#3*-- setFormula().#I(#+B'$#39"3*$("*$(#$%(
2(+*&"&"H#G&(-4'#5*3T#&"$9#*#'&"H-(#'$2&"H@

!"#9B2#'(39"4 QTextStream#()*+,-(.#I(#I&--#B'(#*#3%*2*3$(2#56#3%*2*3$(2#*,,29*3%#$9#&+,-(+("$#*
,29H2*+#$%*$#2(*4'#&"#*#$()$#G&-(#*"4#9B$,B$'#$%(#'*+(#$()$#5B$#I&$%#$2*&-&"H#',*3('#2(+97(4#G29+
-&"('#*"4#*--#$*5'#2(,-*3(4#56#',*3('@#A%(#,29H2*+S'#I92T#&'#49"(#56#$%( tidyFile()#GB"3$&9"

j&T( QDataStream. QTextStream#9,(2*$('#9"#* QIODevice#'B53-*''.#I%&3%#3*"#5(#* QFile.#*


QTemporaryFile.#* QBuffer.#* QProcess.#* QTcpSocket.#92#* QUdpSocket@#!"#*44&$&9".#&$#3*"#5(#B'(4 void tidyFile(QIODevice *inDevice, QIODevice *outDevice)
4&2(3$-6#9"#* QString@#L92#()*+,-( {
QTextStream in(inDevice);
QTextStream out(outDevice);
QString str; const int TabSize = 8;
QTextStream(&str) << oct << 31 << " " << dec << 25 << endl; int endlCount = 0;
int spaceCount = 0;
int column = 0;
QChar ch;
A%&'#+*T('#$%(#39"$("$'#9G str#/:?#8<_#"/.#'&"3(#$%(#4(3&+*-#"B+5(2#:1#&'#(),2(''(4#*'#:?#&"#93$*-@ while (!in.atEnd()) {
!"#$%&'#3*'(.#I(#49"S$#"((4#$9#'($#*"#("394&"H#9"#$%(#'$2(*+.#'&"3( QString#&'#*-I*6'#J"&394(@ in >> ch;
if (ch == '\n') {
j($S'#-99T#*$#*#'&+,-(#()*+,-(#9G#*#$()$D5*'(4#G&-(#G92+*$@#!"#$%(#F,2(*4'%(($#*,,-&3*$&9"#4('32&5(4 ++endlCount;
spaceCount = 0;
&" ]*2$#!.#I(#B'(4#*#5&"*26#G92+*$#G92#'$92&"H#F,2(*4'%(($#4*$*@#A%(#4*$*#39"'&'$(4#9G#*#'(WB("3(#9G
column = 0;
C%$01-2$/(, 1-3$%,(/+E#$2&,-('.#9"(#G92#(7(26#"9"D(+,$6#3(--@#X2&$&"H#$%(#4*$*#*'#$()$#&'
} else if (ch == '\t') {
'$2*&H%$G92I*24V#%(2( &'#*"#()$2*3$#G29+#*#2(7&'(4#7(2'&9"#9G Spreadsheet::writeFile() int size = TabSize - (column % TabSize);
spaceCount += size;
column += size;
} else if (ch == ' ') { TEMPLATE = app
++spaceCount; QT = core
++column; CONFIG += console
} else { CONFIG -= app_bundle
while (endlCount > 0) { SOURCES = tidy.cpp
out << endl;
--endlCount;
column = 0;
} X(#9"-6#-&"T#*H*&"'$ !"#$%&#'&"3(#I(#49"S$#B'(#*"6#cJ!#GB"3$&9"*-&$6@#A%("#I( ',(3&G6#$%*$#I(#I*"$
while (spaceCount > 0) { $9#("*5-(#39"'9-(#9B$,B$#9"#X&"49I'#*"4#$%*$#I(#49"S$#I*"$#$%(#*,,-&3*$&9"#$9#-&7(#&"#*#5B"4-(#9"
out << ' '; d*3#KF#i@
--spaceCount;
++column; L92#2(*4&"H#*"4#I2&$&"H#,-*&"#YF[!!#G&-('#92#!FK#^^<;D1#Cj*$&"D1E#G&-('.#&$#&'#,9''&5-(#$9#B'(
} QIODeviceS'#Y]!#4&2(3$-6#&"'$(*4#9G#B'&"H#* QTextStream@#!$#&'#2*2(-6#I&'(#$9#49#$%&'#'&"3(#+9'$
out << ch; *,,-&3*$&9"'#"((4#'B,,92$#G92#9$%(2#("394&"H'#*$#'9+(#,9&"$#92#9$%(2.#*"4#9"-6 QTextStream#,297&4('
++column; '(*+-(''#'B,,92$#G92#$%('(@#!G#69B#'$&--#I*"$#$9#I2&$(#$()$#4&2(3$-6#$9#* QIODevice.#69B#+B'$#(),-&3&$-6
}
',(3&G6#$%( QIODevice::Text#G-*H#$9#$%( open()#GB"3$&9".#G92#()*+,-(
}
out << endl;
}
file.open(QIODevice::WriteOnly | QIODevice::Text);

X(#32(*$(#*"#&",B$#*"4#*"#9B$,B$ QTextStream#5*'(4#9"#$%( QIODevice'#$%*$#*2(#,*''(4#$9#$%(


GB"3$&9"@#X(#+*&"$*&"#$%2((#(-(+("$'#9G#'$*$( #9"(#39B"$&"H#"(I-&"('.#9"(#39B"$&"H#',*3('.#*"4#9"( X%("#I2&$&"H.#$%&'#G-*H#$(--' QIODevice#$9#39"7(2$#S_"S#3%*2*3$(2'#&"$9#/_2_"/#'(WB("3('#9"#X&"49I'@
+*2T&"H#$%(#3B22("$#39-B+"#,9'&$&9"#&"#$%(#3B22("$#-&"(#CG92#39"7(2$&"H#$%(#$*5'#$9#$%(#3922(3$ X%("#2(*4&"H.#$%&'#G-*H#$(--'#$%(#4(7&3(#$9#&H"92(#S_2S#3%*2*3$(2'#9"#*--#,-*$G92+'@#X(#3*"#$%("
"B+5(2#9G#',*3('E@ *''B+(#$%*$#$%(#("4#9G#(*3%#-&"(#&'#'&H"&G&(4#I&$%#*#S_"S#"(I-&"(#3%*2*3$(2#2(H*24-(''#9G#$%(#-&"(D
("4&"H#39"7("$&9"#B'(4#56#$%(#9,(2*$&"H#'6'$(+@
A%(#,*2'&"H#&'#49"(#&"#* while#-99,#$%*$#&$(2*$('#97(2#(7(26#3%*2*3$(2#&"#$%(#&",B$#G&-(.#9"(#*$#*#$&+(@
A%(#394(#&'#*#5&$#'B5$-(#&"#,-*3('@#L92#()*+,-(.#*-$%9BH%#I(#'($ TabSize#$9#^.#I(#2(,-*3(#$*5'#I&$% Traversing Directories
,2(3&'(-6#("9BH%#',*3('#$9#,*4#$9#$%(#"()$#$*5#59B"4*26.#2*$%(2#$%*"#32B4(-6#2(,-*3&"H#(*3%#$*5
I&$%#(&H%$#',*3('@#!G#I(#H($#*#"(I-&"(.#$*5.#92#',*3(.#I(#'&+,-6#B,4*$(#$%(#'$*$(#4*$*@#K"-6#I%("
A%( QDir#3-*''#,297&4('#*#,-*$G92+D&"4(,("4("$#+(*"'#9G#$2*7(2'&"H#4&2(3$92&('#*"4#2($2&(7&"H
I(#H($#*"9$%(2#T&"4#9G#3%*2*3$(2#49#I(#,294B3(#*"6#9B$,B$.#*"4#5(G92(#I2&$&"H#$%(#3%*2*3$(2#I(
&"G92+*$&9"#*59B$#G&-('@#A9#'((#%9I QDir#&'#B'(4.#I(#I&--#I2&$(#*#'+*--#39"'9-(#*,,-&3*$&9"#$%*$
I2&$(#*"6#,("4&"H#"(I-&"('#*"4#',*3('#C$9#2(',(3$#5-*"T#-&"('#*"4#$9#,2('(27(#&"4("$*$&9"E#*"4
3*-3B-*$('#$%(#',*3(#39"'B+(4#56#*--#$%(#&+*H('#&"#*#,*2$&3B-*2#4&2(3$926#*"4#*--#&$'#'B54&2(3$92&('#$9
B,4*$(#$%(#'$*$(@
*"6#4(,$%@

int main() A%(#%(*2$#9G#$%(#*,,-&3*$&9"#&'#$%( imageSpace()#GB"3$&9".#I%&3%#2(3B2'&7(-6#39+,B$('#$%(#3B+B-*$&7(


{ '&M(#9G#*#H&7("#4&2(3$926S'#&+*H('
QFile inFile;
QFile outFile;
inFile.open(stdin, QFile::ReadOnly); qlonglong imageSpace(const QString &path)
outFile.open(stdout, QFile::WriteOnly); {
tidyFile(&inFile, &outFile); QDir dir(path);
return 0; qlonglong size = 0;
} QStringList filters;
foreach (QByteArray format, QImageReader::supportedImageFormats())
filters += "*." + format;
foreach (QString file, dir.entryList(filters, QDir::Files))
L92#$%&'#()*+,-(.#I(#49"S$#"((4#* QApplication#95Q(3$.#5(3*B'(#I(#*2(#9"-6#B'&"H#\$S'#$99-#3-*''('@ size += QFileInfo(dir, file).size();
F(( %$$, ff493@$29--$(3%@39+f>@1f$99-'@%$+-#G92#$%(#-&'$#9G#*--#$99-#3-*''('@#X(#%*7(#*''B+(4#$%*$#$%( foreach (QString subDir, dir.entryList(QDir::Dirs
,29H2*+#&'#B'(4#*'#*#G&-$(2.#G92#()*+,-( | QDir::NoDotAndDotDot))
size += imageSpace(path + QDir::separator() + subDir);
return size;
tidy < cool.cpp > cooler.cpp }

!$#I9B-4#5(#(*'6#$9#()$("4#&$#$9#5(#*5-(#$9#%*"4-(#G&-(#"*+('#H&7("#9"#$%(#39++*"4#-&"(#&G#$%(6#*2( X(#5(H&"#56#32(*$&"H#* QDir#95Q(3$#B'&"H#$%(#H&7("#,*$%.#I%&3%#+*6#5(#2(-*$&7(#$9#$%(#3B22("$


H&7(".#*"4#$9#G&-$(2 cin#$9 cout#9$%(2I&'(@ 4&2(3$926#92#*5'9-B$(@#X(#,*''#$%( entryList()#GB"3$&9"#$I9#*2HB+("$'@#A%(#G&2'$#&'#*#-&'$#9G#G&-(
"*+(#G&-$(2'@#A%('(#3*"#39"$*&"#SOS#*"4#SlS#I&-43*24#3%*2*3$(2'@#!"#$%&'#()*+,-(.#I(#*2(#G&-$(2&"H#$9
F&"3(#$%&'#&'#*#39"'9-(#*,,-&3*$&9".#&$#%*'#*#'-&H%$-6#4&GG(2("$ .pro#G&-(#G29+#$%9'(#I(#%*7(#'(("#G92 &"3-B4(#9"-6#G&-(#G92+*$'#$%*$ QImage#3*"#2(*4@#A%(#'(39"4#*2HB+("$#',(3&G&('#I%*$#T&"4#9G#("$2&('
cJ!#*,,-&3*$&9"' I(#I*"$#C"92+*-#G&-('.#4&2(3$92&('.#42&7('.#($3@E@
X(#&$(2*$(#97(2#$%(#-&'$#9G#G&-('.#*33B+B-*$&"H#$%(&2#'&M('@#A%( QFileInfo#3-*''#*--9I'#B'#$9#*33(''#*
G&-(S'#*$$2&5B$('.#'B3%#*'#$%(#G&-(S'#'&M(.#,(2+&''&9"'.#9I"(2.#*"4#$&+('$*+,'@ <!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>datafiles/phone-codes.dat</file>
A%(#'(39"4 entryList()#3*--#2($2&(7('#*--#$%(#'B54&2(3$92&('#&"#$%&'#4&2(3$926@#X(#&$(2*$(#97(2#$%(+ </qresource>
C()3-B4&"H .#*"4 ..E#*"4#2(3B2'&7(-6#3*-- imageSpace()#$9#*'3(2$*&"#$%(&2#*33B+B-*$(4#&+*H( '&M('@ </RCC>

A9#32(*$(#(*3%#'B54&2(3$926S'#,*$%.#I(#39+5&"(#$%(#3B22("$#4&2(3$926S'#,*$%#I&$%#$%(#'B54&2(3$926
"*+(.#'(,*2*$&"H#$%(+#I&$%#*#'-*'%@ QDir#$2(*$'#SfS#*'#*#4&2(3$926#'(,*2*$92#9"#*--#,-*$G92+'.#&"
L29+#$%(#*,,-&3*$&9".#2('9B23('#*2(#&4("$&G&(4#56#$%( :/#,*$%#,2(G&)@#!"#$%&'#()*+,-(.#$%(#4&*-&"H
*44&$&9"#$9#2(39H"&M&"H#S_S#9"#X&"49I'@#X%("#,2('("$&"H#,*$%'#$9#$%(#B'(2.#I(#3*"#3*--#$%(#'$*$&3
394('#G&-(#%*'#$%(#,*$% :/datafiles/phone-codes.dat#*"4#3*"#5(#2(*4#QB'$#-&T(#*"6#9$%(2#G&-(#B'&"H
GB"3$&9" QDir::convertSeparators()#$9#39"7(2$#'-*'%('#$9#$%(#3922(3$#,-*$G92+D',(3&G&3#'(,*2*$92@
QFile@

j($S'#*44#* main()#GB"3$&9"#$9#9B2#'+*--#,29H2*+
k+5(44&"H#4*$*#&"#$%(#()(3B$*5-(#%*'#$%(#*47*"$*H(#$%*$#&$#3*""9$#H($#-9'$#*"4#+*T('#&$#,9''&5-(#$9
32(*$(#$2B-6#'$*"4D*-9"(#()(3B$*5-('#C&G#'$*$&3#-&"T&"H#&'#*-'9#B'(4E@ AI9#4&'*47*"$*H('#*2(#$%*$#&G#$%(
(+5(44(4#4*$*#"((4'#3%*"H&"H#$%(#I%9-(#()(3B$*5-(#+B'$#5(#2(,-*3(4.#*"4#$%(#'&M(#9G#$%(
int main(int argc, char *argv[])
()(3B$*5-(#I&--#5(#-*2H(2#5(3*B'(#&$#+B'$#*339++94*$(#$%(#(+5(44(4#4*$*@
{
QCoreApplication app(argc, argv);
QStringList args = app.arguments(); \$S'#2('9B23(#'6'$(+#,297&4('#+92(#G(*$B2('#$%*"#I(#,2('("$(4#&"#$%&'#()*+,-(.#&"3-B4&"H#'B,,92$
QString path = QDir::currentPath(); G92#G&-(#"*+(#*-&*'('#*"4#G92#-93*-&M*$&9"@#A%('(#G*3&-&$&('#*2(#493B+("$(4#*$
if (args.count() > 1) %$$, ff493@$29--$(3%@39+f>@1f2('9B23('@%$+-@
path = args[1];
cout << "Space used by images in " << qPrintable(path)
<< " and its subdirectories is " << (imageSpace(path) / 1024) Inter-Process Communication
<< " KB" << endl;
return 0; A%( QProcess#3-*''#*--9I'#B'#$9#2B"#()$(2"*-#,29H2*+'#*"4#$9#&"$(2*3$#I&$%#$%(+@#A%(#3-*''#I92T'
} *'6"3%29"9B'-6.#49&"H#&$'#I92T#&"#$%(#5*3TH29B"4#'9#$%*$#$%(#B'(2#&"$(2G*3(#2(+*&"'#2(',9"'&7(@
QProcess#(+&$'#'&H"*-'#$9#"9$&G6#B'#I%("#$%(#()$(2"*-#,293(''#%*'#4*$*#92#%*'#G&"&'%(4@

X(#B'( QDir::currentPath()#$9#&"&$&*-&M(#$%(#,*$%#$9#$%(#3B22("$#4&2(3$926@#Y-$(2"*$&7(-6.#I(#39B-4 X(#I&--#2(7&(I#$%(#394(#9G#*#'+*--#*,,-&3*$&9"#$%*$#,297&4('#*#B'(2#&"$(2G*3(#G92#*"#()$(2"*-#&+*H(


%*7(#B'(4 QDir::homePath()#$9#&"&$&*-&M(#&$#$9#$%(#B'(2S'#%9+(#4&2(3$926@#!G#$%(#B'(2#%*'#',(3&G&(4#* 39"7(2'&9"#,29H2*+@#L92#$%&'#()*+,-(.#I(#2(-6#9"#$%(#!+*H(d*H&3T convert#,29H2*+.#I%&3%#&'#G2((-6
,*$%#9"#$%(#39++*"4#-&"(.#I(#B'(#$%*$#&"'$(*4@#L&"*--6.#I(#3*--#9B2 imageSpace()#GB"3$&9"#$9 *7*&-*5-(#G92#*--#+*Q92#,-*$G92+'@
3*-3B-*$(#%9I#+B3%#',*3(#&'#39"'B+(4#56#&+*H('@
!"#$%&'()()&12%&345"%&6-*7%$,%$&5008!+5,!-*
A%( QDir#3-*''#,297&4('#9$%(2#G&-(D#*"4#4&2(3$926D2(-*$(4#GB"3$&9"'.#&"3-B4&"H entryInfoList()#CI%&3%
2($B2"' *#-&'$#9G QFileInfo#95Q(3$'E. rename(). exists(). mkdir().#*"4 rmdir()@#A%( QFile#3-*''
,297&4('#'9+(#'$*$&3#39"7("&("3(#GB"3$&9"'.#&"3-B4&"H remove()#*"4 exists()@

Embedding Resources
F9#G*2#&"#$%&'#3%*,$(2#I(#%*7(#$*-T(4#*59B$#*33(''&"H#4*$*#&"#()$(2"*-#4(7&3('.#5B$#I&$%#\$#&$#&'#*-'9
,9''&5-(#$9#(+5(4#5&"*26#4*$*#92#$()$#&"'&4(#$%(#*,,-&3*$&9"S'#()(3B$*5-(@#A%&'#&'#*3%&(7(4#B'&"H#\$S'
2('9B23(#'6'$(+@#!"#9$%(2#3%*,$(2'.#I(#B'(4#2('9B23(#G&-('#$9#(+5(4#&+*H('#&"#$%(#()(3B$*5-(.#5B$
&$#&'#,9''&5-(#$9#(+5(4#*"6#T&"4#9G#G&-(@#k+5(44(4#G&-('#3*"#5(#2(*4#B'&"H QFile#QB'$#-&T(#"92+*-#G&-('
&"#$%(#G&-(#'6'$(+@

g('9B23('#*2(#39"7(2$(4#&"$9#[``#394(#56 rcc.#\$S'#2('9B23(#39+,&-(2@#X(#3*"#$(-- qmake#$9#&"3-B4(


',(3&*-#2B-('#$9#2B" rcc#56#*44&"H#$%&'#-&"(#$9#$%( .pro#G&-(

RESOURCES = myresourcefile.qrc

A%( myresourcefile.qrc#G&-(#&'#*"#idj#G&-(#$%*$#-&'$'#$%(#G&-('#$9#(+5(4#&"#$%(#()(3B$*5-(@

j($S'#&+*H&"(#$%*$#I(#*2(#I2&$&"H#*"#*,,-&3*$&9"#$%*$#T((,'#39"$*3$#4($*&-'@#L92#$%(#39"7("&("3(#9G
A%(#B'(2#&"$(2G*3(#I*'#32(*$(4#&" !"-4&*)5 &%@#A%( .ui#G&-(#&'#9"#$%(#[h#$%*$#*339+,*"&('#$%&'
9B2#B'(2'.#I(#I*"$#$9#(+5(4#$%(#&"$(2"*$&9"*-#4&*-&"H#394('#&"#$%(#()(3B$*5-(@#!G#$%(#G&-(#&'#&"#$%(
datafiles#4&2(3$926#&"#$%(#*,,-&3*$&9"S'#5B&-4#4&2(3$926.#$%(#2('9B23(#G&-(#+&H%$#-99T#-&T(#$%&'
599T@#Z(2(.#I(#I&--#G93B'#9"#$%( 'B53-*''#$%*$#&"%(2&$'#G29+#$%( uicDH("(2*$(4 Ui::ConvertDialog
3-*''.#'$*2$&"H#I&$%#$%(#%(*4(2 }

#ifndef CONVERTDIALOG_H A%(#R29I'(#5B$$9"S' clicked()#'&H"*-#&'#*B$9+*$&3*--6#39""(3$(4#$9#$%( on_browseButton_clicked()


#define CONVERTDIALOG_H '-9$#56 setupUi()@#!G#$%(#B'(2#%*'#,2(7&9B'-6#'(-(3$(4#*#G&-(.#I(#&"&$&*-&M(#$%(#G&-(#4&*-9H#I&$%#$%*$#G&-(S'
#include <QDialog>
"*+(V#9$%(2I&'(.#I(#B'(#$%(#B'(2S'#%9+(#4&2(3$926@
#include <QProcess>
#include "ui_convertdialog.h"
class ConvertDialog : public QDialog, public Ui::ConvertDialog
{ void ConvertDialog::on_convertButton_clicked()
Q_OBJECT {
public: QString sourceFile = sourceFileEdit->text();
ConvertDialog(QWidget *parent = 0); targetFile = QFileInfo(sourceFile).path() + QDir::separator()
private slots: + QFileInfo(sourceFile).baseName() + "."
void on_browseButton_clicked(); + targetFormatComboBox->currentText().toLower();
void on_convertButton_clicked(); convertButton->setEnabled(false);
void updateOutputTextEdit(); outputTextEdit->clear();
void processFinished(int exitCode, QProcess::ExitStatus exitStatus); QStringList args;
void processError(QProcess::ProcessError error); if (enhanceCheckBox->isChecked())
private: args << "-enhance";
QProcess process; if (monochromeCheckBox->isChecked())
QString targetFile; args << "-monochrome";
}; args << sourceFile << targetFile;
#endif process.start("convert", args);
}

A%(#%(*4(2#G9--9I'#$%(#G*+&-&*2#,*$$(2"#G92#'B53-*''('#9G !"-4&*)5 &%#G92+'@#A%*"T'#$9 !"


4&*)5 &%S'#*B$9+*$&3#39""(3$&9"#+(3%*"&'+#C,@#8^E.#$%( on_browseButton_clicked()#*"4 X%("#$%(#B'(2#3-&3T'#$%(#[9"7(2$#5B$$9".#I(#39,6#$%(#'9B23(#G&-(S'#"*+(#*"4#3%*"H(#$%(#()$("'&9"
$9#+*$3%#$%(#$*2H($#G&-(#G92+*$@#X(#B'(#$%(#,-*$G92+D',(3&G&3#4&2(3$926#'(,*2*$92#CSfS#92#S_S.#*7*&-*5-(
on_convertButton_clicked()#'-9$'#*2(#*B$9+*$&3*--6#39""(3$(4#$9#$%(#R29I'(#*"4#[9"7(2$#5B$$9"'S
*' QDir::separator()E#&"'$(*4#9G#%*24D394&"H#'-*'%('#5(3*B'(#$%(#G&-(#"*+(#I&--#5(#7&'&5-(#$9#$%(
clicked()#'&H"*-'@
B'(2@

ConvertDialog::ConvertDialog(QWidget *parent) X(#$%("#4&'*5-(#$%( Convert#5B$$9"#$9#*79&4#$%(#B'(2#*33&4("$*--6#-*B"3%&"H#+B-$&,-(#39"7(2'&9"'.


: QDialog(parent) *"4#I(#3-(*2#$%(#$()$#(4&$#$%*$#I(#B'(#$9#'%9I#'$*$B'#&"G92+*$&9"@
{
setupUi(this); A9#&"&$&*$(#$%(#()$(2"*-#,293(''.#I(#3*-- QProcess::start()#I&$%#$%(#"*+(#9G#$%(#,29H2*+#I(#I*"$#$9
connect(&process, SIGNAL(readyReadStandardError()), 2B"#CconvertE#*"4#*"6#*2HB+("$'#&$#2(WB&2('@#!"#$%&'#3*'(#I(#,*''#$%( -enhance#*"4 -monochrome
this, SLOT(updateOutputTextEdit())); G-*H'#&G#$%(#B'(2#3%(3T(4#$%(#*,,29,2&*$(#9,$&9"'.#G9--9I(4#56#$%(#'9B23(#*"4#$*2H($#G&-(#"*+('@#A%(
connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)),
convert#,29H2*+#&"G(2'#$%(#2(WB&2(4#39"7(2'&9"#G29+#$%(#G&-(#()$("'&9"'@
this, SLOT(processFinished(int, QProcess::ExitStatus)));
connect(&process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError(QProcess::ProcessError)));
} void ConvertDialog::updateOutputTextEdit()
{
QByteArray newData = process.readAllStandardError();
QString text = outputTextEdit->toPlainText()
A%( setupUi()#3*--#32(*$('#*"4#-*6'#9B$#*--#$%(#G92+S'#I&4H($'.#('$*5-&'%('#$%(#'&H"*-'-9$#39""(3$&9"' + QString::fromLocal8Bit(newData);
G92#$%( on_objectName_signalName()#'-9$'.#*"4#39""(3$'#$%(#\B&$#5B$$9"#$9 QDialog::accept()@#YG$(2 outputTextEdit->setPlainText(text);
$%*$.#I(#+*"B*--6#39""(3$#$%2((#'&H"*-'#G29+#$%( QProcess#95Q(3$#$9#$%2((#,2&7*$(#'-9$'@#X%("(7(2 }
$%(#()$(2"*-#,293(''#%*'#4*$*#9"#&$' cerr.#I(#I&--#%*"4-(#&$#&" updateOutputTextEdit()@

X%("(7(2#$%(#()$(2"*-#,293(''#I2&$('#$9 cerr.#$%( updateOutputTextEdit()#'-9$#&'#3*--(4@#X(#2(*4#$%(


void ConvertDialog::on_browseButton_clicked() (2292#$()$#*"4#*44#&$#$9#$%( QTextEditS'#()&'$&"H#$()$@
{
QString initialName = sourceFileEdit->text();
if (initialName.isEmpty())
void ConvertDialog::processFinished(int exitCode,
initialName = QDir::homePath();
QProcess::ExitStatus exitStatus)
QString fileName =
{
QFileDialog::getOpenFileName(this, tr("Choose File"),
if (exitStatus == QProcess::CrashExit) {
initialName);
outputTextEdit->append(tr("Conversion program crashed"));
fileName = QDir::convertSeparators(fileName);
} else if (exitCode != 0) {
if (!fileName.isEmpty()) {
outputTextEdit->append(tr("Conversion failed"));
sourceFileEdit->setText(fileName);
} else {
convertButton->setEnabled(true);
outputTextEdit->append(tr("File %1 created").arg(targetFile));
}
} 4(-($('#$%(#$(+,92*26#G&-(#I%("#$%(#95Q(3$#H9('#9B$#9G#'39,(@
convertButton->setEnabled(true);
}
F&H"*-'-9$#39""(3$&9"'#*2(#"9$#"((4(4#I%(" QProcess#&'#B'(4#'6"3%29"9B'-6@#!G#G&"(2#39"$29-#&'
2(WB&2(4#$%*"#,297&4(4#56#$%(#'$*$&3 execute()#GB"3$&9".#I(#3*"#B'(#*"#*-$(2"*$&7(#*,,29*3%@#A%&'
&"79-7('#32(*$&"H#* QProcess#95Q(3$#*"4#3*--&"H start()#9"#&$.#*"4#$%("#G923&"H#&$#$9#5-93T#56#3*--&"H
X%("#$%(#,293(''#%*'#G&"&'%(4.#I(#-($#$%(#B'(2#T"9I#$%(#9B$39+(#*"4#("*5-(#$%(#[9"7(2$#5B$$9"@ QProcess::waitFor-Started().#*"4#&G#$%*$#&'#'B33(''GB-.#3*--&"H QProcess::waitForFinished()@#F((#$%(
QProcess#2(G(2("3(#493B+("$*$&9"#G92#*"#()*+,-(#$%*$#B'('#$%&'#*,,29*3%@

void ConvertDialog::processError(QProcess::ProcessError error)


{ !"#$%&'#'(3$&9".#I(#B'(4 QProcess#$9 H&7(#B'#*33(''#$9#,2(()&'$&"H#GB"3$&9"*-&$6@#J'&"H#*,,-&3*$&9"'
if (error == QProcess::FailedToStart) { $%*$#*-2(*46#()&'$#3*"#'*7(#4(7(-9,+("$#$&+(#*"4#3*"#&"'B-*$(#B'#G29+#$%(#4($*&-'#9G#&''B('#$%*$#*2(
outputTextEdit->append(tr("Conversion program not found")); 9G#+*2H&"*-#&"$(2('$#$9#9B2#+*&"#*,,-&3*$&9"S'#,B2,9'(@#Y"9$%(2#I*6#$9#*33(''#,2(()&'$&"H
convertButton->setEnabled(true); GB"3$&9"*-&$6#&'#$9#-&"T#*H*&"'$#*#-&52*26#$%*$#,297&4('#&$@#RB$#I%(2(#"9#'B&$*5-(#-&52*26#()&'$'.
} I2*,,&"H#*#39"'9-(#*,,-&3*$&9"#B'&"H QProcess#3*"#I92T#I(--@
}
Y"9$%(2#B'(#9G QProcess#&'#$9#-*B"3%#9$%(2#cJ!#*,,-&3*$&9"'.#'B3%#*'#*#I(5#529I'(2#92#*"#(+*&-
3-&("$@#Z9I(7(2.#&G#9B2#*&+#&'#39++B"&3*$&9"#5($I(("#*,,-&3*$&9"'#2*$%(2#$%*"#'&+,-6#2B""&"H#9"(
!G#$%(#,293(''#3*""9$#5(#'$*2$(4. QProcess#(+&$' error()#&"'$(*4#9G finished()@#X(#2(,92$#*"6#(2292 G29+#*"9$%(2.#I(#+&H%$#5(#5($$(2#9GG#%*7&"H#$%(+#39++B"&3*$(#4&2(3$-6.#B'&"H#\$S'#"($I92T&"H
*"4#("*5-(#$%( Click#5B$$9"@ 3-*''('#92#$%(#Y3$&7(\$#()$("'&9"#9"#X&"49I'@

!"#$%&'#()*+,-(.#I(#%*7(#,(2G92+(4#$%(#G&-(#39"7(2'&9"'#*'6"3%29"9B'-6$%*$#&'.#I(#%*7(#$9-4
QProcess#$9#2B"#$%( convert#,29H2*+#*"4#$9#2($B2"#39"$29-#$9#$%(#*,,-&3*$&9"#&++(4&*$(-6@#A%&'#T((,'
$%(#B'(2#&"$(2G*3(#2(',9"'&7(#I%&-(#$%(#,293(''&"H#933B2'#&"#$%(#5*3TH29B"4@#RB$#&"#'9+(#'&$B*$&9"'
I(#"((4#$%(#()$(2"*-#,293(''#$9#39+,-($(#5(G92(#I(#3*"#H9#*"6#GB2$%(2#&"#9B2#*,,-&3*$&9".#*"4#&"
'B3%#3*'('#I(#"((4 QProcess#$9#9,(2*$(#'6"3%29"9B'-6@

K"(#39++9"#()*+,-(#I%(2(#'6"3%29"9B'#5(%*7&92#&'#4('&2*5-(#&'#G92#*,,-&3*$&9"'#$%*$#'B,,92$#,-*&"
$()$#(4&$&"H#B'&"H#$%(#B'(2S'#,2(G(22(4#$()$#(4&$92@#A%&'#&'#'$2*&H%$G92I*24#$9#&+,-(+("$#B'&"H
QProcess@#L92#()*+,-(.#-($S'#*''B+(#$%*$#I(#%*7(#$%(#,-*&"#$()$#&"#* QTextEdit.#*"4#,297&4(#*"#k4&$
5B$$9"#$%*$#$%(#B'(2#3*"#3-&3T.#39""(3$(4#$9#*" edit()#'-9$@

void ExternalEditor::edit()
{
QTemporaryFile outFile;
if (!outFile.open())
return;
QString fileName = outFile.fileName();
QTextStream out(&outFile);
out << textEdit->toPlainText();
outFile.close();
QProcess::execute(editor, QStringList() << options << fileName);
QFile inFile(fileName);
if (!inFile.open(QIODevice::ReadOnly))
return;
QTextStream in(&inFile);
textEdit->setPlainText(in.readAll());
}

X(#B'( QTemporaryFile#$9#32(*$(#*"#(+,$6#G&-(#I&$%#*#B"&WB(#"*+(@#X(#49"S$#',(3&G6#*"6#*2HB+("$'
$9 QTemporaryFile::open()#'&"3(#&$#39"7("&("$-6#4(G*B-$'#$9#9,("&"H#&"#2(*4fI2&$(#+94(@#X(#I2&$(#$%(
39"$("$'#9G#$%(#$()$#(4&$#$9#$%(#$(+,92*26#G&-(.#*"4#$%("#I(#3-9'(#$%(#G&-(#5(3*B'(#'9+(#$()$#(4&$92'
3*""9$#I92T#9"#*-2(*46#9,("#G&-('@

A%( QProcess::execute()#'$*$&3#GB"3$&9"#2B"'#*"#()$(2"*-#,293(''#*"4#5-93T'#B"$&-#$%(#,293(''#%*'
G&"&'%(4@#A%( editor#*2HB+("$#&'#* QString#%9-4&"H#$%(#"*+(#9G#*"#(4&$92#()(3B$*5-(#CG92#()*+,-(.
/H7&+/E@#A%( options#*2HB+("$#&'#* QStringList#C39"$*&"&"H#9"(#&$(+.#/DG/.#&G#I(#*2(#B'&"H gvimE@

YG$(2#$%(#B'(2#%*'#3-9'(4#$%(#$()$#(4&$92.#$%(#,293(''#G&"&'%('#*"4#$%( execute()#3*--#2($B2"'@#X(
$%("#9,("#$%(#$(+,92*26#G&-(#*"4#2(*4#&$'#39"$("$'#&"$9#$%( QTextEdit@ QTemporaryFile#*B$9+*$&3*--6
db.setHostName("mozart.konkordia.edu");
db.setDatabaseName("musicdb");
Chapter 13. Databases db.setUserName("gbatstone");
db.setPassword("T17aV44");
if (!db.open()) {
• ;3%%!2*$%&'"%#'<7!),$%& QMessageBox::critical(0, QObject::tr("Database Error"),
• :)!1!%*$%&'-"*"'$%'."67=")'>3)5 db.lastError().text());
• 85?=!5!%*$%&'@"1*!)-!*"$='>3)51 return false;
}
return true;
A%( !"67/#+94B-(#,297&4('#*#,-*$G92+D#*"4#4*$*5*'(D&"4(,("4("$#&"$(2G*3(#G92#*33(''&"H#F\j
}
4*$*5*'('@#A%&'#&"$(2G*3(#&'#'B,,92$(4#56#*#'($#9G#3-*''('#$%*$#B'(#\$S'#+94(-f7&(I#*23%&$(3$B2(#$9
,297&4(#4*$*5*'(#&"$(H2*$&9"#I&$%#$%(#B'(2#&"$(2G*3(@#A%&'#3%*,$(2#*''B+('#G*+&-&*2&$6#I&$%#\$S'
+94(-f7&(I#3-*''('.#397(2(4#&" [%*,$(2#1=@
L&2'$.#I(#3*-- QSqlDatabase::addDatabase()#$9#32(*$(#* QSqlDatabase#95Q(3$@#A%(#G&2'$#*2HB+("$#$9
Y#4*$*5*'(#39""(3$&9"#&'#2(,2('("$(4#56#* QSqlDatabase#95Q(3$@#\$#B'('#42&7(2'#$9#39++B"&3*$(#I&$% addDatabase()#',(3&G&('#I%&3%#4*$*5*'(#42&7(2#\$#+B'$#B'(#$9#*33(''#$%(#4*$*5*'(@#!"#$%&'#3*'(.#I(
$%(#7*2&9B'#4*$*5*'(#Y]!'@ A%(#\$#h('T$9,#k4&$&9"#&"3-B4('#$%(#G9--9I&"H#42&7(2' B'(#d6F\j@

b()$.#I(#'($#$%(#4*$*5*'(#%9'$#"*+(.#$%(#4*$*5*'(#"*+(.#$%(#B'(2#"*+(.#*"4#$%(#,*''I924.#*"4
9$!7%$ 95,5:5.% I(#9,("#$%(#39""(3$&9"@#!G open()#G*&-'.#I(#'%9I#*"#(2292#+(''*H(@
\hR8 !Rd#hR8#7(2'&9"#?@1*"4#-*$(2
A6,&3*--6.#I(#I9B-4#3*-- createConnection()#&" main()
\!RYFk R92-*"4#!"$(2R*'(
\dmF\j d6F\j int main(int argc, char *argv[])
{
\K[! K2*3-(#CK2*3-(#[*--#!"$(2G*3(E QApplication app(argc, argv);
if (!createConnection())
\KhR[ KhR[#C&"3-B4('#d&329'9G$#F\j#F(27(2E return 1;
...
\]F\j ]9'$H2(F\j#7(2'&9"'#e@)#*"4#?@) return app.exec();
}
\F\j!Ak F\j&$(#7(2'&9"#:#*"4#-*$(2
\F\j!Ak8 F\j&$(#7(2'&9"#8
K"3(#*#39""(3$&9"#&'#('$*5-&'%(4.#I(#3*"#B'( QSqlQuery#$9#()(3B$(#*"6#F\j#'$*$(+("$#$%*$#$%(
\AhF F65*'(#Y4*,$&7(#F(27(2 B"4(2-6&"H#4*$*5*'(#'B,,92$'@#L92#()*+,-(.#%(2(S'#%9I#$9#()(3B$(#* SELECT#'$*$(+("$

QSqlQuery query;
hB(#$9#-&3("'(#2('$2&3$&9"'.#"9$#*--#9G#$%(#42&7(2'#*2(#,297&4(4#I&$%#$%(#\$#K,("#F9B23(#k4&$&9"@#X%("
query.exec("SELECT title, year FROM cd WHERE year >= 1998");
39"G&HB2&"H#\$.#I(#3*"#3%99'(#5($I(("#&"3-B4&"H#$%(#F\j#42&7(2'#&"'&4(#\$#&$'(-G#*"4#5B&-4&"H#$%(+
*'#,-BH&"'@#\$#&'#'B,,-&(4#I&$%#$%(#F\j&$(#4*$*5*'(.#*#,B5-&3#49+*&"#&"D,293(''#4*$*5*'(@

L92#B'(2'#I%9#*2(#39+G92$*5-(#I&$%#F\j#'6"$*).#$%( QSqlQuery#3-*''#,297&4('#*#+(*"'#9G#4&2(3$-6 YG$(2#$%( exec()#3*--.#I(#3*"#"*7&H*$(#$%29BH%#$%(#WB(26S'#2('B-$#'($


()(3B$&"H#*25&$2*26#F\j#'$*$(+("$'#*"4#%*"4-&"H#$%(&2#2('B-$'@#L92#B'(2'#I%9#,2(G(2#*#%&H%(2D-(7(-
4*$*5*'(#&"$(2G*3(#$%*$#*79&4'#F\j#'6"$*). QSqlTableModel#*"4 QSqlRelationalTableModel#,297&4(
while (query.next()) {
'B&$*5-(#*5'$2*3$&9"'@#A%('(#3-*''('#2(,2('("$#*"#F\j#$*5-(#&"#$%(#'*+(#I*6#*'#\$S'#9$%(2#+94(-
QString title = query.value(0).toString();
3-*''('#C397(2(4#&" [%*,$(2#1=E@#A%(6#3*"#5(#B'(4#'$*"4D*-9"(#$9#$2*7(2'(#*"4#(4&$#4*$*#&"#394(.#92 int year = query.value(1).toInt();
$%(6#3*"#5(#*$$*3%(4#$9#7&(I'#$%29BH%#I%&3%#("4DB'(2'#3*"#7&(I#*"4#(4&$#$%(#4*$*#$%(+'(-7('@ cerr << qPrintable(title) << ": " << year << endl;
}
\$#*-'9#+*T('#&$#'$2*&H%$G92I*24#$9#,29H2*+#$%(#39++9"#4*$*5*'(#&4&9+'.#'B3%#*'#+*'$(24($*&-#*"4
42&--D49I".#*'#'9+(#9G#$%(#()*+,-('#&"#$%&'#3%*,$(2#I&--#4(+9"'$2*$(@
X(#3*-- next()#9"3(#$9#,9'&$&9"#$%( QSqlQuery#9"#$%( 3)%*"#2(3924#9G#$%(#2('B-$#'($@#FB5'(WB("$#3*--'
Connecting and Querying $9 next()#*47*"3(#$%(#2(3924#,9&"$(2#56#9"(#2(3924#(*3%#$&+(.#B"$&-#$%(#("4#&'#2(*3%(4.#*$#I%&3%
,9&"$ next()#2($B2"' false@#!G#$%(#2('B-$#'($#&'#(+,$6#C92#&G#$%(#WB(26#G*&-(4E.#$%(#G&2'$#3*--#$9 next()
A9#()(3B$(#F\j#WB(2&('.#I(#+B'$#G&2'$#('$*5-&'%#*#39""(3$&9"#I&$%#*#4*$*5*'(@#A6,&3*--6.#4*$*5*'( I&--#2($B2" false@
39""(3$&9"'#*2(#'($#B,#&"#*#'(,*2*$(#GB"3$&9"#$%*$#I(#3*--#*$#*,,-&3*$&9"#'$*2$B,@#L92#()*+,-(
A%( value()#GB"3$&9"#2($B2"'#$%(#7*-B(#9G#*#G&(-4#*'#* QVariant@#A%(#G&(-4'#*2(#"B+5(2(4#G29+#=#&"
$%(#924(2#H&7("#&"#$%( SELECT#'$*$(+("$@#A%( QVariant#3-*''#3*"#%9-4#+*"6#[``#*"4#\$#$6,('.
bool createConnection() &"3-B4&"H int#*"4 QString@#A%(#4&GG(2("$#$6,('#9G#4*$*#$%*$#3*"#5(#'$92(4#&"#*#4*$*5*'(#*2(#+*,,(4
{ &"$9#$%(#3922(',9"4&"H#[``#*"4#\$#$6,('#*"4#'$92(4#&" QVariant'@#L92#()*+,-(.#* VARCHAR#&'
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
2(,2('("$(4#*'#* QString#*"4#* DATETIME#*'#* QDateTime@ query.addBindValue(102);
query.addBindValue("Living in America");
query.addBindValue(2002);
QSqlQuery#,297&4('#'9+(#9$%(2#GB"3$&9"'#$9#"*7&H*$(#$%29BH%#$%(#2('B-$#'($ first(). last().
query.exec();
previous().#*"4 seek()@#A%('(#GB"3$&9"'#*2(#39"7("&("$.#5B$#G92#'9+(#4*$*5*'('#$%(6#3*"#5(#'-9I(2
*"4#+92(#+(+926D%B"H26#$%*" next()@#L92#*"#(*'6#9,$&+&M*$&9"#I%("#9,(2*$&"H#9"#-*2H(#4*$*#'($'.
I(#3*"#3*-- QSqlQuery::setForwardOnly(true)#5(G92(#3*--&"H exec().#*"4#$%("#9"-6#B'( next()#G92
"*7&H*$&"H#$%(#2('B-$#'($@ !"#$%"&#%'())%"* exec()+%,#%'(-%'()) bindValue()%*$ addBindValue()%"*%./-0%-#,%1()2#3+%"&#-%'())
exec()%(4(/-%"*%#5#'2"#%"&#%62#$7%,/"&%"&#%-#,%1()2#38

k*2-&(2#I(#',(3&G&(4#$%(#F\j#WB(26#*'#*"#*2HB+("$#$9 QSqlQuery::exec().#5B$#I(#3*"#*-'9#,*''#&$
4&2(3$-6#$9#$%(#39"'$2B3$92.#I%&3%#()(3B$('#&$#&++(4&*$(-6 9)('#&*)0#$3%($#%*!"#-%23#0%"*%3:#'/!7%./-($7%0("(%*$%3"$/-43%"&("%'*-"(/-%-*-; <=>>%*$%-*-;?("/-;@
'&($('"#$38%A#&/-0%"&#%3'#-#3+%B"%23#3%C-/'*0#%,/"&%"&*3#%0("(.(3#3%"&("%32::*$"%C-/'*0#+%(-0%!*$
"&*3#%"&("%0*-D"+%B"%"$(-3:($#-")7%'*-1#$"3%3"$/-43%"*%"&#%(::$*:$/("#%#-'*0/-48
QSqlQuery query("SELECT title, year FROM cd WHERE year >= 1998");
B"%32::*$"3%<B?%"$(-3('"/*-3%*-%0("(.(3#3%,&#$#%"&#7%($#%(1(/)(.)#8%E*%3"($"%(%"$(-3('"/*-+%,#%'())
transaction()%*-%"&# QSqlDatabase%*.F#'"%"&("%$#:$#3#-"3%"&#%0("(.(3#%'*--#'"/*-8%E*%!/-/3&%"&#
"$(-3('"/*-+%,#%'())%#/"&#$ commit()%*$ rollback()8%G*$%#5(H:)#+%&#$#D3%&*,%,#%,*2)0 )**I%2:%(
X(#3*"#3%(3T#G92#*"#(2292#56#3*--&"H isActive()#9"#$%(#WB(26
!*$#/4-%I#7%(-0%#5#'2"#%(- INSERT%3"("#H#-"%/-3/0#%(%"$(-3('"/*-J

if (!query.isActive())
QMessageBox::warning(this, tr("Database Error"), QSqlDatabase::database().transaction();
query.lastError().text()); QSqlQuery query;
query.exec("SELECT id FROM artist WHERE name = 'Gluecifer'");
if (query.next()) {
int artistId = query.value(0).toInt();
!G#"9#(2292#933B2'.#$%(#WB(26#I&--#5(39+(#/*3$&7(/#*"4#I(#3*"#B'( next()#$9#"*7&H*$(#$%29BH%#$%( query.exec("INSERT INTO cd (id, artistid, title, year) "
2('B-$#'($@ "VALUES (201, " + QString::number(artistId)
+ ", 'Riding the Tiger', 1997)");
h9&"H#*" INSERT#&'#*-+9'$#*'#(*'6#*'#,(2G92+&"H#* SELECT }
QSqlDatabase::database().commit();

QSqlQuery query("INSERT INTO cd (id, artistid, title, year) "


"VALUES (203, 102, 'Living in America', 2002)"); E&# QSqlDatabase::database()%!2-'"/*-%$#"2$-3 ( QSqlDatabase%*.F#'"%$#:$#3#-"/-4%"&#%'*--#'"/*-%,#
'$#("#0%/- createConnection()8%>!%(%"$(-3('"/*-%'(--*"%.#%3"($"#0+ QSqlDatabase::transaction()
$#"2$-3 false8%<*H#%0("(.(3#3%0*-D"%32::*$"%"$(-3('"/*-38%G*$%"&*3#+%"&# transaction()+ commit()+
YG$(2#$%&'. numRowsAffected()#2($B2"'#$%(#"B+5(2#9G#29I'#$%*$#I(2(#*GG(3$(4#56#$%(#F\j#'$*$(+("$ (-0 rollback()%!2-'"/*-3%0*%-*"&/-48%K#%'(-%"#3"%,&#"&#$%(%0("(.(3#%32::*$"3%"$(-3('"/*-3%23/-4
C92 D1#9"#(2292E@ hasFeature()%*-%"&# QSqlDriver%(33*'/("#0%,/"&%"&#%0("(.(3#J

!G#I(#"((4#$9#&"'(2$#*#-9$#9G#2(3924'.#92#&G#I(#I*"$#$9#*79&4#39"7(2$&"H#7*-B('#$9#'$2&"H'#C*"4
('3*,&"H#$%(+#3922(3$-6E.#I(#3*"#B'( prepare()#$9#',(3&G6#*#WB(26#$%*$#39"$*&"'#,-*3(%9-4(2'#*"4 QSqlDriver *driver = QSqlDatabase::database().driver();
if (driver->hasFeature(QSqlDriver::Transactions))
$%("#5&"4#$%(#7*-B('#I(#I*"$#$9#&"'(2$@#\$#'B,,92$'#59$%#$%(#K2*3-(D'$6-(#*"4#$%(#KhR[D'$6-(#'6"$*)
...
G92#,-*3(%9-4(2'#G92#*--#4*$*5*'('.#B'&"H#"*$&7(#'B,,92$#I%(2(#&$#&'#*7*&-*5-(#*"4#'&+B-*$&"H#&$
9$%(2I&'(@#Z(2(S'#*"#()*+,-(#$%*$#B'('#$%(#K2*3-(D'$6-(#'6"$*)#I&$%#"*+(4#,-*3(%9-4(2'

<#1#$()%*"&#$%0("(.(3#%!#("2$#3%'(-%.#%"#3"#0%!*$+%/-')20/-4%,&#"&#$%"&#%0("(.(3#%32::*$"3%A?LA3
QSqlQuery query; MA/-($7%?($4#%L.F#'"3N+%C-/'*0#+%(-0%:$#:($#0%62#$/#38
query.prepare("INSERT INTO cd (id, artistid, title, year) "
"VALUES (:id, :artistid, :title, :year)"); >-%"&#%#5(H:)#3%3*%!($+%,#%&(1#%(332H#0%"&("%"&#%(::)/'("/*-%/3%23/-4%(%3/-4)#%0("(.(3#%'*--#'"/*-8
query.bindValue(":id", 203); >!%,#%,(-"%"*%'$#("#%H2)"/:)#%'*--#'"/*-3+%,#%'(-%:(33%(%-(H#%(3%3#'*-0%($42H#-"%"*
query.bindValue(":artistid", 102); addDatabase()8%G*$%#5(H:)#J
query.bindValue(":title", "Living in America");
query.bindValue(":year", 2002);
query.exec();
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL", "OTHER");
db.setHostName("saturn.mcmanamy.edu");
db.setDatabaseName("starsdb");
Z(2(S'#$%(#'*+(#()*+,-(#B'&"H#KhR[D'$6-(#,9'&$&9"*-#,-*3(%9-4(2' db.setUserName("hilbert");
db.setPassword("ixtapa7");

QSqlQuery query;
query.prepare("INSERT INTO cd (id, artistid, title, year) " K#%'(-%"&#-%$#"$/#1#%(%:*/-"#$%"*%"&# QSqlDatabase%*.F#'"%.7%:(33/-4%"&#%-(H#%"*
"VALUES (?, ?, ?, ?)");
QSqlDatabase::database()J
query.addBindValue(203);
QSqlDatabase db = QSqlDatabase::database("OTHER");
E*%/-3#$"%(%$#'*$0%/-"*%(%0("(.(3#%"(.)#+%,#%23#%"&#%3(H#%(::$*('&%(3%,# ,*2)0%/-3#$"/-4%/-"*%(-7
",*;0/H#-3/*-()%H*0#)J%G/$3"+%,#%'()) insertRow()%"*%'$#("#%(%-#,%#H:"7%$*,%M$#'*$0N+%(-0%"&#-%,#
E*%#5#'2"#%62#$/#3%23/-4%"&#%*"&#$%'*--#'"/*-+%,#%:(33%"&# QSqlDatabase%*.F#'"%"*%"&# QSqlQuery 23# setData()%"*%3#"%"&#%1()2#3%*!%#('&%'*)2H-%M!/#)0N8
'*-3"$2'"*$J

QSqlTableModel model;
QSqlQuery query(db); model.setTable("cd");
query.exec("SELECT id FROM artist WHERE name = 'Mando Diao'"); int row = 0;
model.insertRows(row, 1);
model.setData(model.index(row, 0), 113);
model.setData(model.index(row, 1), "Shanghai My Heart");
O2)"/:)#%'*--#'"/*-3%($#%23#!2)%/!%,#%,(-"%"*%:#$!*$H%H*$#%"&(-%*-#%"$(-3('"/*-%("%(%"/H#+%3/-'#
model.setData(model.index(row, 2), 224);
#('&%'*--#'"/*-%'(-%*-)7%&(-0)#%(%3/-4)#%('"/1#%"$(-3('"/*-8%K&#-%,#%23#%H2)"/:)#%0("(.(3#
model.setData(model.index(row, 3), 2003);
'*--#'"/*-3+%,#%'(-%3"/))%&(1#%*-#%2--(H#0%'*--#'"/*-+%(-0 QSqlQuery%,/))%23#%"&("%'*--#'"/*-%/! model.submitAll();
-*-#%/3%3:#';/!/#08

>-%(00/"/*-%"* QSqlQuery+%B"%:$*1/0#3%"&# QSqlTableModel%')(33%(3%(%&/4&#$;)#1#)%/-"#$!('#+%())*,/-4%23


!"#$%"&#%'())%"* submitAll()+%"&#%$#'*$0%H/4&" .#%H*1#0%"*%(%0/!!#$#-"%$*,%:*3/"/*-+%0#:#-0/-4%*-
"*%(1*/0%23/-4%$(,%<B?%!*$%:#$!*$H/-4%"&#%H*3"%'*HH*-%<B?%*:#$("/*-3%M SELECT+ INSERT+ UPDATE+
&*,%"&#%"(.)#%/3%*$0#$#08%E&# submitAll()%'())%,/))%$#"2$- false%/!%"&#%/-3#$"/*-%!(/)#08
(-0 DELETEN8%E&#%')(33%'(-%.#%23#0%3"(-0;()*-#%"*%H(-/:2)("#%(%0("(.(3#%,/"&*2"%(-7%PC>
/-1*)1#H#-"+%*$%/"%'(-%.#%23#0%(3%(%0("(%3*2$'#%!*$ QListView%*$ QTableView8
-%/H:*$"(-"%0/!!#$#-'#%.#",##-%(-%<B?%H*0#)%(-0%(%3"(-0($0%H*0#)%/3%"&("%!*$%(-%<B?%H*0#)%,#
H23"%'()) submitAll()%"*%&(1#%(-7%'&(-4#3%,$/""#-%"*%"&#%0("(.(3#8
Q#$#D3%(-%#5(H:)#%"&("%23#3 QSqlTableModel%"*%:#$!*$H%( SELECTJ
E*%2:0("#%(%$#'*$0+%,#%H23"%!/$3"%:*3/"/*-%"&# QSqlTableModel%*-%"&#%$#'*$0%,#%,(-"%"*%H*0/!7%M!*$
QSqlTableModel model; #5(H:)#+%23/-4 select()N8%K#%"&#-%#5"$('"%"&#%$#'*$0+%2:0("#%"&#%!/#)03%,#%,(-"%"*%'&(-4#+%(-0
model.setTable("cd"); ,$/"#%*2$%'&(-4#3%.('I%"*%"&#%0("(.(3#J
model.setFilter("year >= 1998");
model.select();
QSqlTableModel model;
model.setTable("cd");
model.setFilter("id = 125");
E&/3%/3%#62/1()#-"%"*%"&#%62#$7 model.select();
if (model.rowCount() == 1) {
QSqlRecord record = model.record(0);
SELECT * FROM cd WHERE year >= 1998 record.setValue("title", "Melody A.M.");
record.setValue("year", record.value("year").toInt() + 1);
model.setRecord(0, record);
R(1/4("/-4%"&$*24&%"&#%$#32)"%3#"%/3%0*-#%.7%$#"$/#1/-4%(%4/1#-%$#'*$0%23/-4 model.submitAll();
}
QSqlTableModel::record()%(-0%.7%(''#33/-4%/-0/1/02()%!/#)03%23/-4 value()J

for (int i = 0; i < model.rowCount(); ++i) { >!%"&#$#%/3%(%$#'*$0%"&("%H("'&#3%"&#%3:#'/!/#0%!/)"#$+%,#%$#"$/#1#%/"%23/-4 QSqlTableModel::record()8


QSqlRecord record = model.record(i); K#%(::)7%*2$%'&(-4#3%(-0%*1#$,$/"#%"&#%*$/4/-()%$#'*$0%,/"&%*2$%H*0/!/#0%$#'*$08
QString title = record.value("title").toString();
int year = record.value("year").toInt(); >"%/3%()3*%:*33/.)#%"*%:#$!*$H%(-%2:0("#%23/-4 setData()+%F23"%(3%,#%,*2)0%0*%!*$%(%-*-;<B?%H*0#)8
cerr << qPrintable(title) << ": " << year << endl; E&#%H*0#)%/-0#5#3%"&("%,#%$#"$/#1#%($#%!*$%(%4/1#-%$*,%(-0%'*)2H-J
}

model.select();
E&# QSqlRecord::value()%!2-'"/*-%"(I#3%#/"&#$%(%!/#)0%-(H#%*$%(%!/#)0%/-0#58%K&#-%*:#$("/-4%*-%)($4# if (model.rowCount() == 1) {
0("(%3#"3+%/"%/3%$#'*HH#-0#0%"&("%!/#)03%($#%3:#'/!/#0%.7%"&#/$%/-0#5#38%G*$%#5(H:)#J model.setData(model.index(0, 1), "Melody A.M.");
model.setData(model.index(0, 3),
model.data(model.index(0, 3)).toInt() + 1);
int titleIndex = model.record().indexOf("title"); model.submitAll();
int yearIndex = model.record().indexOf("year"); }
for (int i = 0; i < model.rowCount(); ++i) {
QSqlRecord record = model.record(i);
QString title = record.value(titleIndex).toString(); S#)#"/-4%(%$#'*$0%/3%3/H/)($%"*%2:0("/-4J
int year = record.value(yearIndex).toInt();
cerr << qPrintable(title) << ": " << year << endl;
}
model.setTable("cd");
model.setFilter("id = 125");
model.select();
if (model.rowCount() == 1) {
model.removeRows(0, 1);
model.submitAll();
}

E&# removeRows()%'())%"(I#3%"&#%$*,%-2H.#$%*!%"&#%!/$3"%$#'*$0%"*%0#)#"#%(-0%"&#%-2H.#$%*!%$#'*$03
"*%0#)#"#8%E&#%-#5"%#5(H:)#%0#)#"#3%())%"&#%$#'*$03%"&("%H("'&%"&#%!/)"#$J

model.setTable("cd");
model.setFilter("year < 1990");
model.select();
if (model.rowCount() > 0) {
model.removeRows(0, model.rowCount());
model.submitAll();
}

E&# QSqlQuery%(-0 QSqlTableModel%')(33#3%:$*1/0#%(-%/-"#$!('#%.#",##-%B"%(-0 (-%<B?%0("(.(3#8


C3/-4%"&#3#%')(33#3+%,#%'(-%'$#("#%!*$H3%"&("%:$#3#-"%0("(%"*%23#$3%(-0%"&("%)#"%"&#H%/-3#$"+
2:0("#+%(-0%0#)#"#%$#'*$038

Presenting Data in Tabular Form


>-%H(-7%'(3#3+%/"%/3%3/H:)#3"%"*%:$#3#-"%23#$3%,/"&%(%"(.2)($%1/#,%*!%(%0("(%3#"8%>-%"&/3%3#'"/*-%(-0
E&#%(::)/'("/*-%23#3%"&$##%"(.)#3+%0#!/-#0%(3%!*))*,3J
"&#%!*))*,/-4%3#'"/*-+%,#%:$#3#-"%(%3/H:)#%=S%=*))#'"/*-%(::)/'("/*-%"&("%23#3 QSqlTableModel%(-0%/"3
32.')(33 QSqlRelationalTableModel "*%)#"%23#$3%1/#,%(-0%/-"#$('"%,/"&%0("(%3"*$#0%/-%(%0("(.(3#8
CREATE TABLE artist (
E&#%H(/-%!*$H%3&*,3%(%H(3"#$0#"(/)%1/#,%*!%=S3%(-0%"&#%"$('I3%*-%"&#%'2$$#-")7%3#)#'"#0%=S+%(3 id INTEGER PRIMARY KEY,
3&*,-%/- G/42$#%@T8@8 name VARCHAR(40) NOT NULL,
country VARCHAR(40));
!"#$%&'()')&*+%&,-&,.//%01!.2&344/!031!.2 CREATE TABLE cd (
id INTEGER PRIMARY KEY,
[View full size image]
title VARCHAR(40) NOT NULL,
artistid INTEGER NOT NULL,
year INTEGER NOT NULL,
FOREIGN KEY (artistid) REFERENCES artist);
CREATE TABLE track (
id INTEGER PRIMARY KEY,
title VARCHAR(40) NOT NULL,
duration INTEGER NOT NULL,
cdid INTEGER NOT NULL,
FOREIGN KEY (cdid) REFERENCES cd);

<*H#%0("(.(3#3%0*-D"%32::*$"%!*$#/4-%I#738%G*$%"&*3#+%,#%H23"%$#H*1#%"&# FOREIGN KEY%')(23#38


E&#%#5(H:)#%,/))%3"/))%,*$I+%.2"%"&#%0("(.(3#%,/))%-*"%#-!*$'#%$#!#$#-"/()%/-"#4$/"78

!"#$%&'()5)&*+%&,-&,.//%01!.2&344/!031!.267&138/%7
E&#%'*-3"$2'"*$%/3%1#$7%3/H/)($%"*%*-#%"&("%,*2)0%.#%23#0%"*%'$#("#%(%!*$H%.(3#0%*-%(%-*-;<B?
H*0#)J

ArtistForm::ArtistForm(const QString &name, QWidget *parent)


: QDialog(parent)
{
model = new QSqlTableModel(this);
model->setTable("artist");
>-%"&/3%3#'"/*-+%,# ,/))%,$/"#%(%0/()*4%"&("%())*,3%"&#%23#$%"*%#0/"%(%)/3"%*!%($"/3"3%23/-4%(%3/H:)# model->setSort(Artist_Name, Qt::AscendingOrder);
model->setHeaderData(Artist_Name, Qt::Horizontal, tr("Name"));
"(.2)($%!*$H8%E&#%23#$%'(-%/-3#$"%*$%0#)#"#%($"/3"3%23/-4%"&#%!*$HD3%.2""*-38%C:0("#3%'(-%.#%(::)/#0
model->setHeaderData(Artist_Country, Qt::Horizontal, tr("Country"));
0/$#'")7+%3/H:)7%.7%#0/"/-4%'#))%"#5"8%=&(-4#3%($#%(::)/#0%"*%"&#%0("(.(3#%,&#-%"&#%23#$%:$#33#3
model->select();
U-"#$%*$%-(1/4("#3%"*%(-*"&#$%$#'*$08 connect(model, SIGNAL(beforeInsert(QSqlRecord &)),
this, SLOT(beforeInsertArtist(QSqlRecord &)));
!"#$%&'()()&*+% ArtistForm&9!3/." tableView = new QTableView;
tableView->setModel(model);
tableView->setColumnHidden(Artist_Id, true);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->resizeColumnsToContents();
for (int row = 0; row < model->rowCount(); ++row) {
QSqlRecord record = model->record(row);
if (record.value(Artist_Name).toString() == name) {
tableView->selectRow(row);
break;
}
}
...
}

K#%.#4/-%"&#%'*-3"$2'"*$%.7%'$#("/-4%( QSqlTableModel8%K#%:(33 this%(3%:($#-"%"*%4/1#%*,-#$3&/:%"*


"&#%!*$H8%K#%&(1#%'&*3#-%"*%3*$"%.7%'*)2H-%@%M3:#'/!/#0%.7%"&#%'*-3"(-" Artist_NameN+%,&/'&
'*$$#3:*-03%"*%"&# name%!/#)08%>!%,#%0/0%-*"%3:#'/!7%'*)2H-%&#(0#$3+%"&#%!/#)0%-(H#3%,*2)0%.#%23#08
K#%:$#!#$%"*%-(H#%"&#H%*2$3#)1#3%"*%#-32$#%"&("%"&#7%($#%:$*:#$)7%'(:/"()/V#0%(-0%/-"#$-("/*-()/V#08

R#5"+%,#%'$#("#%( QTableView%"*%1/32()/V#%"&#%H*0#)8%K#%&/0#%"&# id%!/#)0%(-0%3#"%"&#%'*)2H-%,/0"&3


Q#$#D3%"&#%')(33%0#!/-/"/*-%!*$%"&# ArtistForm%0/()*4J "*%(''*HH*0("#%"&#/$%"#5"%,/"&*2"%-##0/-4%"*%3&*,%#))/:3#38

E&# ArtistForm%'*-3"$2'"*$%"(I#3%"&#%-(H#%*!%"&#%($"/3"%"&("%3&*2)0%.#%3#)#'"#0%,&#-%"&#%0/()*4
class ArtistForm : public QDialog :*:3%2:8%K#%/"#$("#%"&$*24&%"&# artist%"(.)#D3%$#'*$03%(-0%3#)#'"%"&#%3:#'/!/#0%($"/3"8%E&#%$#3"%*!%"&#
{ '*-3"$2'"*$D3%'*0#%/3%23#0%"*%'$#("#%(-0%'*--#'"%"&#%.2""*-3%(-0%"*%)(7%*2"%"&#%'&/)0%,/04#"38
Q_OBJECT
public:
ArtistForm(const QString &name, QWidget *parent = 0); void ArtistForm::addArtist()
private slots: {
void addArtist(); int row = model->rowCount();
void deleteArtist(); model->insertRow(row);
void beforeInsertArtist(QSqlRecord &record); QModelIndex index = model->index(row, Artist_Name);
private: tableView->setCurrentIndex(index);
enum { tableView->edit(index);
Artist_Id = 0, }
Artist_Name = 1,
Artist_Country = 2
};
QSqlTableModel *model; E*%(00%(%-#,%($"/3"+%,#%/-3#$"%(%3/-4)#%.)(-I%$*,%("%"&#%.*""*H%*!%"&# QTable-View8%R*,%"&#%23#$%'(-
QTableView *tableView; #-"#$%(%-#,%($"/3"D3%-(H#%(-0%'*2-"$78%>!%"&#%23#$%'*-!/$H3%"&#%/-3#$"/*-%.7%:$#33/-4%U-"#$+%"&#
QPushButton *addButton; beforeInsert()%3/4-()%/3%#H/""#0%(-0%"&#-%"&#%-#,%$#'*$0%/3%/-3#$"#0%/-"*%"&#%0("(.(3#8
QPushButton *deleteButton;
QPushButton *closeButton;
}; void ArtistForm::beforeInsertArtist(QSqlRecord &record)
{
record.setValue("id", generateId("artist"));
}

>-%"&#%'*-3"$2'"*$+%,#%'*--#'"#0%"&#%H*0#)D3 beforeInsert()%3/4-()%"*%"&/3%3)*"8%K#%($#%:(33#0%(
Implementing MasterDetail Forms
-*-;'*-3"%$#!#$#-'#%"*%"&#%$#'*$0%F23"%.#!*$#%/"%/3%/-3#$"#0%/-"*%"&#%0("(.(3#8% "%"&/3%:*/-"+%,#
:*:2)("#%/"3 id%!/#)08 K#%,/))%-*,%$#1/#,%"&#%H(/-%!*$H%,&/'&%"(I#3%(%H(3"#$0#"(/)%(::$*('&8%E&#%H(3"#$%1/#,%/3%(%)/3"%*!
=S38%E&#%0#"(/)%1/#,%/3%(%)/3"%*!%"$('I3%!*$%"&#%'2$$#-"%=S8%E&/3%!*$H%/3%"&#%H(/-%,/-0*,%*!%"&#%=S
</-'#%,#%,/))%-##0 generateId()%(%!#,%"/H#3+%,#%0#!/-#%/"%/-)/-#%/-%(%&#(0#$%!/)#%(-0%/-')20#%/"%#('& =*))#'"/*-%(::)/'("/*-%(3%3&*,-%/- G/42$#%@T8@%M:8%TXXN8
"/H#%,#%-##0%/"8%Q#$#D3%(%62/'I%M(-0 /-#!!/'/#-"N%,(7%*!%/H:)#H#-"/-4%/"J
class MainForm : public QWidget
{
inline int generateId(const QString &table)
Q_OBJECT
{
public:
QSqlQuery query;
MainForm();
query.exec("SELECT MAX(id) FROM " + table);
private slots:
int id = 0;
void addCd();
if (query.next())
void deleteCd();
id = query.value(0).toInt() + 1;
void addTrack();
return id;
void deleteTrack();
}
void editArtists();
void currentCdChanged(const QModelIndex &index);
void beforeInsertCd(QSqlRecord &record);
E&# generateId()%!2-'"/*-%'(-%*-)7%.#%42($(-"##0%"*%,*$I%'*$$#'")7%/!%/"%/3%#5#'2"#0%,/"&/-%"&# void beforeInsertTrack(QSqlRecord &record);
'*-"#5"%*!%"&#%3(H#%"$(-3('"/*-%(3%"&#%'*$$#3:*-0/-4 INSERT%3"("#H#-"8%<*H#%0("(.(3#3%32::*$" void refreshTrackViewHeader();
(2"*;4#-#$("#0%!/#)03+%(-0%/"%/3%232())7%!($%.#""#$%"*%23#%"&#%0("(.(3#;3:#'/!/'%32::*$"%!*$%"&/3 private:
*:#$("/*-8 enum {
Cd_Id = 0,
Cd_Title = 1,
E&#%)(3"%:*33/./)/"7%"&# ArtistForm%0/()*4%*!!#$3%/3%0#)#"/*-8%W("&#$%"&(-%:#$!*$H/-4%'(3'(0/-4 Cd_ArtistId = 2,
0#)#"/*-3%M'*1#$#0%3&*$")7N+%,#%&(1#%'&*3#-%"*%*-)7%:#$H/"%0#)#"/*-3%*!%($"/3"3%,&*%&(1#%-*%=S3%/- Cd_Year = 3
"&#%'*))#'"/*-8 };
enum {
Track_Id = 0,
void ArtistForm::deleteArtist() Track_Title = 1,
{ Track_Duration = 2,
tableView->setFocus(); Track_CdId = 3
QModelIndex index = tableView->currentIndex(); };
if (!index.isValid()) QSqlRelationalTableModel *cdModel;
return; QSqlTableModel *trackModel;
QSqlRecord record = model->record(index.row()); QTableView *cdTableView;
QSqlTableModel cdModel; QTableView *trackTableView;
cdModel.setTable("cd"); QPushButton *addCdButton;
cdModel.setFilter("artistid = " + record.value("id").toString()); QPushButton *deleteCdButton;
cdModel.select(); QPushButton *addTrackButton;
if (cdModel.rowCount() == 0) { QPushButton *deleteTrackButton;
model->removeRow(tableView->currentIndex().row()); QPushButton *editArtistsButton;
} else { QPushButton *quitButton;
QMessageBox::information(this, };
tr("Delete Artist"),
tr("Cannot delete %1 because there are CDs associated "
"with this artist in the collection.")
K#%23#%( QSqlRelationalTableModel%!*$%"&# cd%"(.)#%$("&#$%"&(-%(%:)(/- QSqlTableModel%.#'(23#%,#
.arg(record.value("name").toString()));
} -##0%"*%&(-0)#%!*$#/4-%I#738%K#%,/))%-*,%$#1/#,%#('&%!2-'"/*-%/-%"2$-+%.#4/--/-4%,/"&%"&#
} '*-3"$2'"*$+%,&/'&%,#%,/))%)**I%("%/-%3#'"/*-3%.#'(23# /"%/3%62/"#%)*-48

MainForm::MainForm()
>!%"&#$#%/3%(%$#'*$0%3#)#'"#0+%,#%'&#'I%"* 3##%/!%"&#%($"/3"%&(3%(-7%=S3+%(-0%/!%"&#7%0*-D"+%,#%0#)#"# {
"&#H%/HH#0/("#)78%L"&#$,/3#+%,#%:*:%2:%(%H#33(4#%.*5%#5:)(/-/-4%,&7%"&#%0#)#"/*-%,(3%-*" cdModel = new QSqlRelationalTableModel(this);
:#$!*$H#08%<"$/'")7%3:#(I/-4+%,#%3&*2)0%&(1#%23#0%(%"$(-3('"/*-+%.#'(23#%(3%"&#%'*0#%3"(-03+%/"%/3 cdModel->setTable("cd");
:*33/.)#%!*$%(%=S%"*%&(1#%/"3%($"/3"%3#"%"*%"&#%*-#%,#%($#%0#)#"/-4%/-;.#",##-%"&# cdModel.select() cdModel->setRelation(Cd_ArtistId,
(-0 model->removeRow()%'())38 K#%,/))%3&*,%(%"$(-3('"/*-%/-%"&#%-#5"%3#'"/*-8 QSqlRelation("artist", "id", "name"));
cdModel->setSort(Cd_Title, Qt::AscendingOrder);
cdModel->setHeaderData(Cd_Title, Qt::Horizontal, tr("Title"));
cdModel->setHeaderData(Cd_ArtistId, Qt::Horizontal, tr("Artist")); ...
cdModel->setHeaderData(Cd_Year, Qt::Horizontal, tr("Year")); }
cdModel->select();

E&#%!/$3"%'*--#'"/*-%/3%2-232()%3/-'#%/-3"#(0%*!%'*--#'"/-4%(%,/04#"+%,#%'*--#'"%"*%(%3#)#'"/*-
E&#%'*-3"$2'"*$%.#4/-3%.7%3#""/-4%2:%"&# QSqlRelationalTableModel%"&("%&(-0)#3%"&# cd%"(.)#8%E&# H*0#)8%E&# QItemSelectionModel%')(33 /3%23#0%"*%I##:%"$('I%*!%3#)#'"/*-3%/-%1/#,38%A7%.#/-4
setRelation()%'())%"#))3%"&#%H*0#)%"&("%/"3 artistid%!/#)0%M,&*3#%!/#)0%/-0#5%/3%&#)0%.7 Cd_ArtistIdN '*--#'"#0%"*%"&#%"(.)#%1/#,D3%3#)#'"/*-%H*0#)+%*2$ currentCdChanged()%3)*"%,/))%.#%'())#0%,&#-#1#$
&*)03%"&# id%!*$#/4-%I#7%!$*H%"&# artist%"(.)#+%(-0%"&("%/"%3&*2)0 0/3:)(7%"&#%'*$$#3:*-0/-4 name "&#%23#$%-(1/4("#3%!$*H%*-#%$#'*$0%"*%(-*"&#$8
!/#)0D3%'*-"#-"3%/-3"#(0%*!%>S38%>!%"&#%23#$%'&**3#3%"*%#0/"%"&/3%!/#)0%M!*$%#5(H:)#+%.7%:$#33/-4%GYN+
"&#%H*0#)%,/))%(2"*H("/'())7%:$#3#-"%(%'*H.*.*5%,/"&%"&#%-(H#3%*!%())%"&#%($"/3"3+%(-0%/!%"&#%23#$
'&**3#3%(%0/!!#$#-"%($"/3"+%,/))%2:0("#%"&# cd%"(.)#8 void MainForm::currentCdChanged(const QModelIndex &index)
{
if (index.isValid()) {
cdTableView = new QTableView; QSqlRecord record = cdModel->record(index.row());
cdTableView->setModel(cdModel); int id = record.value("id").toInt();
cdTableView->setItemDelegate(new QSqlRelationalDelegate(this)); trackModel->setFilter(QString("cdid = %1").arg(id));
cdTableView->setSelectionMode(QAbstractItemView::SingleSelection); } else {
cdTableView->setSelectionBehavior(QAbstractItemView::SelectRows); trackModel->setFilter("cdid = -1");
cdTableView->setColumnHidden(Cd_Id, true); }
cdTableView->resizeColumnsToContents(); trackModel->select();
refreshTrackViewHeader();
}

<#""/-4%2:%"&#%1/#,%!*$%"&# cd%"(.)#%/3%(4(/-%3/H/)($%"*%,&("%,#%&(1#%()$#(07%3##-8%E&#%*-)7
3/4-/!/'(-"%0/!!#$#-'#%/3%"&("%/-3"#(0%*!%23/-4%"&#%1/#,D3%0#!(2)"%0#)#4("#%,#%23#
E&/3%3)*"%/3%'())#0%,&#-#1#$%"&#%'2$$#-"%=S%'&(-4#38%E&/3%*''2$3%,&#-%"&#%23#$%-(1/4("#3%"*%(-*"&#$
QSqlRelationalDelegate8%>"%/3%"&/3%0#)#4("#%"&("%0*#3%"&#%!*$#/4-%I#7%&(-0)/-48
=S%M.7%')/'I/-4%*$%.7%23/-4%"&#%C:%(-0%S*,-%I#73N8%>!%"&#%=S%/3%/-1()/0%M!*$%#5(H:)#+%/!%"&#$#%($#%-*
=S3%*$%(%-#,%*-#%/3%.#/-4%/-3#$"#0+%*$%"&#%'2$$#-"%*-#%&(3%F23"%.##-%0#)#"#0N+%,#%3#"%"&# TRack
trackModel = new QSqlTableModel(this); "(.)#D3 cdid%"* ;@%M(-%/-1()/0%>S%"&("%,#%I-*,%,/))%H("'&%-*%$#'*$03N8
trackModel->setTable("track");
trackModel->setHeaderData(Track_Title, Qt::Horizontal, tr("Title")); E&#-+%&(1/-4%3#"%"&#%!/)"#$+%,#%3#)#'"%"&#%H("'&/-4%"$('I%$#'*$038%E&# refresh-TrackViewHeader()
trackModel->setHeaderData(Track_Duration, Qt::Horizontal, !2-'"/*-%,/))%.#%#5:)(/-#0%/-%(%H*H#-"8
tr("Duration"));
trackTableView = new QTableView;
trackTableView->setModel(trackModel); void MainForm::addCd()
trackTableView->setItemDelegate( {
new TrackDelegate(Track_Duration, this)); int row = 0;
trackTableView->setSelectionMode( if (cdTableView->currentIndex().isValid())
QAbstractItemView::SingleSelection); row = cdTableView->currentIndex().row();
trackTableView->setSelectionBehavior(QAbstractItemView::SelectRows); cdModel->insertRow(row);
cdModel->setData(cdModel->index(row, Cd_Year),
QDate::currentDate().year());
G*$%"$('I3+%,#%($#%*-)7%4*/-4%"*%3&*,%"&#/$%-(H#3%(-0%02$("/*-3+%3*%( QSqlTableModel%/3%32!!/'/#-"8 QModelIndex index = cdModel->index(row, Cd_Title);
cdTableView->setCurrentIndex(index);
ME&# id%(-0 cdid%!/#)0D3%($#%&/00#-%/-%"&# currentCd-Changed()%3)*"%3&*,-%)("#$8N%E&#%*-)7%-*"(.)#
cdTableView->edit(index);
(3:#'"%*!%"&/3%:($"%*!%"&#%'*0#%/3%"&("%,#%23#%"&# trackDelegate%0#1#)*:#0%/- =&(:"#$%@X%"*%3&*, }
"$('I%"/H#3%(3%Z !"#$%&'&%()"*&Z%(-0%"*%())*,%"&#H%"*%.#%#0/"#0%23/-4%(%32/"(.)# QTimeEdit8

E&#%'$#("/*-+%'*--#'"/-4+%(-0%)(7/-4%*2"%*!%"&#%1/#,3%(-0%.2""*-3%&*)03%-*%32$:$/3#3+%3*%"&#%*-)7
K&#-%"&#%23#$%')/'I3%"&#% 00%=S%.2""*-+%(%-#,%.)(-I%$*,%/3%/-3#$"#0%/-%"&# cdTableView%(-0%,#
*"&#$%:($"%*!%"&#%'*-3"$2'"*$%"&("%,#%,/))%3&*,%($#%(%!#,%-*-;*.1/*23%'*--#'"/*-38
#-"#$%#0/"%H*0#8%K#%()3*%3#"%(%0#!(2)"%1()2#%!*$%"&# year%!/#)08% "%"&/3%:*/-"+%"&#%23#$%'(-%#0/"%"&#
$#'*$0+%!/))/-4%/-%"&#%.)(-I%!/#)03%(-0%3#)#'"/-4%(-%($"/3"%!$*H%"&#%($"/3"%'*H.*.*5%"&("%/3
... (2"*H("/'())7%:$*1/0#0%.7%"&# QSqlRelationalTableModel%.#'(23#%*!%"&# setRelation()%'())+%(-0%#0/"
connect(cdTableView->selectionModel(), "&#%7#($%/!%"&#%0#!(2)"%,(3%-*"%(::$*:$/("#8%>!%"&#%23#$%'*-!/$H3%"&#%/-3#$"/*-%.7%:$#33/-4%U-"#$+%"&#
SIGNAL(currentRowChanged(const QModelIndex &, $#'*$0%/3%/-3#$"#08%E&#%23#$%'(-%'(-'#)%.7%:$#33/-4%U3'8
const QModelIndex &)),
this, SLOT(currentCdChanged(const QModelIndex &)));
connect(cdModel, SIGNAL(beforeInsert(QSqlRecord &)), void MainForm::beforeInsertCd(QSqlRecord &record)
this, SLOT(beforeInsertCd(QSqlRecord &))); {
connect(trackModel, SIGNAL(beforeInsert(QSqlRecord &)), record.setValue("id", generateId("cd"));
this, SLOT(beforeInsertTrack(QSqlRecord &))); }
connect(trackModel, SIGNAL(rowsInserted(const QModelIndex &, int,
int)),
this, SLOT(refreshTrackViewHeader()));
E&/3%3)*"%/3%'())#0%,&#-%"&# cdModel%#H/"3%/"3 beforeInsert()%3/4-()8%K#%23#%/"%"*%:*:2)("#%"&# id%!/#)0
F23"%(3%,#%0/0%!*$%/-3#$"/-4%-#,%($"/3"3+%(-0%"&#%3(H#%'(1#("%(::)/#3J%>"%3&*2)0%.#%0*-#%,/"&/-%"&#
3'*:#%*!%(%"$(-3('"/*-+%(-0%/0#())7%"&#%0("(.(3#;3:#'/!/'%H#(-3%*!%'$#("/-4%>S3%M!*$%#5(H:)#+%(2"*;
4#-#$("#0%>S3N%3&*2)0%.#%23#0%/-3"#(08 E&/3%,*$I3%/-%"&#%3(H#%,(7%(3 addCd()+%,/"&%(%-#,%.)(-I%$*,%.#/-4%/-3#$"#0%/-"*%"&#%1/#,8

void MainForm::deleteCd() void MainForm::beforeInsertTrack(QSqlRecord &record)


{ {
QModelIndex index = cdTableView->currentIndex(); QSqlRecord cdRecord = cdModel->record(cdTableView->currentIndex()
if (!index.isValid()) .row());
return; record.setValue("id", generateId("track"));
QSqlDatabase db = QSqlDatabase::database(); record.setValue("cdid", cdRecord.value(Cd_Id).toInt());
db.transaction(); }
QSqlRecord record = cdModel->record(index.row());
int id = record.value(Cd_Id).toInt();
int tracks = 0;
QSqlQuery query; >!%"&#%23#$%'*-!/$H3%"&#%/-3#$"/*-%/-/"/("#0%.7 addTrack()+%"&/3%!2-'"/*-%/3%'())#0%"*%:*:2)("#%"&# id
query.exec(QString("SELECT COUNT(*) FROM track WHERE cdid = %1") (-0 cdid%!/#)038%E&#%'(1#("3%H#-"/*-#0%#($)/#$%3"/))%(::)7%*!%'*2$3#8
.arg(id));
if (query.next())
tracks = query.value(0).toInt(); void MainForm::deleteTrack()
if (tracks > 0) { {
int r = QMessageBox::question(this, tr("Delete CD"), trackModel->removeRow(trackTableView->currentIndex().row());
tr("Delete \"%1\" and all its tracks?") if (trackModel->rowCount() == 0)
.arg(record.value(Cd_ArtistId).toString()), trackTableView->horizontalHeader()->setVisible(false);
QMessageBox::Yes | QMessageBox::Default, }
QMessageBox::No | QMessageBox::Escape);
if (r == QMessageBox::No) {
db.rollback();
return; >!%"&#%23#$%')/'I3%"&#%S#)#"#%E$('I%.2""*-+%,#%0#)#"#%"&#%"$('I%,/"&*2"%!*$H()/"78%>"%,*2)0%.#%#(37%"*
} 23#%(%[#3\R*%H#33(4#%.*5%/!%,#%:$#!#$$#0%0#)#"/*-3%"*%.#%'*-!/$H#08
query.exec(QString("DELETE FROM track WHERE cdid = %1")
.arg(id));
} void MainForm::refreshTrackViewHeader()
cdModel->removeRow(index.row()); {
cdModel->submitAll(); trackTableView->horizontalHeader()->setVisible(
db.commit(); trackModel->rowCount() > 0);
currentCdChanged(QModelIndex()); trackTableView->setColumnHidden(Track_Id, true);
} trackTableView->setColumnHidden(Track_CdId, true);
trackTableView->resizeColumnsToContents();
}
>!%"&#%23#$%')/'I3%"&#%S#)#"#%=S%.2""*-+%"&/3%3)*"%/3%'())#08%>!%"&#$#%/3%(%'2$$#-"%=S%,#%!/-0%*2"%&*,
H(-7%"$('I3%/"%&(38%>!%"&#$#%($#%-*%"$('I3%,#%3/H:)7%0#)#"#%"&#%=SD3%$#'*$08%>!%"&#$#%/3%("%)#(3"%*-#
"$('I%,#%(3I%"&#%23#$%"*%'*-!/$H%"&#%0#)#"/*-+%(-0%/!%"&#7%')/'I%[#3+%,#%0#)#"#%())%"&#%"$('I%$#'*$03+ E&# refreshTrackViewHeader()%3)*"%/3%/-1*I#0%!$*H%1($/*23%:)('#3%"*%#-32$#%"&("%"&#%&*$/V*-"()
(-0%"&#-%"&#%=SD3%$#'*$08% ))%"&/3%/3%0*-#%,/"&/-%"&#%3'*:#%*!%(%"$(-3('"/*-+%3*%"&#%'(3'(0#%0#)#"/*- &#(0#$%*!%"&#%"$('I%1/#,%/3%3&*,-%/!%(-0%*-)7%/!%"&#$#%($#%"$('I3%"*%3&*,8%>"%()3*%&/0#3%"&# id%(-0
,/))%#/"&#$%!(/)%(3%(%,&*)#%*$%32''##0%(3%(%,&*)#(332H/-4%"&("%"&#%2-0#$)7/-4%0("(.(3#%32::*$"3 cdid%!/#)03%(-0%$#3/V#3%"&#%1/3/.)#%"(.)#%'*)2H-3%.(3#0%*-%"&#%'2$$#-"%'*-"#-"3%*!%"&#%"(.)#8
"$(-3('"/*-38

Q(-0)/-4%"&#%"$('I%0("(%/3%1#$7%3/H/)($%"*%&(-0)/-4%=S%0("(8%C:0("#3%'(-%.#%:#$!*$H#0%3/H:)7%.7%"&# void MainForm::editArtists()


23#$%#0/"/-4%'#))38%>-%"&#%'(3#%*!%"$('I%02$("/*-3+%*2$ TRackDelegate%#-32$#3%"&("%"/H#3%($#%3&*,-%/- {
(%-/'#%!*$H("%(-0%($#%#(3/)7%#0/"#0%23/-4%( QTimeEdit8 QSqlRecord record = cdModel->record(cdTableView->currentIndex()
.row());
ArtistForm artistForm(record.value(Cd_ArtistId).toString(), this);
artistForm.exec();
void MainForm::addTrack()
cdModel->select();
{
}
if (!cdTableView->currentIndex().isValid())
return;
int row = 0;
if (trackTableView->currentIndex().isValid()) E&/3%3)*"%/3%'())#0%/!%"&#%23#$%')/'I3%"&#%U0/"% $"/3"3%.2""*-8%>"%:$*1/0#3%0$/));0*,-%*-%"&#%'2$$#-"%=SD3
row = trackTableView->currentIndex().row(); ($"/3"+%/-1*I/-4%"&# ArtistForm%'*1#$#0%/-%"&#%:$#1/*23%3#'"/*-%(-0%3#)#'"/-4%"&#%(::$*:$/("#%($"/3"8%>!
trackModel->insertRow(row); "&#$#%/3%-*%'2$$#-"%$#'*$0+%(%3(!#%#H:"7%$#'*$0%/3%$#"2$-#0%.7 record()+%(-0%"&/3%,/))%&($H)#33)7%-*"
QModelIndex index = trackModel->index(row, Track_Title); H("'&%M(-0%"&#$#!*$#%-*"%3#)#'"N%(-7%($"/3"%/-%"&#%($"/3"3%!*$H8%K&("%('"2())7%&(::#-3%/3%"&("%,&#-
trackTableView->setCurrentIndex(index);
,#%'()) record.value(Cd_ArtistId)+%.#'(23#%,#%($#%23/-4%( QSqlRelationalTableModel%"&("%H(:3
trackTableView->edit(index);
} ($"/3"%>S3%"*%($"/3"%-(H#3+%"&#%1()2#%"&("%/3%$#"2$-#0%/3%"&#%($"/3"D3%-(H#%M,&/'&%,/))%.#%(-%#H:"7
3"$/-4%/!%"&#%$#'*$0%/3%#H:"7N8% "%"&#%#-0+%,#%4#"%"&# cdModel%"*%$#;3#)#'"%/"3%0("(+%,&/'&%'(23#3%"&#
cdTableView%"*%$#!$#3&%/"3%1/3/.)#%'#))38%E&/3%/3%0*-#%"*%#-32$#%"&("%"&#%($"/3"%-(H#3%($#%3&*,-
'*$$#'")7%3/-'#%3*H#%'*2)0%&(1#%.##-%'&(-4#0%.7%"&#%23#$%/- "&# ArtistForm%0/()*48 Chapter 14. Networking
G*$%:$*F#'"3%"&("%23#%"&#%<B?%')(33#3+%,#%H23"%(00%"&#%)/-# • !"#"$%&'()&*+",$#-
• !"#"$%&.(()&*+",$#-
• !"#"$%&(*)&*+",$#/,!0,!&122+"34#"5$-
QT += sql • /,$6"$%&4$6&7,3,"0"$%&89)&94#4%!4:-

B"%:$*1/0#3%"&# QFtp%(-0 QHttp%')(33#3%!*$%,*$I/-4%,/"&%GE9%(-0%QEE98%E&#3#%:$*"*'*)3%($#%#(37%"*


"*%"&# .pro%!/)#3]%"&/3%,/))%#-32$#%"&("%"&#%(::)/'("/*-%/3%)/-I#0%(4(/-3"%"&# +$,-.%)/.$($78 23#%!*$%0*,-)*(0/-4%(-0%2:)*(0/-4%!/)#3%(-0+%/-%"&#%'(3#%*!%QEE9+%!*$%3#-0/-4%$#62#3"3%"*%,#.
3#$1#$3%(-0%$#"$/#1/-4%"&#%$#32)"38
E&/3%'&(:"#$%&(3%3&*,-%"&("%B"D3%H*0#)\1/#,%')(33#3%H(I#%1/#,/-4%(-0%#0/"/-4%0("(%/-%<B?
0("(.(3#3%(3%#(37%(3%:*33/.)#8%>-%'(3#3%,&#$#%!*$#/4-%I#73%$#!#$%"*%"(.)#3%,/"&%)*"3%*!%$#'*$03%M3(7+ B"%()3*%:$*1/0#3%"&#%)*,#$;)#1#) QTcpSocket%(-0 QUdpSocket%')(33#3+%,&/'&%/H:)#H#-"%"&#%E=9%(-0
"&*23(-03%*$%H*$#N+%/"%/3%:$*.(.)7%.#3"%"*%'$#("#%*2$%*,-%0#)#4("#%(-0%23#%/"%"*%:$#3#-"%(%Z)/3"%*! CS9%"$(-3:*$"%:$*"*'*)38%E=9%/3%(%$#)/(.)#%'*--#'"/*-;*$/#-"#0%:$*"*'*)%"&("%*:#$("#3%/-%"#$H3%*!
1()2#3Z%!*$H%,/"&%(%3#($'&%'(:(./)/"7%$("&#$%"&(-%$#)7/-4%*- QSqlRelationalTableModelD3%0#!(2)" 0("(%3"$#(H3%"$(-3H/""#0%.#",##-%-#",*$I%-*0#3+%,&/)#%CS9%/3%(-%2-$#)/(.)#%'*--#'"/*-)#33%:$*"*'*)
'*H.*.*5#38% -0%/-%3/"2("/*-3%,&#$#%,#%,(-"%"*%:$#3#-"%$#'*$03%23/-4%(%!*$H%1/#,+%,#%H23"%&(-0)# .(3#0%*-%0/3'$#"#%:('I#"3%3#-"%.#",##-%-#",*$I%-*0#38%A*"&%'(-%.#%23#0%"*%'$#("#%-#",*$I%')/#-"
"&/3%*2$3#)1#3J%.7%23/-4%( QSqlQuery%*$ QSqlTableModel%"*%&(-0)#%"&#%0("(.(3#%/-"#$('"/*-+%(-0 (-0%3#$1#$%(::)/'("/*-38%G*$%3#$1#$3+%,#%()3*%-##0%"&# QTcpServer%')(33%"*%&(-0)#%/-'*H/-4%E=9
H(::/-4%"&#%'*-"#-"3%*!%"&#%23#$%/-"#$!('#%,/04#"3%,#%,(-"%"*%23#%!*$%:$#3#-"/-4%(-0%#0/"/-4%"&# '*--#'"/*-38
0("(%"*%"&#%2-0#$)7/-4%0("(.(3#%/-%*2$%*,-%'*0#8

Writing FTP Clients


E&# QFtp%')(33%/H:)#H#-"3%"&#%')/#-"%3/0#%*!%"&#%GE9%:$*"*'*)%/-%B"8%>"%*!!#$3%1($/*23%!2-'"/*-3%"*
:#$!*$H%"&#%H*3"%'*HH*-%GE9%*:#$("/*-3%(-0%)#"3%23%#5#'2"#%($./"$($7%GE9%'*HH(-038

E&# QFtp%')(33%,*$I3%(37-'&$*-*23)78%K&#-%,#%'())%(%!2-'"/*-%)/I# get()%*$ put()+%/"%$#"2$-3


/HH#0/("#)7%(-0%"&#%0("(%"$(-3!#$%*''2$3%,&#-%'*-"$*)%:(33#3%.('I%"*%B"D3%#1#-"%)**:8%E&/3%#-32$#3
"&("%"&#%23#$%/-"#$!('#%$#H(/-3%$#3:*-3/1#%,&/)#%GE9%'*HH(-03%($#%#5#'2"#08

K#%,/))%3"($"%,/"&%(-%#5(H:)#%"&("%3&*,3%&*,%"*%$#"$/#1#%(%3/-4)#%!/)#%23/-4 get()8%E&#%#5(H:)#%/3%(
'*-3*)#%(::)/'("/*-%'())#0 ftpget%"&("%0*,-)*(03%"&#%$#H*"#%!/)#%3:#'/!/#0%*-%"&#%'*HH(-0%)/-#8%?#"D3
.#4/-%,/"&%"&# main()%!2-'"/*-J

int main(int argc, char *argv[])


{
QCoreApplication app(argc, argv);
QStringList args = app.arguments();
if (args.count() != 2) {
cerr << "Usage: ftpget url" << endl
<< "Example:" << endl
<< " ftpget ftp://ftp.trolltech.com/mirrors" << endl;
return 1;
}
FtpGet getter;
if (!getter.getFile(QUrl(args[1])))
return 1;
QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));
return app.exec();
}

K#%'$#("#%( QCoreApplication%$("&#$ "&(-%/"3%32.')(33 QApplication%"*%(1*/0%)/-I/-4%/-%"&# +$/#!


)/.$($78%E&# QCoreApplication::arguments()%!2-'"/*-%$#"2$-3%"&#%'*HH(-0;)/-#%($42H#-"3%(3%(
QStringList+%,/"&%"&#%!/$3"%/"#H%.#/-4%"&#%-(H#%"&#%:$*4$(H%,(3%/-1*I#0%(3+%(-0%(-7%B";3:#'/!/'
($42H#-"3%32'&%(3 -style%$#H*1#08%E&#%&#($"%*!%"&# main()%!2-'"/*-%/3%"&#%'*-3"$2'"/*-%*!%"&#
FtpGet%*.F#'"%(-0%"&# getFile()%'())8%>!%"&#%'())%32''##03+%,#%)#"%"&#%#1#-"%)**:%$2-%2-"/)%"&#
0*,-)*(0%!/-/3&#38 << " for writing: " << qPrintable(file.errorString())
<< endl;
return false;
))%"&#%,*$I%/3%0*-#%.7%"&# FtpGet%32.')(33+%,&/'&%/3 0#!/-#0%(3%!*))*,3J
}
ftp.connectToHost(url.host(), url.port(21));
ftp.login();
class FtpGet : public QObject ftp.get(url.path(), &file);
{ ftp.close();
Q_OBJECT return true;
public: }
FtpGet(QObject *parent = 0);
bool getFile(const QUrl &url);
signals:
void done(); E&# getFile()%!2-'"/*-%.#4/-3%.7%'&#'I/-4%"&#%CW?%"&("%,(3%:(33#0%/-8%>!%(%:$*.)#H%/3%#-'*2-"#$#0+
private slots: "&#%!2-'"/*-%:$/-"3%(-%#$$*$%H#33(4#%"* cerr%(-0%$#"2$-3 false%"*%/-0/'("#%"&("%"&#%0*,-)*(0%!(/)#08
void ftpDone(bool error);
private: >-3"#(0%*!%!*$'/-4%"&#%23#$%"*%H(I#%2:%(%)*'()%!/)#%-(H#+%,#%"$7%"*%'$#("#%(%3#-3/.)#%-(H#%23/-4%"&#
QFtp ftp;
CW?%/"3#)!+%,/"&%(%!()).('I%*! ftpget.out8%>!%,#%!(/)%"*%*:#-%"&#%!/)#+%,#%:$/-"%(-%#$$*$%H#33(4#%(-0
QFile file;
}; $#"2$- false8

R#5"+%,#%#5#'2"#%(%3#62#-'#%*!%!*2$%GE9%'*HH(-03%23/-4%*2$ QFtp%*.F#'"8%E&# url.port(21)%'())


$#"2$-3%"&#%:*$"%-2H.#$%3:#'/!/#0%/-%"&#%CW?+%*$%:*$"%Y@%/!%-*-#%/3%3:#'/!/#0%/-%"&#%CW?%/"3#)!8%</-'#
E&#%')(33%&(3%(%:2.)/'%!2-'"/*-+ getFile()+%"&("%$#"$/#1#3%"&#%!/)#%3:#'/!/#0%.7%(%CW?8%E&# QUrl%')(33
-*%23#$%-(H#%*$%:(33,*$0%($#%4/1#-%"*%"&# login()%!2-'"/*-+%(-%(-*-7H*23%)*4/-%/3%(""#H:"#08%E&#
:$*1/0#3%(%&/4&;)#1#)%/-"#$!('#%!*$%#5"$('"/-4%"&#%0/!!#$#-"%:($"3%*!%(%CW?+%32'&%(3%"&#%!/)#%-(H#+
3#'*-0%($42H#-"%"* get()%3:#'/!/#3%"&#%*2":2"%>\L%0#1/'#8
:("&+%:$*"*'*)+%(-0%:*$"8

E&#%GE9%'*HH(-03%($#%62#2#0%(-0%#5#'2"#0%/-%B"D3%#1#-"%)**:8%E&#%'*H:)#"/*-%*!%())%"&#
FtpGet%&(3%(%:$/1("#%3)*"+ ftpDone()+%"&("%/3%'())#0%,&#-%"&#%!/)#%"$(-3!#$%/3%'*H:)#"#0+%(-0%( done()
'*HH(-03%/3%/-0/'("#0%.7 QFtpD3 done(bool)%3/4-()+%,&/'&%,#%'*--#'"#0%"* ftpDone(bool)%/-%"&#
3/4-()%"&("%/"%#H/"3%,&#-%"&#%!/)#%&(3%.##-%0*,-)*(0#08%E&#%')(33%()3*%&(3%",*%:$/1("#%1($/(.)#3J%E&#
'*-3"$2'"*$8
ftp%1($/(.)#+%*!%"7:# QFtp+%#-'(:32)("#3%"&#%'*--#'"/*-%"*%(-%GE9%3#$1#$+%(-0 "&# file%1($/(.)#%"&("
/3%23#0%!*$%,$/"/-4%"&#%0*,-)*(0#0%!/)#%"*%0/3I8
void FtpGet::ftpDone(bool error)
{
FtpGet::FtpGet(QObject *parent) if (error) {
: QObject(parent) cerr << "Error: " << qPrintable(ftp.errorString()) << endl;
{ } else {
connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool))); cerr << "File downloaded as " << qPrintable(file.fileName())
} << endl;
}
file.close();
>-%"&#%'*-3"$2'"*$+%,#%'*--#'"%"&# QFtp::done(bool)%3/4-()%"*%*2$ ftpDone(bool)%:$/1("#%3)*"8 QFtp emit done();
#H/"3 done(bool)%,&#-%/"%&(3%!/-/3&#0%:$*'#33/-4%())%$#62#3"38%E&# bool%:($(H#"#$%/-0/'("#3%,&#"&#$ }
(-%#$$*$%*''2$$#0%*$%-*"8

L-'#%"&#%GE9%'*HH(-03%&(1#%())%.##-%#5#'2"#0+%,#%')*3#%"&#%!/)#%(-0%#H/"%*2$%*,- done()%3/4-()8%>"
bool FtpGet::getFile(const QUrl &url) H(7%(::#($%3"$(-4#%"&("%,#%')*3#%"&#%!/)#%&#$#+%$("&#$%"&(-%(!"#$%"&# ftp.close()%'())%("%"&#%#-0%*!
{ "&# getFile()%!2-'"/*-+%.2"%$#H#H.#$%"&("%"&#%GE9%'*HH(-03%($#%#5#'2"#0%(37-'&$*-*23)7%(-0
if (!url.isValid()) { H(7%,#))%.#%/-%:$*4$#33%(!"#$%"&# getFile()%!2-'"/*-%&(3%$#"2$-#08%L-)7%,&#-%"&# QFtp%*.F#'"D3
cerr << "Error: Invalid URL" << endl;
done()%3/4-()%/3%#H/""#0%0*%,#%I-*,%"&("%"&#%0*,-)*(0%/3%!/-/3&#0%(-0%"&("%/"%/3%3(!#%"*%')*3#%"&#%!/)#8
return false;
}
if (url.scheme() != "ftp") { QFtp%:$*1/0#3%3#1#$()%GE9%'*HH(-03+%/-')20/-4 connectToHost()+ login()+ close()+ list()+ cd()+
cerr << "Error: URL must start with 'ftp:'" << endl; get()+ put()+ remove()+ mkdir()+ rmdir()+%(-0 rename()8% ))%*!%"&#3#%!2-'"/*-3%3'&#02)#%(-%GE9
return false; '*HH(-0%(-0%$#"2$-%(-%>S%-2H.#$%"&("%/0#-"/!/#3%"&#%'*HH(-08%>"%/3%()3*%:*33/.)#%"* '*-"$*)%"&#
} "$(-3!#$%H*0#%M"&#%0#!(2)"%/3%:(33/1#N%(-0%"&#%"$(-3!#$%"7:#%M"&#%0#!(2)"%/3%./-($7N8
if (url.path().isEmpty()) {
cerr << "Error: URL has no path" << endl;
$./"$($7%GE9%'*HH(-03%'(-%.#%#5#'2"#0%23/-4 rawCommand()8%G*$%#5(H:)#+%&#$#D3%&*,%"*%#5#'2"#%(
return false;
} SITE CHMOD%'*HH(-0J
QString localFileName = QFileInfo(url.path()).fileName();
if (localFileName.isEmpty())
localFileName = "ftpget.out"; ftp.rawCommand("SITE CHMOD 755 fortune");
file.setFileName(localFileName);
if (!file.open(QIODevice::WriteOnly)) {
cerr << "Error: Cannot open " << qPrintable(file.fileName())
QFtp%#H/"3%"&# commandStarted(int)%3/4-()%,&#-%/"%3"($"3%#5#'2"/-4%(%'*HH(-0+%(-0%/"%#H/"3%"&#
commandFinished(int, bool)%3/4-()%,&#-%"&#%'*HH(-0%/3%!/-/3&#08%E&# int%:($(H#"#$%/3%"&#%>S QFtp ftp;
-2H.#$%"&("%/0#-"/!/#3%"&#%'*HH(-08%>!%,#%($#%/-"#$#3"#0%/-%"&#%!("#%*!%/-0/1/02()%'*HH(-03+%,# QList<QFile *> openedFiles;
'(-%3"*$#%"&#%>S%-2H.#$3%,&#-%,#%3'&#02)#%"&#%'*HH(-038%^##:/-4%"$('I%*!%"&#%>S%-2H.#$3%())*,3 QString currentDir;
23%"*%:$*1/0#%0#"(/)#0%!##0.('I%"*%"&#%23#$8%G*$%#5(H:)#J QString currentLocalDir;
QStringList pendingDirs;
};
bool FtpGet::getFile(const QUrl &url)
{
... E&#%3"($"/-4%0/$#'"*$7%/3%3:#'/!/#0%(3%( QUrl%(-0%/3%3#"%23/-4%"&# getdirectory()%!2-'"/*-8
connectId = ftp.connectToHost(url.host(), url.port(21));
loginId = ftp.login();
getId = ftp.get(url.path(), &file); Spider::Spider(QObject *parent)
closeId = ftp.close(); : QObject(parent)
return true; {
} connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));
void FtpGet::ftpCommandStarted(int id) connect(&ftp, SIGNAL(listInfo(const QUrlInfo &)),
{ this, SLOT(ftpListInfo(const QUrlInfo &)));
if (id == connectId) { }
cerr << "Connecting..." << endl;
} else if (id == loginId) {
cerr << "Logging in..." << endl;
... >-%"&#%'*-3"$2'"*$+%,#%#3"(.)/3&%",*%3/4-()3)*"%'*--#'"/*-38%E&# listInfo(const QUrlInfo &)%3/4-()%/3
} #H/""#0%.7 QFtp%,&#-%,#%$#62#3"%(%0/$#'"*$7%)/3"/-4%M/- getdirectory()N%!*$%#('&%!/)#%"&("%/"%$#"$/#1#38
E&/3%3/4-()%/3%'*--#'"#0%"*%(%3)*"%'())#0 ftpListInfo()+%,&/'&%0*,-)*(03%"&#%!/)#%(33*'/("#0%,/"&%"&#
CW?%/"%/3%4/1#-8
-*"&#$%,(7%*!%:$*1/0/-4%!##0.('I%/3%"*%'*--#'"%"* QFtpD3 stateChanged()%3/4-()+%,&/'&%/3%#H/""#0
,&#-#1#$%"&#%'*--#'"/*-%#-"#$3%(%-#,%3"("#%MQFtp::Connecting+ QFtp::Connected+ QFtp::LoggedIn+
bool Spider::getDirectory(const QUrl &url)
#"'8N8
{
if (!url.isValid()) {
>-%H*3"%(::)/'("/*-3+%,#%($#%*-)7%/-"#$#3"#0%/-%"&#%!("#%*!%"&#%3#62#-'#%*!%'*HH(-03%(3%(%,&*)# cerr << "Error: Invalid URL" << endl;
$("&#$%"&(-%/-%:($"/'2)($%'*HH(-038%>-%32'&%'(3#3+%,#%'(-%3/H:)7%'*--#'"%"*%"&# done(bool)%3/4-()+ return false;
,&/'&%/3%#H/""#0%,&#-#1#$%"&#%'*HH(-0%62#2#%.#'*H#3%#H:"78 }
if (url.scheme() != "ftp") {
K&#-%(-%#$$*$%*''2$3+ QFtp%(2"*H("/'())7%')#($3%"&#%'*HH(-0%62#2#8%E&/3%H#(-3%"&("%/!%"&# cerr << "Error: URL must start with 'ftp:'" << endl;
'*--#'"/*-%*$%"&#%)*4/-%!(/)3+%"&#%'*HH(-03%"&("%!*))*,%/-%"&#%62#2#%($#%-#1#$%#5#'2"#08%>!%,# return false;
}
3'&#02)#%-#,%'*HH(-03%(!"#$%"&#%#$$*$%&(3%*''2$$#0%23/-4%"&#%3(H# QFtp%*.F#'"+%"&#3#%'*HH(-03
ftp.connectToHost(url.host(), url.port(21));
,/))%.#%62#2#0%(-0%#5#'2"#08 ftp.login();
QString path = url.path();
>-%"&#%(::)/'("/*-D3 .pro%!/)#+%,#%-##0%"&#%!*))*,/-4%)/-#%"*%)/-I%(4(/-3"%"&# +$0%$1)23%)/.$($7J if (path.isEmpty())
path = "/";
pendingDirs.append(path);
QT += network processNextDirectory();
return true;
}
K#%,/))%-*,%$#1/#,%(%H*$#%(01(-'#0%#5(H:)#8%E&# spider '*HH(-0;)/-#%:$*4$(H%0*,-)*(03%())%"&#
!/)#3%)*'("#0%/-%(-%GE9%0/$#'"*$7+%$#'2$3/1#)7%0*,-)*(0/-4%!$*H%())%"&#%0/$#'"*$7D3%32.0/$#'"*$/#38%E&#
-#",*$I%)*4/'%/3%)*'("#0%/-%"&# Spider%')(33J K&#-%"&# getdirectory()%!2-'"/*-%/3%'())#0+%/"%.#4/-3%.7%0*/-4%3*H#%3(-/"7%'&#'I3+%(-0%/!%())%/3%,#))+
(""#H:"3%"*%#3"(.)/3&%(-%GE9%'*--#'"/*-8%>"%I##:3%"$('I%*!%"&#%:("&3%"&("%/"%H23"%:$*'#33%(-0%'())3
processNextDirectory()%"*%3"($"%0*,-)*(0/-4%"&#%$**"%0/$#'"*$78
class Spider : public QObject
{
Q_OBJECT void Spider::processNextDirectory()
public: {
Spider(QObject *parent = 0); if (!pendingDirs.isEmpty()) {
bool getDirectory(const QUrl &url); currentDir = pendingDirs.takeFirst();
signals: currentLocalDir = "downloads/" + currentDir;
void done(); QDir(".").mkpath(currentLocalDir);
private slots: ftp.cd(currentDir);
void ftpDone(bool error); ftp.list();
void ftpListInfo(const QUrlInfo &urlInfo); } else {
private: emit done();
void processNextDirectory(); }
} -#5"%0/$#'"*$7%/-%"&#%)/3"]%*"&#$,/3#+%"&#%0*,-)*(0/-4%3"*:3%(-0 done()%/3%#H/""#08

>!%"&#$#%($#%-*%#$$*$3+%"&#%3#62#-'#%*!%GE9%'*HH(-03%(-0%3/4-()3%/3%(3%!*))*,3J
E&# processNextDirectory()%!2-'"/*-%"(I#3%"&#%!/$3"%$#H*"#%0/$#'"*$7%*2"%*!%"&# pendingDirs%)/3"%(-0
'$#("#3%(%'*$$#3:*-0/-4%0/$#'"*$7%/-%"&#%)*'()%!/)#%373"#H8%>"%"&#-%"#))3%"&# QFtp%*.F#'"%"*%'&(-4#
0/$#'"*$7%/-"*%"&#%"(I#-%0/$#'"*$7%(-0%"*%)/3"%/"3%!/)#38%G*$%#1#$7%!/)#%"&(" list()%:$*'#33#3+%/"%#H/"3%( connectToHost(host, port)
listInfo()%3/4-()%"&("%'(23#3%"&# ftpListInfo()%3)*"%"*%.#%'())#08 login()
cd(directory_1)
list()
>!%"&#$#%($#%-*%H*$#%0/$#'"*$/#3%"*%:$*'#33+%"&#%!2-'"/*-%#H/"3%"&# done()%3/4-()%"*%/-0/'("#%"&("%"&# emit listInfo(file_1_1)
0*,-)*(0/-4%/3%'*H:)#"#8 get(file_1_1)
emit listInfo(file_1_2)
get(file_1_2)
void Spider::ftpListInfo(const QUrlInfo &urlInfo) ...
{ emit done()
if (urlInfo.isFile()) { ...
if (urlInfo.isReadable()) { cd(directory_N)
QFile *file = new QFile(currentLocalDir + "/" list()
+ urlInfo.name()); emit listInfo(file_N_1)
if (!file->open(QIODevice::WriteOnly)) { get(file_N_1)
cerr << "Warning: Cannot open file " emit listInfo(file_N_2)
<< qPrintable( get(file_N_2)
QDir::convertSeparators(file->fileName())) ...
<< endl; emit done()
return;
}
ftp.get(urlInfo.name(), file);
openedFiles.append(file); >!%(%!/)#%/3%/-%!('"%(%0/$#'"*$7+%/"%/3%(00#0%"*%"&# pendingDirs%)/3"+%(-0%,&#-%"&#%)(3"%!/)#%*!%"&#%'2$$#-"
} list()%'*HH(-0%&(3%.##-%0*,-)*(0#0+%(%-#, cd()%'*HH(-0%/3%/332#0+%!*))*,#0%.7%(%-#, list()
} else if (urlInfo.isDir() && !urlInfo.isSymLink()) { '*HH(-0%,/"&%"&#%-#5"%:#-0/-4%0/$#'"*$7+%(-0%"&#%,&*)#%:$*'#33%.#4/-3%(4(/-%,/"&%"&#%-#,
pendingDirs.append(currentDir + "/" + urlInfo.name()); 0/$#'"*$78%E&/3%/3%$#:#("#0+%,/"&%-#,%!/)#3%.#/-4%0*,-)*(0#0+%(-0%-#,%0/$#'"*$/#3%(00#0%"*%"&#
} pendingDirs%)/3"+%2-"/)%#1#$7%!/)#%&(3%.##-%0*,-)*(0#0%!$*H%#1#$7%0/$#'"*$7+%("%,&/'&%:*/-"%"&#
} pendingDirs%)/3"%,/))%!/-())7%.#%#H:"78

>!%(%-#",*$I%#$$*$%*''2$3%,&/)#%0*,-)*(0/-4%"&#%!/!"&%*!+%3(7+%",#-"7%!/)#3%/-%(%0/$#'"*$7+%"&#
E&# ftpListInfo()%3)*"D3 urlInfo%:($(H#"#$%:$*1/0#3%0#"(/)#0%/-!*$H("/*-%(.*2"%(%$#H*"#%!/)#8%>!%"&# $#H(/-/-4%!/)#3%,/))%-*"%.#%0*,-)*(0#08%>!%,#%,(-"#0%"*%0*,-)*(0%(3%H(-7%!/)#3%(3%:*33/.)#+%*-#
!/)#%/3%(%-*$H()%!/)#%M-*"%(%0/$#'"*$7N%(-0%/3%$#(0(.)#+%,#%'()) get()%"*%0*,-)*(0%/"8%E&# QFile%*.F#'" 3*)2"/*-%,*2)0%.#%"*%3'&#02)#%"&# GET%*:#$("/*-3%*-#%("%(%"/H#%(-0%"*%,(/"%!*$%"&# done(bool)%3/4-()
23#0%!*$%0*,-)*(0/-4%/3%())*'("#0%23/-4 new%(-0%(%:*/-"#$%"*%/"%/3%3"*$#0%/-%"&# openedFiles%)/3"8 .#!*$#%3'&#02)/-4%(%-#, GET%*:#$("/*-8%>- listInfo()+%,#%,*2)0%3/H:)7%(::#-0%"&#%!/)#%-(H#%"*%(
QStringList+%/-3"#(0%*!%'())/-4 get()%$/4&"%(,(7+%(-0%/- done(bool)%,#%,*2)0%'()) get()%*-%"&#%-#5"
>!%"&# QUrlInfo%&*)03%"&#%0#"(/)3%*!%(%$#H*"#%0/$#'"*$7%"&("%/3%-*"%(%37H.*)/'%)/-I+%,#%(00%"&/3 !/)#%"*%0*,-)*(0%/-%"&# QStringList8%E&#%3#62#-'#%*!%#5#'2"/*-%,*2)0%"&#-%)**I%)/I#%"&/3J
0/$#'"*$7%"*%"&# pendingDirs%)/3"8%K#%3I/:%37H.*)/'%)/-I3%.#'(23#%"&#7%'(-%#(3/)7%)#(0%"*%/-!/-/"#
$#'2$3/*-8
connectToHost(host, port)
login()
void Spider::ftpDone(bool error) cd(directory_1)
{ list()
if (error) { ...
cerr << "Error: " << qPrintable(ftp.errorString()) << endl; cd(directory_N)
} else { list()
cout << "Downloaded " << qPrintable(currentDir) << " to " emit listInfo(file_1_1)
<< qPrintable(QDir::convertSeparators( emit listInfo(file_1_2)
QDir(currentLocalDir).canonicalPath())); ...
} emit listInfo(file_N_1)
qDeleteAll(openedFiles); emit listInfo(file_N_2)
openedFiles.clear(); ...
processNextDirectory(); emit done()
} get(file_1_1)
emit done()
get(file_1_2)
emit done()
E&# ftpDone()%3)*"%/3%'())#0%,&#-%())%"&#%GE9%'*HH(-03%&(1#%!/-/3&#0%*$%/!%(-%#$$*$%*''2$$#08%K# ...
0#)#"#%"&# QFile%*.F#'"3%"* :$#1#-"%H#H*$7%)#(I3%(-0%()3*%"*%')*3#%#('&%!/)#8%G/-())7+%,#%'()) get(file_N_1)
processNextDirectory()8%>!%"&#$#%($#%(-7%0/$#'"*$/#3%)#!"+%"&#%,&*)#%:$*'#33%.#4/-3%(4(/-%,/"&%"&# emit done()
get(file_N_2)
emit done() !2-'"/*-()/"7%(-0%/H:)#H#-"("/*-+%3*%,#%,/))%-*"%3&*,%"&#%&#(0#$%!/)#8
...

HttpGet::HttpGet(QObject *parent)
-*"&#$%3*)2"/*-%,*2)0%.#%"*%23#%*-# QFtp%*.F#'"%:#$%!/)#8%E&/3%,*2)0%#-(.)#%23%"*%0*,-)*(0%"&#%!/)#3 : QObject(parent)
/-%:($())#)+%"&$*24&%3#:($("#%GE9%'*--#'"/*-38 {
connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv); >-%"&#%'*-3"$2'"*$+%,#%'*--#'"%"&# QHttp%*.F#'"D3 done(bool)%3/4-()%"*%"&#%:$/1("# httpDone(bool)
QStringList args = app.arguments(); 3)*"8
if (args.count() != 2) {
cerr << "Usage: spider url" << endl
<< "Example:" << endl bool HttpGet::getFile(const QUrl &url)
<< " spider ftp://ftp.trolltech.com/freebies/leafnode" {
<< endl; if (!url.isValid()) {
return 1; cerr << "Error: Invalid URL" << endl;
} return false;
Spider spider; }
if (!spider.getDirectory(QUrl(args[1]))) if (url.scheme() != "http") {
return 1; cerr << "Error: URL must start with 'http:'" << endl;
QObject::connect(&spider, SIGNAL(done()), &app, SLOT(quit())); return false;
return app.exec(); }
} if (url.path().isEmpty()) {
cerr << "Error: URL has no path" << endl;
return false;
E&# main()%!2-'"/*-%'*H:)#"#3%"&#%:$*4$(H8%>!%"&#%23#$%0*#3 -*"%3:#'/!7%(%CW?%*-%"&#%'*HH(-0 }
)/-#+%,#%4/1#%(-%#$$*$%H#33(4#%(-0%"#$H/-("#%"&#%:$*4$(H8 QString localFileName = QFileInfo(url.path()).fileName();
if (localFileName.isEmpty())
localFileName = "httpget.out";
>-%.*"&%GE9%#5(H:)#3+%"&#%0("(%$#"$/#1#0%23/-4 get()%,(3%,$/""#-%"*%( QFile8%E&/3%-##0%-*"%.#%"&# file.setFileName(localFileName);
'(3#8%>!%,#%,(-"#0%"&#%0("(%/-%H#H*$7+%,#%'*2)0%23#%( QBuffer+%"&# QIODevice%32.')(33%"&("%,$(:3%( if (!file.open(QIODevice::WriteOnly)) {
QByteArray8%G*$%#5(H:)#J cerr << "Error: Cannot open " << qPrintable(file.fileName())
<< " for writing: " << qPrintable(file.errorString())
<< endl;
QBuffer *buffer = new QBuffer; return false;
buffer->open(QIODevice::WriteOnly); }
ftp.get(urlInfo.name(), buffer); http.setHost(url.host(), url.port(80));
http.get(url.path(), &file);
http.close();
return true;
K#%'*2)0%()3*%*H/"%"&#%>\L%0#1/'#%($42H#-"%"* get()%*$%:(33%(%-2))%:*/-"#$8%E&# QFtp%')(33%"&#- }
#H/"3%( readyRead()%3/4-()%#1#$7%"/H#%-#,%0("(%/3%(1(/)(.)#+%(-0%"&#%0("(%'(-%.#%$#(0%23/-4 read()
*$ readAll()8
E&# getFile()%!2-'"/*-%:#$!*$H3%"&#%3(H#%I/-0%*!%#$$*$%'&#'I3%(3%"&# FtpGet::getFile()%3&*,-
#($)/#$%(-0%23#3%"&#%3(H#%(::$*('&%"*%4/1/-4%"&#%!/)#%(%)*'()%-(H#8%K&#-%$#"$/#1/-4%!$*H%,#.%3/"#3+
Writing HTTP Clients -*%)*4/-%/3%-#'#33($7+%3*%,#%3/H:)7%3#"%"&#%&*3"%(-0%:*$"%M23/-4%"&#%0#!(2)"%QEE9 :*$"%_X%/!%-*-#%/3
3:#'/!/#0%/-%"&#%CW?N%(-0%0*,-)*(0%"&#%0("(%/-"*%"&#%!/)#+%3/-'#%"&#%3#'*-0%($42H#-"%"* QHttp::get()
3:#'/!/#3%"&#%*2":2"%>\L%0#1/'#8
E&# QHttp%')(33%/H:)#H#-"3%"&#%')/#-"%3/0#%*!%"&#%QEE9%:$*"*'*)%/-%B"8%>"%:$*1/0#3%1($/*23%!2-'"/*-3
"*%:#$!*$H%"&#%H*3"%'*HH*-%QEE9%*:#$("/*-3+%/-')20/-4 get()%(-0 post()+%(-0%:$*1/0#3%(%H#(-3%*!
E&#%QEE9%$#62#3"3%($#%62#2#0%(-0%#5#'2"#0%(37-'&$*-*23)7%/-%B"D3%#1#-"%)**:8%E&#%'*H:)#"/*-%*!
3#-0/-4%($./"$($7%QEE9%$#62#3"38%>!%7*2%&(1#%$#(0%"&#%:$#1/*23%3#'"/*-%(.*2" QFtp+%7*2%,/))%!/-0%"&(" "&#%$#62#3"3%/3%/-0/'("#0%.7 QHttpD3 done(bool)%3/4-()+%,&/'&%,#%'*--#'"#0%"* httpDone(bool)%/-%"&#
"&#$#%($#%H(-7%3/H/)($/"/#3%.#",##- QFtp%(-0 QHttp8 '*-3"$2'"*$8

E&# QHttp%')(33%,*$I3%(37-'&$*-*23)78%K&#-%,#%'())%(%!2-'"/*-%)/I# get()%*$ post()+%"&#%!2-'"/*-


$#"2$-3%/HH#0/("#)7+%(-0%"&#%0("(%"$(-3!#$%*''2$3%)("#$+%,&#-%'*-"$*)%$#"2$-3%"*%B"D3%#1#-"%)**:8 void HttpGet::httpDone(bool error)
E&/3%#-32$#3%"&("%"&#%(::)/'("/*-D3%23#$%/-"#$!('#%$#H(/-3%$#3:*-3/1#%,&/)#%QEE9%$#62#3"3%($#%.#/-4 {
:$*'#33#08 if (error) {
cerr << "Error: " << qPrintable(http.errorString()) << endl;
K#%,/))%$#1/#,%(%'*-3*)#%(::)/'("/*-%#5(H:)#%'())#0 httpget%"&("%3&*,3%&*,%"*%0*,-)*(0%(%!/)#%23/-4 } else {
cerr << "File downloaded as " << qPrintable(file.fileName())
"&#%QEE9%:$*"*'*)8%>"%/3%1#$7%3/H/)($%"*%"&# ftpget%#5(H:)#%!$*H%"&#%:$#1/*23%3#'"/*-+%.*"&%/-
<< endl;
} 32''#33!2))7%*$%-*"8%E&/3%/3%#(3/)7%('&/#1#0%.7%'*--#'"/-4%"*%"&# done(bool)%3/4-()+%,&/'&%/3%#H/""#0
file.close(); ,&#-%"&#%$#62#3"%62#2#%.#'*H#3%#H:"78
emit done();
}
K&#-%(-%#$$*$%*''2$3+%"&#%$#62#3"%62#2#%/3%(2"*H("/'())7%')#($#08%A2"%/!%,#%3'&#02)#%-#,%$#62#3"3
(!"#$%"&#%#$$*$%&(3%*''2$$#0%23/-4%"&#%3(H# QHttp%*.F#'"+%"&#3#%$#62#3"3%,/))%.#%62#2#0%(-0%3#-"%(3
232()8
L-'#%"&#%QEE9%$#62#3"3%($#%!/-/3&#0+%,#%')*3#%"&#%!/)#+%-*"/!7/-4%"&#%23#$%/!%(-%#$$*$%*''2$$#08
?/I# QFtp+ QHttp%:$*1/0#3%( readyRead()%3/4-()%(3%,#))%(3%"&# read()%(-0 readAll()%!2-'"/*-3%"&("%,#
E&# main()%!2-'"/*-%/3%1#$7%3/H/)($%"*%"&#%*-#%23#0%.7 ftpgetJ '(-%23#%/-3"#(0%*!%3:#'/!7/-4%(-%>\L%0#1/'#8

int main(int argc, char *argv[]) Writing TCP ClientServer Applications


{
QCoreApplication app(argc, argv);
E&# QTcpSocket%(-0 QTcpServer%')(33#3%'(-%.#%23#0%"*%/H:)#H#-"%E=9%')/#-"3%(-0%3#$1#$38%E=9%/3%(
QStringList args = app.arguments();
"$(-3:*$"%:$*"*'*)%"&("%!*$H3%"&#%.(3/3%*!%H*3"%(::)/'("/*-;)#1#)%>-"#$-#"%:$*"*'*)3+%/-')20/-4%GE9
if (args.count() != 2) {
cerr << "Usage: httpget url" << endl (-0%QEE9+%(-0%"&("%'(-%()3*%.#%23#0%!*$%'23"*H%:$*"*'*)38
<< "Example:" << endl
<< " httpget http://doc.trolltech.com/qq/index.html" E=9%/3%(%3"$#(H;*$/#-"#0%:$*"*'*)8%G*$%(::)/'("/*-3+%"&#%0("(%(::#($3%"*%.#%(%)*-4%3"$#(H+%$("&#$%)/I#
<< endl; (%)($4#%!)("%!/)#8%E&#%&/4&;)#1#)%:$*"*'*)3%.2/)"%*-%"*:%*!%E=9%($#%"7:/'())7%#/"&#$%)/-#;*$/#-"#0%*$
return 1; .)*'I;*$/#-"#0J
}
HttpGet getter; • ?/-#;*$/#-"#0%:$*"*'*)3%"$(-3!#$%0("(%(3%)/-#3%*!%"#5"+%#('&%"#$H/-("#0%.7%(%-#,)/-#8
if (!getter.getFile(QUrl(args[1])))
• A)*'I;*$/#-"#0%:$*"*'*)3%"$(-3!#$%0("(%(3%./-($7%0("(%.)*'I38%U('&%.)*'I%'*-3/3"3%*!%(%3/V#
return 1;
!/#)0%!*))*,#0%.7%"&("%H2'&%0("(8
QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));
return app.exec();
} QTcpSocket%/-&#$/"3%!$*H QIODevice%"QW*24& QAbstractSocket+%3*%/"%'(-%.#%$#(0%!$*H%(-0%,$/""#-%"*
23/-4%( QDataStream%*$%( QTextStream8%L-#%-*"(.)#%0/!!#$#-'#%,&#-%$#(0/-4%0("(%!$*H%(%-#",*$I
'*H:($#0%,/"&%$#(0/-4%!$*H%(%!/)#%/3%"&("%,#%H23"%H(I#%32$#%"&("%,#%&(1#%$#'#/1#0%#-*24&%0("(
E&# QHttp%')(33%:$*1/0#3%H(-7%*:#$("/*-3+%/-')20/-4 setHost()+ get()+ post()+%(-0 head()8%>!%(%3/"# !$*H%"&#%:##$%.#!*$#%,#%23#%"&# >>%*:#$("*$8%G(/)/-4%"*%0*%3*%H(7%$#32)"%/-%2-0#!/-#0%.#&(1/*$8
$#62/$#3%(2"&#-"/'("/*-+ setUser()%'(-%.#%23#0%"*%32::)7%(%23#$%-(H#%(-0%:(33,*$08 QHttp%'(-%23#
(%3*'I#"%32::)/#0%.7%"&#%:$*4$(HH#$%$("&#$%"&(-%/"3%*,-%/-"#$-() QTcpSocket8%E&/3%H(I#3%/"%:*33/.)# >-%"&/3%3#'"/*-+%,#%,/))%$#1/#,%"&#%'*0#%*!%(%')/#-"%(-0%(%3#$1#$%"&("%23#%(%'23"*H%.)*'I;*$/#-"#0
"*%23#%(%3#'2$# QtSslSocket+%:$*1/0#0%(3%(%B"%<*)2"/*-%!$*H%E$*))"#'&+%"*%('&/#1#%QEE9%*1#$%<<?8 :$*"*'*)8%E&#%')/#-"%/3%'())#0%E$/:%9)(--#$%(-0%())*,3%23#$3%"*%:)(-%"&#/$%-#5"%"$(/-%"$/:8%E&#%3#$1#$%/3
'())#0%E$/:%<#$1#$%(-0%:$*1/0#3%"&#%"$/:%/-!*$H("/*-%"*%"&#%')/#-"8%K#%,/))%3"($"%.7%,$/"/-4%"&#%E$/:
9)(--#$%')/#-"8
E*%3#-0%(%)/3"%*!%Z"4 %%`54.#%Z%:(/$3%"*%(%=P>%3'$/:"+%,#%'(-%23# post()J
E&#%E$/:%9)(--#$%:$*1/0#3%(%G$*H%!/#)0+%(%E*%!/#)0+%(%S("#%!/#)0+%(-% ::$*5/H("#%E/H#%!/#)0+%(-0%",*
http.setHost("www.example.com"); $(0/*%.2""*-3%"*%3#)#'"%,&#"&#$%"&#%(::$*5/H("#%"/H#%/3%"&("%*!%0#:($"2$#%*$%($$/1()8%K&#-%"&#%23#$
http.post("/cgi/somescript.py", "x=200&y=320", &file); ')/'I3%<#($'&+%"&#%(::)/'("/*-%3#-03%(%$#62#3"%"*%"&#%3#$1#$+%,&/'&%$#3:*-03%,/"&%(%)/3"%*!%"$(/-%"$/:3
"&("%H("'&%"&#%23#$D3%'$/"#$/(8%E&#%)/3"%/3%3&*,-%/-%( QTableWidget%/-%"&#%E$/:%9)(--#$%,/-0*,8%E&#
1#$7%.*""*H%*!%"&#%,/-0*,%/3%*''2:/#0%.7%( QLabel%"&("%3&*,3%"&#%3"("23%*!%"&#%)(3"%*:#$("/*-%(-0%(
QProgressBar8
K#%'(-%:(33%"&#%0("(%#/"&#$%(3%(-%_;./"%3"$/-4%*$%.7%:(33/-4%(-%*:#- QIODevice+%32'&%(3%( QFile8%G*$
H*$#%'*-"$*)+%,#%'(-%23#%"&# request()%!2-'"/*-+%,&/'&%(''#:"3%(-%($./"$($7%QEE9%&#(0#$%(-0%0("(8
G*$%#5(H:)#J !"#$%&':)')&*+%&*$!4&;/322%$&344/!031!.2
[View full size image]

QHttpRequestHeader header("POST", "/search.html");


header.setValue("Host", "www.trolltech.com");
header.setContentType("application/x-www-form-urlencoded");
http.setHost("www.trolltech.com");
http.request(header, "qt-interest=on&search=opengl");

QHttp%#H/"3%"&# requestStarted(int)%3/4-()%,&#-%/"%3"($"3%#5#'2"/-4%(%$#62#3"+%(-0%/"%#H/"3%"&#
requestFinished(int, bool)%3/4-()%,&#-%"&#%$#62#3"%&(3%!/-/3&#08%E&# int%:($(H#"#$%/3%(-%>S
-2H.#$%"&("%/0#-"/!/#3%(%$#62#3"8%>!%,#%($#%/-"#$#3"#0%/-%"&#%!("#%*!%/-0/1/02()%$#62#3"3+%,#%'(-%3"*$#
"&#%>S%-2H.#$3%,&#-%,#%3'&#02)#%"&#%$#62#3"38%^##:/-4%"$('I%*!%"&#%>S%-2H.#$3%())*,3%23%"*
:$*1/0#%0#"(/)#0%!##0.('I%"*%"&#%23#$8

>-%H*3"%(::)/'("/*-3+%,#%*-)7%,(-"%"*%I-*,%,&#"&#$%"&#%#-"/$#%3#62#-'#%*! $#62#3"3%'*H:)#"#0
tableWidget->verticalHeader()->hide();
tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
connect(searchButton, SIGNAL(clicked()),
this, SLOT(connectToServer()));
connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSearch()));
connect(&tcpSocket, SIGNAL(connected()), this, SLOT(sendRequest()));
connect(&tcpSocket, SIGNAL(disconnected()),
this, SLOT(connectionClosedByServer()));
connect(&tcpSocket, SIGNAL(readyRead()),
this, SLOT(updateTableWidget()));
connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(error()));
}

>-%"&#%'*-3"$2'"*$+%,#%/-/"/()/V#%"&#%0("#%(-0%"/H#%#0/"*$3%.(3#0%*-%"&#%'2$$#-"%0("#%(-0%"/H#8%K#
()3*%&/0#%"&#%:$*4$#33%.($+%.#'(23#%,#%*-)7%,(-"%"*%3&*,%/"%,&#-%(%'*--#'"/*-%/3%('"/1#8%>- +$
7%&!8"%2+%"&#%:$*4$#33%.($D3 minimum%(-0 maximum%:$*:#$"/#3%,#$#%.*"&%3#"%"*%X8%E&/3%"#))3%"&#
QProgressBar%"*%.#&(1#%(3%(%.237%/-0/'("*$%/-3"#(0%*!%(3%(%3"(-0($0%:#$'#-"(4#;.(3#0%:$*4$#33%.($8

)3*%/-%"&#%'*-3"$2'"*$+%,#%'*--#'"%"&# QTcpSocketD3 connected()+ disconnected()+ readyRead()+%(-0


error(QAbstractSocket::SocketError)%3/4-()3%"*%:$/1("#%3)*"38

E&#%E$/:%9)(--#$D3%23#$%/-"#$!('#%,(3%'$#("#0%23/-4 +$67%&!8"%2%/-%(%!/)#%'())#0 tripplanner.ui8 void TripPlanner::connectToServer()


Q#$#+%,#%,/))%!*'23%*-%"&#%3*2$'#%'*0#%*!%"&# QDialog%32.')(33%"&("%/H:)#H#-"3%"&#%(::)/'("/*-D3 {
!2-'"/*-()/"7J tcpSocket.connectToHost("tripserver.zugbahn.de", 6178);
tableWidget->setRowCount(0);
searchButton->setEnabled(false);
#include "ui_tripplanner.h" stopButton->setEnabled(true);
class TripPlanner : public QDialog, public Ui::TripPlanner statusLabel->setText(tr("Connecting to server..."));
{ progressBar->show();
Q_OBJECT nextBlockSize = 0;
public: }
TripPlanner(QWidget *parent = 0);
private slots:
void connectToServer();
E&# connectToServer()%3)*"%/3%#5#'2"#0%,&#-%"&#%23#$%')/'I3%<#($'&%"*%3"($"%(%3#($'&8%K#%'())
void sendRequest();
connectToHost()%*-%"&# QTcpSocket%*.F#'"%"*%'*--#'"%"*%"&#%3#$1#$+%,&/'&%,#%(332H#%/3%(''#33/.)#%("
void updateTableWidget();
void stopSearch(); :*$" a@b_%*-%"&#%!/'"/"/*23%&*3" TRipserver.zugbahn.de8%M>!%7*2%,(-"%"*%"$7%"&#%#5(H:)#%*-%7*2$%*,-
void connectionClosedByServer(); H('&/-#+%$#:)('#%"&#%&*3"%-(H#%,/"& QHostAddress::LocalHost8N%E&# connectToHost()%'())%/3
void error(); (37-'&$*-*23]%/"%(),(73%$#"2$-3%/HH#0/("#)78%E&#%'*--#'"/*-%/3%"7:/'())7%#3"(.)/3&#0%)("#$8%E&#
private: QTcpSocket%*.F#'"%#H/"3%"&# connected()%3/4-()%,&#-%"&#%'*--#'"/*-%/3%2:%(-0%$2--/-4+%*$
void closeConnection(); error(QAbstractSocket::SocketError)%/!%"&#%'*--#'"/*-%!(/)#08
QTcpSocket tcpSocket;
quint16 nextBlockSize;
R#5"+%,#%2:0("#%"&#%23#$%/-"#$!('#+%/-%:($"/'2)($%H(I/-4%"&#%:$*4$#33%.($%1/3/.)#8
};

G/-())7+%,#%3#"%"&# nextBlockSize%1($/(.)#%"*%X8%E&/3%1($/(.)#%3"*$#3%"&#%)#-4"&%*!%"&#%-#5"%.)*'I
$#'#/1#0%!$*H%"&#%3#$1#$8%K#%&(1#%'&*3#-%"*%23#%"&#%1()2#%*!%X%"*%H#(-%"&("%,#%0*-D"%7#"%I-*,%"&#
E&# TRipPlanner%')(33%/-&#$/"3%!$*H Ui::TripPlanner%M,&/'&%/3%4#-#$("#0%.7 uic%!$*H 3/V#%*!%"&#%-#5"%.)*'I8
tripplanner.uiN%/-%(00/"/*-%"* QDialog8%E&# tcpSocket%H#H.#$%1($/(.)#%#-'(:32)("#3%"&#%E=9
'*--#'"/*-8%E&# nextBlockSize%1($/(.)#%/3%23#0%,&#-%:($3/-4%"&#%.)*'I3%$#'#/1#0%!$*H%"&#%3#$1#$8
void TripPlanner::sendRequest()
{
TripPlanner::TripPlanner(QWidget *parent) QByteArray block;
: QDialog(parent) QDataStream out(&block, QIODevice::WriteOnly);
{ out.setVersion(QDataStream::Qt_4_1);
setupUi(this); out << quint16(0) << quint8('S') << fromComboBox->currentText()
QDateTime dateTime = QDateTime::currentDateTime(); << toComboBox->currentText() << dateEdit->date()
dateEdit->setDate(dateTime.date()); << timeEdit->time();
timeEdit->setTime(QTime(dateTime.time().hour(), 0)); if (departureRadioButton->isChecked()) {
progressBar->hide(); out << quint8('D');
progressBar->setSizePolicy(QSizePolicy::Preferred, } else {
QSizePolicy::Ignored);
out << quint8('A'); quint16 duration;
} quint8 changes;
out.device()->seek(0); QString trainType;
out << quint16(block.size() - sizeof(quint16)); in >> date >> departureTime >> duration >> changes >> trainType;
tcpSocket.write(block); arrivalTime = departureTime.addSecs(duration * 60);
statusLabel->setText(tr("Sending request...")); tableWidget->setRowCount(row + 1);
} QStringList fields;
fields << date.toString(Qt::LocalDate)
<< departureTime.toString(tr("hh:mm"))
<< arrivalTime.toString(tr("hh:mm"))
E&# sendRequest()%3)*"%/3%#5#'2"#0%,&#-%"&# QTcpSocket%*.F#'"%#H/"3%"&# connected()%3/4-()+ << tr("%1 hr %2 min").arg(duration / 60)
/-0/'("/-4%"&("%(%'*--#'"/*-%&(3%.##-%#3"(.)/3&#08%E&#%3)*"D3%"(3I%/3%"*%4#-#$("#%(%$#62#3"%"*%"&# .arg(duration % 60)
3#$1#$+%,/"&%())%"&#%/-!*$H("/*-%#-"#$#0%.7%"&#%23#$8 << QString::number(changes)
<< trainType;
E&#%$#62#3"%/3%(%./-($7%.)*'I%,/"&%"&#%!*))*,/-4%!*$H("J for (int i = 0; i < fields.count(); ++i)
tableWidget->setItem(row, i,
new QTableWidgetItem(fields[i]));
quint16 A)*'I%3/V#%/-%.7"#3%M#5')20/-4%"&/3%!/#)0N nextBlockSize = 0;
}
quint8 W#62#3"%"7:#%M(),(73%D<DN }
QString S#:($"2$#%'/"7
QString $$/1()%'/"7 E&# updateTableWidget()%3)*"%/3%'*--#'"#0%"*%"&# QTcpSocketD3 readyRead()%3/4-()+%,&/'&%/3%#H/""#0
,&#-#1#$%"&# QTcpSocket%&(3%$#'#/1#0%-#,%0("(%!$*H%"&#%3#$1#$8%E&#%3#$1#$%3#-03%23%(%)/3"%*!
QDate S("#%*!%"$(1#) :*33/.)#%"$(/-%"$/:3%"&("%H("'&%"&#%23#$D3%'$/"#$/(8%U('&%H("'&/-4%"$/:%/3%3#-"%(3%(%3/-4)#%.)*'I+%(-0
#('&%.)*'I%3"($"3%,/"&%(%3/V#8%E&# forever%)**:%/3%-#'#33($7%.#'(23#%,#%0*-D"%-#'#33($/)7%4#"%*-#
QTime ::$*5/H("#%"/H#%*!%"$(1#) .)*'I%*!%0("(%!$*H%"&#%3#$1#$%("%(%"/H#8cde%K#%H/4&"%&(1#%$#'#/1#0%(-%#-"/$#%.)*'I+%*$%F23"%:($"%*!%(
quint8 .)*'I+%*$%*-#%(-0%(%&()!%.)*'I3+%*$%#1#-%())%*!%"&#%.)*'I3%("%*-'#8
E/H#%/3%!*$%0#:($"2$#%MDSDN%*$%($$/1()%MD DN
[*]
The forever keyword is provided by Qt. It simply expands to for (;;).

K#%!/$3"%,$/"#%"&#%0("(%"*%( QByteArray%'())#0 block8%K#%'(-D"%,$/"#%"&#%0("(%0/$#'")7%"*%"&# !"#$%&':)5)&*+%&*$!4&<%$=%$67&8/.0>7


QTcpSocket%.#'(23#%,#%0*-D"%I-*,%"&#%3/V#%*!%"&#%.)*'I+%,&/'&%H23"%.#%3#-"%!/$3"+%2-"/)%(!"#$%,#%&(1#
:2"%())%"&#%0("(%/-"*%"&#%.)*'I8

K#%/-/"/())7%,$/"#%X%(3%"&#%.)*'I%3/V#+%!*))*,#0%.7%"&#%$#3"%*!%"&#%0("(8%E&#-%,#%'()) seek(0)%*-%"&#
>\L%0#1/'#%M( QBuffer%'$#("#0%.7 QDataStream%.#&/-0%"&#%3'#-#3N%"*%H*1#%.('I%"*%"&#%.#4/--/-4%*!
"&#%.7"#%($$(7+%(-0%*1#$,$/"#%"&#%/-/"/()%X%,/"&%"&#%3/V#%*!%"&#%.)*'ID3%0("(8%E&#%3/V#%/3%'()'2)("#0%.7
"(I/-4%"&#%.)*'ID3%3/V#%(-0%32."$('"/-4 sizeof(quint16)%M"&("%/3+%YN%"*%#5')20#%"&#%3/V#%!/#)0%!$*H%"&#
.7"#%'*2-"8% !"#$%"&("+%,#%'()) write()%*-%"&# QTcpSocket "*%3#-0%"&#%.)*'I%"*%"&#%3#$1#$8
<*%&*,%0*#3%"&# forever )**:%,*$If%>!%"&# nextBlockSize%1($/(.)#%/3%X+%"&/3%H#(-3%"&("%,#%&(1#%-*"
$#(0%"&#%3/V#%*!%"&#%-#5"%.)*'I8%K#%"$7%"*%$#(0%/"%M(332H/-4%"&#$#%($#%("%)#(3"%Y%.7"#3%(1(/)(.)#%!*$
void TripPlanner::updateTableWidget() $#(0/-4N8%E&#%3#$1#$%23#3%(%3/V#%1()2#%*! 0xFFFF%"*%3/4-/!7%"&("%"&#$#%/3%-*%H*$#%0("(%"*%$#'#/1#+%3*%/!
{ ,#%$#(0%"&/3%1()2#+%,#%I-*,%"&("%,#%&(1#%$#('&#0%"&#%#-08
QDataStream in(&tcpSocket);
in.setVersion(QDataStream::Qt_4_1); >!%"&#%.)*'I%3/V#%/3%-*" 0xFFFF+%,#%"$7%"*%$#(0%/-%"&#%-#5"%.)*'I8%G/$3"+%,#%'&#'I%"*%3##%/!%"&#$#%($#
forever {
.)*'I%3/V#%.7"#3%(1(/)(.)#%"*%$#(08%>!%"&#$#%($#%-*"+%,#%3"*:%"&#$#%!*$%-*,8%E&# readyRead()%3/4-()
int row = tableWidget->rowCount();
if (nextBlockSize == 0) { ,/))%.#%#H/""#0%(4(/-%,&#-%H*$#%0("(%/3%(1(/)(.)#+%(-0%,#%,/))%"$7%(4(/-%"&#-8
if (tcpSocket.bytesAvailable() < sizeof(quint16))
break; L-'#%,#%($#%32$#%"&("%(-%#-"/$#%.)*'I%&(3%($$/1#0+%,#%'(-%3(!#)7%23#%"&# >>%*:#$("*$%*-%"&#
in >> nextBlockSize; QDataStream%"*%#5"$('"%"&#%/-!*$H("/*-%$#)("#0%"*%(%"$/:+%(-0%,#%'$#("# QTableWidgetItem3%,/"&%"&("
} /-!*$H("/*-8% %.)*'I%$#'#/1#0%!$*H%"&#%3#$1#$%&(3%"&#%!*))*,/-4%!*$H("J
if (nextBlockSize == 0xFFFF) {
closeConnection();
statusLabel->setText(tr("Found %1 trip(s)").arg(row)); quint16 A)*'I%3/V#%/-%.7"#3%M#5')20/-4%"&/3%!/#)0N
break;
} QDate S#:($"2$#%0("#
if (tcpSocket.bytesAvailable() < nextBlockSize)
break; QTime S#:($"2$#%"/H#
QDate date;
QTime departureTime;
QTime arrivalTime;
quint8 ,#%,*2)0%#5:#'"J
R2H.#$%*!%'&(-4#3
QString E$(/-%"7:#
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
"%"&#%#-0+%,#%$#3#"%"&# nextBlockSize%1($/(.)#%"*%X%"*%/-0/'("#%"&("%"&#%-#5"%.)*'ID3%3/V#%/3%2-I-*,- TripPlanner tripPlanner;
(-0%-##03%"*%.#%$#(08 tripPlanner.show();
return app.exec();
}
void TripPlanner::closeConnection()
{
tcpSocket.close(); R*,%)#"D3%/H:)#H#-"%"&#%3#$1#$8%E&#%3#$1#$%'*-3/3"3%*!%",*%')(33#3J TRipServer%(-0 ClientSocket8
searchButton->setEnabled(true); E&# TRipServer%')(33%/-&#$/"3 QTcpServer+%(%')(33%"&("%())*,3%23%"*%(''#:"%/-'*H/-4%E=9%'*--#'"/*-38
stopButton->setEnabled(false); ClientSocket%$#/H:)#H#-"3 QTcpSocket%(-0%&(-0)#3%(%3/-4)#%'*--#'"/*-8% "%(-7%*-#%"/H#+%"&#$#%($#
progressBar->hide(); (3%H(-7 Client-Socket%*.F#'"3%/-%H#H*$7%(3%"&#$#%($#%')/#-"3%.#/-4%3#$1#08
}

class TripServer : public QTcpServer


E&# closeConnection()%:$/1("#%!2-'"/*-%')*3#3%"&#%'*--#'"/*-%"*%"&#%E=9%3#$1#$%(-0%2:0("#3%"&#%23#$ {
/-"#$!('#8%>"%/3%'())#0%!$*H updateTableWidget()%,&#-%"&# 0xFFFF%/3%$#(0%(-0%!$*H%3#1#$() *"&#$%3)*"3 Q_OBJECT
"&("%,#%,/))%'*1#$%3&*$")78 public:
TripServer(QObject *parent = 0);
private:
void TripPlanner::stopSearch() void incomingConnection(int socketId);
{ };
statusLabel->setText(tr("Search stopped"));
closeConnection();
} E&# tripServer%')(33%$#/H:)#H#-"3%"&# incomingConnection()%!2-'"/*-%!$*H QTcpServer8%E&/3%!2-'"/*-
/3%'())#0%,&#-#1#$%(%')/#-"%(""#H:"3%"*%'*--#'"%"*%"&#%:*$"%"&#%3#$1#$%/3%)/3"#-/-4%"*8

E&# stopSearch()%3)*"%/3%'*--#'"#0%"*%"&#%<"*:%.2""*-D3 clicked()%3/4-()8%U33#-"/())7%/"%F23"%'())3


closeConnection()8 TripServer::TripServer(QObject *parent)
: QTcpServer(parent)
{
}
void TripPlanner::connectionClosedByServer()
{
if (nextBlockSize != 0xFFFF)
statusLabel->setText(tr("Error: Connection closed by server")); E&# tripServer%'*-3"$2'"*$%/3%"$/1/()8
closeConnection();
}
void TripServer::incomingConnection(int socketId)
{
E&# connectionClosedByServer()%3)*"%/3%'*--#'"#0%"* QTcpSocketD3 disconnected()%3/4-()8%>!%"&# ClientSocket *socket = new ClientSocket(this);
3#$1#$%')*3#3%"&#%'*--#'"/*-%(-0%,#%&(1#%-*"%7#"%$#'#/1#0%"&# 0xFFFF%#-0;*!;0("(%H($I#$+%,#%"#)) socket->setSocketDescriptor(socketId);
}
"&#%23#$%"&("%(-%#$$*$%*''2$$#08%K#%'()) closeConnection()%(3%232()%"*%2:0("#%"&#%23#$%/-"#$!('#8

void TripPlanner::error() >- incomingConnection()+%,#%'$#("#%( ClientSocket%*.F#'"%(3%(%'&/)0%*!%"&# tripServer%*.F#'"+%(-0%,#


{ 3#"%/"3%3*'I#"%0#3'$/:"*$%"*%"&#%-2H.#$%:$*1/0#0%"*%238%E&# ClientSocket%*.F#'"%,/))%0#)#"#%/"3#)!
statusLabel->setText(tcpSocket.errorString()); (2"*H("/'())7%,&#-%"&#%'*--#'"/*-%/3%"#$H/-("#08
closeConnection();
}
class ClientSocket : public QTcpSocket
{
E&# error()%3)*"%/3%'*--#'"#0%"* QTcpSocketD3 error(QAbstractSocket::SocketError)%3/4-()8%K#%/4-*$# Q_OBJECT
public:
"&#%#$$*$%'*0#%(-0%23# QTcpSocket::errorString()+%,&/'&%$#"2$-3%(%&2H(-;$#(0(.)#%#$$*$%H#33(4#
ClientSocket(QObject *parent = 0);
!*$%"&#%)(3"%#$$*$%"&("%*''2$$#08
private slots:
void readClient();
private:
void generateRandomTrip(const QString &from, const QString &to,
const QDate &date, const QTime &time); "$(/-%"$/:38%A2"%&#$#%,#%,/))%.#%'*-"#-"%,/"&%(%!2-'"/*-%'())#0 generateRandomTrip()%"&("%,/))%4#-#$("#
quint16 nextBlockSize; (%$(-0*H%"$/:8%K#%'())%"&#%!2-'"/*-%(%$(-0*H%-2H.#$%*!%"/H#3+%(-0%"&#-%,#%3#-0 0xFFFF%"*%3/4-/!7
}; "&#%#-0%*!%"&#%0("(8% "%"&#%#-0+%,#%')*3#%"&#%'*--#'"/*-8

E&# ClientSocket%')(33%/-&#$/"3%!$*H QTcpSocket%(-0%#-'(:32)("#3%"&#%3"("#%*!%(%3/-4)#%')/#-"8 void ClientSocket::generateRandomTrip(const QString & /* from */,


const QString & /* to */, const QDate &date, const QTime &time)
{
ClientSocket::ClientSocket(QObject *parent) QByteArray block;
: QTcpSocket(parent) QDataStream out(&block, QIODevice::WriteOnly);
{ out.setVersion(QDataStream::Qt_4_1);
connect(this, SIGNAL(readyRead()), this, SLOT(readClient())); quint16 duration = rand() % 200;
connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); out << quint16(0) << date << time << duration << quint8(1)
nextBlockSize = 0; << QString("InterCity");
} out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));
write(block);
}
>-%"&#%'*-3"$2'"*$+%,#%#3"(.)/3&%"&#%-#'#33($7%3/4-()3)*"%'*--#'"/*-3+%(-0%,#%3#"%"&# nextBlockSize
1($/(.)#%"*%X+%/-0/'("/-4%"&("%,#%0*%-*"%7#"%I-*,%"&#%3/V#%*!%"&#%.)*'I%3#-"%.7%"&#%')/#-"8
E&# generateRandomTrip()%!2-'"/*-%3&*,3%&*,%"*%3#-0%(%.)*'I%*!%0("(%*1#$%(%E=9%'*--#'"/*-8%E&/3%/3
E&# disconnected()%3/4-()%/3%'*--#'"#0%"* deleteLater()+%( QObject;/-&#$/"#0%!2-'"/*-%"&("%0#)#"#3 1#$7%3/H/)($%"* ,&("%,#%0/0%/-%"&#%')/#-"%/-%"&# sendRequest()%!2-'"/*-%M:8%TYaN8%L-'#%(4(/-+%,#%,$/"#
"&#%*.F#'"%,&#-%'*-"$*)%$#"2$-3%"*%B"D3%#1#-"%)**:8%E&/3%#-32$#3%"&("%"&# ClientSocket%*.F#'"%/3 "&#%.)*'I%"*%( QByteArray%3*%"&("%,#%'(-%0#"#$H/-#%/"3%3/V#%.#!*$#%,#%3#-0%/"%23/-4 write()8
0#)#"#0%,&#-%"&#%3*'I#"%'*--#'"/*-%/3%')*3#08

int main(int argc, char *argv[])


void ClientSocket::readClient() {
{ QApplication app(argc, argv);
QDataStream in(this); TripServer server;
in.setVersion(QDataStream::Qt_4_1); if (!server.listen(QHostAddress::Any, 6178)) {
if (nextBlockSize == 0) { cerr << "Failed to bind to port" << endl;
if (bytesAvailable() < sizeof(quint16)) return 1;
return; }
in >> nextBlockSize; QPushButton quitButton(QObject::tr("&Quit"));
} quitButton.setWindowTitle(QObject::tr("Trip Server"));
if (bytesAvailable() < nextBlockSize) QObject::connect(&quitButton, SIGNAL(clicked()),
return; &app, SLOT(quit()));
quint8 requestType; quitButton.show();
QString from; return app.exec();
QString to; }
QDate date;
QTime time;
quint8 flag;
in >> requestType; >- main()+%,#%'$#("#%( tripServer%*.F#'"%(-0%( QPushButton%"&("%#-(.)#3%"&#%23#$%"*%3"*:%"&#%3#$1#$8
if (requestType == 'S') { K#%3"($"%"&#%3#$1#$%.7%'())/-4 QTcpSocket::listen()+%,&/'&%"(I#3%"&#%>9%(00$#33%(-0%:*$"%-2H.#$%*-
in >> from >> to >> date >> time >> flag; ,&/'&%,#%,(-"%"*%(''#:"%'*--#'"/*-38%E&#%3:#'/()%(00$#33%X8X8X8X%M QHostAddress::AnyN%3/4-/!/#3%(-7
srand(from.length() * 3600 + to.length() * 60 + time.hour()); >9%/-"#$!('#%:$#3#-"%*-%"&#%)*'()%&*3"8
int numTrips = rand() % 8;
for (int i = 0; i < numTrips; ++i)
generateRandomTrip(from, to, date, time); E&/3%'*H:)#"#3%*2$%')/#-"3#$1#$%#5(H:)#8%>-%"&/3%'(3#+%,#%23#0%(%.)*'I;*$/#-"#0%:$*"*'*)%"&("%())*,3
QDataStream out(this); 23%"*%23# QDataStream%!*$%$#(0/-4%(-0%,$/"/-48%>!%,#%,(-"#0%"*%23#%(%)/-#;*$/#-"#0%:$*"*'*)+%"&#
out << quint16(0xFFFF); 3/H:)#3"%(::$*('&%,*2)0%.#%"*%23# QTcpSocketD3 canReadLine()%(-0 readLine()%!2-'"/*-3%/-%(%3)*"
} '*--#'"#0%"*%"&# readyRead()%3/4-()J
close();
}
QStringList lines;
while (tcpSocket.canReadLine())
E&# readClient()%3)*"%/3%'*--#'"#0%"* QTcpSocketD3 readyRead()%3/4-()8%>! next-BlockSize%/3%X+%,# lines.append(tcpSocket.readLine());
3"($"%.7%$#(0/-4%"&#%.)*'I%3/V#]%*"&#$,/3#+%,#%&(1#%()$#(07%$#(0%/"+%(-0%/-3"#(0%,#%'&#'I%"*%3##%/!%(
,&*)#%.)*'I%&(3%($$/1#08%L-'#%(-%#-"/$#%.)*'I%/3%$#(07%!*$%$#(0/-4+%,#%$#(0%/"%/-%*-#%4*8%K#%23#%"&#
QDataStream%0/$#'")7%*-%"&# QTcpSocket%M"&# this%*.F#'"N%(-0%$#(0%"&#%!/#)03%23/-4%"&# >>%*:#$("*$8 K#%,*2)0%"&#-%:$*'#33%#('&%)/-#%"&("%&(3%.##-%$#(08% 3%!*$%3#-0/-4%0("(+%"&("%'(-%.#%0*-#%23/-4%(
QTextStream%*-%"&# QTcpSocket8
L-'#%,#%&(1#%$#(0%"&#%')/#-"D3%$#62#3"+%,#%($#%$#(07%"*%4#-#$("#%(%$#:)78%>!%"&/3%,#$#%(%$#()
(::)/'("/*-+%,#%,*2)0%)**I%2:%"&#%/-!*$H("/*-%/-%(%"$(/-%3'&#02)#%0("(.(3#%(-0%"$7%"*%!/-0%H("'&/-4 E&#%3#$1#$%/H:)#H#-"("/*-%"&("%,#%&(1#%23#0%0*#3-D"%3'()#%1#$7%,#))%,&#-%"&#$#%($#%)*"3%*!
'*--#'"/*-38%E&#%:$*.)#H%/3%"&("%,&/)#%,#%($#%:$*'#33/-4%(%$#62#3"+%,#%0*-D"%&(-0)#%"&#%*"&#$ connect(&timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));
'*--#'"/*-38% %H*$#%3'()(.)#%(::$*('&%,*2)0%.#%"*%3"($"%(%-#,%"&$#(0%!*$%#('&%'*--#'"/*-8%E&# timer.start(2 * 1000);
E&$#(0#0%G*$"2-#%<#$1#$%#5(H:)#%)*'("#0%/-%B"D3 examples/network/threadedfortuneserver%0/$#'"*$7 setWindowTitle(tr("Weather Balloon"));
/))23"$("#3%&*,%"*%0*%"&/38 }

Sending and Receiving UDP Datagrams >-%"&#%'*-3"$2'"*$+%,#%3"($"%( QTimer%"*%/-1*I# sendDatagram()%#1#$7%Y%3#'*-038

E&# QUdpSocket%')(33%'(-%.#%23#0%"*%3#-0%(-0%$#'#/1#%CS9%0("(4$(H38%CS9%/3%(-%2-$#)/(.)#+
0("(4$(H;*$/#-"#0%:$*"*'*)8%<*H#%(::)/'("/*-;)#1#)%:$*"*'*)3%23#%CS9%.#'(23#%/"%/3%H*$#%)/4&",#/4&" void WeatherBalloon::sendDatagram()
"&(-%E=98%K/"&%CS9+%0("(%/3%3#-"%(3%:('I#"3%M0("(4$(H3N%!$*H%*-#%&*3"%"*%(-*"&#$8%E&#$#%/3%-* {
'*-'#:"%*!%'*--#'"/*-+%(-0%/!%(%CS9%:('I#"%0*#3-D"%4#"%0#)/1#$#0%32''#33!2))7+%-*%#$$*$%/3%$#:*$"#0%"* QByteArray datagram;
"&#%3#-0#$8 QDataStream out(&datagram, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_1);
out << QDateTime::currentDateTime() << temperature() << humidity()
!"#$%&':)()&*+%&?%31+%$&<131!.2&344/!031!.2 << altitude();
udpSocket.writeDatagram(datagram, QHostAddress::LocalHost, 5824);
}

>- sendDatagram()+%,#%4#-#$("#%(-0%3#-0%(%0("(4$(H%'*-"(/-/-4%"&#%'2$$#-"%0("#+%"/H#+
"#H:#$("2$#+%&2H/0/"7+%(-0%()"/"20#J

QDateTime S("#%(-0%"/H#%*!%H#(32$#H#-"
double E#H:#$("2$#%M/-%g=N
double Q2H/0/"7%M/-%hN
double )"/"20#%M/-%H#"#$3N

K#%,/))%3##%&*,%"*%23#%CS9%!$*H%(%B"%(::)/'("/*- "&$*24&%"&#%K#("&#$%A())**-%(-0%K#("&#$%<"("/*-
#5(H:)#8%E&#%K#("&#$%A())**-%(::)/'("/*-%H/H/'3%(%,#("&#$%.())**-%"&("%3#-03%(%CS9%0("(4$(H
E&#%0("(4$(H%/3%3#-"%23/-4 QUdpSocket::writeDatagram()8%E&#%3#'*-0%(-0%"&/$0%($42H#-"3%"*
M:$#32H(.)7%23/-4%(%,/$#)#33%'*--#'"/*-N%'*-"(/-/-4%"&#%'2$$#-"%("H*3:&#$/'%'*-0/"/*-3%#1#$7%Y
3#'*-038%E&#%K#("&#$ <"("/*-%(::)/'("/*-%$#'#/1#3%"&#3#%0("(4$(H3%(-0%0/3:)(73%"&#H%*-%3'$##-8 writeDatagram()%($#%"&#%>9%(00$#33%(-0%"&#%:*$"%-2H.#$%*!%"&#%:##$%M"&#%K#("&#$%<"("/*-N8%G*$%"&/3
K#%,/))%3"($"%.7%$#1/#,/-4%"&#%'*0#%!*$%"&#%K#("&#$%A())**-8 #5(H:)#+%,#%(332H#%"&("%"&#%K#("&#$%<"("/*-%/3%$2--/-4%*-%"&#%3(H#%H('&/-#%(3%"&#%K#("&#$
A())**-+%3*%,#%23#%(-%>9%(00$#33%*!%@Yb8X8X8@%M QHostAddress::LocalHostN+%(%3:#'/()%(00$#33%"&("
0#3/4-("#3%"&#%)*'()%&*3"8
class WeatherBalloon : public QPushButton
{ C-)/I#%"&# QAbstractSocket%32.')(33#3+ QUdpSocket%0*#3%-*"%(''#:"%&*3"%-(H#3+%*-)7%&*3"%(00$#33#38
Q_OBJECT >!%,#%,(-"#0%"*%$#3*)1#%(%&*3"%-(H#%"*%/"3%>9%(00$#33%&#$#+%,#%&(1#%",*%'&*/'#3J%>!%,#%($#%:$#:($#0
public: "*%.)*'I%,&/)#%"&#%)**I2:%"(I#3%:)('#+%,#%'(-%23#%"&#%3"("/' QHostInfo::fromName()%!2-'"/*-8
WeatherBalloon(QWidget *parent = 0); L"&#$,/3#+%,#%'(-%23#%"&#%3"("/' QHostInfo::lookupHost()%!2-'"/*-+%,&/'&%$#"2$-3%/HH#0/("#)7%(-0
double temperature() const; '())3%"&#%3)*"%/"%/3%:(33#0%,/"&%( QHostInfo%*.F#'"%'*-"(/-/-4%"&#%'*$$#3:*-0/-4%(00$#33#3%,&#-%"&#
double humidity() const;
)**I2:%/3%'*H:)#"#8
double altitude() const;
private slots:
void sendDatagram();
private: int main(int argc, char *argv[])
QUdpSocket udpSocket; {
QTimer timer; QApplication app(argc, argv);
}; WeatherBalloon balloon;
balloon.show();
return app.exec();
}
E&# WeatherBalloon%')(33%/-&#$/"3%!$*H QPushButton8%>"%23#3%/"3 QUdpSocket%:$/1("# 1($/(.)#%!*$
'*HH2-/'("/-4%,/"&%"&#%K#("&#$%<"("/*-8
E&# main()%!2-'"/*-%3/H:)7%'$#("#3%( WeatherBalloon%*.F#'"+%,&/'&%3#$1#3%.*"&%(3%(%CS9%:##$%(-0%(3
( QPushButton%*-%3'$##-8%A7%')/'I/-4%"&# QPushButton+%"&#%23#$%'(-%62/"%"&#%(::)/'("/*-8
WeatherBalloon::WeatherBalloon(QWidget *parent)
: QPushButton(tr("Quit"), parent)
{ R*,%)#"D3%$#1/#,%"&#%3*2$'#%'*0#%!*$%"&#%K#("&#$%<"("/*-%')/#-"8
connect(this, SIGNAL(clicked()), this, SLOT(close()));
/-'*H/-4%0("(4$(H3%(-0%)#"3%23%(''#33%"&#H%*-#%("%(%"/H#8%R*$H())7+%"&#$#%3&*2)0%.#%*-)7%*-#
class WeatherStation : public QDialog 0("(4$(H+%.2"%,#%'(-D"%#5')20#%"&#%:*33/./)/"7%"&("%"&#%3#-0#$%,*2)0%3#-0%(%!#,%0("(4$(H3%/-%(%$*,
{ .#!*$#%"&# readyRead()%3/4-()%/3%#H/""#08%>-%"&("%'(3#+%,#%'(-%/4-*$#%())%"&#%0("(4$(H3%#5'#:"%"&#
Q_OBJECT )(3"%*-#+%3/-'#%"&#%#($)/#$%*-#3%'*-"(/-%*.3*)#"#%("H*3:&#$/'%'*-0/"/*-38
public:
WeatherStation(QWidget *parent = 0);
private slots: E&# pendingDatagramSize()%!2-'"/*-%$#"2$-3%"&#%3/V#%*!%"&#%!/$3"%:#-0/-4%0("(4$(H8%G$*H%"&#
void processPendingDatagrams(); (::)/'("/*-D3%:*/-"%*!%1/#,+%0("(4$(H3%($#%(),(73%3#-"%(-0%$#'#/1#0%(3%(%3/-4)#%2-/"%*!%0("(8%E&/3
private: H#(-3%"&("%/!%(-7%.7"#3%($#%(1(/)(.)#+%(-%#-"/$#%0("(4$(H%'(-%.#%$#(08%E&# readDatagram()%'())
QUdpSocket udpSocket; '*:/#3%"&#%'*-"#-"3%*!%"&#%!/$3"%:#-0/-4%0("(4$(H%/-"*%"&#%3:#'/!/#0 char *%.2!!#$%M"$2-'("/-4%0("(%/!
QLabel *dateLabel; "&#%.2!!#$%/3%"**%3H())N%(-0%(01(-'#3%"*%"&#%-#5"%:#-0/-4%0("(4$(H8%L-'#%,#%&(1#%$#(0%())%"&#
QLabel *timeLabel; 0("(4$(H3+%,#%0#'*H:*3#%"&#%)(3"%*-#%M"&#%*-#%,/"&%"&#%H*3"%$#'#-"%("H*3:&#$/'%H#(32$#H#-"3N
... /-"*%/"3%:($"3%(-0%:*:2)("#%"&# QLineEdit3%,/"&%"&#%-#,%0("(8
QLineEdit *altitudeLineEdit;
};
int main(int argc, char *argv[])
{
E&# WeatherStation%')(33%/-&#$/"3%!$*H QDialog8%>"%)/3"#-3%"*%(%:($"/'2)($%CS9%:*$"+%:($3#3%(-7 QApplication app(argc, argv);
/-'*H/-4%0("(4$(H3%M!$*H%"&#%K#("&#$%A())**-N+%(-0%0/3:)(73%"&#/$%'*-"#-"3%/-%!/1#%$#(0;*-)7 WeatherStation station;
QLineEdit38%E&#%*-)7%:$/1("#%1($/(.)#%*!%/-"#$#3"%&#$#%/3 udpSocket%*!%"7:# QUdpSocket+%,&/'&%,#%,/)) station.show();
23#%"*%$#'#/1#%0("(4$(H38 return app.exec();
}

WeatherStation::WeatherStation(QWidget *parent)
: QDialog(parent) G/-())7+%/- main()+%,#%'$#("#%(-0%3&*,%"&# WeatherStation8
{
udpSocket.bind(5824); K#%&(1#%-*,%!/-/3&#0%*2$%CS9%3#-0#$ (-0%$#'#/1#$8%E&#%(::)/'("/*-3%($#%(3%3/H:)#%(3%:*33/.)#+%,/"&
connect(&udpSocket, SIGNAL(readyRead()),
"&#%K#("&#$%A())**-%3#-0/-4%0("(4$(H3%(-0%"&#%K#("&#$%<"("/*-%$#'#/1/-4%"&#H8%>-%H*3"%$#();,*$)0
this, SLOT(processPendingDatagrams()));
(::)/'("/*-3+%.*"&%(::)/'("/*-3%,*2)0%-##0%"*%.*"&%$#(0%(-0%,$/"#%*-%"&#/$%3*'I#"8%E&#
...
} QUdpSocket::writeDatagram()%!2-'"/*-3%'(-%.#%:(33#0%(%&*3"%(00$#33%(-0%:*$"%-2H.#$+%3*%"&#
QUdpSocket%'(-%$#(0%!$*H%"&#%&*3"%(-0%:*$"%/"%/3%.*2-0%"*%,/"& bind()+%(-0%,$/"#%"*%3*H#%*"&#$%&*3"
(-0%:*$"8
>-%"&#%'*-3"$2'"*$+%,#%3"($"%.7%./-0/-4%"&# QUdpSocket%"*%"&#%:*$"%"&("%"&#%,#("&#$%.())**-%/3
"$(-3H/""/-4%"*8%</-'#%,#%&(1#%-*"%3:#'/!/#0%(%&*3"%(00$#33+%"&#%3*'I#"%,/))%(''#:"%0("(4$(H3%3#-"%"*
(-7%>9%(00$#33%"&("%.#)*-43%"*%"&#%H('&/-#%"&#%K#("&#$%<"("/*-%/3%$2--/-4%*-8%E&#-+%,#%'*--#'"%"&#
3*'I#"D3 readyRead()%3/4-()%"*%"&#%:$/1("# processPendingDatagrams()%"&("%#5"$('"3%(-0%0/3:)(73%"&#
0("(8

void WeatherStation::processPendingDatagrams()
{
QByteArray datagram;
do {
datagram.resize(udpSocket.pendingDatagramSize());
udpSocket.readDatagram(datagram.data(), datagram.size());
} while (udpSocket.hasPendingDatagrams());
QDateTime dateTime;
double temperature;
double humidity;
double altitude;
QDataStream in(&datagram, QIODevice::ReadOnly);
in.setVersion(QDataStream::Qt_4_1);
in >> dateTime >> temperature >> humidity >> altitude;
dateLineEdit->setText(dateTime.date().toString());
timeLineEdit->setText(dateTime.time().toString());
temperatureLineEdit->setText(tr("%1 ° C").arg(temperature));
humidityLineEdit->setText(tr("%1%").arg(humidity));
altitudeLineEdit->setText(tr("%1 m").arg(altitude));
}

E&# processPendingDatagrams()%3)*"%/3%'())#0%,&#-%(%0("(4$(H%&(3%($$/1#08 QUdpSocket%62#2#3%"&#


E&#%(.*1#%!2-'"/*-3%($#%())%0#')($#0%/- QXmlContentHandler8%G*$%3/H:)/'/"7+%,#%*H/""#0%3*H#%*!%"&#
Chapter 15. XML ($42H#-"3%"* startElement()%(-0 endElement()8

• 7,46"$%&;<=&>"#?&/1; QXmlContentHandler%/3%F23"%*-#%*!%H(-7%&(-0)#$%')(33#3%"&("%'(-%.#%23#0%/-%'*-F2-'"/*-%,/"&
• 7,46"$%&;<=&>"#?&9@< QXmlSimpleReader8%E&#%*"&#$3%($# QXmlEntityResolver+ QXmlDTDHandler+ QXmlErrorHandler+
• !"#"$%&;<= QXmlDeclHandler+%(-0 QXmlLexicalHandler8%E&#3#%')(33#3%*-)7%0#')($#%:2$#%1/$"2()%!2-'"/*-3%(-0%4/1#
/-!*$H("/*-%(.*2"%0/!!#$#-"%I/-03%*!%:($3/-4%#1#-"38%G*$%H*3"%(::)/'("/*-3+ QXmlContentHandler%(-0
iO?%MU5"#-3/.)#%O($I2:%?(-42(4#N%/3%(%4#-#$();:2$:*3#%"#5"%!/)#%!*$H("%"&("%/3%:*:2)($%!*$%0("( QXmlErrorHandler%($#%"&#%*-)7%",*%"&("%($#%-##0#08
/-"#$'&(-4#%(-0%0("(%3"*$(4#8%B"%:$*1/0#3%",*%0/3"/-'"% 9>3%!*$%$#(0/-4%iO?%0*'2H#-"3%(3%:($"%*!
"&# +$9 .%H*02)#J G*$%'*-1#-/#-'#+%B"%()3*%:$*1/0#3 QXmlDefaultHandler+%(%')(33%"&("%/-&#$/"3%!$*H%())%"&#%&(-0)#$
')(33#3%(-0%"&("%:$*1/0#3%"$/1/()%/H:)#H#-"("/*-3%!*$%())%"&#%!2-'"/*-38%E&/3%0#3/4-+%,/"&%H(-7
• < i%M</H:)#% 9>%!*$%iO?N%$#:*$"3%Z:($3/-4%#1#-"3Z%0/$#'")7%"*%"&#%(::)/'("/*-%"&$*24&%1/$"2() (.3"$('"%&(-0)#$%')(33#3%(-0%*-#%"$/1/()%32.')(33+%/3%2-232()%!*$%B"]%/"%,(3%(0*:"#0%"*%')*3#)7%!*))*,
!2-'"/*-38 "&#%H*0#)%j(1(%/H:)#H#-"("/*-8
• SLO%MS*'2H#-"%L.F#'"%O*0#)N%'*-1#$"3%(-%iO?%0*'2H#-"%/-"*%(%"$##%3"$2'"2$#+%,&/'&%"&#
(::)/'("/*-%'(-%"&#-%-(1/4("#8 K#%,/))%-*,%$#1/#,%(-%#5(H:)#%"&("%3&*,3%&*,%"*%23# QXmlSimpleReader%(-0 QXmlDefaultHandler%"*
:($3#%(-%(0%&*'%iO?%!/)#%!*$H("%(-0%$#-0#$%/"3%'*-"#-"3%/-%( QtreeWidget8%E&# QXmlDefaultHandler
E&#$#%($#%H(-7%!('"*$3%"*%"(I#%/-"*%(''*2-"%,&#-%'&**3/-4%.#",##-%SLO%(-0%< i%!*$%(%:($"/'2)($ 32.')(33 /3%'())#0 SaxHandler+%(-0%"&#%!*$H("%/"%&(-0)#3%/3%"&("%*!%(%.**I%/-0#5+%,/"&%/-0#5%#-"$/#3
(::)/'("/*-8%< i%/3%H*$#%)*,%)#1#)%(-0%232())7%!(3"#$+%,&/'&%H(I#3%/"%#3:#'/())7%(::$*:$/("#%.*"&%!*$ (-0%32.#-"$/#38
3/H:)#%"(3I3%M)/I#%!/-0/-4%())%"&#%*''2$$#-'#3%*!%(%4/1#-%"(4%/-%(-%iO?%0*'2H#-"N%(-0%!*$%$#(0/-4
1#$7%)($4#%!/)#3%"&("%H(7%-*"%!/"%/-%H#H*$78%A2"%!*$%H(-7%(::)/'("/*-3+%"&#%'*-1#-/#-'#%*!!#$#0%.7
!"#$%&'@)')&A2+%$!1320%&1$%%&B.$ SaxHandler
SLO%*2",#/4&3%"&#%:*"#-"/()%3:##0%(-0%H#H*$7%.#-#!/"3%*!%< i8

G*$%,$/"/-4%iO?%!/)#3+%",*%*:"/*-3%($#%(1(/)(.)#%(3%,#))J%K#%'(-%4#-#$("#%"&#%iO?%.7%&(-0+%*$%,#
'(-%$#:$#3#-"%"&#%0("(%(3%(%SLO%"$##%/-%H#H*$7%(-0%(3I%"&#%"$##%"*%,$/"#%/"3#)!%"*%(%!/)#8

Reading XML with SAX


Q#$#D3%"&#%.**I%/-0#5%!/)#%"&("%/3%0/3:)(7#0%/-%"&# QTReeWidget%/- G/42$#%@k8YJ
< i%/3%(%:2.)/'%0*H(/-%0#%!('"*%3"(-0($0% 9>%!*$%$#(0/-4%iO?%0*'2H#-"38%B"D3%< i%')(33#3%($#
H*0#)#0%(!"#$%"&#%< iY%j(1(%/H:)#H#-"("/*-+%,/"&%3*H#%0/!!#$#-'#3%/-%-(H/-4%"*%H("'&%"&#%B"
'*-1#-"/*-38%G*$%H*$#%/-!*$H("/*-%(.*2"%< i+%3## &"":J\\,,,83(5:$*F#'"8*$4\8 <?xml version="1.0"?>
<bookindex>
B"%:$*1/0#3%(%< i;.(3#0%-*-;1()/0("/-4%iO?%:($3#$%'())#0 QXmlSimpleReader8%E&/3%:($3#$%$#'*4-/V#3 <entry term="sidebearings">
,#));!*$H#0%iO?%(-0%32::*$"3%iO?%-(H#3:('#38%K&#-%"&#%:($3#$%4*#3%"&$*24&%"&#%0*'2H#-"+%/" <page>10</page>
'())3%1/$"2()%!2-'"/*-3%/-%$#4/3"#$#0%&(-0)#$%')(33#3%"*%/-0/'("#%:($3/-4%#1#-"38%ME&#3#%Z:($3/-4 <page>34-35</page>
#1#-"3Z%($#%2-$#)("#0%"*%B"%#1#-"3+%32'&%(3%I#7%(-0%H*23#%#1#-"38N%G*$%#5(H:)#+%)#"D3%(332H#%"&# <page>307-308</page>
:($3#$%/3%(-()7V/-4%"&#%!*))*,/-4%iO?%0*'2H#-"J </entry>
<entry term="subtraction">
<entry term="of pictures">
<doc> <page>115</page>
<quote>Ars longa vita brevis</quote> <page>244</page>
</doc> </entry>
<entry term="of vectors">
<page>9</page>
</entry>
E&#%:($3#$%,*2)0%'())%"&#%!*))*,/-4%:($3/-4%#1#-"%&(-0)#$3J </entry>
</bookindex>

startDocument()
startElement("doc")
startElement("quote")
!"#$%&'@)5)&C&8..>&!29%D&B!/%&9!74/3E%9&!2&3 QtreeWidget
characters("Ars longa vita brevis")
endElement("quote")
endElement("doc")
endDocument()
}
return true;
}

!" startElement()#$/-1(%*-#%'#1.,,"3#7!"-#(!"#&".3"&#"-1*/-("&'#.#-"7#*)"-%-;#(.;5# !"#(!%&3


).&.+"("&#%'#(!"#(.;<'#-.+"#=*&#+*&"#)&"1%'",>4#%('#?@/.,%$%"3#-.+"?A5# !"#$*/&(!#).&.+"("&#%'#(!"
,%'(#*$#.((&%0/("'5#B-#(!%'#"C.+),"4#7"#%;-*&"#(!"#$%&'(#.-3#'"1*-3#).&.+"("&'5# !">#.&"#/'"$/,#$*&
89:#$%,"'#(!.(#/'"#89:<'#-.+"').1"#+"1!.-%'+4#.#'/0D"1(#(!.(#%'#3%'1/''"3#%-#3"(.%,#%-#(!"#&"$"&"-1"
3*1/+"-(.(%*-5
!"#$%&'(#'(")#(*#%+),"+"-(#(!"#).&'"&#%'#(*#'/01,.'' QXmlDefaultHandler2
B$#(!"#(.;#%' <entry>4#7"#1&".("#.#-"7 QtreeWidget#%("+5#B$#(!"#(.;#%'#-"'("3#7%(!%-#.-*(!"& <entry>
(.;4#(!"#-"7#(.;#3"$%-"'#.#'/0"-(&>#%-#(!"#%-3"C4#.-3#(!"#-"7 QtreeWidgetItem#%'#1&".("3#.'#.#1!%,3
class SaxHandler : public QXmlDefaultHandler *$#(!" QtreeWidgetItem#(!.(#&")&"'"-('#(!"#"-1*+).''%-;#"-(&>5#E(!"&7%'"4#7"#1&".("#(!"
{ QTReeWidgetItem#7%(! treeWidget#.'#%('#).&"-(4#+.F%-;#%(#.#(*)G,"H",#%("+5#I"#1.,, setText()#(*#'"(
public: (!"#("C(#'!*7-#%-#1*,/+-#J#(*#(!"#H.,/"#*$#(!" <entry>#(.;<' term#.((&%0/("5
SaxHandler(QTreeWidget *tree);
bool startElement(const QString &namespaceURI,
const QString &localName, B$#(!"#(.;#%' <page>4#7"#'"(#(!" currentText#(*#0"#.-#"+)(>#'(&%-;5# !" currentText#'"&H"'#.'#.-
const QString &qName, .11/+/,.(*&#$*&#(!"#("C(#,*1.("3#0"(7""-#(!" <page>#.-3 </page>#(.;'5
const QXmlAttributes &attributes);
bool endElement(const QString &namespaceURI, K(#(!"#"-34#7"#&"(/&- true#(*#(",,#LK8#(*#1*-(%-/"#).&'%-;#(!"#$%,"5#B$#7"#7.-("3#(*#&")*&(#/-F-*7-
const QString &localName, (.;'#.'#"&&*&'4#7"#7*/,3#&"(/&- false#%-#(!*'"#1.'"'5#I"#7*/,3#(!"-#.,'*#&"%+),"+"-(
const QString &qName);
errorString()#$&*+ QXmlDefaultHandler#(*#&"(/&-#.-#.))&*)&%.("#"&&*&#+"''.;"5
bool characters(const QString &str);
bool fatalError(const QXmlParseException &exception);
private:
QTreeWidget *treeWidget; bool SaxHandler::characters(const QString &str)
QTreeWidgetItem *currentItem; {
QString currentText; currentText += str;
}; return true;
}

!" SaxHandler#1,.''#%-!"&%(' QXmlDefaultHandler#.-3#&"%+),"+"-('#$*/&#$/-1(%*-'2 startElement()4


endElement()4 characters()4#.-3 fatalError()5# !"#$%&'(#(!&""#$/-1(%*-'#.&"#3"1,.&"3#%- !" characters()#$/-1(%*-#%'#1.,,"3#(*#&")*&(#1!.&.1("&#3.(.#%-#(!"#89:#3*1/+"-(5#I"#'%+),>#.))"-3
QXmlContentHandler6#(!"#,.'(#$/-1(%*-#%'#3"1,.&"3#%- QXmlErrorHandler5 (!"#1!.&.1("&'#(*#(!" currentText#H.&%.0,"5

SaxHandler::SaxHandler(QTreeWidget *tree) bool SaxHandler::endElement(const QString & /* namespaceURI */,


{ const QString & /* localName */,
treeWidget = tree; const QString &qName)
currentItem = 0; {
} if (qName == "entry") {
currentItem = currentItem->parent();
} else if (qName == "page") {
if (currentItem) {
!" SaxHandler#1*-'(&/1(*&#.11")('#(!" QtreeWidget#7"#7.-(#(*#)*)/,.("#7%(!#(!"#%-$*&+.(%*-#'(*&"3 QString allPages = currentItem->text(1);
%-#(!"#89:#$%,"5 if (!allPages.isEmpty())
allPages += ", ";
allPages += currentText;
bool SaxHandler::startElement(const QString & /* namespaceURI */, currentItem->setText(1, allPages);
const QString & /* localName */, }
const QString &qName, }
const QXmlAttributes &attributes) return true;
{ }
if (qName == "entry") {
if (currentItem) {
currentItem = new QTreeWidgetItem(currentItem); !" endElement()#$/-1(%*-#%'#1.,,"3#7!"-#(!"#&".3"&#"-1*/-("&'#.#1,*'%-;#(.;5#M/'(#.'#7%(!
} else {
startElement()4#(!"#(!%&3#).&.+"("&#%'#(!"#-.+"#*$#(!"#(.;5
currentItem = new QTreeWidgetItem(treeWidget);
}
currentItem->setText(0, attributes.value("term")); B$#(!"#(.;#%' </entry>4#7"#/)3.("#(!" currentItem#)&%H.("#H.&%.0,"#(*#)*%-(#(*#(!"#1/&&"-(
} else if (qName == "page") { QtreeWidgetItem<'#).&"-(5# !%'#"-'/&"'#(!.(#(!" currentItem#H.&%.0,"#%'#&"'(*&"3#(*#(!"#H.,/"#%(#!",3
currentText.clear();
0"$*&"#(!"#1*&&"')*-3%-; <entry>#(.;#7.'#&".35
QT += xml
B$#(!"#(.;#%' </page>4#7"#.33#(!"#')"1%$%"3#).;"#-/+0"&#*&#).;"#&.-;"#(*#(!"#1*++.G'").&.("3#,%'(
%-#(!"#1/&&"-(#%("+<'#("C(#%-#1*,/+-#N5
Reading XML with DOM
bool SaxHandler::fatalError(const QXmlParseException &exception)
{ QE9#%'#.#'(.-3.&3#KRB#$*&#).&'%-;#89:#3"H",*)"3#0>#(!"#I*&,3#I%3"#I"0#S*-'*&(%/+#=ITSA5#U(
QMessageBox::warning(0, QObject::tr("SAX Handler"), )&*H%3"'#.#-*-GH.,%3.(%-;#QE9#:"H",#V#%+),"+"-(.(%*-#$*&#&".3%-;4#+.-%)/,.(%-;4#.-3#7&%(%-;#89:
QObject::tr("Parse error at line %1, column " 3*1/+"-('5
"%2:\n%3.")
.arg(exception.lineNumber()) QE9#&")&"'"-('#.-#89:#$%,"#.'#.#(&""#%-#+"+*&>5#I"#1.-#-.H%;.("#(!&*/;!#(!"#QE9#(&""#.'#+/1!
.arg(exception.columnNumber()) .'#7"#7.-(4#.-3#7"#1.-#+*3%$>#(!"#(&""#.-3#'.H"#%(#0.1F#(*#3%'F#.'#.-#89:#$%,"5
.arg(exception.message()));
return false;
} :"(<'#1*-'%3"&#(!"#$*,,*7%-;#89:#3*1/+"-(2

<doc>
!" fatalError()#$/-1(%*-#%'#1.,,"3#7!"-#(!"#&".3"&#$.%,'#(*#).&'"#(!"#89:#$%,"5#B$#(!%'#*11/&'4#7" <quote>Ars longa vita brevis</quote>
'%+),>#3%'),.>#.#+"''.;"#0*C4#;%H%-;#(!"#,%-"#-/+0"&4#(!"#1*,/+-#-/+0"&4#.-3#(!"#).&'"&<'#"&&*& <translation>Art is long, life is short</translation>
("C(5 </doc>

!%'#1*+),"("'#(!"#%+),"+"-(.(%*-#*$#(!" SaxHandler#1,.''5#O*7#,"(<'#'""#!*7#7"#1.-#+.F"#/'"#*$
%(2 B(#1*&&"')*-3'#(*#(!"#$*,,*7%-;#QE9#(&""2

bool parseFile(const QString &fileName)


{
QStringList labels;
labels << QObject::tr("Terms") << QObject::tr("Pages");
QTreeWidget *treeWidget = new QTreeWidget;
treeWidget->setHeaderLabels(labels);
treeWidget->setWindowTitle(QObject::tr("SAX Handler"));
treeWidget->show();
QFile file(fileName);
QXmlInputSource inputSource(&file); !"#QE9#(&""#1*-(.%-'#-*3"'#*$#3%$$"&"-(#(>)"'5#P*&#"C.+),"4#.- Element#-*3"#1*&&"')*-3'#(*#.-
QXmlSimpleReader reader; *)"-%-;#(.;#.-3#%('#+.(1!%-;#1,*'%-;#(.;5# !"#+.("&%.,#(!.(#$.,,'#0"(7""-#(!"#(.;'#.))".&'#.'#1!%,3
SaxHandler handler(treeWidget); -*3"'#*$#(!" Element#-*3"5
reader.setContentHandler(&handler);
reader.setErrorHandler(&handler);
return reader.parse(inputSource); B-#U(4#(!"#-*3"#(>)"'#=,%F"#.,,#*(!"&#QE9G&",.("3#1,.''"'A#!.H"#. QDom#)&"$%C5# !/'4 QDomElement
} &")&"'"-('#.- Element#-*3"4#.-3 QDomText#&")&"'"-('#. Text#-*3"5

Q%$$"&"-(#(>)"'#*$#-*3"'#1.-#!.H"#3%$$"&"-(#F%-3'#*$#1!%,3#-*3"'5#P*&#"C.+),"4#.- Element#-*3"#1.-
I"#'"(#/)#. QtreeWidget#7%(!#(7*#1*,/+-'5# !"-#7"#1&".("#. QFile#*0D"1(#$*&#(!"#$%,"#(!.(#%'#(* 0" 1*-(.%-#*(!"& Element#-*3"'4#.-3#.,'* EntityReference4 Text4 CDATASection4 ProcessingInstruction4
&".3#.-3#. QXmlSimpleReader#(*#).&'"#(!"#$%,"5#I"#3*-<(#-""3#(*#*)"-#(!" QFile#*/&'",H"'6 .-3 Comment#-*3"'5 P%;/&"#NW5T#'!*7'#7!%1!#-*3"'#1.-#!.H"#7!%1!#F%-3'#*$#1!%,3#-*3"'5# !"#-*3"'
QXmlInputSource#3*"'#(!.(#./(*+.(%1.,,>5 '!*7-#%-#;&.>#1.--*(#!.H"#.->#1!%,3#-*3"'#*$#(!"%&#*7-5

P%-.,,>4#7"#1&".("#. SaxHandler#*0D"1(4#7"#%-'(.,,#%(#*-#(!"#&".3"&#0*(!#.'#.#1*-("-(#!.-3,"&#.-3#.' !"#$%&'()*)&+,$%-./0!12&$%1,.!3-40!54&6%.7%%-&89:&-32%4


.-#"&&*&#!.-3,"&4#.-3#7"#1.,, parse()#*-#(!"#&".3"&#(*#)"&$*&+#(!"#).&'%-;5
[View full size image]

B-'(".3#*$#).''%-;#.#'%+),"#$%,"#*0D"1(#(*#(!" parse()#$/-1(%*-4#7"#).''#. QXmlInputSource5# !%'#1,.''


*)"-'#(!"#$%,"#%(#%'#;%H"-4#&".3'#%(#=(.F%-;#%-(*#.11*/-(#.->#1!.&.1("&#"-1*3%-;#')"1%$%"3#%-#(!"
<?xml?>#3"1,.&.(%*-A4#.-3#)&*H%3"'#.-#%-("&$.1"#(!&*/;!#7!%1!#(!"#).&'"&#&".3'#(!"#$%,"5

B- SaxHandler4#7"#*-,>#&"%+),"+"-("3#$/-1(%*-'#$&*+#(!" QXmlContentHandler#.-3 QXmlErrorHandler


1,.''"'5#B$#7"#!.3#%+),"+"-("3#$/-1(%*-'#$&*+#*(!"&#!.-3,"&#1,.''"'4#7"#7*/,3#.,'*#!.H"#-""3"3#(*
1.,,#(!"%&#1*&&"')*-3%-;#'"(("&#$/-1(%*-'#*-#(!"#&".3"&5

*#,%-F#(!"#.)),%1.(%*-#.;.%-'(#(!" !"#$#,%0&.&>4#7"#+/'(#.33#(!%'#,%-"#(*#(!" .pro#$%,"2


B-#(!"#1*-'(&/1(*&4#7"#1&".("#. QDomDocument#*0D"1(#.-3#1.,, setContent()#*-#%(#(*#!.H"#%(#&".3#(!"
89:#3*1/+"-(#)&*H%3"3#0>#(!" QIODevice5# !" setContent()#$/-1(%*-#./(*+.(%1.,,>#*)"-'#(!"#3"H%1"
%$#%(#%'-<(#.,&".3>#*)"-5# !"-#7"#1.,, documentElement()#*-#(!" QDomDocument#(*#*0(.%-#%('#'%-;,"
QDomElement#1!%,34#.-3#7"#1!"1F#(!.(#%(#%'#. <bookindex>#","+"-(5#I"#%("&.("#*H"&#.,,#(!"#1!%,3#-*3"'4
.-3#%$#(!"#-*3"#%'#.- <entry>#","+"-(4#7"#1.,, parseEntry()#(*#).&'"#%(5

!" QDomNode#1,.''#1.-#'(*&"#.->#(>)"#*$#-*3"5#B$#7"#7.-(#(*#)&*1"''#.#-*3"#$/&(!"&4#7"#+/'(#$%&'(
1*-H"&(#%(#(*#(!"#&%;!(#3.(.#(>)"5#B-#(!%'#"C.+),"4#7"#*-,>#1.&"#.0*/( Element#-*3"'4#'*#7"#1.,,
toElement()#*-#(!" QDomNode#(*#1*-H"&(#%(#(*#. QDomElement#.-3#(!"-#1.,, tagName()#(*#&"(&%"H"#(!"
","+"-(<'#(.;#-.+"5#B$#(!"#-*3"#%' %&!#*$#(>)" Element4#(!" toElement()#$/-1(%*-#&"(/&-'#.#-/,,
QDomElement#*0D"1(4#7%(!#.-#"+)(>#(.;#-.+"5

void DomParser::parseEntry(const QDomElement &element,


*#%,,/'(&.("#!*7#(*#/'"#QE9#$*&#&".3%-;#89:#$%,"'4#7"#7%,,#7&%("#.#).&'"&#$*&#(!"#0**F#%-3"C#$%," QTreeWidgetItem *parent)
$*&+.(#3"'1&%0"3#%-#(!"#)&"H%*/'#'"1(%*-#=)5#TXJA5 {
QTreeWidgetItem *item;
if (parent) {
class DomParser item = new QTreeWidgetItem(parent);
{ } else {
public: item = new QTreeWidgetItem(treeWidget);
DomParser(QIODevice *device, QTreeWidget *tree); }
private: item->setText(0, element.attribute("term"));
void parseEntry(const QDomElement &element, QDomNode node = element.firstChild();
QTreeWidgetItem *parent); while (!node.isNull()) {
QTreeWidget *treeWidget; if (node.toElement().tagName() == "entry") {
}; parseEntry(node.toElement(), item);
} else if (node.toElement().tagName() == "page") {
QDomNode childNode = node.firstChild();
while (!childNode.isNull()) {
I"#3"$%-"#.#1,.''#1.,,"3 DomParser#(!.(#7%,,#).&'"#.#0**F#%-3"C#89:#3*1/+"-(#.-3#3%'),.>#(!"#&"'/,( if (childNode.nodeType() == QDomNode::TextNode) {
%-#. QTReeWidget5# !%'#1,.''#3*"'#-*(#%-!"&%(#$&*+#.->#*(!"&#1,.''5 QString page = childNode.toText().data();
QString allPages = item->text(1);
if (!allPages.isEmpty())
DomParser::DomParser(QIODevice *device, QTreeWidget *tree) allPages += ", ";
{ allPages += page;
treeWidget = tree; item->setText(1, allPages);
QString errorStr; break;
int errorLine; }
int errorColumn; childNode = childNode.nextSibling();
QDomDocument doc; }
if (!doc.setContent(device, true, &errorStr, &errorLine, }
&errorColumn)) { node = node.nextSibling();
QMessageBox::warning(0, QObject::tr("DOM Parser"), }
QObject::tr("Parse error at line %1, " }
"column %2:\n%3")
.arg(errorLine)
.arg(errorColumn)
B- parseEntry()4#7"#1&".("#. QTReeWidget#%("+5#B$#(!"#(.;#%'#-"'("3#7%(!%-#.-*(!"& <entry>#(.;4#(!"
.arg(errorStr));
return; -"7#(.;#3"$%-"'#.#'/0"-(&>#%-#(!"#%-3"C4#.-3#7"#1&".("#(!" QTReeWidgetItem#.'#.#1!%,3#*$#(!"
} QtreeWidgetItem#(!.(#&")&"'"-('#(!"#"-1*+).''%-;#"-(&>5#E(!"&7%'"4#7"#1&".("#(!" QtreeWidgetItem
QDomElement root = doc.documentElement(); 7%(! treeWidget#.'#%('#).&"-(4#+.F%-;#%(#.#(*)G,"H",#%("+5#I"#1.,, setText()#(*#'"(#(!"#("C(#'!*7-#%-
if (root.tagName() != "bookindex") 1*,/+-#J#(*#(!"#H.,/"#*$#(!" <entry>#(.;<' term#.((&%0/("5
return;
QDomNode node = root.firstChild(); E-1"#7"#!.H"#%-%(%.,%Y"3#(!" QtreeWidgetItem4#7"#%("&.("#*H"&#(!"#1!%,3#-*3"'#*$#(!" QDomElement
while (!node.isNull()) {
-*3"#1*&&"')*-3%-;#(*#(!"#1/&&"-( <entry>#(.;5
if (node.toElement().tagName() == "entry")
parseEntry(node.toElement(), 0);
node = node.nextSibling(); B$#(!"#","+"-(#%' <entry>4#7"#1.,, parseEntry()#7%(!#(!"#1/&&"-(#%("+#.'#(!"#'"1*-3#.&;/+"-(5# !"
} -"7#"-(&><' QTReeWidgetItem#7%,,#(!"-#0"#1&".("3#7%(!#(!"#"-1*+).''%-;#"-(&><' QTReeWidgetItem#.'
} %('#).&"-(5

B$#(!"#","+"-(#%' <page>4#7"#-.H%;.("#(!&*/;!#(!"#","+"-(<'#1!%,3#,%'(#(*#$%-3#. Text#-*3"5#E-1"#7"


!.H"#$*/-3#%(4#7"#1.,, toText()#(*#1*-H"&(#%(#(*#. QDomText#*0D"1(#.-3 data()#(*#"C(&.1(#(!"#("C(#.'#. quote.appendChild(latin);
QString5# !"-#7"#.33#(!"#("C(#(*#(!"#1*++.G'").&.("3#,%'(#*$#).;"#-/+0"&'#%-#1*,/+-#N#*$#(!" translation.appendChild(english);
QtreeWidgetItem5 QTextStream out(&file);
doc.save(out, Indent);
:"(<'#-*7#'""#!*7#7"#1.-#/'"#(!" DomParser#1,.''#(*#).&'"#.#$%,"2

!"#'"1*-3#.&;/+"-(#(* save()#%'#(!"#%-3"-(.(%*-#'%Y"#(*#/'"5#K#-*-GY"&*#H.,/"#+.F"'#(!"#$%,"#".'%"&
void parseFile(const QString &fileName) $*&#!/+.-'#(*#&".35#Z"&"<'#(!"#89:#$%,"#*/()/(2
{
QStringList labels;
labels << QObject::tr("Terms") << QObject::tr("Pages"); <doc>
QTreeWidget *treeWidget = new QTreeWidget; <quote>Ars longa vita brevis</quote>
treeWidget->setHeaderLabels(labels); <translation>Art is long, life is short</translation>
treeWidget->setWindowTitle(QObject::tr("DOM Parser")); </doc>
treeWidget->show();
QFile file(fileName);
DomParser(&file, treeWidget);
K-*(!"&#'1"-.&%*#*11/&'#%-#.)),%1.(%*-'#(!.(#/'"#(!"#QE9#(&""#.'#(!"%&#)&%+.&>#3.(.#'(&/1(/&"5# !"'"
}
.)),%1.(%*-'#7*/,3#-*&+.,,>#&".3#%-#89:#3*1/+"-('#/'%-;#QE94#(!"-#+*3%$>#(!"#QE9#(&""#%-
+"+*&>4#.-3#$%-.,,>#1.,, save()#(*#1*-H"&(#(!"#(&""#0.1F#(*#89:5

I"#'(.&(#0>#'"((%-;#/)#. QtreeWidget5# !"-#7"#1&".("#. QFile#.-3#. DomParser5#I!"-#(!" DomParser [>#3"$./,(4 QDomDocument::save()#/'"'#\ PG]#.'#(!"#"-1*3%-;#$*&#(!"#;"-"&.("3#$%,"5#I"#1.-#/'"


%'#1*-'(&/1("34#%(#).&'"'#(!"#$%,"#.-3#)*)/,.("'#(!"#(&""#7%3;"(5 .-*(!"&#"-1*3%-;#0>#)&")"-3%-;#.-#89:#3"1,.&.(%*-#'/1!#.'

:%F"#(!"#)&"H%*/'#"C.+),"4#7"#-""3#(!"#$*,,*7%-;#,%-"#%-#(!"#.)),%1.(%*-<' .pro#$%,"#(*#,%-F#.;.%-'(#(!"
!"#$#,%0&.&>2 <?xml version="1.0" encoding="ISO-8859-1"?>

QT += xml
(*#(!"#QE9#(&""5# !"#$*,,*7%-;#1*3"#'-%))"(#'!*7'#!*7#(*#3*#(!%'2

K'#(!"#"C.+),"#%,,/'(&.("'4#-.H%;.(%-;#(!&*/;!#.#QE9#(&""#1.-#0"#1/+0"&'*+"5#L%+),>#"C(&.1(%-; QTextStream out(&file);


(!"#("C(#0"(7""- <page>#.-3 </page>#&"@/%&"3#/'#(*#%("&.("#(!&*/;!#.#,%'(#*$ QDomNode'#/'%-; QDomNode xmlNode = doc.createProcessingInstruction("xml",
firstChild()#.-3 nextSibling()5#R&*;&.++"&'#7!*#/'"#QE9#.#,*(#*$("-#7&%("#(!"%&#*7-#!%;!"&G,"H", "version=\"1.0\" encoding=\"ISO-8859-1\"");
7&.))"&#$/-1(%*-'#(*#'%+),%$>#1*++*-,>#-""3"3#*)"&.(%*-'4#'/1!#.'#"C(&.1(%-;#(!"#("C(#0"(7""- doc.insertBefore(xmlNode, doc.firstChild());
*)"-%-;#.-3#1,*'%-;#(.;'5 doc.save(out, Indent);

Writing XML ^"-"&.(%-;#89:#$%,"'#0>#!.-3#%'-<(#+/1!#!.&3"&#(!.-#/'%-;#QE95#I"#1.-#/'" QTextStream#.-3#7&%("


(!"#'(&%-;'#.'#7"#7*/,3#3*#7%(!#.->#*(!"&#("C(#$%,"5# !"#+*'(#(&%1F>#).&(#%'#(*#"'1.)"#')"1%.,
!"&"#.&"#0.'%1.,,>#(7*#.))&*.1!"'#$*&#;"-"&.(%-;#89:#$%,"'#$&*+#U(#.)),%1.(%*-'2 1!.&.1("&'#%-#("C(#.-3#.((&%0/("#H.,/"'5# !" Qt::escape()#$/-1(%*-#"'1.)"'#(!"#1!.&.1("&'#<_<4#<`<4
.-3#<a<5#Z"&"<'#'*+"#1*3"#(!.(#+.F"'#/'"#*$#%(2
• I"#1.-#0/%,3#.#QE9#(&""#.-3#1.,, save()#*-#%(5
• I"#1.-#;"-"&.("#89:#0>#!.-35
QTextStream out(&file);
!"#1!*%1"#0"(7""-#(!"'"#.))&*.1!"'#%'#*$("-#%-3")"-3"-(#*$#7!"(!"&#7"#/'"#LK8#*&#QE9#$*& out.setCodec("UTF-8");
&".3%-;#89:#3*1/+"-('5 out << "<doc>\n"
<< " <quote>" << Qt::escape(quoteText) << "</quote>\n"
<< "
Z"&"<'#.#1*3"#'-%))"(#(!.(#%,,/'(&.("'#!*7#7"#1.-#1&".("#.#QE9#(&""#.-3#7&%("#%(#/'%-;#. <<" <translation>" << Qt::escape(translationText)
QTextStream2 << "</translation>\n"
<< "</doc>\n";

const int Indent = 4;


QDomDocument doc;
QDomElement root = doc.createElement("doc"); !" !' ()*!+*$,#.&(%1,"#?^"-"&.(%-;#89:?4#.H.%,.0,"#*-,%-"#.( !(()2bb3*15(&*,,("1!51*+b@@b@@JWG
QDomElement quote = doc.createElement("quote"); ;"-"&.(%-;GC+,5!(+,4#)&"'"-('#.#H"&>#'%+),"#1,.''#(!.(#+.F"'#%(#".'>#(*#;"-"&.("#89:#$%,"'5# !"
QDomElement translation = doc.createElement("translation"); 1,.''#(.F"'#1.&"#*$#(!"#3"(.%,'#'/1!#.'#')"1%.,#1!.&.1("&'4#%-3"-(.(%*-4#.-3#"-1*3%-;#%''/"'4#,".H%-;
QDomText latin = doc.createTextNode("Ars longa vita brevis"); /'#$&""#(*#1*-1"-(&.("#*-#(!"#89:#7"#7.-(#(*#;"-"&.("5# !"#1,.''#7.'#3"'%;-"3#(*#7*&F#7%(!#U(#T
QDomText english = doc.createTextNode("Art is long, life is short"); 0/(#%(#%'#(&%H%.,#(*#)*&(#(*#U(#X5
doc.appendChild(root);
root.appendChild(quote);
root.appendChild(translation);
Chapter 16. Providing Online Help
• !!"#$%&'()#*#+&( $%&'(*,-(./0*#1&( 0$&2. 34"%
• 5&$,6(7 48#9:!;&4:(*&(*()$<%"4(34"%(=,6$,4
• 5&$,6(7#(>&&$&#*,#(?!:(@!;4:?+"(A,"$,4(34"%

9*'(#.)),%1.(%*-'#)&*H%3"#(!"%&#/'"&'#7%(!#*-,%-"#!",)5#L*+"#!",)#%'#'!*&(4#'/1!#.'#(**,(%)'4#'(.(/'
(%)'4#.-3#?I!.(<'# !%'c?#!",)5#O.(/&.,,>4#U(#'/))*&('#.,,#*$#(!"'"5#E(!"&#!",)#1.-#0"#+/1!#+*&"
"C("-'%H"4#%-H*,H%-;#+.->#).;"'#*$#("C(5#P*&#(!%'#F%-3#*$#!",)4#>*/#1.-#/'" QTextBrowser#.'#.#'%+),"
*-,%-"#!",)#0&*7'"&4#*&#>*/#1.-#%-H*F" !'-../.!)%!#*&#.-#Z 9:#0&*7'"&#$&*+#>*/&#.)),%1.(%*-5

Tooltips, Status Tips, and "What's This?" Help


K#(**,(%)#%'#.#'+.,,#)%"1"#*$#("C(#(!.(#.))".&'#7!"-#(!"#+*/'"#!*H"&'#*H"&#.#7%3;"(#$*&#.#1"&(.%-
)"&%*3#*$#(%+"5# **,(%)'#.&"#)&"'"-("3#7%(!#0,.1F#("C(#*-#.#>",,*7#0.1F;&*/-35# !"%&#)&%+.&>#/'"#%'
(*#)&*H%3"#("C(/.,#3"'1&%)(%*-'#*$#(**,0.&#0/((*-'5

I"#1.-#.33#(**,(%)'#(*#.&0%(&.&>#7%3;"('#%-#1*3"#/'%-; QWidget::setToolTip()5#P*&#"C.+),"2

findButton->setToolTip(tr("Find next"));

B-#'*+"#'%(/.(%*-'4#%(#%'#3"'%&.0,"#(*#)&*H%3"#+*&"#%-$*&+.(%*-#.0*/(#.#7%3;"(#(!.-#1.-#0"#;%H"-#0>
*#'"(#(!"#(**,(%)#*$#. QAction#(!.(#1*/,3#0"#.33"3#(*#.#+"-/#*&#.#(**,0.&4#7"#1.-#'%+),>#1.,, (**,(%)'#*&#'(.(/'#(%)'5#P*&#"C.+),"4#7"#+%;!(#7.-(#(*#)&*H%3"#.#1*+),"C#3%.,*;#7%(!#"C),.-.(*&>
setToolTip()#*-#(!"#.1(%*-5#P*&#"C.+),"2 ("C(#.0*/(#".1!#$%",3#7%(!*/(#$*&1%-;#(!"#/'"&#(*#%-H*F"#.#'").&.("#!",)#7%-3*75#?I!.(<'# !%'c?
+*3"#%'#.-#%3".,#'*,/(%*-#$*&#(!%'5#I!"-#.#7%-3*7#%'#%-#?I!.(<'# !%'c?#+*3"4#(!"#1/&'*&#1!.-;"'#(*
.-3#(!"#/'"&#1.-#1,%1F#*-#.->#/'"&#%-("&$.1"#1*+)*-"-(#(*#*0(.%-#%('#!",)#("C(5# *#"-("&#?I!.(<'
newAction = new QAction(tr("&New"), this);
!%'c?#+*3"4#(!"#/'"&#1.-#"%(!"&#1,%1F#(!"#c#0/((*-#%-#(!"#3%.,*;<'#(%(,"#0.&#=*-#I%-3*7'#.-3#dQeA#*&
newAction->setToolTip(tr("New document"));
)&"'' Shift+F15

Z"&"#%'#.-#"C.+),"#*$#.#?I!.(<'# !%'c?#("C(#'"(#*-#.#3%.,*;2
B$#7"#3*-<(#"C),%1%(,>#'"(#.#(**,(%)4 QAction#7%,,#./(*+.(%1.,,>#/'"#(!"#.1(%*-#("C(5

K#'(.(/'#(%)#%'#.,'*#.#'!*&(#)%"1"#*$#3"'1&%)(%H"#("C(4#/'/.,,>#.#,%((,"#,*-;"&#(!.-#.#(**,(%)5#I!"-#(!" dialog->setWhatsThis(tr("<img src=\":/images/icon.png\">"


+*/'"#!*H"&'#*H"&#.#(**,0.&#0/((*-#*&#.#+"-/#*)(%*-4#.#'(.(/'#(%)#.))".&'#%-#(!"#'(.(/'#0.&5#S.,, "&nbsp;The meaning of the Source field depends "
setStatusTip()#(*#.33#.#'(.(/'#(%)#(*#.-#.1(%*-#*&#(*#.#7%3;"(2 "on the Type field:"
"<ul>"
"<li><b>Books</b> have a Publisher"
newAction->setStatusTip(tr("Create a new document")); "<li><b>Articles</b> have a Journal name with "
"volume and issue number"
"<li><b>Theses</b> have an Institution name "
"and a Department name"
!"#$%&';)')&<-&,551!/,.!3-&4037!-"&,&.331.!5&,-2&,&4.,.#4&.!5 "</ul>"));
[View full size image]

I"#1.-#/'"#Z 9:#(.;'#(*#$*&+.(#(!"#("C(#*$#.#?I!.(<'# !%'c?#("C(5#B-#(!"#"C.+),"4#7"#%-1,/3"#.-


%+.;"#=7!%1!#%'#,%'("3#%-#(!"#.)),%1.(%*-<'#&"'*/&1"#$%,"A4#.#0/,,"("3#,%'(4#.-3#'*+"#("C(#%-#0*,35# !"
(.;'#.-3#.((&%0/("'#(!.(#U(#'/))*&('#.&"#')"1%$%"3#.( !(()2bb3*15(&*,,("1!51*+bX5Nb&%1!("C(G!(+,G
'/0'"(5!(+,5

!"#$%&';)=)&<&2!,13"&4037!-"&,&>?0,.@4&A0!4B>&0%15&.%C.
I"#0";%-#7%(!#(!"#!".3"&#$%,"2
I!"-#7"#'"(#.#?I!.(<'# !%'c?#("C(#*-#.-#.1(%*-4#(!"#("C(#7%,,#0"#'!*7-#7!"-#(!"#/'"&#1,%1F'#(!"
+"-/#%("+#*&#(**,0.&#0/((*-#*&#)&"''"'#(!"#'!*&(1/(#F">#7!%,"#%-#?I!.(<'# !%'c?#+*3"5#I!"-#(!"
/'"&#%-("&$.1"#1*+)*-"-('#*$#.-#.)),%1.(%*-<'#+.%-#7%-3*7#)&*H%3"#?I!.(<'# !%'c?#("C(4#%(#%' #include <QWidget>
1/'(*+.&>#(*#)&*H%3"#.#I!.(<'# !%'c#*)(%*-#%-#(!"#Z",)#+"-/#.-3#.#1*&&"')*-3%-;#(**,0.&#0/((*-5 class QPushButton;
!%'#1.-#0"#3*-"#0>#1&".(%-;#.#I!.(<'# !%'c#.1(%*-#7%(!#(!"#'(.(%1 QWhatsThis::createAction() class QTextBrowser;
$/-1(%*-#.-3#.33%-;#(!"#.1(%*-#%(#&"(/&-'#(*#.#Z",)#+"-/#.-3#(*#.#(**,0.&5# !" QWhatsThis#1,.''#.,'* class HelpBrowser : public QWidget
)&*H%3"'#'(.(%1#$/-1(%*-'#(*#)&*;&.++.(%1.,,>#"-("&#.-3#,".H"#?I!.(<'# !%'c?#+*3"5 {
Q_OBJECT
public:
HelpBrowser(const QString &path, const QString &page,
Using QTextBrowser as a Simple Help Engine QWidget *parent = 0);
static void showPage(const QString &page);
private slots:
:.&;"#.)),%1.(%*-'#+.>#&"@/%&"#+*&"#*-,%-"#!",)#(!.-#(**,(%)'4#'(.(/'#(%)'4#.-3#?I!.(<'# !%'c?#!",) void updateWindowTitle();
1.-#&".'*-.0,>#'!*75#K#'%+),"#'*,/(%*-#(*#(!%'#%'#(*#)&*H%3"#.#!",)#0&*7'"&5#K)),%1.(%*-'#(!.(#%-1,/3" private:
.#!",)#0&*7'"&#(>)%1.,,>#!.H"#.#Z",)#"-(&>#%-#(!"#+.%-#7%-3*7<'#Z",)#+"-/#.-3 .#Z",)#0/((*-#%- QTextBrowser *textBrowser;
"H"&>#3%.,*;5 QPushButton *homeButton;
QPushButton *backButton;
B-#(!%'#'"1(%*-4#7"#)&"'"-(#(!"#'%+),"#!",)#0&*7'"&#'!*7-#%- P%;/&"#Nf5T#.-3#"C),.%-#!*7#%(#1.-#0" QPushButton *closeButton;
};
/'"3#7%(!%-#.-#.)),%1.(%*-5# !"#7%-3*7#/'"'#. QTextBrowser#(*#3%'),.>#!",)#).;"'#(!.(#.&"#+.&F"3
/)#7%(!#.-#Z 9:G0.'"3#'>-(.C5 QTextBrowser#1.-#!.-3,"#.#,*(#*$#Z 9:#(.;'4#'*#%(#%'#%3".,#$*&#(!%'
)/&)*'"5
!" HelpBrowser#)&*H%3"'#.#'(.(%1#$/-1(%*-#(!.(#1.-#0"#1.,,"3#$&*+#.->7!"&"#%-#(!"#.)),%1.(%*-5# !%'
$/-1(%*-#1&".("'#. HelpBrowser#7%-3*7#.-3#'!*7'#(!"#;%H"-#).;"5
!"#$%&';)*)&A0% HelpBrowser&7!2"%.
[View full size image] Z"&"<'#(!"#0";%--%-;#*$#(!"#%+),"+"-(.(%*-2

#include <QtGui>
#include "helpbrowser.h"
HelpBrowser::HelpBrowser(const QString &path, const QString &page,
QWidget *parent)
: QWidget(parent)
{
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_GroupLeader); P*&#(!%'#"C.+),"4#7"#.''/+"#(!.(#(!"#3*1/+"-(.(%*-#%'#,*1.("3#%-#(!" doc#'/03%&"1(*&>#*$#(!"
textBrowser = new QTextBrowser; 3%&"1(*&>#1*-(.%-%-;#(!"#.)),%1.(%*-<'#"C"1/(.0,"5#K,,#(!"#).;"'#).''"3#(*#(!" showPage()#$/-1(%*-#7%,,
homeButton = new QPushButton(tr("&Home")); 0"#(.F"-#$&*+#(!%'#'/03%&"1(*&>5
backButton = new QPushButton(tr("&Back"));
closeButton = new QPushButton(tr("Close"));
closeButton->setShortcut(tr("Esc")); O*7#7"#.&"#&".3>#(* %-H*F"#(!"#!",)#0&*7'"&#$&*+#(!"#.)),%1.(%*-5#B-#(!"#.)),%1.(%*-<'#+.%-#7%-3*74
QHBoxLayout *buttonLayout = new QHBoxLayout; 7"#7*/,3#1&".("#.#Z",)#.1(%*-#.-3#1*--"1(#%(#(*#. help()#',*(#(!.(#1*/,3#,**F#,%F"#(!%'2
buttonLayout->addWidget(homeButton);
buttonLayout->addWidget(backButton);
buttonLayout->addStretch(); void MainWindow::help()
buttonLayout->addWidget(closeButton); {
QVBoxLayout *mainLayout = new QVBoxLayout; HelpBrowser::showPage("index.html");
mainLayout->addLayout(buttonLayout); }
mainLayout->addWidget(textBrowser);
setLayout(mainLayout);
connect(homeButton, SIGNAL(clicked()), textBrowser, SLOT(home()));
connect(backButton, SIGNAL(clicked()), !%'#.''/+"'#(!.(#(!"#+.%-#!",)#$%,"#%'#1.,,"3 index.html5#P*&#3%.,*;'4#7"#7*/,3#1*--"1(#(!"#Z",)
textBrowser, SLOT(backward())); 0/((*-#(*#. help()#',*(#(!.(#+%;!(#,**F#,%F"#(!%'2
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
connect(textBrowser, SIGNAL(sourceChanged(const QUrl &)),
this, SLOT(updateWindowTitle())); void EntryDialog::help()
textBrowser->setSearchPaths(QStringList() << path << ":/images"); {
textBrowser->setSource(page); HelpBrowser::showPage("forms.html#editing");
} }

I"#'"(#(!" Qt::WA_GroupLeader#.((&%0/("#0"1./'"#7"#7.-(#(*#)*)#/) HelpBrowser#7%-3*7'#$&*+ Z"&"#7"#,**F#%-#.#3%$$"&"-(#!",)#$%,"4 forms.html4#.-3#'1&*,,#(!" QTextBrowser#(*#(!" editing#.-1!*&5


+*3.,#3%.,*;'#%-#.33%(%*-#(*#(!"#+.%-#7%-3*75#9*3.,#3%.,*;'#-*&+.,,>#)&"H"-(#(!"#/'"&#$&*+
%-("&.1(%-;#7%(!#.->#*(!"&#7%-3*7#%-#(!"#.)),%1.(%*-5#Z*7"H"&4#.$("&#&"@/"'(%-;#!",)4#(!"#/'"&#+/'(
*0H%*/',>#0"#.,,*7"3#(*#%-("&.1(#7%(!#0*(!#(!"#+*3.,#3%.,*;#.-3#7%(!#(!"#!",)#0&*7'"&5#L"((%-;#(!"
Qt::WA_GroupLeader#.((&%0/("#+.F"'#(!%'#%-("&.1(%*-#)*''%0,"5 Using Qt Assistant for Powerful Online Help
I"#)&*H%3"#(7*#'".&1!#).(!'4#(!"#$%&'(#.#).(!#%-#(!"#$%,"#'>'("+#(!.(#1*-(.%-'#(!"#.)),%1.(%*-<' !'-../.!)%!#%'#.#&"3%'(&%0/(.0,"#*-,%-"#!",)#.)),%1.(%*-#'/)),%"3#0># &*,,("1!5#B('#+.%-#H%&(/"'#.&"
3*1/+"-(.(%*-4#.-3#(!"#'"1*-3#(!"#,*1.(%*-#*$#(!"#%+.;"#&"'*/&1"'5# !"#Z 9:#1.-#%-1,/3" (!.(#%(#'/))*&('#%-3"C%-;#.-3#$/,,#("C(#'".&1!#.-3#(!.(#%(#1.-#!.-3,"#3*1/+"-(.(%*-#'"('#$*&#+/,(%),"
&"$"&"-1"'#(*#%+.;"'#%-#(!"#$%,"#'>'("+#%-#(!"#-*&+.,#7.>#.-3#.,'*#&"$"&"-1"'#(*#%+.;"#&"'*/&1"'#0> .)),%1.(%*-'5
/'%-;#.#).(!#(!.(#0";%-'#7%(! :/#=1*,*-#',.'!A5# !" page#).&.+"("&#%'#(!"#-.+"#*$#(!"#3*1/+"-(.(%*-
$%,"4#7%(!#.-#*)(%*-.,#Z 9:#.-1!*&5 *#+.F"#/'"#*$ !'-../.!)%!4#7"#+/'(#%-1*&)*&.("#(!"#-"1"''.&>#1*3"#%-#*/&#.)),%1.(%*-4 .-3#7"
+/'(#+.F" !'-../.!)%!#.7.&"#*$#*/&#3*1/+"-(.(%*-5

void HelpBrowser::updateWindowTitle() S*++/-%1.(%*-#0"(7""-#.#U(#.)),%1.(%*-#.-3 !'-../.!)%!#%'#!.-3,"3#0>#(!" QAssistantClient


{ 1,.''4#7!%1!#%'#,*1.("3#%-#.#'").&.("#,%0&.&>5# *#,%-F#(!%'#,%0&.&>#7%(!#.-#.)),%1.(%*-4#7"#+/'(#.33#(!"
setWindowTitle(tr("Help: %1").arg(textBrowser->documentTitle())); $*,,*7%-;#,%-"#(*#(!"#.)),%1.(%*-<' .pro#$%,"2
}

CONFIG += assistant
I!"-"H"&#(!"#'*/&1"#).;"#1!.-;"'4#(!" updateWindowTitle()#',*(#%'#1.,,"35# !" documentTitle()
$/-1(%*-#&"(/&-'#(!"#("C(#')"1%$%"3#%-#(!"#).;"<' <title>#(.;5
I"#7%,,#-*7#&"H%"7#(!"#1*3"#*$#.#-"7 HelpBrowser#1,.''#(!.(#/'"' !'-../.!)%!5
void HelpBrowser::showPage(const QString &page)
{
#ifndef HELPBROWSER_H
QString path = QApplication::applicationDirPath() + "/doc";
#define HELPBROWSER_H
HelpBrowser *browser = new HelpBrowser(path, page);
class QAssistantClient;
browser->resize(500, 400);
class QString;
browser->show();
class HelpBrowser
}
{
public:
static void showPage(const QString &page);
B-#(!" showPage()#'(.(%1#$/-1(%*-4#7"#1&".("#(!" HelpBrowser#7%-3*7#.-3#(!"-#'!*7#%(5# !"#7%-3*7 private:
7%,,#0"#3"'(&*>"3#./(*+.(%1.,,>#7!"-#(!"#/'"&#1,*'"'#%(4#'%-1"#7"#'"(#(!" Qt::WA_DeleteOnClose static QAssistantClient *assistant;
.((&%0/("#%-#(!" HelpBrowser#1*-'(&/1(*&5 };
#endif
Z"&"<'#(!"#-"7 helpbrowser.cpp#$%,"2
Part III: Advanced Qt
#include <QApplication>
#include <QAssistantClient>
#include "helpbrowser.h"
QAssistantClient *HelpBrowser::assistant = 0; S!.)("&#Ni5 #B-("&-.(%*-.,%Y.(%*-
void HelpBrowser::showPage(const QString &page)
{
QString path = QApplication::applicationDirPath() + "/doc/" + page; S!.)("&#N]5 #9/,(%(!&".3%-;
if (!assistant)
assistant = new QAssistantClient(""); S!.)("&#Nj5 #S&".(%-;#R,/;%-'
assistant->showPage(path);
} S!.)("&#VJ5 #R,.($*&+GL)"1%$%1#P".(/&"'

S!.)("&#VN5 #e+0"33"3#R&*;&.++%-;
!" QAssistantClient#1*-'(&/1(*&#.11")('#.#).(!#'(&%-;#.'#%('#$%&'(#.&;/+"-(4#7!%1!#%(#/'"'#(*#,*1.("
(!" !'-../.!)%!#"C"1/(.0,"5#[>#).''%-;#.-#"+)(>#).(!4#7"#'%;-%$>#(!.( QAssistantClient#'!*/,3
,**F#$*&#(!"#"C"1/(.0,"#%-#(!" PATH#"-H%&*-+"-(#H.&%.0,"5 QAssistantClient#!.'#. showPage()#$/-1(%*-
(!.(#.11")('#.#).;"#-.+"#7%(!#.-#*)(%*-.,#Z 9:#.-1!*&5

!"#-"C(#'(")#%'#(*#)&").&"#.#(.0,"#*$#1*-("-('#.-3#.-#%-3"C#$*&#(!"#3*1/+"-(.(%*-5# !%'#%'#3*-"#0>
1&".(%-;#. !'-../.!)%!#)&*$%,"#.-3#7&%(%-;#. .dcf#$%,"#(!.(#)&*H%3"'#%-$*&+.(%*-#.0*/(#(!"
3*1/+"-(.(%*-5#K,,#(!%'#%'#"C),.%-"3#%- !'-../.!)%!<'#*-,%-"#3*1/+"-(.(%*-4#'*#7"#7%,,#-*(#3/),%1.("
(!.(#%-$*&+.(%*-#!"&"5

K-#.,("&-.(%H"#(*#/'%-; QTextBrowser#*& !'-../.!)%!#%'#(*#/'"#),.($*&+G')"1%$%1#.))&*.1!"'#(*


)&*H%3%-;#*-,%-" !",)5#P*&#I%-3*7'#.)),%1.(%*-'4#%(#+%;!(#0"#3"'%&.0,"#(*#1&".("#I%-3*7'#Z 9:#Z",)
$%,"'#.-3#(*#)&*H%3"#.11"''#(*#(!"+#/'%-;#9%1&*'*$(#B-("&-"(#eC),*&"&5#g*/#1*/,3#/'"#U(<' QProcess
1,.''#*&#(!"#K1(%H"U(#$&.+"7*&F#$*&#(!%'5#P*&#8NN#.)),%1.(%*-'4#.#'/%(.0," .))&*.1!#+%;!(#0"#(*
)&*H%3"#Z 9:#$%,"'#.-3#(*#,./-1!#.#7"0#0&*7'"&#/'%-; QProcess5#E-#9.1#EL#84#K)),"#Z",)#)&*H%3"'
'%+%,.&#$/-1(%*-.,%(>#(* !'-../.!)%!5

I"#!.H"#-*7#&".1!"3#(!"#"-3#*$ R.&(#BB5# !"#1!.)("&'#(!.(#$*,,*7#%- R.&(#BBB#1*H"&#+*&"#.3H.-1"3


.-3#')"1%.,%Y"3#$".(/&"'#*$#U(5# !"#Shh#.-3#U(#1*3%-;#(!">#)&"'"-(#.&"#-*#+*&"#3%$$%1/,(#(!.-#(!.(
'""-#%- R.&(#BB4#0/(#'*+"#*$#(!"#1*-1")('#.-3#%3".'#+.>#0"#+*&"#1!.,,"-;%-;#%-#(!*'"#.&".'#(!.(#.&"
-"7#(*#>*/5
<,/$+;$!2*$#(?)%*$;+&*$2'#$',(!2*)$*,%(/+,-A$!2*$,?D*)+%$E'&?*$9()F#$;+,*=
Chapter 17. Internationalization
str[0] = QChar(0xD1);
• /!:B$,6(;$#0(5,$C!-4
• D*B$,6(>%%"$C*#$!,&( :*,&"*#$!,E>;*:4
• FG,*<$C(H*,6+*64();$#C0$,6
• :*,&"*#$,6(>%%"$C*#$!,& G*$%',$#B*%+;:$',:$.,+%(/*$%2')'%!*)$6:$+!#$,?D*)+%$E'&?*0$H()$*I'DB&*A$2*)*"#$2(9$!($#B*%+;:$!2*
J)**F$%'B+!'&$&*!!*)$#+-D'$K" "L$',/$!2*$*?)($%?))*,%:$#:D6(&$K" M$"L=
B-#.33%(%*-#(*#(!"#:.(%-#.,)!.0"(#/'"3#$*&#e-;,%'!#.-3#$*&#+.->#e/&*)".-#,.-;/.;"'4#U(#X#.,'*
)&*H%3"'#"C("-'%H"#'/))*&(#$*&#(!"#&"'(#*$#(!"#7*&,3<'#7&%(%-;#'>'("+'2
str[0] = QChar(0x3A3);
str[0] = QChar(0x20AC);
• U(#/'"'#\-%1*3"#(!&*/;!*/(#(!"#KRB#.-3#%-("&-.,,>5#O*#+.(("&#7!.(#,.-;/.;"#7"#/'"#$*&#(!"
/'"&#%-("&$.1"4#(!"#.)),%1.(%*-#1.-#'/))*&(#.,,#/'"&'#.,%F"5
• U(<'#("C(#"-;%-"#1.-#!.-3,"#.,,#(!"#+.D*&#-*-G:.(%-#7&%(%-;#'>'("+'4#%-1,/3%-;#K&.0%14
S!%-"'"4#S>&%,,%14#Z"0&"74#M.).-"'"4#d*&".-4# !.%4#.-3#(!"#B-3%1#,.-;/.;"'5 N2*$,?D*)+%$E'&?*#$(;$'&&$!2*$%2')'%!*)#$#?BB()!*/$6:$.,+%(/*$')*$&+#!*/$'!
• U(<'#,.>*/(#"-;%-"#'/))*&('#&%;!(G(*G,"$(#,.>*/('#$*&#,.-;/.;"'#'/1!#.'#K&.0%1#.-3#Z"0&"75 2!!B=OO9990?,+%(/*0()-O#!',/')/O0$>;$:(?$)')*&:$,**/$,(,5@'!+,53$.,+%(/*$%2')'%!*)#A$&((F+,-$?B
• S"&(.%-#,.-;/.;"'#&"@/%&"#')"1%.,#%-)/(#+"(!*3'#$*&#"-("&%-;#("C(5#e3%(*&#7%3;"('#'/1!#.' %2')'%!*)#$(,&+,*$+#$#?;;+%+*,!P$6?!$ !$B)(E+/*#$D()*$%(,E*,+*,!$9':#$(;$*,!*)+,-$.,+%(/*$#!)+,-#$+,
QLineEdit#.-3 QTextEdit#7*&F#7",,#7%(!#.->#%-)/(#+"(!*3#%-'(.,,"3#*-#(!"#/'"&<'#'>'("+5 '$ !$B)(-)'DA$'#$9*$9+&&$#**$&'!*)$+,$!2+#$#*%!+(,0

E$("-4#%(#%'-<(#"-*/;!#(*#.,,*7#/'"&'#(*#"-("&#("C(#%-#(!"%&#-.(%H"#,.-;/.;"6#(!"#"-(%&"#/'"&#%-("&$.1"<' !$Q"#$!*I!$*,-+,*$#?BB()!#$!2*$;(&&(9+,-$9)+!+,-$#:#!*D#$(,$'&&$B&'!;()D#=$<)'6+%A$R2+,*#*A$R:)+&&+%A
+/'(#0"#(&.-',.("3#.'#7",,5#U(#+.F"'#(!%'#".'>2#L%+),>#7&.)#.,,#/'"&GH%'%0,"#'(&%-;' 7%(!#(!" tr() J)**FA$8*6)*9A$S'B',*#*A$T()*',A$@'(A$@'!+,A$N2'+A$',/$U+*!,'D*#*0$>!$'&#($#?BB()!#$'&&$!2*$.,+%(/*
$/-1(%*-#=.'#7"#!.H"#3*-"#%-#".&,%"&#1!.)("&'A#.-3#/'"#U(<'#'/))*&(%-;#(**,'#(*#)&").&"#(&.-',.(%*- Q03$#%)+B!#$!2'!$/(,"!$)*V?+)*$',:$#B*%+'&$B)(%*##+,-0$>,$'//+!+(,A$!2*$;(&&(9+,-$9)+!+,-$#:#!*D#$')*
$%,"'#%-#(!"#&"@/%&"3#,.-;/.;"'5#U(#)&*H%3"'#.#^\B#(**,#1.,,"3 !'0/%1(/.!#$*&#/'"#0>#(&.-',.(*&'5 ! #?BB()!*/$(,$W33$9+!2$H(,!%(,;+-$',/$(,$)*%*,!$E*)#+(,#$(;$G+,/(9#=$X*,-'&+A$Y*E','-')+A$J?C')'!+A
0/%1(/.!#%'#1*+),"+"-("3#0>#(7*#1*++.-3G,%-"#)&*;&.+'4 lupdate#.-3 lrelease4#7!%1!#.&" J?)D?F2+A$T',,'/'A$T2D*)A$Z'&':'&'DA$[:)+'%A$N'D+&A$N*&?-?A$N2'','$KY2+E*2+LA$',/$N+6*!',0
(>)%1.,,>#&/-#0>#(!"#.)),%1.(%*-<'#3"H",*)"&'5 H+,'&&:A$\)+:'$+#$#?BB()!*/$(,$W33A$',/$Z(,-(&+',$',/$[+,2'&'$')*$#?BB()!*/$(,$G+,/(9#$W]0
<##?D+,-$!2'!$!2*$B)(B*)$;(,!#$')*$+,#!'&&*/$(,$!2*$#:#!*DA$ !$%',$)*,/*)$!*I!$?#+,-$',:$(;$!2*#*
9)+!+,-$#:#!*D#0$<,/$'##?D+,-$!2'!$!2*$B)(B*)$+,B?!$D*!2(/#$')*$+,#!'&&*/A$?#*)#$9+&&$6*$'6&*$!(
P*&#+*'(#.)),%1.(%*-'4#.#(&.-',.(%*-#$%,"#%'#,*.3"3#.(#'(.&(/)4#0.'"3#*-#(!"#/'"&<'#,*1.,"#'"((%-;'5#[/(
*,!*)$!*I!$!2'!$?#*#$!2*#*$9)+!+,-$#:#!*D#$+,$!2*+)$ !$'BB&+%'!+(,#0
%-#.#$"7#1.'"'4#%(#%'#.,'*#-"1"''.&>#$*&#/'"&'#(*#0"#.0," (*#'7%(1!#,.-;/.;"#.(#&/-G(%+"5# !%'#%'
)"&$"1(,>#)*''%0,"#7%(!#U(4#.,(!*/;!#%(#3*"'#&"@/%&"#.#0%(#*$#"C(&.#7*&F5#K-3#(!.-F'#(*#U(<'#,.>*/(
'>'("+4#(!"#H.&%*/'#/'"&#%-("&$.1"#1*+)*-"-('#7%,,#./(*+.(%1.,,>#.3D/'(#(*#+.F"#&**+#$*&#(!" ])(-)'DD+,-$9+!2 QChar$+#$#&+-2!&:$/+;;*)*,!$;)(D$B)(-)'DD+,-$9+!2 char0$N($(6!'+,$!2*$,?D*)+%
(&.-',.("3#("C('#7!"-#(!">#.&"#,*-;"&#(!.-#(!"#*&%;%-.,#("C('5 E'&?*$(;$' QCharA$%'&& unicode()$(,$+!0$N($(6!'+,$!2*$<[R>>$()$@'!+,53$E'&?*$(;$' QChar$K'#$' charLA$%'&&
toLatin1()0$H()$,(,5@'!+,53$%2')'%!*)#A toLatin1()$)*!?),#$"^_"0

Working with Unicode >;$9*$F,(9$!2'!$'&&$!2*$#!)+,-#$+,$'$B)(-)'D$')*$<[R>>A$9*$%',$?#*$#!',/')/ <cctype>$;?,%!+(,#$&+F*


isalpha()A isdigit()A$',/ isspace()$(,$!2*$)*!?),$E'&?*$(; toLatin1()0$8(9*E*)A$+!$+#$-*,*)'&&:
\-%1*3"#%'#.#1!.&.1("&#"-1*3%-;#'(.-3.&3#(!.(#'/))*&('#+*'(#*$#(!"#7*&,3<'#7&%(%-;#'>'("+'5# !" 6*!!*)$!($?#* QChar"#$D*D6*)$;?,%!+(,#$;()$B*);()D+,-$!2*#*$(B*)'!+(,#A$#+,%*$!2*:$9+&&$9()F$;()$',:
*&%;%-.,#%3".#0"!%-3#\-%1*3"#%'#(!.(#0>#/'%-;#Nf#0%('#$*&#'(*&%-;#1!.&.1("&'#%-'(".3#*$#]#0%('4#%(#7*/,3 .,+%(/*$%2')'%!*)0$N2*$;?,%!+(,# QChar$B)(E+/*#$+,%&?/* isPrint()A isPunct()A isSpace()A isMark()A
0"#)*''%0,"#(*#"-1*3"#.&*/-3#fW4JJJ#1!.&.1("&'#%-'(".3#*$#*-,>#VWf5 klm#\-%1*3"#1*-(.%-'#KLSBB#.-3 isLetter()A isNumber()A isLetterOrNumber()A isDigit()A isSymbol()A isLower()A$',/ isUpper()0$H()
BLE#]]WjGN#=:.(%-GNA#.'#'/0'"('#.(#(!"#'.+"#1*3"#)*'%(%*-'5#P*&#"C.+),"4#(!"#1!.&.1("&#<K<#!.' *I'DB&*A$2*)*"#$(,*$9':$!($!*#!$!2'!$'$%2')'%!*)$+#$'$/+-+!$()$',$?BB*)%'#*$&*!!*)=
H.,/" 0x41#%-#KLSBB4#:.(%-GN4#.-3#\-%1*3"4#.-3#(!"#1!.&.1("&#<n<#!.'#H.,/" 0xD1#%-#0*(!#:.(%-GN#.-3
\-%1*3"5
if (ch.isDigit() || ch.isUpper())
[*]
Recent versions of the Unicode standard assign character values above 65,535. These characters can be represented using ...
sequences of two 16-bit values called "surrogate pairs".

!"# QString$%&'##$#!()*#$#!)+,-#$'#$.,+%(/*0$1'%2$%2')'%!*)$+,$' QString$+#$'$3456+! QChar$)'!2*)$!2',


',$756+! char0$8*)*$')*$!9($9':#$(;$#*!!+,-$!2*$;+)#!$%2')'%!*)$(;$'$#!)+,-$!($"<"= N2*$%(/*$#,+BB*!$9()F#$;()$',:$'&B2'6*!$!2'!$/+#!+,-?+#2*#$6*!9**,$?BB*)%'#*$',/$&(9*)%'#*A
+,%&?/+,-$@'!+,A$J)**FA$',/$R:)+&&+%0

str[0] = 'A'; \,%*$9*$2'E*$'$.,+%(/*$#!)+,-A$9*$%',$?#*$+!$',:92*)*$+,$ !"#$<]>$92*)*$' QString$+#$*IB*%!*/0$>!


str[0] = QChar(0x41); +#$!2*,$ !"#$)*#B(,#+6+&+!:$!($/+#B&':$+!$B)(B*)&:$',/$!($%(,E*)!$+!$!($!2*$)*&*E',!$*,%(/+,-#$92*,
!'&F+,-$!($!2*$(B*)'!+,-$#:#!*D0

>;$!2*$#(?)%*$;+&*$+#$*,%(/*/$+,$@'!+,53A$#B*%+;:+,-$@'!+,53$%2')'%!*)#$+#$C?#!$'#$*'#:= [B*%+'&$%')*$+#$,**/*/$92*,$9*$)*'/$',/$9)+!*$!*I!$;+&*#0$N*I!$;+&*#$%',$?#*$'$E')+*!:$(;$*,%(/+,-#A
',/$+!$+#$(;!*,$+DB(##+6&*$!($-?*##$'$!*I!$;+&*"#$*,%(/+,-$;)(D$+!#$%(,!*,!#0$X:$/*;'?&!A QTextStream
?#*#$!2*$#:#!*D"#$&(%'&$756+!$*,%(/+,-$K'E'+&'6&*$'# QTextCodec::codecForLocale()L$;()$6(!2$)*'/+,-
str[0] = 'Ñ'; ',/$9)+!+,-0$H()$<D*)+%',$',/$G*#!$1?)(B*',$&(%'&*#A$!2+#$?#?'&&:$D*',#$@'!+,530

>;$9*$/*#+-,$(?)$(9,$;+&*$;()D'!$',/$9',!$!($6*$'6&*$!($)*'/$',/$9)+!*$')6+!)'):$.,+%(/*$%2')'%!*)#A
9*$%',$#'E* !2*$/'!'$'#$.,+%(/*$6:$%'&&+,- */+!()$!2'!$?#*#$',$*,%(/+,-$#?%2$'#$1.R5S]$()$[2+;!5S>[0$[?%2$',$*/+!()$'&&(9#$!2*D$!($!:B*$+,
S'B',*#*$%2')'%!*)#$#*'D&*##&:A$#($!2'!$!2*:$%',$9)+!*$%(/*$&+F*$!2+#=

stream.setCodec("UTF-16");
stream.setGenerateByteOrderMark(true); QPushButton *button = new QPushButton(tr(" "));

6*;()*$9*$#!')!$9)+!+,-$!($!2* QTextStream0$N2*$/'!'$9+&&$!2*,$6*$#'E*/$+,$.NH534A$'$;()D'!$!2'! X:$/*;'?&!A$ !$+,!*)B)*!#$')-?D*,!#$!( TR()$'#$@'!+,530$N($%2',-*$!2+#A$%'&&$!2*


)*V?+)*#$!9($6:!*#$B*)$%2')'%!*)A$',/$9+&&$6*$B)*;+I*/$9+!2 '$#B*%+'&$3456+!$E'&?*$K!2*$.,+%(/*$6:!* QTextCodec::setCodecForTr()$#!'!+%$;?,%!+(,0$H()$*I'DB&*=
()/*)$D')FA 0xFFFEL$+/*,!+;:+,-$!2'!$!2*$;+&*$+#$+,$.,+%(/*$',/$92*!2*)$!2*$6:!*#$')*$+,$&+!!&*5*,/+',
()$6+-5*,/+',$()/*)0$N2*$.NH534$;()D'!$+#$+/*,!+%'&$!($!2*$D*D():$)*B)*#*,!'!+(,$(;$' QStringA$#(
)*'/+,-$',/$9)+!+,-$.,+%(/*$#!)+,-#$+,$.NH534$%',$6*$E*):$;'#!0$8(9*E*)A$!2*)*$+#$',$+,2*)*,! QTextCodec::setCodecForTr(QTextCodec::codecForName("EUC-JP"));
(E*)2*'/$92*,$#'E+,-$B?)*$<[R>>$/'!'$+,$.NH534$;()D'!A$#+,%*$+!$#!()*#$!9($6:!*#$;()$*E*):
%2')'%!*)$+,#!*'/$(;$C?#!$(,*0

N2+#$D?#!$6*$/(,*$6*;()*$!2*$;+)#!$%'&&$!( tr()0$N:B+%'&&:A$9*$9(?&/$/($!2+#$+, main()A$+DD*/+'!*&:


\!2*)$*,%(/+,-#$%',$6*$#B*%+;+*/$6:$%'&&+,- setCodec()$9+!2$',$'BB)(B)+'!* QTextCodec0$< QTextCodec
';!*)$!2* QApplication$(6C*%!$+#$%)*'!*/0
+#$',$(6C*%!$!2'!$%(,E*)!#$6*!9**,$.,+%(/*$',/$'$-+E*,$*,%(/+,-0 QTextCodec#$')*$?#*/$+,$'$E')+*!:
(;$%(,!*I!#$6:$ !0$>,!*),'&&:A$!2*:$')*$?#*/$!($#?BB()!$;(,!#A$+,B?!$D*!2(/#A$!2*$%&+B6(')/A$/)'-$',/
/)(BA$',/$;+&*$,'D*#0$X?!$!2*:$')*$'&#($'E'+&'6&*$!($?#$92*,$9*$9)+!*$ !$'BB&+%'!+(,#0 \!2*)$#!)+,-#$#B*%+;+*/$+,$!2*$B)(-)'D$9+&&$#!+&&$6*$+,!*)B)*!*/$'#$@'!+,53$#!)+,-#0$>;$!2*$B)(-)'DD*)#
9',!$!($*,!*)$S'B',*#*$%2')'%!*)#$+,$!2(#*$'#$9*&&A$!2*:$%',$*IB&+%+!&:$%(,E*)!$!2*D$!($.,+%(/*
?#+,-$' QTextCodec=
G2*,$)*'/+,-$'$!*I!$;+&*A QTextStream$/*!*%!#$.,+%(/*$'?!(D'!+%'&&:$+;$!2*$;+&*$#!')!#$9+!2$!2*$6:!*
()/*)$D')F0$N2+#$6*2'E+()$%',$6*$!?),*/$(;;$6:$%'&&+,- setAutoDetectUnicode(false)0$>;$!2*$/'!'$%',"!
6*$'##?D*/$!($#!')!$9+!2$!2*$6:!*$()/*)$D')FA$+!$+#$6*#!$!($%'&& setCodec()$9+!2$`.NH534`$6*;()*
)*'/+,-0 QString text = japaneseCodec->toUnicode(" ");

<,(!2*)$*,%(/+,-$!2'!$#?BB()!#$!2*$92(&*$(;$.,+%(/*$+#$.NH570$>!#$D'+,$'/E',!'-*$(E*)$.NH534$+#
!2'!$+!$+#$'$#?B*)#*!$(;$<[R>>0$<,:$%2')'%!*)$+,$!2*$)',-* 0x00$!( 0x7F$+#$)*B)*#*,!*/$'#$'$#+,-&* <&!*),'!+E*&:A$!2*:$%',$!*&&$ !$!($?#*$'$#B*%+;+%$%(/*%$92*,$%(,E*)!+,-$6*!9**, const char *$',/
6:!*0$\!2*)$%2')'%!*)#A$+,%&?/+,-$@'!+,53$%2')'%!*)#$'6(E* 0x7FA$')*$)*B)*#*,!*/$6:$D?&!+56:!* QString$6:$%'&&+,- QTextCodec::setCodecForCStrings()=
#*V?*,%*#0$H()$!*I!$!2'!$+#$D(#!&:$<[R>>A$.NH57$!'F*#$?B$'6(?!$2'&;$!2*$#B'%*$%(,#?D*/$6:$.NH5340
N($?#*$.NH57$9+!2 QTextStreamA$%'&& setCodec()$9+!2$`.NH57`$'#$!2*$%(/*%$,'D*$6*;()*$)*'/+,-$',/
9)+!+,-0 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("EUC-JP"));

>;$9*$'&9':#$9',!$!($)*'/$',/$9)+!*$@'!+,53$)*-')/&*##$(;$!2*$?#*)"#$&(%'&*A$9*$%',$#*!$!2*$`>[\
77ab53`$%(/*%$(,$!2* QTextStream0$H()$*I'DB&*= N2*$!*%2,+V?*#$/*#%)+6*/$'6(E*$%',$6*$'BB&+*/$!($',:$,(,5@'!+,53$&',-?'-*A$+,%&?/+,-$R2+,*#*A
J)**FA$T()*',A$',/$c?##+',0

QTextStream in(&file); 8*)*"#$'$&+#!$(;$!2*$*,%(/+,-#$#?BB()!*/$6:$ !$Q=


in.setCodec("ISO 8859-1");
• <BB&*$c(D',
• X+-a
[(D*$;+&*$;()D'!#$#B*%+;:$!2*+)$*,%(/+,-$+,$!2*+)$2*'/*)0$N2*$2*'/*)$+#$!:B+%'&&:$B&'+,$<[R>>$!( • X+-a58T[R[
*,#?)*$!2'!$+!$+#$)*'/$%())*%!&:$,($D'!!*)$92'!$*,%(/+,-$+#$?#*/$K'##?D+,-$!2'!$+!$+#$'$#?B*)#*!$(; • 1.R5S]
<[R>>L0$N2*$WZ@$;+&*$;()D'!$+#$',$+,!*)*#!+,-$*I'DB&*$(;$!2+#0$WZ@$;+&*#$')*$,()D'&&:$*,%(/*/$'# • 1.R5Tc
.NH57$()$.NH5340$N2*$B)(B*)$9':$!($)*'/$!2*D$+,$+#$!($%'&& setCodec()$9+!2$`.NH57`0$>;$!2*$;()D'!$+# • JX37_d_5_
.NH534A QTextStream$9+&&$'?!(D'!+%'&&:$/*!*%!$!2+#$',/$'/C?#!$+!#*&;0$N2* <?xml?>$2*'/*)$(;$',$WZ@ • >XZ$7a_
;+&*$#(D*!+D*#$%(,!'+,#$', encoding$')-?D*,!A$;()$*I'DB&*= • >XZ$744
• >XZ$7eQ
• >[\$f_ff5S]
<?xml version="1.0" encoding="EUC-KR"?> • >[\$77ab53
• >[\$77ab5f
• >[\$77ab5d
• >[\$77ab5Q
[+,%* QTextStream$/(*#,"!$'&&(9$?#$!($%2',-*$!2*$*,%(/+,-$(,%*$+!$2'#$#!')!*/$)*'/+,-A$!2*$)+-2!$9':
• >[\$77ab5a
!($)*#B*%!$',$*IB&+%+!$*,%(/+,-$+#$!($#!')!$)*'/+,-$!2*$;+&*$';)*#2A$?#+,-$!2*$%())*%!$%(/*%$K(6!'+,*/ • >[\$77ab54
;)(D QTextCodec::codecForName()L0$>,$!2*$%'#*$(;$WZ@A$9*$%',$'E(+/$2'E+,-$!($2',/&*$!2*$*,%(/+,- • >[\$77ab5e
(?)#*&E*#$6:$?#+,-$ !"#$WZ@$%&'##*#A$/*#%)+6*/$+, R2'B!*)$3a0 • >[\$77ab57
• >[\$77ab5b
<,(!2*)$?#*$(; QTextCodec#$+#$!($#B*%+;:$!2*$*,%(/+,-$(;$#!)+,-#$!2'!$(%%?)$+,$!2*$#(?)%*$%(/*0$@*!"# • >[\$77ab53_
%(,#+/*)$;()$*I'DB&*$'$!*'D$(;$S'B',*#*$B)(-)'DD*)#$92($')*$9)+!+,-$',$'BB&+%'!+(,$!')-*!*/ • >[\$77ab53d
B)+D')+&:$'!$S'B',"#$2(D*$D')F*!0$N2*#*$B)(-)'DD*)#$')*$&+F*&:$!($9)+!*$!2*+)$#(?)%*$%(/*$+,$'$!*I! • >[\$77ab53Q
• >[\$77ab53a < tr()$%'&&$2'#$!2*$;(&&(9+,-$-*,*)'&$#:,!'I=
• >[\$77ab534
• >#%++5X,-
• >#%++5Y*E Context::tr(sourceText, comment)
• >#%++5JC)
• >#%++5T,/
• >#%++5Z&D N2* Context$B')!$+#$!2*$,'D*$(;$' QObject$#?6%&'##$/*;+,*/$9+!2$!2* Q_OBJECT$D'%)(0$G*$/(,"!$,**/
• >#%++5\)+
!($#B*%+;:$+!$+;$9*$%'&& tr()$;)(D$'$D*D6*)$;?,%!+(,$(;$!2*$%&'##$+,$V?*#!+(,0$N2* sourceText$B')!$+#
• >#%++5],C
!2*$#!)+,-$&+!*)'&$!2'!$,**/#$!($6*$!)',#&'!*/0$N2* comment$B')!$+#$(B!+(,'&P$+!$%',$6*$?#*/$!($B)(E+/*
• >#%++5N&-
'//+!+(,'&$+,;()D'!+(,$!($!2*$!)',#&'!()0
• >#%++5ND&
• S>[$W$_f_3
• S>[$W$_f_7 8*)*$')*$'$;*9$*I'DB&*#=
• T\>75c
• T\>75.
• Z?&*@'(53 RockyWidget::RockyWidget(QWidget *parent)
: QWidget(parent)
• c\Z<g7
{
• [2+;!5S>[
QString str1 = tr("Letter");
• N>[54f_ QString str2 = RockyWidget::tr("Letter");
• N[R>> QString str3 = SnazzyDialog::tr("Letter");
• .NH57 QString str4 = SnazzyDialog::tr("Letter", "US paper size");
• .NH534 }
• .NH534X1
• .NH534@1
• G+,/(9#53fa_
N2*$;+)#!$!9($%'&&#$!( tr()$2'E*$`c(%F:G+/-*!`$'#$%(,!*I!A$',/$!2*$&'#!$!9($%'&&#$2'E*
• G+,/(9#53fa3
`[,'hh:Y+'&(-`0$<&&$;(?)$2'E*$`@*!!*)`$'#$#(?)%*$!*I!0$N2*$&'#!$%'&&$'&#($2'#$'$%(DD*,!$!($2*&B$!2*
• G+,/(9#53faf
!)',#&'!()$?,/*)#!',/$!2*$D*',+,-$(;$!2*$#(?)%*$!*I!0
• G+,/(9#53fad
• G+,/(9#53faQ
• G+,/(9#53faa [!)+,-#$+,$/+;;*)*,!$%(,!*I!#$K%&'##*#L$')*$!)',#&'!*/$+,/*B*,/*,!&:$(;$*'%2$(!2*)0$N)',#&'!()#
• G+,/(9#53fa4 !:B+%'&&:$9()F$(,$(,*$%(,!*I!$'!$'$!+D*A$(;!*,$9+!2$!2*$'BB&+%'!+(,$)?,,+,-$',/$#2(9+,-$!2*$9+/-*!
• G+,/(9#53fae ()$/+'&(-$6*+,-$!)',#&'!*/0
• G+,/(9#53fa7
• G>g[<Z>f G2*,$9*$%'&& TR()$;)(D$'$-&(6'&$;?,%!+(,A$9*$D?#!$#B*%+;:$!2*$%(,!*I!$*IB&+%+!&:0$<,: QObject
#?6%&'##$+,$!2*$'BB&+%'!+(,$%',$6*$?#*/$'#$!2*$%(,!*I!0$>;$,(,*$+#$'BB)(B)+'!*A$9*$%',$'&9':#$?#*
H()$'&&$(;$!2*#*A QTextCodec::codecForName()$9+&&$'&9':#$)*!?),$'$E'&+/$B(+,!*)0 \!2*)$*,%(/+,-#$%', QObject$+!#*&;0$H()$*I'DB&*=
6*$#?BB()!*/$6:$#?6%&'##+,- QTextCodec0

int main(int argc, char *argv[])


Making Applications Translation-Aware {
QApplication app(argc, argv);
...
>;$9*$9',!$!($D'F*$(?)$'BB&+%'!+(,#$'E'+&'6&*$+,$D?&!+B&*$&',-?'-*#A$9*$D?#!$/($!9($!2+,-#= QPushButton button(QObject::tr("Hello Qt!"));
button.show();
• Z'F*$#?)*$!2'!$*E*):$?#*)5E+#+6&*$#!)+,-$-(*#$!2)(?-2 tr()0 return app.exec();
• @('/$'$!)',#&'!+(,$K.qmL$;+&*$'!$#!')!?B0 }

g*+!2*)$(;$!2*#*$+#$,*%*##'):$;()$'BB&+%'!+(,#$!2'!$9+&&$,*E*)$6*$!)',#&'!*/0$8(9*E*)A$?#+,- TR()
)*V?+)*#$'&D(#!$,($*;;()!$',/$&*'E*#$!2*$/(()$(B*,$;()$/(+,-$!)',#&'!+(,#$'!$'$&'!*)$/'!*0 >,$*E*):$*I'DB&*$#($;')A$!2*$%(,!*I!$2'#$6**,$'$%&'##$,'D*0$N2+#$+#$%(,E*,+*,!A$6*%'?#*$9*$%',
'&D(#!$'&9':#$(D+!$+!A$6?!$!2+#$/(*#,"!$2'E*$!($6*$!2*$%'#*0$N2*$D(#!$-*,*)'&$9':$(;$!)',#&'!+,-$'
N2* tr()$;?,%!+(,$+#$'$#!'!+%$;?,%!+(,$/*;+,*/$+, QObject$',/$(E*))+//*,$+,$*E*):$#?6%&'##$/*;+,*/ #!)+,-$+,$ !$+#$!($?#*$!2* QApplication::translate()$;?,%!+(,A$92+%2$'%%*B!#$?B$!($!2)**$')-?D*,!#=
9+!2$!2* Q_OBJECT$D'%)(0$G2*,$9)+!+,-$%(/*$+,#+/*$' QObject$#?6%&'##A$9*$%',$%'&& tr()$9+!2(?! !2*$%(,!*I!A$!2*$#(?)%*$!*I!A$',/$!2*$(B!+(,'&$%(DD*,!0$H()$*I'DB&*A$2*)*"#$',(!2*)$9':$!(
;()D'&+!:0$<$%'&&$!( TR()$)*!?),#$'$!)',#&'!+(,$+; (,*$+#$'E'+&'6&*P$(!2*)9+#*A$!2*$()+-+,'&$!*I!$+# !)',#&'!*$`8*&&($ !i`=
)*!?),*/0

N($B)*B')*$!)',#&'!+(,$;+&*#A$9*$D?#!$)?,$ !"# lupdate$!((&0$N2+#$!((&$*I!)'%!#$'&&$!2*$#!)+,-$&+!*)'&# QApplication::translate("Global Stuff", "Hello Qt!")


!2'!$'BB*')$+, TR()$%'&&#$',/$B)(/?%*#$!)',#&'!+(,$;+&*#$!2'!$%(,!'+,$'&&$(;$!2*#*$#!)+,-#$)*'/:$!($6*
!)',#&'!*/0$N2*$;+&*#$%',$!2*,$6*$#*,!$!($'$!)',#&'!()$!($2'E*$!2*$!)',#&'!+(,#$'//*/0$N2+#$B)(%*##$+#
*IB&'+,*/$+,$!2*$`N)',#&'!+,-$<BB&+%'!+(,#`$#*%!+(,$&'!*)$+,$!2+#$%2'B!*)0 N2+#$!+D*A$9*$B?!$!2*$!*I!$+, !2*$`J&(6'&$[!?;;`$%(,!*I!0

N2* tr()$',/ translate()$;?,%!+(,#$#*)E*$'$/?'&$B?)B(#*=$N2*:$')*$D')F*)#$!2'! lupdate$?#*#$!(


;+,/$?#*)5E+#+6&*$#!)+,-#A$',/$'!$!2*$#'D*$!+D*$!2*:$')*$Rjj$;?,%!+(,#$!2'!$!)',#&'!*$!*I!0$N2+#$2'# static const char * const flowers[] = {
',$+DB'%!$(,$2(9$9*$9)+!*$%(/*0 H()$*I'DB&*A$!2*$;(&&(9+,-$9+&&$,(!$9()F= QT_TRANSLATE_NOOP("OrderForm", "Medium Stem Pink Roses"),
QT_TRANSLATE_NOOP("OrderForm", "One Dozen Boxed Roses"),
QT_TRANSLATE_NOOP("OrderForm", "Calypso Orchid"),
// WRONG QT_TRANSLATE_NOOP("OrderForm", "Dried Red Rose Bouquet"),
const char *appName = "OpenDrawer 2D"; QT_TRANSLATE_NOOP("OrderForm", "Mixed Peonies Bouquet"),
QString translated = tr(appName); 0
};

N2*$B)(6&*D$2*)*$+#$!2'! lupdate$9+&&$,(!$6*$'6&*$!($*I!)'%!$!2*$`\B*,Y)'9*)$fY`$#!)+,-$&+!*)'&A$'#$+!
N2*$%(,!*I!$')-?D*,!$D?#!$6*$!2*$#'D*$'#$!2*$%(,!*I!$-+E*,$!( TR()$() translate()$&'!*)$(,0
/(*#,"!$'BB*')$+,#+/*$' tr()$%'&&0$N2+#$D*',#$!2'!$!2*$!)',#&'!()$9+&&$,(!$2'E*$!2*$(BB()!?,+!:$!(
!)',#&'!*$!2*$#!)+,-0$N2+#$+##?*$(;!*,$')+#*#$+,$%(,C?,%!+(,$9+!2$/:,'D+%$#!)+,-#=
G2*,$9*$#!')!$?#+,- TR()$+,$',$'BB&+%'!+(,A$+!"#$*'#:$!($;()-*!$!($#?))(?,/$#(D*$?#*)5E+#+6&*$#!)+,-#
9+!2$' tr()$%'&&A$*#B*%+'&&:$92*,$9*$')*$C?#!$6*-+,,+,-$!($?#*$+!0$N2*#*$D+##+,- TR()$%'&&#$')*
// WRONG *E*,!?'&&:$/+#%(E*)*/$6:$!2*$!)',#&'!()$()A$9()#*A$6:$?#*)#$(;$!2*$!)',#&'!*/$'BB&+%'!+(,A$92*,$#(D*
statusBar()->showMessage(tr("Host " + hostName + " found")); #!)+,-#$'BB*')$+,$!2*$()+-+,'&$&',-?'-*0$N($'E(+/$!2+#$B)(6&*DA$9*$%',$!*&&$ !$!($;()6+/$+DB&+%+!
%(,E*)#+(,#$;)(D const char *$!( QString0$G*$/($!2+#$6:$/*;+,+,-$!2* QT_NO_CAST_FROM_ASCII
B)*B)(%*##()$#:D6(&$6*;()*$+,%&?/+,-$',:$ !$2*'/*)0$N2*$*'#+*#!$9':$!($*,#?)*$!2+#$#:D6(&$+#$#*!$+#
!($'//$!2*$;(&&(9+,-$&+,*$!($!2*$'BB&+%'!+(,"# .pro$;+&*=
8*)*A$!2*$#!)+,-$9*$B'##$!( tr()$E')+*#$/*B*,/+,-$(,$!2*$E'&?*$(; hostNameA$#($9*$%',"!$)*'#(,'6&:
*IB*%! TR()$!($!)',#&'!*$+!$%())*%!&:0
DEFINES += QT_NO_CAST_FROM_ASCII
N2*$#(&?!+(,$+#$!($?#* QString::arg()=

statusBar()->showMessage(tr("Host %1 found").arg(hostName)); N2+#$9+&&$;()%*$*E*):$#!)+,-$&+!*)'&$!($)*V?+)*$9)'BB+,-$6: TR()$()$6: QLatin1String()A$/*B*,/+,-$(,


92*!2*)$+!$#2(?&/$6*$!)',#&'!*/$()$,(!0$[!)+,-#$!2'!$')*$,(!$#?+!'6&:$9)'BB*/$9+&&$B)(/?%*$'$%(DB+&*5
!+D*$*))()A$!2*)*6:$%(DB*&&+,-$?#$!($'//$!2*$D+##+,- TR()$() QLatin1String()$%'&&0
g(!+%*$2(9$+!$9()F#=$N2*$#!)+,-$&+!*)'&$`8(#!$k3$;(?,/`$+#$B'##*/$!( tr()0$<##?D+,-$!2'!$'$H)*,%2
\,%*$9*$2'E*$9)'BB*/$*E*):$?#*)5E+#+6&*$#!)+,-$6:$' tr()$%'&&A$!2*$(,&:$!2+,-$&*;!$!($/($!($*,'6&*
!)',#&'!+(,$;+&*$+#$&('/*/A tr()$9(?&/$)*!?),$#(D*!2+,-$&+F*$`8l!*$k3$!)(?Em`0$N2*,$!2*$`k3`
!)',#&'!+(,$+#$!($&('/$'$!)',#&'!+(,$;+&*0$N:B+%'&&:A$9*$9(?&/$/($!2+#$+,$!2*$'BB&+%'!+(,"# main()
B')'D*!*)$+#$)*B&'%*/$9+!2$!2*$%(,!*,!#$(;$!2* hostName$E')+'6&*0
;?,%!+(,0$H()$*I'DB&*A$2*)*"#$2(9$9*$9(?&/$!):$!($&('/$'$!)',#&'!+(,$;+&*$/*B*,/+,-$(,$!2*$?#*)"#
&(%'&*=
<&!2(?-2$+!$+#$-*,*)'&&:$+,'/E+#'6&*$!($%'&& tr()$(,$'$E')+'6&*A$+!$%',$6*$D'/*$!($9()F0$G*$D?#!$?#*
!2* QT_tr_NOOP()$D'%)($!($D')F$!2*$#!)+,-$&+!*)'&#$;()$!)',#&'!+(,$6*;()*$9*$'##+-,$!2*D$!($'
E')+'6&*0$N2+#$+#$D(#!&:$?#*;?&$;()$#!'!+%$'))':#$(;$#!)+,-#0$H()$*I'DB&*= int main(int argc, char *argv[])
{
QApplication app(argc, argv);
void OrderForm::init() QTranslator appTranslator;
{ appTranslator.load("myapp_" + QLocale::system().name(),
static const char * const flowers[] = { qApp->applicationDirPath());
QT_TR_NOOP("Medium Stem Pink Roses"), app.installTranslator(&appTranslator);
QT_TR_NOOP("One Dozen Boxed Roses"), ...
QT_TR_NOOP("Calypso Orchid"), return app.exec();
QT_TR_NOOP("Dried Red Rose Bouquet"), }
QT_TR_NOOP("Mixed Peonies Bouquet"),
0
};
for (int i = 0; flowers[i]; ++i) N2* QLocale::system()$;?,%!+(,$)*!?),#$' QLocale$(6C*%!$!2'!$B)(E+/*#$+,;()D'!+(,$'6(?!$!2*$?#*)"#
comboBox->addItem(tr(flowers[i])); &(%'&*0$R(,E*,!+(,'&&:A$9*$?#*$!2*$&(%'&*"#$,'D*$'#$B')!$(;$!2* .qm$;+&*$,'D*0$@(%'&*$,'D*#$%',$6*
} D()*$()$&*##$B)*%+#*P$;()$*I'DB&*A fr$#B*%+;+*#$'$H)*,%25&',-?'-*$&(%'&*A fr_CA$#B*%+;+*#$'$H)*,%2
R','/+',$&(%'&*A$',/ fr_CA.ISO8859-15$#B*%+;+*#$'$H)*,%2$R','/+',$&(%'&*$9+!2$>[\$77ab53a
*,%(/+,-$K',$*,%(/+,-$!2'!$#?BB()!#$"M"A$"n"A$"o"A$',/$" "L0
N2* QT_tr_NOOP()$D'%)($#+DB&:$)*!?),#$+!#$')-?D*,!0$X?! lupdate$9+&&$*I!)'%!$'&&$!2*$#!)+,-#$9)'BB*/
+, QT_tr_NOOP()$#($!2'!$!2*:$%',$6*$!)',#&'!*/0$G2*,$?#+,-$!2*$E')+'6&*$&'!*)$(,A$9*$%'&& tr()$!( <##?D+,-$!2'!$!2*$&(%'&*$+# fr_CA.ISO8859-15A$!2* Qtranslator::load()$;?,%!+(,$;+)#!$!)+*#$!($&('/$!2*
B*);()D$!2*$!)',#&'!+(,$'#$?#?'&0$1E*,$!2(?-2$9*$2'E*$B'##*/ tr()$'$E')+'6&*A$!2*$!)',#&'!+(,$9+&& ;+&* myapp_fr_CA.ISO8859-15.qm0$>;$!2+#$;+&*$/(*#$,(!$*I+#!A load()$,*I!$!)+*# myapp_fr_CA.qmA$!2*,
#!+&&$9()F0 myapp_fr.qmA$',/$;+,'&&: myapp.qmA$6*;()*$-+E+,-$?B0$g()D'&&:A$9*$9(?&/$(,&:$B)(E+/* myapp_fr.qmA
%(,!'+,+,-$'$#!',/')/$H)*,%2$!)',#&'!+(,A$6?!$+;$9*$,**/$'$/+;;*)*,!$;+&*$;()$H)*,%25#B*'F+,-$R','/'A
N2*)*$+#$'&#($' QT_TRANSLATE_NOOP()$D'%)($!2'!$9()F#$&+F* QT_tr_NOOP()$6?!$'&#($!'F*#$'$%(,!*I!0 9*$%', '&#($B)(E+/* myapp_fr_CA.qm$',/$+!$9+&&$6*$?#*/$;() fr_CA$&(%'&*#0
N2+#$D'%)($+#$?#*;?&$92*,$+,+!+'&+h+,-$E')+'6&*#$(?!#+/*$(;$'$%&'##=
N2*$#*%(,/$')-?D*,!$!( QTRanslator::load()$+#$!2*$/+)*%!():$92*)*$9*$9',! load()$!($&((F$;()$!2*
!)',#&'!+(,$;+&*0$>,$!2+#$%'#*A$9*$'##?D*$!2'!$!2*$!)',#&'!+(,$;+&*#$')*$&(%'!*/$+,$!2*$#'D*$/+)*%!():$'#
!2*$*I*%?!'6&*0 &(%'&*5#B*%+;+%$+,;()D'!+(,A$9*$%',$?#*$!2*$#!',/')/$Rjj setlocale()$',/ localeconv()$;?,%!+(,#0

N2*$ !$&+6)')+*#$%(,!'+,$'$;*9$#!)+,-#$!2'!$,**/$!($6*$!)',#&'!*/0$N)(&&!*%2$B)(E+/*#$H)*,%2A$J*)D',A [(D*$ !$%&'##*#$',/$;?,%!+(,#$'/'B!$!2*+)$6*2'E+()$!($!2*$&(%'&*=


',/$[+DB&+;+*/$R2+,*#*$!)',#&'!+(,#$+,$ !"# translations$/+)*%!():0$<$;*9$(!2*)$&',-?'-*#$')*
B)(E+/*/$'#$9*&&A$6?!$!2*#*$')*$%(,!)+6?!*/$6:$ !$?#*)#$',/$')*$,(!$(;;+%+'&&:$#?BB()!*/0$N2*$ ! • QString::localeAwareCompare()$%(DB')*#$!9($#!)+,-#$+,$'$&(%'&*5/*B*,/*,!$D',,*)0 >!$+#
&+6)')+*#"$!)',#&'!+(,$;+&*$#2(?&/$'&#($6*$&('/*/= ?#*;?&$;()$#()!+,-$?#*)5E+#+6&*$+!*D#0
• N2* toString()$;?,%!+(,$B)(E+/*/$6: QDateA QTimeA$',/ QDateTime$)*!?),#$'$#!)+,-$+,$'$&(%'&
;()D'!$92*,$%'&&*/$9+!2 Qt::LocalDate$'#$')-?D*,!0
QTranslator qtTranslator; • X:$/*;'?&!A$!2* QDateEdit$',/ QDateTimeEdit$9+/-*!#$B)*#*,!$/'!*#$+,$!2*$&(%'&$;()D'!0
qtTranslator.load("qt_" + QLocale::system().name(),
qApp->applicationDirPath());
app.installTranslator(&qtTranslator); H+,'&&:A$'$!)',#&'!*/$'BB&+%'!+(,$D':$,**/$!($?#*$/+;;*)*,!$+%(,#$+,$%*)!'+,$#+!?'!+(,#$)'!2*)$!2',$!2*
()+-+,'&$+%(,#0$H()$*I'DB&*A$!2*$&*;!$',/$)+-2!$'))(9#$(,$'$9*6$6)(9#*)"#$X'%F$',/$H()9')/$6?!!(,#
#2(?&/$6*$#9'BB*/$92*, /*'&+,-$9+!2$'$)+-2!5!(5&*;!$&',-?'-*0$G*$%',$/($!2+#$'#$;(&&(9#=
< QTRanslator$(6C*%!$%',$(,&:$2(&/$(,*$!)',#&'!+(,$;+&*$'!$'$!+D*A$#($9*$?#*$'$#*B')'!* Qtranslator
;()$ !"#$!)',#&'!+(,0$8'E+,-$C?#!$(,*$;+&*$B*)$!)',#&'!()$+#$,(!$'$B)(6&*D$#+,%*$9*$%',$+,#!'&&$'#$D',: if (QApplication::isRightToLeft()) {
!)',#&'!()#$'#$9*$,**/0 QApplication$9+&&$?#*$'&&$(;$!2*D$92*,$#*')%2+,-$;()$'$!)',#&'!+(,0 backAction->setIcon(forwardIcon);
forwardAction->setIcon(backIcon);
[(D*$&',-?'-*#A$#?%2$'#$<)'6+%$',/$8*6)*9A$')*$9)+!!*,$)+-2!5!(5&*;!$+,#!*'/$(;$&*;!5!(5)+-2!0$>, } else {
!2(#*$&',-?'-*#A$!2*$92(&*$&':(?!$(;$!2*$'BB&+%'!+(,$D?#!$6*$)*E*)#*/A$',/$!2+#$+#$/(,*$6: %'&&+,- backAction->setIcon(backIcon);
QApplication::setLayoutDirection(Qt::RightToLeft)0$N2*$!)',#&'!+(,$;+&*#$;()$ !$%(,!'+,$'$#B*%+'& forwardAction->setIcon(forwardIcon);
D')F*)$%'&&*/$`@Nc`$!2'!$!*&&#$ !$92*!2*)$!2*$&',-?'-*$+#$&*;!5!(5)+-2!$()$)+-2!5!(5&*;!A$#($9*$,()D'&&: }
/(,"!$,**/$!($%'&& setLayoutDirection()$(?)#*&E*#0

>!$D':$B)(E*$D()*$%(,E*,+*,!$;()$(?)$?#*)#$+;$9*$#?BB&:$(?)$'BB&+%'!+(,#$9+!2$!2*$!)',#&'!+(,$;+&*# >%(,#$!2'!$%(,!'+,$'&B2'6*!+%$%2')'%!*)#$E*):$%(DD(,&:$,**/$!($6*$!)',#&'!*/0$H()$*I'DB&*A$!2*
*D6*//*/$+,$!2*$*I*%?!'6&*A$?#+,-$ !"#$)*#(?)%*$#:#!*D0$g(!$(,&:$/(*#$!2+#$)*/?%*$!2*$,?D6*)$(; &*!!*)$">"$(,$'$!((&6')$6?!!(,$'##(%+'!*/$9+!2$'$9()/$B)(%*##()"#$>!'&+%$(B!+(,$#2(?&/$6*$)*B&'%*/$6:$'
;+&*#$/+#!)+6?!*/$'#$B')!$(;$!2*$B)(/?%!A$+!$'&#($'E(+/#$!2*$)+#F$(;$!)',#&'!+(,$;+&*#$-*!!+,-$&(#!$() "R"$+,$[B',+#2$KR?)#+E(L$',/$6:$'$"T"$+,$Y',+#2A$Y?!%2A$J*)D',A$g()9*-+',A$',/$[9*/+#2$KT?)#+EL0
/*&*!*/$6:$'%%+/*,!0 8*)*"#$'$#+DB&*$9':$!($/($+!=

<##?D+,-$!2'!$!2* .qm$;+&*#$')*$&(%'!*/$+,$' TRanslations$#?6/+)*%!():$+,$!2*$#(?)%*$!)**A$9*$9(?&/


if (tr("Italic")[0] == 'C') {
!2*,$2'E*$' myapp.qrc$;+&*$9+!2$!2*$;(&&(9+,-$%(,!*,!#=
italicAction->setIcon(iconC);
} else if (tr("Italic")[0] == 'K') {
italicAction->setIcon(iconK);
<!DOCTYPE RCC><RCC version="1.0"> } else {
<qresource> italicAction->setIcon(iconI);
<file>translations/myapp_de.qm</file> }
<file>translations/myapp_fr.qm</file>
<file>translations/myapp_zh.qm</file>
<file>translations/qt_de.qm</file>
<file>translations/qt_fr.qm</file> <,$'&!*),'!+E*$+#$!($?#*$!2*$)*#(?)%*$#:#!*D"#$#?BB()!$;()$D?&!+B&*$&(%'&*#0$>,$!2* .qrc$;+&*A$9*$%',
<file>translations/qt_zh.qm</file> #B*%+;:$'$&(%'&*$;()$'$)*#(?)%*$?#+,-$!2* lang$'!!)+6?!*0$H()$*I'DB&*=
</qresource>
</RCC>
<qresource>
<file>italic.png</file>
N2* .pro$;+&*$9(?&/$%(,!'+,$!2*$;(&&(9+,-$*,!):= </qresource>
<qresource lang="es">
<file alias="italic.png">cursivo.png</file>
</qresource>
RESOURCES = myapp.qrc <qresource lang="sv">
<file alias="italic.png">kursiv.png</file>
</qresource>
H+,'&&:A$+, main()A$9*$D?#!$#B*%+;: :/translations$'#$!2*$B'!2$;()$!2*$!)',#&'!+(,$;+&*#0$N2*$&*'/+,-
%(&(,$+,/+%'!*#$!2'!$!2*$B'!2$)*;*)#$!($'$)*#(?)%*$'#$(BB(#*/$!($'$;+&*$+,$!2*$;+&*$#:#!*D0
>;$!2*$?#*)"#$&(%'&*$+# es$K1#B'p(&LA :/italic.png$6*%(D*#$'$)*;*)*,%*$!($!2* cursivo.png$+D'-*0$>;
G*$2'E*$,(9$%(E*)*/$'&&$!2'!$+#$)*V?+)*/$!($D'F*$',$'BB&+%'!+(,$'6&*$!($(B*)'!*$?#+,-$!)',#&'!+(,# !2*$&(%'&* +# sv$K[E*,#F'LA$!2* kursiv.png$+D'-*$+#$?#*/0 H()$(!2*)$&(%'&*#A italic.png$+#$?#*/0
+,!($(!2*)$&',-?'-*#0$X?!$&',-?'-*$',/$!2*$/+)*%!+(,$(;$!2*$9)+!+,-$#:#!*D$')*$,(!$!2*$(,&:$!2+,-#
!2'!$E'):$6*!9**,$%(?,!)+*#$',/$%?&!?)*#0$<,$+,!*),'!+(,'&+h*/$B)(-)'D$D?#!$'&#($!'F*$+,!($'%%(?,!
!2*$&(%'&$/'!*$',/$!+D*$;()D'!#A$D(,*!'):$;()D'!#A$,?D*)+%$;()D'!#A$',/$#!)+,-$%(&&'!+(,$()/*)0$ !
+,%&?/*#$' QLocale$%&'##$!2'!$B)(E+/*#$&(%'&+h*/$,?D*)+%$',/$/'!*O!+D*$;()D'!#0$N($V?*):$(!2*)
N2* qttranslator$E')+'6&*$+#$' QTRanslator$(6C*%!$?#*/$;()$#!()+,-$ !"#$!)',#&'!+(,0
Dynamic Language Switching •
• N2* qmPath$E')+'6&*$+#$' QString$!2'!$#B*%+;+*# !2*$B'!2$(;$!2*$/+)*%!():$!2'!$%(,!'+,#$!2*
'BB&+%'!+(,"#$!)',#&'!+(,$;+&*#0
H()$D(#!$'BB&+%'!+(,#A$/*!*%!+,-$!2*$?#*)"#$B)*;*))*/$&',-?'-*$+, main()$',/$&('/+,-$!2*$'BB)(B)+'!*
.qm$;+&*#$!2*)*$+#$B*);*%!&:$#'!+#;'%!():0$X?!$!2*)*$')*$#(D*$#+!?'!+(,#$92*)*$?#*)#$D+-2!$,**/$!2* <!$!2*$*,/A$9*$%'&&$!2* createActions()$',/ createMenus()$B)+E'!*$;?,%!+(,#$!($%)*'!*$!2*$D*,?
'6+&+!:$!($#9+!%2$&',-?'-*$/:,'D+%'&&:0$<,$'BB&+%'!+(,$!2'!$+#$?#*/$%(,!+,?(?#&:$6:$/+;;*)*,!$B*(B&*$+, #:#!*DA$',/$9*$%'&& retranslateUi()A$'&#($'$B)+E'!*$;?,%!+(,A$!($#*!$!2*$?#*)5E+#+6&*$#!)+,-#$;()$!2*
#2+;!#$D':$,**/$!($%2',-*$&',-?'-*$9+!2(?!$2'E+,-$!($6*$)*#!')!*/0$H()$*I'DB&*A$'BB&+%'!+(,#$?#*/ ;+)#!$!+D*0
6:$%'&&$%*,!*)$(B*)'!()#A$6:$#+D?&!',*(?#$!)',#&'!()#A$',/$6:$%(DB?!*)+h*/$%'#2$)*-+#!*)$(B*)'!()#
(;!*,$)*V?+)*$!2+#$%'B'6+&+!:0
void MainWindow::createActions()
Z'F+,-$',$'BB&+%'!+(,$'6&*$!($#9+!%2$&',-?'-*$/:,'D+%'&&:$)*V?+)*#$'$&+!!&*$D()*$9()F$!2',$&('/+,-$' {
#+,-&*$!)',#&'!+(,$'!$#!')!?BA$6?!$+!$+#$,(!$/+;;+%?&!0 8*)*"#$92'!$D?#!$6*$/(,*= newAction = new QAction(this);
connect(newAction, SIGNAL(triggered()), this, SLOT(newFile()));
• ])(E+/*$'$D*',#$6:$92+%2$!2*$?#*)$%',$#9+!%2$&',-?'-*0 ...
• H()$*E*):$9+/-*!$()$/+'&(-A$#*!$'&&$(;$+!#$!)',#&'!'6&*$#!)+,-#$+,$'$#*B')'!*$;?,%!+(,$K(;!*, aboutQtAction = new QAction(this);
%'&&*/ retranslateUi()L$',/$%'&&$!2+#$;?,%!+(,$92*,$!2*$&',-?'-*$%2',-*#0 connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
@*!"#$)*E+*9$!2*$)*&*E',!$B')!#$(;$'$`%'&&$%*,!*)`$'BB&+%'!+(,"#$#(?)%*$%(/*0$N2*$'BB&+%'!+(,$B)(E+/*#$'
@',-?'-*$D*,?$!($'&&(9$!2*$?#*)$!($#*!$!2*$&',-?'-*$'!$)?,5!+D*0 N2*$/*;'?&!$&',-?'-*$+#$1,-&+#20
N2* createActions()$;?,%!+(,$%)*'!*#$!2* QAction$(6C*%!#$'#$?#?'&A$6?!$9+!2(?!$#*!!+,-$',:$(;$!2*
!*I!#$()$#2()!%?!$F*:#0$N2*#*$9+&&$6*$/(,*$+, retranslate-Ui()0
!"#$%&'()')&*&+,-./!0&1.-"#."%&/%-#

void MainWindow::createMenus()
{
fileMenu = new QMenu(this);
fileMenu->addAction(newAction);
fileMenu->addAction(openAction);
fileMenu->addAction(saveAction);
fileMenu->addAction(exitAction);
...
createLanguageMenu();
helpMenu = new QMenu(this);
helpMenu->addAction(aboutAction);
helpMenu->addAction(aboutQtAction);
menuBar()->addMenu(fileMenu);
[+,%*$9*$/(,"!$F,(9$92+%2$&',-?'-*$!2*$?#*)$9+&&$9',!$!($?#*$92*,$!2*$'BB&+%'!+(,$+#$#!')!*/A$9*$,( menuBar()->addMenu(editMenu);
&(,-*)$&('/$!)',#&'!+(,#$+,$!2* main()$;?,%!+(,0$>,#!*'/A$9*$9+&&$&('/$!2*D$/:,'D+%'&&:$92*,$!2*:$')* menuBar()->addMenu(reportsMenu);
,**/*/A$#($'&&$!2*$%(/*$!2'!$9*$,**/$!($2',/&*$!)',#&'!+(,#$D?#!$-($+,$!2*$D'+,$9+,/(9$',/$/+'&(- menuBar()->addMenu(languageMenu);
%&'##*#0 menuBar()->addMenu(helpMenu);
}
@*!"#$2'E*$'$&((F$'!$!2*$'BB&+%'!+(,"# QMainWindow$#?6%&'##0

N2* createMenus()$;?,%!+(,$%)*'!*#$D*,?#A$6?!$/(*#$,(!$-+E*$!2*D$',:$!+!&*#0$<-'+,A$!2+#$9+&&$6*
MainWindow::MainWindow() /(,*$+, retranslateUi()0
{
journalView = new JournalView; >,$!2*$D+//&*$(;$!2*$;?,%!+(,A$9*$%'&& createLanguageMenu()$!($;+&&$!2*$@',-?'-*$D*,?$9+!2$!2*$&+#!$(;
setCentralWidget(journalView); #?BB()!*/$&',-?'-*#0$G*$9+&&$)*E+*9$+!#$#(?)%*$%(/*$+,$'$D(D*,!0 H+)#!A$&*!"#$&((F$'!
qApp->installTranslator(&appTranslator);
retranslateUi()=
qApp->installTranslator(&qtTranslator);
qmPath = qApp->applicationDirPath() + "/translations";
createActions();
createMenus(); void MainWindow::retranslateUi()
retranslateUi(); {
} newAction->setText(tr("&New"));
newAction->setShortcut(tr("Ctrl+N"));
newAction->setStatusTip(tr("Create a new journal"));
...
>,$!2*$%(,#!)?%!()A$9*$#*!$!2*$%*,!)'&$9+/-*!$!($6*$' JournalViewA$' QTableWidget$#?6%&'##0$N2*,$9* aboutQtAction->setText(tr("About &Qt"));
#*!$?B$'$;*9$B)+E'!*$D*D6*)$E')+'6&*#$)*&'!*/ !($!)',#&'!+(,= aboutQtAction->setStatusTip(tr("Show the Qt library's About box"));
fileMenu->setTitle(tr("&File"));
• N2* appTranslator$E')+'6&*$+#$' QTRanslator$(6C*%!$?#*/$;()$#!()+,-$!2*$%?))*,!$'BB&+%'!+(,"# editMenu->setTitle(tr("&Edit"));
!)',#&'!+(,0 reportsMenu->setTitle(tr("&Reports"));
languageMenu->setTitle(tr("&Language"));
helpMenu->setTitle(tr("&Help")); void MainWindow::switchLanguage(QAction *action)
setWindowTitle(tr("Call Center")); {
} QString locale = action->data().toString();
appTranslator.load("callcenter_" + locale, qmPath);
qtTranslator.load("qt_" + locale, qmPath);
retranslateUi();
N2* retranslateUi()$;?,%!+(,$+#$92*)*$'&&$!2* TR()$%'&&#$;()$!2* MainWindow$%&'##$(%%?)0$>!$+#$%'&&*/$'! }
!2*$*,/$(;$!2* MainWindow$%(,#!)?%!()$',/$'&#($*E*):$!+D*$'$?#*)$%2',-*#$!2*$'BB&+%'!+(,"#$&',-?'-*
?#+,-$!2*$@',-?'-*$D*,?0

N2* switchLanguage()$#&(!$+#$%'&&*/$92*,$!2*$?#*)$%2((#*#$'$&',-?'-*$;)(D$!2*$@',-?'-*$D*,?0$G*
G*$#*!$*'%2 QAction"#$!*I!A$#2()!%?!$F*:A$',/$#!'!?#$!+B0$G*$'&#($#*!$*'%2 QMenu"#$!+!&*A$'#$9*&&$'#$!2*
&('/$!2*$!)',#&'!+(,$;+&*#$;()$!2*$'BB&+%'!+(,$',/$;()$ !A$',/$9*$%'&& retranslateUi()$!($)*!)',#&'!*$'&&
9+,/(9$!+!&*0
!2*$#!)+,-#$;()$!2*$D'+,$9+,/(90

N2* createMenus()$;?,%!+(,$B)*#*,!*/$*')&+*)$%'&&*/ createLanguageMenu()$!($B(B?&'!*$!2*$@',-?'-*


\,$G+,/(9#A$',$'&!*),'!+E*$!($B)(E+/+,-$'$@',-?'-*$D*,?$+#$!($)*#B(,/$!( LocaleChange$*E*,!#A$'
D*,?$9+!2$'$&+#!$(;$&',-?'-*#=
!:B*$(;$*E*,!$*D+!!*/$6:$ !$92*,$+!$/*!*%!#$'$%2',-*$+,$!2*$*,E+)(,D*,!"#$&(%'&*0$N2*$*E*,!$!:B*
*I+#!#$(,$'&&$B&'!;()D#$#?BB()!*/$6:$ !A$6?!$+#$(,&:$'%!?'&&:$-*,*)'!*/$(,$G+,/(9#A$92*,$!2*$?#*)
%2',-*#$!2*$#:#!*D"#$&(%'&*$#*!!+,-#$K+,$!2*$R(,!)(&$]',*&"#$c*-+(,'&$',/$@',-?'-*$\B!+(,#L0$N(
void MainWindow::createLanguageMenu()
{ 2',/&* LocaleChange$*E*,!#A$9*$%',$)*+DB&*D*,! QWidget::changeEvent()$'#$;(&&(9#=
languageMenu = new QMenu(this);
languageActionGroup = new QActionGroup(this);
connect(languageActionGroup, SIGNAL(triggered(QAction *)), void MainWindow::changeEvent(QEvent *event)
this, SLOT(switchLanguage(QAction *))); {
QDir dir(qmPath); if (event->type() == QEvent::LocaleChange) {
QStringList fileNames = appTranslator.load("callcenter_"
dir.entryList(QStringList("callcenter_*.qm")); + QLocale::system().name(), qmPath);
for (int i = 0; i < fileNames.size(); ++i) { qtTranslator.load("qt_" + QLocale::system().name(), qmPath);
QString locale = fileNames[i]; retranslateUi();
locale.remove(0, locale.indexOf('_') + 1); }
locale.truncate(locale.lastIndexOf('.')); QMainWindow::changeEvent(event);
QTranslator translator; }
translator.load(fileNames[i], qmPath);
QString language = translator.translate("MainWindow",
"English"); >;$!2*$?#*)$#9+!%2*#$&(%'&*$92+&*$!2*$'BB&+%'!+(,$+#$6*+,-$)?,A$9*$'!!*DB!$!($&('/$!2*$%())*%!
QAction *action = new QAction(tr("&%1 %2")
!)',#&'!+(,$;+&*#$;()$!2*$,*9$&(%'&*$',/$%'&& retranslateUi()$!($?B/'!*$!2*$?#*)$+,!*);'%*0$>,$'&&$%'#*#A
.arg(i + 1).arg(language), this);
action->setCheckable(true); 9*$B'##$!2*$*E*,!$(,$!($!2*$6'#*$%&'##"# changeEvent()$;?,%!+(,A$#+,%*$!2*$6'#*$%&'##$D':$'&#($6*
action->setData(locale); +,!*)*#!*/$+, LocaleChange$()$(!2*)$%2',-*$*E*,!#0
languageMenu->addAction(action);
languageActionGroup->addAction(action); G*$2'E*$,(9$;+,+#2*/$(?)$)*E+*9$(;$!2* MainWindow$%(/*0$g*I!$9*$9+&&$&((F$'!$!2*$%(/*$;()$(,*$(;$!2*
if (language == "English") 'BB&+%'!+(,"#$9+/-*!$%&'##*#A$!2* JournalView$%&'##A$!($#**$92'!$%2',-*#$')*$,**/*/$!($D'F*$+!
action->setChecked(true); #?BB()!$/:,'D+%$!)',#&'!+(,0
}
}
JournalView::JournalView(QWidget *parent)
: QTableWidget(parent)
>,#!*'/$(;$2')/5%(/+,-$!2*$&',-?'-*#$#?BB()!*/$6:$!2*$'BB&+%'!+(,A$9*$%)*'!*$(,*$D*,?$*,!):$;() {
*'%2 .qm$;+&*$&(%'!*/$+,$!2*$'BB&+%'!+(,"# translations$/+)*%!():0$H()$#+DB&+%+!:A$9*$'##?D*$!2'! ...
1,-&+#2$'&#($2'#$' .qm$;+&*0$<,$'&!*),'!+E*$9(?&/$2'E*$6**,$!($%'&& clear()$(,$!2* Qtranslator$(6C*%!# retranslateUi();
92*,$!2*$?#*)$%2((#*#$1,-&+#20 }

\,*$B')!+%?&')$/+;;+%?&!:$+#$!($B)*#*,!$'$,+%*$,'D*$;()$!2*$&',-?'-*$B)(E+/*/$6:$*'%2 .qm$;+&*0$S?#!
#2(9+,-$`*,`$;()$`1,-&+#2`$()$`/*`$;()$`Y*?!#%2`A$6'#*/$(,$!2*$,'D*$(;$!2* .qm$;+&*A$&((F#$%)?/*$',/ N2* JournalView$%&'##$+#$' QTableWidget$#?6%&'##0$<!$!2*$*,/$(;$!2*$%(,#!)?%!()A$9*$%'&&$!2*$B)+E'!*
9+&&$%(,;?#*$#(D*$?#*)#0$N2*$#(&?!+(,$?#*/$+, createLanguageMenu()$+#$!($%2*%F$!2*$!)',#&'!+(,$(;$!2* ;?,%!+(, retranslateUi()$!($#*!$!2*$9+/-*!"#$#!)+,-#0$N2+#$+#$#+D+&')$!($92'!$9*$/+/$;() MainWindow0
#!)+,-$`1,-&+#2`$+,$!2*$`Z'+,G+,/(9`$%(,!*I!0$N2'!$#!)+,-$#2(?&/$6*$!)',#&'!*/$!($`Y*?!#%2`$+,$'
J*)D',$!)',#&'!+(,A$!($`H)',q'+#`$+,$'$H)*,%2$!)',#&'!+(,A$',/$!($` `$+,$'$S'B',*#*$!)',#&'!+(,0
void JournalView::changeEvent(QEvent *event)
{
G*$%)*'!*$(,*$%2*%F'6&* QAction$;()$*'%2$&',-?'-*$',/$#!()*$!2*$&(%'&*$,'D*$+,$!2*$'%!+(,"#$`/'!'` if (event->type() == QEvent::LanguageChange)
+!*D0$G*$'//$!2*D$!($' QActionGroup$(6C*%!$!($*,#?)*$!2'!$(,&:$(,*$@',-?'-*$D*,?$+!*D$+#$%2*%F*/ retranslateUi();
'!$'$!+D*0$G2*,$',$'%!+(,$;)(D$!2*$-)(?B$+#$%2(#*,$6:$!2*$?#*)A$!2* QActionGroup$*D+!#$!2* QTableWidget::changeEvent(event);
triggered(QAction *)$#+-,'&A$92+%2$+#$%(,,*%!*/$!( switchLanguage()0 }
!2*$;+)#!$!+D*$9*$)?, lupdate$',/$')*$?B/'!*/$*E*):$!+D*$9*$#?6#*V?*,!&:$)?, lupdate0
G*$'&#($)*+DB&*D*,!$!2* changeEvent()$;?,%!+(,$!($%'&& retranslateUi()$(, LanguageChange$*E*,!#0
!$-*,*)'!*#$' LanguageChange$*E*,!$92*,$!2*$%(,!*,!#$(;$' QTRanslator$%?))*,!&:$+,#!'&&*/$(, N2*#*$;+&*#$,()D'&&:$2'E*$' .ts$*I!*,#+(,0$N2*:$')*$+,$'$#!)'+-2!;()9')/$WZ@$;()D'!$',/$')*$,(!$'#
QApplication$%2',-*#0$>,$(?)$'BB&+%'!+(,A$!2+#$(%%?)#$92*,$9*$%'&& load()$(, appTranslator$() %(DB'%!$'#$!2*$6+,'): .qm$;+&*#$?,/*)#!((/$6: Qtranslator0$>!$+# lrelease"#$C(6$!($%(,E*)!$2?D',5
qttranslatorA$*+!2*)$;)(D MainWindow::switchLanguage()$()$;)(D MainWindow::changeEvent()0 )*'/'6&* .ts$;+&*#$+,!($D'%2+,*5*;;+%+*,! .qm$;+&*#0$H()$!2*$%?)+(?#A .ts$#!',/#$;()$`!)',#&'!+(,$#(?)%*`
',/ .qm$;()$` ! D*##'-*`$;+&*0
LanguageChange$*E*,!#$#2(?&/$,(!$6*$%(,;?#*/$9+!2 LocaleChange$*E*,!#0 Locale-Change$*E*,!#$')*
-*,*)'!*/$6:$!2*$#:#!*D$',/$!*&&$!2*$'BB&+%'!+(,A$`Z':6*$:(?$#2(?&/$&('/$'$,*9$!)',#&'!+(,0` <##?D+,-$!2'!$9*$')*$&(%'!*/$+,$!2*$/+)*%!():$!2'!$%(,!'+,#$!2*$[B)*'/#2**!$'BB&+%'!+(,"#$#(?)%*
LanguageChange$*E*,!#$')*$-*,*)'!*/$6:$ !$',/$!*&&$!2*$'BB&+%'!+(,"#$9+/-*!#A$`Z':6*$:(?$#2(?&/ %(/*A$9*$%',$)?, lupdate$(, spreadsheet.pro$;)(D$!2*$%(DD',/$&+,*$'#$;(&&(9#=
)*!)',#&'!*$'&&$:(?)$#!)+,-#0`

G2*,$9*$+DB&*D*,!*/ MainWindowA$9*$/+/,"!$,**/$!($)*#B(,/$!( LanguageChange0$>,#!*'/A$9*$#+DB&: lupdate -verbose spreadsheet.pro


%'&&*/ retranslateUi()$92*,*E*)$9*$%'&&*/ load()$(,$' Qtranslator0

N2* -verbose$(B!+(,$!*&&# lupdate$!($B)(E+/*$D()*$;**/6'%F$!2',$?#?'&0$8*)*"#$!2*$*IB*%!*/$(?!B?!=


void JournalView::retranslateUi()
{
QStringList labels; Updating 'spreadsheet_de.ts'...
labels << tr("Time") << tr("Priority") << tr("Phone Number") Found 98 source texts (98 new and 0 already existing)
<< tr("Subject"); Updating 'spreadsheet_fr.ts'...
setHorizontalHeaderLabels(labels); Found 98 source texts (98 new and 0 already existing)
}

1E*): #!)+,-$!2'!$'BB*')#$9+!2+,$' tr()$%'&&$+,$!2*$'BB&+%'!+(,"#$#(?)%*$%(/*$+#$#!()*/$+,$!2* .ts$;+&*#A


N2* retranslateUi()$;?,%!+(,$?B/'!*#$!2*$%(&?D,$2*'/*)#$9+!2$,*9&:$!)',#&'!*/$!*I!#A$%(DB&*!+,- '&(,-$9+!2$',$*DB!:$!)',#&'!+(,0$[!)+,-#$!2'!$'BB*')$+,$!2*$'BB&+%'!+(,"# .ui$;+&*#$')*$'&#($+,%&?/*/0
!2*$!)',#&'!+(,5)*&'!*/$%(/*$(;$'$2',/$9)+!!*,$9+/-*!0$H()$9+/-*!#$',/$/+'&(-#$/*E*&(B*/$9+!2 !
"#$%&'#(A$!2* uic$!((&$'?!(D'!+%'&&:$-*,*)'!*#$'$;?,%!+(,$#+D+&')$!($(?) retranslateUi()$;?,%!+(,
N2* lupdate$!((&$'##?D*#$6:$/*;'?&!$!2'!$!2*$')-?D*,!#$!( tr()$')*$@'!+,53$#!)+,-#0$>;$!2+#$+#,"!$!2*
!2'!$+#$'?!(D'!+%'&&:$%'&&*/$+,$)*#B(,#*$!( LanguageChange$*E*,!#0
%'#*A$9*$D?#!$'//$' CODECFORTR$*,!):$!($!2* .pro$;+&*0$H()$*I'DB&*=

Translating Applications
CODECFORTR = EUC-JP
N)',#&'!+,-$'$ !$'BB&+%'!+(,$!2'!$%(,!'+,# tr()$%'&&#$+#$'$!2)**5#!*B$B)(%*##=

N2+#$D?#!$6*$/(,*$+,$'//+!+(,$!($%'&&+,- QTextCodec::setCodecForTr()$;)(D$!2*$'BB&+%'!+(,"# main()


') c?, lupdate$!($*I!)'%!$'&&$!2*$?#*)5E+#+6&*$#!)+,-#$;)(D$!2*$'BB&+%'!+(,"#$#(?)%*$%(/*0
;?,%!+(,0

N)',#&'!+(,#$!2*,$,**/$!($6*$'//*/$!($!2* spreadsheet_de.ts$',/ spreadsheet_fr.ts$;+&*#$?#+,- !


2) N)',#&'!*$!2*$'BB&+%'!+(,$?#+,- !)*%'&+%$!0 *%'&+%$!0

3) c?, lrelease$!($-*,*)'!*$6+,'): .qm$;+&*#$!2'!$!2*$'BB&+%'!+(,$%',$&('/$?#+,- QTRanslator0 N($)?, !)*%'&+%$!A$%&+%F$ !$6:$N)(&&!*%2$EQ0I0:r@+,-?+#!$+,$!2*$[!')!$D*,?$(,$G+,/(9#A$!:B*


linguist$(,$!2*$%(DD',/$&+,*$(,$.,+IA$()$/(?6&*5%&+%F$@+,-?+#!$+,$!2*$Z'%$\[$W$H+,/*)0$N($#!')!
'//+,-$!)',#&'!+(,#$!($' .ts$;+&*A$%&+%F$H+&*r\B*,$',/$%2((#*$!2*$;+&*$!($!)',#&'!*0
[!*B#$3$',/$d$')*$B*);()D*/$6:$'BB&+%'!+(,$/*E*&(B*)#0$[!*B$f$+#$2',/&*/$6:$!)',#&'!()#0$N2+#$%:%&*
%',$6*$)*B*'!*/$'#$(;!*,$'#$,*%*##'):$/?)+,-$!2*$'BB&+%'!+(,"#$/*E*&(BD*,!$',/$&+;*!+D*0 N2*$&*;!52',/$#+/*$(; !)*%'&+%$!"#$D'+,$9+,/(9$#2(9#$!2*$&+#!$(;$%(,!*I!#$;()$!2*$'BB&+%'!+(,$6*+,-
!)',#&'!*/0$H()$!2*$[B)*'/#2**!$'BB&+%'!+(,A$!2*$%(,!*I!#$')*$`H+,/Y+'&(-`A$`J(N(R*&&Y+'&(-`A
<#$',$*I'DB&*A$9*$9+&&$#2(9$2(9$!($!)',#&'!*$!2*$[B)*'/#2**!$'BB&+%'!+(,$(; R2'B!*)$d0$N2* `Z'+,G+,/(9`A$`[()!Y+'&(-`A$',/$`[B)*'/#2**!`0$N2*$!(B5)+-2!$')*'$+#$!2*$&+#!$(;$#(?)%*$!*I!#$;()$!2*
'BB&+%'!+(,$'&)*'/:$%(,!'+,# TR()$%'&&#$')(?,/$*E*):$?#*)5E+#+6&*$#!)+,-0 %?))*,!$%(,!*I!0$1'%2$#(?)%*$!*I!$+#$#2(9,$'&(,-$9+!2$'$!)',#&'!+(,$',/$'$Y(,*$;&'-0$N2*$D+//&*5
)+-2!$')*'$+#$92*)*$9*$%',$*,!*)$'$!)',#&'!+(,$;()$!2*$%?))*,!$#(?)%*$+!*D0$N2*$6(!!(D5)+-2!$')*'$+#$'
&+#!$(;$#?--*#!+(,#$'?!(D'!+%'&&:$B)(E+/*/$6: !)*%'&+%$!0
H+)#!A$9*$D?#!$D(/+;:$!2*$'BB&+%'!+(,"# .pro$;+&*$#&+-2!&:$!($#B*%+;:$92+%2$&',-?'-*#$9*$9',!$!(
#?BB()!0$H()$*I'DB&*A$+;$9*$9',!$!($#?BB()!$J*)D',$',/$H)*,%2$+,$'//+!+(,$!($1,-&+#2A$9*$9(?&/
'//$!2*$;(&&(9+,- trANSLATIONS$*,Nc:$!( spreadsheet.pro= \,%*$9*$2'E*$'$!)',#&'!*/ .ts$;+&*A$9*$,**/$!($%(,E*)!$+!$!($'$6+,'): .qm$;+&*$;()$+!$!($6*$?#'6&*$6:
Qtranslator0$N($/($!2+#$;)(D$9+!2+, !)*%'&+%$!A$%&+%F$H+&*rc*&*'#*0$N:B+%'&&:A$9*$9(?&/$#!')!$6:
!)',#&'!+,-$(,&:$'$;*9$#!)+,-#$',/$)?,$!2*$'BB&+%'!+(,$9+!2$!2* .qm$;+&*$!($D'F*$#?)*$!2'!$*E*):!2+,-
TRANSLATIONS = spreadsheet_de.ts \ 9()F#$B)(B*)&:0
spreadsheet_fr.ts
!"#$%&'()2) !"#$%&'$(!&!-&.04!5-

8*)*A$9*$#B*%+;:$!9($!)',#&'!+(,$;+&*#=$(,*$;()$J*)D',$',/$(,*$;()$H)*,%20$N2*#*$;+&*#$9+&&$6*$%)*'!*/ [View full size image]


Chapter 18. Multithreading
• )*+,!$%&"-.*+,/(
• 01%2.*3%$4$%&"-.*+,/(
• )355'%$2,!$%&"6$!."!.+"7,$%"-.*+,/
• 8($%&" !9("):,((+("$%"0+23%/,*1"-.*+,/(

R(,E*,!+(,'&$J.>$'BB&+%'!+(,#$2'E*$(,*$!2)*'/$(;$*I*%?!+(,$',/$B*);()D$(,*$(B*)'!+(,$'!$'$!+D*0$>;
!2*$?#*)$+,E(F*#$'$!+D*5%(,#?D+,-$(B*)'!+(,$;)(D$!2*$?#*)$+,!*);'%*A$!2*$+,!*);'%*$!:B+%'&&:$;)**h*#
92+&*$!2*$(B*)'!+(,$+#$+,$B)(-)*##0 R2'B!*)$e$K1E*,!$])(%*##+,-L$B)*#*,!#$#(D*$#(&?!+(,#$!($!2+#
B)(6&*D0$Z?&!+5!2)*'/+,-$+#$',(!2*)$#(&?!+(,0

>,$'$D?&!+!2)*'/*/$'BB&+%'!+(,A$!2*$J.>$)?,#$+,$+!#$(9,$!2)*'/$',/$!2*$B)(%*##+,-$!'F*#$B&'%*$+,$(,*
()$D()*$(!2*)$!2)*'/#0$N2+#$)*#?&!# +,$'BB&+%'!+(,#$!2'!$2'E*$)*#B(,#+E*$J.>#$*E*,$/?)+,-$+,!*,#+E*
B)(%*##+,-0$<,(!2*)$6*,*;+!$(;$D?&!+!2)*'/+,-$+#$!2'!$D?&!+B)(%*##()$#:#!*D#$%',$*I*%?!*$#*E*)'&
!2)*'/#$#+D?&!',*(?#&:$(,$/+;;*)*,!$B)(%*##()#A$)*#?&!+,-$+,$6*!!*)$B*);()D',%*0

>,$!2+#$%2'B!*)A$9*$9+&&$#!')!$6:$#2(9+,-$2(9$!($#?6%&'## QTHRead$',/$2(9$!($?#* QMutexA QSemaphoreA


',/ QWaitCondition$!($#:,%2)(,+h*$!2)*'/#0$N2*,$9*$9+&&$#**$2(9$!($%(DD?,+%'!*$9+!2$!2*$D'+,
>;$9*$9',!$!($)*-*,*)'!*$!2* .qm$;+&*#$;()$'&& .ts$;+&*#A$9*$%',$?#*$!2* lrelease$!((&$'#$;(&&(9#= !2)*'/$;)(D$#*%(,/'):$!2)*'/#$92+&*$!2*$*E*,!$&((B$+#$)?,,+,-0$H+,'&&:A$9*$)(?,/$(;;$9+!2$'$)*E+*9$(;
92+%2$ !$%&'##*#$%',$6*$?#*/$+,$#*%(,/'):$!2)*'/#$',/$92+%2$%',,(!0

lrelease -verbose spreadsheet.pro Z?&!+!2)*'/+,-$+#$'$&')-*$!(B+%$9+!2$D',:$6((F#$/*E(!*/$*I%&?#+E*&:$!($!2*$#?6C*%!0$8*)*$+!$+#


'##?D*/$!2'!$:(?$'&)*'/:$?,/*)#!',/$!2*$;?,/'D*,!'&#$(;$D?&!+!2)*'/*/$B)(-)'DD+,-A$#($!2*$;(%?#
+#$(,$*IB&'+,+,-$2(9$!($/*E*&(B$D?&!+!2)*'/*/$ !$'BB&+%'!+(,#$)'!2*)$!2',$(,$!2*$#?6C*%!$(;
!2)*'/+,-$+!#*&;0
<##?D+,-$!2'!$9*$!)',#&'!*/$3b$#!)+,-#$!($H)*,%2$',/$%&+%F*/$!2*$Y(,*$;&'-$;()$3e$(;$!2*DA lrelease
B)(/?%*#$!2*$;(&&(9+,-$(?!B?!=

Updating 'spreadsheet_de.qm'...
Creating Threads
Generated 0 translations (0 finished and 0 unfinished)
Ignored 98 untranslated source texts ])(E+/+,-$D?&!+B&*$!2)*'/#$+,$'$ !$'BB&+%'!+(,$+#$#!)'+-2!;()9')/=$G*$C?#!$#?6%&'## QThread$',/
Updating 'spreadsheet_fr.qm'... )*+DB&*D*,!$+!# run()$;?,%!+(,0$N($#2(9$2(9$!2+#$9()F#A$9*$9+&&$#!')!$6:$)*E+*9+,-$!2*$%(/*$;()$'
Generated 19 translations (17 finished and 2 unfinished) E*):$#+DB&* QThread$#?6%&'##$!2'!$)*B*'!*/&:$B)+,!#$'$-+E*,$#!)+,-$(,$'$%(,#(&*0
Ignored 79 untranslated source texts

class Thread : public QThread


.,!)',#&'!*/$#!)+,-#$')*$#2(9,$+,$!2*$()+-+,'&$&',-?'-*#$92*,$)?,,+,-$!2*$'BB&+%'!+(,0$N2*$Y(,* {
;&'-$+#$+-,()*/$6: lreleaseP$+!$%',$6*$?#*/$6:$!)',#&'!()#$!($+/*,!+;:$92+%2$!)',#&'!+(,#$')*$;+,+#2*/ Q_OBJECT
public:
',/$92+%2$(,*#$D?#!$6*$)*E+#+!*/0
Thread();
void setMessage(const QString &message);
G2*,$9*$D(/+;:$!2*$#(?)%*$%(/*$(;$!2*$'BB&+%'!+(,A$!2*$!)',#&'!+(,$;+&*#$D':$6*%(D*$(?!$(;$/'!*0 void stop();
N2*$#(&?!+(,$+#$!($)?, lupdate$'-'+,A$B)(E+/*$!)',#&'!+(,#$;()$!2*$,*9$#!)+,-#A$',/$)*-*,*)'!*$!2* .qm protected:
;+&*#0$[(D*$/*E*&(BD*,!$!*'D#$;+,/$+!$?#*;?&$!($)?, lupdate$;)*V?*,!&:A$92+&*$(!2*)#$B)*;*)$!($9'+! void run();
?,!+&$!2*$'BB&+%'!+(,$+#$'&D(#!$)*'/:$!($)*&*'#*0 private:
QString messageStr;
N2* lupdate$',/ !)*%'&+%$!$!((&#$')*$V?+!*$#D')!0$N)',#&'!+(,#$!2'!$')*$,($&(,-*)$?#*/$')*$F*B!$+, volatile bool stopped;
};
!2* .ts$;+&*#$+,$%'#*$!2*:$')*$,**/*/$+,$&'!*)$)*&*'#*#0$G2*,$?B/'!+,- .ts$;+&*#A lupdate$?#*#$',
+,!*&&+-*,!$D*)-+,-$'&-()+!2D$!2'!$%',$#'E*$!)',#&'!()#$%(,#+/*)'6&*$!+D*$9+!2$!*I!$!2'!$+#$!2*$#'D*
()$#+D+&')$+,$/+;;*)*,!$%(,!*I!#0
N2* Thread$%&'##$+,2*)+!#$;)(D QThread$',/$)*+DB&*D*,!#$!2* run()$;?,%!+(,0$>!$B)(E+/*#$!9(
H()$D()*$+,;()D'!+(,$'6(?! !)*%'&+%$!A lupdateA$',/ lreleaseA$)*;*)$!($!2* !)*%'&+%$!$D',?'&$'! '//+!+(,'&$;?,%!+(,#= setMessage()$',/ stop()0
2!!B=OO/(%0!)(&&!*%20%(DOQ03O&+,-?+#!5D',?'&02!D&0$N2*$D',?'&$%(,!'+,#$'$;?&&$*IB&','!+(,$(; !
*%'&+%$!"#$?#*)$+,!*);'%*$',/$'$#!*B56:5#!*B$!?!()+'&$;()$B)(-)'DD*)#0 N2* stopped$E')+'6&*$+#$/*%&')*/$E(&'!+&*$6*%'?#*$+!$+#$'%%*##*/$;)(D$/+;;*)*,!$!2)*'/#$',/$9*$9',!
!($6*$#?)*$!2'!$+!$+#$;)*#2&: )*'/$*E*):$!+D*$+!$+#$,**/*/0$>;$9*$(D+!!*/$!2* volatile$F*:9()/A$!2*
%(DB+&*)$D+-2!$(B!+D+h*$'%%*##$!($!2*$E')+'6&*A$B(##+6&:$&*'/+,-$!($+,%())*%!$)*#?&!#0
protected:
Thread::Thread() void closeEvent(QCloseEvent *event);
{ private slots:
stopped = false; void startOrStopThreadA();
} void startOrStopThreadB();
private:
Thread threadA;
Thread threadB;
G*$#*! stopped$!( false$+,$!2*$%(,#!)?%!()0 QPushButton *threadAButton;
QPushButton *threadBButton;
QPushButton *quitButton;
void Thread::run() };
{
while (!stopped)
cerr << qPrintable(messageStr);
stopped = false; N2* ThreadDialog$%&'##$/*%&')*#$!9($E')+'6&*#$(;$!:B* Thread$',/$#(D*$6?!!(,#$!($B)(E+/*$'$6'#+%
cerr << endl; ?#*)$+,!*);'%*0
}

ThreadDialog::ThreadDialog(QWidget *parent)
: QDialog(parent)
N2* run()$;?,%!+(,$+#$%'&&*/$!($#!')!$*I*%?!+,-$!2*$!2)*'/0$<#$&(,-$'#$!2* stopped$E')+'6&*$+# falseA
{
!2*$;?,%!+(,$F**B#$B)+,!+,-$!2*$-+E*,$D*##'-*$!($!2*$%(,#(&*0$N2*$!2)*'/$!*)D+,'!*#$92*,$%(,!)(& threadA.setMessage("A");
&*'E*#$!2* run()$;?,%!+(,0 threadB.setMessage("B");
threadAButton = new QPushButton(tr("Start A"));
threadBButton = new QPushButton(tr("Start B"));
void Thread::stop() quitButton = new QPushButton(tr("Quit"));
{ quitButton->setDefault(true);
stopped = true; connect(threadAButton, SIGNAL(clicked()),
} this, SLOT(startOrStopThreadA()));
connect(threadBButton, SIGNAL(clicked()),
this, SLOT(startOrStopThreadB()));
...
N2* stop()$;?,%!+(,$#*!#$!2* stopped$E')+'6&*$!( trueA$!2*)*6:$!*&&+,- run()$!($#!(B$B)+,!+,-$!*I!$!(
}
!2*$%(,#(&*0$N2+#$;?,%!+(,$%',$6*$%'&&*/$;)(D$',:$!2)*'/$'!$',:$!+D*0$H()$!2*$B?)B(#*#$(;$!2+#
*I'DB&*A$9*$'##?D*$!2'!$'##+-,D*,!$!($' bool$+#$',$'!(D+%$(B*)'!+(,0$N2+#$+#$'$)*'#(,'6&*
'##?DB!+(,A$%(,#+/*)+,-$!2'!$' bool$%',$(,&:$2'E*$!9($#!'!*#0$G*$9+&&$#**$&'!*)$+,$!2+#$#*%!+(,$2(9
!($?#* QMutex$!($-?')',!**$!2'!$'##+-,+,-$!($'$E')+'6&*$+#$',$'!(D+%$(B*)'!+(,0 >,$!2*$%(,#!)?%!()A$9*$%'&& setMessage()$!($D'F*$!2*$;+)#!$!2)*'/$)*B*'!*/&:$B)+,!$"<"#$',/$!2*$#*%(,/
!2)*'/$"X"#0
QThread$B)(E+/*#$' terminate()$;?,%!+(,$!2'!$!*)D+,'!*#$!2*$*I*%?!+(,$(;$'$!2)*'/$92+&*$+!$+#$#!+&&
)?,,+,-0$.#+,- terminate()$+#$,(!$)*%(DD*,/*/A$#+,%*$+!$%',$#!(B$!2*$!2)*'/$'!$',:$B(+,!$',/$/(*# void ThreadDialog::startOrStopThreadA()
,(!$-+E*$!2*$!2)*'/$',:$%2',%*$!($%&*',$?B$';!*)$+!#*&;0$>!$+#$'&9':#$#';*)$!($?#*$' stopped$E')+'6&* {
',/$' stop()$;?,%!+(,$'#$9*$/+/$2*)*0 if (threadA.isRunning()) {
threadA.stop();
!"#$%&'6)')&78%&78$%.+9&.::;!0.4!5- threadAButton->setText(tr("Start A"));
} else {
threadA.start();
threadAButton->setText(tr("Stop A"));
}
}

G2*,$!2*$?#*)$%&+%F#$!2*$6?!!(,$;()$!2)*'/$<A startOrStopThreadA()$#!(B#$!2*$!2)*'/$+;$+!$9'#
)?,,+,-$',/$#!')!#$+!$(!2*)9+#*0$>!$'&#($?B/'!*#$!2*$6?!!(,"#$!*I!0

G*$9+&&$,(9$#**$2(9$!($?#*$!2* THRead$%&'##$+,$'$#D'&&$ !$'BB&+%'!+(,$!2'!$?#*#$!9($!2)*'/#A$<$',/


XA$+,$'//+!+(,$!($!2*$D'+,$!2)*'/0 void ThreadDialog::startOrStopThreadB()
{
if (threadB.isRunning()) {
class ThreadDialog : public QDialog threadB.stop();
{ threadBButton->setText(tr("Start B"));
Q_OBJECT } else {
public: threadB.start();
ThreadDialog(QWidget *parent = 0); threadBButton->setText(tr("Stop B"));
}
} }
mutex.unlock();
cerr << qPrintable(messageStr);
}
N2*$%(/*$;() startOrStopThreadB()$+#$E*):$#+D+&')0 cerr << endl;
}

void ThreadDialog::closeEvent(QCloseEvent *event)


{
threadA.stop(); N2* stop()$;?,%!+(,$9(?&/$6*%(D*$!2+#=
threadB.stop();
threadA.wait();
threadB.wait(); void Thread::stop()
event->accept(); {
} mutex.lock();
stopped = true;
mutex.unlock();
}
>;$!2*$?#*)$%&+%F#$ ?+!$()$%&(#*#$!2*$9+,/(9A$9*$#!(B$',:$)?,,+,-$!2)*'/#$',/$9'+!$;()$!2*D$!($;+,+#2
K?#+,- QThread::wait()L$6*;()*$9*$%'&& QCloseEvent::accept()0$N2+#$*,#?)*#$!2'!$!2*$'BB&+%'!+(,$*I+!#
+,$'$%&*',$#!'!*A$'&!2(?-2$+!$/(*#,"!$)*'&&:$D'!!*)$+,$!2+#$*I'DB&*0
@(%F+,-$',/$?,&(%F+,-$'$D?!*I$+,$%(DB&*I$;?,%!+(,#A$()$;?,%!+(,#$!2'!$?#*$Rjj$*I%*B!+(,#A$%',$6*
>;$:(?$)?,$!2*$'BB&+%'!+(,$',/$%&+%F$[!')!$<A$!2*$%(,#(&*$9+&&$6*$;+&&*/$9+!2$"<"#0$>;$:(?$%&+%F$[!')!$XA$+! *))()5B)(,*0$ !$(;;*)#$!2* QMutexLocker$%(,E*,+*,%*$%&'##$!($#+DB&+;:$D?!*I$2',/&+,-0 QMutexLocker"#
9+&&$,(9$;+&&$9+!2$'&!*),'!+,-$#*V?*,%*#$(;$"<"#$',/$"X"#0$R&+%F$[!(B$<A$',/$,(9$+!$9+&&$(,&:$B)+,!$"X"#0 %(,#!)?%!()$'%%*B!#$' QMutex$'#$')-?D*,!$',/$&(%F#$+!0 QMutexLocker"#$/*#!)?%!()$?,&(%F#$!2*$D?!*I0
H()$*I'DB&*A$9*$%(?&/$)*9)+!*$!2*$B)*E+(?# run()$',/ stop()$;?,%!+(,#$'#$;(&&(9#=

void Thread::run()
{
forever {
Synchronizing Threads {
QMutexLocker locker(&mutex);
<$%(DD(,$)*V?+)*D*,!$;()$D?&!+!2)*'/*/$'BB&+%'!+(,#$+#$!2'!$(;$#:,%2)(,+h+,-$#*E*)'&$!2)*'/#0$ ! if (stopped) {
B)(E+/*#$!2*$;(&&(9+,-$#:,%2)(,+h'!+(,$%&'##*#= QMutexA QReadWriteLockA QSemaphoreA$',/ stopped = false;
QWaitCondition0 break;
}
}
N2* QMutex$%&'##$B)(E+/*#$'$D*',#$(;$B)(!*%!+,-$'$E')+'6&*$()$'$B+*%*$(;$%(/*$#($!2'!$(,&:$(,*$!2)*'/ cerr << qPrintable(messageStr);
%',$'%%*##$+!$'!$'$!+D*0$N2*$%&'##$B)(E+/*#$' lock()$;?,%!+(,$!2'!$&(%F#$!2*$D?!*I0$>;$!2*$D?!*I$+# }
?,&(%F*/A$!2*$%?))*,!$!2)*'/$#*+h*#$+!$+DD*/+'!*&:$',/$&(%F#$+!P$(!2*)9+#*A$!2*$%?))*,!$!2)*'/$+# cerr << endl;
6&(%F*/$?,!+&$!2*$!2)*'/$!2'!$2(&/#$!2*$D?!*I$?,&(%F#$+!0$1+!2*)$9':A$92*,$!2*$%'&&$!( lock()$)*!?),#A }
!2*$%?))*,!$!2)*'/$2(&/#$!2*$D?!*I$?,!+&$+!$%'&&# unlock()0$N2* QMutex$%&'##$'&#($B)(E+/*#$' tryLock() void Thread::stop()
;?,%!+(,$!2'!$)*!?),#$+DD*/+'!*&:$+;$!2*$D?!*I$+#$'&)*'/:$&(%F*/0 {
QMutexLocker locker(&mutex);
stopped = true;
H()$*I'DB&*A$&*!"#$#?BB(#*$!2'!$9*$9',!*/$!($B)(!*%!$!2* stopped$E')+'6&*$(;$!2* Thread$%&'##$;)(D
}
!2*$B)*E+(?#$#*%!+(,$9+!2$' QMutex0$G*$9(?&/$!2*,$'//$!2*$;(&&(9+,-$/'!'$D*D6*)$!( Thread=

private: \,*$+##?*$9+!2$?#+,-$D?!*I*#$+#$!2'!$(,&:$(,*$!2)*'/$%',$'%%*##$!2*$#'D*$E')+'6&*$'!$'$!+D*0$>,
... B)(-)'D#$9+!2$&(!#$(;$!2)*'/#$!):+,-$!($)*'/$!2*$#'D*$E')+'6&*$#+D?&!',*(?#&:$K9+!2(?!$D(/+;:$+!LA
QMutex mutex; !2*$D?!*I$%',$6*$'$#*)+(?#$B*);()D',%*$6(!!&*,*%F0$>,$!2*#*$%'#*#A$9*$%',$?#* QReadWriteLockA$'
}; #:,%2)(,+h'!+(,$%&'##$!2'!$'&&(9#$#+D?&!',*(?#$)*'/5(,&:$'%%*##$9+!2(?!$%(DB)(D+#+,-$B*);()D',%*0

>,$!2* THRead$%&'##A$+!$9(?&/$D'F*$,($#*,#*$!($)*B&'%* QMutex$9+!2 QReadWriteLock$!($B)(!*%!$!2*


N2* run()$;?,%!+(,$9(?&/$%2',-*$!($!2+#= stopped$E')+'6&*A$6*%'?#*$'!$D(#!$(,*$!2)*'/$D+-2!$!):$!($)*'/$!2*$E')+'6&*$'!$',:$-+E*,$!+D*0$<
D()*$'BB)(B)+'!*$*I'DB&*$9(?&/$+,E(&E*$(,*$()$D',:$)*'/*)$!2)*'/#$'%%*##+,-$#(D*$#2')*/$/'!'
',/$(,*$()$D',:$9)+!*)$!2)*'/#$D(/+;:+,-$!2*$/'!'0$H()$*I'DB&*=
void Thread::run()
{
forever { MyData data;
mutex.lock(); QReadWriteLock lock;
if (stopped) { void ReaderThread::run()
stopped = false; {
mutex.unlock(); ...
break; lock.lockForRead();
access_data_without_modifying_it(&data); )*'/#$!2*$/'!'$!(($;'#!A$+!$9+&&$B'##$!2*$B)(/?%*)$',/$)*'/$-')6'-*0
lock.unlock();
...
<$%)?/*$9':$!($#(&E*$!2+#$B)(6&*D$+#$!($2'E*$!2*$B)(/?%*)$;+&&$!2*$6?;;*)A$!2*,$9'+!$?,!+&$!2*
}
%(,#?D*)$2'#$)*'/$!2*$*,!+)*$6?;;*)A$',/$#($(,0$8(9*E*)A$(,$D?&!+B)(%*##()$D'%2+,*#A$!2+#$+#,"!$'#
void WriterThread::run()
{ ;'#!$'#$&*!!+,-$!2*$B)(/?%*)$',/$%(,#?D*)$!2)*'/#$(B*)'!*$(,$/+;;*)*,!$B')!#$(;$!2* 6?;;*)$'!$!2*
... #'D*$!+D*0
lock.lockForWrite();
modify_data(&data); \,*$9':$!($*;;+%+*,!&:$#(&E*$!2*$B)(6&*D$+,E(&E*#$!9($#*D'B2()*#=
lock.unlock();
...
} QSemaphore freeSpace(BufferSize);
QSemaphore usedSpace(0);

H()$%(,E*,+*,%*A$9*$%',$?#*$!2* QReadLocker$',/ QWriteLocker$%&'##*#$!($&(%F$',/$?,&(%F$'


QReadWriteLock0 N2* freeSpace$#*D'B2()*$-(E*),#$!2*$B')!$(;$!2*$6?;;*)$!2'!$!2*$B)(/?%*)$%',$;+&&$9+!2$/'!'0$N2*
usedSpace$#*D'B2()*$-(E*),#$!2*$')*'$!2'!$!2*$%(,#?D*)$%',$)*'/0$N2*#*$!9($')*'#$')*
QSemaphore$+#$',(!2*)$-*,*)'&+h'!+(,$(;$D?!*I*#A$6?!$?,&+F*$)*'/O9)+!*$&(%F#A$#*D'B2()*#$%',$6* %(DB&*D*,!'):0$N2* freeSpace$#*D'B2()*$+#$+,+!+'&+h*/$9+!2 BufferSize$KQ_b4LA$D*',+,-$!2'!$+!$2'#
?#*/$!($-?')/$'$%*)!'+,$,?D6*)$(;$+/*,!+%'&$)*#(?)%*#0$N2*$;(&&(9+,-$!9($%(/*$#,+BB*!#$#2(9$!2* !2'!$D',:$)*#(?)%*#$!2'!$%',$6*$'%V?+)*/0$G2*,$!2*$'BB&+%'!+(,$#!')!#A$!2*$)*'/*)$!2)*'/$9+&&$#!')!
%())*#B(,/*,%*$6*!9**, QSemaphore$',/ QMutex= '%V?+)+,-$`;)**`$6:!*#$',/$%(,E*)!$!2*D$+,!($`?#*/`$6:!*#0$N2* usedSpace$#*D'B2()*$+#$+,+!+'&+h*/
9+!2$_$!($*,#?)*$!2'!$!2*$%(,#?D*)$9(,"!$)*'/$-')6'-*$'!$#!')!?B0

QSemaphore semaphore(1); | QMutex mutex; H()$!2+#$*I'DB&*A$*'%2$6:!*$%(?,!#$'#$(,*$)*#(?)%*0$>,$'$)*'&59()&/$'BB&+%'!+(,A$9*$9(?&/$B)(6'6&:


semaphore.acquire(); | mutex.lock(); (B*)'!*$(,$&')-*)$?,+!#$K;()$*I'DB&*A$4Q$()$fa4$6:!*#$'!$'$!+D*L$!($)*/?%*$!2*$(E*)2*'/$'##(%+'!*/
semaphore.release(); | mutex.unlock(); 9+!2$?#+,-$#*D'B2()*#0

X:$B'##+,-$3$!($!2*$%(,#!)?%!()A$9*$!*&&$!2*$#*D'B2()*$!2'!$+!$%(,!)(&#$'$#+,-&*$)*#(?)%*0$N2* void Producer::run()


'/E',!'-*$(;$?#+,-$'$#*D'B2()*$+#$!2'!$9*$%',$B'##$,?D6*)#$(!2*)$!2',$3$!($!2*$%(,#!)?%!()$',/ {
!2*,$%'&& acquire()$D?&!+B&*$!+D*#$!($'%V?+)*$D',:$)*#(?)%*#0 for (int i = 0; i < DataSize; ++i) {
freeSpace.acquire();
buffer[i % BufferSize] = "ACGT"[uint(rand()) % 4];
<$!:B+%'&$'BB&+%'!+(,$(;$#*D'B2()*#$+#$92*,$!)',#;*))+,-$'$%*)!'+,$'D(?,!$(;$/'!'$K DataSizeL usedSpace.release();
6*!9**,$!9($!2)*'/#$?#+,-$'$#2')*/$%+)%?&')$6?;;*)$(;$'$%*)!'+,$#+h*$K BufferSizeL= }
}

const int DataSize = 100000;


const int BufferSize = 4096;
char buffer[BufferSize]; >,$!2*$B)(/?%*)A$*E*):$+!*)'!+(,$#!')!#$6:$'%V?+)+,-$(,*$`;)**`$6:!*0$>;$!2*$6?;;*)$+#$;?&&$(;$/'!'$!2'!
!2*$%(,#?D*)$2'#,"!$)*'/$:*!A$!2*$%'&&$!( acquire()$9+&&$6&(%F$?,!+&$!2*$%(,#?D*)$2'#$#!')!*/$!(
%(,#?D*$!2*$/'!'0$\,%*$9*$2'E*$'%V?+)*/$!2*$6:!*A$9*$;+&&$+!$9+!2$#(D*$)',/(D$/'!'$K"<"A$"R"A$"J"A$()
"N"L$',/$)*&*'#*$!2*$6:!*$'#$`?#*/`A$#($!2'!$+!$%',$6*$)*'/$6:$!2*$%(,#?D*)$!2)*'/0
N2*$B)(/?%*)$!2)*'/$9)+!*#$/'!'$!($!2*$6?;;*)$?,!+&$+!$)*'%2*#$!2*$*,/$',/$!2*,$)*#!')!#$;)(D$!2*
6*-+,,+,-A$(E*)9)+!+,-$*I+#!+,-$/'!'0$N2*$%(,#?D*)$!2)*'/$)*'/#$!2*$/'!'$'#$+!$+#$-*,*)'!*/0 H+-?)*
370f$+&&?#!)'!*#$!2+#A$'##?D+,-$'$!+,:$3456:!*$6?;;*)0 void Consumer::run()
{
!"#$%&'6)2)&78%&:$5+#0%$05-9#/%$&/5+%; for (int i = 0; i < DataSize; ++i) {
usedSpace.acquire();
cerr << buffer[i % BufferSize];
freeSpace.release();
}
cerr << endl;
}

>,$!2*$%(,#?D*)A$9*$#!')!$6:$'%V?+)+,-$(,*$`?#*/`$6:!*0$>;$!2*$6?;;*)$%(,!'+,#$,($/'!'$!($)*'/A$!2*
%'&&$!( acquire()$9+&&$6&(%F$?,!+&$!2*$B)(/?%*)$2'#$B)(/?%*/$#(D*0$\,%*$9*$2'E*$'%V?+)*/$!2*$6:!*A
9*$B)+,!$+!$',/$)*&*'#*$!2*$6:!*$'#$`;)**`A$D'F+,-$+!$B(##+6&*$;()$!2*$B)(/?%*)$!($;+&&$+!$9+!2$/'!'
'-'+,0

N2*$,**/$;()$#:,%2)(,+h'!+(,$+,$!2*$B)(/?%*)%(,#?D*)$*I'DB&*$+#$!9(;(&/=$>;$!2*$B)(/?%*) int main()


-*,*)'!*#$!2*$/'!'$!(($;'#!A$+!$9+&&$(E*)9)+!*$/'!'$!2'!$!2*$%(,#?D*)$2'#,"!$:*!$)*'/P$+;$!2*$%(,#?D*) {
Producer producer; ',/$9'F*$',:$!2)*'/$9'+!+,-$;()$!2*$`6?;;*) +#$,(!$*DB!:`$%(,/+!+(,$!($!?),$!)?*0
Consumer consumer;
producer.start();
G*$?#*$'$D?!*I$!($B)(!*%!$'&&$'%%*##*#$!($!2* usedSpace$E')+'6&*0$N2* QWaitCondition::wait()
consumer.start();
producer.wait(); ;?,%!+(,$%',$!'F*$'$&(%F*/$D?!*I$'#$+!#$;+)#!$')-?D*,!A$92+%2$+!$?,&(%F#$6*;()*$6&(%F+,-$!2*$%?))*,!
consumer.wait(); !2)*'/$',/$!2*,$&(%F#$6*;()*$)*!?),+,-0
return 0;
} H()$!2+#$*I'DB&*A$9*$%(?&/$2'E*$)*B&'%*/$!2* while$&((B

H+,'&&:A$+, main()A$9*$#!')!$!2*$B)(/?%*)$',/$%(,#?D*)$!2)*'/#0$G2'!$2'BB*,#$!2*,$+#$!2'!$!2* while (usedSpace == BufferSize)


bufferIsNotFull.wait(&mutex);
B)(/?%*)$%(,E*)!#$#(D*$`;)**`$#B'%*$+,!($`?#*/`$#B'%*A$',/$!2*$%(,#?D*)$%',$!2*,$%(,E*)!$+!$6'%F
!($`;)**`$#B'%*0

G2*,$9*$)?,$!2*$B)(-)'DA$+!$9)+!*#$'$)',/(D$#*V?*,%*$(;$3__A___$"<"#A$"R"#A$"J"#A$',/$"N"#$!($!2* 9+!2$!2+# if$#!'!*D*,!=


%(,#(&*$',/$!*)D+,'!*#0$N($)*'&&:$?,/*)#!',/$92'!$+#$-(+,-$(,A$9*$%',$/+#'6&*$9)+!+,-$!2*$(?!B?!
',/$+,#!*'/$9)+!*$"]"$*'%2$!+D*$!2*$B)(/?%*)$-*,*)'!*#$'$6:!*$',/$"%"$*'%2$!+D*$!2*$%(,#?D*)$)*'/#
'$6:!*0$<,/$!($D'F*$!2+,-#$'#$#+DB&*$!($;(&&(9$'#$B(##+6&*A$9*$%',$?#*$#D'&&*)$E'&?*#$;() DataSize if (usedSpace == BufferSize) {
mutex.unlock();
',/ BufferSize0
bufferIsNotFull.wait();
mutex.lock();
H()$*I'DB&*A$2*)*"#$'$B(##+6&*$)?,$9+!2$' DataSize$(;$3_$',/$' BufferSize$(;$Q= }
`]%]%]%]%]%]%]%]%]%]%`0$>,$!2+#$%'#*A$!2*$%(,#?D*)$)*'/#$!2*$6:!*#$'#$#((,$'#$!2*:$')*$-*,*)'!*/
6:$!2*$B)(/?%*)P$!2*$!9($!2)*'/#$')*$*I*%?!+,-$'!$!2*$#'D*$#B**/0$<,(!2*)$B(##+6+&+!:$+#$!2'!$!2*
B)(/?%*)$;+&&#$!2*$92(&*$6?;;*)$6*;()*$!2*$%(,#?D*)$*E*,$#!')!#$)*'/+,-$+!=$`]]]]%%%%]]]]%%%%]]%%`0
8(9*E*)A$!2+#$9(?&/$6)*'F$'#$#((,$'#$9*$'&&(9$D()*$!2',$(,*$B)(/?%*)$!2)*'/A$#+,%*$',(!2*)
N2*)*$')*$D',:$(!2*)$B(##+6+&+!+*#0$[*D'B2()*#$-+E*$'$&(!$(;$&'!+!?/*$!($!2*$#:#!*D5#B*%+;+%$!2)*'/
B)(/?%*)$%(?&/$#*+h*$!2*$D?!*I$+DD*/+'!*&:$';!*)$!2* wait()$%'&&$',/$D'F*$!2*$`6?;;*)$+#$,(!$;?&&`
#%2*/?&*)A$92+%2$%',$#!?/:$!2*$!2)*'/#"$6*2'E+()$',/$%2((#*$',$'BB)(B)+'!*$#%2*/?&+,-$B(&+%:0
%(,/+!+(,$;'&#*$'-'+,0
<$/+;;*)*,!$'BB)('%2$!($!2*$B)(6&*D$(;$#:,%2)(,+h+,-$'$B)(/?%*)$',/$'$%(,#?D*)$+#$!($?#*
QWaitCondition$',/ QMutex0$< QWaitCondition$'&&(9#$'$!2)*'/$!($9'F*$?B$(!2*)$!2)*'/#$92*,$#(D* void Consumer::run()
%(,/+!+(,$2'#$6**,$D*!0$N2+#$'&&(9#$;()$D()*$B)*%+#*$%(,!)(&$!2',$+#$B(##+6&*$9+!2$D?!*I*#$'&(,*0$N( {
#2(9$2(9$+!$9()F#A$9*$9+&&$)*/($!2*$B)(/?%*)%(,#?D*)$*I'DB&*$?#+,-$9'+!$%(,/+!+(,#0 for (int i = 0; i < DataSize; ++i) {
mutex.lock();
while (usedSpace == 0)
const int DataSize = 100000; bufferIsNotEmpty.wait(&mutex);
const int BufferSize = 4096; cerr << buffer[i % BufferSize];
char buffer[BufferSize]; --usedSpace;
QWaitCondition bufferIsNotFull; bufferIsNotFull.wakeAll();
QWaitCondition bufferIsNotEmpty; mutex.unlock();
QMutex mutex; }
int usedSpace = 0; cerr << endl;
}

>,$'//+!+(,$!($!2*$6?;;*)A$9*$/*%&')*$!9( QWaitCondition#A$(,* QMutexA$',/$(,*$E')+'6&*$!2'!$#!()*#


2(9$D',:$6:!*#$+,$!2*$6?;;*)$')*$`?#*/`$6:!*#0 N2*$%(,#?D*)$/(*#$!2*$*I'%!$(BB(#+!*$(;$!2*$B)(/?%*)=$>!$9'+!#$;()$!2*$`6?;;*)$+#$,(!$*DB!:`
%(,/+!+(,$',/$9'F*#$?B$',:$!2)*'/$9'+!+,-$;()$!2*$`6?;;*)$+#$,(!$;?&&`$%(,/+!+(,0

void Producer::run() >,$'&&$!2*$*I'DB&*#$#($;')A$(?)$!2)*'/#$2'E*$'%%*##*/$!2*$#'D* -&(6'&$E')+'6&*#0$X?!$#(D*$!2)*'/*/


{ 'BB&+%'!+(,#$,**/$!($2'E*$'$-&(6'&$E')+'6&*$2(&/$/+;;*)*,!$E'&?*#$+,$/+;;*)*,!$!2)*'/#0$N2+#$+#$(;!*,
for (int i = 0; i < DataSize; ++i) { %'&&*/$!2)*'/5&(%'&$#!()'-*$()$!2)*'/5#B*%+;+%$/'!'0$G*$%',$;'F*$+!$?#+,-$'$D'B$F*:*/$(,$!2)*'/$>Y#
mutex.lock(); K)*!?),*/$6: QThread::currentThread()LA$6?!$'$,+%*)$'BB)('%2$+#$!($?#*$!2* QTHReadStorage<T>$%&'##0
while (usedSpace == BufferSize)
bufferIsNotFull.wait(&mutex);
buffer[i % BufferSize] = "ACGT"[uint(rand()) % 4]; <$%(DD(,$?#*$(; QThreadStorage<T>$+#$;()$%'%2*#0$X:$2'E+,-$'$#*B')'!*$%'%2*$+,$/+;;*)*,!$!2)*'/#A
++usedSpace; 9*$'E(+/$!2*$(E*)2*'/$(;$&(%F+,-A$?,&(%F+,-A$',/$B(##+6&:$9'+!+,-$;()$'$D?!*I0$H()$*I'DB&*=
bufferIsNotEmpty.wakeAll();
mutex.unlock();
} QThreadStorage<QHash<int, double> *> cache;
} void insertIntoCache(int id, double value)
{
if (!cache.hasLocalData())
cache.setLocalData(new QHash<int, double>);
>,$!2*$B)(/?%*)A$9*$#!')!$6:$%2*%F+,-$92*!2*)$!2*$6?;;*)$+#$;?&&0$>;$+!$+#A$9*$9'+!$(,$!2*$`6?;;*)$+#$,(! cache.localData()->insert(id, value);
;?&&`$%(,/+!+(,0$G2*,$!2'!$%(,/+!+(,$+#$D*!A$9*$9)+!*$(,*$6:!*$!($!2*$6?;;*)A$+,%)*D*,! usedSpaceA }
void removeFromCache(int id)
{
if (cache.hasLocalData())
cache.localData()->remove(id);
}

N2* cache$E')+'6&*$2(&/#$(,*$B(+,!*)$!($' QMap<int, double>$B*)$!2)*'/0$KX*%'?#*$(;$B)(6&*D#$9+!2


#(D*$%(DB+&*)#A$!2*$!*DB&'!*$!:B*$+, QThreadStorage<T>$D?#!$6*$'$B(+,!*)$!:B*0L$N2*$;+)#!$!+D*$9*
?#*$!2*$%'%2*$+,$'$B')!+%?&')$!2)*'/A hasLocalData()$)*!?),# false$',/$9*$%)*'!*$!2* QHash<int,
double>$(6C*%!0

>,$'//+!+(,$!($%'%2+,-A QTHReadStorage<T>$%',$6*$?#*/$;()$-&(6'&$*))()5#!'!*$E')+'6&*#$K#+D+&')$!(
errnoL$!($*,#?)*$!2'!$D(/+;+%'!+(,#$+,$(,*$!2)*'/$/(,"!$';;*%!$(!2*)$!2)*'/#0

Communicating with the Main Thread


G2*,$'$ !$'BB&+%'!+(,$#!')!#A$(,&:$(,*$!2)*'/$+#$)?,,+,-!2*$D'+,$!2)*'/0$N2+#$+#$!2*$(,&:$!2)*'/$!2'!
+#$'&&(9*/$!($%)*'!*$!2* QApplication$() QCoreApplication$(6C*%!$',/$%'&& exec()$(,$+!0$<;!*)$!2*$%'&&
!( exec()A$!2+#$!2)*'/$+#$*+!2*)$9'+!+,-$;()$',$*E*,!$()$B)(%*##+,-$',$*E*,!0

N2*$D'+,$!2)*'/$%',$#!')!$,*9$!2)*'/#$6:$%)*'!+,-$(6C*%!#$(;$' QThread$#?6%&'##A$'#$9*$/+/$+,$!2*
B)*E+(?#$#*%!+(,0$>;$!2*#*$,*9$!2)*'/#$,**/$!($%(DD?,+%'!*$'D(,-$!2*D#*&E*#A$!2*:$%',$?#*
#2')*/$E')+'6&*#$!(-*!2*)$9+!2$D?!*I*#A$)*'/O9)+!*$&(%F#A$#*D'B2()*#A$()$9'+!$%(,/+!+(,#0$X?!$,(,*
(;$!2*#*$!*%2,+V?*#$%',$6*$?#*/$!($%(DD?,+%'!*$9+!2$!2*$D'+,$!2)*'/A$#+,%*$!2*:$9(?&/$&(%F$!2*
*E*,!$&((B$',/$;)**h*$!2*$?#*)$+,!*);'%*0 N($+&&?#!)'!*$2(9$#+-,'&#&(!$%(,,*%!+(,#$'%)(##$!2)*'/#$9()FA$9*$9+&&$)*E+*9$!2*$%(/*$(;$!2*$>D'-*
])($'BB&+%'!+(,A'$6'#+%$+D'-*$B)(%*##+,-$'BB&+%'!+(,$!2'!$'&&(9#$!2*$?#*)$!($)(!'!*A$)*#+h*A$',/
N2*$#(&?!+(,$;()$%(DD?,+%'!+,-$;)(D$'$#*%(,/'):$!2)*'/$!($!2*$D'+,$!2)*'/$+#$!($?#*$#+-,'&#&(! %2',-*$!2*$%(&()$/*B!2$(;$',$+D'-*0$N2*$'BB&+%'!+(,$?#*#$(,*$#*%(,/'):$!2)*'/$!($B*);()D
%(,,*%!+(,#$'%)(##$!2)*'/#0$g()D'&&:A$!2*$#+-,'&#$',/$#&(!#$D*%2',+#D$(B*)'!*#$#:,%2)(,(?#&:A (B*)'!+(,#$(,$+D'-*#$9+!2(?!$&(%F+,-$!2*$*E*,!$&((B0$N2+#$D'F*#$'$#+-,+;+%',!$/+;;*)*,%*$92*,
D*',+,-$!2'!$!2*$#&(!#$%(,,*%!*/$!($'$#+-,'&$')*$+,E(F*/$+DD*/+'!*&:$92*,$!2*$#+-,'&$+#$*D+!!*/A B)(%*##+,-$E*):$&')-*$+D'-*#0$N2*$#*%(,/'):$!2)*'/$2'#$'$&+#!$(;$!'#F#A$()$`!)',#'%!+(,#`A$!(
?#+,-$'$/+)*%!$;?,%!+(,$%'&&0 '%%(DB&+#2$',/$#*,/#$*E*,!#$!($!2*$D'+,$9+,/(9$!($)*B()!$B)(-)*##0

8(9*E*)A$92*,$9*$%(,,*%!$(6C*%!#$!2'!$`&+E*`$+,$/+;;*)*,!$!2)*'/#A$!2*$D*%2',+#D$6*%(D*#
ImageWindow::ImageWindow()
'#:,%2)(,(?#0$KN2+#$6*2'E+()$%',$6*$%2',-*/$!2)(?-2$',$(B!+(,'&$;+;!2$B')'D*!*)$!(
{
QObject::connect()0L$X*2+,/$!2*$#%*,*#A$!2*#*$%(,,*%!+(,#$')*$+DB&*D*,!*/$6:$B(#!+,-$',$*E*,!0 imageLabel = new QLabel;
N2*$#&(!$+#$!2*,$%'&&*/$6:$!2*$*E*,!$&((B$(;$!2*$!2)*'/$+,$92+%2$!2*$)*%*+E*)$(6C*%!$*I+#!#0$X:$/*;'?&!A imageLabel->setBackgroundRole(QPalette::Dark);
' QObject$*I+#!#$+,$!2*$!2)*'/$+,$92+%2$+!$9'#$%)*'!*/P$!2+#$%',$6*$%2',-*/$'!$',:$!+D*$6:$%'&&+,- imageLabel->setAutoFillBackground(true);
QObject::moveToThread()0 imageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
setCentralWidget(imageLabel);
createActions();
!"#$%&'6)3)&78%&</."%&=$5&.::;!0.4!5-
createMenus();
statusBar()->showMessage(tr("Ready"), 2000);
connect(&thread, SIGNAL(transactionStarted(const QString &)),
statusBar(), SLOT(showMessage(const QString &)));
connect(&thread, SIGNAL(finished()),
this, SLOT(allTransactionsDone()));
setCurrentFile("");
}

N2*$+,!*)*#!+,-$B')!$(;$!2* ImageWindow$%(,#!)?%!()$+#$!2*$!9($#+-,'&#&(!$%(,,*%!+(,#0$X(!2$(;$!2*D
+,E(&E*$#+-,'&#$*D+!!*/$6:$!2* transactionThread$(6C*%!A$92+%2$9*$9+&&$%(E*)$+,$'$D(D*,!0

void ImageWindow::flipHorizontally()
{
addTransaction(new FlipTransaction(Qt::Horizontal));
} QMutexLocker locker(&mutex);
transactions.enqueue(transact);
if (!isRunning())
start();
N2* flipHorizontally()$#&(!$%)*'!*#$'$`;&+B`$!)',#'%!+(,$',/$)*-+#!*)#$+!$?#+,-$!2*$B)+E'!*$;?,%!+(, }
addTransaction()0$N2* flipVertically()A resizeImage()A convertTo32Bit()A convertTo8Bit()A$',/
convertTo1Bit()$;?,%!+(,#$')*$#+D+&')0

N2* addTransaction()$;?,%!+(,$'//#$'$!)',#'%!+(,$!($!2*$!)',#'%!+(,$V?*?*$',/$#!')!#$!2*$!)',#'%!+(,
void ImageWindow::addTransaction(Transaction *transact) !2)*'/$+;$+!$+#,"!$'&)*'/:$)?,,+,-0$<&&$'%%*##*#$!($!2* TRansactions$D*D6*)$E')+'6&*$')*$B)(!*%!*/$6:
{ '$D?!*IA$6*%'?#*$!2*$D'+,$!2)*'/$D+-2!$D(/+;:$!2*D$!2)(?-2 addTransaction()$'!$!2*$#'D*$!+D*
thread.addTransaction(transact); '#$!2*$#*%(,/'):$!2)*'/$+#$+!*)'!+,-$(E*) transactions0
openAction->setEnabled(false);
saveAction->setEnabled(false);
saveAsAction->setEnabled(false); void TransactionThread::setImage(const QImage &image)
} {
QMutexLocker locker(&mutex);
currentImage = image;
}
N2* addTransaction()$;?,%!+(,$'//#$'$!)',#'%!+(,$!($!2*$#*%(,/'):$!2)*'/"#$!)',#'%!+(,$V?*?*$',/
QImage TransactionThread::image()
/+#'6&*#$!2*$\B*,A$['E*A$',/$['E*$<#$'%!+(,#$92+&*$!)',#'%!+(,#$')*$6*+,-$B)(%*##*/0 {
QMutexLocker locker(&mutex);
return currentImage;
void ImageWindow::allTransactionsDone() }
{
openAction->setEnabled(true);
saveAction->setEnabled(true);
saveAsAction->setEnabled(true); N2* setImage()$',/ image()$;?,%!+(,#$&*!$!2*$D'+,$!2)*'/$#*!$!2*$+D'-*$(,$92+%2$!($B*);()D$!2*
imageLabel->setPixmap(QPixmap::fromImage(thread.image())); !)',#'%!+(,#$',/$)*!)+*E*$!2*$)*#?&!+,-$+D'-*$(,%*$'&&$!)',#'%!+(,#$')*$/(,*0$<-'+,A$9*$B)(!*%!
setWindowModified(true); '%%*##*#$!($'$D*D6*)$E')+'6&*$?#+,-$'$D?!*I0
statusBar()->showMessage(tr("Ready"), 2000);
}
void TransactionThread::run()
{
N2* allTransactionsDone()$#&(!$+#$%'&&*/$92*,$!2* transactionThread"#$!)',#'%!+(,$V?*?*$6*%(D*# Transaction *transact;
forever {
*DB!:0
mutex.lock();
if (transactions.isEmpty()) {
g(9A$&*!"#$!?),$!($!2* TRansactionThread$%&'##= mutex.unlock();
break;
}
class TransactionThread : public QThread QImage oldImage = currentImage;
{ transact = transactions.dequeue();
Q_OBJECT mutex.unlock();
public: emit transactionStarted(transact->message());
void addTransaction(Transaction *transact); QImage newImage = transact->apply(oldImage);
void setImage(const QImage &image); delete transact;
QImage image(); mutex.lock();
signals: currentImage = newImage;
void transactionStarted(const QString &message); mutex.unlock();
protected: }
void run(); }
private:
QMutex mutex;
QImage currentImage;
N2* run()$;?,%!+(,$-(*#$!2)(?-2$!2*$!)',#'%!+(,$V?*?*$',/$*I*%?!*#$*'%2$!)',#'%!+(,$+,$!?),$6:
QQueue<Transaction *> transactions;
}; %'&&+,- apply()$(,$!2*D0

G2*,$'$!)',#'%!+(,$+#$#!')!*/A$9*$*D+!$!2* transactionStarted()$#+-,'&$9+!2$'$D*##'-*$!($/+#B&':$+,
N2* transactionThread$%&'##$D'+,!'+,#$'$&+#!$(;$!)',#'%!+(,#$!($B)(%*##$',/$*I*%?!*#$!2*D$(,*$';!*) !2*$'BB&+%'!+(,"#$#!'!?#$6')0$G2*,$'&&$!2*$!)',#'%!+(,#$2'E*$;+,+#2*/$B)(%*##+,-A$!2* run()$;?,%!+(,
!2*$(!2*)$+,$!2*$6'%F-)(?,/0 )*!?),#$',/ QThread$*D+!#$!2* finished()$#+-,'&0

void TransactionThread::addTransaction(Transaction *transact) class Transaction


{ {
public:
virtual ~Transaction() { } *E*,$92*,$(B*)'!+,-$(,$!2*$#'D*$(6C*%!0
virtual QImage apply(const QImage &image) = 0;
virtual QString message() = 0;
!"#$!2)*'/5#';*$%&'##*#$')* QMutexA QMutexLockerA QReadWriteLockA QReadLockerA QWriteLockerA
};
QSemaphoreA QThreadStorage<T>A QWaitConditionA$',/$B')!#$(;$!2* QThread$<]>0$>,$'//+!+(,A$#*E*)'&
;?,%!+(,#$')*$!2)*'/5#';*A$+,%&?/+,- QObject::connect()A QObject::disconnect()A
QCoreApplication::postEvent()A QCoreApplication::removePostedEvent()A$',/
N2* transaction$%&'##$+#$',$'6#!)'%!$6'#*$%&'##$;()$(B*)'!+(,#$!2'!$!2*$?#*)$%',$B*);()D$(,$', QCoreApplication::removePostedEvents()0
+D'-*0$N2*$E+)!?'&$/*#!)?%!()$+#$,*%*##'):$6*%'?#*$9*$,**/$!($/*&*!*$+,#!',%*#$(; TRansaction
#?6%&'##*#$!2)(?-2$' transaction$B(+,!*)0$K<&#(A$+;$9*$(D+!$+!A$#(D*$%(DB+&*)#$*D+!$'$9'),+,-0L
Z(#!$(;$ !"#$,(,5J.>$%&'##*#$D**!$'$&*##$#!)+,-*,!$)*V?+)*D*,!=$N2*:$')* (##'!(-'!0$<$%&'##$+#
TRansaction$2'#$!2)**$%(,%)*!*$#?6%&'##*#= FlipTransactionA ResizeTransactionA$',/ )**,!)',!$+;$/+;;*)*,!$+,#!',%*#$(;$!2*$%&'##$%',$6*$?#*/$#+D?&!',*(?#&:$+,$/+;;*)*,!$!2)*'/#0
ConvertDepthTransaction0$G*$9+&&$(,&:$)*E+*9 FlipTransactionP$!2*$(!2*)$!9($%&'##*#$')*$#+D+&')0 8(9*E*)A$'%%*##+,-$!2*$#'D*$)**,!)',!$(6C*%!$+,$D?&!+B&*$!2)*'/#$#+D?&!',*(?#&:$+#$,(!$#';*A$',/
#?%2$'%%*##*#$#2(?&/$6*$B)(!*%!*/$9+!2$'$D?!*I0$c**,!)',!$%&'##*#$')*$D')F*/$'#$#?%2$+,$!2*$ !
)*;*)*,%*$/(%?D*,!'!+(,0$N:B+%'&&:A$',:$Rjj$%&'##$!2'!$/(*#,"!$)*;*)*,%*$-&(6'&$()$(!2*)9+#*$#2')*/
class FlipTransaction : public Transaction /'!'$+#$)**,!)',!0
{
public:
FlipTransaction(Qt::Orientation orientation); QObject$+#$)**,!)',!A$6?!$!2*)*$')*$!2)**$%(,#!)'+,!#$!($F**B$+,$D+,/=
QImage apply(const QImage &image);
QString message(); • >8!;+&?@AB%049&/#94&A%&0$%.4%+&!-&48%!$&:.$%-4C9&48$%.+)
private:
Qt::Orientation orientation; >,$B')!+%?&')A$!2+#$D*',#$!2'!$!2*$(6C*%!#$%)*'!*/$+,$'$#*%(,/'):$!2)*'/$D?#!$,*E*)$6*
}; %)*'!*/$9+!2$!2* QThread$(6C*%!$'#$!2*+)$B')*,!A$6*%'?#*$!2'!$(6C*%!$9'#$%)*'!*/$+,$',(!2*)
!2)*'/$K*+!2*)$!2*$D'+,$!2)*'/$()$'$/+;;*)*,!$#*%(,/'):$!2)*'/L0

N2* FlipTransaction$%(,#!)?%!()$!'F*#$(,*$B')'D*!*)$!2'!$#B*%+;+*#$!2*$()+*,!'!+(,$(;$!2*$;&+B • D%&/#94&+%;%4%&.;;&?@AB%049&0$%.4%+&!-&.&9%05-+.$,&48$%.+&A%E5$%&+%;%4!-"&48%


K2()+h(,!'&$()$E*)!+%'&L0 05$$%9:5-+!-"&?78$%.+&5AB%04)

!"#$%&'$()$*+')$(,$%-)&."'/$.!)$+(0)%.#$+'$.!)$#.&%1$"' QTHRead::run()2
QImage FlipTransaction::apply(const QImage &image)
{
return image.mirrored(orientation == Qt::Horizontal, • !"#$%&'()*'&("$(+$,$&$+(-.(&/$(&/0$1+(&/1&(%0$1&$+(&/$)2
orientation == Qt::Vertical);
} 34$5)$'))*$.+$*)6).)$& QObject$.!&.$)7"#.#$"'$&$*"44)-)'.$.!-)&*8$5)$9:#.$%&66$.!)$.!-)&*;#&4)
QObject::deleteLater()$4:'%."+'$"'#.)&*8$5!"%!$<+#.#$&$=*)4)--)*$*)6).)=$)>)'.2

N2* apply()$;?,%!+(,$%'&&# QImage::mirrored()$(,$!2* QImage$+!$)*%*+E*#$'#$B')'D*!*)$',/$)*!?),#$!2* ?+';@A3 QObject$#:(%6&##)#$#:%!$&# QTimer8 QProcess8$&'*$.!)$').5+-1$%6&##)#$&-)$-))'.-&'.2$B)


)*#?&!+,- QImage0 %&'$:#)$.!)9$"'$&',$.!-)&*8$&#$6+'/$&#$.!)$.!-)&*$!&#$&'$)>)'.$6++<2$C+-$#)%+'*&-,$.!-)&*#8$.!)
)>)'.$6++<$"#$#.&-.)*$(,$%&66"'/ QTHRead::exec()$+-$(,$%+'>)'")'%)$4:'%."+'#$#:%!$&#
QProcess::waitForFinished()$&'* QAbstractSocket::waitForDisconnected()2
QString FlipTransaction::message()
{ D)%&:#)$+4$6"9".&."+'#$"'!)-".)*$4-+9$.!)$6+5;6)>)6$6"(-&-")#$+'$5!"%!$E.F#$@A3$#:<<+-.$"#$(:"6.8
if (orientation == Qt::Horizontal) { QWidget$&'*$".#$#:(%6&##)#$&-)$'+.$-))'.-&'.2$G')$%+'#)H:)'%)$+4$.!"#$"#$.!&.$5)$%&''+.$*"-)%.6,$%&66
return QObject::tr("Flipping image horizontally...");
4:'%."+'#$+'$&$5"*/).$4-+9$&$#)%+'*&-,$.!-)&*2 34$5)$5&'.$.+8$#&,8$%!&'/)$.!)$.)7.$+4$& QLabel$4-+9
} else {
return QObject::tr("Flipping image vertically..."); &$#)%+'*&-,$.!-)&*8$5)$%&'$)9".$&$#"/'&6$%+'')%.)*$.+ QLabel::setText()$+-$%&66
} QMetaObject::invokeMethod()$4-+9$.!&.$.!-)&*2$C+-$)7&9<6)I
}

void MyThread::run()
{
N2* message()$;?,%!+(,$)*!?),#$!2*$D*##'-*$!($/+#B&':$+,$!2*$#!'!?#$6')$92+&*$!2*$(B*)'!+(,$+#$+, ...
B)(-)*##0$N2+#$;?,%!+(,$+#$%'&&*/$+, transactionThread::run()$92*,$*D+!!+,-$!2* QMetaObject::invokeMethod(label, SLOT(setText(const QString &)),
transactionStarted()$#+-,'&0 Q_ARG(QString, "Hello"));
...
}

Using Qt's Classes in Secondary Threads


J&',$+4$E.F#$'+';@A3$%6&##)#8$"'%6:*"'/ QImage8 QString8$&'*$.!)$%+'.&"')-$%6&##)#8:#)$"9<6"%".
<$;?,%!+(,$+#$#'+/$!($6* !,(#-./$-0#$92*,$+!$%',$#';*&:$6*$%'&&*/$;)(D$/+;;*)*,!$!2)*'/# #!&-"'/$&#$&'$+<."9"K&."+'$.)%!'"H:)2$B!"6)$.!"#$+<."9"K&."+'$:#:&66,$9&1)#$&$%6&##$'+';-))'.-&'.8$"'
#+D?&!',*(?#&:0$>;$!9($!2)*'/5#';*$;?,%!+(,#$')*$%'&&*/$;)(D$/+;;*)*,!$!2)*'/#$(,$!2*$#'D*$#2')*/ E.$.!"#$"#$'+.$&'$"##:)$()%&:#)$E.$:#)#$&.+9"%$&##)9(6,$6&'/:&/)$"'#.-:%."+'#$.+$"9<6)9)'.$.!-)&*;
/'!'A$!2*$)*#?&!$+#$'&9':#$/*;+,*/0$X:$*I!*,#+(,A$'$%&'##$+#$#'+/$!($6*$!2)*'/5#';*$92*,$'&&$(;$+!# #&4)$-)4)-)'%)$%+:'."'/8$9&1"'/$E.F#$"9<6"%".6,$#!&-)*$%6&##)#$-))'.-&'.2
;?,%!+(,#$%',$6*$%'&&*/$;)(D$/+;;*)*,!$!2)*'/#$#+D?&!',*(?#&:$9+!2(?!$+,!*);*)+,-$9+!2$*'%2$(!2*)A
E.F# !"#$$9+*:6)$%&'$&6#+$()$:#)*$"' 9:6.".!-)&*)*$&<<6"%&."+'#8$(:.$".$!&#$".#$+5'$-)#.-"%."+'#8
5!"%!$>&-,$4-+9$*&.&(&#)$.+$*&.&(&#)2$C+-$*).&"6#8$#)) !..<ILL*+%2.-+66.)%!2%+9LM2NL#H6;*-">)-2!.962
C+-$&$%+9<6).)$6"#.$+4$9:6.";.!-)&*"'/$%&>)&.#8$#)) !..<ILL*+%2.-+66.)%!2%+9LM2NL.!-)&*#2!.962 Chapter 19. Creating Plugins
• !"#$%&$'()"(*&"+(,-.'&$/
• 012&$'(344-&51"&6$/(,-.'&$73*18#
• 98&"&$'(344-&51"&6$(,-.'&$/

O,'&9"%$6"(-&-")#$P&6#+$%&66)*$#!&-)*$6"(-&-")#$+-$OQQ#R$&-)$"'*)<)'*)'.$9+*:6)#$.!&.$&-)$#.+-)*$"'$&
#)<&-&.)$4"6)$+'$*"#1$&'*$%&'$()$&%%)##)*$(,$9:6."<6)$&<<6"%&."+'#2$S-+/-&9#$:#:&66,$#<)%"4,$5!"%!
*,'&9"%$6"(-&-")#$.!),$'))*$&.$6"'1$."9)8$"' 5!"%!$%&#)$.!)$6"(-&-")#$&-)$&:.+9&."%&66,$6+&*)*$5!)'
.!)$&<<6"%&."+'$#.&-.#2$ !"#$&<<-+&%!$:#:&66,$"'>+6>)#$&**"'/$.!)$6"(-&-,$&'*$<+##"(6,$".#$"'%6:*)$<&.!
.+$.!)$&<<6"%&."+'F# .pro$4"6)$&'*$"'%6:*"'/$.!)$-)6)>&'.$!)&*)-#$"'$.!)$#+:-%)$4"6)#2$C+-$)7&9<6)I

LIBS += -ldb_cxx
INCLUDEPATH += /usr/local/BerkeleyDB.4.2/include

!)$&6.)-'&.">)$"#$.+$*,'&9"%&66,$6+&*$.!)$6"(-&-,$5!)'$".$"#$-)H:"-)*8$&'*$.!)'$-)#+6>)$.!)$#,9(+6#
.!&.$5)$5&'.$.+$:#)$4-+9$".2$E.$<-+>"*)#$.!) QLibrary$%6&##$.+$&%!")>)$.!"#$"'$&$<6&.4+-9;"'*)<)'*)'.
9&'')-2$@">)'$.!)$#.)9$+4$&$6"(-&-,F#$'&9)8 QLibrary$#)&-%!)#$.!)$<6&.4+-9F#$#.&'*&-*$6+%&."+'#$4+-
.!)$6"(-&-,$6++1"'/$4+-$&'$&<<-+<-"&.)$4"6)2$C+-$)7&9<6)8$/">)'$.!)$'&9) mimetype8$".$5"66$6++1$4+-
mimetype.dll$+'$B"'*+5#8 mimetype.so$+'$Q"':78$&'* mimetype.dylib$+'$J&%$GT$U2

J+*)-'$@A3$&<<6"%&."+'#$%&'$+4.)'$()$)7.)'*)*$(,$.!)$:#)$+4$<6:/"'#2$V$<6:/"'$"#$&$*,'&9"%$6"(-&-,
.!&.$"9<6)9)'.#$&$<&-."%:6&-$"'.)-4&%)$.+$<-+>"*)$+<."+'&6$)7.-&$4:'%."+'&6".,2$C+-$)7&9<6)8$"'
W!&<.)-$X8$5)$%-)&.)*$&$<6:/"'$.+$"'.)/-&.)$&$%:#.+9$5"*/).$5".! !%&'()*+',$P<2$NNYR2

E.$-)%+/'"K)#$".#$+5'$#).$+4$<6:/"'$"'.)-4&%)#$4+-$>&-"+:#$*+9&"'#8$"'%6:*"'/$"9&/)$4+-9&.#8
*&.&(&#)$*-">)-#8$5"*/).$#.,6)#8$.)7.$)'%+*"'/#8$&'*$&%%)##"("6".,2$ !"#$%!&<.)-F#$4"-#.$#)%."+'
)7<6&"'#$!+5$.+$)7.)'*$E.$5".!$&$E.$<6:/"'2

3.$"#$&6#+$<+##"(6)$.+$%-)&.)$&<<6"%&."+';#<)%"4"%$<6:/"'#$4+-$<&-."%:6&-$E.$&<<6"%&."+'#2$E.$9&1)#
5-"."'/$#:%!$<6:/"'#$)&#,$.!-+:/!$".#$<6:/"'$4-&9)5+-18$5!"%!$&**#$%-&#!$#&4).,$&'*$%+'>)'")'%)$.+
QLibrary2$3'$.!)$6&#.$.5+$#)%."+'#$+4$.!"#$%!&<.)-8$5)$#!+5$!+5$.+$9&1)$&'$&<<6"%&."+'$#:<<+-.
<6:/"'#$&'*$!+5$.+$%-)&.)$&$%:#.+9$<6:/"'$4+-$&'$&<<6"%&."+'2

Extending Qt with Plugins


E.$%&'$()$)7.)'*)*$5".!$&$>&-").,$+4$<6:/"'$.,<)#8$.!)$9+#.$%+99+'$()"'/$*&.&(&#)$*-">)-#8$"9&/)
4+-9&.#8$#.,6)#8$&'*$.)7.$%+*)%#2$C+-$)&%!$.,<)$+4$<6:/"'8$5)$'+-9&66,$'))*$&.$6)&#.$.5+$%6&##)#I$&
<6:/"'$5-&<<)-$%6&##$.!&.$"9<6)9)'.#$.!)$/)')-"%$<6:/"'$VS3$4:'%."+'#8$&'*$+')$+-$9+-)$!&'*6)-
%6&##)#$.!&.$)&%!$"9<6)9)'.$.!)$VS3$4+-$&$<&-."%:6&-$.,<)$+4$<6:/"'2$ !)$!&'*6)-#$&-)$&%%)##)*
.!-+:/!$.!)$5-&<<)-$%6&##2

3-4*0$(56252( &(7,*4-.(1.+(/1.+,$0 %,1''$'(8$9%,*+-.4( &:7-1(;:0$<

=,*4-.(;,1'' >1.+,$0(?1'$(;,1''

EV%%)##"(6)D-"*/)S6:/"' EV%%)##"(6)D-"*/)
EV%%)##"(6)S6:/"' EV%%)##"(6)3'.)-4&%)
E3%+'Z'/"')S6:/"' E3%+'Z'/"')
E39&/)3GS6:/"' E39&/)3G[&'*6)-
return CanRead;
E3'<:.W+'.)7.S6:/"' E3'<:.W+'.)7. }
return 0;
ES"%.:-)C+-9&.S6:/"' ?LV }
ETH6O-">)-S6:/"' ETH6O-">)-
ET.,6)S6:/"' ET.,6) !) capabilities()$4:'%."+'$-).:-'#$5!&.$.!)$"9&/)$!&'*6)-$"#$%&<&(6)$+4$*+"'/$5".!$.!)$/">)'
"9&/)$4+-9&.2$ !)-)$&-)$.!-))$%&<&("6".")#$PCanRead8 CanWrite8$&'* CanReadIncrementalR8$&'*$.!)
E )7.W+*)%S6:/"' E )7.W+*)% -).:-'$>&6:)$"#$&$(".5"#)$G]$+4$.!+#)$.!&.$&<<6,2

34$.!)$4+-9&.$"#$=%:-=8$+:-$"9<6)9)'.&."+'$-).:-'# CanRead2$34$'+$4+-9&.$"#$/">)'8$5)$%-)&.)$&$%:-#+-
!&'*6)-$&'*$%!)%1$5!).!)-$".$"#$%&<&(6)$+4$-)&*"'/$.!)$*&.&$4-+9$.!)$/">)'$*)>"%)2$ !) canRead()
+$*)9+'#.-&.)$.!"#8$5)$5"66$"9<6)9)'.$&$<6:/"'$.!&.$%&'$-)&*$9+'+%!-+9)$B"'*+5#$%:-#+-$4"6)# 4:'%."+'$+'6,$<))1#$&.$.!)$*&.&8$#))"'/$"4$".$-)%+/'"K)#$.!)$4"6)8$5".!+:.$%!&'/"'/$.!)$4"6)$<+"'.)-2$V
P.cur$4"6)#R2$ !)#)$4"6)#$%&'$!+6*$#)>)-&6$"9&/)#$+4$.!)$#&9)$%:-#+-$&.$*"44)-)'.$#"K)#2$G'%)$.!) %&<&("6".,$+4$^$9)&'#$.!&.$.!)$4"6)$%&''+.$()$-)&*$+-$5-"..)'$(,$.!"#$!&'*6)-2
%:-#+-$<6:/"'$"#$(:"6.$&'*$"'#.&66)*8$E.$5"66$()$&(6)$.+$-)&* .cur$4"6)#$&'*$&%%)##$"'*">"*:&6$%:-#+-#$P4+-
)7&9<6)8$.!-+:/! QImage8 QImageReader8$+- QMovieR8$&'*$5"66$()$&(6)$.+$5-".)$.!)$%:-#+-#$+:.$"'$&',$+4
QImageIOHandler *CursorPlugin::create(QIODevice *device,
E.F#$+.!)-$"9&/)$4"6)$4+-9&.#8$#:%!$&#$DJS8$\SZ@8$&'*$S?@2$ !)$<6:/"'$%+:6*$&6#+$()$*)<6+,)*$5".!
const QByteArray &format) const
E.$&<<6"%&."+'#$#"'%)$.!),$&:.+9&."%&66,$%!)%1$.!)$#.&'*&-*$6+%&."+'#$4+-$E.$<6:/"'#$&'*$6+&*$&',
{
.!&.$.!),$4"'*2 CursorHandler *handler = new CursorHandler;
handler->setDevice(device);
?)5$"9&/)$4+-9&.$<6:/"'$5-&<<)-#$9:#.$#:(%6&## QImageIOPlugin$&'*$-)"9<6)9)'.$&$4)5$>"-.:&6 handler->setFormat(format);
4:'%."+'#I return handler;
}

class CursorPlugin : public QImageIOPlugin


{ B!)'$&$%:-#+-$4"6)$"#$+<)')*$P4+-$)7&9<6)8$(, QImageReaderR8$.!)$<6:/"'$5-&<;<)-F# create()$4:'%."+'
public:
5"66$()$%&66)*$5".!$.!)$*)>"%)$<+"'.)-$&'*$5".!$=%:-=$&#$.!)$4+-9&.2$B)$%-)&.)$& CursorHandler
QStringList keys() const;
Capabilities capabilities(QIODevice *device, "'#.&'%)$&'*$#).$".$:<$5".!$.!)$#<)%"4")*$*)>"%)$&'*$4+-9&.2$ !)$%&66)-$.&1)#$+5')-#!"<$+4$.!)
const QByteArray &format) const; !&'*6)-$&'*$5"66$*)6).)$".$5!)'$".$"#$'+$6+'/)-$-)H:"-)*2$34$9:6."<6)$4"6)#$&-)$.+$()$-)&*8$&$4-)#!
QImageIOHandler *create(QIODevice *device, !&'*6)-$5"66$()$%-)&.)*$4+-$)&%!$+')2
const QByteArray &format) const;
};
Q_EXPORT_PLUGIN2(cursorplugin, CursorPlugin)

!) keys()$4:'%."+'$-).:-'#$&$6"#.$+4$.!)$"9&/)$4+-9&.#$.!)$<6:/"'$#:<<+-.#2$ !) format$<&-&9).)-$+4
.!) capabilities()$&'* create()$4:'%."+'#$%&'$()$&##:9)*$.+$!&>)$&$>&6:)$4-+9$.!&.$6"#.2 V.$.!)$)'*$+4$.!) .cpp$4"6)8$5)$:#)$.!) Q_EXPORT_PLUGIN2()$9&%-+$.+$)'#:-)$.!&.$.!)$<6:/"'$"#
-)%+/'"K)*$(,$E.2$ !)$4"-#.$<&-&9).)-$"#$&'$&-(".-&-,$'&9)$.!&.$5)$5&'.$.+$/">)$.+$.!)$<6:/"'2$ !)
#)%+'*$<&-&9).)-$"#$.!)$<6:/"'$%6&##$'&9)2
QStringList CursorPlugin::keys() const
{ T:(%6&##"'/ QImageIOPlugin$"#$#.-&"/!.4+-5&-*2$ !)$-)&6$5+-1$+4$.!)$<6:/"'$"#$*+')$"'$.!)$!&'*6)-2
return QStringList() << "cur"; 39&/)$4+-9&.$!&'*6)-#$9:#.$#:(%6&## QImageIOHandler$&'*$-)"9<6)9)'.$#+9)$+-$&66$+4$".#$<:(6"%
} 4:'%."+'#2$Q).F#$#.&-.$5".!$.!)$!)&*)-I

G:-$<6:/"'$+'6,$#:<<+-.#$+')$"9&/)$4+-9&.8$#+$".$-).:-'#$&$6"#.$5".!$0:#.$+')$'&9)2$3*)&66,$.!)$'&9) class CursorHandler : public QImageIOHandler


#!+:6*$()$.!)$4"6)$)7.)'#"+'$:#)*$(,$.!)$4+-9&.2$B!)'$*)&6"'/$5".!$4+-9&.#$5".!$#)>)-&6$)7.)'#"+'# {
P#:%!$&# .jpg$&'* .jpeg$4+-$\SZ@R8$5)$%&'$-).:-'$&$6"#.$5".!$#)>)-&6$)'.-")#$4+-$.!)$#&9)$4+-9&.8$+') public:
4+-$)&%!$)7.)'#"+'2 CursorHandler();
bool canRead() const;
bool read(QImage *image);
bool jumpToNextImage();
QImageIOPlugin::Capabilities
int currentImageNumber() const;
CursorPlugin::capabilities(QIODevice *device,
int imageCount() const;
const QByteArray &format) const
private:
{
enum State { BeforeHeader, BeforeImage, AfterLastImage, Error };
if (format == "cur")
void readHeaderIfNecessary() const;
return CanRead;
QBitArray readBitmap(int width, int height, QDataStream &in) const;
if (format.isEmpty()) {
void enterErrorState() const;
CursorHandler handler;
mutable State state;
handler.setDevice(device);
mutable int currentImageNo;
if (handler.canRead())
mutable int numImages;
}; 3-4*0$(562@2(A/$ .cur(B-,$(B:0)1&

[View full size image]


!)$#"/'&.:-)#$+4$&66$.!)$<:(6"%$4:'%."+'#$&-)$4"7)*2$B)$!&>)$+9"..)*$#)>)-&6$4:'%."+'#$.!&.$5)$*+'F.
'))*$.+$-)"9<6)9)'.$4+-$&$-)&*;+'6,$!&'*6)-8$"'$<&-."%:6&- write()2$ !)$9)9()-$>&-"&(6)#$&-)
*)%6&-)*$5".!$.!) mutable$1),5+-*$()%&:#)$.!),$&-)$9+*"4")*$"'#"*)$%+'#.$4:'%."+'#2

CursorHandler::CursorHandler()
{
state = BeforeHeader;
currentImageNo = 0;
numImages = 0;
}

B!)'$.!)$!&'*6)-$"#$%+'#.-:%.)*8 5)$()/"'$(,$#).."'/$".#$#.&.)2$B)$#).$.!)$%:--)'.$%:-#+-$"9&/)
':9()-$.+$.!)$4"-#.$%:-#+-8$(:.$#"'%)$5)$#). numImages$.+$^$".$"#$%6)&-$.!&.$5)$!&>)$'+$"9&/)#$,).2

!)$')7.$4:'%."+'$"#$H:".)$"'>+6>)*8$#+$5)$5"66$-)>")5$".$"'$<")%)#I
bool CursorHandler::canRead() const
{
if (state == BeforeHeader) {
bool CursorHandler::read(QImage *image)
return device()->peek(4) == QByteArray("\0\0\2\0", 4);
{
} else {
readHeaderIfNecessary();
return state != Error;
if (state != BeforeImage)
}
return false;
}

!) read()$4:'%."+'$-)&*#$.!)$*&.&$4+-$5!"%!)>)-$"9&/)$()/"'#$&.$.!)$%:--)'.$*)>"%)$<+"'.)-
!) canRead()$4:'%."+'$%&'$()$%&66)*$&.$&',$."9)$.+$*).)-9"')$5!).!)-$.!)$"9&/)$!&'*6)-$%&'$-)&*
<+#"."+'2$34$.!)$4"6)F#$!)&*)-$"#$-)&*$#:%%)##4:66,8$+-$&4.)-$&'$"9&/)$!&#$())'$-)&*$&'*$.!)$*)>"%)
9+-)$*&.&$4-+9$.!)$*)>"%)2$34$.!)$4:'%."+'$"#$%&66)*$()4+-)$5)$!&>)$-)&*$&',$*&.&8$5!"6)$5)$&-)$#."66
<+"'.)-$"#$&.$.!)$#.&-.$+4$&'+.!)-$"9&/)8$5)$%&'$-)&*$.!)$')7.$"9&/)2
"'$.!) BeforeHeader$#.&.)8$5)$%!)%1$4+-$.!)$<&-."%:6&-$#"/'&.:-)$.!&.$"*)'."4")#$B"'*+5#$%:-#+-$4"6)#2
!) QIODevice::peek()$%&66$-)&*#$.!)$4"-#.$4+:-$(,.)# -)!./0!$%!&'/"'/$.!)$*)>"%)F#$4"6)$<+"'.)-2$34
canRead()$"#$%&66)*$6&.)-$+'8$5)$-).:-' true$:'6)##$&'$)--+-$!&#$+%%:--)*2 quint32 size;
quint32 width;
quint32 height;
int CursorHandler::currentImageNumber() const quint16 numPlanes;
{ quint16 bitsPerPixel;
return currentImageNo; quint32 compression;
} QDataStream in(device());
in.setByteOrder(QDataStream::LittleEndian);
in >> size;
!"#$.-">"&6$4:'%."+'$-).:-'#$.!)$':9()-$+4$.!)$%:-#+-$&.$5!"%!$.!)$*)>"%)$4"6)$<+"'.)-$"#$<+#"."+')*2 if (size != 40) {
enterErrorState();
return false;
G'%)$.!)$!&'*6)-$"#$%+'#.-:%.)*8$".$"#$<+##"(6)$4+-$.!)$:#)-$.+$%&66$&',$+4$".#$<:(6"%$4:'%."+'#8$"'$&', }
+-*)-2$ !"#$"#$&$<+.)'."&6$<-+(6)9$#"'%)$5)$9:#.$&##:9)$.!&.$5)$%&'$+'6,$-)&*$#)-"&66,8$#+$5)$'))* in >> width >> height >> numPlanes >> bitsPerPixel >> compression;
.+$-)&*$.!)$4"6)$!)&*)-$+'%)$()4+-)$*+"'/$&',.!"'/$)6#)2$B)$#+6>)$.!)$<-+(6)9$(,$%&66"'/$.!) height /= 2;
readHeaderIfNecessary()$4:'%."+'$"'$.!+#)$4:'%."+'#$.!&.$*)<)'*$+'$.!)$!)&*)-$!&>"'/$())'$-)&*2 if (numPlanes != 1 || bitsPerPixel != 1 || compression != 0) {
enterErrorState();
return false;
int CursorHandler::imageCount() const }
{ in.skipRawData((size - 20) + 8);
readHeaderIfNecessary();
return numImages;
} B)$%-)&.)$& QDataStream$.+$-)&*$.!)$*)>"%)2$B)$9:#.$#).$.!)$(,.)$+-*)-$.+$9&.%!$.!&.$#<)%"4")*$(,
.!) .cur$4"6)$4+-9&.$#<)%"4"%&."+'2$ !)-)$"#$'+$'))*$.+$#).$& QDataStream$>)-#"+'$':9()-$#"'%)$.!)
4+-9&.$+4$"'.)/)-#$&'*$46+&."'/;<+"'.$':9()-#$*+)#$'+.$>&-,$().5))'$*&.&$#.-)&9$>)-#"+'#2$?)7.8
!"#$4:'%."+'$-).:-'#$.!)$':9()-$+4$"9&/)#$"'$.!)$4"6)2$C+-$&$>&6"*$4"6)$5!)-)$'+$-)&*"'/$)--+-#$!&>) 5)$-)&*$"'$>&-"+:#$".)9#$+4$%:-#+-$!)&*)-$*&.&8$&'*$5)$#1"<$.!)$"--)6)>&'.$<&-.#$+4$.!)$!)&*)-$&'*
+%%:--)*8$".$5"66$-).:-'$&$%+:'.$+4$&.$6)&#.$N2 .!)$_;(,.)$%+6+-$.&(6)$:#"'/ QDataStream::skipRawData()2
B)$9:#.$&%%+:'.$4+-$&66$.!)$4+-9&.F#$"*"+#,'%-&#")#4+-$)7&9<6)8$!&6>"'/$.!)$!)"/!.$()%&:#)$.!) .cur
4+-9&.$/">)# &$!)"/!.$.!&.$"#$.5"%)$&#$!"/!$&#$.!)$&%.:&6$"9&/)F#$!)"/!.2$ !) bitsPerPixel$&'* D6&%18$5!".)8$&'*$.-&'#<&-)'.$<"7)6#$&-)$'+$<-+(6)98$(:.$.!)-)F# '+$5&,$+4$+(.&"'"'/$&'$"'>)-.)*
compression$>&6:)#$&-)$&65&,#$N$&'*$^$"'$&$9+'+%!-+9) .cur$4"6)2$34$5)$!&>)$&',$<-+(6)9#8$5)$%&66 (&%1/-+:'*$<"7)6$:#"'/$&'$V]@D$%+6+-$#<)%"4"%&."+'$5".!+:.$1'+5"'/$.!)$%+6+-$+4$.!)$+-"/"'&6
enterErrorState()$&'*$-).:-' false2 (&%1/-+:'*$<"7)62$V#$&$#:(#.".:.)8$5)$:#)$&$#)9";.-&'#<&-)'.$/-&,$%+6+-$P0x7F7F7F7FR2

QBitArray xorBitmap = readBitmap(width, height, in); ++currentImageNo;


QBitArray andBitmap = readBitmap(width, height, in); if (currentImageNo == numImages)
if (in.status() != QDataStream::Ok) { state = AfterLastImage;
enterErrorState(); return true;
return false; }
}

G'%)$5)$!&>)$4"'"#!)*$-)&*"'/$.!)$"9&/)8$5)$:<*&.)$.!)$%:--)'.$"9&/)$':9()-$&'*$:<*&.)$.!)
!)$')7.$".)9#$"'$.!)$4"6)$&-)$.5+$(".9&<#8$+')$&'$UG]$9&#1$&'*$.!)$+.!)-$&'$V?O$9&#12$B)$-)&* #.&.)$"4$5)$!&>)$-)&%!)*$.!)$6&#.$"9&/)2$V.$.!)$)'*$+4$.!)$4:'%."+'8$.!)$*)>"%)$5"66$()$<+#"."+')*$&.
.!)#)$"'.+ QBitArray#$-&.!)-$.!&'$"'.+ QBitmap#2$V QBitmap$"#$&$%6&##$*)#"/')*$.+$()$*-&5'$+'$&'* .!)$')7.$"9&/)$+-$&.$.!)$)'*$+4$.!)$4"6)2
<&"'.)*$+';#%-))'8$(:.$5!&.$5)$'))*$!)-)$"#$&$<6&"'$&--&,$+4$(".#2

B!)'$5)$&-)$*+')$5".!$-)&*"'/$.!)$4"6)8$5)$%!)%1$.!) QDataStreamF#$#.&.:#2$ !"#$5+-1#$()%&:#)$"4$& bool CursorHandler::jumpToNextImage()


QDataStream$)'.)-#$&'$)--+-$#.&.)8$".$#.&,#$"'$.!&.$#.&.)$&'*$%&'$+'6,$-).:-'$K)-+#2$C+-$)7&9<6)8$"4 {
-)&*"'/$4&"6#$+'$.!)$4"-#.$(".$&--&,8$.!)$&..)9<.$.+$-)&*$.!)$#)%+'*$5"66$-)#:6.$"'$&'$)9<., QBitArray2 QImage image;
return read(&image);
}
*image = QImage(width, height, QImage::Format_ARGB32);
for (int i = 0; i < int(height); ++i) {
for (int j = 0; j < int(width); ++j) { !) jumpToNextImage()$4:'%."+'$"#$:#)*$.+$#1"<$&'$"9&/)2$C+-$#"9<6"%".,8$5)$#"9<6,$%&66 read()$&'*
QRgb color; "/'+-)$.!)$-)#:6."'/ QImage2$V$9+-)$)44"%")'.$"9<6)9)'.&."+'$5+:6*$:#)$.!)$"'4+-9&."+'$#.+-)*$"'$.!)
int bit = (i * width) + j; .cur$4"6)$!)&*)-$.+$#1"<$*"-)%.6,$.+$.!)$&<<-+<-"&.)$+44#).$"'$.!)$4"6)2
if (andBitmap.testBit(bit)) {
if (xorBitmap.testBit(bit)) {
color = 0x7F7F7F7F; void CursorHandler::readHeaderIfNecessary() const
} else { {
color = 0x00FFFFFF; if (state != BeforeHeader)
} return;
} else { quint16 reserved;
if (xorBitmap.testBit(bit)) { quint16 type;
color = 0xFFFFFFFF; quint16 count;
} else { QDataStream in(device());
color = 0xFF000000; in.setByteOrder(QDataStream::LittleEndian);
} in >> reserved >> type >> count;
} in.skipRawData(16 * count);
image->setPixel(j, i, color); if (in.status() != QDataStream::Ok || reserved != 0
} || type != 2 || count == 0) {
} enterErrorState();
return;
}
B)$%+'#.-:%.$&$')5 QImage$+4$.!)$%+--)%.$#"K)$&'*$#). image$.+$<+"'.$.+$".2$ !)'$5)$".)-&.)$+>)-$)>)-, state = BeforeImage;
<"7)6$"'$.!)$UG]$&'*$V?O$(".$&--&,#$&'*$%+'>)-.$.!)9$"'.+$Y`;(".$V]@D$%+6+-$#<)%"4"%&."+'#2$ !) currentImageNo = 0;
V?O$&'*$UG]$(".$&--&,#$&-)$:#)*$&#$#!+5'$"'$.!)$4+66+5"'/$.&(6)$.+$+(.&"'$.!)$%+6+-$+4$)&%!$%:-#+- numImages = int(count);
<"7)6I }

CDE F!G G$'*,& !) readHeaderIfNecessary()$<-">&.)$4:'%."+'$"#$%&66)*$4-+9 imageCount()$&'* read()2 34$.!)$4"6)F#


N N 3'>)-.)*$(&%1/-+:'*$<"7)6 !)&*)-$!&#$&6-)&*,$())'$-)&*8$.!)$#.&.)$"#$'+. BeforeHeader$&'*$5)$-).:-'$"99)*"&.)6,2$G.!)-5"#)8
5)$+<)'$&$*&.&$#.-)&9$+'$.!)$*)>"%)8$-)&*$"'$#+9)$/)')-"%$*&.&$P"'%6:*"'/$.!)$':9()-$+4$%:-#+-#$"'
N ^ -&'#<&-)'.$<"7)6 .!)$4"6)R8$&'*$#).$.!)$#.&.)$.+ BeforeImage2 V.$.!)$)'*8$.!)$*)>"%)F#$4"6)$<+"'.)-$"#$<+#"."+')*$()4+-)
.!)$4"-#.$"9&/)2
^ N B!".)$<"7)6
^ ^ D6&%1$<"7)6 void CursorHandler::enterErrorState() const
{
state = Error;
currentImageNo = 0; #!+:6*$/+2$V66$E.$<6:/"'#$9:#.$/+$"'$.!)$&<<-+<-"&.) plugins$#:(*"-)%.+-,$5!)-)$E.$5&#$"'#.&66)*8
numImages = 0; &'*$#"'%)$+:-$<6:/"'$<-+>"*)#$&$')5$"9&/)$4+-9&.$5)$<:.$".$"' plugins/imageformats2$ !)$6"#.$+4
} *"-)%.+-,$'&9)#$&'*$<6:/"'$.,<)#$"#$/">)'$&. !..<ILL*+%2.-+66.)%!2%+9LM2NL<6:/"'#;!+5.+2!.962$C+-
.!"#$)7&9<6)8$5)$&##:9)$.!&.$.!) QtdIR$)'>"-+'9)'.$>&-"&(6)$"#$#).$.+$.!)$*"-)%.+-,$5!)-)$E.$"#
"'#.&66)*2
34$&'$)--+-$+%%:-#8$5)$&##:9)$.!&.$.!)-)$&-)$'+$>&6"*$"9&/)#$&'*$#).$.!)$#.&.)$.+ Error2$G'%)$"'$.!)
Error$#.&.)8$.!)$!&'*6)-F#$#.&.)$%&''+.$%!&'/)2 S6:/"'#$(:"6.$4+-$E.$"'$-)6)&#)$9+*)$&'*$*)(:/$9+*)$&-)$*"44)-)'.8$#+$"4$(+.!$>)-#"+'#$+4$E.$&-)
"'#.&66)*8$".$"#$5"#)$.+$#<)%"4,$5!"%!$+')$.+$:#)$"'$.!) .pro$4"6)4+-$)7&9<6)8$(,$&**"'/$.!)$6"')

QBitArray CursorHandler::readBitmap(int width, int height,


QDataStream &in) const CONFIG += release
{
QBitArray bitmap(width * height);
quint8 byte;
quint32 word; V<<6"%&."+'#$.!&.$:#)$E.$<6:/"'#$9:#.$()$*)<6+,)*$5".!$.!)$<6:/"'#$.!),$&-)$"'.)'*)*$.+$:#)2$E.
for (int i = 0; i < height; ++i) { <6:/"'#$9:#.$()$<6&%)*$"'$#<)%"4"%$#:(*"-)%.+-")#$P4+-$)7&9<6)8 imageformats$4+-$"9&/)$4+-9&.#R2$E.
for (int j = 0; j < width; ++j) { &<<6"%&."+'#$#)&-%!$4+-$<6:/"'#$"'$.!) plugins$*"-)%.+-,$"'$.!)$*"-)%.+-,$5!)-)$.!)$&<<6"%&."+'F#
if ((j % 32) == 0) { )7)%:.&(6)$-)#"*)#8$#+$4+-$"9&/)$<6:/"'#$.!),$#)&-%! application_dir/plugins/imageformats2$34$5)
word = 0; 5&'.$.+$*)<6+,$E.$<6:/"'#$"'$&$*"44)-)'.$*"-)%.+-,8$.!)$<6:/"'#$#)&-%!$<&.!$%&'$()$&:/9)'.)*$(,
for (int k = 0; k < 4; ++k) { :#"'/ QCoreApplication::addLibraryPath()2
in >> byte;
word = (word << 8) | byte;
}
}
bitmap.setBit(((height - i - 1) * width) + j,
Making Applications Plugin-Aware
word & 0x80000000);
word <<= 1; V'$&<<6"%&."+'$<6:/"'$"#$&$*,'&9"%$6"(-&-,$.!&.$"9<6)9)'.#$+')$+-$9+-) )+!',234'(2$V'$"'.)-4&%)$"#$&
} %6&##$.!&.$%+'#"#.#$)7%6:#">)6,$+4$<:-)$>"-.:&6$4:'%."+'#2$ !)$%+99:'"%&."+'$().5))'$.!)$&<<6"%&."+'
} &'*$.!)$<6:/"'#$"#$*+')$.!-+:/!$.!)$"'.)-4&%)F#$>"-.:&6$.&(6)2$3'$.!"#$#)%."+'8$5)$5"66$4+%:#$+'$!+5$.+
return bitmap; :#)$&$<6:/"'$"'$&$E.$&<<6"%&."+'$.!-+:/!$".#$"'.)-4&%)#8$&'*$"'$.!)$')7.$#)%."+'$5)$5"66$#!+5$!+5$.+
} "9<6)9)'.$&$<6:/"'2

+$<-+>"*)$&$%+'%-).)$)7&9<6)8$5)$5"66$%-)&.)$.!)$#"9<6)$ )7.$V-.$&<<6"%&."+'$#!+5'$"' C"/:-)$Na2Y2


!) readBitmap()$4:'%."+'$"#$:#)*$.+$-)&*$&$%:-#+-F#$V?O$&'*$UG]$9&#1#2$ !)#)$9&#1#$!&>)$.5+ !)$.)7.$)44)%.#$&-)$<-+>"*)*$(,$<6:/"'#b$.!)$&<<6"%&."+'$-).-")>)#$.!)$6"#.$+4$.)7.$)44)%.#$<-+>"*)*$(,
:':#:&6$4)&.:-)#2$C"-#.8$.!),$#.+-)$.!)$-+5#$4-+9$(+..+9$.+$.+<8$"'#.)&*$+4$.!)$9+-)$%+99+'$.+<;.+; )&%!$<6:/"'$&'*$".)-&.)#$+>)-$.!)9$.+$#!+5$)&%!$+')$&#$&'$".)9$"'$& QListWidget2
(+..+9$&<<-+&%!2$T)%+'*8$.!)$)'*"&'')##$+4$.!)$*&.&$&<<)&-#$.+$()$-)>)-#)*$4-+9$.!&.$:#)*
)>)-,5!)-)$)6#)$"' .cur$4"6)#2$3'$>")5$+4$.!"#8$5)$9:#.$"'>)-.$.!) 1$%++-*"'&.)$"'$.!) setBit()$%&668 3-4*0$(562H2(A/$(A$9&(C0&(177,-%1&-:.
&'*$5)$-)&*$"'$.!)$9&#1$>&6:)#$+')$(,.)$&.$&$."9)8$(".;#!"4."'/$&'*$9&#1"'/$.+$)7.-&%.$.!)"-$%+--)%.
>&6:)#2 [View full size image]

!"#$%+9<6).)#$.!)$"9<6)9)'.&."+'$+4$.!) CursorHandler$"9&/)$4+-9&.$<6:/"'2$S6:/"'#$4+-$+.!)-
"9&/)$4+-9&.#$5+:6*$4+66+5$.!)$#&9)$<&..)-'8$&6.!+:/!$#+9)$9"/!.$"9<6)9)'.$9+-)$+4$.!)
QImageIOHandler$VS38$"'$<&-."%:6&-$.!)$4:'%."+'#$:#)*$4+-$5-"."'/$"9&/)#2$S6:/"'#$+4$+.!)-$1"'*#8$4+-
)7&9<6)8$.)7.$%+*)%#$+-$*&.&(&#)$*-">)-#8$4+66+5$.!)$#&9)$<&..)-'$+4$!&>"'/$&$<6:/"'$5-&<<)-$.+
<-+>"*)$&$/)')-"%$VS3$.!&.$&<<6"%&."+'#$%&'$:#)8$&'*$&$!&'*6)-$.+$<-+>"*)$.!)$:'*)-6,"'/
4:'%."+'&6".,2

!) .pro$4"6)$"#$*"44)-)'.$4+-$<6:/"'#$.!&'$4+-$&<<6"%&."+'#8$#+$5)$5"66$)'*$5".!$.!&.I

TEMPLATE = lib
CONFIG += plugin
HEADERS = cursorhandler.h \
cursorplugin.h
SOURCES = cursorhandler.cpp \
cursorplugin.cpp
DESTDIR = $(QTDIR)/plugins/imageformats

D,$*)4&:6.8 .pro$4"6)#$:#)$.!) app$.)9<6&.)8$(:.$!)-)$5)$9:#.$#<)%"4,$.!) lib$.)9<6&.)$()%&:#)$&


<6:/"'$"#$&$6"(-&-,8$'+.$&$#.&'*;&6+')$&<<6"%&."+'2$ !) CONFIG$6"')$"#$:#)*$.+$.)66$E.$.!&.$.!)$6"(-&-,$"#
'+.$0:#.$&$<6&"'$6"(-&-,8$(:.$&$<6:/"'$6"(-&-,2$ !) DESTDIR$#<)%"4")#$.!)$*"-)%.+-,$5!)-)$.!)$<6:/"'
|| pluginDir.dirName().toLower() == "release")
!)$ )7.$V-.$&<<6"%&."+'$*)4"')#$+')$"'.)-4&%)I pluginDir.cdUp();
#elif defined(Q_OS_MAC)
if (pluginDir.dirName() == "MacOS") {
pluginDir.cdUp();
class TextArtInterface
pluginDir.cdUp();
{
pluginDir.cdUp();
public:
}
virtual ~TextArtInterface() { }
#endif
virtual QStringList effects() const = 0;
if (!pluginDir.cd("plugins"))
virtual QPixmap applyEffect(const QString &effect,
return;
const QString &text,
foreach (QString fileName, pluginDir.entryList(QDir::Files)) {
const QFont &font, const QSize &size,
QPluginLoader loader(pluginDir.absoluteFilePath(fileName));
const QPen &pen,
if (TextArtInterface *interface =
const QBrush &brush) = 0;
qobject_cast<TextArtInterface *>(loader.instance()))
};
interfaces.append(interface);
Q_DECLARE_INTERFACE(TextArtInterface,
}
"com.software-inc.TextArt.TextArtInterface/1.0")
}

V'$"'.)-4&%)$%6&##$'+-9&66,$*)%6&-)#$&$>"-.:&6$*)#.-:%.+-8$&$>"-.:&6$4:'%."+'$.!&.$-).:-'#$&
3' loadPlugins()8$5)$&..)9<.$.+$6+&*$&66$.!)$4"6)#$"'$.!)$&<<6"%&."+'F# plugins$*"-)%.+-,2$PG'
QStringList8$&'*$+')$+-$9+-)$+.!)-$>"-.:&6$4:'%."+'#2$ !)$*)#.-:%.+-$"#$.!)-)$<-"9&-"6,$.+$#"6)'%)$.!)
B"'*+5#8$.!)$&<<6"%&."+'F#$)7)%:.&(6)$:#:&66,$6">)#$"'$& debug$+- release$#:(*"-)%.+-,8$#+$5)$9+>)
%+9<"6)-8$5!"%!$9"/!.$+.!)-5"#)$%+9<6&"'$&(+:.$.!)$6&%1$+4$&$>"-.:&6$*)#.-:%.+-$"'$&$%6&##$.!&.$!&#
+')$*"-)%.+-,$:<2$G'$J&%$GT$U8$5)$.&1)$.!)$(:'*6)$*"-)%.+-,$#.-:%.:-)$"'.+$&%%+:'.2R
>"-.:&6$4:'%."+'#2$3'$.!"#$)7&9<6)8$.!) effects()$4:'%."+'$-).:-'#$&$6"#.$+4$.!)$.)7.$)44)%.#$.!)$<6:/"'
%&'$<-+>"*)2$B)$%&'$.!"'1$+4$.!"#$6"#.$&#$&$6"#.$+4$1),#2$Z>)-,$."9)$5)$%&66$+')$+4$.!)$+.!)-$4:'%."+'#8
34$.!)$4"6)$5)$.-,$.+$6+&*$"#$&$E.$<6:/"'$.!&.$:#)#$.!)$#&9)$>)-#"+'$+4$E.$&#$.!)$&<<6"%&."+'8
5)$<&##$+')$+4$.!)#)$1),#$&#$4"-#.$&-/:9)'.8$9&1"'/$".$<+##"(6)$.+$"9<6)9)'.$9:6."<6)$)44)%.#$"'$+')
QPluginLoader::instance()$5"66$-).:-'$& QObject *$.!&.$<+"'.#$.+$&$E.$<6:/"'2$B)$:#)
<6:/"'2
qobject_cast<T>()$.+$%!)%1$5!).!)-$.!)$<6:/"'$"9<6)9)'.#$.!) TextArtInterface2$Z&%!$."9)$.!)$%&#.
"#$#:%%)##4:68$5)$&**$.!)$"'.)-4&%)$.+$.!) TextArtDialogF#$6"#.$+4$"'.)-4&%)#$P+4$.,<)
V.$.!)$)'*8$5)$:#)$.!) Q_DECLARE_INTERFACE()$9&%-+$.+$&##+%"&.)$&'$"*)'."4")-$.+$.!)$"'.)-4&%)2$ !)
QList<TextArtInterface *>R2
"*)'."4")-$'+-9&66,$!&#$4+:-$%+9<+')'.#I$&'$"'>)-.)*$*+9&"'$'&9)$#<)%"4,"'/$.!)$%-)&.+-$+4$.!)
"'.)-4&%)8$.!)$'&9)$+4$.!)$&<<6"%&."+'8$.!)$'&9)$+4$.!)$"'.)-4&%)8$&'*$&$>)-#"+'$':9()-2$B!)')>)-
5)$&6.)-$.!)$"'.)-4&%)$P4+-$)7&9<6)8$(,$&**"'/$&$>"-.:&6$4:'%."+'$+-$%!&'/"'/$.!)$#"/'&.:-)$+4$&' T+9)$&<<6"%&."+'#$9&,$5&'.$.+$6+&*$.5+$+-$9+-)$*"44)-)'.$"'.)-4&%)#8$"'$5!"%!$%&#)$.!)$%+*)$4+-
)7"#."'/$4:'%."+'R8$5)$9:#.$-)9)9()-$.+$"'%-)&#)$.!)$>)-#"+'$':9()-b$+.!)-5"#)8$.!)$&<<6"%&."+' +(.&"'"'/$.!)$"'.)-4&%)#$5+:6*$6++1$9+-)$6"1)$.!&.$#!+5'$()6+5I
9"/!.$%-&#!$.-,"'/$.+$&%%)##$&'$+:.*&.)*$<6:/"'2

QObject *plugin = loader.instance();


!)$&<<6"%&."+'$"#$"9<6)9)'.)*$"'$&$%6&##$%&66)* TextArtDialog2$B)$5"66$+'6,$#!+5$.!)$%+*)$-)6)>&'.
if (TextArtInterface *i = qobject_cast<TextArtInterface *>(plugin))
.+$9&1"'/$".$<6:/"';&5&-)2$Q).F#$#.&-.$5".!$.!)$%+'#.-:%.+-I textArtInterfaces.append(i);
if (BorderArtInterface *i = qobject_cast<BorderArtInterface *>(plugin))
borderArtInterfaces.append(i);
TextArtDialog::TextArtDialog(const QString &text, QWidget *parent) if (TextureInterface *i = qobject_cast<TextureInterface *>(plugin))
: QDialog(parent) textureInterfaces.append(i);
{
listWidget = new QListWidget;
listWidget->setViewMode(QListWidget::IconMode);
listWidget->setMovement(QListWidget::Static); !)$#&9)$<6:/"'$9&,$#:%%)##4:66,$%&#.$.+$9+-)$.!&'$+')$"'.)-4&%)$<+"'.)-8$#"'%)$".$"#$<+##"(6)$4+-
listWidget->setIconSize(QSize(260, 80)); <6:/"'#$.+$<-+>"*)$9:6."<6)$"'.)-4&%)#$(,$:#"'/$9:6."<6)$"'!)-".&'%)2
...
loadPlugins();
populateListWidget(text); void TextArtDialog::populateListWidget(const QString &text)
... {
} QSize iconSize = listWidget->iconSize();
QPen pen(QColor("darkseagreen"));
QLinearGradient gradient(0, 0, iconSize.width() / 2,
iconSize.height() / 2);
!)$%+'#.-:%.+-$%-)&.)#$& QListWidget$.+$6"#.$.!)$&>&"6&(6)$)44)%.#2$3.$%&66#$.!)$<-">&.)$4:'%."+' gradient.setColorAt(0.0, QColor("darkolivegreen"));
loadPlugins()$.+$4"'*$&'*$6+&*$&',$<6:/"'#$.!&.$"9<6)9)'.$.!) TextArtInterface$&'*$<+<:6&.)#$.!) gradient.setColorAt(0.8, QColor("darkgreen"));
6"#.$5"*/).$&%%+-*"'/6,$(,$%&66"'/$&'+.!)-$<-">&.)$4:'%."+'8 populateListWidget()2 gradient.setColorAt(1.0, QColor("lightgreen"));
QFont font("Helvetica", iconSize.height(), QFont::Bold);
foreach (TextArtInterface *interface, interfaces) {
void TextArtDialog::loadPlugins() foreach (QString effect, interface->effects()) {
{ QListWidgetItem *item = new QListWidgetItem(effect,
QDir pluginDir(QApplication::applicationDirPath()); listWidget);
#if defined(Q_OS_WIN) QPixmap pixmap = interface->applyEffect(effect, text, font,
if (pluginDir.dirName().toLower() == "debug" iconSize, pen,
gradient); -)>")5$".$"'$<")%)#2
item->setData(Qt::DecorationRole, pixmap);
}
} QPixmap BasicEffectsPlugin::applyEffect(const QString &effect,
listWidget->setCurrentRow(0); const QString &text, const QFont &font, const QSize &size,
} const QPen &pen, const QBrush &brush)
{
QFont myFont = font;
!) populateListWidget()$4:'%."+'$()/"'#$(,$%-)&."'/$#+9)$>&-"&(6)#$.+$<&##$.+$.!) applyEffect() QFontMetrics metrics(myFont);
4:'%."+'8$"'$<&-."%:6&-$&$<)'8$&$6"')&-$/-&*")'.8$&'*$&$4+'.2$3.$.!)'$".)-&.)#$+>)-$)>)-, while ((metrics.width(text) > size.width()
|| metrics.height() > size.height())
TextArtInterface$.!&.$5&#$4+:'*$(, loadPlugins()2$C+-$)&%! )44)%.$<-+>"*)*$(,$)&%!$"'.)-4&%)8$&
&& myFont.pointSize() > 9) {
')5 QListWidgetItem$"#$%-)&.)*$5".!$".#$.)7.$#).$.+$.!)$'&9)$+4$.!)$)44)%.$".$-)<-)#)'.#8$&'*$& myFont.setPointSize(myFont.pointSize() - 1);
QPixmap$"#$%-)&.)*$:#"'/ applyEffect()2 metrics = QFontMetrics(myFont);
}
3'$.!"#$#)%."+'$5)$!&>)$#))'$!+5$.+$6+&*$<6:/"'#$(,$%&66"'/ loadPlugins()$"'$.!)$%+'#.-:%.+-8$&'*
!+5$.+$9&1)$:#)$+4$.!)9$"' populateListWidget()2$ !)$%+*)$%+<)#$/-&%)4:66,$5!).!)-$.!)-)$&-)$'+
<6:/"'#$<-+>"*"'/ TextArtInterface#8$0:#.$+')8$+-$9+-)$.!&'$+')2$C:-.!)-9+-)8$&**"."+'&6$<6:/"'# B)$5&'.$.+$)'#:-)$.!&.$.!)$/">)'$.)7.$5"66$4".$"'$.!)$#<)%"4")*$#"K)$"4$<+##"(6)2$C+-$.!"#$-)&#+'8$5)$:#)
%+:6*$()$&**)*$6&.)-I$Z>)-,$."9)$.!)$&<<6"%&."+'$#.&-.#$:<$".$6+&*#$5!&.)>)-$<6:/"'#$".$4"'*#$.!&. .!)$4+'.F#$9).-"%#$.+$#))$"4$.!)$.)7.$"#$.++$6&-/)$.+$4".8$&'*$"4$".$"#$5)$)'.)-$&$6++<$5!)-)$5)$-)*:%)$.!)
<-+>"*)$.!)$"'.)-4&%)#$".$5&'.#2$ !"#$9&1)#$".$)&#,$.+$)7.)'*$.!)$&<<6"%&."+'F#$4:'%."+'&6".,$5".!+:. <+"'.$#"K)$:'."6$5)$4"'*$&$#"K)$.!&.$5"66$4".8$+-$:'."6$5)$-)&%!$a$<+"'.#8$+:-$4"7)*$9"'"9:9$#"K)2
%!&'/"'/$.!)$&<<6"%&."+'$".#)642

QPixmap pixmap(size);
QPainter painter(&pixmap);
Writing Application Plugins painter.setFont(myFont);
painter.setPen(pen);
V'$&<<6"%&."+'$<6:/"'$"#$&$#:(%6&##$+4 QObject$&'*$+4$.!)$"'.)-4&%)#$".$5&'.#$.+$<-+>"*)2$ !)$WO$.!&. painter.setBrush(brush);
&%%+9<&'")#$.!"#$(++1$"'%6:*)#$.5+$<6:/"'#$4+-$.!)$ )7.$V-.$&<<6"%&."+'$<-)#)'.)*$"'$.!)$<-)>"+:# painter.setRenderHint(QPainter::Antialiasing, true);
painter.setRenderHint(QPainter::TextAntialiasing, true);
#)%."+'8$.+$#!+5$.!&.$.!)$&<<6"%&."+'$%+--)%.6,$!&'*6)#$9:6."<6)$<6:/"'#2
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.eraseRect(pixmap.rect());
[)-)8$5)$5"66$+'6,$-)>")5$.!)$%+*)$4+-$+')$+4$.!)98$.!)$D&#"%$Z44)%.#$S6:/"'2$B)$5"66$&##:9)$.!&.$.!)
<6:/"'F#$#+:-%)$%+*)$"#$6+%&.)*$"'$&$*"-)%.+-,$%&66)* basiceffectsplugin$&'*$.!&.$.!)$ )7.$V-.
&<<6"%&."+'$"#$6+%&.)*$"'$&$<&-&66)6$*"-)%.+-,$%&66)* textart2$[)-)F#$.!)$*)%6&-&."+'$+4$.!)$<6:/"'$%6&##I
B)$%-)&.)$&$<"79&<$+4$.!)$-)H:"-)*$#"K)$&'*$&$<&"'.)-$.+$<&"'.$+'.+$.!)$<"79&<2$B)$&6#+$#).$#+9)
-)'*)-$!"'.#$.+$)'#:-)$.!)$#9++.!)#.$<+##"(6)$-)#:6.#2$ !)$%&66$.+ eraseRect()$%6)&-#$.!)$<"79&<$5".!
.!)$(&%1/-+:'*$%+6+-2
class BasicEffectsPlugin : public QObject, public TextArtInterface
{
Q_OBJECT
Q_INTERFACES(TextArtInterface) if (effect == "Plain") {
public: painter.setPen(Qt::NoPen);
QStringList effects() const; } else if (effect == "Outline") {
QPixmap applyEffect(const QString &effect, const QString &text, QPen pen(Qt::black);
const QFont &font, const QSize &size, pen.setWidthF(2.5);
const QPen &pen, const QBrush &brush); painter.setPen(pen);
}; } else if (effect == "Shadow") {
QPainterPath path;
painter.setBrush(Qt::darkGray);
path.addText(((size.width() - metrics.width(text)) / 2) + 3,
!)$<6:/"'$"9<6)9)'.#$+'6,$+')$"'.)-4&%)8 TextArtInterface2$3'$&**"."+'$.+ Q_OBJECT8$5)$9:#.$:#) (size.height() - metrics.descent()) + 3, myFont,
.!) Q_INTERFACES()$9&%-+$4+-$)&%!$+4$.!)$"'.)-4&%)#$.!&.$&-)$#:(%6&##)*$.+$)'#:-)$#9++.! text);
%++<)-&."+'$().5))' moc$&'* qobject_cast<T>()2 painter.drawPath(path);
painter.setBrush(brush);
}
QStringList BasicEffectsPlugin::effects() const
{
return QStringList() << "Plain" << "Outline" << "Shadow"; C+-$.!)$=S6&"'=$)44)%.8$'+$+:.6"')$"#$-)H:"-)*2$C+-$.!)$=G:.6"')=$)44)%.8$5)$"/'+-)$.!)$+-"/"'&6$<)'$&'*
} %-)&.)$+:-$+5'$(6&%1$<)'$5".!$&$`2X;<"7)6$5"*.!2$C+-$.!)$=T!&*+5=$)44)%.8$5)$'))*$.+$*-&5$.!)
#!&*+5$4"-#.8$#+$.!&.$.!)$.)7.$%&'$()$<&"'.)*$+'$.+<$+4$".2

!) effects()$4:'%."+'$-).:-'#$&$6"#.$+4$.)7.$)44)%.#$#:<<+-.)*$(,$.!)$<6:/"'2$ !"#$<6:/"'$#:<<+-.#
.!-))$)44)%.#8$#+$5)$0:#.$-).:-'$&$6"#.$%+'.&"'"'/$.!)$'&9)$+4$)&%!$+')2 QPainterPath path;
path.addText((size.width() - metrics.width(text)) / 2,
size.height() - metrics.descent(), myFont, text);
!) applyEffect()$4:'%."+'$<-+>"*)#$.!)$<6:/"'F#$4:'%."+'&6".,$&'*$"#$#6"/!.6,$"'>+6>)*8$#+$5)$5"66
painter.drawPath(path);
return pixmap;
} Chapter 20. Platform-Specific Features
• :$"#8;15&$'(*&"+(<1"&=#(3,:/
B)$'+5$!&>)$.!)$<)'$&'*$(-:#!)#$#).$&<<-+<-"&.)6,$4+-$)&%!$.)7.$)44)%.8$&'*$"'$.!)$=T!&*+5=$)44)%.
• >/&$'(35"&=#?(6$(9&$%6*/
%&#)$!&>)$*-&5'$.!)$#!&*+52$B)$&-)$'+5$-)&*,$.+$-)'*)-$.!)$.)7.2$ !)$.)7.$"#$!+-"K+'.&66,$%)'.)-)*
• @1$%-&$'(?AA(B#//&6$(01$1'#C#$"
&'*$*-&5'$4&-$)'+:/!$&(+>)$.!)$(+..+9$+4$.!)$<"79&<$.+$&66+5$-++9$4+-$*)#%)'*)-#2
3'$.!"#$%!&<.)-8$5)$5"66$-)>")5$#+9)$+4$.!)$<6&.4+-9;#<)%"4"%$+<."+'#$&>&"6&(6)$.+$E.$<-+/-&99)-#2
Q_EXPORT_PLUGIN2(basiceffectsplugin, BasicEffectsPlugin) B)$()/"'$(,$6++1"'/$&.$!+5$.+$&%%)##$'&.">)$VS3#$#:%!$&#$.!)$B"'Y`$VS3$+'$B"'*+5#8$W&-(+'$+'
J&%$GT$U8$&'*$U6"($+'$UNN2$B)$.!)'$9+>)$+'$.+$)7<6+-)$.!)$V%.">)E.$)7.)'#"+'8$#!+5"'/$!+5$.+$:#)
V%.">)U$%+'.-+6#$5".!"'$E.LB"'*+5#$&<<6"%&."+'#$&'*$!+5$.+$%-)&.)$&<<6"%&."+'#$.!&.$&%.$&#$V%.">)U
#)->)-#2$3'$.!)$6&#.$#)%."+'8$5)$)7<6&"'$!+5$.+$9&1)$E.$&<<6"%&."+'#$%++<)-&.)$5".!$.!)$#)##"+'
V.$.!)$)'*$+4$.!) .cpp$4"6)8$5)$:#)$.!) Q_EXPORT_PLUGIN2()$9&%-+$.+$9&1)$.!)$<6:/"'$&>&"6&(6)$.+$E.2 9&'&/)-$:'*)-$UNN2

!) .pro$4"6)$"#$#"9"6&-$.+$.!)$+')$5)$:#)*$4+-$.!)$B"'*+5#$%:-#+-$<6:/"'$)&-6")-$"'$.!"#$%!&<.)-$P<2 3'$&**"."+'$.+$.!)$4)&.:-)#$<-)#)'.)*$!)-)8$ -+66.)%!$+44)-#$#)>)-&6$<6&.4+-9;#<)%"4"%$E.$T+6:."+'#8


M^_RI "'%6:*"'/$.!)$E.LJ+."4$&'*$E.LJCW$9"/-&."+'$4-&9)5+-1#$.+$)&#)$.!)$9"/-&."+'$+4$J+."4LU.$&'*$JCW
&<<6"%&."+'#$.+$E.2$V$#"9"6&-$)7.)'#"+'$4+-$ %6L 1$&<<6"%&."+'#$"#$<-+>"*)*$(, 2,/*$/*)48$&'*$&
J"%-+#+4.$B"'*+5#$-)#+:-%)$%+'>)-.)-$"#$&>&"6&(6)$4-+9$d6&-e6>*&6)'#$O&.&1+'#:6.2 T))$.!)$4+66+5"'/
TEMPLATE = lib 5)($<&/)#$4+-$*).&"6#I
CONFIG += plugin
HEADERS = ../textart/textartinterface.h \
basiceffectsplugin.h • !..<ILL5552.-+66.)%!2%+9L<-+*:%.#L#+6:."+'#L%&.&6+/L
SOURCES = basiceffectsplugin.cpp • !..<ILL55524-+/6+/"%2%+9L.HL
DESTDIR = ../textart/plugins • !..<ILL55521*&(2').L1':.L

C+-$)9()**)*$*)>)6+<9)'.8$ -+66.)%!$+44)-#$.!)$E.+<"&$&<<6"%&."+'$<6&.4+-92 !"#$"#$%+>)-)*$"'


W!&<.)-$`N2
34$.!"#$%!&<.)-$!&#$5!).$,+:-$&<<).".)$4+-$&<<6"%&."+'$<6:/"'#8$,+:$9"/!.$6"1)$.+$#.:*,$.!)$9+-)
&*>&'%)*$S6:/$c$S&"'.$)7&9<6)$<-+>"*)*$5".!$E.2$ !)$&<<6"%&."+'$#:<<+-.#$.!-))$*"44)-)'.$"'.)-4&%)#
&'*$"'%6:*)#$&$:#)4:6$S6:/"'$3'4+-9&."+'$*"&6+/$.!&.$6"#.# .!)$<6:/"'#$&'*$"'.)-4&%)#$.!&.$&-)$&>&"6&(6)
.+$.!)$&<<6"%&."+'2 Interfacing with Native APIs
E.F#$%+9<-)!)'#">)$VS3$%&.)-#$4+-$9+#.$'))*#$+'$&66$<6&.4+-9#8$(:.$"'$#+9)$%"-%:9#.&'%)#8$5)$9&,
5&'.$.+$:#)$.!)$:'*)-6,"'/$<6&.4+-9;#<)%"4"%$VS3#2$3'$.!"#$#)%."+'8$5)$5"66$#!+5$!+5$.+$:#)$.!)
'&.">)$VS3#$4+-$.!)$*"44)-)'.$<6&.4+-9#$#:<<+-.)*$(,$E.$.+$&%%+9<6"#!$<&-."%:6&-$.&#1#2

G'$)>)-,$<6&.4+-98 QWidget$<-+>"*)#$& winId()$4:'%."+'$.!&.$-).:-'#$.!)$5"'*+5$3O$+-$!&'*6)2


QWidget$&6#+$<-+>"*)#$&$#.&."%$4:'%."+'$%&66)* find()$.!&.$-).:-'#$.!) QWidget$5".! &$<&-."%:6&-
5"'*+5$3O2$B)$%&'$<&##$.!"#$3O$.+$'&.">)$VS3$4:'%."+'#$.+$&%!")>)$<6&.4+-9;#<)%"4"%$)44)%.#2$C+-
)7&9<6)8$.!)$4+66+5"'/$%+*)$:#)# winId()$.+$9+>)$.!)$.".6)$(&-$+4$&$.++6$5"'*+5$.+$.!)$6)4.$:#"'/
'&.">)$J&%$GT$U$4:'%."+'#I

#ifdef Q_WS_MAC
ChangeWindowAttributes(HIViewGetWindow(HIViewRef(toolWin.winId())),
kWindowSideTitlebarAttribute,
kWindowNoAttributes);
#endif

3-4*0$(@I252(C(J1%(!K(F(&::,(L-.+:L(L-&/(&/$(&-&,$("10(:.(&/$('-+$
QPaintEngineF# getdC()$&'* releaseDC()$4:'%."+'#I

void MyWidget::paintEvent(QPaintEvent * /* event */)


{
QPainter painter(this);
painter.fillRect(rect().adjusted(20, 20, -20, -20), Qt::red);
#ifdef Q_WS_WIN
HDC hdc = painter.paintEngine()->getDC();
Rectangle(hdc, 40, 40, width() - 40, height() - 40);
painter.paintEngine()->releaseDC();
#endif
}

J"7"'/ QPainter$&'*$@O3$%&66#$6"1)$.!"#$%&'$#+9)."9)#$6)&*$.+$#.-&'/)$-)#:6.#8$)#<)%"&66,$5!)'
QPainter$%&66#$+%%:-$&4.)-$@O3$%&66#8$()%&:#) QPainter$9&1)#$#+9)$&##:9<."+'# &(+:.$.!)$#.&.)$+4
.!)$:'*)-6,"'/$*-&5"'/$6&,)-2

E.$*)4"')#$+')$+4$.!)$4+66+5"'/$4+:-$5"'*+5$#,#.)9$#,9(+6#I Q_WS_WIN8 Q_WS_X118 Q_WS_MAC8$&'*


Q_WS_QWS$PE.+<"&R2$B)$9:#.$"'%6:*)$&.$6)&#.$+')$E.$!)&*)-$()4+-)$5)$%&'$:#)$.!)9$"'$&<<6"%&."+'#2
E.$&6#+$<-+>"*)#$<-)<-+%)##+-$#,9(+6#$.+$"*)'."4,$.!)$+<)-&."'/$#,#.)9I

• Q_OS_AIX
• Q_OS_BSD4
G'$UNN8$!)-)F#$!+5$5)$5+:6*$9+*"4,$&$5"'*+5$<-+<)-.,I • Q_OS_BSDI
• Q_OS_CYGWIN
• Q_OS_DGUX
#ifdef Q_WS_X11 • Q_OS_DYNIX
Atom atom = XInternAtom(QX11Info::display(), "MY_PROPERTY", False); • Q_OS_FREEBSD
long data = 1; • Q_OS_HPUX
XChangeProperty(QX11Info::display(), window->winId(), atom, atom, • Q_OS_HURD
32, PropModeReplace,
• Q_OS_IRIX
reinterpret_cast<uchar *>(&data), 1);
#endif • Q_OS_LINUX
• Q_OS_LYNX
• Q_OS_MAC
• Q_OS_NETBSD
!) #ifdef$&'* #endif$*"-)%.">)#$&-+:'*$.!)$<6&.4+-9;#<)%"4"%$%+*)$)'#:-)$.!&.$.!)$&<<6"%&."+'$5"66
• Q_OS_OPENBSD
#."66$%+9<"6)$+'$+.!)-$<6&.4+-9#2
• Q_OS_OS2EMX
• Q_OS_OSF
C+-$&$B"'*+5#;+'6,$&<<6"%&."+'8$!)-)F#$&'$)7&9<6)$+4$!+5$5)$%&'$:#)$@O3$%&66#$.+$*-&5$+'$&$E.
• Q_OS_QNX6
5"*/).I
• Q_OS_QNX
• Q_OS_RELIANT
void GdiControl::paintEvent(QPaintEvent * /* event */) • Q_OS_SCO
{ • Q_OS_SOLARIS
RECT rect; • Q_OS_ULTRIX
GetClientRect(winId(), &rect); • Q_OS_UNIXWARE
HDC hdc = GetDC(winId()); • Q_OS_WIN32
FillRect(hdc, &rect, HBRUSH(COLOR_WINDOW + 1)); • Q_OS_WIN64
SetTextAlign(hdc, TA_CENTER | TA_BASELINE);
TextOutW(hdc, width() / 2, height() / 2, text.utf16(), text.size());
ReleaseDC(winId(), hdc); B)$%&'$&##:9)$.!&.$&.$9+#.$+')$+4$.!)#)$5"66$()$*)4"')*2$C+-$%+'>)'")'%)8$E.$&6#+$*)4"')# Q_OS_WIN
} 5!)'$)".!)-$B"'Y`$+-$B"'fM$"#$*).)%.)*8$&'* Q_OS_UNIX$5!)'$&',$A'"7;(&#)*$+<)-&."'/$#,#.)9
P"'%6:*"'/$Q"':7$&'*$J&%$GT$UR$"#$*).)%.)*2$V.$-:';."9)8$5)$%&'$%!)%1 QSysInfo::WindowsVersion$+-
QSysInfo:: MacintoshVersion$.+$*"#."'/:"#!$().5))'$*"44)-)'.$>)-#"+'#$+4$B"'*+5#$P`^^^8$JZ8$).%2R
+-$J&%$GT$U$PN^2`8$N^2Y8$).%2R2
C+-$.!"#$.+$5+-18$5)$9:#.$&6#+$-)"9<6)9)'. QPaintDevice::paintEngine()$.+$-).:-'$&$':66$<+"'.)-$&'*
#).$.!) Qt::WA_PaintOnScreen$&..-"(:.)$"'$.!)$5"*/).F#$%+'#.-:%.+-2
3'$&**"."+'$.+$.!)$+<)-&."'/$#,#.)9$&'*$5"'*+5$#,#.)9$9&%-+#8$.!)-)$"#$&6#+$&$#).$+4$%+9<"6)-
9&%-+#2$C+-$)7&9<6)8 Q_CC_MSVC$"#$*)4"')*$"4$.!)$%+9<"6)-$"#$J"%-+#+4.$g"#:&6$Whh2$ !)#)$%&'$()
!)$')7.$)7&9<6)$#!+5#$!+5$.+$%+9("') QPainter$&'*$@O3$%&66#$"'$&$<&"'.$)>)'.$!&'*6)-$:#"'/
:#)4:6$4+-$5+-1"'/$&-+:'*$%+9<"6)-$(:/#2
T)>)-&6$+4$E.F#$@A3;-)6&.)*$%6&##)#$<-+>"*)$<6&.4+-9;#<)%"4"%$4:'%."+'#$.!&.$-).:-'$6+5;6)>)6$!&'*6)#
.+$.!)$:'*)-6,"'/$+(0)%.2$ !)#)$&-)$6"#.)*$"' C"/:-)$`^2`2 G'$UNN8 QPixmap::x11Info()$&'* QWidget::x11Info()$-).:-'$& QX11Info$+(0)%.$.!&.$<-+>"*)#$>&-"+:#
<+"'.)-#$+-$!&'*6)#8$#:%!$&# display()8 screen()8 colormap()8$&'* visual()2$B)$%&'$:#)$.!)#)$.+$#).
3-4*0$(@I2@2(=,1&B:0)M'7$%-B-%(B*.%&-:.'(&:(1%%$''(,:LM,$N$,(/1.+,$' :<$&'$UNN$/-&<!"%#$%+'.)7.$+'$& QPixmap$+- QWidget8$4+-$)7&9<6)2

E.$&<<6"%&."+'#$.!&.$'))*$.+$"'.)-4&%)$5".!$+.!)-$.++61".#$+-$6"(-&-")#$4-)H:)'.6,$'))*$.+$&%%)##$.!)
J&%$GT$U 6+5;6)>)6$)>)'.#$PXEvent#$+'$UNN8 MSG#$+'$B"'*+5#8 Eventref$+'$J&%$GT$U8 QWSEvent#$+'$E.+<"&R
V TC+'.C+-9&.])4 EC+'.II!&'*6)PR ()4+-)$.!),$&-)$%+'>)-.)*$"'.+ QEvent#2$B)$%&'$*+$.!"#$(,$#:(%6&##"'/ QApplication$&'*
-)"9<6)9)'."'/$.!)$-)6)>&'.$<6&.4+-9;#<)%"4"%$)>)'.$4"6.)-8$+')$+4 x11EventFilter()8
W@39&/)])4 ES"79&<II9&%W@[&'*6)PR winEventFilter()8 macEventFilter()8$&'* qwsEventFilter()2$V6.)-'&.">)6,8$5)$%&'$&%%)##$.!)
<6&.4+-9;#<)%"4"%$)>)'.#$.!&.$&-)$#)'.$.+$&$/">)' QWidget$(,$-)"9<6)9)'."'/$+')$+4 x11Event()8
@B+-6*S.- ES"79&<II9&%EOV6<!&[&'*6)PR winEvent()8 macEvent()8$&'* qwsEvent()2$ !"#$%&'$()$:#)4:6$4+-$!&'*6"'/$%)-.&"'$.,<)#$+4$)>)'.#$.!&.
E.$'+-9&66,$"/'+-)#8$#:%!$&#$0+,#."%1$)>)'.#2
@B+-6*S.- ES"79&<II9&%EO[&'*6)PR
]/'[&'*6) E])/"+'II!&'*6)PR C+-$9+-)$"'4+-9&."+'$&(+:.$<6&.4+-9;#<)%"4"%$"##:)#8$"'%6:*"'/$!+5$.+$*)<6+,$E.$&<<6"%&."+'#$+'
*"44)-)'.$<6&.4+-9#8$#)) !..<ILL*+%2.-+66.)%!2%+9LM2NL5"'#,#.)92!.962
[3g")5])4 EB"*/).II5"'3*PR

B"'*+5# Using ActiveX on Windows


[WA]TG] EW:-#+-II!&'*6)PR J"%-+#+4.F#V%.">)U$.)%!'+6+/,$&66+5#$&<<6"%&."+'#.+$"'%+-<+-&.)$:#)-$"'.)-4&%)$%+9<+')'.#$<-+>"*)*
(,$+.!)-$&<<6"%&."+'#$+-$6"(-&-")#2$3.$"#$(:"6.$+'$J"%-+#+4.$WGJ$&'*$*)4"')#$+')$#).$+4$"'.)-4&%)#$4+-
[OW ES&"'.Z'/"')II/).OWPR &<<6"%&."+'#$.!&.$:#)$%+9<+')'.#$&'*$&'+.!)-$#).$+4$"'.)-4&%)#$4+-$&<<6"%&."+'#$&'*$6"(-&-")#$.!&.
<-+>"*)$%+9<+')'.#2
[OW ES-"'.Z'/"')II/).S-"'.)-OWPR
[CG? EC+'.II!&'*6)PR !)$E.LB"'*+5#$O)#1.+<$Z*"."+'$<-+>"*)#$.!)$V%.">)E.$4-&9)5+-1$.+$#)&9;6)##6,$%+9("')$V%.">)U
&'*$E.2 V%.">)E.$%+'#"#.#$+4$.5+$9+*:6)#I
[SVQZ Z EW+6+-9&<II!S&6PR
• !) 567/+!3)+',$9+*:6)$&66+5#$:#$.+$:#)$WGJ$+(0)%.#$&'*$.+$)9()*$V%.">)U$%+'.-+6#$"'
[]@? E])/"+'II!&'*6)PR E.$&<<6"%&."+'#2
[B?O EB"*/).II5"'3*PR • !) 56"',8',$9+*:6)$&66+5#$:#$.+$)7<+-.$%:#.+9$WGJ$+(0)%.#$&'*$V%.">)U$%+'.-+6#$5-"..)'
:#"'/$E.2

UNN G:-$4"-#.$)7&9<6)$5"66$)9()*$.!)$B"'*+5#$J)*"&$S6&,)-$"'$&$E.$&<<6"%&."+'$:#"'/$.!) 567/+!3)+',


9+*:6)2$ !)$E.$&<<6"%&."+'$&**#$&'$G<)'$(:..+'8$&$S6&,LS&:#)$(:..+'8$&$T.+<$(:..+'8$&'*$&$#6"*)-$.+
W:-#+- EW:-#+-II!&'*6)PR .!)$B"'*+5#$J)*"&$S6&,)-$V%.">)U$%+'.-+62

C+'. EC+'.II!&'*6)PR 3-4*0$(@I2H2(A/$(J$+-1(=,1O$0(177,-%1&-:.


S"%.:-) ES"79&<II7NNS"%.:-)[&'*6)PR
S"%.:-) EB"*/).II7NNS"%.:-)[&'*6)PR
S"79&< ES"79&<II!&'*6)PR
EUNN3'4+ ES"79&<II7NN3'4+PR
EUNN3'4+ EB"*/).II7NN3'4+PR
])/"+' E])/"+'II!&'*6)PR
T%-))' EW:-#+-II7NNT%-))'PR
T9%W+'' ET)##"+'J&'&/)-II!&'*6)PR
B"'*+5 EB"*/).II!&'*6)PR
B"'*+5 EB"*/).II5"'3*PR
!)$&<<6"%&."+'F#$9&"'$5"'*+5$"#$+4$.,<) PlayerWindowI

class PlayerWindow : public QWidget


{
Q_OBJECT
Q_ENUMS(ReadyStateConstants)
public:
enum PlayStateConstants { Stopped = 0, Paused = 1, Playing = 2 }; !)$WGJ$*&.&$.,<)#$&-)$&:.+9&."%&66,$%+'>)-.)*$"'.+$.!)$%+--)#<+'*"'/$E.$.,<)#8$&#$#:99&-"K)*$"'
enum ReadyStateConstants { Uninitialized = 0, Loading = 1,
C"/:-)$`^2X2$C+-$)7&9<6)8$&'$"';<&-&9).)-$+4$.,<) VARIANT_BOOL$()%+9)#$& bool8$&'*$&'$+:.;
Interactive = 3, Complete = 4 };
PlayerWindow(); <&-&9).)-$+4$.,<) VARIANT_BOOL$()%+9)#$& bool &2$34$.!)$-)#:6."'/$.,<)$"#$&$E.$%6&##$PQString8
protected: QDateTime8$).%2R8$.!)$"';<&-&9).)-$"#$&$%+'#.$-)4)-)'%)$P4+-$)7&9<6)8 const QString &R2
void timerEvent(QTimerEvent *event);
private slots: 3-4*0$(@I2R2(G$,1&-:.'/-7("$&L$$.(;!J(&O7$'(1.+( &(&O7$'
void onPlayStateChange(int oldState, int newState);
void onReadyStateChange(ReadyStateConstants readyState);
void onPositionChange(double oldPos, double newPos); !"#$%&'( )$#$%&'(
void sliderValueChanged(int newValue);
void openFile(); !"#!$%&'(() *++,
private:
QAxWidget *wmp; char- short- int- long int
QToolButton *openButton;
QToolButton *playPauseButton; unsigned char- unsigned short- unsigned int- unsigned uint
QToolButton *stopButton; long
QSlider *seekSlider;
QString fileFilters; float- double double
int updateTimer;
}; CY qlonglong- qulonglong
BSTR QString
!) PlayerWindow$%6&##$"'!)-".#$4-+9 QWidget2$ !) Q_ENUMS()$9&%-+$P0:#.$()6+5 Q_OBJECTR$"# DATE QDateTime- QDate-
')%)##&-,$.+$.)66 moc$.!&.$.!) ReadyStateConstants$.,<)$:#)*$"'$.!) onReadyStateChange()$#6+.$"#$&' QTime
)':9$.,<)2$3'$.!)$<-">&.)$#)%."+'8$5)$*)%6&-)$& QAxWidget *$*&.&$9)9()-2
OLE_COLOR QColor
SAFEARRAY(VARIANT) QList<QVariant>
PlayerWindow::PlayerWindow()
{ SAFEARRAY(BSTR) QStringList
wmp = new QAxWidget;
wmp->setControl("{22D6F312-B0F6-11D0-94AB-0080C74C7E95}"); SAFEARRAY(BYTE) QByteArray
VARIANT QVariant
3'$.!)$%+'#.-:%.+-8$5)$#.&-.$(,$%-)&."'/$& QAxWidget$+(0)%.$.+$)'%&<#:6&.)$.!)$B"'*+5#$J)*"&$S6&,)- IFontDisp * QFont
V%.">)U$%+'.-+62$ !) 567/+!3)+',$9+*:6)$%+'#"#.#$+4$.!-))$%6&##)#I QAxObject$)'%&<#:6&.)#$&$WGJ
IPictureDisp * QPixmap
+(0)%.8 QAxWidget$)'%&<#:6&.)#$&'$V%.">)U$%+'.-+68$&'* QAxBase$"9<6)9)'.#$.!)$%+-)$WGJ
4:'%."+'&6".,$4+- QAxObject$&'* QAxWidget2 ./012304560327890 QRect- QSize- QPoint

B)$%&66 setControl()$+'$.!) QAxWidget$5".!$.!)$%6&##$3O$+4$.!)$B"'*+5#$J)*"&$S6&,)-$f2M$%+'.-+62


!"#$5"66$%-)&.)$&'$"'#.&'%)$+4$.!)$-)H:"-)*$%+9<+')'.2$C-+9$.!)'$+'8$&66$.!)$<-+<)-.")#8$)>)'.#8$&'*
9).!+*# +4$.!)$V%.">)U$%+'.-+6$&-)$&>&"6&(6)$&#$E.$<-+<)-.")#8$#"/'&6#8$&'*$#6+.#$.!-+:/!$.!)
QAxWidget$+(0)%.2 %+2+*7:5627;02,5/72+42:,,27;0291+901750/-2/5<6:,/-2:632/,+7/2:=:5,:*,02562: QAxObject2+1 QAxWidget2>57;
7;0512?723:7:27890/-2@:,, QAxBase::generateDocumentation()2+12A/02?7B/ dumpdoc2@+CC:63D,56027++,-
3-4*0$(@I2P2(Q./$0-&1.%$(&0$$(B:0(&/$ )3!D6$"1&$#8():+*,$ ,+@:7032562?7B/ tools\activeqt\dumpdoc23510@7+18E

)07B/2@+6756A02>57;27;0 PlayerWindow2@+6/71A@7+1F

wmp->setProperty("ShowControls", false);
wmp->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(wmp, SIGNAL(PlayStateChange(int, int)),
this, SLOT(onPlayStateChange(int, int))); :1<AC067/27+27;02C07;+32:/2:33575+6:,29:1:C0701/E2T+120K:C9,0F
connect(wmp, SIGNAL(ReadyStateChange(ReadyStateConstants)),
this, SLOT(onReadyStateChange(ReadyStateConstants)));
connect(wmp, SIGNAL(PositionChange(double, double)), wmp->dynamicCall("TitlePlay(uint)", 6);
this, SLOT(onPositionChange(double, double)));

%;0 dynamicCall()24A6@75+627:L0/2A927+205<;729:1:C0701/2+427890 QVariant2:632107A16/2: QVariantE2#4


!47012@:,,56< QAxWidget::setControl()-2>02@:,, QObject::setProperty()27+2/0727;0 ShowControls >02600327+29://2:6 IDispatch *2+12:6 IUnknown *27;5/2>:8-2>02@:6206@:9/A,:7027;02@+C9+60672562:
91+901782+427;02G563+>/2H035:2I,:80127+ false-2/56@02>0291+=5302+A12+>62*A77+6/27+2C:659A,:7027;0 QAxObject2:632@:,, asVariant()2+625727+2@+6=01725727+2: QVariantE2#42>02600327+2@:,,2:2J(H2C07;+3
@+C9+6067E QObject::setProperty()2@:62*02A/032*+7;24+12J(H291+901750/2:6324+126+1C:,2?7 7;:72107A16/2:6 IDispatch *2+12:6 IUnknown *-2+12542>02600327+2:@@0//2:2J(H291+901782+42+602+4
91+901750/E2#7/2/0@+6329:1:C070125/2+427890 QVariantE 7;+/027890/-2>02@:62A/0 querySubObject()256/70:3F

$0K7-2>02@:,, setSizePolicy()27+2C:L027;02!@75=0M2@+671+,27:L02:,,27;02:=:5,:*,02/9:@0256 7;02,:8+A7-


:632>02@+660@727;1002!@75=0M20=067/241+C27;02J(H2@+C9+606727+27;1002/,+7/E QAxObject *session = outlook.querySubObject("Session");
QAxObject *defaultContacts =
session->querySubObject("GetDefaultFolder(OlDefaultFolders)",
... "olFolderContacts");
stopButton = new QToolButton;
stopButton->setText(tr("&Stop"));
stopButton->setEnabled(false);
connect(stopButton, SIGNAL(clicked()), wmp, SLOT(Stop())); #42>02>:6727+2@:,,2C07;+3/27;:72;:=02A6/A99+170323:7:27890/25627;05129:1:C07012,5/7-2>02@:62A/0
... QAxBase::queryInterface()27+2107150=027;02J(H2567014:@02:632@:,,27;02C07;+323510@7,8E2!/2A/A:,2>57;
} J(H-2>02CA/72@:,, Release()2>;062>02;:=024565/;032A/56<27;02567014:@0E2#42>02+47062600327+2@:,,
/A@;2C07;+3/-2>02@:62/A*@,:// QAxObject2+1 QAxWidget2:63291+=5302C0C*0124A6@75+6/27;:7
06@:9/A,:7027;02J(H2567014:@02@:,,/E2'02:>:1027;:7 QAxObject2:63 QAxWidget2/A*@,://0/2@:66+7
30456027;0512+>6291+901750/-2/5<6:,/-2+12/,+7/E
%;0210/72+427;0 PlayerWindow2@+6/71A@7+124+,,+>/27;02A/A:,29:77016-20K@09727;:72>02@+660@72/+C02?7
/5<6:,/27+2/,+7/291+=53032*827;02J(H2+*N0@72OPlay()- Pause()-2:63 Stop()PE2Q56@027;02*A77+6/2:10
/5C5,:1-2>02;:=02+6,82/;+>627;02Q7+92*A77+6B/25C9,0C067:75+62;010E G02>5,,26+>210=50>27;0 !"+)*,)*2C+3A,0E2%;5/2C+3A,0206:*,0/2A/27+27A162:2/7:63:132?7291+<1:C
567+2:62!@75=0M2/01=01E2%;02/01=012@:62057;012*02:2/;:1032,5*1:182+12:2/7:63D:,+602:99,5@:75+6E
Q01=01/2*A5,72:/2/;:1032,5*1:150/2:102+47062@:,,03256D91+@0//2/01=01/U2/7:63D:,+602:99,5@:75+6/2:10
)07B/2,0:=027;02@+6/71A@7+12:632,++L2:727;0 timerEvent()24A6@75+6F
@:,,032+A7D+4D91+@0//2/01=01/E

void PlayerWindow::timerEvent(QTimerEvent *event) (A12451/7 !"+)*,)*20K:C9,025/2:6256D91+@0//2/01=0127;:7291+=530/2:2>53<0727;:72/;+>/2:2*:,,


{ *+A6@56<2,0472:63215<;7E2G02>5,,2:,/+2/002;+>27+20C*0327;02>53<072562#67016072VK9,+101E
if (event->timerId() == updateTimer) {
double curPos = wmp->property("CurrentPosition").toDouble(); W010B/27;02*0<56656<2+427;02@,://230456575+62+427;0 AxBouncer2>53<07F
onPositionChange(-1, curPos);
} else {
QWidget::timerEvent(event); class AxBouncer : public QWidget, public QAxBindable
} {
} Q_OBJECT
Q_ENUMS(SpeedValue)
Q_PROPERTY(QColor color READ color WRITE setColor)
%;0 timerEvent()24A6@75+625/2@:,,032:7210<A,:1256701=:,/2>;5,02:2C035:2@,5925/29,:856<E2G02A/025727+ Q_PROPERTY(SpeedValue speed READ speed WRITE setSpeed)
Q_PROPERTY(int radius READ radius WRITE setRadius)
:3=:6@027;02/,5301E2%;5/25/23+602*82@:,,56< property() +627;02!@75=0M2@+671+,27+2+*7:5627;02=:,A02+4
Q_PROPERTY(bool running READ isRunning)
7;0 CurrentPosition291+901782:/2: QVariant2:632@:,,56< toDouble()27+2@+6=01725727+2: doubleE2G027;06
@:,, onPositionChange()27+29014+1C27;02A93:70E

AxBouncer256;0157/241+C2*+7; QWidget2:63 QAxBindableE2%;0 QAxBindable2@,://291+=530/2:62567014:@0


G02>5,,26+7210=50>27;0210/72+427;02@+302*0@:A/02C+/72+425725/6B723510@7,8210,0=:6727+2!@75=0M2:63
3+0/6B72/;+>2:687;56<27;:72>02;:=06B72@+=01032:,10:38E2%;02@+3025/256@,A3032+627;02JRE *07>00627;02>53<072:632:62!@75=0M2@,5067E2!68 QWidget2@:62*020K9+17032:/2:62!@75=0M2@+671+,-2*A72*8
/A*@,://56< QAxBindable2>02@:626+754827;02@,50672>;062:291+90178B/2=:,A02@;:6<0/-2:632>02@:6
5C9,0C0672J(H2567014:@0/27+2/A99,0C06727;+/02:,10:3825C9,0C067032*8 !"+)*,)*E
#627;0 .pro245,0-2>02600327;5/20671827+2,56L2>57;27;0 !"#$%&'(%)*2C+3A,0F

*+,-.'#/0121#34' AxBouncer#5+6,'$#+7#87$'.7'$#9:&;<.'.
CONFIG += qaxcontainer

(602410SA067260032>;06230:,56<2>57;2J(H2+*N0@7/25/27+2*02:*,027+2@:,,2:2J(H2C07;+323510@7,82O:/
+99+/0327+2@+660@756<25727+2:2?72/5<6:,PE2%;020:/50/72>:827+23+27;5/25/27+256=+L0
QAxBase::dynamicCall()2>57;27;026:C02:632/5<6:7A102+427;02C07;+32:/2451/729:1:C07012:6327;0
7;5/2/5<6:7A10E

%;0 createAggregate()24A6@75+625/2105C9,0C06703241+C QAxBindableE2G02>5,,20K9,:56257 562:2C+C067E

protected:
void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *event);
private:
int intervalInMilliseconds() const;
QColor ballColor;
SpeedValue ballSpeed;
int ballRadius;
int myTimerId;
int x;
int delta;
};

%;0291+70@7032:632915=:702/0@75+6/2+427;02@,://2:1027;02/:C02:/27;+/02>02>+A,32;:=025427;5/2>:/2:
/7:63:132?72>53<07E

AxBouncer::AxBouncer(QWidget *parent)
: QWidget(parent)
{
ballColor = Qt::blue;
ballSpeed = Normal;
ballRadius = 15;
myTimerId = 0;
x = 20;
delta = 2;
}
G;0623+56<2CA,759,0256;0157:6@0256=+,=56<2: QObjectD3015=032@,://-2>02CA/72:,>:8/29A727;0 QObjectD
3015=032@,://2451/72/+27;:7 moc2@:6295@L2572A9E
%;0 AxBouncer2@+6/71A@7+1256575:,5X0/27;02@,://B/2915=:702=:15:*,0/E
G0230@,:1027;100210:3D>1570291+901750/2:632+60210:3D+6,8291+90178E2%;0 Q_ENUMS()2C:@1+25/
60@0//:1827+270,, moc27;:727;0 SpeedValue2789025/2:6206AC27890E2%;0206AC25/230@,:10325627;029A*,5@
/0@75+62+427;02@,://F void AxBouncer::setColor(const QColor &newColor)
{
if (newColor != ballColor && requestPropertyChange("color")) {
public: ballColor = newColor;
enum SpeedValue { Slow, Normal, Fast }; update();
AxBouncer(QWidget *parent = 0); propertyChanged("color");
void setSpeed(SpeedValue newSpeed); }
SpeedValue speed() const { return ballSpeed; } }
void setRadius(int newRadius);
int radius() const { return ballRadius; }
void setColor(const QColor &newColor); %;0 setColor()24A6@75+62/07/27;02=:,A02+427;0 color291+90178E2#72@:,,/ update()27+2109:56727;02>53<07E
QColor color() const { return ballColor; }
bool isRunning() const { return myTimerId != 0; }
QSize sizeHint() const; %;02A6A/A:,29:1725/27;0 requestPropertyChange()2:63 propertyChanged()2@:,,/E2%;0/024A6@75+6/2:10
QAxAggregated *createAggregate(); 56;015703241+C QAxBindable2:632/;+A,32530:,,82*02@:,,032>;060=012>02@;:6<02:291+90178E2%;0
public slots: requestPropertyChange()2:/L/27;02@,5067B/2901C5//5+627+2@;:6<02:291+90178-2:632107A16/ true25427;0
void start(); @,50672:,,+>/27;02@;:6<0E2%;0 propertyChanged()24A6@75+626+75450/27;02@,506727;:727;0291+901782;:/
void stop(); *0062@;:6<03E
signals:
void bouncing(); %;0 setSpeed()2:63 setRadius()291+901782/07701/2:,/+24+,,+>27;5/29:77016-2:632/+23+27;0 start()2:63
stop()2/,+7/-2/56@027;082@;:6<027;02=:,A02+427;0 running291+90178E

%;0 AxBouncer2@+6/71A@7+125/2:2/7:63:132@+6/71A@7+124+12:2>53<07-2>57;2: parent29:1:C0701E2%;0 %;01025/2+60 567010/756< AxBouncer2C0C*0124A6@75+62,047F


QAXFACTORY_DEFAULT()2C:@1+-2>;5@;2>02>5,,2A/027+20K9+1727;02@+C9+6067-20K90@7/2:2@+6/71A@7+12>57;
QAxAggregated *AxBouncer::createAggregate() }
{ HRESULT WINAPI ObjectSafetyImpl::SetInterfaceSafetyOptions(
return new ObjectSafetyImpl; REFIID /* riid */, DWORD /* pdwSupportedOptions */,
} DWORD /* pdwEnabledOptions */)
{
return S_OK;
}
%;0 createAggregate()24A6@75+625/2105C9,0C06703241+C QAxBindableE2#72:,,+>/2A/27+25C9,0C0672J(H
567014:@0/27;:727;0 !"+)*,)*2C+3A,023+0/6B72:,10:3825C9,0C0672+127+2*89:// !"+)*,)*B/2304:A,7
J(H2567014:@0/E2W010-2>023+25727+291+=53027;0 IObjectSafety2567014:@0-2>;5@;25/2A/032*82#6701607
VK9,+10127+2:@@0//2:2@+C9+6067B/2/:40782+975+6/E2%;5/25/27;02/7:63:132715@L27+2<0721532+42#6701607 %;0 GetInterfaceSafetyOptions()2:63 SetInterfaceSafetyOptions()24A6@75+6/2:10230@,:103256
VK9,+101B/2564:C+A/2Y(*N0@726+72/:4024+12/@159756<Y2011+12C0//:<0E IObjectSafetyE2G025C9,0C06727;0C27+270,,27;02>+1,327;:72+A12+*N0@725/2/:4024+12/@159756<E

W010B/27;0230456575+62+427;02@,://27;:725C9,0C067/27;0 IObjectSafety2567014:@0F )07B/26+>210=50> main.cppF

class ObjectSafetyImpl : public QAxAggregated, public IObjectSafety #include <QAxFactory>


{ #include "axbouncer.h"
public: QAXFACTORY_DEFAULT(AxBouncer,
long queryInterface(const QUuid &iid, void **iface); "{5e2461aa-a3e8-4f7a-8b04-307459a4c08c}",
QAXAGG_IUNKNOWN "{533af11f-4899-43de-8b7f-2ddf588d1015}",
HRESULT WINAPI GetInterfaceSafetyOptions(REFIID riid, "{772c14a5-a840-4023-b79d-19549ece0cd9}",
DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions); "{dbce1e56-70dd-4f74-85e0-95c65d86254d}",
HRESULT WINAPI SetInterfaceSafetyOptions(REFIID riid, "{3f3db5e0-78ff-4e35-8a5d-3d3b96c83e09}")
DWORD pdwSupportedOptions, DWORD pdwEnabledOptions);
};
%;0 QAXFACTORY_DEFAULT()2C:@1+20K9+17/2:62!@75=0M2@+671+,E2G02@:62A/025724+12!@75=0M2/01=01/27;:7
0K9+172+6,82+602@+671+,E2%;0260K720K:C9,025627;5/2/0@75+62>5,,2/;+>2;+>27+20K9+172C:682!@75=0M
%;0 ObjectSafetyImpl2@,://256;0157/2*+7; QAxAggregated2:63 IObjectSafetyE2%;0 QAxAggregated2@,:// @+671+,/E
5/2:62:*/71:@72*:/02@,://24+125C9,0C067:75+6/2+42:33575+6:,2J(H2567014:@0/E2%;02J(H2+*N0@727;:727;0
QAxAggregated20K7063/25/2:@@0//5*,027;1+A<; controllingUnknown()E2%;5/2J(H2+*N0@725/2@10:703 %;02451/72:1<AC06727+ QAXFACTORY_DEFAULT()25/27;026:C02+427;02?72@,://27+20K9+17E2%;5/25/2:,/+27;0
*0;56327;02/@060/2*827;0 !"+)*,)*2C+3A,0E 6:C02A63012>;5@;27;02@+671+,25/20K9+1703E2%;02+7;01245=02:1<AC067/2:1027;02@,://2#R-27;02567014:@0
#R-27;020=0672567014:@02#R-27;0278902,5*1:182#R-2:6327;02:99,5@:75+62#RE2G02@:62A/02/7:63:1327++,/2,5L0
%;0 QAXAGG_IUNKNOWN2C:@1+291+=530/2/7:63:1325C9,0C067:75+6/2+4 QueryInter-face()- AddRef()-2:63 guidgen2+1 uuidgen27+2<0601:7027;0/025306754501/E2'0@:A/027;02/01=0125/2:2,5*1:18-2>023+6B7260032:
Release()E2%;0/025C9,0C067:75+6/2/5C9,82@:,,27;02/:C024A6@75+6/2+627;02@+671+,,56<2J(H2+*N0@7E main()24A6@75+6E

W010B/27;0 .pro245,024+12+A1256D91+@0//2!@75=0M2/01=01F
long ObjectSafetyImpl::queryInterface(const QUuid &iid, void **iface)
{
*iface = 0; TEMPLATE = lib
if (iid == IID_IObjectSafety) { CONFIG += dll qaxserver
*iface = static_cast<IObjectSafety *>(this); HEADERS = axbouncer.h \
} else { objectsafetyimpl.h
return E_NOINTERFACE; SOURCES = axbouncer.cpp \
} main.cpp \
AddRef(); objectsafetyimpl.cpp
return S_OK; RC_FILE = qaxserver.rc
} DEF_FILE = qaxserver.def

%;0 queryInterface()24A6@75+625/2:29A102=517A:,24A6@75+62+4 QAxAggregatedE2#725/2@:,,032*827;0 %;0 qaxserver.rc2:63 qaxserver.def245,0/21040110327+25627;0 .pro245,02:102/7:63:13245,0/27;:72@:62*0


@+671+,,56<2J(H2+*N0@727+2<5=02:@@0//27+27;02567014:@0/291+=53032*827;0 QAxAggregated2/A*@,://E2G0 @+9503241+C2?7B/ src\activeqt\control23510@7+18E
CA/72107A16 E_NOINTERFACE24+12567014:@0/27;:72>023+6B725C9,0C0672:6324+1 IUnknownE
%;02C:L045,02+1 5/A:,2JZZ291+N0@7245,02<0601:7032*8 qmake2@+67:56/21A,0/27+210<5/70127;02/01=01256
7;02G563+>/210<5/718E2%+210<5/70127;02/01=012+62063DA/012C:@;560/-2>02@:62A/027;0 regsvr3227++,
HRESULT WINAPI ObjectSafetyImpl::GetInterfaceSafetyOptions(
:=:5,:*,02+62:,,2G563+>/2/8/70C/E
REFIID /* riid */, DWORD *pdwSupportedOptions,
DWORD *pdwEnabledOptions)
{ G02@:627;06256@,A3027;02'+A6@012@+C9+6067 562:62W%H)29:<02A/56<27;0 <object>27:<F
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA
| INTERFACESAFE_FOR_UNTRUSTED_CALLER;
*pdwEnabledOptions = *pdwSupportedOptions; <object id="AxBouncer"
return S_OK; classid="clsid:5e2461aa-a3e8-4f7a-8b04-307459a4c08c">
<b>The ActiveX control is not available. Make sure you have built and • G02@:62A/027;0 QAXFACTORY_BEGIN()- QAXFACTORY_END()- QAXCLASS()-2:63 QAX-TYPE()2C:@1+/27+
registered the component server.</b> 30@,:102:63210<5/70127;024:@7+18E2%;5/2:991+:@;210SA510/2A/27+2/90@54827;02@,://2:632567014:@0
</object> #R/2A/56< Q_CLASSINFO()E

':@L27+27;0 AddressBook2@,://230456575+6F2%;027;5132+@@A1106@02+4 Q_CLASSINFO()2C:82/00C2:2*57


G02@:62@10:702*A77+6/27;:7256=+L02/,+7/F C8/7015+A/E2'82304:A,7-2!@75=0M2@+671+,/20K9+/026+72+6,827;0512+>6291+901750/- /5<6:,/-2:632/,+7/27+
@,5067/-2*A72:,/+27;+/02+427;0512/A901@,://0/2A927+ QWidgetE2%;0 ToSuperClass2:7715*A702,07/2A/2/90@548
7;02;5<;0/72/A901@,://2O5627;0256;0157:6@027100P27;:72>02>:6727+20K9+/0E2W010-2>02/90@54827;02@,://
<input type="button" value="Start" onClick="AxBouncer.start()"> 6:C02+427;02@+C9+60672OAddressBookP2:/27;02;5<;0/72/A901@,://27+20K9+17-2C0:656<27;:7291+901750/-
<input type="button" value="Stop" onClick="AxBouncer.stop()">
/5<6:,/-2:632/,+7/23045603256 AddressBookB/2/A901@,://0/2>5,,26+72*020K9+1703E

G02@:62C:659A,:7027;02>53<072A/56<2[:=:Q@15972+12 'Q@15972NA/72,5L02:682+7;012!@75=0M2@+671+,E2Q00 class ABItem : public QObject, public QTreeWidgetItem


7;0 demo.html245,02+627;02JR24+12:21A35C067:1829:<027;:72A/0/27;02!@75=0M2/01=01E {
Q_OBJECT
(A12,:/720K:C9,025/2:2/@1597:*,02!3310//2'++L2:99,5@:75+6E2%;02:99,5@:75+62@:62/01=02:/2:2/7:63:13 Q_PROPERTY(QString contact READ contact WRITE setContact)
?7\G563+>/2:99,5@:75+62+12:62+A7D+4D91+@0//2!@75=0M2/01=01E2%;02,:770129+//5*5,5782:,,+>/2A/27+2/@1597 Q_PROPERTY(QString address READ address WRITE setAddress)
Q_PROPERTY(QString phoneNumber READ phoneNumber WRITE setPhoneNumber)
7;02:99,5@:75+62A/56<-2/:8-2 5/A:,2':/5@E
Q_CLASSINFO("ClassID", "{bc82730e-5f39-4e5c-96be-461c2cd0d282}")
Q_CLASSINFO("InterfaceID", "{c8bc1656-870e-48a9-9937-fbe1ceff8b2e}")
Q_CLASSINFO("ToSuperClass", "ABItem")
class AddressBook : public QMainWindow public:
{ ABItem(QTreeWidget *treeWidget);
Q_OBJECT void setContact(const QString &contact);
Q_PROPERTY(int count READ count) QString contact() const { return text(0); }
Q_CLASSINFO("ClassID", "{588141ef-110d-4beb-95ab-ee6a478b576d}") void setAddress(const QString &address);
Q_CLASSINFO("InterfaceID", "{718780ec-b30c-4d88-83b3-79b3d9e78502}") QString address() const { return text(1); }
Q_CLASSINFO("ToSuperClass", "AddressBook") void setPhoneNumber(const QString &number);
public: QString phoneNumber() const { return text(2); }
AddressBook(QWidget *parent = 0); public slots:
~AddressBook(); void remove();
int count() const; };
public slots:
ABItem *createEntry(const QString &contact);
ABItem *findEntry(const QString &contact) const;
ABItem *entryAt(int index) const; %;0 ABItem2@,://210910/067/2+6020671825627;02:3310//2*++LE2#7256;0157/241+C QtreeWidgetItem2/+27;:7
private slots: 572@:62*02/;+>62562: QtreeWidget2:63241+C QObject2/+27;:72572@:62*020K9+17032:/2:2J(H2+*N0@7E
void addEntry();
void editEntry();
void deleteEntry(); int main(int argc, char *argv[])
private: {
void createActions(); QApplication app(argc, argv);
void createMenus(); if (!QAxFactory::isServer()) {
QTreeWidget *treeWidget; AddressBook addressBook;
QMenu *fileMenu; addressBook.show();
QMenu *editMenu; return app.exec();
QAction *exitAction; }
QAction *addEntryAction; return app.exec();
QAction *editEntryAction; }
QAction *deleteEntryAction;
};

#6 main()-2>02@;0@L2>;07;0127;02:99,5@:75+625/2*056<21A62/7:63D:,+602+12:/2:2/01=01E2%;0 -activex
@+CC:63D,5602+975+625/210@+<65X032*8 QApplication2:632C:L0/27;02:99,5@:75+621A62:/2:2/01=01E2#427;0
%;0 AddressBook2>53<0725/27;02:99,5@:75+6B/2C:562>563+>E2%;0291+901782:6327;02/,+7/257291+=530/2>5,,
:99,5@:75+625/6B721A62:/2:2/01=01-2>02@10:7027;02C:562>53<072:632/;+>2572:/2>02>+A,326+1C:,,823+256
*02:=:5,:*,024+12/@159756<E2%;0 Q_CLASSINFO()2C:@1+25/2A/0327+2/90@54827;02@,://2:632567014:@02#R/
:682/7:63D:,+602?72:99,5@:75+6E
://+@5:7032>57;27;02@,://E2%;0/02>0102<0601:7032A/56<2:27++,2/A@;2:/ guid2+1 uuidE
#62:33575+627+ -activex-2!@75=0M2/01=01/2A6301/7:6327;024+,,+>56<2@+CC:63D,5602+975+6/F
#627;02910=5+A/20K:C9,0-2>02/90@5450327;02@,://2:632567014:@02#R/2>;06 >020K9+170327;0 QAxBouncer
@,://2A/56<27;0 QAXFACTORY_DEFAULT()2C:@1+E2#627;5/20K:C9,0-2>02>:6727+20K9+172/0=01:,2@,://0/-2/+
• -regserver210<5/701/27;02/01=0125627;02/8/70C210<5/718E
>02@:66+72A/0 QAXFACTORY_DEFAULT()E %;0102:1027>+2+975+6/2:=:5,:*,027+2A/F
• -unregserver2A610<5/701/27;02/01=01241+C27;02/8/70C210<5/718E
• -dumpidl file2>1570/27;02/01=01B/2#R)27+27;02/90@54503245,0E
• G02@:62/A*@,:// QAxFactory-2105C9,0C067257/2=517A:,24A6@75+6/27+291+=5302564+1C:75+62:*+A7
7;027890/2>02>:6727+20K9+17-2:632A/027;0 QAXFACTORY_EXPORT()2C:@1+27+210<5/70127;024:@7+18E
G;0627;02:99,5@:75+625/21A62:/2:2/01=01-2>02CA/720K9+1727;0 AddressBook2:63 ABItem2@,://0/2:/2J(H
@+C9+6067/F

QAXFACTORY_BEGIN("{2b2b6f3e-86cf-4c49-9df5-80483b47f17b}",
"{8e827b25-148b-4307-ba7d-23f275244818}")
QAXCLASS(AddressBook)
QAXTYPE(ABItem)
QAXFACTORY_END()

%;02:*+=02C:@1+/20K9+172:24:@7+1824+12@10:756<2J(H2+*N0@7/E2Q56@02>02>:6727+20K9+1727>+27890/2+4
J(H2+*N0@7/-2>02@:66+72/5C9,82A/0 QAXFACTORY_DEFAULT()2:/2>0235325627;02910=5+A/20K:C9,0E

%;02451/72:1<AC06727+ QAXFACTORY_BEGIN()25/27;0278902,5*1:182#RU27;02/0@+632:1<AC06725/27;0
:99,5@:75+62#RE2'07>006 QAXFACTORY_BEGIN()2:63 QAXFACTORY_END()-2>02/90@5482:,,27;02@,://0/27;:7
@:62*0256/7:675:7032:632:,,27;023:7:27890/27;:72>02>:6727+2C:L02:@@0//5*,02:/2J(H2+*N0@7/E

%;5/25/27;0 .pro245,024+12+A12+A7D+4D91+@0//2!@75=0M2/01=01F

TEMPLATE = app G563+>/2^___2:632MI-2:632/+C02.65K2/8/70C/-2+44012:23544010672C0@;:65/C2@:,,032;5*016:75+6E


CONFIG += qaxserver G;0627;02A/0129A7/27;02@+C9A7012567+2;5*016:75+6-27;02+901:756<2/8/70C2/5C9,823AC9/27;0
HEADERS = abitem.h \ @+C9A701B/2C0C+182+67+235/L2:63210,+:3/2572>;062572>:L0/2A9E2!99,5@:75+6/23+26+72600327+23+
addressbook.h \ :687;56<2+120=062*02:>:1027;:727;5/2;:9906/E
editdialog.h
SOURCES = abitem.cpp \
addressbook.cpp \ G;0627;02A/01256575:70/2:2/;A73+>6-2>02@:627:L02@+671+,2NA/72*04+1027;02/;A73+>62+@@A1/2*8
editdialog.cpp \ 105C9,0C06756< QApplication::commitData()E2%;5/2:,,+>/2A/27+2/:=02:682A6/:=0323:7: :6327+
main.cpp 56701:@72>57;27;02A/01254210SA5103E2%;5/29:172+42/0//5+62C:6:<0C06725/2/A99+17032+62*+7;2M]]2:63
FORMS = editdialog.ui G563+>/E
RC_FILE = qaxserver.rc
G02>5,,20K9,+102/0//5+62C:6:<0C0672*82<+56<27;1+A<;27;02@+302+42:2/0//5+6D:>:102%5@D%:@D%+0
:99,5@:75+6E2T51/7-2,07B/2,++L2:727;0 main()24A6@75+6F
%;0 qaxserver.rc245,021040110327+25627;0 .pro245,025/2:2/7:63:13245,027;:72@:62*02@+9503241+C2?7B/
src\activeqt\control23510@7+18E
int main(int argc, char *argv[])
{
)++L25627;020K:C9,0B/ vb23510@7+1824+12:2 5/A:,2':/5@291+N0@727;:72A/0/27;02!3310//2'++L2/01=01E Application app(argc, argv);
TicTacToe toe;
%;5/2@+C9,070/2+A12+=01=50>2+427;02!@75=0?7241:C0>+1LE2%;02?7235/715*A75+6256@,A30/2:33575+6:, toe.setObjectName("toe");
0K:C9,0/-2:6327;023+@AC067:75+62@+67:56/2564+1C:75+62:*+A72;+>27+2*A5,327;0 !"#$%&'(%)*2:63 app.setTicTacToe(&toe);
!"+)*,)*2C+3A,0/2:632;+>27+2/+,=02@+CC+6256701+901:*5,57825//A0/E toe.show();
return app.exec();
}

Handling X11 Session Management


G02@10:702:6 Application2+*N0@7E2%;0 Application2@,://256;0157/ 41+C QApplication2:63
G;062>02,+<2+A72+62M]]-2/+C02>563+>2C:6:<01/2:/L2A/2>;07;012>02>:6727+2/:=027;02/0//5+6E2#4 105C9,0C067/2*+7; commitData()2:63 saveState()27+2/A99+172/0//5+62C:6:<0C067E
>02/:8280/-27;02:99,5@:75+6/ 7;:72>01021A6656<2:102:A7+C:75@:,,8210/7:170327;0260K7275C02>02,+<256-
>57;27;02/:C02/@100629+/575+6/2:63-2530:,,8-2>57;27;02/:C02/7:702:/27;082;:32>;062>02,+<<032+A7E $0K7-2>02@10:702: TicTacToe2>53<07-2C:L027;0 Application2+*N0@72:>:102+4257-2:632/;+>257E2G02;:=0
@:,,0327;0 TicTacToe2>53<072Y7+0YE2G02CA/72<5=02A65SA02+*N0@726:C0/27+27+9D,0=0,2>53<07/2542>02>:67
%;02M]]D/90@545@2@+C9+606727;:727:L0/2@:102+42/:=56<2:63210/7+156<27;02/0//5+625/2@:,,0327;0 -)--($% 7;02/0//5+62C:6:<0127+210/7+1027;02>563+>/B2/5X0/2:6329+/575+6/E
.'%'/)*E2%+2C:L02:2?7\M]]2:99,5@:75+62:>:102+427;02/0//5+62C:6:<01-2>02CA/72105C9,0C067
QApplication::saveState()2:632/:=027;02:99,5@:75+6B/2/7:7027;010E
*+,-.'#/01A1#34'#3+BC3DBC3<'#D&&;+BD$+<7
*+,-.'#/01=1#><,,+7,#<-$#<7#?@9
CA/720K0@A7027+210/7:1727;02:99,5@:75+6E2'82304:A,7-2?7291+=530/27;024+,,+>56<210/7:172@+CC:63F

appname -session id_key

%;02451/729:17- appname-25/23015=03241+C argv[0]E2%;0 id29:1725/27;02/0//5+62#R291+=53032*827;02/0//5+6


C:6:<01U25725/2<A:1:6700327+2*02A65SA02:C+6<23544010672:99,5@:75+6/2:632:C+6<235440106721A6/2+427;0
/:C02:99,5@:75+6E2%;0 key29:17 5/2:330327+2A65SA0,825306754827;0275C02:72>;5@;27;02/7:702>:/2/:=03E
T+12=:15+A/210:/+6/-27;02/0//5+62C:6:<012@:62@:,, saveState()2CA,759,0275C0/23A156<27;02/:C0
/0//5+6-2:6327;023544010672/7:70/2CA/72*0235/756<A5/;03E

'0@:A/02+42,5C57:75+6/25620K5/756<2/0//5+62C:6:<01/-2>02CA/7206/A1027;:727;02:99,5@:75+6B/23510@7+18
5/25627;0 PATH206=51+6C0672=:15:*,02542>02>:6727;02:99,5@:75+627+210/7:172@+110@7,8E2#629:175@A,:1-254
8+A2>:6727+27182+A727;02%5@D%:@%+020K:C9,024+128+A1/0,4-28+A2CA/7256/7:,,257256-2/:8- /usr/bin2:63
56=+L02572:/ tictactoeE

W010B/27;0230456575+62+427;0 Application2@,://F
T+12/5C9,02:99,5@:75+6/-256@,A356<2%5@D%:@D%+0-2>02@+A,32/:=027;02/7:702:/2:62:33575+6:,2@+CC:63D
,5602:1<AC06727+27;0210/7:172@+CC:63E2T+120K:C9,0F
class Application : public QApplication
{
Q_OBJECT tictactoe -state OX-XO-X-O
public:
Application(int &argc, char *argv[]);
void setTicTacToe(TicTacToe *tic); %;5/2>+A,32/:=02A/241+C2/7+156<27;023:7:2562:245,02:63291+=5356<2:235/@:132@+CC:6327+210C+=027;0
void saveState(QSessionManager &sessionManager); 45,0E
void commitData(QSessionManager &sessionManager);
private:
TicTacToe *ticTacToe; void Application::commitData(QSessionManager &sessionManager)
}; {
if (ticTacToe->gameInProgress()
&& sessionManager.allowsInteraction()) {
%;0 Application2@,://2L009/2:29+5670127+27;0 TicTacToe2>53<072:/2:2915=:702=:15:*,0E int r = QMessageBox::warning(ticTacToe, tr("Tic-Tac-Toe"),
tr("The game hasn't finished.\n"
"Do you really want to quit?"),
void Application::saveState(QSessionManager &sessionManager) QMessageBox::Yes | QMessageBox::Default,
{ QMessageBox::No | QMessageBox::Escape);
QString fileName = ticTacToe->saveState(); if (r == QMessageBox::Yes) {
QStringList discardCommand; sessionManager.release();
discardCommand << "rm" << fileName; } else {
sessionManager.setDiscardCommand(discardCommand); sessionManager.cancel();
} }
}
}

(62M]]-27;0 saveState()24A6@75+625/2@:,,032>;0627;02/0//5+62C:6:<012>:67/27;02:99,5@:75+627+2/:=0
57/2/7:70E2%;024A6@75+625/2:=:5,:*,0 +62+7;0129,:74+1C/2:/2>0,,-2*A725725/260=012@:,,03E2%;0
%;0 commitData()24A6@75+625/2@:,,032>;0627;02A/012,+</2+A7E2G02@:62105C9,0C06725727+29+92A9 :
QSessionManager29:1:C07012:,,+>/2A/27+2@+CCA65@:702>57;27;02/0//5+62C:6:<01E
C0//:<02*+K2>:1656<27;02A/012:*+A729+70675:,23:7:2,+//E2%;02304:A,725C9,0C067:75+62@,+/0/2:,,27+9D
,0=0,2>53<07/-2>;5@;210/A,7/25627;02/:C02*0;:=5+12:/2>;0627;02A/012@,+/0/27;02>563+>/2+602:4701
G02/7:172*82:/L56<27;0 TicTacToe2>53<0727+2/:=0257/2/7:7027+2:245,0E2%;062>02/0727;02/0//5+6 :6+7;012*82@,5@L56<27;02@,+/02*A77+625627;0512757,02*:1/E2#6 J;:97012`-2>02/:>2;+>27+2105C9,0C067
C:6:<01B/235/@:132@+CC:63E2! 0(-1'*021$..'%025/2:2@+CC:6327;:727;02/0//5+62C:6:<012CA/7 closeEvent()27+2@:7@;27;5/2:6329+92A92:2C0//:<02*+KE
0K0@A7027+230,0702:682/7+1032564+1C:75+6210<:1356<27;02@A110672/7:70E2T+127;5/20K:C9,0-2>02/0725727+
T+127;029A19+/0/2+427;5/20K:C9,0-2>02105C9,0C067 commitData()2:6329+92A92:2C0//:<02*+K2:/L56<
7;02A/0127+2@+6451C27;02,+<2+A7254 :2<:C025/256291+<10//2:6325427;02/0//5+62C:6:<012:,,+>/2A/27+
rm sessionfile
56701:@72>57;27;02A/01E2#427;02A/012@,5@L/2a0/-2>02@:,, release()27+270,,27;02/0//5+62C:6:<0127+
@+6756A02,+<<56<2+A7U25427;02A/012@,5@L/2$+-2>02@:,, cancel()27+2@:6@0,27;02,+<2+A7E

>;010 sessionfile25/27;026:C02+427;0245,027;:72@+67:56/27;02/:=032/7:7024+127;0 /0//5+6-2:63 rm25/27;0


/7:63:132.65K2@+CC:6327+210C+=0245,0/E
*+,-.'#/01E1#F@<#%<-#.'D;;%#5D7$#$<#G-+$HF

%;02/0//5+62C:6:<012:,/+2;:/2: *)-&'*&21$..'%0E2%;5/25/27;02@+CC:6327;:727;02/0//5+62C:6:<01
board[row][column] = Empty;
}
}
turnNumber = 0;
}

#6 clearBoard()-2>02@,0:12:,,27;02@0,,/2:632/07 turnNumber27+2_E

QString TicTacToe::saveState() const


{
$+>2,07B/2,++L2:727;0 TicTacToe2@,://F QFile file(sessionFileName());
if (file.open(QIODevice::WriteOnly)) {
QTextStream out(&file);
class TicTacToe : public QWidget for (int row = 0; row < 3; ++row) {
{ for (int column = 0; column < 3; ++column)
Q_OBJECT out << board[row][column];
public: }
TicTacToe(QWidget *parent = 0); }
bool gameInProgress() const; return file.fileName();
QString saveState() const; }
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent *event); #6 saveState()-2>02>157027;02/7:70 +427;02*+:1327+235/LE2%;024+1C:725/2/71:5<;74+1>:13-2>57;2BMB24+1
void mousePressEvent(QMouseEvent *event); @1+//0/-2B(B24+126+A<;7/-2:632BDB24+120C9782@0,,/E
private:
enum { Empty = '-', Cross = 'X', Nought = 'O' };
void clearBoard();
void restoreState(); QString TicTacToe::sessionFileName() const
QString sessionFileName() const; {
QRect cellRect(int row, int column) const; return QDir::homePath() + "/.tictactoe_" + qApp->sessionId() + "_"
int cellWidth() const { return width() / 3; } + qApp->sessionKey();
int cellHeight() const { return height() / 3; } }
bool threeInARow(int row1, int col1, int row3, int col3) const;
char board[3][3];
int turnNumber; %;0 sessionFileName()2915=:7024A6@75+62107A16/27;0245,026:C024+127;02@A110672/0//5+62#R2:632/0//5+6
}; L08E2%;5/24A6@75+625/2A/0324+12*+7; saveState()2:63 restoreState()E2%;0245,026:C025/23015=03241+C
7;02/0//5+62#R2:632/0//5+62L08E

%;0 TicTacToe2@,://256;0157/ QWidget2:632105C9,0C067/ sizeHint()- paintEvent()-2:63


mousePressEvent()E2#72:,/+291+=530/27;0 gameInProgress()2:63 saveState()24A6@75+6/27;:72>02A/03256 void TicTacToe::restoreState()
+A1 Application2@,://E {
QFile file(sessionFileName());
if (file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
TicTacToe::TicTacToe(QWidget *parent)
for (int row = 0; row < 3; ++row) {
: QWidget(parent)
for (int column = 0; column < 3; ++column) {
{
in >> board[row][column];
clearBoard();
if (board[row][column] != Empty)
if (qApp->isSessionRestored())
++turnNumber;
restoreState();
}
setWindowTitle(tr("Tic-Tac-Toe"));
}
}
}
update();
}
#627;02@+6/71A@7+1-2>02@,0:127;02*+:13-2:63254 7;02:99,5@:75+62>:/256=+L032>57;27;0 -session2+975+6-
>02@:,,27;02915=:7024A6@75+6 restoreState()27+210,+:327;02+,32/0//5+6E
#6 restoreState()-2>02,+:327;0245,027;:72@+110/9+63/27+27;0210/7+1032/0//5+62:63245,,27;02*+:132>57;
7;:72564+1C:75+6E2G02303A@027;02=:,A02+4 turnNumber241+C27;026AC*012+42MB/2:632(B/2+627;02*+:13E
void TicTacToe::clearBoard()
{
for (int row = 0; row < 3; ++row) { #627;0 TicTacToe2@+6/71A@7+1-2>02@:,,03 restoreState()254 QApplication::isSessionRestored()
for (int column = 0; column < 3; ++column) { 107A1603 trueE2#627;:72@:/0- sessionId()2:63 sessionKey()2107A1627;02/:C02=:,A0/2:/2>;0627;0
:99,5@:75+6B/2/7:702>:/2/:=03-2:632/+ sessionFile-Name()2107A16/27;0245,026:C024+127;:72/0//5+6E

%0/756<2:63230*A<<56<2/0//5+62C:6:<0C0672@:62*0241A/71:756<-2*0@:A/02>02600327+2,+<2562:632+A7 Chapter 21. Embedded Programming


:,,27;0275C0E2(602>:827+2:=+5327;5/25/27+2A/0 7;02/7:63:13 xsm2A75,578291+=53032>57;2M]]E2%;02451/7275C0
>0256=+L0 xsm-25729+9/2A92:2/0//5+62C:6:<012>563+>2:632:2701C56:,E2%;02:99,5@:75+6/2>02/7:17241+C • !""#$%&'"()"!*&+#",&-"./#(
7;:72701C56:,2>5,,2:,,2A/0 xsm2:/27;0512/0//5+62C:6:<01256/70:32+427;02A/A:,-2/8/70CD>5302/0//5+6 • 012".3#4#$%&-"./#(&0.)!
C:6:<01E2G02@:627;062A/0 xsmB/2>563+>27+2063-210/7:17-2+1235/@:132:2/0//5+6-2:632/002542+A1
:99,5@:75+62*0;:=0/2:/2572/;+A,3E2T+12307:5,/2:*+A72;+>27+23+27;5/-2/00 R0=0,+956<2/+47>:1027+21A62+62C+*5,0230=5@0/2/A@;2:/2IR!/2:632C+*5,029;+60/2@:62*02=018
;779F\\3+@E71+,,70@;E@+C\bE]\/0//5+6E;7C,E @;:,,06<56<2*0@:A/020C*033032/8/70C/2<0601:,,82;:=02/,+>01291+@0//+1/-2,0//2901C:60672/7+1:<0
O4,:/;2C0C+182+12;:13235/LP-2,0//2C0C+18-2:632/C:,,01235/9,:8/27;:6230/L7+92@+C9A701/E

?7+95:2J+102O910=5+A/,82@:,,032?7\VC*03303P25/2:2=01/5+62+42?72+975C5X0324+120C*033032)56AKE
?7+95:2J+10291+=530/27;02/:C02!I#2:6327++,/2:/27;0230/L7+92=01/5+6/2+42?72O?7\G563+>/-2?7\M]]-
:632?7\H:@P-2:632:33/27;02@,://0/2:6327++,/260@0//:1824+120C*03303291+<1:CC56<E2%;1+A<;23A:,
,5@06/56<-25725/2:=:5,:*,024+12*+7;2+9062/+A1@02:632@+CC01@5:,230=0,+9C067E

?7+95:2J+102@:621A62+62:682;:13>:1027;:721A6/2)56AK2O56@,A356<2#670,2Kcd-2H#IQ-2!"H-2Q71+6<!"H-
H+7+1+,:2dc___-2:632I+>01IJ2:1@;570@7A10/PE2#72;:/2:2C0C+18DC:9903241:C02*A44012:632/A99+17/2:
JZZ2@+C95,01E2.6,5L02?7\M]]-25723+0/26+72600327;02M2G563+>2Q8/70CU256/70:3-25725C9,0C067/257/2+>6
>563+>2/8/70C2O?GQP-206:*,56<2/5<6545@:672/7+1:<02:632C0C+182/:=56</E2%+2103A@0257/2C0C+18
4++79156720=062C+10-2?7+95:2J+102@:62*0210@+C95,0327+20K@,A302A6A/03240:7A10/E2#427;02:99,5@:75+6/
:632@+C9+6067/2A/032+62:230=5@02:102L6+>62562:3=:6@0-27;082@:62*02@+C95,0327+<07;012567+2+60
0K0@A7:*,027;:72,56L/2/7:75@:,,82:<:56/727;02?7+95:2J+102,5*1:150/E

?7+95:2J+102:,/+2*060457/241+C2=:15+A/240:7A10/27;:72:10 :,/+29:172+427;0230/L7+92=01/5+6/2+42?7-
56@,A356<27;020K706/5=02A/02+425C9,5@5723:7:2/;:156<2OY@+982+62>1570YP2:/2:2C0C+18D/:=56<270@;65SA0-
/A99+1724+12@A/7+C2>53<072/78,0/27;1+A<; QStyle-2:632:2,:8+A72/8/70C27;:72:3:97/27+2C:L027;02*0/7
A/02+427;02:=:5,:*,02/@10062/9:@0E

?7+95:2J+1024+1C/27;02*:/5/2+42%1+,,70@;B/20C*033032+440156<-2>;5@;2:,/+256@,A30/2?7+95:2I,:74+1C-
?7+95:2IR!-2:632?7+95:2I;+60E2%;0/0291+=5302@,://0/2:632:99,5@:75+6/230/5<6032/90@545@:,,824+1
9+17:*,0230=5@0/2:632@:62*025670<1:7032>57;2/0=01:,27;513D9:1782[:=:2=517A:,2C:@;560/E

Getting Started with Qtopia


?7+95:2J+102:99,5@:75+6/2@:62*0230=0,+9032+62:6829,:74+1C20SA599032>57;2:2CA,75D9,:74+1C27++,
@;:56E2%;02C+/72@+CC+62+975+625/27+2*A5,32:2e$.2JZZ2@1+//D@+C95,012+62:2.65K2/8/70CE2%;5/
91+@0//25/2/5C9,545032*82:2/@15972:632:2/072+429:7@;0/291+=53032*82R:62f0<0,2:7
;779F\\L0<0,E@+C\@1+//7++,\E2Q56@02?7+95:2J+102@+67:56/27;02?72!I#-25725/2A/A:,,829+//5*,027+2A/02:
30/L7+92=01/5+62+42?7-2/A@;2:/2?7\M]]2+12?7\G563+>/-24+12C+/72+427;0230=0,+9C067E

?7+95:2J+10B/2@+645<A1:75+62/8/70C2/A99+17/2@1+//D@+C95,01/-27;1+A<;27;0 configure2/@1597B/ -
embedded2+975+6E2T+120K:C9,0-27+2*A5,324+127;02!"H2:1@;570@7A102>02>+A,327890

./configure -embedded arm

G02@:62@10:702@A/7+C2@+645<A1:75+6/2*82:3356<260>245,0/27+2?7B/ mkspecs/qws23510@7+18E

?7+95:2J+10231:>/23510@7,827+27;02)56AK241:C02*A44012O7;02C0C+182:10:2://+@5:7032>57;27;02=530+
35/9,:8PE2%+2:@@0//27;0241:C02*A4401-28+A2C5<;72600327+2<1:672>15702901C5//5+6/27+27;0 /dev/fb0
30=5@0E

%+21A62?7+95:2J+102:99,5@:75+6/-2>02CA/72451/72/7:172+60291+@0//27+2:@72:/2:2/01=01E2%;02/01=0125/
10/9+6/5*,024+12:,,+@:756<2/@1006210<5+6/27+2@,5067/2:6324+12<0601:756<2C+A/02:632L08*+:1320=067/E
!682?7+95:2J+102:99,5@:75+62@:62*0@+C02:2/01=012*82/90@54856< -qws2+6257/2@+CC:632,5602+12*8
9://56< QApplication:: GuiServer2:/27;027;51329:1:C070127+27;0 QApplication2@+6/71A@7+1E src/corelib/qfeatures.txtE

J,50672:99,5@:75+6/2@+CCA65@:702>57;27;02?7+95:2J+102/01=012A/56<2/;:1032C0C+18E2'0;56327;0 ?7+95:2J+10291+=530/245=0 0K:C9,02@+645<A1:75+6/2Ominimum- small- medium- large-2:63 distP27;:72:10


/@060/-27;02@,5067/231:>27;0C/0,=0/2567+2/;:1032C0C+182:632:10210/9+6/5*,024+129:56756<27;0512+>6 /7+103256 src/corelib/qconfig_xxx.h245,0/E2%;0/02@+645<AD1:75+6/2@:62*02/90@545032A/56<27;0 configure
>563+>230@+1:75+6/E2%;5/2L009/2@+CCA65@:75+62*07>00627;02@,5067/2:6327;02/01=0127+2:2C565CAC- /@1597B/ -qconfig xxx2+975+6-24+120K:C9,0F
10/A,756<2562:2/6:9982A/012567014:@0E2?7+95:2J+102:99,5@:75+6/26+1C:,,82A/0 QPainter27+231:>
7;0C/0,=0/-2*A727;082@:62:,/+2:@@0//27;02=530+2;:13>:1023510@7,82A/56< QDirectPainterE
./configure -qconfig small
J,5067/2@:62@+CCA65@:702>57;20:@;2+7;012A/56<27;02?J(I291+@+7+,E2!2@,50672@:62,5/7062+62:26:C03
@;:660,2*82@10:756<2: QCopChannel2+*N0@72:632@+660@756<27+257/ received()2/5<6:,E2T+120K:C9,0F
%+2@10:702@A/7+C2@+645<A1:75+6/-2>02@:62C:6A:,,8291+=5302: qconfig-xxx.h245,02:632A/02572:/254257
>0102:2/7:63:132@+645<A1:75+6E2!,7016:75=0,8-2>02@:62A/027;0 qconfig2<1:9;5@:,27++,-2,+@:7032562?7B/
QCopChannel *channel = new QCopChannel("System", this); tools2/A*3510@7+18E
connect(channel, SIGNAL(received(const QString &, const QByteArray &)),
this, SLOT(received(const QString &, const QByteArray &)));
?7+95:2J+10291+=530/27;024+,,+>56<2@,://0/24+12567014:@56<2>57;2569A72:632+A79A7230=5@0/2:6324+1
@A/7+C5X56<27;02,++L2:632400,2+427;02>563+>2/8/70CF

!2?J(I2C0//:<02@+6/5/7/2+42:26:C02:632:62+975+6:, QByteArrayE2%;02/7:75@ QCopChannel::send()


*1+:3@:/7/2:2C0//:<02+62:2@;:660,E2T+120K:C9,0F ;D(( ID('#B;D((#J<.
QScreen /@10062315=01/
QByteArray data; QScreenDriverPlugin /@10062315=0129,A<56/
QDataStream out(&data, QIODevice::WriteOnly);
out << QDateTime::currentDateTime(); QWSMouseHandler C+A/02315=01/
QCopChannel::send("System", "clockSkew(QDateTime)", data);
QMouseDriverPlugin C+A/02315=01 9,A<56/
QWSKeyboardHandler L08*+:132315=01/
%;02910=5+A/20K:C9,025,,A/71:70/2:2@+CC+62535+CF2G02A/0 QDataStream27+206@+3027;023:7:-2:6327+
06/A1027;:727;0 QByteArray25/2567019107032@+110@7,82*827;0210@05=01-2>02C:6<,027;023:7:24+1C:725627;0 QKbdDriverPlugin L08*+:132315=0129,A<56/
C0//:<026:C02:/2542572>0102:2JZZ24A6@75+6E
QWSInputMethod 569A72C07;+3/
:15+A/206=51+6C0672=:15:*,0/2:440@72?7+95:2J+102:99,5@:75+6/E2%;02C+/725C9+17:672+60/2:10
QWS_MOUSE_PROTO2:63 QWS_KEYBOARD-2>;5@;2/90@54827;02C+A/0230=5@02:6327;02L08*+:1327890E2Q00 QDecoration >563+>230@+1:75+62/78,0/
;779F\\3+@E71+,,70@;E@+C\bE]\0C*D06==:1/E;7C,24+12:2@+C9,0702,5/72+4206=51+6C0672=:15:*,0/E
QDecorationPlugin 9,A<56/291+=5356<2>563+>230@+1:75+62/78,0/
#42>02A/02.65K2:/2+A1230=0,+9C06729,:74+1C-2>02@:6270/727;02:99,5@:75+62A/56<27;02?7+95:2=517A:,
41:C02*A44012OqvfbP-2:62M]]2:99,5@:75+627;:72/5CA,:70/-295K0,24+1295K0,-27;02:@7A:,241:C02*A4401E2%;5/
:@@0,01:70/27;0230=0,+9C0672@8@,02@+6/5301:*,8E2%+206:*,02=517A:,2*A44012/A99+172562?7+95:2J+10- %+2+*7:5627;02,5/72+4291030456032315=01/-2569A72C07;+3/-2:632>563+>230@+1:75+62/78,0/-21A627;0
9://27;0 -qvfb2+975+627+27;0 configure2/@1597E2'02:>:1027;:727;5/2+975+625/26+725670630324+1 configure2/@15972>57;27;0 -help2+975+6E
91+3A@75+62A/0E2%;02=517A:,241:C02*A44012:99,5@:75+625/2,+@:703256 tools/qvfb2:632@:62*0256=+L032:/
4+,,+>/F %;02/@10062315=012@:62*02/90@545032A/56<27;0 -display2@+CC:63D,5602+975+62>;062/7:1756<27;02?7+95:
J+102/01=01-2:/2/00625627;02910=5+A/2/0@75+6-2+12*82/07756<27;0 QWS_DISPLAY206=51+6C0672=:15:*,0E
%;02C+A/02315=012:6327;02://+@5:703230=5@02@:62*02/90@545032A/56<27;0 QWS_MOUSE_PROTO206=51+6C067
qvfb -width 320 -height 480 -depth 32
=:15:*,0-2>;+/02=:,A02CA/72;:=027;02/867:K &56)2F0),(1)-2>;010 &56)25/2+602+427;02/A99+1703
315=01/2:63 device27;029:7;27+27;0230=5@02O4+120K:C9,0- QWS_MOUSE_PROTO=IntelliMouse:/dev/mousePE
f08*+:13/2:102;:63,032/5C5,:1,827;1+A<;27;0 QWS_KEYBOARD206=51+6C0672=:15:*,0E2#69A72C07;+3/2:63
!6+7;012+975+627;:72>+1L/2+62C+/729,:74+1C/25/27+2A/02 $J2O 517A:,2$07>+1L2J+C9A756<P27+21A627;0 >563+>230@+1:75+6/2:102/07291+<1:CC:75@:,,825627;02/01=012A/56<
:99,5@:75+6/210C+70,8E2%+206:*,02 $J2/A99+172562?7+95:2J+10-29://27;0 -qt-gfx-vnc2+975+627+ QWSServer::setCurrentInputMethod()2:63 QApplication::qwsSetDecoration()E
configureE2%;062,:A6@;28+A12?7+95:2J+102:99,5@:75+6/2>57;27;0 -display VNC:02@+CC:63D,5602+975+6
:6321A62:2 $J2@,506729+56756<2:727;02;+/72+62>;5@;28+A12:99,5@:75+6/2:1021A6656<E2%;0235/9,:82/5X0 G563+>230@+1:75+62/78,0/2@:62*02/07256309063067,82+427;02>53<072/78,0-2>;5@;256;0157/241+C QStyleE
:632*5723097;2@:62*02/90@545032*82/07756<27;0 QWS_SIZE2:63 QWS_DEPTH206=51+6C0672=:15:*,0/2+627;0 T+120K:C9,0-25725/2067510,829+//5*,027+2/072G563+>/2:/27;02>563+>230@+1:75+62/78,02:632I,:/75SA02:/
;+/727;:721A6/27;02?7+95:2J+102:99,5@:75+6/2O4+120K:C9,0- QWS_SIZE=320x4802:63 QWS_DEPTH=32PE 7;02>53<072/78,0E2#4230/5103-230@+1:75+6/2@:62*02/072+62:2901D>563+>2*:/5/E

Customizing Qtopia Core %;0 QWSServer2@,://291+=530/2=:15+A/24A6@75+6/24+12@A/7+C5X56<27;02>563+>2/8/70CE2!99,5@:75+6/27;:7


1A62:/2?7+95:2J+102/01=01/2@:62:@@0//27;02A65SA0 QWSServer256/7:6@027;1+A<;27;0 qwsServer2<,+*:,
=:15:*,0-2>;5@;25/256575:,5X032*827;0 QApplication2@+6/71A@7+1E
G;06256/7:,,56<2?7+95:2J+10-2>02@:62/90@548240:7A10/2>02>:6727+2,0:=02+A727+2103A@0257/2C0C+18
4++791567E2?7+95:2J+10256@,A30/2+=012:2;A631032@+645<A1:*,0240:7A10/-20:@;2+42>;5@; 5/2://+@5:70327+
:291091+@0//+12/8C*+,E2T+120K:C9,0- QT_NO_FILEDIALOG20K@,A30/ QFileDialog241+C27;0 &34(2,5*1:18- ?7+95:2J+102/A99+17/27;024+,,+>56<24+6724+1C:7/F2%1A0%8902O%%TP-2I+/7Q@15972%8902]-2'57C:9
:63 QT_NO_I18N2,0:=0/2+A72:,,2/A99+1724+12567016:75+6:,5X:75+6E2%;0240:7A10/2:102,5/703
R5/715*A75+62T+1C:72O'RTP-2:632?72I10D106301032T+67/2O?ITPE

'0@:A/02?IT25/2:21:/70124+1C:7- 5725/24:/7012:632A/A:,,82C+102@+C9:@727;:62=0@7+124+1C:7/2/A@;2:/
Installing Qt/Windows
%%T2:632%8902]2542>0260032572+6,82:72+602+127>+23544010672/5X0/E2%;0 makeqpf27++,2,07/2A/2910D1063012:
%%T2+12:2%8902]245,02:632/:=027;0210/A,72562?IT24+1C:7E2!62:,7016:75=025/27+21A62+A12:99,5@:75+6/2>57; G;0628+A256/01727;02JR2+62:2G563+>/2C:@;560-27;0256/7:,,:75+6291+<1:C2/;+A,32/7:172:A7+C:75@:,,8E
7;0 -savefonts2@+CC:63D,5602+975+6E #427;5/23+0/26+72+@@A1-2A/02T5,02VK9,+10127+26:=5<:7027+27;02JRB/21++724+,3012:6323+A*,0D@,5@L
install.exeE2O%;5/291+<1:C2C:82:990:12:/ install230906356<2+62;+>28+A12/8/70C25/2@+645<A103EP
!727;0275C02+42>15756<-2%1+,,70@;25/230=0,+956<2:62:33575+6:,2,:8012+627+92+42?7+95:2J+1027+2C:L0
0C*033032:99,5@:75+6230=0,+9C06720=0624:/7012:632C+102@+6=065067E2#725/2;+90327;:72:2,:701203575+6 #428+A2:,10:382;:=027;02H56eG2JZZ2@+C95,0128+A2CA/72/90@54827;023510@7+182>;01025725/2,+@:703U
+427;5/2*++L2>5,,256@,A302C+102564+1C:75+62+627;5/27+95@E +7;01>5/0-2/0727;02@;0@L2*+K2:632;:=027;0256/7:,,01256/7:,,2H56eG24+128+AE2%;02eI)2=01/5+62+42?7
/A99,5032+627;02JR2>5,,26+72>+1L2>57;2 5/A:,2JZZ-2/+25428+A23+26+72;:=02H56eG2:,10:38256/7:,,0328+A
>5,,2600327+256/7:,,257E2%;0256/7:,,012:,/+2<5=0/28+A27;02+975+627+256/7:,,27;020K:C9,0/27;:72:@@+C9:68
7;02*++LE2?7B/2/7:63:1320K:C9,0/2:102:A7+C:75@:,,8256/7:,,03-2:,+6<2>57;27;023+@AC067:75+6E
Appendix A. Installing Qt #428+A2@;++/027+256/7:,,27;02H56eG2@+C95,01-27;0102C:82*02:2/C:,,230,:82*07>00627;02@+C9,075+62+4
7;02H56eG256/7:,,:75+62:6327;02/7:172+427;02?7256/7:,,:75+6E
• 5&6."!&.$&7#8!$2#$%
• 9$2"(::#$%&-";<#$*.+2 !4701256/7:,,:75+628+A2>5,,2;:=02:260>24+,30125627;02Q7:172C06A2@:,,032Y?72*82%1+,,70@;2=bE]E]
• 9$2"(::#$%&-";=(8 O+906/+A1@0PYE2%;5/24+,3012;:/2/;+17@A7/27+ &2!--(-&'%&2:63 &27)-(/%)*-2:632:,/+2+602@:,,032Y?7
• 9$2"(::#$%&-";>?? bE]E]2J+CC:632I1+C97Y27;:72/7:17/2:2@+6/+,02>563+>E2G;0628+A2/7:1727;5/2>563+>2572>5,,2/0727;0
06=51+6C0672=:15:*,0/24+12@+C95,56<2?7291+<1:C/2>57;2H56eGE2#725/25627;5/2>563+>27;:728+A2@:621A6
%;5/2:990635K20K9,:56/2;+>27+256/7:,, ?7241+C27;02JR27;:72:@@+C9:650/27;5/2*++L2+67+28+A12/8/70CE qmake2:63 make27+2*A5,32?72:99,5@:75+6/E
%;02JR2;:/203575+6/2+42?72bE]E]24+12G563+>/-2H:@2(Q2M-2:632M]]2O4+12)56AK2:632C+/72=01/5+6/2+4
.65KPE2%;082:,,256@,A302Q?)570-2:29A*,5@23+C:56256D91+@0//23:7:*:/0-27+<07;012>57;2:2Q?)5702315=01E
%;0203575+6/2+42?72+627;02JR2:10291+=530324+128+A12@+6=06506@0E2T+12/015+A/2/+47>:10230=0,+9C067-
5725/2*0/727+23+>6,+:327;02,:70/72=01/5+62+42?7241+C ;779F\\>>>E71+,,70@;E@+C\3+>6,+:3\2+127+2*A82: Installing Qt/Mac
@+CC01@5:,2=01/5+6E
'04+102?72@:62*0256/7:,,032+62H:@2(Q2M-2!99,0B/2M@+302%++,/2CA/72:,10:382*0256/7:,,03E2%;02JR2O+1
%1+,,70@;2:,/+291+=530/2?7+95:2J+1024+12*A5,356<2:99,5@:75+6/24+12)56AKD*:/0320C*03303230=5@0/2/A@; R RP2@+67:5656<27;0/027++,/25/2A/A:,,82/A99,5032>57;2H:@2(Q2MU27;082@:62:,/+2*023+>6,+:303241+C
:/2IR!/2:632C+*5,029;+60/E2#428+A2:102567010/7032562@10:756<20C*033032:99,5@:75+6/-28+A2@:62+*7:56 7;02!99,02R0=0,+9012J+660@75+6- ;779F\\30=0,+901E:99,0E@+CE
?7+95:2J+10241+C2%1+,,70@;B/23+>6,+:32>0*29:<0E
#428+A2;:=02H:@2(Q2M2]_Eb2O%5<01P2:632M@+302%++,/2^EK2O>57;2eJJ2bE_EKP-28+A2@:62A/027;0256/7:,,01
%;020K:C9,02:99,5@:75+6/2A/0325627;02*++L2:102+627;02JR25627;0 examples23510@7+18E2#62:33575+6-2?7 30/@15*032*0,+>E2#428+A2;:=02:620:1,5012=01/5+62+42H:@2(Q2M-2+12:62+,3012=01/5+62+42eJJ-28+A2>5,,
91+=530/2C:682/C:,,20K:C9,02:99,5@:75+6/2,+@:70325627;0 examples2/A*3510@7+18E 600327+256/7:,,27;02/+A1@029:@L:<02C:6A:,,8E2%;5/29:@L:<025/2@:,,03 qt-mac-opensource-4.1.1.tar.gz
:6325/2,+@:70325627;0 mac24+,3012+627;02JRE2#428+A 56/7:,,27;5/29:@L:<0-24+,,+>27;0256/71A@75+6/25627;0
A Note on Licensing 60K72/0@75+624+1256/7:,,56<2?72+62M]]E

%+2A/027;0256/7:,,01-256/01727;02JR2:6323+A*,0D@,5@L27;029:@L:<02@:,,03 Qt.mpkgE2%;5/2>5,,2,:A6@;27;0
?725/291+3A@0325627>+24+1C/F2+9062/+A1@0 :632@+CC01@5:,E2%;02+9062/+A1@0203575+6/2:102:=:5,:*,0
56/7:,,01- Installer.app-2:632?72>5,,2*0256/7:,,032>57;27;02/7:63:1320K:C9,0/-23+@AC067:75+6-2:63
41002+42@;:1<0U27;02@+CC01@5:,203575+6/2CA/72*029:5324+1E
7;020K:C9,0/27;:72:@@+C9:6827;5/2*++LE2?72>5,,2*0256/7:,,03256 /Developer-2>57;27;02*++LB/20K:C9,0/
56 /Developer/Examples/Qt4BookE
%;02/+47>:102+627;02JR25/2/A57:*,024+12@10:756<2:99,5@:75+6/24+128+A12+>6203A@:75+6:,2:632901/+6:,
A/0E
%+21A62@+CC:63/2,5L0 qmake2:63 make-28+A2>5,,2600327+2A/02:2701C56:,2>563+>-24+120K:C9,0-
Terminal.app256 /Applications/UtilitiesE2#725/2:,/+29+//5*,027+2<0601:702M@+30291+N0@7/2A/56< qmakeE
#428+A2>:6727+235/715*A7027;02:99,5@:75+6/27;:728+A2@10:702>57;2:62+9062/+A1@0203575+62+42?7-28+A
CA/72@+C9,82>57;27;02/90@545@2701C/2:632@+63575+6/2,:5323+>625627;02,5@06/0/24+127;02/+47>:1028+A T+120K:C9,0-27+2<0601:702:62M@+30291+N0@724+127;0 hello20K:C9,0-2/7:172:2@+6/+,02/A@;2:/
A/027+2@10:7027;02:99,5@:75+6/E2T+12+9062/+A1@0203575+6/-27;02701C/2:632@+63575+6/256@,A3027;0 Terminal.app-2@;:6<023510@7+1827+ /Developer/Examples/Qt4Book/chap01/hello-2:6320670127;0
10SA510C06727+2A/027;02e$.2e0601:,2IA*,5@2)5@06/02OeI)PE2(9062,5@06/0/2,5L027;02eI)2<5=027;0 4+,,+>56<2@+CC:63F
:99,5@:75+6/B2A/01/2@017:56215<;7/-256@,A356<27;0215<;727+2=50>2:632C+354827;02/+A1@02:6327+235/715*A70
7;02:99,5@:75+6/2O+627;02/:C02701C/PE#428+A2>:6727+235/715*A70 8+A12:99,5@:75+6/2>57;+A72/+A1@02@+30
O7+2L00928+A12@+302915=:70P2+125428+A2>:6727+2:99,828+A12+>62@+CC01@5:,2,5@06/02@+63575+6/27+28+A1 qmake -spec macx-xcode hello.pro
:99,5@:75+6/-28+A2CA/72*A82@+CC01@5:,203575+6/2+427;02/+47>:1028+A2A/027+2@10:7027;02:99,5@:75+6/E
%;02@+CC01@5:,203575+6/2+427;02/+47>:102:,,+>28+A27+2/0,,2:63235/715*A7028+A12:99,5@:75+6/2+628+A1
+>62701C/E
Installing Qt/X11
%+256/7:,,2?7256257/2304:A,72,+@:75+62+62M]]-28+A2>5,,2600327+2*021++7E2#428+A23+26+72;:=021++72:@@0//-
%;02JR2@+67:56/2eI)2=01/5+6/2+42?724+12G563+>/-2H:@2(Q2M-2:632M]]E2%;024A,,2,0<:,270K7/2+427;0
A/0 configureB/ -prefix2:1<AC06727+2/90@5482:23510@7+1827+2>;5@;28+A2;:=02901C5//5+627+2>1570E
,5@06/0/2:10256@,A3032>57;27;029:@L:<0/2+627;02JR-2:,+6<2>57;2564+1C:75+62+62;+>27+2+*7:56
@+CC01@5:,2=01/5+6/E
]E J;:6<023510@7+1827+2:270C9+1:1823510@7+18E T+120K:C9,0F
2.
3. cd /tmp
bE .69:@L27;02:1@;5=0245,0241+C27;02JRF
5.
6. cp /cdrom/x11/qt-x11-opensource-src-4.1.1.tgz .
7.
8.
gunzip qt-x11-opensource-src-4.1.1.tgz
tar xvf qt-x11-opensource-src-4.1.1.tar Appendix B. Introduction to C++ for Java
%;5/2>5,,2@10:7027;023510@7+18 /tmp/qt-x11-opensource-src-4.1.1-2://AC56<27;:728+A12JRD"(H and C# Programmers
5/2C+A67032:7 /cdromE2?7210SA510/2e$. tarU2+62/+C02/8/70C/25725/2@:,,03 gtarE
• !""#$%&'"()"!*&+#",&0@@
gE VK0@A7027;0 configure27++,2>57;28+A129104011032+975+6/27+2*A5,327;02?7 ,5*1:182:6327;027++,/ • =(#$&7($%1(%!&A#BB!)!$8!2
/A99,5032>57;257F • C,!&'"($*()*&0@@&7#D)()E
10.
11. cd /tmp/qt-x11-opensource-src-4.1.1 !"#$%&&'()"*$&+,-")'#$%$#!,+.$"(.+,)/0.",($.,$122$3,+$)'-'4,&'+#$5!,$%4+'%)6$7(,5$8%-%$,+$19:$;.
12. ./configure %##/<'#$.!%.$6,/$%+'$3%<"4"%+$5".!$,=>'0.?,+"'(.')$0,(0'&.#$#/0!$%#$"(!'+".%(0'$%()$&,46<,+&!"#<
%()$5%(.$.,$4'%+($122:$ ,$%-,")$<%7"(@$.!"#$=,,7$%($/(5"'4)6$ABCDD$&%@'$),,+#.,&$=6$"(04/)"(@$%
a+A2@:621A6 ./configure -help27+2<072:2,5/72+42@+645<A1:75+62+975+6/E 0,<&4'.'$122$&+"<'+B$.!"#$%&&'()"*$0,(3"('#$".#'43$.,$'##'(."%4#:$;.$&+'#'(.#$.!'$=%#"0$7(,54')@'
%()$.'0!("E/'#$('0'##%+6$.,$/()'+#.%()$.!'$&+,@+%<#$&+'#'(.')$"($.!'$+'#.$,3$.!'$=,,7B$5".!
]`E %+2*A5,32?7-27890 '(,/@!$"(3,+<%.",($.,$#.%+.$)'-'4,&"(@$0+,##?&4%.3,+<$122$FG;$%&&4"0%.",(#$/#"(@$H.:
14.
15. make I.$.!'$."<'$,3$5+"."(@B$122$"#$.!'$,(46$+'%4"#."0$,&.",($3,+$5+"."(@$0+,##?&4%.3,+<B$!"@!?&'+3,+<%(0'
,=>'0.?,+"'(.')$FG;$%&&4"0%.",(#:$;.#$)'.+%0.,+#$/#/%446$&,"(.$,/.$.!%.$8%-%$,+$19B$5!"0!$)+,&&')$1
%;5/2>5,,2@10:7027;02,5*1:182:632@+C95,02:,,27;0230C+/-20K:C9,0/-2:6327++,/E (62/+C02/8/70C/ 0,<&%."="4".6B$%+'$("0'+$.,$/#'J$"($3%0.B$K>%+('$L.+,/#.+/&B$.!'$"(-'(.,+$,3$122B$(,.')$"( !"#$"%&'(
make25/2@:,,03 gmakeE )(*#+,-./0&-(#-1#233$.!%.$M5".!"($122B$.!'+'$"#$%$</0!$#<%44'+$%()$04'%('+$4%(@/%@'$#.+/@@4"(@
.,$@'.$,/.M:
]dE %+256/7:,,2?7-27890
17. N,+./(%.'46B$5!'($5'$&+,@+%<$5".!$H.B$5'$/#/%446$#."07$.,$%$#/=#'.$,3$122$.!%.$"#$-'+6$04,#'$.,$.!'
18. su -c "make install" /.,&"%($4%(@/%@'$'(-"#",(')$=6$L.+,/#.+/&B$4'%-"(@$/#$3+''$.,$0,(0'(.+%.'$,($.!'$&+,=4'<$%.$!%():
N/+.!'+<,+'B$H.$'*.'()#$122$"($#'-'+%4$+'#&'0.#B$.!+,/@!$".#$"((,-%."-'$M#"@(%4#$%()$#4,.#M
:6320670127;021++729://>+13E2%;5/2>5,,256/7:,,2?72567+ /usr/local/Troll-tech/Qt-4.1.1E2a+A2@:6 <'0!%("#<B$".#$G("0,)'$#/&&,+.B$%()$".# foreach$7'65,+):
@;:6<027;0230/756:75+62*82A/56<27;0 -prefix2+975+62>57; configure-2:6325428+A2;:=02>1570
:@@0//27+27;0230/756:75+628+A2@:62/5C9,827890F ;($.!'$3"+#.$#'0.",($,3$.!"#$%&&'()"*B$5'$5"44$#''$!,5$.,$0,<="('$122$#,/+0'$3"4'#$.,$,=.%"($%(
'*'0/.%=4'$&+,@+%<:$ !"#$5"44$4'%)$/#$.,$'*&4,+'$0,+'$122$0,(0'&.#$#/0!$%#$0,<&"4%.",($/(".#B
!'%)'+$3"4'#B$,=>'0.$3"4'#B$4"=+%+"'#%()$.,$@'.$3%<"4"%+$5".!$.!'$122$&+'&+,0'##,+B$0,<&"4'+B$%()
make install 4"(7'+:

]gE Q072A92@017:56206=51+6C0672=:15:*,0/24+12?7E !'($5'$5"44$./+($.,$.!'$<,#.$"<&,+.%(.$4%(@/%@'$)"33'+'(0'#$='.5''($122B$8%-%$%()$19O$!,5$.,


)'3"('$04%##'#B$!,5$.,$/#'$&,"(.'+#$%()$+'3'+'(0'#B$!,5$.,$,-'+4,%)$,&'+%.,+#B$!,5$.,$/#'$.!'
#428+A12/;0,,25/ bash- ksh- zsh-2+1 sh-2:3327;024+,,+>56<2,560/27+28+A1 .profile245,0F &+'&+,0'##,+B$%()$#,$,(:$I4.!,/@!$.!'$122$#6(.%*$"#$#/&'+3"0"%446$#"<"4%+$.,$.!%.$,3$8%-%$,+$19B$.!'
/()'+46"(@$0,(0'&.#$)"33'+$"($#/=.4'$5%6#:$I.$.!'$#%<'$."<'B$%#$%($"(#&"+%.",(%4$#,/+0'$3,+$8%-%$%()
19B$.!'$122$4%(@/%@'$!%#$%$4,.$"($0,<<,($5".!$.!'#'$.5,$4%(@/%@'#B$"(04/)"(@$#"<"4%+$)%.%$.6&'#B
PATH=/usr/local/Trolltech/Qt-4.1.1/bin:$PATH .!'$#%<'$%+".!<'."0$,&'+%.,+#B$%()$.!'$#%<'$=%#"0$0,(.+,4$34,5$#.%.'<'(.#:
export PATH
!'$4%#.$#'0.",($"#$)')"0%.')$.,$.!'$L.%()%+)$122$4"=+%+6B$5!"0!$&+,-")'#$+'%)6?<%)'$3/(0.",(%4".6
#428+A12/;0,,25/ csh2+1 tcsh-2:3327;024+,,+>56<2,56027+28+A1 .login245,0F .!%.$0%($='$/#')$"($%(6$122$&+,@+%<:$ !'$4"=+%+6$"#$.!'$+'#/4.$,3$,-'+$PD$6'%+#$,3$'-,4/.",(B$%() %#
#/0!$&+,-")'#$%$5")'$+%(@'$,3$%&&+,%0!'#$"(04/)"(@$&+,0')/+%4B$,=>'0.?,+"'(.')B$%()$3/(0.",(%4
&+,@+%<<"(@$#.64'#B$%()$=,.!$<%0+,#$%()$.'<&4%.'#:$1,<&%+')$5".!$.!'$4"=+%+"'#$&+,-")')$5".!
setenv PATH /usr/local/Trolltech/Qt-4.1.1/bin:$PATH 8%-%$%()$19B$.!'$L.%()%+)$122$4"=+%+6$!%#$%$+%.!'+$4"<".')$#0,&'J$3,+$'*%<&4'B$".$!%#$(,$#/&&,+.
3,+$FG;$&+,@+%<<"(@B$</4.".!+'%)"(@B$)%.%=%#'#B$"(.'+(%.",(%4"Q%.",(B$('.5,+7"(@B$RSTB$,+$G("0,)':
,$=+,%)'($122U#$#0,&'$"(.,$.!'#'$%+'%#B$122$)'-'4,&'+#$%+'$'*&'0.')$.,$/#'$-%+",/#$V,3.'(
#428+A2A/03 -prefix2>57; configure-2A/027;029:7;28+A2/90@54503256/70:32+427;02304:A,729:7;
&4%.3,+<?#&'0"3"0W$4"=+%+"'#:
/;+>62:*+=0E

!"#$"#$5!'+'$H.$#%-'#$.!'$)%6:$H.$='@%($%#$%$0+,##?&4%.3,+<$FG;$.,,47".$V%$#'.$,3$04%##'#$.!%.
#428+A2:102A/56<2:2@+C95,0127;:723+0/26+72/A99+17 rpath28+A2CA/72:,/+20K706327;0
<%7'#$".$&,##"=4'$.,$5+".'$&,+.%=4'$@+%&!"0%4$/#'+$"(.'+3%0'$%&&4"0%.",(#W$=/.$+%&")46$'-,4-')$"(.,$%
LD_LIBRARY_PATH206=51+6C0672=:15:*,027+256@,A30 /usr/local/Trolltech/Qt-4.1.1/libE2%;5/25/
3/44?=4,5($3+%<'5,+7$.!%.$&%+.46$'*.'()#$%()$&%+.46$+'&4%0'#$.!'$L.%()%+)$122$4"=+%+6:$I4.!,/@!
6+7260@0//:182+62)56AK2>57;2eJJE
.!"#$=,,7$/#'#$H.B$".$"#$/#'3/4$.,$7(,5$5!%.$.!'$L.%()%+)$122$4"=+%+6$!%#$.,$,33'+B$#"(0'$6,/$<%6
!%-'$.,$5,+7$5".!$0,)'$.!%.$/#'#$".:
?72@+C0/2>57;2:230C+2:99,5@:75+6- qtdemo-27;:72/;+>/2+442C:682+427;0 ,5*1:18B/240:7A10/E2#72/01=0/2:/
:265@02/7:1756<29+56727+2/002>;:72?72@:623+E2%+2/002?7B/23+@AC067:75+6-2057;012=5/57
;779F\\3+@E71+,,70@;E@+C-2+121A6 &2!--(-&'%&-2?7B/2;0,92:99,5@:75+6-256=+L032*8278956< assistant256 Getting Started with C++
:2@+6/+,02>563+>E
I$122$&+,@+%<$0,(#"#.#$,3$,('$,+$<,+' 4-56&.)0&-(#/(&0%:$X%0!$0,<&"4%.",($/(".$"#$%$#'&%+%.'
#,/+0'$0,)'$3"4'B$.6&"0%446$5".!$% .cpp$'*.'(#",($V,.!'+$0,<<,($'*.'(#",(#$%+' .cc$%() .cxxW$.!%. 14 }
.!'$0,<&"4'+$&+,0'##'#$"($,('$+/(:$N,+$'%0!$0,<&"4%.",($/(".B$.!'$0,<&"4'+$@'('+%.'#$%( -78"40#1&."B
5".!$.!'$'*.'(#",( .obj V,($Y"(),5#W$,+ .o$V,($G("*$%()$S%0$ZL$RW:$ !'$,=>'0.$3"4'$"#$%$="(%+6$3"4'
.!%.$0,(.%"(#$<%0!"('$0,)'$3,+$.!'$%+0!".'0./+'$,($5!"0!$.!'$&+,@+%<$5"44$+/(: !' main.cpp$#,/+0'$3"4'$0,(.%"(#$.!' main()$3/(0.",(U#$)'3"(".",(:$;($122B$.!"#$3/(0.",($.%7'#$%( int
%()$% char *$%++%6$V%($%++%6$,3$0!%+%0.'+$#.+"(@#W$%#$&%+%<'.'+#:$ !'$&+,@+%<U#$(%<'$"#$%-%"4%=4'
Z(0'$%44$.!' .cpp$3"4'#$!%-'$=''($0,<&"4')B$5'$0%($0,<="('$.!'$,=>'0.$3"4'#$.,@'.!'+$.,$0+'%.'$%( %# argv[0]$%()$.!'$0,<<%()?4"('$%+@/<'(.#$%# argv[1]B argv[2]B$\B argv[argc - 1]:$ !'$&%+%<'.'+
'*'0/.%=4'$/#"(@$%$#&'0"%4$&+,@+%<$0%44')$.!' .&(9"::$ !'$4"(7'+$0,(0%.'(%.'#$.!'$,=>'0.$3"4'#$%() (%<'# argc$VM%+@/<'(.$0,/(.MW$%() argv$VM%+@/<'(.$-%4/'#MW$%+'$0,(-'(.",(%4:$;3$.!'$&+,@+%<
+'#,4-'#$.!'$<'<,+6$%))+'##'#$,3$3/(0.",(#$%()$,.!'+$#6<=,4#$+'3'+'(0')$"($.!'$0,<&"4%.",($/(".#: ),'#(U.$%00'##$.!'$0,<<%()?4"('$%+@/<'(.#B$5'$0%($)'3"(' main()$5".!$(,$&%+%<'.'+#:

!"#$#%&'()(&*"+&,--&./01#23%#/4&15/.+66&7/4&8#49/:6; !' main()$3/(0.",($/#'# strtod()$VM#.+"(@$., doubleMWB cout$V122U#$#.%()%+)$,/.&/.$#.+'%<WB$%()


cerr$V122U#$#.%()%+)$'++,+$#.+'%<W$3+,<$.!'$L.%()%+)$122$4"=+%+6$.,$0,(-'+.$.!'$0,<<%()?4"('
%+@/<'(.$.,$% double$%()$.,$&+"(.$.'*.$.,$.!'$0,(#,4':$L.+"(@#B$(/<='+#B$%()$'()?,3?4"('$<%+7'+#
VendlW$%+'$,/.&/.$/#"(@$.!' <<$,&'+%.,+B$5!"0!$"#$%4#,$/#')$3,+$=".?#!"3."(@:$ ,$%00'##$.!"#$#.%()%+)
3/(0.",(%4".6B$5'$('')$.!' #include$)"+'0."-'#$,($4"('#$A$%()$]:

!' using namespace$)"+'0."-'$,($4"('$P$.'44#$.!'$0,<&"4'+$.!%.$5'$5%(.$.,$"<&,+.$%44$")'(."3"'+#


)'04%+')$"($.!' std$(%<'#&%0'$"(.,$.!'$@4,=%4$(%<'#&%0':$ !"#$'(%=4'#$/#$.,$5+".' strtod()B coutB
cerrB$%() endl$"(#.'%)$,3$.!'$3/446?E/%4"3"') std::strtod()B std::coutB std::cerrB$%() std::endl:$;(
122B$.!' ::$,&'+%.,+$#'&%+%.'#$.!'$0,<&,('(.#$,3$%$0,<&4'*$(%<':

!'$)'04%+%.",($,($4"('$^$"#$% 1/(40&-(#6:-0-0;6":$;.$.'44#$.!'$0,<&"4'+$.!%.$%$3/(0.",($'*"#.#$5".!
Y!'($=/"4)"(@$%$&+,@+%<B$'*%0.46$,('$0,<&"4%.",($/(".$</#.$0,(.%"($% main()$3/(0.",($.!%.$#'+-'#$%# .!'$@"-'($&%+%<'.'+#$%()$+'./+($-%4/':$ !'$%0./%4$3/(0.",($0%($='$4,0%.')$"($.!'$#%<'$0,<&"4%.",(
.!'$&+,@+%<U#$'(.+6$&,"(.:$ !"#$3/(0.",($),'#(U.$='4,(@$.,$%(6$04%##J$".$"#$% '.-7).#1/(40&-(: /(".$,+$"($%(,.!'+$0,<&"4%.",($/(".:$Y".!,/.$.!'$3/(0.",($&+,.,.6&'B$.!'$0,<&"4'+$5,/4)(U. 4'.$/#$0%44
.!'$3/(0.",($,($4"('$A]:$_%+%<'.'+$(%<'#$"($3/(0.",($&+,.,.6&'#$%+'$,&.",(%4:
G(4"7'$8%-%B$5!'+'$'%0!$#,/+0'$3"4'$</#.$0,(.%"($'*%0.46$,('$04%##B$122$4'.#$/#$,+@%("Q'$.!'
0,<&"4%.",($/(".#$%#$5'$5%(.:$Y'$0%($"<&4'<'(.$#'-'+%4$04%##'#$"($.!'$#%<' .cpp$3"4'B$,+$#&+'%)$.!' !'$&+,0')/+'$.,$0,<&"4'$.!'$&+,@+%<$-%+"'#$3+,<$&4%.3,+<$.,$&4%.3,+<:$N,+$'*%<&4'B$.,$0,<&"4'$,(
"<&4'<'(.%.",($,3$%$04%##$%0+,##$#'-'+%4 .cpp$3"4'#B$%()$5'$0%($@"-'$.!'$#,/+0'$3"4'#$%(6$(%<'#$5' L,4%+"#$5".!$.!'$L/($122$0,<&"4'+B$5'$5,/4)$.6&'$.!'$3,44,5"(@$0,<<%()#O
4"7':$Y!'($5'$<%7'$%$0!%(@'$"($,('$&%+."0/4%+ .cpp$3"4'B$5'$,(46$('')$.,$+'0,<&"4'$.!%.$3"4'$%()
.!'($+'4"(7$.!'$%&&4"0%.",($.,$0+'%.'$%$('5$'*'0/.%=4':
CC -c main.cpp
K'3,+'$5'$@,$3/+.!'+B$4'.U#$E/"0746$+'-"'5$.!'$#,/+0'$0,)'$,3$%$.+"-"%4$122$&+,@+%<$.!%.$0,<&/.'# CC -c square.cpp
ld main.o square.o -o square
.!'$#E/%+'$,3$%($"(.'@'+:$ !'$&+,@+%<$0,(#"#.#$,3$.5,$0,<&"4%.",($/(".#O main.cpp$%() square.cpp:

['+'U# square.cppO
!'$3"+#.$.5,$4"('#$"(-,7'$.!'$0,<&"4'+$.,$@'('+%.' .o$3"4'#$3,+$.!' .cpp$3"4'#:$ !'$.!"+)$4"('$"(-,7'#
.!'$4"(7'+$%()$@'('+%.'#$%($'*'0/.%=4'$0%44') squareB$5!"0!$5'$0%($"(-,7'$%#$3,44,5#O
1 double square(double n)
2 {
3 return n * n; ./square 64
4 }

!'$&+,@+%<$,/.&/.#$.!'$3,44,5"(@$<'##%@'$.,$.!'$0,(#,4'O
!"#$3"4'$#"<&46$0,(.%"(#$%$@4,=%4$3/(0.",($0%44') square()$.!%.$+'./+(#$.!'$#E/%+'$,3$".#$&%+%<'.'+:

['+'U# main.cppO The square of 64 is 4096

1 #include <cstdlib> ,$0,<&"4'$.!'$&+,@+%<B$6,/$&+,=%=46$5%(.$.,$@'.$!'4&$3+,<$6,/+$4,0%4$122$@/+/:$N%"4"(@$.!"#B$6,/


2 #include <iostream> 0%($#."44$+'%)$.!'$+'#.$,3$.!"#$%&&'()"*$5".!,/.$0,<&"4"(@$%(6.!"(@$%()$3,44,5$.!'$"(#.+/0.",(#$"(
3 using namespace std; 1!%&.'+$A$.,$0,<&"4'$6,/+$3"+#.$122`H.$%&&4"0%.",(:$H.$&+,-")'#$.,,4#$.!%.$<%7'$".$'%#6$.,$=/"4)
4 double square(double); %&&4"0%.",(#$,($%44$&4%.3,+<#:
5 int main(int argc, char *argv[])
6 {
7 if (argc != 2) { K%07$.,$,/+$&+,@+%<O$;($%$+'%4?5,+4)$%&&4"0%.",(B 5'$5,/4)$(,+<%446$&/.$.!' square()$3/(0.",(
8 cerr << "Usage: square <number>" << endl; &+,.,.6&'$"($%$#'&%+%.'$3"4'$%()$"(04/)'$.!%.$3"4'$"($%44$.!'$0,<&"4%.",($/(".#$5!'+'$5'$('')$.,$0%44$.!'
9 return 1; 3/(0.",(:$L/0!$%$3"4'$"#$0%44')$% !")*":#1&."$%()$/#/%446$!%#$% .h$'*.'(#",($V.hhB .hppB$%() .hxx$%+'
10 } %4#,$0,<<,(W:$;3$5'$+'),$,/+$'*%<&4'$/#"(@$.!'$!'%)'+$3"4'$%&&+,%0!B$5'$5,/4)$0+'%.'$%$3"4'$0%44')
11 double n = strtod(argv[1], 0); square.h$5".!$.!'$3,44,5"(@$0,(.'(.#O
12 cout << "The square of " << argv[1] << " is " << square(n) << endl;
13 return 0;
1 #ifndef SQUARE_H )6(%<"0$4"=+%+6$,($<,#.$&4%.3,+<#:$H.$".#'43$"#$%$0,44'0.",($,3$4"=+%+"'#$.!%.$0%($='$=/"4.$'".!'+$%#
2 #define SQUARE_H #.%."0$,+$%#$)6(%<"0$4"=+%+"'#$V.!'$)'3%/4.$"#$)6(%<"0W:
3 double square(double);
4 #endif
Main Language Differences
!'$!'%)'+$3"4'$"#$=+%07'.')$=6$.!+''$&+'&+,0'##,+$)"+'0."-'#$V#ifndefB #defineB$%() #endifW:$ !'#' Y'$5"44$(,5$.%7' %$<,+'$#.+/0./+')$4,,7$%.$.!'$%+'%#$5!'+'$122$)"33'+#$3+,<$8%-%$%()$19:$S%(6$,3
)"+'0."-'#$'(#/+'$.!%.$.!'$!'%)'+$3"4'$"#$&+,0'##')$,(46$,(0'B$'-'($"3$.!'$!'%)'+$3"4'$"#$"(04/)') .!'$4%(@/%@'$)"33'+'(0'#$%+'$)/'$.,$122U#$0,<&"4')$(%./+'$%()$0,<<".<'(.$.,$&'+3,+<%(0':$ !/#B
#'-'+%4$."<'#$"($.!'$#%<'$0,<&"4%.",($/(".$V%$#"./%.",($.!%.$0%($%+"#'$5!'($!'%)'+$3"4'#$"(04/)'$,.!'+ 122$),'#$(,.$0!'07$%++%6$=,/()#$%.$+/(?."<'B$%()$.!'+'$"#$(,$@%+=%@'$0,44'0.,+$.,$+'04%"<$/(/#')
!'%)'+$3"4'#W:$K6$0,(-'(.",(B$.!'$&+'&+,0'##,+$#6<=,4$/#')$.,$%00,<&4"#!$.!"#$"#$)'+"-')$3+,<$.!' )6(%<"0%446$%44,0%.')$<'<,+6:
3"4'$(%<'$V"($,/+$'*%<&4'B SQUARE_HW:$Y'$5"44$0,<'$=%07$.,$.!'$&+'&+,0'##,+$4%.'+$"($.!"#$%&&'()"*:
N,+$.!'$#%7'$,3$=+'-".6B$122$0,(#.+/0.#$.!%.$%+'$('%+46$")'(."0%4$.,$.!'"+$8%-%$%()$19$0,/(.'+&%+.#
!'$('5 main.cpp$3"4'$4,,7#$4"7'$.!"#O %+'$(,.$+'-"'5'):$;($%))".",(B$#,<'$122$.,&"0#$%+'$(,.$0,-'+')$!'+'$='0%/#'$.!'6$%+'$(,.
('0'##%+6$5!'($&+,@+%<<"(@$/#"(@$H.:$I<,(@$.!'#'$%+'$)'3"("(@$.'<&4%.'$04%##'#$%()$3/(0.",(#B
)'3"("(@$/(",($.6&'#B$%()$/#"(@$'*0'&.",(#:$N,+$.!'$5!,4'$#.,+6B$+'3'+$.,$%$=,,7$#/0!$%# !"#233
1 #include <cstdlib> =:-':)55&('#>)('/)'"$=6$K>%+('$L.+,/#.+/&$,+ 233#1-:#?),)#=:-':)55":%$=6$S%+7$I44'(
2 #include <iostream> Y'"##:
3 #include "square.h"
4 using namespace std; Primitive Data Types
5 int main(int argc, char *argv[])
6 {
7 if (argc != 2) { !'$&+"<"."-'$)%.%$.6&'#$,33'+')$=6$.!'$122$4%(@/%@'$%+'$#"<"4%+$.,$.!,#'$3,/()$"($8%-%$,+$19:
8 cerr << "Usage: square <number>" << endl; N"@/+'$K:]$4"#.#$122U#$&+"<"."-'$.6&'#$%()$.!'"+$)'3"(".",($,($.!'$&4%.3,+<#$#/&&,+.')$=6$H.$^:
9 return 1;
10 } K6$)'3%/4.B$.!' shortB intB longB$%() long long$)%.%$.6&'#$%+'$#"@(')B$<'%("(@$.!%.$.!'6$0%($!,4)
11 double n = strtod(argv[1], 0); ('@%."-'$-%4/'#$%#$5'44$%#$&,#"."-'$-%4/'#:$;3$5'$,(46$('')$.,$#.,+'$(,(('@%."-'$"(.'@'+#B$5'$0%($&/.
12 cout << "The square of " << argv[1] << " is " << square(n) << endl; .!' unsigned$7'65,+)$"($3+,(.$,3$.!'$.6&':$Y!"4'$% short$0%($!,4)$%(6$-%4/'$='.5''( ?P]Bbcd$%()
13 return 0;
14 } 2P]BbcbB$%( unsigned short$@,'#$3+,<$D$.,$cCBCPC:$ !'$+"@!.?#!"3.$,&'+%.,+ >>$!%#$/(#"@(')$VM3"44
5".!$D#MW$#'<%(."0#$"3$,('$,3$.!'$,&'+%()#$"#$/(#"@('):

!' #include$)"+'0."-'$,($4"('$P$'*&%()#$.,$.!'$0,(.'(.#$,3$.!'$3"4' square.h:$a"+'0."-'#$.!%.$#.%+.


<#=>5+&'(?(&@5#0#%#A+&,--&%B1+6
5".!$% #$%+'$&"07')$/&$=6$.!'$122$&+'&+,0'##,+$='3,+'$.!'$0,<&"4%.",($&+,&'+$.%7'#$&4%0':$;($.!'
,4)$)%6#B$.!'$&+'&+,0'##,+$5%#$%$#'&%+%.'$&+,@+%<$.!%.$.!'$&+,@+%<<'+$"(-,7')$<%(/%446$='3,+' ,--&%B1+ C+6.5#1%#/4
+/(("(@$.!'$0,<&"4'+:$S,)'+($0,<&"4'+#$!%()4'$.!'$&+'&+,0'##,+$#.'&$"<&4"0".46:
bool K,,4'%($-%4/'
!' #include$)"+'0."-'#$,($4"('#$A$%()$] '*&%()$.,$.!'$0,(.'(.#$,3$.!' cstdlib$%() iostream$!'%)'+ char d?=".$"(.'@'+
3"4'#B$5!"0!$%+'$&%+.$,3$.!'$L.%()%+)$122$4"=+%+6:$L.%()%+)$!'%)'+$3"4'#$!%-'$(, .h$#/33"*:$ !'$%(@4'
=+%07'.#$%+,/()$.!'$3"4'$(%<'#$"()"0%.'$.!%.$.!'$!'%)'+$3"4'#$%+'$4,0%.')$"($%$#.%()%+)$4,0%.",($,( short Ac?=".$"(.'@'+
.!'$#6#.'<B$5!"4'$),/=4'$E/,.'#$.'44$.!'$0,<&"4'+$.,$4,,7$"($.!'$0/++'(.$)"+'0.,+6:$;(04/)'#$%+'
(,+<%446$@%.!'+')$%.$.!'$.,&$,3$% .cpp$3"4': int P]?=".$"(.'@'+
long P]?=".$,+$c^?=".$"(.'@'+
G(4"7' .cpp$3"4'#B$!'%)'+$3"4'#$%+'$(,.$0,<&"4%.",($/(".#$"($.!'"+$,5($+"@!.$%()$),$(,.$+'#/4.$"($%(6
,=>'0.$3"4'#:$ !'6$<%6$,(46$0,(.%"($)'04%+%.",(#$.!%.$'(%=4'$)"33'+'(.$0,<&"4%.",($/(".#$., long longefg c^?=".$"(.'@'+
0,<</("0%.'$5".!$'%0!$,.!'+:$1,(#'E/'(.46B$".$5,/4)$='$"(%&&+,&+"%.'$.,$&/.$.!' square()$3/(0.",(U#
"<&4'<'(.%.",($"($%$!'%)'+$3"4':$;3$5'$)")$#,$"($,/+$'*%<&4'B$(,.!"(@$=%)$5,/4)$!%&&'(B$='0%/#'$5' float P]?=".$34,%."(@?&,"(.$-%4/'$V;XXX$bC^W
"(04/)' square.h$,(46$,(0'B$=/.$"3$5'$"(04/)') square.h$3+,<$#'-'+%4 .cpp$3"4'#B$5'$5,/4)$@'.
</4."&4'$"<&4'<'(.%.",(#$,3$.!' square()$3/(0.",($V,('$&'+ .cpp$3"4'$.!%.$"(04/)'#$".W:$ !'$4"(7'+ double c^?=".$34,%."(@?&,"(.$-%4/'$V;XXX$bC^W
5,/4)$.!'($0,<&4%"($%=,/.$</4."&4'$V")'(."0%4W$)'3"(".",(#$,3 square()$%()$+'3/#'$.,$@'('+%.'$%(
'*'0/.%=4':$;(-'+#'46B$"3$5'$)'04%+'$%$3/(0.",($=/.$('-'+$"<&4'<'(.$".B$.!'$4"(7'+$0,<&4%"(#$%=,/.$%(
M/(+'#,4-')$#6<=,4M:
[*]
Microsoft calls the long long type __int64. In Qt programs, qlonglong is available as an alternative that works on all Qt
platforms.
L,$3%+B$5'$!%-'$%##/<')$.!%.$%($'*'0/.%=4'$,(46$0,(#"#.#$,3$,=>'0.$3"4'#:$;($&+%0."0'B$.!'6$,3.'($%4#,
4"(7$%@%"(#.$4"=+%+"'#$.!%.$"<&4'<'(.$+'%)6?<%)'$3/(0.",(%4".6: !'+'$%+'$.5,$<%"($.6&'#$,3$4"=+%+6O

• <0)0&4#.&7:):&"%$%+'$&/.$)"+'0.46$"(.,$.!'$'*'0/.%=4'B$%#$"3$.!'6$5'+'$,=>'0.$3"4'#:$ !"#$'(#/+'#
!' bool$.6&'$0%($.%7'$.!'$-%4/'# true$%() false:$;($%))".",(B$(/<'+"0$.6&'#$0%($='$/#')$5!'+'$%
.!%.$.!'$4"=+%+6$0%((,.$@'.$4,#.$=/.$"(0+'%#'#$.!'$#"Q'$,3$.!'$'*'0/.%=4':
bool$"#$'*&'0.')B$5".!$.!'$+/4'$.!%.$D$<'%(# false$%()$%(6$(,(?Q'+,$-%4/'$<'%(# TRue:
• $;()5&4#.&7:):&"%$V%4#,$0%44')$#!%+')$4"=+%+"'#$,+$aTT#W$%+'$4,0%.')$%.$%$#.%()%+)$4,0%.",(
,($.!'$/#'+U#$<%0!"('$%()$%+'$%/.,<%."0%446$4,%)')$%.$%&&4"0%.",($#.%+./&:
!' char$.6&'$"#$/#')$=,.!$3,+$#.,+"(@$IL1;;$0!%+%0.'+#$%()$d?=".$"(.'@'+#$V=6.'#W:$Y!'($/#')$%#$%(
N,+$.!' square$&+,@+%<B$5'$4"(7$%@%"(#. .!'$L.%()%+)$122$4"=+%+6B$5!"0!$"#$"<&4'<'(.')$%#$% "(.'@'+B$".$0%($='$#"@(')$,+$/(#"@(')B$)'&'()"(@$,($.!'$&4%.3,+<:$ !'$.6&'# signed char$%()
unsigned char$%+'$%-%"4%=4'$%#$/(%<="@/,/#$%4.'+(%."-'#$., char:$H.$&+,-")'#$% QChar$.6&'$.!%. setY()W:
#.,+'#$Ac?=".$G("0,)'$0!%+%0.'+#:
!'$3/(0.",(#$%=,-'$5'+'$"<&4'<'(.')$"(4"('B$%#$&%+.$,3$.!'$04%##$)'3"(".",(:$I($%4.'+(%."-'$"#$.,
;(#.%(0'#$,3$=/"4.?"($.6&'#$%+'$(,.$"("."%4"Q')$=6$)'3%/4.:$Y!'($5'$0+'%.'$%( int$-%+"%=4'B$".#$-%4/' &+,-")'$,(46$3/(0.",($&+,.,.6&'#$"($.!'$!'%)'+$3"4'$%()$.,$"<&4'<'(.$.!'$3/(0.",(#$"($% .cpp$3"4':
0,/4)$0,(0'"-%=46$='$DB$=/.$0,/4)$>/#.$%#$4"7'46$=' ?]DhB^dcBCAC:$N,+./(%.'46B$<,#.$0,<&"4'+#$5%+( G#"(@$.!"#$%&&+,%0!B$.!'$!'%)'+$3"4'$5,/4)$4,,7$4"7'$.!"#O
/#$5!'($5'$%..'<&.$.,$+'%)$.!'$0,(.'(.#$,3$%($/("("."%4"Q')$-%+"%=4'B$%()$5'$0%($/#'$.,,4#$4"7'
i%.",(%4$_/+"36_4/#$%()$j%4@+"()$.,$)'.'0.$/("."%4"Q')$<'<,+6$%00'##'#$%()$,.!'+$<'<,+6?+'4%.')
&+,=4'<#$%.$+/(?."<': #ifndef POINT2D_H
#define POINT2D_H
;($<'<,+6B$.!'$(/<'+"0$.6&'#$V'*0'&. longW$!%-'$")'(."0%4$#"Q'#$,($.!'$)"33'+'(.$&4%.3,+<# class Point2D
{
#/&&,+.')$=6$H.B$=/.$.!'"+$+'&+'#'(.%.",($-%+"'#$)'&'()"(@$,($.!'$#6#.'<U#$=6.'$,+)'+:$Z($="@?
public:
'()"%($%+0!".'0./+'#$V#/0!$%#$_,5'+_1$%()$L_Ii1WB$.!'$P]?=".$-%4/' 0x12345678$"#$#.,+')$%#$.!'$3,/+ Point2D();
=6.'# 0x12 0x34 0x56 0x78B$5!'+'%#$,($4"..4'?'()"%($%+0!".'0./+'#$V#/0!$%#$;(.'4$*dcWB$.!'$=6.' Point2D(double x, double y);
#'E/'(0'$"#$+'-'+#'):$ !"#$<%7'#$%$)"33'+'(0'$"($&+,@+%<#$.!%.$0,&6$<'<,+6$%+'%#$,(.,$)"#7$,+ void setX(double x);
.!%.$#'()$="(%+6$)%.%$,-'+$.!'$('.5,+7:$H.U# QDataStream$04%##B$&+'#'(.')$"( 1!%&.'+$A] void setY(double y);
V;(&/.`Z/.&/.WB$0%($='$/#')$.,$#.,+'$="(%+6$)%.%$"($%$&4%.3,+<?"()'&'()'(.$5%6: double x() const;
double y() const;
private:
Class Definitions double xVal;
double yVal;
14%##$)'3"(".",(#$"($122$%+'$#"<"4%+$.,$.!,#'$"($8%-%$%()$19B$=/.$.!'+'$%+'$#'-'+%4$)"33'+'(0'#$.,$=' };
%5%+'$,3:$Y'$5"44$#./)6$.!'#'$)"33'+'(0'#$/#"(@$%$#'+"'#$,3$'*%<&4'#:$T'.U#$#.%+.$5".!$%$04%##$.!%. #endif
+'&+'#'(.$%($V@A#;W$0,,+)"(%.'$&%"+O

!'$3/(0.",(#$5,/4)$.!'($='$"<&4'<'(.')$"( point2d.cppO
#ifndef POINT2D_H
#define POINT2D_H
class Point2D
{ #include "point2d.h"
public: Point2D::Point2D()
Point2D() { {
xVal = 0; xVal = 0.0;
yVal = 0; yVal = 0.0;
} }
Point2D(double x, double y) { Point2D::Point2D(double x, double y)
xVal = x; {
yVal = y; xVal = x;
} yVal = y;
void setX(double x) { xVal = x; } }
void setY(double y) { yVal = y; } void Point2D::setX(double x)
double x() const { return xVal; } {
double y() const { return yVal; } xVal = x;
private: }
double xVal; void Point2D::setY(double y)
double yVal; {
}; yVal = y;
#endif }
double Point2D::x() const
{
return xVal;
!'$%=,-'$04%##$)'3"(".",($5,/4)$%&&'%+$"($%$!'%)'+$3"4'B$.6&"0%446$0%44') point2d.h:$ !'$'*%<&4' }
'*!"=".#$.!'$3,44,5"(@$122$")",#6(0+%#"'#O double Point2D::y() const
{
• I$04%##$)'3"(".",($"#$)"-")')$"($&/=4"0B$&+,.'0.')B$%()$&+"-%.'$#'0.",(#B$%()$'()#$5".!$% return yVal;
}
#'<"0,4,(:$;3$(,$#'0.",($"#$#&'0"3"')B$.!'$)'3%/4.$"#$&+"-%.':$VN,+$0,<&%."="4".6$5".!$1B$122
&+,-")'#$% struct$7'65,+)$.!%.$"#$")'(."0%4$., class$'*0'&.$.!%.$.!'$)'3%/4.$"#$&/=4"0$"3$(,
#'0.",($"#$#&'0"3"'):W
• !'$04%##$!%#$.5,$0,(#.+/0.,+#$V,('$.!%.$!%#$(,$&%+%<'.'+#$%()$,('$.!%.$!%#$.5,W:$;3$5' Y'$#.%+.$=6$"(04/)"(@ point2d.h$='0%/#'$.!'$0,<&"4'+$('')#$.!'$04%##$)'3"(".",($='3,+'$".$0%($&%+#'
)'04%+')$(,$0,(#.+/0.,+B$122$5,/4)$%/.,<%."0%446$#/&&46$,('$5".!$(,$&%+%<'.'+#$%()$%( <'<='+$3/(0.",($"<&4'<'(.%.",(#:$ !'($5'$"<&4'<'(.$.!'$3/(0.",(#B$&+'3"*"(@$.!'$3/(0.",($(%<'
'<&.6$=,)6: 5".!$.!'$04%##$(%<'$/#"(@$.!' ::$,&'+%.,+:
• !'$@'..'+$3/(0.",(# x()$%() y()$%+'$)'04%+')$.,$='$0,(#.:$ !"#$<'%(#$.!%.$.!'6$),(U.$V%()
0%(U.W$<,)"36$.!'$<'<='+$-%+"%=4'#$,+$0%44$(,(?0,(#.$<'<='+$3/(0.",(#$V#/0!$%# setX()$%() Y'$!%-'$#''($!,5$.,$"<&4'<'(.$%$3/(0.",($"(4"('$%()$(,5$!,5$.,$"<&4'<'(.$".$"($% .cpp$3"4':$ !'
.5,$%&&+,%0!'#$%+'$#'<%(."0%446$'E/"-%4'(.B$=/.$5!'($5'$0%44$%$3/(0.",($.!%.$"#$)'04%+')$"(4"('B$<,#.
0,<&"4'+#$#"<&46$'*&%()$.!'$3/(0.",(U#$=,)6$"(#.'%)$,3$@'('+%."(@$%($%0./%4$3/(0.",($0%44:$ !"# %$04%##$5".!$,(46$&/+'$-"+./%4$3/(0.",(#$"($122:
(,+<%446$4'%)#$.,$3%#.'+$0,)'B$=/.$<"@!.$"(0+'%#'$.!'$#"Q'$,3$6,/+$%&&4"0%.",(:$N,+$.!"#$+'%#,(B$,(46
-'+6$#!,+.$3/(0.",(#$#!,/4)$='$"<&4'<'(.')$"(4"('J$4,(@'+$3/(0.",(#$#!,/4)$%45%6#$='$"<&4'<'(.') ['+'U#$.!'$)'3"(".",($,3$.!' Circle$#/=04%##O
"($% .cpp$3"4':$;($%))".",(B$"3$5'$3,+@'.$.,$"<&4'<'(.$%$3/(0.",($%()$.+6$.,$0%44$".B$.!'$4"(7'+$5"44
0,<&4%"($%=,/.$%($/(+'#,4-')$#6<=,4:
#ifndef CIRCLE_H
k,5B$4'.U#$.+6$.,$/#'$.!'$04%##: #define CIRCLE_H
#include "shape.h"
class Circle : public Shape
#include "point2d.h" {
int main() public:
{ Circle(Point2D center, double radius = 0.5)
Point2D alpha; : Shape(center) {
Point2D beta(0.666, 0.875); myRadius = radius;
alpha.setX(beta.y()); }
beta.setY(alpha.x()); void draw() {
return 0; // do something here
} }
private:
double myRadius;
};
;($122B$-%+"%=4'#$,3$%(6$.6&'#$0%($='$)'04%+')$)"+'0.46$5".!,/.$/#"(@ new:$ !'$3"+#.$-%+"%=4'$"# #endif
"("."%4"Q')$/#"(@$.!'$)'3%/4. Point2D$0,(#.+/0.,+$V.!'$0,(#.+/0.,+$.!%.$!%#$(,$&%+%<'.'+#W:$ !'
#'0,()$-%+"%=4'$"#$"("."%4"Q')$/#"(@$.!'$#'0,()$0,(#.+/0.,+:$I00'##$.,$%($,=>'0.U#$<'<='+$"#
&'+3,+<')$/#"(@$.!' .$V),.W$,&'+%.,+: !' Circle$04%##$"(!'+".#$&/=4"046$3+,< ShapeB$<'%("(@$.!%.$%44$&/=4"0$<'<='+#$,3 Shape$+'<%"(
&/=4"0$"( Circle:$122$%4#,$#/&&,+.#$&+,.'0.')$%()$&+"-%.'$"(!'+".%(0'B$5!"0!$+'#.+"0.$.!'$%00'##$,3
j%+"%=4'#$)'04%+')$.!"#$5%6$='!%-'$4"7'$8%-%`19$&+"<"."-'$.6&'#$#/0!$%# int$%() double:$N,+ .!'$=%#'$04%##U#$&/=4"0$%()$&+,.'0.')$<'<='+#:
'*%<&4'B$5!'($5'$/#'$.!'$%##"@(<'(.$,&'+%.,+B .!'$0,(.'(.#$,3$.!'$-%+"%=4'$"#$0,&"')(,.$>/#.$%
+'3'+'(0'$.,$%($,=>'0.:$I()$"3$5'$<,)"36$%$-%+"%=4'$4%.'+$,(B$%(6$,.!'+$-%+"%=4'#$.!%.$5'+'$%##"@(') !'$0,(#.+/0.,+$.%7'#$.5,$&%+%<'.'+#:$ !'$#'0,()$&%+%<'.'+$"#$,&.",(%4$%()$.%7'#$.!'$-%4/'$D:C$"3
3+,<$".$%+'$4'3.$/(0!%(@'): (,.$#&'0"3"'):$ !'$0,(#.+/0.,+$&%##'#$.!' center$&%+%<'.'+$.,$.!'$=%#'$04%##U#$0,(#.+/0.,+$/#"(@$%
#&'0"%4$#6(.%*$='.5''($.!'$3/(0.",($#"@(%./+'$%()$.!' 3/(0.",($=,)6:$;($.!'$=,)6B$5'$"("."%4"Q'$.!'
I#$%($,=>'0.?,+"'(.')$4%(@/%@'B$122$#/&&,+.#$"(!'+".%(0'$%()$&,46<,+&!"#<:$ , "44/#.+%.'$!,5$". myRadius$<'<='+$-%+"%=4':$Y'$0,/4)$%4#,$!%-'$"("."%4"Q')$.!'$-%+"%=4'$,($.!'$#%<'$4"('$%#$.!'$=%#'
5,+7#B$5'$5"44$+'-"'5$.!'$'*%<&4'$,3$% Shape$%=#.+%0.$=%#'$04%##$%()$%$#/=04%##$0%44') Circle:$T'.U# 04%##$0,(#.+/0.,+$"("."%4"Q%.",(O
#.%+.$5".!$.!'$=%#'$04%##O

Circle(Point2D center, double radius = 0.5)


#ifndef SHAPE_H : Shape(center), myRadius(radius) { }
#define SHAPE_H
#include "point2d.h"
class Shape
{ Z($.!'$,.!'+$!%()B$122$),'#(U.$%44,5$/#$.,$"("."%4"Q'$%$<'<='+$-%+"%=4'$"($.!'$04%##$)'3"(".",(B$#,
public: .!'$3,44,5"(@$0,)'$"#$5+,(@O
Shape(Point2D center) { myCenter = center; }
virtual void draw() = 0;
protected: // WON'T COMPILE
Point2D myCenter; private:
}; double myRadius = 0.5;
#endif };

!'$)'3"(".",($%&&'%+#$"($%$!'%)'+$3"4'$0%44') shape.h:$L"(0'$.!'$04%##$)'3"(".",($+'3'+#$.,$.!' Point2D !' draw()$3/(0.",($!%#$.!'$#%<'$#"@(%./+'$%#$.!' -"+./%4 draw()$3/(0.",($)'04%+')$"( Shape:$;.$"#$%


04%##B$5'$"(04/)' point2d.h: +'"<&4'<'(.%.",($%()$".$5"44$='$"(-,7')$&,46<,+&!"0%446$5!'( draw()$"#$0%44')$,($% Circle$"(#.%(0'
.!+,/@!$% Shape$+'3'+'(0'$,+$&,"(.'+:$122$!%#$(, override$7'65,+)$4"7'$"($19:$k,+$),'#$122$!%-'
!' Shape$04%##$!%#$(,$=%#'$04%##:$G(4"7'$8%-%$%()$19B$122$),'#(U.$&+,-")'$%$@'('+"0 Object$04%## % super$,+ base$7'65,+)$.!%.$+'3'+#$.,$.!'$=%#'$04%##:$;3$5'$('')$.,$0%44$.!'$=%#'$"<&4'<'(.%.",($,3
3+,<$5!"0!$%44$04%##'#$"(!'+".:$H.$&+,-")'# QObject$%#$%$(%./+%4$=%#'$04%##$3,+$%44$7"()#$,3$,=>'0.#: %$3/(0.",(B$5'$0%($&+'3"*$.!'$3/(0.",($(%<'$5".!$.!'$=%#'$04%##$(%<'$%()$.!' ::$,&'+%.,+:$N,+
'*%<&4'O
!' draw()$3/(0.",($)'04%+%.",($!%#$.5,$"(.'+'#."(@$3'%./+'#O$;.$0,(.%"(#$.!' virtual$7'65,+)B$%()$".
'()#$5".! = 0:$ !' virtual$7'65,+)$"()"0%.'#$.!%.$.!'$3/(0.",($<%6$='$+'"<&4'<'(.')$"($#/=04%##'#:
T"7'$"($19B$122$<'<='+$3/(0.",(#$%+'(U.$+'"<&4'<'(.%=4'$=6$)'3%/4.:$ !'$="Q%++' = 0$#6(.%* class LabeledCircle : public Circle
{
"()"0%.'#$.!%.$.!'$3/(0.",($"#$% 6/:"#,&:0/).#1/(40&-(%$3/(0.",($.!%.$!%#$(,$)'3%/4.$"<&4'<'(.%.",(
public:
%()$.!%.$</#.$='$"<&4'<'(.')$"($#/=04%##'#:$ !'$0,(0'&.$,3$%($M"(.'+3%0'M$"($8%-%$%()$19$<%&#$., void draw() {
Circle::draw();
drawLabel(); cout << Truck::instanceCount() << " equals 2" << endl;
} return 0;
... }
};

122$#/&&,+.#$</4."&4'$"(!'+".%(0'B$<'%("(@$.!%.$%$04%##$0%($)'+"-'$3+,<$#'-'+%4$04%##'#$%.$.!' Pointers
#%<'$."<':$ !'$#6(.%*$"#$%#$3,44,5#O
I 6-&(0":$"($122$"#$%$-%+"%=4'$.!%.$#.,+'#$.!'$<'<,+6$%))+'##$,3$%($,=>'0.$V"(#.'%)$,3$#.,+"(@$.!'
class DerivedClass : public BaseClass1, public BaseClass2, ..., ,=>'0.$)"+'0.46W:$8%-%$%()$19$!%-'$%$#"<"4%+$0,(0'&.B$.!%.$,3$%$M+'3'+'(0'MB$=/.$.!'$#6(.%*$"#
public BaseClassN )"33'+'(.:$Y'$5"44$#.%+.$=6$#./)6"(@$%$0,(.+"-')$'*%<&4'$.!%.$"44/#.+%.'#$&,"(.'+#$"($%0.",(O
{
...
}; 1 #include "point2d.h"
2 int main()
3 {
4 Point2D alpha;
K6$)'3%/4.B$3/(0.",(#$%()$-%+"%=4'#$)'04%+')$"($%$04%##$%+'$%##,0"%.')$5".!$"(#.%(0'#$,3$.!%.$04%##:$Y' 5 Point2D beta;
0%($%4#,$)'04%+'$#.%."0$<'<='+$3/(0.",(#$%()$#.%."0$<'<='+$-%+"%=4'#B$5!"0!$0%($='$/#')$5".!,/.$%( 6 Point2D *ptr;
"(#.%(0':$N,+$'*%<&4'O 7 ptr = &alpha;
8 ptr->setX(1.0);
9 ptr->setY(2.5);
#ifndef TRUCK_H 10 ptr = &beta;
#define TRUCK_H 11 ptr->setX(4.0);
class Truck 12 ptr->setY(4.5);
{ 13 ptr = 0;
public: 14 return 0;
Truck() { ++counter; } 15 }
~Truck() { --counter; }
static int instanceCount() { return counter; }
private:
static int counter; !'$'*%<&4'$+'4"'#$,($.!' Point2D$04%##$3+,<$.!'$&+'-",/#$#/=#'0.",(:$T"('#$^$%()$C$)'3"('$.5,
}; ,=>'0.#$,3$.6&' Point2D:$ !'#'$,=>'0.#$%+' "("."%4"Q')$.,$VDB$DW$=6$.!'$)'3%/4. Point2D$0,(#.+/0.,+:
#endif
T"('$c$)'3"('#$%$&,"(.'+$.,$% Point2D$,=>'0.:$ !'$#6(.%*$3,+$&,"(.'+#$/#'#$%($%#.'+"#7$"($3+,(.$,3$.!'
-%+"%=4'$(%<':$L"(0'$5'$)")$(,.$"("."%4"Q'$.!'$&,"(.'+B$".$0,(.%"(#$%$+%(),<$<'<,+6$%))+'##:$ !"#$"#
!'$#.%."0$<'<='+$-%+"%=4' counter$7''&#$.+%07$,3$!,5$<%(6 truck$"(#.%(0'#$'*"#.$%.$%(6$."<':$ !' #,4-')$,($4"('$b$=6$%##"@("(@ alphaU#$%))+'##$.,$.!'$&,"(.'+:$ !'$/(%+6 &$,&'+%.,+$+'./+(#$.!'
truck$0,(#.+/0.,+$"(0+'<'(.#$".:$ !'$)'#.+/0.,+B$+'0,@("Q%=4'$=6$.!' ~$&+'3"*B$)'0+'<'(.#$".:$;($122B <'<,+6$%))+'##$,3$%($,=>'0.:$I($%))+'##$"#$.6&"0%446$%$P]?=".$,+$%$c^?=".$"(.'@'+$-%4/'$#&'0"36"(@$.!'
.!'$)'#.+/0.,+$"#$%/.,<%."0%446$"(-,7')$5!'($%$#.%."0%446$%44,0%.')$-%+"%=4' @,'#$,/.$,3$#0,&'$,+ ,33#'.$,3$%($,=>'0.$"($<'<,+6:
5!'($%$-%+"%=4'$%44,0%.')$/#"(@ new$"#$)'4'.'):$ !"#$"#$#"<"4%+$.,$.!' finalize()$<'.!,)$"($8%-%B
'*0'&.$.!%.$5'$0%($+'46$,($".$='"(@$0%44')$%.$%$#&'0"3"0$&,"(.$"($."<': Z($4"('#$d$%()$hB$5' %00'##$.!' alpha$,=>'0.$.!+,/@!$.!' ptr$&,"(.'+:$K'0%/#' ptr$"#$%$&,"(.'+$%()
(,.$%($,=>'0.B$5'$</#.$/#'$.!' ->$V%++,5W$,&'+%.,+$"(#.'%)$,3$.!' .$V),.W$,&'+%.,+:
I$#.%."0$<'<='+$-%+"%=4'$!%#$%$#"(@4'$'*"#.'(0'$"($%$04%##O$L/0! -%+"%=4'#$%+'$M04%##$-%+"%=4'#M
+%.!'+$.!%($M"(#.%(0'$-%+"%=4'#M:$X%0!$#.%."0$<'<='+$-%+"%=4'$</#.$='$)'3"(')$"($% .cpp$3"4'$V=/. Z($4"('$ADB$5'$%##"@( betaU#$%))+'##$.,$.!'$&,"(.'+:$N+,<$.!'($,(B$%(6$,&'+%.",($5'$&'+3,+<
5".!,/.$+'&'%."(@$.!' static$7'65,+)W:$N,+$'*%<&4'O .!+,/@!$.!'$&,"(.'+$5"44$%33'0.$.!' beta$,=>'0.:

T"('$AP$#'.#$.!'$&,"(.'+$.,$='$%$(/44$&,"(.'+:$122$!%#$(,$7'65,+)$3,+$+'&+'#'(."(@$%$&,"(.'+$.!%.
#include "truck.h" ),'#$(,.$&,"(.$.,$%($,=>'0.J$"(#.'%)B$5'$/#'$.!'$-%4/'$D$V,+$.!'$#6<=,4"0$0,(#.%(. NULLB$5!"0!
int Truck::counter = 0; '*&%()#$.,$DW:$ +6"(@$.,$/#'$%$(/44$&,"(.'+$+'#/4.#$"($%$0+%#!$5".!$%($'++,+$<'##%@'$#/0!$%#
ML'@<'(.%.",($3%/4.MB$MF'('+%4$&+,.'0.",($3%/4.MB$,+$MK/#$'++,+M:$G#"(@$%$)'=/@@'+B$5'$0%($3"()$,/.
5!"0!$4"('$,3$0,)'$0%/#')$.!'$0+%#!:
N%"4"(@$.,$),$.!"#$5,/4)$+'#/4.$"($%($M/(+'#,4-')$#6<=,4M$'++,+$%.$4"(7$."<':$ !' instanceCount()
#.%."0$3/(0.",($0%($='$%00'##')$3+,<$,/.#")'$.!'$04%##B$&+'3"*')$=6$.!'$04%##$(%<':$N,+$'*%<&4'O I.$.!'$'()$,3$.!'$3/(0.",(B$.!' alpha$,=>'0.$!,4)#$.!'$0,,+)"(%.'$&%"+$VA:DB$]:CWB$5!'+'%# beta$!,4)#
V^:DB$^:CW:

#include <iostream> _,"(.'+#$%+'$,3.'($/#')$.,$#.,+'$,=>'0.#$%44,0%.')$)6(%<"0%446$/#"(@ new:$;($122$>%+@,(B$5'$#%6$.!%.


#include "truck.h" .!'#'$,=>'0.#$%+'$%44,0%.')$,($.!'$M!'%&MB$5!'+'%#$4,0%4$-%+"%=4'#$V-%+"%=4'#$)'3"(')$"(#")'$%
using namespace std; 3/(0.",(W$%+'$#.,+')$,($.!'$M#.%07M:
int main()
{
Truck truck1; ['+'U#$%$0,)'$#("&&'.$.!%.$"44/#.+%.'#$)6(%<"0$<'<,+6$%44,0%.",($/#"(@ newO
Truck truck2;
%()$&'+3,+<%(0'$@%"(#:$19$!%#$% const$7'65,+)$.!%.$"#$-'+6$#"<"4%+$.,$.!%.$,3$122:$ !'$04,#'#.$8%-%
#include "point2d.h" 'E/"-%4'(.$"# finalB$=/.$".$,(46$&+,.'0.#$-%+"%=4'#$3+,<$%##"@(<'(.B$(,.$3+,<$0%44"(@$M(,(?0,(#.M
int main() <'<='+$3/(0.",(#$,($".:
{
Point2D *point = new Point2D;
point->setX(1.0); _,"(.'+#$0%($='$/#')$5".!$=/"4.?"($.6&'#$%#$5'44$%#$5".!$04%##'#:$;($%($'*&+'##",(B$.!'$/(%+6 *
point->setY(2.5); ,&'+%.,+$+'./+(#$.!'$-%4/'$,3$.!'$,=>'0.$%##,0"%.')$5".!$.!'$&,"(.'+:$N,+$'*%<&4'O
delete point;
return 0;
} int i = 10;
int j = 20;
int *p = &i;
int *q = &j;
!' new$,&'+%.,+$+'./+(#$.!'$<'<,+6$%))+'##$,3$%$('546$%44,0%.')$,=>'0.:$Y'$#.,+'$.!'$%))+'##$"($% cout << *p << " equals 10" << endl;
&,"(.'+$-%+"%=4'$%()$%00'##$.!'$,=>'0.$.!+,/@!$.!%.$&,"(.'+:$Y!'($5'$%+'$),('$5".!$.!'$,=>'0.B$5' cout << *q << " equals 20" << endl;
+'4'%#'$".#$<'<,+6$/#"(@$.!' delete$,&'+%.,+:$G(4"7'$8%-%$%()$19B$122$!%#$(,$@%+=%@'$0,44'0.,+J *p = 40;
)6(%<"0%446$%44,0%.')$,=>'0.#$</#.$='$'*&4"0".46$+'4'%#')$/#"(@ delete$5!'($5'$),(U.$('')$.!'< cout << i << " equals 40" << endl;
%(6<,+': 1!%&.'+$]$)'#0+"='#$H.U#$&%+'(.0!"4)$<'0!%("#<B$5!"0!$@+'%.46 #"<&4"3"'#$<'<,+6 p = q;
<%(%@'<'(.$"($122$&+,@+%<#: *p = 100;
cout << i << " equals 40" << endl;
cout << j << " equals 100" << endl;
;3$5'$3,+@'.$.,$0%44 deleteB$.!'$<'<,+6$"#$7'&.$%+,/()$/(."4$.!'$&+,@+%<$3"("#!'#:$ !"#$5,/4)$(,.$='
%($"##/'$"($.!'$'*%<&4'$%=,-'B$='0%/#'$5'$,(46$%44,0%.'$,('$,=>'0.B$=/.$"($%$&+,@+%<$.!%.$%44,0%.'#
('5$,=>'0.#$%44$.!'$."<'B$.!"#$0,/4)$0%/#'$.!'$&+,@+%<$.,$7''&$%44,0%."(@$<'<,+6$/(."4$.!'
<%0!"('U#$<'<,+6$"#$'*!%/#.'):$Z(0'$%($,=>'0.$"#$)'4'.')B$.!'$&,"(.'+$-%+"%=4'$#."44$!,4)#$.!' !' ->$,&'+%.,+B$5!"0!$0%($='$/#')$.,$%00'##$%($,=>'0.U#$<'<='+#$.!+,/@!$%$&,"(.'+B$"#$&/+'
%))+'##$,3$.!'$,=>'0.:$L/0!$%$&,"(.'+$"#$%$M)%(@4"(@$&,"(.'+M$%()$#!,/4)$(,.$='$/#')$.,$%00'##$.!' #6(.%0."0$#/@%+: ;(#.'%)$,3 ptr->memberB$5'$0%($%4#,$5+".' (*ptr).member:$ !'$&%+'(.!'#'#$%+'
,=>'0.:$H.$&+,-")'#$%$M#<%+.M$&,"(.'+B QPointer<T>B$.!%.$%/.,<%."0%446$#'.#$".#'43$.,$D$"3$.!' QObject$". ('0'##%+6$='0%/#'$.!' .$V),.W$,&'+%.,+$!%#$&+'0')'(0'$,-'+$.!'$/(%+6 *$,&'+%.,+:
&,"(.#$.,$"#$)'4'.'):
_,"(.'+#$!%)$%$&,,+$+'&/.%.",($"($1$%()$122B$.,$.!'$'*.'(.$.!%.$8%-%$"#$,3.'($%)-'+."#')$%#$!%-"(@
;($.!'$'*%<&4'$%=,-'B$5'$"(-,7')$.!'$)'3%/4.$0,(#.+/0.,+$%()$0%44') setX()$%() setY()$.,$"("."%4"Q' (,$&,"(.'+#:$;($+'%4".6B122$&,"(.'+#$%+'$0,(0'&./%446$#"<"4%+$.,$8%-%$%()$19$+'3'+'(0'#$'*0'&.$.!%.
.!'$,=>'0.:$Y'$0,/4)$!%-'$/#')$.!'$.5,?&%+%<'.'+$0,(#.+/0.,+$"(#.'%)OE 5'$0%($/#'$&,"(.'+#$.,$".'+%.'$.!+,/@!$<'<,+6B$%#$5'$5"44$#''$4%.'+$"($.!"#$#'0.",(:$N/+.!'+<,+'B.!'
"(04/#",($,3$M0,&6$,($5+".'M$0,(.%"('+$04%##'#$"($H.B %4,(@$5".!$122U#$%="4".6$.,$"(#.%(."%.'$%(6$04%##
,($.!'$#.%07B$<'%(#$.!%.$5'$0%($,3.'($%-,")$&,"(.'+#:
Point2D *point = new Point2D(1.0, 2.5);
References
!'$'*%<&4'$)")(U.$+'E/"+'$.!'$/#'$,3 new$%() delete:$Y'$0,/4)$>/#.$%#$5'44$!%-'$%44,0%.')$.!' ;($%))".",($.,$&,"(.'+#B$122$%4#,$#/&&,+.#$.!'$0,(0'&.$,3$%$M+'3'+'(0'M:$T"7'$%$&,"(.'+B$%$122
,=>'0.$,($.!'$#.%07$%#$3,44,5#O +'3'+'(0'$#.,+'#$.!'$%))+'##$,3$%($,=>'0.: !'$<%"($)"33'+'(0'#$%+'$.!'#'O

• i'3'+'(0'#$%+'$)'04%+')$/#"(@ &$"(#.'%)$,3 *:
Point2D point; • !'$+'3'+'(0'$</#.$='$"("."%4"Q')$%()$0%(U.$='$+'%##"@(')$4%.'+:
point.setX(1.0);
• !'$,=>'0.$%##,0"%.')$5".!$%$+'3'+'(0'$"#$)"+'0.46$%00'##"=4'J$.!'+'$"#$(,$#&'0"%4$#6(.%*$#/0!
point.setY(2.5);
%# *$,+ ->:
• I$+'3'+'(0'$0%((,.$='$(/44:

Z=>'0.#$%44,0%.')$4"7'$.!"#$%+'$%/.,<%."0%446$3+'')$%.$.!'$'()$,3$.!'$=4,07$"($5!"0!$.!'6$%&&'%+:
i'3'+'(0'#$%+'$<,#.46$/#')$5!'($)'04%+"(@$&%+%<'.'+#:$K6$)'3%/4.B$122$/#'#$0%44?=6?-%4/'$%#$".#
&%+%<'.'+?&%##"(@$<'0!%("#<B$<'%("(@$.!%.$5!'($%($%+@/<'(.$"#$&%##')$.,$%$3/(0.",(B$.!'
;3$5'$),(U.$"(.'()$.,$<,)"36$.!'$,=>'0.$.!+,/@!$.!'$&,"(.'+B$5'$0%($)'04%+'$.!'$&,"(.'+$0,(#.:$N,+ 3/(0.",($+'0'"-'#$%$=+%()$('5$0,&6$,3$.!'$,=>'0.:$['+'U#$.!'$)'3"(".",($,3$%$3/(0.",($.!%.$+'0'"-'#$".#
'*%<&4'O &%+%<'.'+#$.!+,/@!$0%44?=6?-%4/'O

const Point2D *ptr = new Point2D(1.0, 2.5); #include <cstdlib>


double x = ptr->x(); using namespace std;
double y = ptr->y(); double manhattanDistance(Point2D a, Point2D b)
// WON'T COMPILE {
ptr->setX(4.0); return abs(b.x() - a.x()) + abs(b.y() - a.y());
*ptr = Point2D(4.0, 4.5); }

!' ptr$0,(#.$&,"(.'+$0%($,(46$='$/#')$.,$0%44$0,(#.$<'<='+$3/(0.",(#$#/0!$%# x()$%() y():$;.$"# Y'$5,/4)$.!'($"(-,7'$.!'$3/(0.",($%#$3,44,5#O


@,,)$#.64'$.,$)'04%+'$&,"(.'+#$0,(#.$5!'($5'$),(U.$"(.'()$.,$<,)"36$.!'$,=>'0.$/#"(@$.!'<:
N/+.!'+<,+'B$"3$.!'$,=>'0.$".#'43$"#$0,(#.B$5'$!%-'$(,$0!,"0'$=/.$.,$/#'$%$0,(#.$&,"(.'+$.,$#.,+'$".#
%))+'##:$ !'$/#'$,3 const$&+,-")'#$"(3,+<%.",($.,$.!'$0,<&"4'+$.!%.$0%($4'%)$.,$'%+46$=/@$)'.'0.",( Point2D broadway(12.5, 40.0);
Point2D harlem(77.5, 50.0);
double distance = manhattanDistance(broadway, harlem);
, 0,(-'+.$%$&,"(.'+$.,$%$+'3'+'(0'B$.!'+'U#$.!'$/(%+6 *$,&'+%.,+O

i'3,+<')$1$&+,@+%<<'+#$%-,")$('')4'##$0,&6$,&'+%.",(#$=6$)'04%+"(@$.!'"+$&%+%<'.'+#$%#$&,"(.'+#
"(#.'%)$,3$%#$-%4/'#O Point2D point;
Point2D *ptr = &point;
Point2D &ref = *ptr;
double manhattanDistance(const Point2D *ap, const Point2D *bp)
{
return abs(bp->x() - ap->x()) + abs(bp->y() - ap->y());
i'3'+'(0'#$%()$&,"(.'+#$%+'$+'&+'#'(.')$.!'$#%<'$5%6$"($<'<,+6B$%()$.!'6$0%($,3.'($='$/#')
}
"(.'+0!%(@'%=46B$5!"0!$='@#$.!'$E/'#.",($,3$5!'($.,$/#'$5!"0!:$Z($.!'$,('$!%()B$+'3'+'(0'#$!%-'$%
<,+'$0,(-'("'(.$#6(.%*J$,($.!'$,.!'+$!%()B$&,"(.'+#$0%($='$+'%##"@(')$%.$%(6$."<'$.,$&,"(.$.,
%(,.!'+$,=>'0.B$.!'6$0%($!,4)$%$(/44$-%4/'B$%()$.!'"+$<,+'$'*&4"0".$#6(.%*$"#$,3.'($%$=4'##"(@$"(
!'6$</#.$.!'($&%##$%))+'##'#$"(#.'%)$,3$-%4/'#$5!'($0%44"(@$.!'$3/(0.",(O )"#@/"#':$N,+$.!'#'$+'%#,(#B$&,"(.'+#$.'()$.,$&+'-%"4B$5".!$+'3'+'(0'#$%4<,#.$'*04/#"-'46$/#')$3,+
)'04%+"(@$3/(0.",($&%+%<'.'+#B$"($0,(>/(0.",($5".! const:

Point2D broadway(12.5, 40.0);


Point2D harlem(77.5, 50.0); Arrays
double distance = manhattanDistance(&broadway, &harlem);
I++%6#$"($122$%+'$)'04%+')$=6$#&'0"36"(@$.!'$(/<='+$,3$".'<#$"($.!'$%++%6$5".!"($=+%07'.#$"($.!'
-%+"%=4'$)'04%+%.",( )10":$.!'$-%+"%=4'$(%<':$ 5,?)"<'(#",(%4$%++%6#$%+'$&,##"=4'$/#"(@$%($%++%6$,3
122$"(.+,)/0')$+'3'+'(0'#$.,$<%7'$.!'$#6(.%*$4'##$0/<='+#,<'$%()$.,$&+'-'(.$.!'$0%44'+$3+,< %++%6#:$['+'U#$.!'$)'3"(".",($,3$%$,('?)"<'(#",(%4$%++%6$0,(.%"("(@$AD$".'<#$,3$.6&' intO
&%##"(@$%$(/44$&,"(.'+:$;3$5'$/#'$+'3'+'(0'#$"(#.'%)$,3$&,"(.'+#B$.!'$3/(0.",($4,,7#$4"7'$.!"#O

int fibonacci[10];
double manhattanDistance(const Point2D &a, const Point2D &b)
{
return abs(b.x() - a.x()) + abs(b.y() - a.y()); !'$".'<#$%+'$%00'##"=4'$%# fibonacci[0]B fibonacci[1]B$\B fibonacci[9]:$Z3.'($5'$5%(.$.,$"("."%4"Q'
} .!'$%++%6$%#$5'$)'3"('$".O

!'$)'04%+%.",($,3$%$+'3'+'(0'$"#$#"<"4%+$.,$.!%.$,3$%$&,"(.'+B$5".! &$"(#.'%)$,3 *:$K/.$5!'($5' int fibonacci[10] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };


%0./%446$/#'$.!'$+'3'+'(0'B$5'$0%($3,+@'.$.!%.$".$"#$%$<'<,+6$%))+'##$%()$.+'%.$".$4"7'$%($,+)"(%+6
-%+"%=4':$;($%))".",(B$0%44"(@$%$3/(0.",($.!%.$.%7'#$+'3'+'(0'#$%#$%+@/<'(.#$),'#(U.$+'E/"+'$%(6
#&'0"%4$0%+'$V(, &$,&'+%.,+W: ;($#/0!$0%#'#B$5'$0%($.!'($,<".$.!'$%++%6$#"Q'B$#"(0'$.!'$0,<&"4'+$0%($)')/0'$".$3+,<$.!'$(/<='+$,3
"("."%4"Q'+#O
I44$"($%44B$=6$+'&4%0"(@ Point2D$5".! const Point2D &$"($.!'$&%+%<'.'+$4"#.B$5'$+')/0')$.!'$,-'+!'%)
,3$.!'$3/(0.",($0%44O$;(#.'%)$,3$0,&6"(@$]Cc$=".#$V.!'$#"Q'$,3$3,/+ double#WB$5'$0,&6$,(46$c^$,+$A]d
=".#B$)'&'()"(@$,($.!'$.%+@'.$&4%.3,+<U#$&,"(.'+$#"Q': int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

!'$&+'-",/#$'*%<&4'$/#')$0,(#.$+'3'+'(0'#B$&+'-'(."(@$.!'$3/(0.",($3+,<$<,)"36"(@$.!'$,=>'0.#
%##,0"%.')$5".!$.!'$+'3'+'(0'#:$Y!'($.!"#$7"()$,3$#")'$'33'0.$"#$)'#"+')B$5'$0%($&%##$%$(,(?0,(#. L.%."0$"("."%4"Q%.",($%4#,$5,+7#$3,+$0,<&4'*$.6&'#B$#/0!$%# Point2DO
+'3'+'(0'$,+$&,"(.'+:$N,+$'*%<&4'O

Point2D triangle[] = {
void transpose(Point2D &point) Point2D(0.0, 0.0), Point2D(1.0, 0.0), Point2D(0.5, 0.866)
{ };
double oldX = point.x();
point.setX(point.y());
point.setY(oldX);
} ;3$5'$!%-'$(,$"(.'(.",($,3$%4.'+"(@$.!'$%++%6$4%.'+$,(B$5'$0%($<%7'$".$0,(#.O

const int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };


;($#,<'$0%#'#B$5'$!%-'$%$+'3'+'(0'$%()$5'$('')$.,$0%44$%$3/(0.",($.!%.$.%7'#$%$&,"(.'+B$,+$-"0'
-'+#%:$ ,$0,(-'+.$%$+'3'+'(0'$.,$%$&,"(.'+B$5'$0%($#"<&46$/#'$.!'$/(%+6 &$,&'+%.,+O

,$3"()$,/.$!,5$<%(6$".'<#$%($%++%6$0,(.%"(#B$5'$0%($/#'$.!' sizeof()$,&'+%.,+$%#$3,44,5#O
Point2D point;
Point2D &ref = point;
Point2D *ptr = &ref; int n = sizeof(fibonacci) / sizeof(fibonacci[0]);
;+,("0%446B$%4.!,/@!$122$),'#(U.$@"-'$/#$%(6$0!,"0'$%=,/.$5!'.!'+$5'$5%(.$.,$&%##$%($%++%6$=6
!' sizeof() ,&'+%.,+$+'./+(#$.!'$#"Q'$,3$".#$%+@/<'(.$"($=6.'#:$ !'$(/<='+$,3$".'<#$"($%($%++%6$"# %))+'##$,+$=6$-%4/'B$".$@"-'#$/#$#,<'$3+''),<$"($.!' %;(0)@$/#')$.,$)'04%+'$.!'$&%+%<'.'+$.6&':
".#$#"Q'$"($=6.'#$)"-")')$=6$.!'$#"Q'$,3$,('$,3$".#$".'<#:$K'0%/#'$.!"#$"#$0/<='+#,<'$.,$.6&'B$% ;(#.'%)$,3 const int *tableB$5'$0,/4)$%4#,$!%-'$5+"..'( const int table[]$.,$)'04%+'$%$&,"(.'+?.,?
0,<<,($%4.'+(%."-'$"#$.,$)'04%+'$%$0,(#.%(.$%()$.,$/#'$".$3,+$)'3"("(@$.!'$%++%6O 0,(#.%(.? int$&%+%<'.'+:$L"<"4%+46B$.!' argv$&%+%<'.'+$., main()$0%($='$)'04%+')$%#$'".!'+ char
*argv[]$,+ char **argv:

enum { NFibonacci = 10 }; ,$0,&6$%($%++%6$"(.,$%(,.!'+$%++%6B$,('$%&&+,%0! "#$.,$4,,&$.!+,/@!$.!'$%++%6O


const int fibonacci[NFibonacci] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

const int fibonacci[NFibonacci] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };


;.$5,/4)$!%-'$=''($.'<&."(@$.,$)'04%+'$.!'$0,(#.%(.$%#$% const int$-%+"%=4':$G(3,+./(%.'46B$#,<' int temp[NFibonacci];
0,<&"4'+#$!%-'$"##/'#$5".!$0,(#.$-%+"%=4'#$%#$%++%6$#"Q'$#&'0"3"'+#:$ !' enum$7'65,+)$5"44$=' for (int i = 0; i < NFibonacci; ++i)
temp[i] = fibonacci[i];
'*&4%"(')$4%.'+$"($.!"#$%&&'()"*:

;.'+%."(@$.!+,/@!$%($%++%6$"#$(,+<%446$),('$/#"(@$%($"(.'@'+:$N,+$'*%<&4'O
N,+$=%#"0$)%.%$.6&'#$#/0!$%# intB$5'$0%($%4#,$/#' std::memcpy()B$5!"0!$0,&"'#$%$=4,07$,3$<'<,+6:
N,+$'*%<&4'O
for (int i = 0; i < NFibonacci; ++i)
cout << fibonacci[i] << endl;
memcpy(temp, fibonacci, sizeof(fibonacci));

;.$"#$%4#,$&,##"=4'$.,$.+%-'+#'$.!'$%++%6$/#"(@$%$&,"(.'+O
Y!'($5'$)'04%+'$%$122$%++%6B$.!'$#"Q'$</#.$='$%$0,(#.%(.: efg$;3$5'$5%(.$.,$0+'%.'$%($%++%6$,3$%
-%+"%=4'$#"Q'B$5'$!%-'$#'-'+%4$,&.",(#:
const int *ptr = &fibonacci[0];
[*]
while (ptr != &fibonacci[10]) { Some compilers allow variables in that context, but this feature should not be relied upon in portable programs.
cout << *ptr << endl;
++ptr; • 8+&.34&9B430#.322B&322/.3%+&%"+&3553BD
} •
• int *fibonacci = new int[n];

Y'$"("."%4"Q'$.!'$&,"(.'+$5".!$.!'$%))+'##$,3$.!'$3"+#.$".'<$%()$4,,&$/(."4$5'$+'%0!$.!'$M,('$&%#.$.!' !' new []$,&'+%.,+$%44,0%.'#$%$0'+.%"($(/<='+$,3$".'<#$%.$0,(#'0/."-'$<'<,+6$4,0%.",(#$%()


4%#.M$".'<$V.!'$M'4'-'(.!M$".'<B fibonacci[10]W:$I.$'%0!$".'+%.",(B$.!' ++$,&'+%.,+$%)-%(0'#$.!' +'./+(#$%$&,"(.'+$.,$.!'$3"+#.$".'<:$ !%(7#$.,$.!'$M'E/"-%4'(0'$,3$&,"(.'+#$%()$%++%6#M
&,"(.'+$.,$.!'$('*.$".'<: &+"(0"&4'B$.!'$".'<#$0%($='$%00'##')$.!+,/@!$.!'$&,"(.'+$%# fibonacci[0]B fibonacci[1]B$\B
fibonacci[n - 1]:$Y!'($5'$!%-'$3"("#!')$/#"(@$.!'$%++%6B$5'$#!,/4)$+'4'%#'$.!'$<'<,+6$".
;(#.'%)$,3 &fibonacci[0]B$5'$0,/4)$%4#,$!%-'$5+"..'( fibonacci:$ !"#$"#$='0%/#'$.!'$(%<'$,3$%( 0,(#/<'#$/#"(@$.!' delete []$,&'+%.,+O
%++%6$/#')$%4,('$"#$%/.,<%."0%446$0,(-'+.')$"(.,$%$&,"(.'+$.,$.!'$3"+#.$".'<$"($.!'$%++%6:$L"<"4%+46B$5'
0,/4)$#/=#."./.' fibonacci + 10$3,+ &fibonacci[10]:$ !"#$5,+7#$.!'$,.!'+$5%6$%+,/()$%#$5'44O$Y'
0%($+'.+"'-'$.!'$0,(.'(.#$,3$.!'$0/++'(.$".'<$/#"(@$'".!'+ *ptr$,+ ptr[0]$%()$0,/4)$%00'##$.!'$('*. delete [] fibonacci;
".'<$/#"(@ *(ptr + 1)$,+ ptr[1]:$ !"#$&+"(0"&4'$"#$#,<'."<'#$0%44')$M'E/"-%4'(0'$,3$&,"(.'+#$%()
%++%6#M: • 8+&.34&>6+&%"+&6%349359&6%9DDA+.%/5E*F&.2366D

,$&+'-'(.$5!%.$".$0,(#")'+#$.,$='$%$@+%./".,/#$"('33"0"'(06B$122$),'#$(,.$4'.$/#$&%##$%++%6#$., • #include <vector>
3/(0.",(#$=6$-%4/':$;(#.'%)B$.!'6$</#.$='$&%##')$=6$%))+'##:$N,+ '*%<&4'O • using namespace std;
• vector<int> fibonacci(n);

#include <iostream>
;.'<#$%+'$%00'##"=4'$/#"(@$.!' []$,&'+%.,+B$>/#.$4"7'$5".!$%$&4%"($122$%++%6:$Y".!
using namespace std;
void printIntegerTable(const int *table, int size) std::vector<T>$V5!'+' T$"#$.!'$.6&'$,3$.!'$".'<#$#.,+')$"($.!'$-'0.,+WB$5'$0%($+'#"Q'$.!'
{ %++%6$%.$%(6$."<'$/#"(@ resize()$%()$5'$0%($0,&6$".$/#"(@$.!'$%##"@(<'(.$,&'+%.,+:$14%##'#
for (int i = 0; i < size; ++i) .!%.$0,(.%"($%(@4'$=+%07'.#$V<>W$"($.!'"+$(%<'$%+'$0%44')$.'<&4%.'$04%##'#:
cout << table[i] << endl;
} • 8+&.34&>6+&G%H6&GI+.%/5E*F&.2366D
int main() •
{
• #include <QVector>
const int fibonacci[10] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };
printIntegerTable(fibonacci, 10); • QVector<int> fibonacci(n);
return 0;
} QVector<T>U#$I_;$"#$-'+6$#"<"4%+$.,$.!%.$,3 std::vector<T>B$=/.$".$%4#,$#/&&,+.#$".'+%.",($/#"(@
H.U# foreach$7'65,+)$%()$/#'#$"<&4"0". )%.%$#!%+"(@$VM0,&6$,($5+".'MW$%#$%$<'<,+6$%()
#&'')$,&."<"Q%.",(: 1!%&.'+$AA$&+'#'(.#$H.U#$0,(.%"('+$04%##'#$%()$'*&4%"(#$!,5$.!'6$+'4%.' {
.,$.!'$L.%()%+)$122$0,(.%"('+#: cout << str << endl;
}
int main(int argc, char *argv[])
l,/$<"@!.$='$.'<&.')$.,$%-,")$=/"4.?"($%++%6#$5!'('-'+$&,##"=4'$%()$/#' std::vector<T>$,+
{
QVector<T>$"(#.'%):$;.$"#$(,('.!'4'##$5,+.!5!"4'$/()'+#.%()"(@$!,5$.!'$=/"4.?"($%++%6#$5,+7$='0%/#' for (int i = 1; i < argc; ++i) {
#,,('+$,+$4%.'+$6,/$<"@!.$5%(.$.,$/#'$.!'<$"($!"@!46$,&."<"Q')$0,)'B$,+$('')$.!'<$.,$"(.'+3%0'$5".! makeUppercase(argv[i]);
'*"#."(@$1$4"=+%+"'#: writeLine(argv[i]);
}
Character Strings return 0;
}

!'$<,#.$=%#"0$5%6$,3$+'&+'#'(."(@$0!%+%0.'+$#.+"(@#$"($122$"#$.,$/#'$%($%++%6$,3 char#$.'+<"(%.')
=6$%$(/44$=6.'$VUmDUW:$ !'$3,44,5"(@$3,/+$3/(0.",(#$)'<,(#.+%.'$!,5$.!'#'$7"()#$,3$#.+"(@#$5,+7O
;($122B$.!' char$.6&'$(,+<%446$!,4)#$%($d?=".$-%4/':$ !"#$<'%(#$.!%.$5'$0%($'%#"46$#.,+'$IL1;;B$;LZ
ddCh?A$VT%."(?AWB$%()$,.!'+$d?=".?'(0,)')$#.+"(@#$"($% char$%++%6B$=/.$.!%.$5'$0%(U.$#.,+'$%+=".+%+6
void hello1() G("0,)'$0!%+%0.'+#$5".!,/.$+'#,+."(@$.,$</4."=6.'$#'E/'(0'#:$H.$&+,-")'#$.!'$&,5'+3/4 QString
{ 04%##B$5!"0!$#.,+'#$G("0,)'$#.+"(@#$%#$#'E/'(0'#$,3$Ac?=". QChar#$%()$"(.'+(%446$/#'#$.!'$"<&4"0".
const char str[] = { )%.%$#!%+"(@$VM0,&6$,($5+".'MW$,&."<"Q%.",(: 1!%&.'+$AA$V1,(.%"('+$14%##'#W$%() 1!%&.'+$Ab
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' V;(.'+(%.",(%4"Q%.",(W$'*&4%"( QString$"($<,+'$)'.%"4:
};
cout << str << endl;
} Enumerations
void hello2()
{ 122$!%#$%($'(/<'+%.",($3'%./+'$3,+$)'04%+"(@$%$#'.$,3$(%<')$0,(#.%(.#$#"<"4%+$.,$.!%.$&+,-")')$=6
const char str[] = "Hello world!"; 19:$T'.U#$#/&&,#'$.!%.$5'$5%(.$.,$#.,+'$)%6#$,3$.!'$5''7$"($%$&+,@+%<O
cout << str << endl;
}
void hello3() enum DayOfWeek {
{ Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
cout << "Hello world!" << endl; };
}
void hello4()
{
const char *str = "Hello world!"; k,+<%446B$5'$5,/4)$&/.$.!"#$)'04%+%.",($"($%$!'%)'+$3"4'B$,+$'-'($"(#")'$%$04%##:$ !'$%=,-'
cout << str << endl; )'04%+%.",($"#$#/&'+3"0"%446$'E/"-%4'(.$.,$.!'$3,44,5"(@$0,(#.%(.$)'3"(".",(#O
}

const int Sunday = 0;


;($.!'$3"+#.$3/(0.",(B$5'$)'04%+'$.!'$#.+"(@$%#$%($%++%6$%()$"("."%4"Q'$".$.!'$!%+)$5%6:$k,."0'$.!'$UmDU const int Monday = 1;
const int Tuesday = 2;
.'+<"(%.,+$%.$.!'$'()B$5!"0!$"()"0%.'#$.!'$'()$,3$.!'$#.+"(@:$ !'$#'0,()$3/(0.",($!%#$%$#"<"4%+$%++%6
const int Wednesday = 3;
)'3"(".",(B$=/.$.!"#$."<'$5'$/#'$%$#.+"(@$4".'+%4$.,$"("."%4"Q'$.!'$%++%6:$;($122B$#.+"(@$4".'+%4#$%+' const int Thursday = 4;
#"<&46 const char$%++%6#$5".!$%($"<&4"0".$UmDU$.'+<"(%.,+:$ !'$.!"+)$3/(0.",($/#'#$%$#.+"(@$4".'+%4 const int Friday = 5;
)"+'0.46B$5".!,/.$@"-"(@$".$%$(%<':$Z(0'$.+%(#4%.')$"(.,$<%0!"('$4%(@/%@'$"(#.+/0.",(#B$".$"#$")'(."0%4 const int Saturday = 6;
.,$.!'$&+'-",/#$.5,$3/(0.",(#:

!'$3,/+.!$3/(0.",($"#$%$=".$)"33'+'(.$"($.!%.$".$0+'%.'#$(,.$,(46$%($V%(,(6<,/#W$%++%6$=/.$%4#,$%
K6$/#"(@$.!'$'(/<'+%.",($0,(#.+/0.B$5'$0%($4%.'+$)'04%+'$-%+"%=4'#$,+$&%+%<'.'+#$,3$.6&' DayOfWeek
&,"(.'+$-%+"%=4'$0%44') str$.!%.$#.,+'#$.!'$%))+'##$,3$.!'$%++%6U#$3"+#.$".'<:$;($#&".'$,3$.!"#B$.!'
%()$.!'$0,<&"4'+$5"44$'(#/+'$.!%.$,(46$-%4/'#$3+,<$.!' DayOfWeek$'(/<'+%.",($%+'$%##"@(')$.,$".:$N,+
#'<%(."0#$,3$.!'$3/(0.",($%+'$")'(."0%4$.,$.!'$&+'-",/#$.!+''$3/(0.",(#B$%()$%($,&."<"Q"(@$0,<&"4'+
'*%<&4'O
5,/4)$'4"<"(%.'$.!'$#/&'+34/,/# str$-%+"%=4':

N/(0.",(#$.!%.$.%7'$122$#.+"(@#$%#$%+@/<'(.#$/#/%446$.%7'$'".!'+$% char *$,+$% const char *:$['+'U# DayOfWeek day = Sunday;


%$#!,+.$&+,@+%<$.!%.$"44/#.+%.'#$.!'$/#'$,3$=,.!O

;3$5'$),(U.$0%+'$%=,/.$.6&'$#%3'.6B$5'$0%($%4#,$5+".'
#include <cctype>
#include <iostream>
using namespace std;
void makeUppercase(char *str) int day = Sunday;
{
for (int i = 0; str[i] != '\0'; ++i)
str[i] = toupper(str[i]); k,."0'$.!%.$.,$+'3'+$.,$.!' Sunday 0,(#.%(.$3+,<$.!' DayOfWeek$'(/<B$5'$#"<&46$5+".' SundayB$(,.
}
void writeLine(const char *str)
DayOfWeek::Sunday: }

K6$)'3%/4.B$.!'$0,<&"4'+$%##"@(#$0,(#'0/."-'$"(.'@'+$-%4/'#$.,$.!'$0,(#.%(.#$,3$%($'(/<B$#.%+."(@$%.
D:$Y'$0%($#&'0"36$,.!'+$-%4/'#$"3$5'$5%(.O I$-%+"%=4'$,3$.6&' FindOption$0%($,(46$0,(.%"($,('$34%@$%.$%$."<':$ !'$+'#/4.$,3$0,<="("(@$#'-'+%4
34%@#$/#"(@ |$"#$%$&4%"($"(.'@'+:$G(3,+./(%.'46B$.!"#$"#$(,.$.6&'?#%3'O$ !'$0,<&"4'+$5,(U.$0,<&4%"($"3$%
3/(0.",($'*&'0."(@$%$0,<="(%.",($,3 FindOption#$.!+,/@!$%( int$&%+%<'.'+$+'0'"-'# Saturday
enum DayOfWeek { "(#.'%):$H.$/#'# QFlags<T>$.,$&+,-")'$.6&'$#%3'.6$3,+$".#$,5($34%@$.6&'#:$ !'$04%##$"#$%4#,$%-%"4%=4'
Sunday = 628, 5!'($5'$)'3"('$0/#.,<$34%@$.6&'#:$L''$.!' QFlags<T>$,(4"('$),0/<'(.%.",($3,+$)'.%"4#:
Monday = 616,
Tuesday = 735,
Wednesday = 932, Typedefs
Thursday = 852,
Friday = 607, 122$4'.#$/#$@"-'$%($%4"%#$.,$%$)%.%$.6&'$/#"(@$.!' typedef$7'65,+):$N,+$'*%<&4'B$"3$5'$/#'
Saturday = 845
QVector<Point2D>$%$4,.$%() 5%(.$.,$#%-'$%$3'5$7'6#.+,7'#$V,+$%+'$/(3,+./(%.'$'(,/@!$.,$='$#./07
};
5".!$%$k,+5'@"%($7'6=,%+)$%()$!%-'$.+,/=4'$4,0%."(@$.!'$%(@4'$=+%07'.#WB$5'$0%($&/.$.!"#$.6&')'3
)'04%+%.",($"($,('$,3$,/+$!'%)'+$3"4'#O

;3$5'$),(U.$#&'0"36$.!'$-%4/'$,3$%($'(/<$".'<B$.!'$".'<$.%7'#$.!'$-%4/'$,3$.!'$&+'-",/#$".'<B$&4/#$A:
X(/<#$%+' #,<'."<'#$/#')$.,$)'04%+'$"(.'@'+$0,(#.%(.#B$"($5!"0!$0%#'$5'$(,+<%446$,<".$.!'$(%<' typedef QVector<Point2D> PointVector;
,3$.!'$'(/<O

N+,<$.!'( ,(B$5'$0%($/#' PointVector$%#$%$#!,+.!%()$3,+ QVector<Point2D>:$k,."0'$.!%.$.!'$('5


enum {
FirstPort = 1024, (%<'$3,+$.!'$.6&'$%&&'%+#$%3.'+$.!'$,4)$(%<':$ !'$.6&')'3$#6(.%*$)'4"='+%.'46$<"<"0#$.!%.$,3
MaxPorts = 32767 -%+"%=4'$)'04%+%.",(#:
};
;($H.B$.6&')'3#$%+'$/#')$<%"(46$3,+$.!+''$+'%#,(#O

I(,.!'+$3+'E/'(.$/#'$,3$'(/<#$"#$.,$+'&+'#'(.$#'.#$,3$,&.",(#:$T'.U#$0,(#")'+$.!'$'*%<&4'$,3$%$N"() • 2-(,"(&"(4"B$H.$)'04%+'# uint$%() QWidgetList$%#$.6&')'3#$3,+ unsigned int$%()


)"%4,@B$5".!$3,/+$0!'07=,*'#$0,(.+,44"(@$.!'$#'%+0!$%4@,+".!<$VY"4)0%+)$#6(.%*B$1%#'$#'(#"."-'B QList<QWidget *>$.,$#%-'$%$3'5$7'6#.+,7'#:
L'%+0!$=%075%+)B$%()$Y+%&$%+,/()W:$Y'$0%($+'&+'#'(.$.!"#$=6$%($'(/<$5!'+'$.!'$0,(#.%(.#$%+' • =.)01-:5#*&11":"(4"%B$1'+.%"($.6&'#$('')$)"33'+'(.$)'3"(".",(#$,($)"33'+'(.$&4%.3,+<#:$N,+
&,5'+#$,3$]O '*%<&4'B qlonglong$"#$)'3"(')$%# __int64$,($Y"(),5#$%()$%# long long$,($,.!'+$&4%.3,+<#:
• 2-56)0&7&.&0;B$ !' QIconSet$04%##$3+,<$H.$P$5%#$+'(%<') QIcon$"($H.$^:$ ,$!'4&$H.$P$/#'+#
&,+.$.!'"+$%&&4"0%.",(#$.,$H.$^B QIconSet$"#$&+,-")')$%#$%$.6&')'3$3,+ QIcon$5!'($H.$P
enum FindOption { 0,<&%."="4".6$"#$'(%=4'):
NoOptions = 0x00000000,
WildcardSyntax = 0x00000001,
CaseSensitive = 0x00000002,
Type Conversions
SearchBackward = 0x00000004,
WrapAround = 0x00000008 122$&+,-")'#$#'-'+%4$#6(.%*'#$3,+$0%#."(@$-%4/'#$3+,<$,('$.6&'$.,$%(,.!'+:$ !'$.+%)".",(%4$#6(.%*B
}; "(!'+".')$3+,<$1B$"(-,4-'#$&/.."(@$.!'$+'#/4."(@$.6&'$"($&%+'(.!'#'#$='3,+'$.!'$-%4/'$.,$0,(-'+.O

X%0!$,&.",($"#$,3.'($0%44')$%$M34%@M:$Y'$0%($0,<="('$34%@#$/#"(@$.!'$=".5"#' |$,+ |=$,&'+%.,+#O const double Pi = 3.14159265359;


int x = (int)(Pi * 100);
cout << x << " equals 314" << endl;
int options = NoOptions;
if (wilcardSyntaxCheckBox->isChecked())
options |= WildcardSyntax; !"#$#6(.%*$"#$-'+6$&,5'+3/4:$;.$0%($='$/#')$.,$0!%(@'$.!'$.6&'$,3$&,"(.'+#B$.,$+'<,-' constB$%()
if (caseSensitiveCheckBox->isChecked()) </0!$<,+':$N,+$'*%<&4'O
options |= CaseSensitive;
if (searchBackwardCheckBox->isChecked())
options |= SearchBackwardSyntax; short j = 0x1234;
if (wrapAroundCheckBox->isChecked()) if (*(char *)&j == 0x12)
options |= WrapAround; cout << "The byte order is big-endian" << endl;

Y'$0%($.'#.$5!'.!'+$%$34%@$"#$#'.$,+$(,.$/#"(@$.!'$=".5"#' &$,&'+%.,+O ;($.!'$'*%<&4'$%=,-'B$5'$0%#.$% short *$.,$% char *$%()$5'$/#'$.!'$/(%+6 *$,&'+%.,+$.,$%00'##$.!'


=6.'$%.$.!'$@"-'($<'<,+6$4,0%.",(:$Z($="@?'()"%($#6#.'<#B$.!%.$=6.'$"# 0x12J$,($4"..4'?'()"%(
#6#.'<#B$.!%.$=6.'$"# 0x34:$L"(0'$&,"(.'+#$%()$+'3'+'(0'#$%+'$+'&+'#'(.')$.!'$#%<'$5%6B$".$#!,/4)
if (options & CaseSensitive) {
// case-sensitive search
0,<'$%#$(,$#/+&+"#'$.!%.$.!'$0,)'$%=,-'$0%($='$+'5+"..'($/#"(@$%$+'3'+'(0'$0%#.O I&&4"0%.",($N/(0.",(%4".6W:

• reinterpret_cast<T>()$0,(-'+.#$%(6$&,"(.'+$,+$+'3'+'(0'$.6&'$.,$%(6$,.!'+$#/0!$.6&': N,+
short j = 0x1234; '*%<&4'O
if ((char &)j == 0x12) •
cout << "The byte order is big-endian" << endl;
• short j = 0x1234;
• if (reinterpret_cast<char &>(j) == 0x12)
• cout << "The byte order is big-endian" << endl;
;3$.!'$)%.%$.6&'$"#$%$04%##$(%<'B$%$.6&')'3B$,+$%$&+"<"."-'$.6&'$.!%.$0%($='$'*&+'##')$%#$%$#"(@4'
%4&!%(/<'+"0$.,7'(B$5'$0%($/#'$.!'$0,(#.+/0.,+$#6(.%*$%#$%$0%#.O
;($8%-%$%()$19B$%(6$+'3'+'(0'$0%($='$#.,+')$%#$%( Object$+'3'+'(0'$"3$('')'):$122$),'#(U.$!%-'
%(6$/("-'+#%4$=%#'$04%##B$=/.$".$&+,-")'#$%$#&'0"%4$)%.%$.6&'B void *B$.!%.$#.,+'#$.!'$%))+'##$,3$%(
int x = int(Pi * 100); "(#.%(0'$,3$%(6$.6&':$I void *$</#.$='$0%#.$=%07$.,$%(,.!'+$.6&'$V/#"(@ static_cast<T>()W$='3,+'$".
0%($='$/#'):

122$&+,-")'#$<%(6$5%6#$,3$0%#."(@$.6&'#B$=/.$<,#.$,3$.!'$."<'$5'$),(U.$'-'($('')$%$0%#.:$Y!'(
1%#."(@$&,"(.'+#$%()$+'3'+'(0'#$/#"(@$.!'$.+%)".",(%4$1?#.64'$0%#.#$"#$%$7"()$,3$'*.+'<'$#&,+.B$,($&%+
/#"(@$0,(.%"('+$04%##'#$#/0! %# std::vector<T>$,+ QVector<T>B$5'$0%($#&'0"36$.!' T$.6&'$%()$'*.+%0.
5".! &%+%@4")"(@$%()$'4'-%.,+$#/+3"(@B$='0%/#'$.!'$0,<&"4'+$4'.#$/#$0%#.$%(6$&,"(.'+$V,+$+'3'+'(0'W
".'<#$5".!,/.$0%#.#:$;($%))".",(B$3,+$&+"<"."-'$.6&'#B$0'+.%"($0,(-'+#",(#$,00/+$"<&4"0".46$V3,+
.6&'$"(.,$%(6$,.!'+$&,"(.'+$V,+$+'3'+'(0'W$.6&':$N,+$.!%.$+'%#,(B$122$"(.+,)/0')$3,/+$('5?#.64'
'*%<&4'B$3+,< char$., intWB$%()$3,+$0/#.,<$.6&'#$5'$0%($)'3"('$"<&4"0".$0,(-'+#",(#$=6$&+,-")"(@$%
0%#.#$5".!$<,+'$&+'0"#'$#'<%(."0#:$N,+$&,"(.'+#$%()$+'3'+'(0'#B$.!'$('5?#.64'$0%#.#$%+'$&+'3'+%=4'
,('?&%+%<'.'+$0,(#.+/0.,+:$N,+$'*%<&4'O
.,$.!'$+"#76$1?#.64'$0%#.#$%()$%+'$/#')$"($.!"#$=,,7:

• static_cast<T>()$0%($='$/#')$.,$0%#.$%$&,"(.'+?.,? A$.,$%$&,"(.'+?.,? BB$5".!$.!'$0,(#.+%"(.


class MyInteger
.!%.$04%## B$</#.$"(!'+".$3+,<$04%## A:$N,+$'*%<&4'O {
• public:
• A *obj = new B; MyInteger();
• B *b = static_cast<B *>(obj); MyInteger(int i);
• b->someFunctionDeclaredInB(); ...
};
int main()
;3$.!'$,=>'0.$"#(U.$%($"(#.%(0'$,3 B$V=/.$#."44$"(!'+".#$3+,< AWB$/#"(@$.!'$+'#/4."(@$&,"(.'+$0%( {
4'%)$.,$,=#0/+'$0+%#!'#: MyInteger n;
n = 5;
• dynamic_cast<T>()$"#$#"<"4%+$., static_cast<T>()B$'*0'&.$.!%.$".$/#'#$+/(."<' .6&'$"(3,+<%.",( ...
Vi ;W$.,$0!'07$.!%.$.!'$,=>'0.$%##,0"%.')$5".!$.!'$&,"(.'+$"#$%($"(#.%(0'$,3$04%## B:$;3$.!"#$"# }
(,.$.!'$0%#'B$.!'$0%#.$+'./+(#$%$(/44$&,"(.'+: N,+$'*%<&4'O

• A *obj = new B; N,+$#,<'$,('?&%+%<'.'+$0,(#.+/0.,+#B$.!'$%/.,<%."0$0,(-'+#",($<%7'#$4"..4'$#'(#':$Y'$0%($)"#%=4'
• B *b = dynamic_cast<B *>(obj); ".$=6$)'04%+"(@$.!'$0,(#.+/0.,+$5".!$.!' explicit$7'65,+)O
• if (b)
• b->someFunctionDeclaredInB();
class MyVector
{
Z($#,<'$0,<&"4'+#B dynamic_cast<T>()$),'#(U.$5,+7$%0+,##$)6(%<"0$4"=+%+6$=,/()%+"'#:$;.
public:
%4#,$+'4"'#$,($.!'$0,<&"4'+$#/&&,+."(@$i ;B$%$3'%./+'$.!%.$&+,@+%<<'+#$0%($./+($,33$., explicit MyVector(int size);
+')/0'$.!'$#"Q'$,3$.!'"+$'*'0/.%=4'#:$H.$#,4-'#$.!'#'$&+,=4'<#$=6$&+,-")"(@ ...
qobject_cast<T>()$3,+ QObject$#/=04%##'#: };

• const_cast<T>()$%))#$,+$+'<,-'#$% const$E/%4"3"'+$.,$%$&,"(.'+$,+$+'3'+'(0': N,+$'*%<&4'O



• int MyClass::someConstFunction() const
Operator Overloading
• {
• if (isDirty()) {
122$%44,5#$/#$.,$,-'+4,%)$3/(0.",(#B$<'%("(@$.!%.$5'$0%($)'04%+'$#'-'+%4$3/(0.",(# 5".!$.!'$#%<'
• MyClass *that = const_cast<MyClass *>(this);
(%<'$"($.!'$#%<'$#0,&'B$%#$4,(@$%#$.!'6$!%-'$)"33'+'(.$&%+%<'.'+$4"#.#:$;($%))".",(B$122$#/&&,+.#
• that->recomputeInternalData();
-6":)0-:#-,":.-)*&('.!'$&,##"="4".6$,3$%##"@("(@$#&'0"%4$#'<%(."0#$.,$=/"4.?"($,&'+%.,+#$V#/0!$%# +B
• }
<<B$%() []W$5!'($.!'6$%+'$/#')$5".!$0/#.,< .6&'#:
• ...
• }
Y'$!%-'$%4+'%)6$#''($%$3'5$'*%<&4'#$,3$,-'+4,%)')$,&'+%.,+#:$Y!'($5'$/#') <<$.,$,/.&/.$.'*.$.,
cout$,+ cerrB$5'$)")(U.$.+"@@'+$122U#$4'3.?#!"3.$,&'+%.,+B$=/.$+%.!'+$%$#&'0"%4$-'+#",($,3$.!'$,&'+%.,+
;($.!'$&+'-",/#$'*%<&4'B$5'$0%#.$%5%6$.!' const$E/%4"3"'+$,3$.!' this$&,"(.'+$.,$0%44$.!'$(,(? .!%.$.%7'#$%( ostream$,=>'0.$V#/0!$%# cout$%() cerrW$,($.!'$4'3.$%()$%$#.+"(@$V%4.'+(%."-'46B$%
0,(#.$<'<='+$3/(0.",( recomputeInternalData():$a,"(@$#,$"#$(,.$+'0,<<'()')$%()$0%( (/<='+$,+$%$#.+'%<$<%("&/4%.,+$#/0!$%# endlW$,($.!'$+"@!.$#")'$%()$.!%.$+'./+(#$.!' ostream$,=>'0.B
(,+<%446$='$%-,")')$=6$/#"(@$.!' mutable$7'65,+)B$%#$'*&4%"(')$"( 1!%&.'+$^$V;<&4'<'(."(@
%44,5"(@$</4."&4'$0%44#$"($%$+,5:
Point2D alpha(12.5, 40.0);
Point2D beta(77.5, 50.0);
!'$='%/.6$,3$,&'+%.,+$,-'+4,%)"(@$"#$.!%.$5'$0%($<%7'$0/#.,<$.6&'#$='!%-'$>/#.$4"7'$=/"4.?"(
alpha += beta;
.6&'#:$ ,$#!,5$!,5$,&'+%.,+$,-'+4,%)"(@$5,+7#B$5'$5"44$,-'+4,%) +=B -=B +B$%() -$.,$5,+7$,( Point2D
beta -= alpha;
,=>'0.#O Point2D gamma = alpha + beta;
Point2D delta = beta - alpha;

#ifndef POINT2D_H
#define POINT2D_H
class Point2D Y'$0%($%4#,$"(-,7'$.!' operator$3/(0.",(#$>/#.$4"7'$%(6$,.!'+$3/(0.",(#O
{
public:
Point2D(); Point2D alpha(12.5, 40.0);
Point2D(double x, double y); Point2D beta(77.5, 50.0);
void setX(double x); alpha.operator+=(beta);
void setY(double y); beta.operator-=(alpha);
double x() const; Point2D gamma = operator+(alpha, beta);
double y() const; Point2D delta = operator-(beta, alpha);
Point2D &operator+=(const Point2D &other) {
xVal += other.xVal;
yVal += other.yVal;
return *this; Z&'+%.,+$,-'+4,%)"(@$"($122$"#$%$0,<&4'*$.,&"0B$=/.$5'$0%($@,$%$4,(@$5%6 5".!,/.$7(,5"(@$%44$.!'
} )'.%"4#:$;.$"#$#."44$"<&,+.%(.$.,$/()'+#.%()$.!'$3/()%<'(.%4#$,3$,&'+%.,+$,-'+4,%)"(@$='0%/#'$#'-'+%4
Point2D &operator-=(const Point2D &other) { H.$04%##'#$V"(04/)"(@ QString$%() QVector<T>W$/#'$.!"#$3'%./+'$.,$&+,-")'$%$#"<&4'$%()$<,+'$(%./+%4
xVal -= other.xVal; #6(.%*$3,+$#/0!$,&'+%.",(#$%# 0,(0%.'(%.",($%()$%&&'():
yVal -= other.yVal;
return *this; Value Types
}
private:
double xVal; 8%-%$%()$19$)"#."(@/"#!$='.5''($-%4/'$.6&'#$%()$+'3'+'(0'$.6&'#:
double yVal;
}; • C)./"#0;6"%B$ !'#'$%+'$&+"<"."-'$.6&'#$#/0!$%# charB intB$%() floatB$%#$5'44$%#$19$#.+/0.#:
inline Point2D operator+(const Point2D &a, const Point2D &b) Y!%.$0!%+%0.'+"Q'#$.!'<$"#$.!%.$.!'6$%+'(U.$0+'%.')$/#"(@ new$%()$.!'$%##"@(<'(.$,&'+%.,+
{ &'+3,+<#$%$0,&6$,3$.!'$-%4/'$!'4)$=6$.!'$-%+"%=4': N,+$'*%<&4'O
return Point2D(a.x() + b.x(), a.y() + b.y()); •
}
inline Point2D operator-(const Point2D &a, const Point2D &b) • int i = 5;
{ • int j = 10;
return Point2D(a.x() - b.x(), a.y() - b.y()); • i = j;
} • D"1":"(4"#0;6"%B$ !'#'$%+'$04%##'#$#/0!$%# Integer$V"($8%-%WB StringB$%() MyVeryOwnClass:
#endif ;(#.%(0'#$%+'$0+'%.')$/#"(@ new:$ !'$%##"@(<'(.$,&'+%.,+$0,&"'#$,(46$%$+'3'+'(0'$.,$.!'
,=>'0.J$.,$,=.%"($%$)''&$0,&6B$5'$</#.$0%44 clone()$V"($8%-%W$,+ Clone()$V"($19W: N,+
'*%<&4'O
Z&'+%.,+#$0%($='$"<&4'<'(.')$'".!'+$%#$<'<='+$3/(0.",(#$,+$%#$@4,=%4$3/(0.",(#:$;($,/+$'*%<&4'B •
5'$"<&4'<'(.') +=$%() -=$%#$<'<='+$3/(0.",(#B +$%() -$%#$@4,=%4$3/(0.",(#: • Integer i = new Integer(5);
• Integer j = new Integer(10);
!' +=$%() -=$,&'+%.,+#$.%7'$%$+'3'+'(0'$.,$%(,.!'+ Point2D$,=>'0.$%()$"(0+'<'(.$,+$)'0+'<'(.$.!' • i = j.clone();
@$%() ;$0,,+)"(%.'#$,3$.!'$0/++'(.$,=>'0.$=%#')$,($.!'$,.!'+$,=>'0.:$ !'6$+'./+( *thisB$5!"0!
)'(,.'#$%$+'3'+'(0'$.,$.!'$0/++'(.$,=>'0.$Vthis$"#$,3$.6&' Point2D *W:$i'./+("(@$%$+'3'+'(0'$%44,5# ;($122B$%44$.6&'#$0%($='$/#')$%#$M+'3'+'(0'$.6&'#MB$%()$.!,#'$.!%.$%+'$0,&6%=4'$0%($='$/#')$%#
/#$.,$5+".'$'*,."0$0,)'$4"7'E M-%4/'$.6&'#M$%#$5'44:$N,+$'*%<&4'B$122$),'#(U.$('')$%(6 Integer$04%##B$='0%/#'$5'$0%($/#'
&,"(.'+#$%() new$%#$3,44,5#O

a += b += c;
int *i = new int(5);
int *j = new int(10);
!' +$%() -$,&'+%.,+#$.%7'$.5,$&%+%<'.'+#$%()$+'./+($% Point2D$,=>'0.$=6$-%4/'$V(,.$%$+'3'+'(0'$., *i = *j;
%($'*"#."(@$,=>'0.W:$ !' inline$7'65,+)$%44,5#$/#$.,$&/.$.!'#'$3/(0.",($)'3"(".",(#$"($.!'$!'%)'+$3"4':
;3$.!'$3/(0.",(U#$=,)6$!%)$=''($4,(@'+B$5'$5,/4)$&/.$%$3/(0.",($&+,.,.6&'$"($.!'$!'%)'+$3"4'$%()$.!'
3/(0.",($)'3"(".",($V5".!,/.$.!' inline$7'65,+)W$"($% .cpp$3"4': G(4"7'$8%-%$%()$19B$122$.+'%.#$/#'+?)'3"(')$04%##'#$.!'$#%<'$%#$=/"4."($.6&'#O

!'$3,44,5"(@$0,)'$#("&&'.#$#!,5#$%44$3,/+$,-'+4,%)')$,&'+%.,+#$"($%0.",(O
Point2D *i = new Point2D(5, 5);
Point2D *j = new Point2D(10, 10);
*i = *j;
;($H.B$<%(6$04%##'#$%+'$)'#"@(')$.,$='$/#')$%#$-%4/'$04%##'#:$ !'#'$!%-'$%$0,&6$0,(#.+/0.,+$%()$%(
%##"@(<'(.$,&'+%.,+B$%()$%+'$(,+<%446$"(#.%(."%.')$,($.!'$#.%07$5".!,/. new:$ !"#$"#$.!'$0%#'$3,+
;3$5'$5%(.$.,$<%7'$%$122$04%##$0,&6%=4'B$5'$</#.$'(#/+'$.!%.$,/+$04%##$!%#$%$0,&6$0,(#.+/0.,+$%() QDateTimeB QImageB QStringB$%()$0,(.%"('+$04%##'#$#/0!$%# QList<T>B QVector<T>B$%() QMap<K, T>:
%($%##"@(<'(.$,&'+%.,+:$ !'$0,&6$0,(#.+/0.,+$"#$"(-,7')$5!'($5'$"("."%4"Q'$%($,=>'0.$5".!$%(,.!'+
,=>'0.$,3$.!'$#%<'$.6&':$122$&+,-")'#$.5,$'E/"-%4'(.$#6(.%*'#$3,+$.!"#O Z.!'+$04%##'#$3%44$"($.!'$M+'3'+'(0'$.6&'M$0%.'@,+6B$(,.%=46 QObject$%()$".#$#/=04%##'#$VQWidgetB
QTimerB QTcpSocketB$'.0:W:$ !'#'$!%-'$-"+./%4$3/(0.",(#$%()$0%((,.$='$0,&"'):$N,+$'*%<&4'B$% QWidget
+'&+'#'(.#$%$#&'0"3"0$5"(),5$,+$0,(.+,4$,($#0+''(:$;3$.!'+'$%+'$bC QWidget$"(#.%(0'#$"($<'<,+6B
Point2D i(20, 20); .!'+'$%+'$%4#,$bC$5"(),5#$,+$0,(.+,4#$,($#0+''(:$ !'#'$04%##'#$%+'$.6&"0%446$"(#.%(."%.')$/#"(@$.!'
Point2D j(i); // first syntax
new$,&'+%.,+:
Point2D k = i; // second syntax

Global Variables and Functions


!'$%##"@(<'(.$,&'+%.,+$"#$"(-,7')$5!'($5'$/#'$.!'$%##"@(<'(.$,&'+%.,+$,($%($'*"#."(@$-%+"%=4'O
122$4'.#$/#$)'04%+' 3/(0.",(#$%()$-%+"%=4'#$.!%.$),(U.$='4,(@$.,$%(6$04%##'#$%()$.!%.$%+'$%00'##"=4'
3+,<$%(6$,.!'+$3/(0.",(:$Y'$!%-'$#''($#'-'+%4$'*%<&4'#$,3$@4,=%4$3/(0.",(#B$"(04/)"(@ main()B$.!'
Point2D i(5, 5); &+,@+%<U#$'(.+6$&,"(.:$F4,=%4$-%+"%=4'#$%+'$+%+'+B$='0%/#'$.!'6$0,<&+,<"#'$<,)/4%+".6$%()$.!+'%)
Point2D j(10, 10); +''(.+%(06:$;.$"#$#."44$"<&,+.%(.$.,$/()'+#.%()$.!'<$='0%/#'$6,/$<"@!.$'(0,/(.'+$.!'<$"($0,)'
j = i; 5+"..'($=6$+'3,+<')$1$&+,@+%<<'+#$%()$,.!'+$122$/#'+#:

,$"44/#.+%.'$!,5$@4,=%4$3/(0.",(#$%()$-%+"%=4'#$5,+7B$5'$5"44$#./)6$%$#<%44$&+,@+%<$.!%.$&+"(.#$%$4"#.
Y!'($5'$)'3"('$%$04%##B$.!'$122$0,<&"4'+$%/.,<%."0%446$&+,-")'#$%$0,&6$0,(#.+/0.,+$%()$%( ,3$A]d$&#'/),?+%(),<$(/<='+#$/#"(@$%$E/"07?%()?)"+.6$%4@,+".!<:$ !'$&+,@+%<U#$#,/+0'$0,)'$"#
%##"@(<'(.$,&'+%.,+$.!%.$&'+3,+<$<'<='+?=6?<'<='+$0,&6:$N,+$.!' Point2D$04%##B$.!"#$"#$%#$"3$5' #&+'%)$,-'+$.5, .cpp$3"4'#:
!%)$5+"..'($.!'$3,44,5"(@$0,)'$"($.!'$04%##$)'3"(".",(O
!'$3"+#.$#,/+0'$3"4'$"# random.cppO

class Point2D
{ int randomNumbers[128];
public: static int seed = 42;
... static int nextRandomNumber()
Point2D(const Point2D &other) {
: xVal(other.xVal), yVal(other.yVal) { } seed = 1009 + (seed * 2011);
Point2D &operator=(const Point2D &other) { return seed;
xVal = other.xVal; }
yVal = other.yVal; void populateRandomArray()
return *this; {
} for (int i = 0; i < 128; ++i)
... randomNumbers[i] = nextRandomNumber();
private: }
double xVal;
double yVal;
};
!'$3"4'$)'04%+'#$.5,$@4,=%4$-%+"%=4'#$VrandomNumbers$%() seedW$%()$.5,$@4,=%4$3/(0.",(#
VnextrandomNumber()$%() populateRandomArray()W:$ 5,$,3$.!'$)'04%+%.",(#$0,(.%"($.!' static
7'65,+)J$.!'#'$%+'$-"#"=4'$,(46$5".!"($.!'$0/++'(.$0,<&"4%.",($/(".$V random.cppW$%()$%+'$#%")$.,$!%-'
N,+$#,<'$04%##'#B$.!'$)'3%/4.$0,&6$0,(#.+/0.,+$%()$%##"@(<'(.$,&'+%.,+$%+'$/(#/".%=4':$ !"#
%0)0&4#.&(9)'":$ !'$.5,$,.!'+#$0%($='$%00'##')$3+,<$%(6$0,<&"4%.",($/(".$"($.!'$&+,@+%<J$.!'#'
.6&"0%446$,00/+#$"3$.!'$04%##$/#'#$)6(%<"0$<'<,+6:$ ,$<%7'$.!'$04%##$0,&6%=4'B$5'$</#.$.!'(
!%-' "@0":().#.&(9)'":
"<&4'<'(.$.!'$0,&6$0,(#.+/0.,+$%()$.!'$%##"@(<'(.$,&'+%.,+$,/+#'4-'#:
L.%."0$4"(7%@'$"#$")'%4$3,+$!'4&'+$3/(0.",(#$%()$"(.'+(%4$-%+"%=4'#$.!%.$#!,/4)$(,.$='$/#')$"($,.!'+
N,+$04%##'#$.!%.$),(U.$('')$.,$='$0,&6%=4'B$5'$0%($)"#%=4'$.!'$0,&6$0,(#.+/0.,+$%()$%##"@(<'(.
0,<&"4%.",($/(".#:$;.$+')/0'#$.!'$+"#7#$,3$!%-"(@$0,44")"(@$")'(."3"'+#$V@4,=%4$-%+"%=4'#$5".!$.!'$#%<'
,&'+%.,+$=6$<%7"(@$.!'<$&+"-%.':$;3$5'$%00")'(.%446$%..'<&.$.,$0,&6$"(#.%(0'#$,3$#/0!$%$04%##B$.!'
(%<'$,+$@4,=%4$3/(0.",(#$5".!$.!'$#%<'$#"@(%./+'$"($)"33'+'(.$0,<&"4%.",($/(".#W$%()$&+'-'(.#
0,<&"4'+$+'&,+.#$%($'++,+:$N,+$'*%<&4'O
<%4"0",/#$,+$,.!'+5"#'$"44?%)-"#')$/#'+#$3+,<$%00'##"(@$.!'$"(.'+(%4#$,3$%$0,<&"4%.",($/(".:

class BankAccount T'.U#$(,5$4,,7$%.$.!'$#'0,()$3"4'B main.cppB$5!"0!$/#'#$.!'$.5,$@4,=%4$-%+"%=4'#$)'04%+')$5".!


{ '*.'+(%4$4"(7%@'$"( random.cppO
public:
...
private: #include <iostream>
BankAccount(const BankAccount &other); using namespace std;
BankAccount &operator=(const BankAccount &other); extern int randomNumbers[128];
}; void populateRandomArray();
int main()
{ #define SOFTWAREINC_RANDOM_H
populateRandomArray(); namespace SoftwareInc
for (int i = 0; i < 128; ++i) {
cout << randomNumbers[i] << endl; extern int randomNumbers[128];
return 0; void populateRandomArray();
} }
#endif

Y'$)'04%+'$.!'$'*.'+(%4$-%+"%=4'#$%()$3/(0.",(#$='3,+'$5'$0%44$.!'<:$ !'$'*.'+(%4$-%+"%=4'
)'04%+%.",($V5!"0!$<%7'#$%($'*.'+(%4$-%+"%=4'$-"#"=4'$"($.!'$0/++'(.$0,<&"4%.",($/(".W$3,+ Vk,."0'$.!%.$5'$!%-'$%4#,$+'(%<')$.!'$&+'&+,0'##,+$<%0+,$/#')$.,$%-,")$</4."&4'$"(04/#",(#B
randomNumbers$#.%+.#$5".!$.!' extern$7'65,+):$Y".!,/. externB$.!'$0,<&"4'+$5,/4)$.!"(7$".$!%#$., +')/0"(@$.!'$+"#7$,3$%$(%<'$04%#!$5".!$%$!'%)'+$3"4'$,3$.!'$#%<'$(%<'$=/.$4,0%.')$"($%$)"33'+'(.
)'%4$5".!$%$-%+"%=4' *"1&(&0&-(B$%()$.!'$4"(7'+$5,/4)$0,<&4%"($='0%/#'$.!'$#%<'$-%+"%=4'$"#$)'3"(') )"+'0.,+6:W
"($.5,$0,<&"4%.",($/(".#$Vrandom.cpp$%() main.cppW:$j%+"%=4'#$0%($='$)'04%+')$%#$<%(6$."<'#$%#$5'
5%(.B$=/.$.!'6$<%6$,(46$='$)'3"(')$,(0':$ !'$)'3"(".",($"#$5!%.$0%/#'#$.!'$0,<&"4'+$.,$+'#'+-' !'$(%<'#&%0'$#6(.%*$"#$#"<"4%+$.,$.!%.$,3$%$04%##B$=/.$".$),'#(U.$'()$5".!$%$#'<"0,4,(:$['+'U#$.!'
#&%0'$3,+$.!'$-%+"%=4': ('5 random.cpp$3"4'O

!' populateRandomArray()$3/(0.",($"#$)'04%+')$/#"(@$%$3/(0.",($&+,.,.6&':$ !' extern$7'65,+)$"#


,&.",(%4$3,+$3/(0.",(#: #include "random.h"
int SoftwareInc::randomNumbers[128];
static int seed = 42;
6&"0%446$5'$5,/4)$&/.$.!'$'*.'+(%4$-%+"%=4'$%()$3/(0.",($)'04%+%.",(#$"($%$!'%)'+$3"4'$%()$"(04/)'$".
static int nextRandomNumber()
"($%44$.!'$3"4'#$.!%.$('')$.!'<O {
seed = 1009 + (seed * 2011);
return seed;
#ifndef RANDOM_H }
#define RANDOM_H void SoftwareInc::populateRandomArray()
extern int randomNumbers[128]; {
void populateRandomArray(); for (int i = 0; i < 128; ++i)
#endif randomNumbers[i] = nextRandomNumber();
}

Y'$!%-'$%4+'%)6$#''($!,5 static$0%($='$/#')$.,$)'04%+'$<'<='+$-%+"%=4'#$%()$3/(0.",(#$.!%.$%+'
(,.$%..%0!')$.,$%$#&'0"3"0$"(#.%(0'$,3$.!'$04%##B$%()$(,5$5'$!%-'$#''($!,5$.,$/#'$".$.,$)'04%+' G(4"7'$04%##'#B$(%<'#&%0'#$0%($='$M+',&'(')M$%.$%(6$."<':$N,+$'*%<&4'O
3/(0.",(#$%()$-%+"%=4'#$5".!$#.%."0$4"(7%@':$ !'+'$"#$,('$<,+'$/#'$,3$.!' static$7'65,+)$.!%.$#!,/4)
='$(,.')$"($&%##"(@:$;($122B$5'$0%($)'04%+'$%$4,0%4$-%+"%=4'$#.%."0:$L/0!$-%+"%=4'#$%+'$"("."%4"Q')$.!'
3"+#.$."<'$.!'$3/(0.",($"#$0%44')$%()$!,4)$.!'"+$-%4/'$='.5''($3/(0.",($"(-,0%.",(#:$N,+$'*%<&4'O namespace Alpha
{
void alpha1();
void nextPrime() void alpha2();
{ }
static int n = 1; namespace Beta
do { {
++n; void beta1();
} while (!isPrime(n)); }
return n; namespace Alpha
} {
void alpha3();
}
L.%."0$4,0%4$-%+"%=4'#$%+'$#"<"4%+$.,$@4,=%4$-%+"%=4'#B$'*0'&.$.!%.$.!'6$%+'$,(46$-"#"=4'$"(#")'$.!'
3/(0.",($5!'+'$.!'6$%+'$)'3"('):
!"#$<%7'#$".$&,##"=4'$.,$)'3"('$!/()+')#$,3$04%##'#B$4,0%.')$"($%#$<%(6$!'%)'+$3"4'#B$%#$&%+.$,3$%
#"(@4'$(%<'#&%0':$G#"(@$.!"#$.+"07B$.!'$L.%()%+)$122$4"=+%+6$&/.#$%44$".#$")'(."3"'+#$"($.!' std
Namespaces (%<'#&%0':$;($H.B$(%<'#&%0'#$%+'$/#')$3,+$@4,=%4?4"7'$")'(."3"'+#$#/0!$%# Qt::AlignBottom$%()
Qt::yellow:$N,+$!"#.,+"0%4$+'%#,(#B$H.$04%##'#$),$(,.$='4,(@$.,$%(6$(%<'#&%0'$=/.$%+'$&+'3"*')$5".!
k%<'#&%0'#$%+'$%$<'0!%("#<$3,+$+')/0"(@$.!'$+"#7#$,3$(%<'$04%#!'#$"($122$&+,@+%<#:$k%<' .!'$4'..'+$UHU:
04%#!'#$%+'$,3.'($%($"##/'$"($4%+@'$&+,@+%<#$.!%.$/#'$#'-'+%4$.!"+)?&%+.6$4"=+%+"'#:$;($6,/+$,5(
&+,@+%<#B$6,/$0%($0!,,#'$5!'.!'+$6,/$5%(.$.,$/#'$(%<'#&%0'#$,+$(,.:
,$+'3'+$.,$%($")'(."3"'+$)'04%+')$"($%$(%<'#&%0'$3+,<$,/.#")'$.!'$(%<'#&%0'B$5'$&+'3"*$".$5".!$.!'
(%<'$,3$.!'$(%<'#&%0'$V%() ::W:$I4.'+(%."-'46B$5'$0%($/#'$,('$,3$.!'$3,44,5"(@$.!+''$<'0!%("#<#B
6&"0%446B$5'$&/.$%$(%<'#&%0'$%+,/()$%44$.!'$)'04%+%.",(#$"($%$!'%)'+$3"4'$.,$'(#/+'$.!%.$.!' 5!"0!$%+'$%"<')$%.$+')/0"(@$.!'$(/<='+$,3$7'6#.+,7'#$5'$</#.$.6&':
")'(."3"'+#$)'04%+')$"($.!%.$!'%)'+$3"4'$),(U.$4'%7$"(.,$.!'$@4,=%4$(%<'#&%0':$N,+$'*%<&4'O
• 8+&.34&9+J#4+&3&430+613.+&32#36D

#ifndef SOFTWAREINC_RANDOM_H
• namespace ElPuebloDeLaReinaDeLosAngeles 0,<&"4%.",($/(".$5".!$.!'$.,7'( 3.14159265359:$ ,$%-,")$04%#!'#$5".!$-%+"%=4'$%()$04%##
• { (%<'#B$".$"# 0,<<,($&+%0."0'$.,$@"-'$<%0+,#$%44/&&'+0%#'$(%<'#:$;.$"#$&,##"=4'$.,$)'3"('
• void beverlyHills(); <%0+,#$.!%.$.%7'$%+@/<'(.#O
• void culverCity();
• void malibu();
• void santaMonica(); #define SQUARE(x) ((x) * (x))
• }
• namespace LA = ElPuebloDeLaReinaDeLosAngeles; ;($.!'$<%0+,$=,)6B$".$"#$@,,)$#.64'$.,$#/++,/()$%44$,00/++'(0'#$,3$.!'$&%+%<'.'+#$5".!
&%+'(.!'#'#B$%#$5'44$%#$.!'$'(."+'$=,)6B$.,$%-,")$&+,=4'<#$5".!$,&'+%.,+$&+'0')'(0':$I3.'+
%44B$5'$5%(. 7 * SQUARE(2 + 3)$.,$'*&%()$., 7 * ((2 + 3) * (2 + 3))B$(,.$., 7 * 2 + 3 * 2 +
I3.'+$.!'$%4"%#$)'3"(".",(B$.!'$%4"%#$0%($='$/#')$"(#.'%)$,3$.!'$,+"@"(%4$(%<':E
3:

• 8+&.34&#01/5%&3&6#4=2+&#9+4%#J#+5&J5/0&3&430+613.+D
122$0,<&"4'+#$(,+<%446$%44,5$/#$.,$)'3"('$<%0+,#$,($.!'$0,<<%()$4"('B$/#"(@$.!' -D$,+ /D

,&.",(:$N,+$'*%<&4'O
• int main()
• {
• using ElPuebloDeLaReinaDeLosAngeles::beverlyHills; CC -DPI=3.14159265359 -c main.cpp
• beverlyHills();
• ... S%0+,#$5'+'$-'+6$&,&/4%+$"($.!'$,4)$)%6#B$='3,+'$.6&')'3#B$'(/<#B$0,(#.%(.#B$"(4"('
• } 3/(0.",(#B$%()$.'<&4%.'#$5'+'$"(.+,)/0'):$k,5%)%6#B$.!'"+$<,#.$"<&,+.%(.$+,4'$"#$.,$&+,.'0.
!'%)'+$3"4'#$%@%"(#.$</4."&4'$"(04/#",(#:
!' using$)'04%+%.",($%44,5#$/#$.,$%00'##$%$@"-'($")'(."3"'+$3+,<$%$(%<'?#&%0'$5".!,/.
!%-"(@$.,$&+'3"*$".$5".!$.!'$(%<'$,3$.!'$(%<'#&%0': • S%0+,#$0%($='$/()'3"(')$%.$%(6$&,"(.$/#"(@ #undefO

• 8+&.34&#01/5%&34&+4%#5+&430+613.+&:#%"&3&6#4=2+&9#5+.%#A+D • #undef PI

• int main() !"#$"#$/#'3/4$"3$5'$5%(.$.,$+')'3"('$%$<%0+,B$#"(0'$.!'$&+'&+,0'##,+$),'#(U.$4'.$/#$)'3"('$.!'
• { #%<'$<%0+,$.5"0': ;.$"#$%4#,$/#'3/4$.,$0,(.+,4$0,()".",(%4$0,<&"4%.",(:
• using namespace ElPuebloDeLaReinaDeLosAngeles;
• santaMonica(); • _,+.",(#$,3$0,)'$0%($='$&+,0'##')$,+$#7"&&')$/#"(@ #ifB #elifB #elseB$%() #endifB$=%#')$,(
• malibu(); .!'$(/<'+"0$-%4/'$,3$<%0+,#: N,+$'*%<&4'O
• ... •
• } • #define NO_OPTIM 0
• #define OPTIM_FOR_SPEED 1
Y".!$.!"#$%&&+,%0!B$(%<' 04%#!'#$%+'$<,+'$4"7'46$.,$,00/+:$;3$.!'$0,<&"4'+$0,<&4%"(#$%=,/.$%( • #define OPTIM_FOR_MEMORY 2
%<="@/,/#$(%<'$V3,+$'*%<&4'B$.5,$04%##'#$5".!$.!'$#%<'$(%<'$)'3"(')$"($.5,$)"33'+'(. • #define OPTIMIZATION OPTIM_FOR_MEMORY
(%<'#&%0'#WB$5'$0%($%45%6#$E/%4"36$.!'$")'(."3"'+$5".!$.!'$(%<'$,3$.!'$(%<'#&%0'$5!'($+'3'++"(@ • ...
.,$".: • #if OPTIMIZATION == OPTIM_FOR_SPEED
• typedef int MyInt;
The Preprocessor • #elif OPTIMIZATION == OPTIM_FOR_MEMORY
• typedef short MyInt;
!'$122$&+'&+,0'##,+$"#$%$&+,@+%<$.!%.$0,(-'+.#$% .cpp$#,/+0'$3"4'$0,(.%"("(@ #?)"+'0."-'#$V#/0!$%# • #else
#includeB #ifndefB$%() #endifW$"(.,$%$#,/+0'$3"4'$.!%.$0,(.%"(#$(,$#/0!$)"+'0."-'#:$ !'#'$)"+'0."-'# • typedef long long MyInt;
&'+3,+<$#"<&4'$.'*./%4$,&'+%.",(#$,( .!'$#,/+0'$3"4'B$#/0!$%#$0,()".",(%4$0,<&"4%.",(B$3"4'$"(04/#",(B • #endif
%()$<%0+,$'*&%(#",(:$k,+<%446B$.!'$&+'&+,0'##,+$"#$"(-,7')$%/.,<%."0%446$=6$.!'$0,<&"4'+B$=/.
<,#.$#6#.'<#$#."44$,33'+$%$5%6$,3$"(-,7"(@$".$%4,('$V,3.'($.!+,/@!$% -E$,+ /E$0,<&"4'+$,&.",(W: ;($.!'$'*%<&4'$%=,-'B$,(46$.!'$#'0,() typedef$)'04%+%.",($5,/4)$='$&+,0'##')$=6$.!'
0,<&"4'+B$+'#/4."(@$"( MyInt$='"(@$)'3"(')$%#$%$#6(,(6<$3,+ short:$K6$0!%(@"(@$.!'$)'3"(".",(
• !' #include$)"+'0."-'$'*&%()#$.,$.!'$0,(.'(.#$,3$.!'$3"4'$#&'0"3"')$5".!"($%(@4'$=+%07'.#$V <>W ,3$.!' OPTIMIZATION$<%0+,B$5'$@'.$)"33'+'(.$&+,@+%<#:$;3$%$<%0+,$"#(U.$)'3"(')B$".#$-%4/'$"#
,+$),/=4'$E/,.'#$V""WB$)'&'()"(@$,($5!'.!'+$.!'$!'%)'+$3"4'$"#$"(#.%44')$%.$%$#.%()%+) .%7'($.,$='$D:
4,0%.",($,+$"#$&%+.$,3$.!'$0/++'(.$&+,>'0.:$ !'$3"4'$(%<'$<%6$0,(.%"( .. %() /$V5!"0!$Y"(),5#
0,<&"4'+#$0,++'0.46$"(.'+&+'.$%#$%$)"+'0.,+6$#'&%+%.,+W: N,+$'*%<&4'O I(,.!'+$%&&+,%0!$.,$0,()".",(%4$0,<&"4%.",($"#$.,$.'#.$5!'.!'+$%$<%0+,$"#$)'3"(')$,+$(,.:$ !"#
• 0%($='$),('$/#"(@$.!'$/#"(@$.!' defined()$,&'+%.,+$%#$3,44,5#O
• #include "../shared/globaldefs.h"
• !' #define$)"+'0."-'$)'3"('#$%$<%0+,:$Z00/++'(0'#$,3$.!'$<%0+,$%&&'%+"(@$%3.'+$.!' #define
)"+'0."-'$%+'$+'&4%0')$5".!$.!'$<%0+,U#$)'3"(".",(: N,+$'*%<&4'B$.!'$)"+'0."-' #define OPTIM_FOR_MEMORY
• ...
• #define PI 3.14159265359 #if defined(OPTIM_FOR_SPEED)
typedef int MyInt;
#elif defined(OPTIM_FOR_MEMORY)
.'44#$.!'$&+'&+,0'##,+$.,$+'&4%0'$%44$3/./+'$,00/++'(0'#$,3$.!'$.,7'( PI$"($.!'$0/++'(.
typedef short MyInt;
#else
typedef long long MyInt;
#endif
The Standard C++ Library
• N,+$0,(-'("'(0'B$.!'$&+'&+,0'##,+$+'0,@("Q'# #ifdef X$%() #ifndef X$%#$#6(,(6<#$3,+ #if
defined(X)$%() #if !defined(X):$ ,$&+,.'0.$%$!'%)'+$3"4'$%@%"(#.$</4."&4'$"(04/#",(#B$5'$5+%& ;($.!"#$#'0.",(B$5'$5"44$=+"'346$+'-"'5$.!'$L.%()%+)$122$4"=+%+6: N"@/+'$K:P$4"#.#$.!'$0,+'$122$!'%)'+
".#$0,(.'(.#$5".!$.!'$3,44,5"(@$")",<O 3"4'#:$ !' <exception>B <limits>B <new>B$%() <typeinfo>$!'%)'+#$#/&&,+. .!'$122$4%(@/%@'J$3,+
• '*%<&4'B <limits>$%44,5#$/#$.,$.'#.$&+,&'+."'#$,3$.!'$0,<&"4'+U#$"(.'@'+$%()$34,%."(@?&,"(.$%+".!<'."0
• #ifndef MYHEADERFILE_H #/&&,+.B$%() <typeinfo>$,33'+#$=%#"0$"(.+,#&'0.",(:$ !'$,.!'+$!'%)'+#$&+,-")'$@'('+%446$/#'3/4
• #define MYHEADERFILE_H 04%##'#B$"(04/)"(@$%$#.+"(@$04%##$%()$%$0,<&4'*$(/<'+"0$.6&':$ !'$3/(0.",(%4".6$,33'+')$=6 <bitset>B
• ... <locale>B <string>B$%() <typeinfo>$4,,#'46$,-'+4%&#$5".!$.!' QBitArrayB QLocaleB QStringB$%()
• #endif QMetaObject$04%##'#$"($H.:

!'$3"+#.$."<'$.!'$!'%)'+$3"4'$"#$"(04/)')B$.!'$#6<=,4 MYHEADERFILE_H$"#$(,.$)'3"(')B$#,$.!' <#=>5+&'(K(&,/5+&,--&2#$535B&"+39+5&J#2+6


0,<&"4'+$&+,0'##'#$.!'$0,)'$='.5''( #ifndef$%() #endif:$ !'$#'0,()$%()$%(6$#/=#'E/'(.
."<'#$.!'$!'%)'+$3"4'$"#$"(04/)')B MYHEADERFILE_H$"#$)'3"(')B$#,$.!'$'(."+' #ifndef$\ #endif
=4,07$"#$#7"&&'): L+39+5&J#2+ C+6.5#1%#/4
<bitset> '<&4%.'$04%##$3,+$+'&+'#'(."(@$3"*')?4'(@.!$=".$#'E/'(0'#
• !' #error$)"+'0."-'$'<".#$%$/#'+?)'3"(')$'++,+$<'##%@'$%.$0,<&"4'$."<':$ !"#$"#$,3.'($/#')$"(
0,(>/(0.",($5".!$0,()".",(%4$0,<&"4%.",($.,$+'&,+.$%($"<&,##"=4'$0%#': N,+$'*%<&4'O <complex> '<&4%.'$04%##$3,+$+'&+'#'(."(@$0,<&4'*$(/<='+#

• class UniChar <exception> 6&'#$%()$3/(0.",(#$+'4%.')$.,$'*0'&.",($!%()4"(@
• {
<limits> '<&4%.'$04%##$.!%.$#&'0"3"'#$&+,&'+."'#$,3$(/<'+"0$.6&'#
• public:
• #if BYTE_ORDER == BIG_ENDIAN <locale> 14%##'#$%()$3/(0.",(#$+'4%.')$.,$4,0%4"Q%.",(
• uchar row;
• uchar cell; <new> N/(0.",(#$.!%.$<%(%@'$)6(%<"0$<'<,+6$%44,0%.",(
• #elif BYTE_ORDER == LITTLE_ENDIAN
<stdexcept> _+')'3"(')$.6&'#$,3$'*0'&.",(#$3,+$+'&,+."(@$'++,+#
• uchar cell;
• uchar row; <string> '<&4%.'$#.+"(@$0,(.%"('+$%()$0!%+%0.'+$.+%".#
• #else
• #error "BYTE_ORDER must be BIG_ENDIAN or LITTLE_ENDIAN" <typeinfo> 14%##$.!%.$&+,-")'#$=%#"0$<'.%?"(3,+<%.",($%=,/.$%$.6&'
• #endif
<valarray> '<&4%.'$04%##'#$3,+$+'&+'#'(."(@$-%4/'$%++%6#
• };

G(4"7'$<,#.$,.!'+$122$0,(#.+/0.#B5!'+'$5!".'#&%0'$"#$"++'4'-%(.B&+'&+,0'##,+$)"+'0."-'#$#.%()
%4,('$,($%$4"('$%()$+'E/"+'$(,$#'<"0,4,(:$j'+6$4,(@$)"+'0."-'#$0%($='$#&4".$%0+,##$</4."&4'$4"('#$=6
'()"(@$'-'+6$4"('$'*0'&.$.!'$4%#.$5".!$%$=%07#4%#!: L.%()%+)$122$%4#,$"(04/)'#$%$#'.$,3$!'%)'+$3"4'#$.!%.$)'%4$5".!$;`ZB$4"#.')$"( N"@/+'$K:^:$ !'
#.%()%+)$;`Z$04%##'#U )'#"@($!%+7#$=%07$.,$.!'$AhdD#$%()$"#$('')4'##46$0,<&4'*B$<%7"(@$.!'<$-'+6
!%+)$.,$'*.'()#,$)"33"0/4.B$"($3%0.B$.!%.$'(."+'$=,,7#$!%-'$=''($5+"..'($,($.!'$#/=>'0.:$;.$%4#,$4'%-'#
.!'$&+,@+%<<'+$5".!$%$_%(),+%U#$=,*$,3$/(+'#,4-')$"##/'#$+'4%.')$.,$0!%+%0.'+$'(0,)"(@#$%()
&4%.3,+<?)'&'()'(.$="(%+6$+'&+'#'(.%.",(#$,3$&+"<"."-'$)%.%$.6&'#:

<#=>5+&'(M(&,--&NOP&2#$535B&"+39+5&J#2+6

L+39+5&J#2+ C+6.5#1%#/4
<fstream> '<&4%.'$04%##'#$.!%.$<%("&/4%.'$'*.'+(%4$3"4'#
<iomanip> ;`Z$#.+'%<$<%("&/4%.,+#$.!%.$.%7'$%($%+@/<'(.
<ios> '<&4%.'$=%#'$04%##$3,+$;`Z$#.+'%<#
<iosfwd> N,+5%+)$)'04%+%.",(#$3,+$#'-'+%4$;`Z$#.+'%<$.'<&4%.'$04%##'#
<iostream> L.%()%+)$;`Z$#.+'%<#$VcinB coutB cerrB clogW
<istream> '<&4%.'$04%##$.!%.$0,(.+,4#$"(&/.$3+,<$%$#.+'%<$=/33'+
<ostream> N"@/+'$K:c$4"#.#$.!'$1$4"=+%+6$!'%)'+$3"4'#:$S,#.$,3$.!'#'$,33'+$3/(0.",(%4".6$.!%.$,-'+4%&#$5".!$<,+'
'<&4%.'$04%##$.!%.$0,(.+,4#$,/.&/.$.,$%$#.+'%<$=/33'+ +'0'(.$122$!'%)'+#$,+$5".!$H.:$Z('$(,.%=4'$'*0'&.",($"# <cmath>B$5!"0!$)'04%+'#$<%.!'<%."0%4
<sstream> '<&4%.'$04%##'#$.!%.$%##,0"%.'$#.+'%<$=/33'+#$5".!$#.+"(@# 3/(0.",(#$#/0!$%# sin()B sqrt()B$%() pow():

<streambuf> '<&4%.'$04%##'#$.!%.$=/33'+$;`Z$,&'+%.",(# <#=>5+&'(T(&,--&"+39+5&J#2+6&J/5&,&2#$535B&J3.#2#%#+6


<strstream> 14%##'#$3,+$&'+3,+<"(@$;`Z$#.+'%<$,&'+%.",(#$,($0!%+%0.'+$%++%6#
L+39+5&J#2+ C+6.5#1%#/4
<cassert> !' ASSERT()$<%0+,

1!%&.'+$A]$V;(&/.`Z/.&/.W$&+'#'(.#$.!'$0,++'#&,()"(@$H.$04%##'#B$5!"0!$3'%./+'$G("0,)'$;`Z$%#$5'44 <cctype> N/(0.",(#$3,+$04%##"36"(@$%()$<%&&"(@$0!%+%0.'+#


%#$%$4%+@'$#'.$,3$(%.",(%4$0!%+%0.'+$'(0,)"(@#$%()$%$&4%.3,+<?"()'&'()'(.$%=#.+%0.",($3,+$#.,+"(@ <cerrno>
="(%+6$)%.%:$H.U#$;`Z$04%##'#$3,+<$.!'$=%#"#$,3$H.U#$"(.'+?&+,0'##$0,<</("0%.",(B$('.5,+7"(@B$%() S%0+,#$+'4%.')$.,$'++,+$0,()".",($+'&,+."(@
RST$#/&&,+.:$H.U#$="(%+6$%()$.'*.$#.+'%<$04%##'#$%+'$-'+6$'%#6$.,$'*.'()$.,$!%()4'$0/#.,<$)%.% <cfloat> S%0+,#$.!%.$#&'0"36$&+,&'+."'#$,3$&+"<"."-'$34,%."(@?&,"(.$.6&'#
.6&'#:
<ciso646> I4.'+(%."-'$#&'44"(@#$3,+$;LZ$c^c$0!%+#'.$/#'+#
!'$'%+46$AhhD#$#%5$.!'$"(.+,)/0.",($,3$.!'$L.%()%+)$ '<&4%.'$T"=+%+6$VL TWB$%$#'.$,3$.'<&4%.'?
=%#')$0,(.%"('+$04%##'#B$".'+%.,+#B$%()$%4@,+".!<#$.!%.$#4"&&')$"(.,$.!'$;LZ$122$#.%()%+)$%.$.!' <climits> S%0+,#$.!%.$#&'0"36$&+,&'+."'#$,3$&+"<"."-'$"(.'@'+$.6&'#
'4'-'(.!$!,/+: N"@/+'$K:C$4"#.#$.!'$!'%)'+$3"4'#$.!%.$3,+<$.!'$L T:$ !'$L T$!%#$%$-'+6$04'%(B$%4<,#.
<clocale> N/(0.",(#$%()$.6&'#$+'4%.')$.,$4,0%4"Q%.",(
<%.!'<%."0%4$)'#"@($.!%.$&+,-")'#$@'('+"0$.6&'?#%3'$3/(0.",(%4".6:$H.$&+,-")'#$".#$,5($0,(.%"('+
04%##'#B$5!,#'$)'#"@($"#$&%+.46$"(#&"+')$=6$L T: !'#'$%+'$)'#0+"=')$"( 1!%&.'+$AA: <cmath> S%.!'<%."0%4$3/(0.",(#$%()$0,(#.%(.#
<#=>5+&'(Q(&R*S&"+39+5&J#2+6 <csetjmp> N/(0.",(#$3,+$&'+3,+<"(@$(,(?4,0%4$>/<&#

<csignal> N/(0.",(#$3,+$!%()4"(@$#6#.'<$#"@(%4#
L+39+5&J#2+ C+6.5#1%#/4
<cstdarg> S%0+,#$3,+$"<&4'<'(."(@$-%+"%=4'$%+@/<'(.$4"#.$3/(0.",(#
<algorithm> F'('+%4?&/+&,#'$.'<&4%.'$3/(0.",(#
<cstddef> 1,<<,($)'3"(".",(#$3,+$#'-'+%4$#.%()%+)$!'%)'+#
<deque> a,/=4'?'()')$E/'/'$.'<&4%.'$0,(.%"('+
<cstdio> N/(0.",(#$3,+$&'+3,+<"(@$;`Z
<functional> '<&4%.'#$.!%.$!'4&$0,(#.+/0.$%()$<%("&/4%.'$3/(0.,+#
<cstdlib> F'('+%4$/."4".6$3/(0.",(#
<iterator> '<&4%.'#$.!%.$!'4&$0,(#.+/0.$%()$<%("&/4%.'$".'+%.,+#
<cstring> N/(0.",(#$3,+$<%("&/4%."(@ char$%++%6#
<list> a,/=46?4"(7')$4"#.$.'<&4%.'$0,(.%"('+
<ctime> 6&'#$%()$3/(0.",(#$3,+$<%("&/4%."(@$."<'
<map> L"(@4'?-%4/')$%()$</4."?-%4/')$<%&$.'<&4%.'$0,(.%"('+#
<cwchar> X*.'()')$</4."=6.'$%()$5")'$0!%+%0.'+$/."4"."'#
<memory> G."4"."'#$3,+$#"<&4"36"(@$<'<,+6$<%(%@'<'(.
<cwctype> N/(0.",(#$3,+$04%##"36"(@$%()$<%&&"(@$5")'$0!%+%0.'+#
<numeric> '<&4%.'$(/<'+"0$,&'+%.",(#
<queue> H/'/'$.'<&4%.'$0,(.%"('+
<set> L"(@4'?-%4/')$%()$</4."?-%4/')$#'.$.'<&4%.'$0,(.%"('+#
!"#$0,<&4'.'#$,/+$E/"07$,-'+-"'5$,3$.!'$L.%()%+)$122$4"=+%+6:$Z($.!'$;(.'+('.B$a"(7/<5%+'$,33'+#
<stack> L.%07$.'<&4%.'$0,(.%"('+ 0,<&4'.'$+'3'+'(0'$),0/<'(.%.",($3,+$.!'$L.%()%+)$122$4"=+%+6$%.
!..&O``555:)"(7/<5%+':0,<`+'3*0&&:!.<4B %()$LF;$!%#$%$0,<&+'!'(#"-'$L T$&+,@+%<<'+U#$@/")'
<utility> K%#"0$.'<&4%.'$3/(0.",(# %. !..&O``555:#@":0,<`.'0!`#.4`:$ !'$,33"0"%4$)'3"(".",($,3$.!'$L.%()%+)$122$4"=+%+6$"#$3,/()$"($.!'$1
%()$122$#.%()%+)#B$%-%"4%=4'$%#$_aN$3"4'#$,+ &%&'+$0,&"'#$3+,<$.!'$;(.'+(%.",(%4$Z+@%("Q%.",($3,+
<vector> j'0.,+$.'<&4%.'$0,(.%"('+ L.%()%+)"Q%.",($V;LZW:

;($.!"#$%&&'()"*B$5'$!%-'$0,-'+')$%$4,.$,3$@+,/()$%.$%$3%#.$&%0':$Y!'($6,/$#.%+.$4'%+("(@$H.$3+,<
1!%&.'+$AB$6,/$#!,/4)$3"()$.!%.$.!'$#6(.%*$"# %$4,.$#"<&4'+$%()$04'%+'+$.!%($.!"#$%&&'()"*$<"@!.$!%-'
#/@@'#.'):$F,,)$H.$&+,@+%<<"(@$,(46$+'E/"+'#$.!'$/#'$,3$%$#/=#'.$,3$122$%()$/#/%446$%-,")#$.!'
L"(0'$122$"#$'##'(."%446$%$#/&'+#'.$,3$.!'$1$&+,@+%<<"(@$4%(@/%@'B$122$&+,@+%<<'+#$%4#,$!%-'
('')$3,+$.!'$<,+'$0,<&4'*$%()$,=#0/+'$#6(.%*$.!%.$122$<%7'#$&,##"=4':$Z(0'$6,/$#.%+.$.6&"(@$"(
.!'$'(."+'$1$4"=+%+6$%.$.!'"+$)"#&,#%4:$ !'$1$!'%)'+$3"4'#$%+'$%-%"4%=4'$'".!'+$5".!$.!'"+$.+%)".",(%4
0,)'$%()$=/"4)"(@$%()$+/(("(@$'*'0/.%=4'#B$.!'$04%+".6$%()$#"<&4"0".6$,3$.!'$H.$%&&+,%0!$5"44$='0,<'
(%<'#$V3,+$'*%<&4'B <stdio.h>W$,+$5".!$('5?#.64'$(%<'#$5".!$% c?$&+'3"*$%()$(, .h$V3,+$'*%<&4'B
%&&%+'(.:$I()$%#$#,,($%#$6,/$#.%+.$5+"."(@$<,+'$%<=".",/#$&+,@+%<#B$'#&'0"%446$.!,#'$.!%.$('')$3%#.
<cstdio>W:$Y!'($5'$/#'$.!'$('5?#.64'$-'+#",(B$.!'$3/(0.",(#$%()$)%.%$.6&'#$%+'$)'04%+')$"($.!' std
%()$3%(06$@+%&!"0#B$.!'$122`H.$0,<="(%.",($5"44$0,(."(/'$.,$7''& &%0'$5".!$6,/+$('')#:
(%<'#&%0':$V !"#$),'#(U.$%&&46$.,$<%0+,#$#/0!$%# ASSERT()B$='0%/#'$.!'$&+'&+,0'##,+$"#$/(%5%+'$,3
(%<'#&%0'#:W$ !'$('5?#.64'$#6(.%*$"#$+'0,<<'()')$"3$6,/+$0,<&"4'+$#/&&,+.#$".:
Appendix. About the Authors
U360#4&'234."+%%+

8%#<"($@+%)/%.')$"($0,<&/.'+$#0"'(0'$"($]DDA$3+,<$.!'$G("-'+#".6$,3$L!'+?=+,,7'B$H/'='0:$['$)")$%
5,+7$.'+<$%.$ +,44.'0!$"($.!'$#/<<'+$,3$]DDD$%#$%$#,3.5%+'$'(@"(''+$%()$!%#$=''($5,+7"(@$.!'+'
0,(."(/,/#46$#"(0'$'%+46$]DDA:$;($]DDPB$8%#<"($0,?5+,.'233#EFG#=:-':)55&('#H&0!#I0#J !"#
$%&!'%()*$#+!,-#!.%/#+!%0!1.%//,#'-2+!3%'4(#$,5,*%$!(5$56#.!5$3!+#$*%.!+%0,&5.#!#$6*$##. !"#!&5+
,-#!3.*7*$6!0%.'#!)#-*$3!,-# !"#$%&'$(!!,.5$+/5,*%$!,%%/!5$3!*+!+,*//!5!8#9!:/59#.!*$!;,!<2+!'%$,5*$#.
'/5++#+ !"#!*+!5/+%!'%=#3*,%.!%0 !" ')*!+*,->!1.%//,#'-2+!,#'-$*'5/!$#&+/#,,#.

!"#$%&''(")*(+,

?5.8!6.5345,#3!*$!'%(:4,#.!+'*#$'#!*$!@AAB!0.%(!,-#!C$*7#.+*,9!%0!D5/#+!E&5$+#5 !"#!0%//%&#3!,-*+
&*,-!5!9#5.2+!:%+,6.5345,#!.#+#5.'-!)#0%.#!6%*$6!*$,%!*$34+,.9 !"#!+:#$,!(5$9!9#5.+!&%.8*$6!5+!5
+%0,&5.#!#$6*$##.!0%.!5!75.*#,9!%0!0*.(+!)#0%.#!F%*$*$6!1.%//,#'- !"#!+:#$,!5/(%+,!,-.##!9#5.+!5+
1.%//,#'-2+!3%'4(#$,5,*%$!(5$56#.>!34.*$6!&-*'-!-#!0%4$3#3 !" ')*!+*,-!5$3!'%=&.%,# .//"012
3*4&*)55$%&"6$!7" !"8 !?5.8!%&$+!;,.5*$*$6 #4!5$3!&%.8+!5+!5$!*$3#:#$3#$,!,.5*$#.!5$3
'%$+4/,5$,!+:#'*5/*G*$6!*$!HII>!;,>!5$3!J9,-%$

View publication stats

You might also like