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