/**************************************************************************** ** ** 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-ntqt.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. Note: 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 ntqfont.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 ntqvbox.h \printline ntqvbox.h We add an include of ntqvbox.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. ntqslider.h and ntqlcdnumber.h are there because we use two new widgets, QSlider and QLCDNumber. ntqvbox.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 ntqvbox.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 ntqwidget.h be included indirectly via other header files such as \c ntqpushbutton.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 somethingChanged(). \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 ntqglobal.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 ntqlayout.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 ntqwmatrix.h, which is included by ntqpainter.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 ntqaccel.h \printline ntqaccel.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] */