diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:24:15 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:24:15 -0500 |
commit | bd0f3345a938b35ce6a12f6150373b0955b8dd12 (patch) | |
tree | 7a520322212d48ebcb9fbe1087e7fca28b76185c /doc/tutorial.doc | |
download | qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.tar.gz qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.zip |
Add Qt3 development HEAD version
Diffstat (limited to 'doc/tutorial.doc')
-rw-r--r-- | doc/tutorial.doc | 2651 |
1 files changed, 2651 insertions, 0 deletions
diff --git a/doc/tutorial.doc b/doc/tutorial.doc new file mode 100644 index 0000000..8bd7218 --- /dev/null +++ b/doc/tutorial.doc @@ -0,0 +1,2651 @@ +/**************************************************************************** +** +** Tutorial +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +/*! \page tutorial.html + +\title Qt Tutorial #1 - The 14 Steps + +This tutorial gives an introduction to GUI programming using the Qt +toolkit. It doesn't cover everything: the emphasis is on teaching the +programming philosophy of GUI programming, and Qt's features are +introduced as needed. Some commonly used features are never used in +this tutorial. + +Chapter one starts with a ten-line hello-world and each subsequent +chapter introduces one or a few more concepts. By Chapter 14, the ten +lines from Chapter 1 have turned into a 650-line game. + +If you're completely new to Qt, please read \link how-to-learn-qt.html +How to Learn Qt\endlink if you haven't already done so. + +Tutorial chapters: +\list 1 +\i \link tutorial1-01.html Hello, World!\endlink +\i \link tutorial1-02.html Calling it Quits\endlink +\i \link tutorial1-03.html Family Values\endlink +\i \link tutorial1-04.html Let There Be Widgets\endlink +\i \link tutorial1-05.html Building Blocks\endlink +\i \link tutorial1-06.html Building Blocks Galore!\endlink +\i \link tutorial1-07.html One Thing Leads to Another\endlink +\i \link tutorial1-08.html Preparing for Battle\endlink +\i \link tutorial1-09.html With Cannon You Can\endlink +\i \link tutorial1-10.html Smooth as Silk\endlink +\i \link tutorial1-11.html Giving It a Shot\endlink +\i \link tutorial1-12.html Hanging in the Air the Way Bricks Don't\endlink +\i \link tutorial1-13.html Game Over\endlink +\i \link tutorial1-14.html Facing the Wall\endlink +\endlist + +This little game doesn't look much like a modern GUI application. It +uses a good few of the GUI techniques, but after you've worked through +it, we recommend reading \link tutorial2.html Tutorial #2\endlink. The +second tutorial is a little more formal and covers the features of +typical application including menubars, toolbars, loading and saving, +dialogs, etc. + +*/ + +/*! \page tutorial1-01.html + +\title Qt Tutorial - Chapter 1: Hello, World! + +\img t1.png Screenshot of tutorial one + +This first program is a simple hello-world example. It contains only +the bare minimum you need to get a Qt application up and running. +The picture above is a snapshot of this program. + +\include t1/main.cpp +\quotefile t1/main.cpp + +\section1 Line-by-line Walkthrough + +\skipto include +\printline qapp + +This line includes the QApplication class definition. There has to be +exactly one QApplication object in every application that uses Qt. +QApplication manages various application-wide resources, such as the +default font and cursor. + +\printline qpushbutton + +This line includes the QPushButton class definition. The +\link hierarchy.html reference documentation \endlink for each class +mentions at the top which file needs to be included to use that class. + +QPushButton is a classical GUI push button that the user can press +and release. It manages its own look and feel, like every other \l +QWidget. A widget is a user interface object that can process user +input and draw graphics. The programmer can change both the overall +\link QApplication::setStyle() look and feel\endlink and many minor +properties of it (such as color), as well as the widget's content. A +QPushButton can show either a text or a \l QPixmap. + +\printline main +\printline { + +The main() function is the entry point to the program. Almost always +when using Qt, main() only needs to perform some kind of initialization +before passing the control to the Qt library, which then tells the +program about the user's actions via events. + +\c argc is the number of command-line arguments and \c argv is the +array of command-line arguments. This is a C/C++ feature. It is not +specific to Qt; however, Qt needs to process these arguments (see +following). + +\printline QApplication + +\c a is this program's QApplication. Here it is created and processes +some of the command-line arguments (such as -display under X Window). +Note that all command-line arguments recognized by Qt are removed from +\c argv (and \c argc is decremented accordingly). See the \l +QApplication::argv() documentation for details. + +<strong>Note:</strong> It is essential that the QApplication object be +created before any window-system parts of Qt are used. + +\printline QPushButton + +Here, \e after the QApplication, comes the first window-system code: A +push button is created. + +The button is set up to display the text "Hello world!" and be a +window of its own (because the constructor specifies 0 for the parent +window, inside which the button should be located). + +\printline resize + +The button is set up to be 100 pixels wide and 30 pixels high (plus the +window system frame). In this case we don't care about the button's +position, and we accept the default value. + +\printline setMainWidget + +The push button is chosen as the main widget for the application. If +the user closes a main widget, the application exits. + +You don't have to have a main widget, but most programs do have one. + +\printline show + +A widget is never visible when you create it. You must call show() to +make it visible. + +\printline exec + +This is where main() passes control to Qt, and exec() will return when +the application exits. + +In exec(), Qt receives and processes user and system events and passes +these on to the appropriate widgets. + +\printline } + +You should now try to compile and run this program. + +\target compiling +\section1 Compiling + +To compile a C++ application you need to create a makefile. The +easiest way to create a makefile for Qt is to use the \link +qmake-manual.book qmake\endlink build tool supplied with Qt. If you've +saved \c main.cpp in its own directory, all you have to do is: +\code +qmake -project +qmake +\endcode + +The first command tells \link qmake-manual.book qmake\endlink to +create a \c .pro (project) file. The second command tells it to create +a (platform-specific) makefile based on the project file. You should +now be able to type \c make (or \c nmake if you're using Visual +Studio) and then run your first Qt application! + +\section1 Behavior + +When you run it, you will see a small window filled with a single +button, and on it you can read the famous words, Hello World! + +\section1 Exercises + +Try to resize the window. Press the button. If you're running X +Window, try running the program with the -geometry option +(for example, \c {-geometry 100x200+10+20}). + +You're now ready for \link tutorial1-02.html Chapter 2.\endlink + +[\link tutorial1-02.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \page tutorial1-02.html + +\title Qt Tutorial - Chapter 2: Calling it Quits + +\img t2.png Screenshot of tutorial two + +Having created a window in \link tutorial1-01.html Chapter 1, \endlink we will +now go on to make the application quit properly when the user tells it to. + +We will also use a font that is more exciting than the default one. + +\include t2/main.cpp +\quotefile t2/main.cpp + +\section1 Line-by-line Walkthrough + +\skipto qfont +\printline qfont + +Since this program uses QFont, it needs to include qfont.h. Qt's font +abstraction is rather different from the horror provided by X, and +loading and using fonts has been highly optimized. + +\skipto QPushButton +\printline QPushButton + +This time, the button says "Quit" and that's exactly what the program +will do when the user clicks the button. This is not a coincidence. +We still pass 0 as the parent, since the button is a top-level window. + +\printline resize + +We've chosen another size for the button since the text is a bit +shorter than "Hello world!". We could also have used \l QFontMetrics +to set right size. + +\printline setFont + +Here we choose a new font for the button, an 18-point bold font from +the Times family. Note that we create the font on the spot. + +It is also possible to change the default font (using \l +QApplication::setFont()) for the whole application. + +\printline connect + +connect() is perhaps \e the most central feature of Qt. +Note that connect() is a static function in QObject. Do not confuse it +with the connect() function in the socket library. + +This line establishes a one-way connection between two Qt objects (objects +that inherit QObject, directly or indirectly). Every Qt object can have +both \c signals (to send messages) and \c slots (to receive messages). All +widgets are Qt objects. They inherit QWidget which in turn inherits +QObject. + +Here, the \e clicked() signal of \e quit is connected to the \e +quit() slot of \e a, so that when the button is clicked, the +application quits. + +The \link signalsandslots.html Signals and Slots\endlink documentation +describes this topic in detail. + +\section1 Behavior + +When you run this program, you will see an even smaller window than in +Chapter 1, filled with an even smaller button. + +(See \link tutorial1-01.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Try to resize the window. Press the button. Oops! That connect() +would seem to make some difference. + +Are there any other signals in QPushButton you can connect to quit? +Hint: The QPushButton inherits most of its behavior from QButton. + +You're now ready for \link tutorial1-03.html Chapter 3.\endlink + +[\link tutorial1-01.html Previous tutorial\endlink] +[\link tutorial1-03.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \page tutorial1-03.html + +\title Qt Tutorial - Chapter 3: Family Values + +\img t3.png Screenshot of tutorial three + +This example shows how to create parent and child widgets. + +We'll keep it simple and use just a single parent and a lone child. + +\include t3/main.cpp +\quotefile t3/main.cpp + +\section1 Line-by-line Walkthrough + +\skipto qvbox.h +\printline qvbox.h + +We add an include of qvbox.h to get the layout class we'll use. + +\skipto QVBox +\printline QVBox + +Here we simply create a vertical box container. The QVBox arranges +its child widgets in a vertical row, one above the other, handing out +space according to each child's \l QWidget::sizePolicy(). + +\printline resize + +We set its width to 200 pixels and the height to 120 pixels. + +\printline quit + +A child is born. + +This QPushButton is created with both a text ("Quit") and a parent +(box). A child widget is always on top of its parent. When +displayed, it is clipped by its parent's bounds. + +The parent widget, the QVBox, automatically adds the child centered in +its box. Because nothing else is added, the button gets all the space +the parent has. + +\skipto show +\printline show + +When a parent widget is shown, it will call show for all its children +(except those on which you have done an explicit \l QWidget::hide()). + +\section1 Behavior + +The button no longer fills the entire widget. Instead, it gets a +"natural" size. This is because there is now a new top-level widget, +which uses the button's size hint and size change policy to set the +button's size and position. (See \l QWidget::sizeHint() and \l +QWidget::setSizePolicy() for more information about these functions.) + +(See \link tutorial1-01.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Try resizing the window. How does the button change? What is the +button's size-change policy? What happens to the button's height if +you run the program with a bigger font? What happens if you try to +make the window \e really small? + +You're now ready for \link tutorial1-04.html Chapter 4.\endlink + +[\link tutorial1-02.html Previous tutorial\endlink] +[\link tutorial1-04.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \page tutorial1-04.html + +\title Qt Tutorial - Chapter 4: Let There Be Widgets + +\img t4.png Screenshot of tutorial four + +This example shows how to create your own widget, describes how to control the +minimum and maximum sizes of a widget, and introduces widget names. + +\include t4/main.cpp +\quotefile t4/main.cpp + +\section1 Line-by-line Walkthrough + +\skipto MyWidget +\printuntil } + +Here we create a new class. Because this class inherits from QWidget, +the new class is a widget and may be a top level window or a child +widget (like the push button in Chapter 3). + +This class has only one member, a constructor (in addition to the +members it inherits from QWidget). The constructor is a standard Qt +widget constructor; you should always include a similar constructor +when you create widgets. + +The first argument is its parent widget. To create a top-level window +you specify a null pointer as the parent. As you can see, this widget +defaults to be a top-level window. + +The second argument is the widget's name. This is \e not the text +that appears in the window's title bar or in the button. It is a name +associated with a widget to make it possible to \link +QObject::queryList() look up \endlink this widget later, and there is +also a \link QObject::dumpObjectTree() handy debugging function +\endlink that will list a complete widget hierarchy. + +\printline MyWidget +\printline QWidget + +The implementation of the constructor starts here. Like most widgets, +it just passes on the \c parent and \c name to the QWidget +constructor. + +\printuntil setMaximumSize + +Because this widget doesn't know how to handle resizing, we fix its size +by setting the minimum and maximum to be equal. In the next chapter +we will show how a widget can respond to resize event from the user. + +\printuntil setFont + +Here we create and set up a child widget of this widget (the new widget's +parent is \c this) which has the widget name "quit". The widget +name has nothing to do with the button text; it just happens to be +similar in this case. + +Note that \c quit is a local variable in the constructor. MyWidget +does not keep track of it, but Qt does, and will by default delete it +when MyWidget is deleted. This is why MyWidget doesn't need a +destructor. (On the other hand, there is no harm in deleting a child +when you choose to, the child will automatically tell Qt about its +imminent death.) + +The setGeometry() call does the same as move() and resize() did in the +previous chapters. + +\printline qApp +\printline } + +Because the MyWidget class doesn't know about the application object, it +has to connect to Qt's pointer to it, \c qApp. + +A widget is a software component and should know as little as possible +about its environment in order to be as general and reusable as +possible. + +Knowing the name of the application object would break this principle, +so Qt offers an alias, qApp, for the cases in which a component such as +MyWidget needs to talk to the application object. + +\printuntil } + +Here we instantiate our new child, set it to be the main widget, and +execute the application. + +\section1 Behavior + +This program is very similar in behavior to the previous one. The +difference lies in the way we have implemented it. It does behave +slightly differently, however. Just try to resize it to see. + +(See \link tutorial1-01.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Try to create another MyWidget object in main(). What happens? + +Try to add more buttons or put in widgets other than QPushButton. + +You're now ready for \link tutorial1-05.html Chapter 5.\endlink + +[\link tutorial1-03.html Previous tutorial\endlink] +[\link tutorial1-05.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \page tutorial1-05.html + +\title Qt Tutorial - Chapter 5: Building Blocks + +\img t5.png Screenshot of tutorial five + +This example shows how to create and connect together several widgets +by using signals and slots, and how to handle resize events. + +\include t5/main.cpp +\quotefile t5/main.cpp + +\section1 Line-by-line Walkthrough + +\skipto qapp +\printuntil qvbox + +Three new include files are shown here. qslider.h and qlcdnumber.h are there +because we use two new widgets, QSlider and QLCDNumber. qvbox.h is +here because we use Qt's automatic layout support. + +\skipto MyWidget +\printuntil } + +\target constructor +\printuntil { + +MyWidget is now derived from QVBox instead of QWidget. That way we use +the layout of the QVBox (which places all of its children vertically +inside itself). Resizes are now handled automatically by the QVBox and +therefore by MyWidget, too. + +\skipto lcd +\printline lcd + +\c lcd is a QLCDNumber, a widget that displays numbers in an LCD-like +fashion. This instance is set up to display two digits and to be a child of +\e this. It is named "lcd". + +\printline QSlider +\printline slider +\printline slider + +QSlider is a classical slider; the user can use the widget to drag +something to adjust an integer value in a range. Here we create a +horizontal one, set its range to 0-99 (inclusive, see the \l +QSlider::setRange() documentation) and its initial value to 0. + +\printline connect + +Here we use the \link signalsandslots.html signal/slot mechanism \endlink +to connect the slider's valueChanged() signal to the LCD number's +display() slot. + +Whenever the slider's value changes it broadcasts the new value by +emitting the valueChanged() signal. Because that signal is connected to +the LCD number's display() slot, the slot is called when the signal is +broadcast. Neither of the objects knows about the other. This is +essential in component programming. + +Slots are otherwise normal C++ member functions and follow the normal +C++ access rules. + +\section1 Behavior + +The LCD number reflects everything you do to the slider, and the +widget handles resizing well. Notice that the LCD number widget +changes in size when the window is resized (because it can), but the +others stay about the same (because otherwise they would look stupid). + +(See \link tutorial1-01.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Try changing the LCD number to add more digits or \link +QLCDNumber::setMode() to change mode.\endlink You can even add four push +buttons to set the number base. + +You can also change the slider's range. + +Perhaps it would have been better to use \l QSpinBox than a slider? + +Try to make the application quit when the LCD number overflows. + +You're now ready for \link tutorial1-06.html Chapter 6.\endlink + +[\link tutorial1-04.html Previous tutorial\endlink] +[\link tutorial1-06.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \page tutorial1-06.html + +\title Qt Tutorial - Chapter 6: Building Blocks Galore! + +\img t6.png Screenshot of tutorial six + +This example shows how to encapsulate two widgets into a new component and +how easy it is to use many widgets. For the first time, we use a custom +widget as a child widget. + +\target main +\include t6/main.cpp +\quotefile t6/main.cpp + +\section1 Line-by-line Walkthrough + +\skipto LCDRange +\printuntil }; + +The LCDRange widget is a widget without any API. It just has a +constructor. This sort of widget is not very useful, so we'll add some API later. + +\printuntil } + +This is lifted straight from the +\link tutorial1-05.html#constructor MyWidget constructor \endlink in Chapter 5. +The only differences are that the button is left out and the class +is renamed. + +\printline MyWidget +\printuntil } + +MyWidget, too, contains no API except a constructor. + +\printline MyWidget +\printuntil connect + +The push button that used to be in what is now LCDRange has been +separated so that we can have one "Quit" button and many LCDRange +objects. + +\printline grid + +We create a QGrid object with four columns. The QGRid widget +automatically arranges its children in rows and columns; you can +specify the number of rows or of columns, and QGrid will discover its +new children and fit them into the grid. + +\printline for +\printline for +\printline LCDRange + +Four columns, four rows. + +We create 4*4 LCDRanges, all of which are children of the grid object. +The QGrid widget will arrange them. + +\printline } + +That's all. + +\section1 Behavior + +This program shows how easy it is to use many widgets at a time. Each +one behaves like the slider and LCD number in the previous +chapter. Again, the difference lies in the implementation. + +(See \link tutorial1-01.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Initialize each slider with a different/random value on startup. + +The source contains three occurrences of "4". What happens if you +change the one in the \l QGrid constructor call? What about the other +two? Why is this? + +You're now ready for \link tutorial1-07.html Chapter 7.\endlink + +[\link tutorial1-05.html Previous tutorial\endlink] +[\link tutorial1-07.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t7/lcdrange.h */ +/*! \file t7/lcdrange.cpp */ +/*! \file t7/main.cpp */ + +/*! \page tutorial1-07.html + +\title Qt Tutorial - Chapter 7: One Thing Leads to Another + +\img t7.png Screenshot of tutorial seven + +This example shows how to create custom widgets with signals and +slots, and how to connect them together in more complex ways. For the +first time, the source is split among several files which we've placed +in the \c t7 subdirectory. + +\list +\i \l t7/lcdrange.h contains the LCDRange class definition. +\i \l t7/lcdrange.cpp contains the LCDRange implementation. +\i \l t7/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + +\section2 \l t7/lcdrange.h + +This file is mainly lifted from \link tutorial1-06.html#main main.cpp \endlink in +Chapter 6; only the changes are noted here. + +\quotefile t7/lcdrange.h + +\skipto ifndef +\printuntil define + +This is the classic C construction to avoid errors if a header file +happens to be included more than once. If you don't use it already, +it is a very good habit to develop. The #ifndef should enclose \e all of the +header file. + +\printline include + +\c qvbox.h is included. LCDRange inherits QVBox, and the header file +of a parent class must always be included. We cheated a bit in the +previous chapters, and we let \c qwidget.h be included indirectly via +other header files such as \c qpushbutton.h. + +\printline QSlider + +This is another classic trick, but one that's much less used often. Because +we don't need QSlider in the \e interface of the class, only in the +implementation, we use a forward declaration of the class in the +header file and include the header file for QSlider in the .cpp +file. + +This makes the compilation of big projects much faster, because when a +header file has changed, fewer files need to be recompiled. It can +often speed up big compilations by a factor of two or more. + +\skipto LCDRange +\printuntil parent=0 + +Note the Q_OBJECT. This macro must be included in \e all classes that +contain signals and/or slots. If you are curious, it defines the +functions that are implemented in the +\link metaobjects.html meta object file \endlink. + +\printline value +\printuntil valueChanged + +These three members make up an interface between this widget and other +components in a program. Until now, LCDRange didn't really have an +interface at all. + +value() is a public function for accessing the value of the LCDRange. +setValue() is our first custom slot and valueChanged() is our first +custom signal. + +Slots must be implemented in the normal way (remember that a slot is also +a C++ member function). Signals are automatically implemented in the +\link signalsandslots.html meta object\endlink file. Signals follow the +access rules of protected C++ functions (i.e., they can be emitted only +by the class they are defined in or by classes inheriting from it). + +The signal valueChanged() is used when the LCDRange's value has +changed - just as you guessed from the name. This is not the last +signal you'll see called <i>something</i>Changed(). + +\section2 \l t7/lcdrange.cpp + +\quotefile t7/lcdrange.cpp + +This file is mainly lifted from \link tutorial1-06.html#main t6/main.cpp \endlink, and +only the changes are noted here. + +\skipto connect +\printline connect +\printline display +\printline connect +\printline valueChanged + +This code is from the LCDRange constructor. + +The first connect is the same that you have seen in the previous chapter. +The second is new; it connects slider's valueChanged() signal to this +object's valueChanged \e signal. Connect() with 3 arguments always +connects to signals or slots in \c this object. + +Yes, that's right. Signals can be connected to other signals. When +the first is emitted, the second signal is also emitted. + +Let's look at what happens when the user operates the slider. The +slider sees that its value has changed and emits the valueChanged() +signal. That signal is connected both to the display() slot of the +QLCDNumber and to the valueChanged() signal of the LCDRange. + +Thus, when the signal is emitted, LCDRange emits its own +valueChanged() signal. In addition, QLCDNumber::display() is called +and shows the new number. + +Note that you're not guaranteed any particular order of execution - +LCDRange::valueChanged() may be emitted before or after +QLCDNumber::display()and is entirely arbitrary. + +\skipto LCDRange::value +\printuntil } + +The implementation of value() is straightforward; it simply returns +the slider's value. + +\printline setValue +\printuntil } + +The implementation of setValue() is equally straightforward. Note +that because the slider and LCD number are connected, setting the +slider's value automatically updates the LCD number as well. In +addition, the slider will automatically adjust the value if it is +outside its legal range. + +\section2 \l t7/main.cpp + +\quotefile t7/main.cpp + +\skipto previous +\printline previous +\printuntil setValue +\printline previous +\printline } +\printline } + +All of main.cpp is copied from the previous chapter except in +the constructor for MyWidget. When we create the 16 LCDRange object, we +now connect them using the \link signalsandslots.html +signal/slot\endlink mechanism. Each has its valueChanged() signal +connected to the setValue() slot in the previous one. Because LCDRange +emits the signal valueChanged() when its value changes (surprise!), we +are here creating a "chain" of signals and slots. + +\target compiling +\section1 Compiling + +Creating a makefile for a multi-file application is no different from +creating one for a single-file application. If you've saved all the +files in this example in their own directory, all you have to do is: +\code +qmake -project +qmake +\endcode + +The first command tells \link qmake-manual.book qmake\endlink to +create a \c .pro (project) file. The second command tells it to create +a (platform-specific) makefile based on the project file. You should +now be able to type \c make (or \c nmake if you're using Visual +Studio) to build your application. + +\section1 Behavior + +On startup, the program's appearance is identical to the previous one. +Try operating the slider to the bottom right... + +\section1 Exercises + +Use the bottom right slider to set all LCDs to 50. Then set the top +half to 40 by clicking once to the left of the slider handle. Now, +use the one to the left of the last one operated to set the first +seven LCDs back to 50. + +Click to the left of the handle on the bottom right slider. What +happens? Why is this the correct behavior? + +You're now ready for \link tutorial1-08.html Chapter 8.\endlink + +[\link tutorial1-06.html Previous tutorial\endlink] +[\link tutorial1-08.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t8/lcdrange.h */ +/*! \file t8/lcdrange.cpp */ +/*! \file t8/cannon.h */ +/*! \file t8/cannon.cpp */ +/*! \file t8/main.cpp */ + +/*! \page tutorial1-08.html + +\title Qt Tutorial - Chapter 8: Preparing for Battle + +\img t8.png Screenshot of tutorial eight + +In this example, we introduce the first custom widget that can paint +itself. We also add a useful keyboard interface (with two lines of +code). + +\list +\i \l t8/lcdrange.h contains the LCDRange class definition. +\i \l t8/lcdrange.cpp contains the LCDRange implementation. +\i \l t8/cannon.h contains the CannonField class definition. +\i \l t8/cannon.cpp contains the CannonField implementation. +\i \l t8/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + +\section2 \l t8/lcdrange.h + +This file is very similar to the lcdrange.h in Chapter 7. We have added +one slot: setRange(). + +\quotefile t8/lcdrange.h + +\skipto setRange +\printline setRange + +We now add the possibility of setting the range of the LCDRange. +Until now, it has been fixed at 0..99. + +\section2 \l t8/lcdrange.cpp + +\quotefile t8/lcdrange.cpp + +There is a change to the constructor (we'll discuss that later). + +\skipto ::setRange +\printuntil slider +\printline } + +SetRange() sets the range of the slider in the LCDRange. Because we +have set up the QLCDNumber to always display two digits, we want to +limit the possible range of \c minVal and \c maxVal to 0..99 to avoid +overflow of the QLCDNumber. (We could have allowed values down to -9 +but chose not to.) If the arguments are illegal, we use Qt's +qWarning() function to issue a warning to the user and return +immediately. qWarning() is a printf-like function that by default +sends its output to \c stderr. If you want, you can install your own handler +function using \l ::qInstallMsgHandler(). + +\section2 \l t8/cannon.h + +CannonField is a new custom widget that knows how to display itself. + +\quotefile t8/cannon.h + +\skipto include +\skipto class +\printuntil parent=0 + +CannonField inherits QWidget, and we use the same idiom as for LCDRange. + +\printuntil angleChanged + +For the time being, CannonField only contains an angle value for which we +provide an interface using the same idiom as for value in LCDRange. + +\printline protected +\printline paintEvent + +This is the second of the many event handlers in QWidget that we +encounter. This virtual function is called by Qt whenever a widget needs +to update itself (i.e., paint the widget's surface). + + +\section2 \l t8/cannon.cpp + +\quotefile t8/cannon.cpp + +\skipto ::CannonField +\printuntil { + +Again, we use the same idiom as for LCDRange in the previous chapter. + +\printuntil } + +The constructor initializes the angle value to 45 degrees and sets a +custom palette for this widget. + +This palette uses the indicated color as background and picks other +colors suitably. (For this widget only the background and text +colors will actually be used.) + +\skipto ::setAngle +\printuntil emit +\printline } + +This function sets the angle value. We have chosen a legal range of +5..70 and adjust the given number of degrees accordingly. We have +chosen not to issue a warning if the new angle is out of range. + +If the new angle equals the old one, we return immediately. It is +important to only emit the signal angleChanged() when the angle \e +really has changed. + +Then we set the new angle value and repaint our widget. The \l +QWidget::repaint() function clears the widget (usually filling it with +its background color) and sends a paint event to the widget. This +results in a call to the paint event function of the widget. + +Finally, we emit the angleChanged() signal to tell the outside world +that the angle has changed. The \c emit keyword is unique to Qt and +not regular C++ syntax. In fact, it is a macro. + +\skipto ::paintEvent +\printuntil drawText +\printline } + +This is our first attempt to write a paint event handler. The event +argument contains a description of the paint event. \l QPaintEvent +contains the region in the widget that must be updated. For the time +being, we will be lazy and just paint everything. + +Our code displays the angle value in the widget at a fixed position. +First we create a QString with some text and the angle; then we create +a QPainter operating on this widget and use it to paint the string. +We'll come back to QPainter later; it can do a great many things. + + +\section2 \l t8/main.cpp + +\quotefile t8/main.cpp + +\skipto cannon.h +\printline cannon.h + +We include our new class. + +\skipto MyWidget +\printuntil }; + +This time we include a single LCDRange and a CannonField in our top-level +widget. + +\skipto angle +\printline angle + +In the constructor, we create and set up our LCDRange. + +\printline setRange + +We set the LCDRange to accept ranges from 5 to 70 degrees. + +\printline cannonField +\printline CannonField + +We create our CannonField. + +\printuntil setValue + +Here we connect the valueChanged() signal of the LCDRange to the +setAngle() slot of the CannonField. This will update CannonField's angle +value whenever the user operates the LCDRange. We also make the reverse +connection so that changing the angle in the CannonField will update the +LCDRange value. In our example we never change the angle of the +CannonField directly; but by doing the last connect() we ensure that no +future changes will disrupt the synchronization between those two values. + +This illustrates the power of component programming and proper +encapsulation. + +Notice how important it is to emit the angleChanged() signal only when +the angle actually changes. If both the LCDRange and the CannonField +had omitted this check, the program would have entered an infinite +loop upon the first change of one of the values. + +\printline QGridLayout +\printline 2x2 + +So far we have used the no-assembly-required QVBox and QGrid widgets +for geometry management. Now, however, we want to have a little more +control over the layout, and we switch to the more powerful QGridLayout +class. QGridLayout isn't a widget; it is a different class that can +manage the children of \e any widget. + +As the comment indicates, we create a two-by-two array with ten pixel +borders. (The constructor for \l QGridLayout can be a little cryptic, +so it's good to put in such comments.) + +\printline addWidget + +We add the Quit button in the top-left cell of the grid: 0, 0. + +\printline addWidget + +We put the angle LCDRange in the bottom-left cell, aligned to the top +of its cell. (This alignment is one of the things QGridLayout allows +but QGrid does not allow.) + +\printline addWidget + +We put the CannonField object in the bottom-right cell. (The top- +right cell is empty.) + +\printline setColStretch + +We tell QGridLayout that the right column (column 1) is stretchable. +Because the left column isn't (it has stretch factor 0, the default +value), QGridLayout will try to let the left-hand widgets' sizes be +unchanged and will resize just the CannonField when the MyWidget is +resized. + +\printline setValue + +We set an initial angle value. Note that this will trigger the +connection from LCDRange to CannonField. + +\printline setFocus + +Our last action is to set \c angle to have keyboard focus so that +keyboard input will go to the LCDRange widget by default. + +LCDRange does not contain any keyPressEvent(), so that would seem not +to be terribly useful. However, its constructor just got a new line: + +\quotefile t8/lcdrange.cpp +\skipto setFocusProxy +\printline setFocusProxy + +The LCDRange sets the slider to be its focus proxy. That means that +when someone (the program or the user) wants to give the LCDRange +keyboard focus, the slider should take care of it. QSlider has a decent +keyboard interface, so with just one line of code we've given LCDRange +one. + +\section1 Behavior + +The keyboard now does something - the arrow keys, Home, End, PageUp +and PageDown all do something vaguely sensible. + +When the slider is operated, the CannonField displays the new angle +value. Upon resizing, CannonField is given as much space as possible. + +On Windows machines with an 8-bit display the new background color is +dithered to death. The next chapter works around this. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Try to resize the window. What happens if you make it really narrow +or really squat? + +If you remove the AlignTop, what happens to the LCDRange's position +and size? Why? + +If you give the left-hand column a non-zero stretch factor, what +happens when you resize the window? + +Leave out the setFocus() call. Which behavior do you prefer? + +Try to change "Quit" to "&Quit" in the QButton::setText() call. How +does the button's look change? What happens if you press Alt+Q while +the program's running? (It is Meta+Q on a few keyboards.) + +Center the text in the CannonField. + +You're now ready for \link tutorial1-09.html Chapter 9.\endlink + +[\link tutorial1-07.html Previous tutorial\endlink] +[\link tutorial1-09.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t9/lcdrange.h */ +/*! \file t9/lcdrange.cpp */ +/*! \file t9/cannon.h */ +/*! \file t9/cannon.cpp */ +/*! \file t9/main.cpp */ + +/*! \page tutorial1-09.html + +\title Qt Tutorial - Chapter 9: With Cannon You Can + +\img t9.png Screenshot of tutorial nine + +In this example we become graphic by drawing a cute little blue +cannon. Only cannon.cpp differs from the previous chapter. + +\list +\i \l t9/lcdrange.h contains the LCDRange +class definition. +\i \l t9/lcdrange.cpp contains the LCDRange +implementation. +\i \l t9/cannon.h contains the CannonField class +definition. +\i \l t9/cannon.cpp contains the CannonField +implementation. +\i \l t9/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + +\section2 \l t9/cannon.cpp + +\quotefile t9/cannon.cpp + +\skipto ::paintEvent +\printuntil QPainter + +We'll now start to use QPainter in earnest. We create a painter that +operates on this widget. + +\printline setBrush + +When QPainter fills a rectangle, a circle, or whatever, it fills the +shape using its brush. Here we set it to use a blue brush. (We +could also use a pattern.) + +\printline setPen + +And the edges of what QPainter draws are drawn using the pen. Here we +set it to NoPen, meaning that there will be no special edge when we +draw something; the blue brush will go all the way to the edges of +the things we draw. + +\skipto translate +\printline translate + +The \l QPainter::translate() function translates the coordinate +system of the QPainter; i.e., it moves it by an offset. Here we set +the (0, 0) point to the bottom-left corner of the widget. The x and +y directions remain unchanged, i.e., all the y coordinates inside the +widget are now negative (see \link coordsys.html The Coordinate +System\endlink for more information about Qt's coordinate system). + +\printline drawPie + +The drawPie() function draws a pie shape inside the specified +rectangle using a start angle and an arc length. The angles are +specified in 1/16th of a degree. Zero degrees is at the 3 o'clock +position. The drawing direction is counter-clockwise. Here we draw a +quarter of a circle in the bottom-left corner of the widget. The pie +is filled with blue and has no outline. + +\printline rotate + +The QPainter::rotate() function rotates the coordinate system of the +QPainter around the origin. The rotation argument is a \c float given +in degrees (not given in 1/16th of a degree as above) and clockwise. +Here we rotate the coordinate system \c ang degrees counter-clockwise. + +\printline drawRect + +The QPainter::drawRect() function draws the specified rectangle. Here +we draw the barrel of the cannon. + +It can often be difficult to envision the resulting drawing when the +coordinate system has been transformed (translated, rotated, scaled, or +sheared) as above. + +In this case the coordinate system is first translated and then rotated. +If the rectangle QRect(33, -4, 15, 8) had been drawn in the translated +coordinate system, it would have looked like this: + +\img t9_1.png The cannon translated but not rotated + +Note that the rectangle is clipped by the border of the CannonField +widget. When we rotate the coordinate system, for instance 60 +degrees, the rectangle will be rotated around (0, 0), which is the +bottom-left corner because we have translated the coordinate system. +The result looks like this: + +\img t9_2.png The cannon translated and rotated + +We're done, except that we haven't explained why Windows didn't dither +this time. + +\quotefile t9/main.cpp +\skipto main +\printline main +\printline { +\printline CustomColor +\printline QApplication + +We tell Qt that we want a different color-allocation strategy for this +program. There is no single correct color-allocation strategy. Because +this program uses an unusual yellow but not many colors, \c +CustomColor is best. There are several other allocation strategies; you can read about them in the \l QApplication::setColorSpec() +documentation. + +Mostly you can ignore this, since the default is good. Occasionally +some applications with unusual color use look bad; changing the +allocation strategy often helps then. + +\section1 Behavior + +When the slider is operated the angle of the drawn cannon changes +accordingly. + +The Q on the Quit button is now underlined, and Alt+Q does what you +think it does. If you do not know why, you didn't do the exercises in +Chapter 8. + +You may notice that the cannon flickers annoyingly, especially on a +slow machine. We'll fix this in the next chapter. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Set a different pen instead of NoPen. Set a patterned brush. + +Try "Q&uit" or "Qu&it" as button text instead of "&Quit". What +happens? + +You're now ready for \link tutorial1-10.html Chapter 10.\endlink + +[\link tutorial1-08.html Previous tutorial\endlink] +[\link tutorial1-10.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t10/lcdrange.h */ +/*! \file t10/lcdrange.cpp */ +/*! \file t10/cannon.h */ +/*! \file t10/cannon.cpp */ +/*! \file t10/main.cpp */ + +/*! \page tutorial1-10.html + +\title Qt Tutorial - Chapter 10: Smooth as Silk + +\img t10.png Screenshot of tutorial ten + +In this example, we introduce painting in a pixmap to remove flickering. +We also add a force control. + +\list +\i \l t10/lcdrange.h contains the LCDRange +class definition. +\i \l t10/lcdrange.cpp contains the LCDRange +implementation. +\i \l t10/cannon.h contains the CannonField class +definition. +\i \l t10/cannon.cpp contains the CannonField +implementation. +\i \l t10/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + +\section2 \l t10/cannon.h + +The CannonField now has a force value in addition to the angle. + +\quotefile t10/cannon.h + +\skipto angle +\printuntil forceChanged + +The interface to the force follows the same practice as for the angle. + +\skipto private +\printuntil cannonRect + +We have put the definition of the cannon's enclosing rectangle in a +separate function. + +\skipto ang +\printuntil }; + +The force is stored in the integer \c f. + +\section2 \l t10/cannon.cpp + +\quotefile t10/cannon.cpp + +\skipto include +\skipto pixmap +\printline pixmap + +We include the QPixmap class definition. + +\skipto ::CannonField +\printuntil } + +The force (\c f) is initialized to zero. + +\skipto ::setAngle +\printuntil } + +We have made a slight change in the setAngle() function. It repaints +only the portion of the widget that contains the cannon. The FALSE +argument indicates that the specified rectangle should not be erased +before a paint event is sent to the widget. This speeds up and smooths +the drawing a little bit. + +\skipto ::setForce +\printuntil } + +The implementation of setForce() is quite similar to that of +setAngle(). The only difference is that because we don't show the force +value, we don't need to repaint the widget. + +\skipto ::paintEvent +\printuntil return + +We have now optimized the paint event to repaint only the parts of the +widget that need updating. First we check whether we have to paint +anything at all, and we return if we don't. + +\printline cannonRect +\printline pix + +Then we create a temporary pixmap, which we use for flicker-free +painting. All the painting operations are done into this pixmap, and +then the pixmap is drawn on the screen in a single operation. + +This is the essence of flicker-free drawing: Draw on each pixel +precisely once. Less, and you get drawing errors. More, and you get +flicker. It doesn't matter much in this example - when the code was +written there were still machines slow enough for it to flicker, but +not any more. We've kept the code for educational purposes. + +\printline fill + +We fill the pixmap with the background from this widget. + +\printline QPainter +\printuntil end + +We paint, as in Chapter 9, but now we paint in the pixmap. + +At this point, we have a painter variable and a pixmap that looks +precisely right, but we still haven't painted on the screen. + +\printline begin +\printline drawPixmap + +So we open the painter on the CannonField itself and then draw the pixmap. + +That's all. A couple of extra lines at the top and a couple at the +bottom, and the code is 100% flicker-free. + +\skipto cannonRect +\printuntil } + +This function returns the rectangle enclosing the cannon in widget +coordinates. First we create a rectangle with the size 50x50 and then +move it so its bottom left corner is equal to the widget's own bottom- +left corner. + +The \l QWidget::rect() function returns the widget's enclosing +rectangle in the widget's own coordinates (where the top left corner +is 0, 0). + +\section2 \l t10/main.cpp + +\quotefile t10/main.cpp + +\skipto MyWidget::MyWidget +\printuntil { + +The constructor is mostly the same, but some new bits have been added. + +\skipto force +\printline force +\printline force + +We add a second LCDRange, which will be used to set the force. + +\skipto force +\printline connect +\printline cannonField +\printline connect +\printline force + +We connect the \c force widget and the \c cannonField widget, just like +we did for the \c angle widget. + +\skipto QVBoxLayout +\printline QVBoxLayout +\printline addLayout +\printline addWidget +\printline addWidget + +In Chapter 9 we put \c angle in the lower-left cell of the layout. +Now we want to have two widgets in that cell, so we make a vertical +box, put the vertical box in the grid cell, and put each of \c angle +and \c range in the vertical box. + +\skipto force +\printline setValue + +We initialize the force value to 25. + +\section1 Behavior + +The flicker has gone and we have a force control. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + + +\section1 Exercises + +Make the size of the cannon barrel be dependent on the force. + +Put the cannon in the bottom-right corner. + +Try adding a better keyboard interface. For example, make + and - +increase and decrease the force and enter shoot. Hint: \l QAccel and +new addStep() and subtractStep() slots in LCDRange, like \l +QSlider::addStep(). If you're bothered by the way the left and right +keys work (I am!), change that too. + +You're now ready for \link tutorial1-11.html Chapter 11.\endlink + +[\link tutorial1-09.html Previous tutorial\endlink] +[\link tutorial1-11.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t11/lcdrange.h */ +/*! \file t11/lcdrange.cpp */ +/*! \file t11/cannon.h */ +/*! \file t11/cannon.cpp */ +/*! \file t11/main.cpp */ + +/*! \page tutorial1-11.html + +\title Qt Tutorial - Chapter 11: Giving It a Shot + +\img t11.png Screenshot of tutorial eleven + +In this example we introduce a timer to implement animated shooting. + +\list +\i \l t11/lcdrange.h contains the LCDRange +class definition. +\i \l t11/lcdrange.cpp contains the LCDRange +implementation. +\i \l t11/cannon.h contains the CannonField class +definition. +\i \l t11/cannon.cpp contains the CannonField +implementation. +\i \l t11/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + +\section2 \l t11/cannon.h + +The CannonField now has shooting capabilities. + +\quotefile t11/cannon.h + +\skipto shoot +\printline shoot + +Calling this slot will make the cannon shoot if a shot is not in the air. + +\printline private +\printline moveShot + +This private slot is used to move the shot while it is in the air, +using a \l QTimer. + +\skipto private +\printline private +\printline paintShot + +This private function paints the shot. + +\skipto shotRect +\printline shotRect + +This private function returns the shot's enclosing rectangle if +one is in the air; otherwise the returned rectangle is undefined. + +\skipto timerCount +\printuntil shoot_f +\printline }; + +These private variables contain information that describes the shot. The +\c timerCount keeps track of the time passed since the shot was fired. +The \c shoot_ang is the cannon angle and \c shoot_f is the cannon force +when the shot was fired. + + +\section2 \l t11/cannon.cpp + +\quotefile t11/cannon.cpp + +\skipto include +\skipto math +\printline math + +We include the math library because we need the sin() and cos() functions. + +\skipto ::CannonField +\printuntil } + +We initialize our new private variables and connect the \l +QTimer::timeout() signal to our moveShot() slot. We'll move the +shot every time the timer times out. + +\skipto ::shoot +\printuntil start +\printline } + +This function shoots a shot unless a shot is in the air. The \c timerCount +is reset to zero. The \c shoot_ang and \c shoot_f are set to the current +cannon angle and force. Finally, we start the timer. + +\skipto ::moveShot +\printuntil repaint +\printline } + +moveShot() is the slot that moves the shot, called every 50 +milliseconds when the QTimer fires. + +Its tasks are to compute the new position, repaint the screen with the +shot in the new position, and if necessary, stop the timer. + +First we make a \l QRegion that holds the old shotRect(). A QRegion +is capable of holding any sort of region, and we'll use it here to +simplify the painting. ShotRect() returns the rectangle where the +shot is now - it is explained in detail later. + +Then we increment the \c timerCount, which has the effect of moving the +shot one step along its trajectory. + +Next we fetch the new shot rectangle. + +If the shot has moved beyond the right or bottom edge of the widget, we +stop the timer or we add the new shotRect() to the QRegion. + +Finally, we repaint the QRegion. This will send a single paint event +for just the one or two rectangles that need updating. + +\skipto ::paintEvent +\printuntil } + +The paint event function has been split in two since the previous +chapter. Now we fetch the bounding rectangle of the region that +needs painting, check whether it intersects either the cannon and/or +the shot, and if necessary, call paintCannon() and/or paintShot(). + +\skipto ::paintShot +\printuntil drawRect +\printline } + +This private function paints the shot by drawing a black filled rectangle. + +We leave out the implementation of paintCannon(); it is the same as +the paintEvent() from the previous chapter. + +\skipto ::shotRect +\printuntil return +\printline } + +This private function calculates the center point of the shot and returns +the enclosing rectangle of the shot. It uses the initial cannon force and +angle in addition to \c timerCount, which increases as time passes. + +The formula used is the classical Newtonian formula for frictionless +movement in a gravity field. For simplicity, we've chosen to +disregard any Einsteinian effects. + +We calculate the center point in a coordinate system where y +coordinates increase upward. After we have calculated the center +point, we construct a QRect with size 6x6 and move its center point to +the point calculated above. In the same operation we convert the +point into the widget's coordinate system (see \link coordsys.html The +Coordinate System\endlink). + +The qRound() function is an inline function defined in qglobal.h (included +by all other Qt header files). qRound() rounds a double to the closest +integer. + +\section2 \l t11/main.cpp + +\quotefile t11/main.cpp + +\skipto class +\printuntil }; + +The only addition is the Shoot button. + +\skipto ::MyWidget +\skipto shoot +\printuntil setFont + +In the constructor we create and set up the Shoot button exactly like we +did with the Quit button. Note that the first argument to the constructor +is the button text, and the third is the widget's name. + +\skipto connect +\printline connect + +Connects the clicked() signal of the Shoot button to the shoot() slot +of the CannonField. + + +\section1 Behavior + +The cannon can shoot, but there's nothing to shoot at. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + + +\section1 Exercises + +Make the shot a filled circle. Hint: \l QPainter::drawEllipse() may +help. + +Change the color of the cannon when a shot is in the air. + +You're now ready for \link tutorial1-12.html Chapter 12.\endlink + +[\link tutorial1-10.html Previous tutorial\endlink] +[\link tutorial1-12.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t12/lcdrange.h */ +/*! \file t12/lcdrange.cpp */ +/*! \file t12/cannon.h */ +/*! \file t12/cannon.cpp */ +/*! \file t12/main.cpp */ + +/*! \page tutorial1-12.html + +\title Qt Tutorial - Chapter 12: Hanging in the Air the Way Bricks Don't + +\img t12.png Screenshot of tutorial twelve + +In this example, we extend our LCDRange class to include a text label. +We also provide something to shoot at. + +\list +\i \l t12/lcdrange.h contains the LCDRange +class definition. +\i \l t12/lcdrange.cpp contains the LCDRange +implementation. +\i \l t12/cannon.h contains the CannonField class +definition. +\i \l t12/cannon.cpp contains the CannonField +implementation. +\i \l t12/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + + +\section2 \l t12/lcdrange.h + +The LCDRange now has a text label. + +\quotefile t12/lcdrange.h + +\skipto QLabel +\printline QLabel + +We name declare QLabel because we want to use a pointer to it in the class +definition. + +\skipto class +\printuntil parent=0 +\printline parent=0 +\printline name=0 + +We have added a new constructor that sets the label text in addition to +the parent and name. + +\skipto text +\printline text + +This function returns the label text. + +\skipto setText +\printline setText + +This slot sets the label text. + +\skipto private +\printuntil init + +Because we now have two constructors, we have chosen to put the common +initialization in the private init() function. + +\skipto QLabel +\printline label + +We also have a new private variable: a QLabel. QLabel is one of Qt's +standard widgets and can show a text or a pixmap with or without a +frame. + + +\section2 \l t12/lcdrange.cpp + +\quotefile t12/lcdrange.cpp + +\skipto qlabel +\printline include + +Here we include the QLabel class definition. + +\skipto ::LCDRange +\printuntil } + +This constructor calls the init() function, which contains the common +initialization code. + +\skipto ::LCDRange +\printuntil } + +This constructor first calls init() and then sets the label text. + +\skipto ::init +\printuntil } + +The setup of \c lcd and \c slider is the same as in the previous +chapter. Next we create a QLabel and tell it to align the contents +centered (both vertically and horizontally). The connect() statements +have also been taken from the previous chapter. + +\skipto ::text +\printuntil } + +This function returns the label text. + +\skipto ::setText +\printuntil } + +This function sets the label text. + +\section2 \l t12/cannon.h + +The CannonField now has two new signals: hit() and missed(). In addition +it contains a target. + +\quotefile t12/cannon.h + +\skipto slots +\skipto newTarget +\printline newTarget + +This slot creates a target at a new position. + +\skipto signals +\printuntil missed + +The hit() signal is emitted when a shot hits the target. The missed() +signal is emitted when the shot moves beyond the right or bottom edge +of the widget (i.e., it is certain that it has not and will not +hit the target). + +\skipto paintTarget +\printline paintTarget + +This private function paints the target. + +\skipto targetRect +\printline targetRect + +This private function returns the enclosing rectangle of the target. + +\skipto target +\printline target + +This private variable contains the center point of the target. + + +\section2 \l t12/cannon.cpp + +\quotefile t12/cannon.cpp + +\skipto qdatetime +\printline qdatetime + +We include the QDate, QTime, and QDateTime class definitions. + +\skipto stdlib +\printline stdlib + +We include the stdlib library because we need the rand() function. + +\skipto newTarget +\printline newTarget + +This line has been added to the constructor. It creates a "random" +position for the target. In fact, the newTarget() function will try +to paint the target. Because we are in a constructor, the CannonField +widget is invisible. Qt guarantees that no harm is done when calling +repaint() on a hidden widget. + +\skipto ::newTarget +\printuntil repaint +\printline } + +This private function creates a target center point at a new "random" +position. + +We use the rand() function to fetch random integers. The rand() function +normally returns the same series of numbers each time you run a program. +This would make the target appear at the same position every time. To +avoid this, we must set a random seed the first time this function is +called. The random seed must also be random in order to avoid equal random +number series. The solution is to use the number of seconds that have +passed since midnight as a pseudo-random value. + +First we create a static bool local variable. A static variable like +this one is guaranteed to keep its value between calls to the function. + +The \c if test will succeed only the first time this function is called +because we set \c first_time to FALSE inside the \c if block. + +Then we create the QTime object \c midnight, which represents the time +00:00:00. Next we fetch the number of seconds from midnight until +now and use it as a random seed. See the documentation for \l QDate, +\l QTime, and \l QDateTime for more information. + +Finally we calculate the target's center point. We keep it within +the rectangle (x=200, y=35, width=190, height=255), (i.e., the +possible x and y values are x = 200..389 and y = 35..289) in a +coordinate system where we put y position 0 at the bottom edge of the +widget and let y values increase upwards X is as normal, with 0 at +the left edge and with x values increasing to the right. + +By experimentation we have found this to always be in reach of the shot. + +Note that rand() returns a random integer >= 0. + +\skipto ::moveShot +\printuntil QRect + +This part of the timer event has not changed from the previous chapter. + +\printuntil hit + +This \c if statement checks whether the shot rectangle intersects the +target rectangle. If it does, the shot has hit the target (ouch!). +We stop the shoot timer and emit the hit() signal to tell the outside +world that a target was destroyed, and return. + +Note that we could have created a new target on the spot, but because the +CannonField is a component we leave such decisions to the user of the +component. + +\printuntil missed + +This \c if statement is the same as in the previous chapter, except that +it now emits the missed() signal to tell the outside world about the +failure. + +\printuntil } + +And the rest of the function is as before. + +CannonField::paintEvent() is as before, except that this has been +added: + +\skipto ::paintEvent +\skipto targetRect +\printline updateR +\printline paintTarget + +These two lines make sure that the target is also painted when necessary. + +\skipto ::paintTarget +\printuntil } + +This private function paints the target; a rectangle filled with red and +with a black outline. + +\skipto ::targetRect +\printuntil } + +This private function returns the enclosing rectangle of the target. +Remember from newTarget() that the \c target point uses y coordinate 0 at +the bottom of the widget. We calculate the point in widget coordinates +before we call \l QRect::moveCenter(). + +The reason we have chosen this coordinate mapping is to fix the distance +between the target and the bottom of the widget. Remember that the widget +can be resized by the user or the program at any time. + +\section2 \l t12/main.cpp + +\quotefile t12/main.cpp + +There are no new members in the MyWidget class, but we have slightly +changed the constructor to set the new LCDRange text labels. + +\skipto ::MyWidget +\skipto angle +\printline ANGLE + +We set the angle text label to "ANGLE". + + +\skipto force +\printline FORCE + +We set the force text label to "FORCE". + + +\section1 Behavior + +The LCDRange widgets look a bit strange - the built-in layout +management in QVBox gives the labels too much space and the rest not +enough. We'll fix that in the next chapter. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + +\section1 Exercises + +Make a cheat button that, when pressed, makes the CannonField display +the shot trajectory for five seconds. + +If you did the "round shot" exercise from the previous chapter, try +changing the shotRect() to a shotRegion() that returns a \l QRegion so +you can have really accurate collision detection. + +Make a moving target. + +Make sure that the target is always created entirely on-screen. + +Make sure that the widget cannot be resized so that the target isn't +visible. Hint: \l QWidget::setMinimumSize() is your friend. + +Not easy; make it possible to have several shots in the air at the +same time. Hint: make a Shot object. + +You're now ready for \link tutorial1-13.html Chapter 13.\endlink + +[\link tutorial1-11.html Previous tutorial\endlink] +[\link tutorial1-13.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t13/lcdrange.h */ +/*! \file t13/lcdrange.cpp */ +/*! \file t13/cannon.h */ +/*! \file t13/cannon.cpp */ +/*! \file t13/gamebrd.h */ +/*! \file t13/gamebrd.cpp */ +/*! \file t13/main.cpp */ + +/*! \page tutorial1-13.html + +\title Qt Tutorial - Chapter 13: Game Over + +\img t13.png Screenshot of tutorial thirteen + +In this example we start to approach a real playable game with a +score. We give MyWidget a new name (GameBoard) and add some slots. + +We put the definition in gamebrd.h and the implementation in gamebrd.cpp. + +The CannonField now has a game over state. + +The layout problems in LCDRange are fixed. + +\list +\i \l t13/lcdrange.h contains the LCDRange +class definition. +\i \l t13/lcdrange.cpp contains the LCDRange +implementation. +\i \l t13/cannon.h contains the CannonField class +definition +\i \l t13/cannon.cpp contains the CannonField +implementation. +\i \l t13/gamebrd.h contains the GameBoard +class definition. +\i \l t13/gamebrd.cpp contains the GameBoard +implementation. +\i \l t13/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + + +\section2 \l t13/lcdrange.h + +\quotefile t13/lcdrange.h + +\skipto include +\printuntil QWidget + +We inherit QWidget rather than QVBox. QVBox is very easy to use, but +again it showed its limitations so we switch to the more powerful and +slightly harder to use QVBoxLayout. (As you remember, QVBoxLayout is +not a widget, it manages one.) + +\section2 \l t13/lcdrange.cpp + +\quotefile t13/lcdrange.cpp + +\skipto layout +\printline layout + +We need to include qlayout.h now to get the other layout management +API. + +\printline LCDRange +\printline QWidget + +We inherit QWidget in the usual way. + +The other constructor has the same change. init() is unchanged, +except that we've added some lines at the end: + +\skipto QVBoxLayout +\printline QVBoxLayout + +We create a QVBoxLayout with all the default values, managing this +widget's children. + +\printline addWidget + +At the top we add the QLCDNumber with a non-zero stretch. + +\printline addWidget +\printline addWidget + +Then we add the other two, both with the default zero stretch. + +This stretch control is something QVBoxLayout (and QHBoxLayout, and +QGridLayout) offers but classes like QVBox do not. In this case +we're saying that the QLCDNumber should stretch and the others should +not. + +\section2 \l t13/cannon.h + +The CannonField now has a game over state and a few new functions. + +\quotefile t13/cannon.h + +\skipto gameOver +\printline gameOver + +This function returns TRUE if the game is over or FALSE if a game +is going on. + +\skipto setGameOver +\printuntil restartGame + +Here are two new slots: setGameOver() and restartGame(). + +\skipto canShoot +\printline canShoot + +This new signal indicates that the CannonField is in a state where the +shoot() slot makes sense. We'll use it below to enable/disable the +Shoot button. + +\skipto gameEnded +\printline gameEnded + +This private variable contains the game state. TRUE means that the +game is over, and FALSE means that a game is going on. + +\section2 \l t13/cannon.cpp + +\quotefile t13/cannon.cpp + +\skipto ::CannonField +\skipto gameEnded +\printline gameEnded + +This line has been added to the constructor. Initially, the game is not +over (luckily for the player :-). + +\skipto ::shoot +\printuntil } + +We added a new isShooting() function, so shoot() uses it instead of +testing directly. Also, shoot tells the world that the CannonField +cannot shoot now. + +\skipto ::setGameOver +\printuntil } + +This slot ends the game. It must be called from outside CannonField, +because this widget does not know when to end the game. This is an +important design principle in component programming. We choose to +make the component as flexible as possible to make it usable with +different rules (for example, a multi-player version of this in which the +first player to hit ten times wins could use the CannonField unchanged). + +If the game has already been ended we return immediately. If a game is +going on we stop the shot, set the game over flag, and repaint the entire +widget. + +\skipto ::restartGame +\printuntil } + +This slot starts a new game. If a shot is in the air, we stop shooting. +We then reset the \c gameEnded variable and repaint the widget. + +moveShot() too emits the new canShoot(TRUE) signal at the same time as +either hit() or miss(). + +Modifications in CannonField::paintEvent(): + +\skipto ::paintEvent +\printuntil } + +The paint event has been enhanced to display the text "Game Over" if +the game is over, i.e., \c gameEnded is TRUE. We don't bother to +check the update rectangle here because speed is not critical when +the game is over. + +To draw the text we first set a black pen; the pen color is used +when drawing text. Next we choose a 48 point bold font from the +Courier family. Finally we draw the text centered in the widget's +rectangle. Unfortunately, on some systems (especially X servers with +Unicode fonts) it can take a while to load such a large font. Because +Qt caches fonts, you will notice this only the first time the font is +used. + +\printuntil } + +We draw the shot only when shooting and the target only when playing +(that is, when the game is not ended). + + +\section2 \l t13/gamebrd.h + +This file is new. It contains the definition of the GameBoard class, +which was last seen as MyWidget. + +\quotefile t13/gamebrd.h + +\skipto include +\skipto class +\printuntil }; + +We have now added four slots. These are protected and are used internally. +We have also added two QLCDNumbers (\c hits and \c shotsLeft) which display +the game status. + + +\section2 \l t13/gamebrd.cpp + +This file is new. It contains the implementation of the GameBoard +class, which was last seen as MyWidget. + +\quotefile t13/gamebrd.cpp + +We have made some changes in the GameBoard constructor. + +\skipto ::GameBoard +\skipto cannonField +\printline cannonField + +\c cannonField is now a member variable, so we carefully change the +constructor to use it. (The \e good programmers at Trolltech never +forget this, but I do. Caveat programmor - if "programmor" is Latin, +at least. Anyway, back to the code.) + +\skipto hit +\printline connect +\printline hit +\printline connect +\printline missed + +This time we want to do something when the shot has hit or missed the +target. Thus we connect the hit() and missed() signals of the +CannonField to two protected slots with the same names in this class. + +\skipto shoot +\skipto connect +\printline fire + +Previously we connected the Shoot button's clicked() signal directly +to the CannonField's shoot() slot. This time we want to keep track of +the number of shots fired, so we connect it to a protected slot in +this class instead. + +Notice how easy it is to change the behavior of a program when you are +working with self-contained components. + +\printline connect +\printline setEnabled + +We also use the cannonField's canShoot() signal to enable or disable +the Shoot button appropriately. + +\skipto restart +\printuntil connect + +We create, set up, and connect the New Game button as we have done +with the other buttons. Clicking this button will activate the +newGame() slot in this widget. + +\printuntil shotsLeftL +\printline QLabel + +We create four new widgets. Note that we don't bother to keep the +pointers to the QLabel widgets in the GameBoard class because there's +nothing much we want to do with them. Qt will delete them when the +GameBoard widget is destroyed, and the layout classes will resize them +appropriately. + +\skipto QHBoxLayout +\printuntil addStretch +\printline addWidget + +The number of widgets in the top-right cell is getting large. Once it +was empty; now it's full enough that we group together the layout +setting for better overview. + +Notice that we let all the widgets have their preferred sizes, instead +putting the stretch just to the left of the New Game button. + +\skipto newGame +\printline newGame +\printline } + +We're all done constructing the GameBoard, so we start it all using +newGame(). (NewGame() is a slot, but as we said, slots can be used as +ordinary functions, too.) + +\skipto ::fire +\printuntil } + +This function fires a shot. If the game is over or if there is a shot in the +air, we return immediately. We decrement the number of shots left and tell +the cannon to shoot. + +\skipto ::hit +\printuntil } + +This slot is activated when a shot has hit the target. We increment the +number of hits. If there are no shots left, the game is over. Otherwise, +we make the CannonField generate a new target. + +\skipto ::missed +\printuntil } + +This slot is activated when a shot has missed the target. If there are no +shots left, the game is over. + +\skipto ::newGame +\printuntil } + +This slot is activated when the user clicks the Restart button. It is +also called from the constructor. First it sets the number of shots +to 15. Note that this is the only place in the program where we set +the number of shots. Change it to whatever you like to change the +game rules. Next we reset the number of hits, restart the game, and +generate a new target. + +\section2 \l t13/main.cpp + +This file has just been on a diet. MyWidget is gone, and the only +thing left is the main() function, unchanged except for the name +change. + + +\section1 Behavior + +The cannon can shoot at a target; a new target is automatically created +when one has been hit. + +Hits and shots left are displayed and the program keeps track of them. +The game can end, and there's a button to start a new game. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + + +\section1 Exercises + +Add a random wind factor and show it to the user. + +Make some splatter effects when the shot hits the target. + +Implement multiple targets. + +You're now ready for \link tutorial1-14.html Chapter 14.\endlink + +[\link tutorial1-12.html Previous tutorial\endlink] +[\link tutorial1-14.html Next tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ + +/*! \file t14/lcdrange.h */ +/*! \file t14/lcdrange.cpp */ +/*! \file t14/cannon.h */ +/*! \file t14/cannon.cpp */ +/*! \file t14/gamebrd.h */ +/*! \file t14/gamebrd.cpp */ +/*! \file t14/main.cpp */ + +/*! \page tutorial1-14.html + +\title Qt Tutorial - Chapter 14: Facing the Wall + +\img t14.png Screenshot of tutorial fourteen + +This is the final example: a complete game. + +We add keyboard accelerators and introduce mouse events to CannonField. We +put a frame around the CannonField and add a barrier (wall) to make the +game more challenging. + +\list +\i \l t14/lcdrange.h contains the LCDRange +class definition. +\i \l t14/lcdrange.cpp contains the LCDRange +implementation. +\i \l t14/cannon.h contains the CannonField class +definition. +\i \l t14/cannon.cpp contains the CannonField +implementation. +\i \l t14/gamebrd.h contains the GameBoard +class definition. +\i \l t14/gamebrd.cpp contains the GameBoard +implementation. +\i \l t14/main.cpp contains MyWidget and main. +\endlist + +\section1 Line-by-line Walkthrough + +\section2 \l t14/cannon.h + +The CannonField can now receive mouse events to make the user aim the +barrel by clicking on it and dragging. CannonField also has a barrier +wall. + +\quotefile t14/cannon.h + +\skipto CannonField +\skipto protected +\printuntil mouseReleaseEvent + +In addition to the familiar event handlers, CannonField implements +three mouse event handlers. The names say it all. + +\skipto paintBarrier +\printline paintBarrier + +This private function paints the barrier wall. + +\skipto barrierRect +\printline barrierRect + +This private function returns the enclosing rectangle of the barrier. + +\skipto barrelHit +\printline barrelHit + +This private function checks if a point is inside the barrel of the cannon. + +\skipto barrelPressed +\printline barrelPressed + +This private variable is TRUE if the user has pressed the mouse on the +barrel and not released it. + + +\section2 \l t14/cannon.cpp + +\quotefile t14/cannon.cpp + +\skipto ::CannonField +\skipto barrelPressed +\printline barrelPressed + +This line has been added to the constructor. Initially, the mouse is +not pressed on the barrel. + +\skipto ::moveShot +\skipto else +\printuntil { + +Now that we have a barrier, there are three ways to miss. We test for +the third, too. + +\skipto ::mousePressEvent +\printuntil } + +This is a Qt event handler. It is called when the user presses a +mouse button when the mouse cursor is over the widget. + +If the event was not generated by the left mouse button, we return +immediately. Otherwise, we check if the position of the mouse cursor +is within the cannon's barrel. If it is, we set \c barrelPressed to +TRUE. + +Notice that the pos() function returns a point in the widget's +coordinate system. + +\skipto ::mouseMoveEvent +\printuntil setAngle +\printline } + +This is another Qt event handler. It is called when the user already +has pressed the mouse button inside this widget and then moves/drags +the mouse. (You can make Qt send mouse move events even when no +buttons are pressed. See \l QWidget::setMouseTracking().) + +This handler repositions the cannon's barrel according to the position of +the mouse cursor. + +First, if the barrel is not pressed, we return. Next, we fetch the +mouse cursor's position. If the mouse cursor is to the left or below +the widget, we adjust the point to be inside the widget. + +Then we calculate the angle between the bottom edge of the widget and +the imaginary line between the bottom-left corner of the widget and +the cursor position. Finally we set the cannon's angle to the new +value converted to degrees. + +Remember that setAngle() redraws the cannon. + +\skipto ::mouseReleaseEvent +\printuntil } + +This Qt event handler is called whenever the user releases a mouse +button and it was pressed inside this widget. + +If the left button is released, we can be sure that the barrel is no +longer pressed. + +The paint event has two extra lines: + +\skipto ::paintEvent +\skipto barrierRect +\printline barrierRect +\printline paintBarrier + +paintBarrier() does the same sort of thing as paintShot(), +paintTarget(), and paintCannon(). + +\skipto ::paintBarrier +\printuntil } + +This private function paints the barrier as a rectangle filled with +yellow and with a black outline. + +\skipto ::barrierRect +\printuntil } + +This private function returns the rectangle of the barrier. We fix +the bottom edge of the barrier to the bottom edge of the widget. + +\skipto ::barrelHit +\printuntil } + +This function returns TRUE if the point is in the barrel; otherwise it returns +FALSE. + +Here we use the class \l QWMatrix. It is defined in the header file +qwmatrix.h, which is included by qpainter.h. + +QWMatrix defines a coordinate system mapping. It can perform the same +transformations as the QPainter. + +Here we perform the same transformation steps as we do when drawing +the barrel in the paintCannon() function. First we translate the +coordinate system and then we rotate it. + +Now we need to check whether the point \c p (in widget coordinates) lies +inside the barrel. To do this, we invert the transformation matrix. +The inverted matrix performs the inverse transformation that we used +when drawing the barrel. We map the point \c p using the inverted +matrix and return TRUE if it is inside the original barrel rectangle. + + +\section2 \l t14/gamebrd.cpp + +\quotefile t14/gamebrd.cpp + +\skipto qaccel.h +\printline qaccel.h + +We include the class definition of \l QAccel. + +\skipto ::GameBoard +\skipto QVBox +\printline QVBox +\printline setFrameStyle +\printline cannonField + +We create and set up a \l QVBox, set its frame style, and then create +\c CannonField as a child of that box. Because nothing else is in the +box, the effect is that the QVBox will put a frame around the +CannonField. + +\skipto QAccel +\printline accel +\printline connectItem +\printline fire +\printline connectItem +\printline fire + +Here we create and set up an accelerator. An accelerator is an object +that intercepts keyboard events to an application and calls slots if +certain keys are pressed. This mechanism is also called shortcut +keys. Note that an accelerator is a child of a widget and will be +destroyed when that widget is destroyed. QAccel is \e not a widget +and has no visible effect on its parent. + +We define two shortcut keys. We want the slot fire() to be called +when the user presses Enter, and we want the application to quit when +key Ctrl+Q is pressed. Because Enter is sometimes Return and there +are even keyboards with \e both keys, we make both Enter and Return +invoke fire(). + +\printline connectItem +\printline quit + +And then we set up Ctrl+Q to do the same thing as Alt+Q. Some +people are more used to Ctrl+Q (and anyway it shows how do do it). + +CTRL, Key_Enter, Key_Return and Key_Q are all constants provided by +Qt. They're actually Qt::Key_Enter, etc., but practically all classes +inherit the \l Qt namespace class. + +\printline QGridLayout +\printline addWidget +\printline addWidget +\printline setColStretch + +We put \c box (the QVBox), not the CannonField, in the lower-right +cell. + +\section1 Behavior + +The cannon now shoots when you press Enter. You can also position the +cannon's angle using the mouse. The barrier makes it a little more +challenging to play the game. We also have a nice looking frame +around the CannonField. + +(See \link tutorial1-07.html#compiling Compiling\endlink for how to create a +makefile and build the application.) + + +\section1 Exercises + +Write a space invaders game. + +(This exercise was first done by +\link mailto:igorr@ifi.uio.no Igor Rafienko\endlink. You can +\link http://www.stud.ifi.uio.no/~igorr/download.html +download his game\endlink.) + +The new exercise is: Write a Breakout game. + +Final exhortation: Go forth now and create \e {masterpieces of the +programming art!} + +\omit +Cf. Chapter 27 of The TeXbook +\endomit + +[\link tutorial1-13.html Previous tutorial\endlink] +[\link tutorial1-01.html First tutorial\endlink] +[\link tutorial.html Main tutorial page\endlink] + +*/ |