1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the documentation of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 \example widgets/calculator
44 \title Calculator Example
46 The example shows how to use signals and slots to implement the
47 functionality of a calculator widget, and how to use QGridLayout
48 to place child widgets in a grid.
50 \image calculator-example.png Screenshot of the Calculator example
52 The example consists of two classes:
55 \o \c Calculator is the calculator widget, with all the
56 calculator functionality.
57 \o \c Button is the widget used for each of the calculator
58 button. It derives from QToolButton.
61 We will start by reviewing \c Calculator, then we will take a
64 \section1 Calculator Class Definition
66 \snippet examples/widgets/calculator/calculator.h 0
68 The \c Calculator class provides a simple calculator widget. It
69 inherits from QDialog and has several private slots associated
70 with the calculator's buttons. QObject::eventFilter() is
71 reimplemented to handle mouse events on the calculator's display.
73 Buttons are grouped in categories according to their behavior.
74 For example, all the digit buttons (labeled \gui 0 to \gui 9)
75 append a digit to the current operand. For these, we connect
76 multiple buttons to the same slot (e.g., \c digitClicked()). The
77 categories are digits, unary operators (\gui{Sqrt}, \gui{x\unicode{178}},
78 \gui{1/x}), additive operators (\gui{+}, \gui{-}), and
79 multiplicative operators (\gui{\unicode{215}}, \gui{\unicode{247}}). The other buttons
82 \snippet examples/widgets/calculator/calculator.h 1
83 \snippet examples/widgets/calculator/calculator.h 2
85 The private \c createButton() function is used as part of the
86 widget construction. \c abortOperation() is called whenever a
87 division by zero occurs or when a square root operation is
88 applied to a negative number. \c calculate() applies a binary
89 operator (\gui{+}, \gui{-}, \gui{\unicode{215}}, or \gui{\unicode{247}}).
91 \snippet examples/widgets/calculator/calculator.h 3
92 \snippet examples/widgets/calculator/calculator.h 4
93 \snippet examples/widgets/calculator/calculator.h 5
94 \snippet examples/widgets/calculator/calculator.h 6
95 \snippet examples/widgets/calculator/calculator.h 7
96 \snippet examples/widgets/calculator/calculator.h 8
98 These variables, together with the contents of the calculator
99 display (a QLineEdit), encode the state of the calculator:
102 \o \c sumInMemory contains the value stored in the calculator's memory
103 (using \gui{MS}, \gui{M+}, or \gui{MC}).
104 \o \c sumSoFar stores the value accumulated so far. When the user
105 clicks \gui{=}, \c sumSoFar is recomputed and shown on the
106 display. \gui{Clear All} resets \c sumSoFar to zero.
107 \o \c factorSoFar stores a temporary value when doing
108 multiplications and divisions.
109 \o \c pendingAdditiveOperator stores the last additive operator
111 \o \c pendingMultiplicativeOperator stores the last multiplicative operator
113 \o \c waitingForOperand is \c true when the calculator is
114 expecting the user to start typing an operand.
117 Additive and multiplicative operators are treated differently
118 because they have different precedences. For example, \gui{1 + 2 \unicode{247}
119 3} is interpreted as \gui{1 + (2 \unicode{247} 3)} because \gui{\unicode{247}} has higher
120 precedence than \gui{+}.
122 The table below shows the evolution of the calculator state as
123 the user enters a mathematical expression.
126 \header \o User Input \o Display \o Sum so Far \o Add. Op. \o Factor so Far \o Mult. Op. \o Waiting for Operand?
127 \row \o \o 0 \o 0 \o \o \o \o \c true
128 \row \o \gui{1} \o 1 \o 0 \o \o \o \o \c false
129 \row \o \gui{1 +} \o 1 \o 1 \o \gui{+} \o \o \o \c true
130 \row \o \gui{1 + 2} \o 2 \o 1 \o \gui{+} \o \o \o \c false
131 \row \o \gui{1 + 2 \unicode{247}} \o 2 \o 1 \o \gui{+} \o 2 \o \gui{\unicode{247}} \o \c true
132 \row \o \gui{1 + 2 \unicode{247} 3} \o 3 \o 1 \o \gui{+} \o 2 \o \gui{\unicode{247}} \o \c false
133 \row \o \gui{1 + 2 \unicode{247} 3 -} \o 1.66667 \o 1.66667 \o \gui{-} \o \o \o \c true
134 \row \o \gui{1 + 2 \unicode{247} 3 - 4} \o 4 \o 1.66667 \o \gui{-} \o \o \o \c false
135 \row \o \gui{1 + 2 \unicode{247} 3 - 4 =} \o -2.33333 \o 0 \o \o \o \o \c true
138 Unary operators, such as \gui Sqrt, require no special handling;
139 they can be applied immediately since the operand is already
140 known when the operator button is clicked.
142 \snippet examples/widgets/calculator/calculator.h 9
144 \snippet examples/widgets/calculator/calculator.h 10
146 Finally, we declare the variables associated with the display and the
147 buttons used to display numerals.
149 \section1 Calculator Class Implementation
151 \snippet examples/widgets/calculator/calculator.cpp 0
153 In the constructor, we initialize the calculator's state. The \c
154 pendingAdditiveOperator and \c pendingMultiplicativeOperator
155 variables don't need to be initialized explicitly, because the
156 QString constructor initializes them to empty strings.
158 \snippet examples/widgets/calculator/calculator.cpp 1
159 \snippet examples/widgets/calculator/calculator.cpp 2
161 We create the QLineEdit representing the calculator's display and
162 set up some of its properties. In particular, we set it to be
165 We also enlarge \c{display}'s font by 8 points.
167 \snippet examples/widgets/calculator/calculator.cpp 4
169 For each button, we call the private \c createButton() function with
170 the proper text label and a slot to connect to the button.
172 \snippet examples/widgets/calculator/calculator.cpp 5
173 \snippet examples/widgets/calculator/calculator.cpp 6
175 The layout is handled by a single QGridLayout. The
176 QLayout::setSizeConstraint() call ensures that the \c Calculator
177 widget is always shown as its optimal size (its
178 \l{QWidget::sizeHint()}{size hint}), preventing the user from
179 resizing the calculator. The size hint is determined by the size
180 and \l{QWidget::sizePolicy()}{size policy} of the child widgets.
182 Most child widgets occupy only one cell in the grid layout. For
183 these, we only need to pass a row and a column to
184 QGridLayout::addWidget(). The \c display, \c backspaceButton, \c
185 clearButton, and \c clearAllButton widgets occupy more than one
186 column; for these we must also pass a row span and a column
189 \snippet examples/widgets/calculator/calculator.cpp 7
191 Pressing one of the calculator's digit buttons will emit the
192 button's \l{QToolButton::clicked()}{clicked()} signal, which will
193 trigger the \c digitClicked() slot.
195 First, we find out which button sent the signal using
196 QObject::sender(). This function returns the sender as a QObject
197 pointer. Since we know that the sender is a \c Button object, we
198 can safely cast the QObject. We could have used a C-style cast or
199 a C++ \c static_cast<>(), but as a defensive programming
200 technique we use a \l qobject_cast(). The advantage is that if
201 the object has the wrong type, a null pointer is returned.
202 Crashes due to null pointers are much easier to diagnose than
203 crashes due to unsafe casts. Once we have the button, we extract
204 the operator using QToolButton::text().
206 The slot needs to consider two situations in particular. If \c
207 display contains "0" and the user clicks the \gui{0} button, it
208 would be silly to show "00". And if the calculator is in
209 a state where it is waiting for a new operand,
210 the new digit is the first digit of that new operand; in that case,
211 any result of a previous calculation must be cleared first.
213 At the end, we append the new digit to the value in the display.
215 \snippet examples/widgets/calculator/calculator.cpp 8
216 \snippet examples/widgets/calculator/calculator.cpp 9
218 The \c unaryOperatorClicked() slot is called whenever one of the
219 unary operator buttons is clicked. Again a pointer to the clicked
220 button is retrieved using QObject::sender(). The operator is
221 extracted from the button's text and stored in \c
222 clickedOperator. The operand is obtained from \c display.
224 Then we perform the operation. If \gui Sqrt is applied to a
225 negative number or \gui{1/x} to zero, we call \c
226 abortOperation(). If everything goes well, we display the result
227 of the operation in the line edit and we set \c waitingForOperand
228 to \c true. This ensures that if the user types a new digit, the
229 digit will be considered as a new operand, instead of being
230 appended to the current value.
232 \snippet examples/widgets/calculator/calculator.cpp 10
233 \snippet examples/widgets/calculator/calculator.cpp 11
235 The \c additiveOperatorClicked() slot is called when the user
236 clicks the \gui{+} or \gui{-} button.
238 Before we can actually do something about the clicked operator,
239 we must handle any pending operations. We start with the
240 multiplicative operators, since these have higher precedence than
243 \snippet examples/widgets/calculator/calculator.cpp 12
244 \snippet examples/widgets/calculator/calculator.cpp 13
246 If \gui{\unicode{215}} or \gui{\unicode{247}} has been clicked earlier, without clicking
247 \gui{=} afterward, the current value in the display is the right
248 operand of the \gui{\unicode{215}} or \gui{\unicode{247}} operator and we can finally
249 perform the operation and update the display.
251 \snippet examples/widgets/calculator/calculator.cpp 14
252 \snippet examples/widgets/calculator/calculator.cpp 15
254 If \gui{+} or \gui{-} has been clicked earlier, \c sumSoFar is
255 the left operand and the current value in the display is the
256 right operand of the operator. If there is no pending additive
257 operator, \c sumSoFar is simply set to be the text in the
260 \snippet examples/widgets/calculator/calculator.cpp 16
261 \snippet examples/widgets/calculator/calculator.cpp 17
263 Finally, we can take care of the operator that was just clicked.
264 Since we don't have the right-hand operand yet, we store the clicked
265 operator in the \c pendingAdditiveOperator variable. We will
266 apply the operation later, when we have a right operand, with \c
267 sumSoFar as the left operand.
269 \snippet examples/widgets/calculator/calculator.cpp 18
271 The \c multiplicativeOperatorClicked() slot is similar to \c
272 additiveOperatorClicked(). We don't need to worry about pending
273 additive operators here, because multiplicative operators have
274 precedence over additive operators.
276 \snippet examples/widgets/calculator/calculator.cpp 20
278 Like in \c additiveOperatorClicked(), we start by handing any
279 pending multiplicative and additive operators. Then we display \c
280 sumSoFar and reset the variable to zero. Resetting the variable
281 to zero is necessary to avoid counting the value twice.
283 \snippet examples/widgets/calculator/calculator.cpp 22
285 The \c pointClicked() slot adds a decimal point to the content in
288 \snippet examples/widgets/calculator/calculator.cpp 24
290 The \c changeSignClicked() slot changes the sign of the value in
291 \c display. If the current value is positive, we prepend a minus
292 sign; if the current value is negative, we remove the first
293 character from the value (the minus sign).
295 \snippet examples/widgets/calculator/calculator.cpp 26
297 The \c backspaceClicked() removes the rightmost character in the
298 display. If we get an empty string, we show "0" and set \c
299 waitingForOperand to \c true.
301 \snippet examples/widgets/calculator/calculator.cpp 28
303 The \c clear() slot resets the current operand to zero. It is
304 equivalent to clicking \gui Backspace enough times to erase the
307 \snippet examples/widgets/calculator/calculator.cpp 30
309 The \c clearAll() slot resets the calculator to its initial state.
311 \snippet examples/widgets/calculator/calculator.cpp 32
313 The \c clearMemory() slot erases the sum kept in memory, \c
314 readMemory() displays the sum as an operand, \c setMemory()
315 replace the sum in memory with the current sum, and \c
316 addToMemory() adds the current value to the value in memory. For
317 \c setMemory() and \c addToMemory(), we start by calling \c
318 equalClicked() to update \c sumSoFar and the value in the
321 \snippet examples/widgets/calculator/calculator.cpp 34
323 The private \c createButton() function is called from the
324 constructor to create calculator buttons.
326 \snippet examples/widgets/calculator/calculator.cpp 36
328 The private \c abortOperation() function is called whenever a
329 calculation fails. It resets the calculator state and displays
332 \snippet examples/widgets/calculator/calculator.cpp 38
334 The private \c calculate() function performs a binary operation.
335 The right operand is given by \c rightOperand. For additive
336 operators, the left operand is \c sumSoFar; for multiplicative
337 operators, the left operand is \c factorSoFar. The function
338 return \c false if a division by zero occurs.
340 \section1 Button Class Definition
342 Let's now take a look at the \c Button class:
344 \snippet examples/widgets/calculator/button.h 0
346 The \c Button class has a convenience constructor that takes a
347 text label and a parent widget, and it reimplements QWidget::sizeHint()
348 to provide more space around the text than the amount QToolButton
351 \section1 Button Class Implementation
353 \snippet examples/widgets/calculator/button.cpp 0
355 The buttons' appearance is determined by the layout of the
356 calculator widget through the size and
357 \l{QWidget::sizePolicy}{size policy} of the layout's child
358 widgets. The call to the
359 \l{QWidget::setSizePolicy()}{setSizePolicy()} function in the
360 constructor ensures that the button will expand horizontally to
361 fill all the available space; by default, \l{QToolButton}s don't
362 expand to fill available space. Without this call, the different
363 buttons in a same column would have different widths.
365 \snippet examples/widgets/calculator/button.cpp 1
366 \snippet examples/widgets/calculator/button.cpp 2
368 In \l{QWidget::sizeHint()}{sizeHint()}, we try to return a size
369 that looks good for most buttons. We reuse the size hint of the
370 base class (QToolButton) but modify it in the following ways:
373 \o We add 20 to the \l{QSize::height()}{height} component of the size hint.
374 \o We make the \l{QSize::width()}{width} component of the size
375 hint at least as much as the \l{QSize::width()}{height}.
378 This ensures that with most fonts, the digit and operator buttons
379 will be square, without truncating the text on the
380 \gui{Backspace}, \gui{Clear}, and \gui{Clear All} buttons.
382 The screenshot below shows how the \c Calculator widget would
383 look like if we \e didn't set the horizontal size policy to
384 QSizePolicy::Expanding in the constructor and if we didn't
385 reimplement QWidget::sizeHint().
387 \image calculator-ugly.png The Calculator example with default size policies and size hints