0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 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 |
*/
|