|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the documentation of the Qt Toolkit. |
|
8 ** |
|
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 |
|
14 ** this package. |
|
15 ** |
|
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. |
|
23 ** |
|
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. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /*! |
|
43 \example widgets/calculator |
|
44 \title Calculator Example |
|
45 |
|
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. |
|
49 |
|
50 \image calculator-example.png Screenshot of the Calculator example |
|
51 |
|
52 The example consists of two classes: |
|
53 |
|
54 \list |
|
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. |
|
59 \endlist |
|
60 |
|
61 We will start by reviewing \c Calculator, then we will take a |
|
62 look at \c Button. |
|
63 |
|
64 \section1 Calculator Class Definition |
|
65 |
|
66 \snippet examples/widgets/calculator/calculator.h 0 |
|
67 |
|
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. |
|
72 |
|
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 |
|
80 have their own slots. |
|
81 |
|
82 \snippet examples/widgets/calculator/calculator.h 1 |
|
83 \snippet examples/widgets/calculator/calculator.h 2 |
|
84 |
|
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}}). |
|
90 |
|
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 |
|
97 |
|
98 These variables, together with the contents of the calculator |
|
99 display (a QLineEdit), encode the state of the calculator: |
|
100 |
|
101 \list |
|
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 |
|
110 clicked by the user. |
|
111 \o \c pendingMultiplicativeOperator stores the last multiplicative operator |
|
112 clicked by the user. |
|
113 \o \c waitingForOperand is \c true when the calculator is |
|
114 expecting the user to start typing an operand. |
|
115 \endlist |
|
116 |
|
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{+}. |
|
121 |
|
122 The table below shows the evolution of the calculator state as |
|
123 the user enters a mathematical expression. |
|
124 |
|
125 \table |
|
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 |
|
136 \endtable |
|
137 |
|
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. |
|
141 |
|
142 \snippet examples/widgets/calculator/calculator.h 9 |
|
143 \codeline |
|
144 \snippet examples/widgets/calculator/calculator.h 10 |
|
145 |
|
146 Finally, we declare the variables associated with the display and the |
|
147 buttons used to display numerals. |
|
148 |
|
149 \section1 Calculator Class Implementation |
|
150 |
|
151 \snippet examples/widgets/calculator/calculator.cpp 0 |
|
152 |
|
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. |
|
157 |
|
158 \snippet examples/widgets/calculator/calculator.cpp 1 |
|
159 \snippet examples/widgets/calculator/calculator.cpp 2 |
|
160 |
|
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 |
|
163 read-only. |
|
164 |
|
165 We also enlarge \c{display}'s font by 8 points. |
|
166 |
|
167 \snippet examples/widgets/calculator/calculator.cpp 4 |
|
168 |
|
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. |
|
171 |
|
172 \snippet examples/widgets/calculator/calculator.cpp 5 |
|
173 \snippet examples/widgets/calculator/calculator.cpp 6 |
|
174 |
|
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. |
|
181 |
|
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 |
|
187 span. |
|
188 |
|
189 \snippet examples/widgets/calculator/calculator.cpp 7 |
|
190 |
|
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. |
|
194 |
|
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(). |
|
205 |
|
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. |
|
212 |
|
213 At the end, we append the new digit to the value in the display. |
|
214 |
|
215 \snippet examples/widgets/calculator/calculator.cpp 8 |
|
216 \snippet examples/widgets/calculator/calculator.cpp 9 |
|
217 |
|
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. |
|
223 |
|
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. |
|
231 |
|
232 \snippet examples/widgets/calculator/calculator.cpp 10 |
|
233 \snippet examples/widgets/calculator/calculator.cpp 11 |
|
234 |
|
235 The \c additiveOperatorClicked() slot is called when the user |
|
236 clicks the \gui{+} or \gui{-} button. |
|
237 |
|
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 |
|
241 additive operators: |
|
242 |
|
243 \snippet examples/widgets/calculator/calculator.cpp 12 |
|
244 \snippet examples/widgets/calculator/calculator.cpp 13 |
|
245 |
|
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. |
|
250 |
|
251 \snippet examples/widgets/calculator/calculator.cpp 14 |
|
252 \snippet examples/widgets/calculator/calculator.cpp 15 |
|
253 |
|
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 |
|
258 display. |
|
259 |
|
260 \snippet examples/widgets/calculator/calculator.cpp 16 |
|
261 \snippet examples/widgets/calculator/calculator.cpp 17 |
|
262 |
|
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. |
|
268 |
|
269 \snippet examples/widgets/calculator/calculator.cpp 18 |
|
270 |
|
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. |
|
275 |
|
276 \snippet examples/widgets/calculator/calculator.cpp 20 |
|
277 |
|
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. |
|
282 |
|
283 \snippet examples/widgets/calculator/calculator.cpp 22 |
|
284 |
|
285 The \c pointClicked() slot adds a decimal point to the content in |
|
286 \c display. |
|
287 |
|
288 \snippet examples/widgets/calculator/calculator.cpp 24 |
|
289 |
|
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). |
|
294 |
|
295 \snippet examples/widgets/calculator/calculator.cpp 26 |
|
296 |
|
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. |
|
300 |
|
301 \snippet examples/widgets/calculator/calculator.cpp 28 |
|
302 |
|
303 The \c clear() slot resets the current operand to zero. It is |
|
304 equivalent to clicking \gui Backspace enough times to erase the |
|
305 entire operand. |
|
306 |
|
307 \snippet examples/widgets/calculator/calculator.cpp 30 |
|
308 |
|
309 The \c clearAll() slot resets the calculator to its initial state. |
|
310 |
|
311 \snippet examples/widgets/calculator/calculator.cpp 32 |
|
312 |
|
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 |
|
319 display. |
|
320 |
|
321 \snippet examples/widgets/calculator/calculator.cpp 34 |
|
322 |
|
323 The private \c createButton() function is called from the |
|
324 constructor to create calculator buttons. |
|
325 |
|
326 \snippet examples/widgets/calculator/calculator.cpp 36 |
|
327 |
|
328 The private \c abortOperation() function is called whenever a |
|
329 calculation fails. It resets the calculator state and displays |
|
330 "####". |
|
331 |
|
332 \snippet examples/widgets/calculator/calculator.cpp 38 |
|
333 |
|
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. |
|
339 |
|
340 \section1 Button Class Definition |
|
341 |
|
342 Let's now take a look at the \c Button class: |
|
343 |
|
344 \snippet examples/widgets/calculator/button.h 0 |
|
345 |
|
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 |
|
349 normally provides. |
|
350 |
|
351 \section1 Button Class Implementation |
|
352 |
|
353 \snippet examples/widgets/calculator/button.cpp 0 |
|
354 |
|
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. |
|
364 |
|
365 \snippet examples/widgets/calculator/button.cpp 1 |
|
366 \snippet examples/widgets/calculator/button.cpp 2 |
|
367 |
|
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: |
|
371 |
|
372 \list |
|
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}. |
|
376 \endlist |
|
377 |
|
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. |
|
381 |
|
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(). |
|
386 |
|
387 \image calculator-ugly.png The Calculator example with default size policies and size hints |
|
388 |
|
389 */ |