1
<?xml version="1.0" encoding="iso-8859-1"?>
3
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
4
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
<!-- /tmp/qt-4.0.0-espenr-1119621036935/qt-x11-opensource-desktop-4.0.0/doc/src/examples/calculator.qdoc -->
7
<title>Qt 4.0: Calculator Example</title>
8
<style>h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }
9
a:link { color: #004faf; text-decoration: none }
10
a:visited { color: #672967; text-decoration: none }
11
td.postheader { font-family: sans-serif }
12
tr.address { font-family: sans-serif }
13
body { background: #ffffff; color: black; }</style>
16
<table border="0" cellpadding="0" cellspacing="0" width="100%">
18
<td align="left" valign="top" width="32"><img src="images/qt-logo.png" align="left" width="32" height="32" border="0" /></td>
19
<td width="1"> </td><td class="postheader" valign="center"><a href="index.html"><font color="#004faf">Home</font></a> · <a href="classes.html"><font color="#004faf">All Classes</font></a> · <a href="mainclasses.html"><font color="#004faf">Main Classes</font></a> · <a href="annotated.html"><font color="#004faf">Annotated</font></a> · <a href="groups.html"><font color="#004faf">Grouped Classes</font></a> · <a href="functions.html"><font color="#004faf">Functions</font></a></td>
20
<td align="right" valign="top" width="230"><img src="images/trolltech-logo.png" align="right" width="203" height="32" border="0" /></td></tr></table><h1 align="center">Calculator Example</h1>
23
<li><a href="widgets-calculator-button-cpp.html">widgets/calculator/button.cpp</a></li>
24
<li><a href="widgets-calculator-button-h.html">widgets/calculator/button.h</a></li>
25
<li><a href="widgets-calculator-calculator-cpp.html">widgets/calculator/calculator.cpp</a></li>
26
<li><a href="widgets-calculator-calculator-h.html">widgets/calculator/calculator.h</a></li>
27
<li><a href="widgets-calculator-main-cpp.html">widgets/calculator/main.cpp</a></li>
29
<p>The example shows how to use signals and slots to implement the functionality of a calculator widget, and how to use <a href="qgridlayout.html">QGridLayout</a> to place child widgets in a grid. This example also demonstrates how to use <a href="qobject.html#installEventFilter">event filters</a> to customize a widget's behavior.</p>
30
<center><img src="images/calculator-example.png" alt="Screenshot of the Calculator example" /></center><p>The example consists of two classes:</p>
32
<li><tt>Calculator</tt> is the calculator widget, with all the calculator functionality.</li>
33
<li><tt>Button</tt> is the widget used for each of the calculator button. It derives from <a href="qtoolbutton.html">QToolButton</a>.</li>
35
<p>We will start by reviewing <tt>Calculator</tt>, then we will take a look at <tt>Button</tt>.</p>
36
<a name="calculator-class-definition"></a>
37
<h2>Calculator Class Definition</h2>
38
<pre> class Calculator : public QDialog
43
Calculator(QWidget *parent = 0);
46
bool eventFilter(QObject *target, QEvent *event);
50
void unaryOperatorClicked();
51
void additiveOperatorClicked();
52
void multiplicativeOperatorClicked();
55
void changeSignClicked();
56
void backspaceClicked();
62
void addToMemory();</pre>
63
<p>The <tt>Calculator</tt> class provides a simple calculator widget. It inherits from <a href="qdialog.html">QDialog</a> and has several private slots associated with the calculator's buttons. <a href="qobject.html#eventFilter">QObject::eventFilter</a>() is reimplemented to handle mouse events on the calculator's display.</p>
64
<p>Buttons are grouped in categories according to their behavior. For example, all the digit buttons (labeled <b>0</b> to <b>9</b>) append a digit to the current operand. For these, we connect multiple buttons to the same slot (e.g., <tt>digitClicked()</tt>). The categories are digits, unary operators (<b>Sqrt</b>, <b>x�</b>, <b>1/x</b>), additive operators (<b>+</b>, <b>-</b>), and multiplicative operators (<b>�</b>, <b>�</b>). The other buttons have their own slots.</p>
66
Button *createButton(const QString &text, const QColor &color,
68
void abortOperation();
69
bool calculate(double rightOperand, const QString &pendingOperator);</pre>
70
<p>The private <tt>createButton()</tt> function is used as part of the widget construction. <tt>abortOperation()</tt> is called whenever a division by zero occurs or when a square root operation is applied to a negative number. <tt>calculate()</tt> applies a binary operator (<b>+</b>, <b>-</b>, <b>�</b>, or <b>�</b>).</p>
71
<pre> double sumInMemory;
74
QString pendingAdditiveOperator;
75
QString pendingMultiplicativeOperator;
76
bool waitingForOperand;</pre>
77
<p>These variables, together with the contents of the calculator display (a <a href="qlineedit.html">QLineEdit</a>), encode the state of the calculator:</p>
79
<li><tt>sumInMemory</tt> contains the value stored in the calculator's memory (using <b>MS</b>, <b>M+</b>, or <b>MC</b>).</li>
80
<li><tt>sumSoFar</tt> stores the value accumulated so far. When the user clicks <b>=</b>, <tt>sumSoFar</tt> is recomputed and shown on the display. <b>Clear All</b> resets <tt>sumSoFar</tt> to zero.</li>
81
<li><tt>factorSoFar</tt> stores a temporary value when doing multiplications and divisions.</li>
82
<li><tt>pendingAdditiveOperator</tt> stores the last additive operator clicked by the user.</li>
83
<li><tt>pendingMultiplicativeOperator</tt> stores the last multiplicative operator clicked by the user.</li>
84
<li><tt>waitingForOperand</tt> is <tt>true</tt> when the calculator is expecting the user to start typing an operand.</li>
86
<p>Additive and multiplicative operators are treated differently because they have different precedences. For example, <b>1 + 2 � 3</b> is interpreted as <b>1 + (2 � 3)</b> because <b>�</b> has higher precedence than <b>+</b>.</p>
87
<p>The table below shows the evolution of the calculator state as the user enters a mathematical expression.</p>
88
<table align="center" cellpadding="2" cellspacing="1" border="0">
89
<tr valign="top" bgcolor="#a2c511"><th>User Input</th><th>Display</th><th>Sum so Far</th><th>Add. Op.</th><th>Factor so Far</th><th>Mult. Op.</th><th>Waiting for Operand?</th></tr>
90
<tr valign="top" bgcolor="#f0f0f0"><td></td><td>0</td><td>0</td><td></td><td></td><td></td><td><tt>true</tt></td></tr>
91
<tr valign="top" bgcolor="#e0e0e0"><td><b>1</b></td><td>1</td><td>0</td><td></td><td></td><td></td><td><tt>false</tt></td></tr>
92
<tr valign="top" bgcolor="#f0f0f0"><td><b>1 +</b></td><td>1</td><td>1</td><td><b>+</b></td><td></td><td></td><td><tt>true</tt></td></tr>
93
<tr valign="top" bgcolor="#e0e0e0"><td><b>1 + 2</b></td><td>2</td><td>1</td><td><b>+</b></td><td></td><td></td><td><tt>false</tt></td></tr>
94
<tr valign="top" bgcolor="#f0f0f0"><td><b>1 + 2 �</b></td><td>2</td><td>1</td><td><b>+</b></td><td>2</td><td><b>�</b></td><td><tt>true</tt></td></tr>
95
<tr valign="top" bgcolor="#e0e0e0"><td><b>1 + 2 � 3</b></td><td>3</td><td>1</td><td><b>+</b></td><td>2</td><td><b>�</b></td><td><tt>false</tt></td></tr>
96
<tr valign="top" bgcolor="#f0f0f0"><td><b>1 + 2 � 3 -</b></td><td>1.66667</td><td>1.66667</td><td><b>-</b></td><td></td><td></td><td><tt>true</tt></td></tr>
97
<tr valign="top" bgcolor="#e0e0e0"><td><b>1 + 2 � 3 - 4</b></td><td>4</td><td>1.66667</td><td><b>-</b></td><td></td><td></td><td><tt>false</tt></td></tr>
98
<tr valign="top" bgcolor="#f0f0f0"><td><b>1 + 2 � 3 - 4 =</b></td><td>-2.33333</td><td>0</td><td></td><td></td><td></td><td><tt>true</tt></td></tr>
100
<p>Unary operators, such as <b>Sqrt</b>, require no special handling; they can be applied immediately since the operand is already known when the operator button is clicked.</p>
101
<pre> QLineEdit *display;
103
enum { NumDigitButtons = 10 };
104
Button *digitButtons[NumDigitButtons];
107
Button *changeSignButton;
108
Button *backspaceButton;
110
Button *clearAllButton;
111
Button *clearMemoryButton;
112
Button *readMemoryButton;
113
Button *setMemoryButton;
114
Button *addToMemoryButton;
116
Button *divisionButton;
120
Button *squareRootButton;
122
Button *reciprocalButton;
125
<p>Finally, we declare the variables associated with the child widgets.</p>
126
<a name="calculator-class-implementation"></a>
127
<h2>Calculator Class Implementation</h2>
128
<pre> Calculator::Calculator(QWidget *parent)
134
waitingForOperand = true;</pre>
135
<p>In the constructor, we initialize the calculator's state. The <tt>pendingAdditiveOperator</tt> and <tt>pendingMultiplicativeOperator</tt> variables don't need to be initialized explicitly, because the <a href="qstring.html">QString</a> constructor initializes them to empty strings.</p>
136
<pre> display = new QLineEdit("0");
137
display->setReadOnly(true);
138
display->setAlignment(Qt::AlignRight);
139
display->setMaxLength(15);
140
display->installEventFilter(this);
142
QFont font = display->font();
143
font.setPointSize(font.pointSize() + 8);
144
display->setFont(font);</pre>
145
<p>We create the <a href="qlineedit.html">QLineEdit</a> representing the calculator's display and set up some of its properties. In particular, we set it to be read-only. The <a href="qobject.html#installEventFilter">QObject::installEventFilter</a>() call installs the <tt>Calculator</tt> object (<tt>this</tt>) as an event filter for <tt>display</tt>; we will come back to it later.</p>
146
<p>We also enlarge <tt>display</tt>'s font by 8 points.</p>
147
<pre> QColor digitColor(150, 205, 205);
148
QColor backspaceColor(225, 185, 135);
149
QColor memoryColor(100, 155, 155);
150
QColor operatorColor(155, 175, 195);
152
for (int i = 0; i < NumDigitButtons; ++i) {
153
digitButtons[i] = createButton(QString::number(i), digitColor,
154
SLOT(digitClicked()));
157
pointButton = createButton(tr("."), digitColor, SLOT(pointClicked()));
158
changeSignButton = createButton(tr("�"), digitColor, SLOT(changeSignClicked()));
160
backspaceButton = createButton(tr("Backspace"), backspaceColor,
161
SLOT(backspaceClicked()));
162
clearButton = createButton(tr("Clear"), backspaceColor, SLOT(clear()));
163
clearAllButton = createButton(tr("Clear All"), backspaceColor.light(120),
166
clearMemoryButton = createButton(tr("MC"), memoryColor,
167
SLOT(clearMemory()));
168
readMemoryButton = createButton(tr("MR"), memoryColor, SLOT(readMemory()));
169
setMemoryButton = createButton(tr("MS"), memoryColor, SLOT(setMemory()));
170
addToMemoryButton = createButton(tr("M+"), memoryColor,
171
SLOT(addToMemory()));
173
divisionButton = createButton(tr("�"), operatorColor,
174
SLOT(multiplicativeOperatorClicked()));
175
timesButton = createButton(tr("�"), operatorColor,
176
SLOT(multiplicativeOperatorClicked()));
177
minusButton = createButton(tr("-"), operatorColor,
178
SLOT(additiveOperatorClicked()));
179
plusButton = createButton(tr("+"), operatorColor,
180
SLOT(additiveOperatorClicked()));
182
squareRootButton = createButton(tr("Sqrt"), operatorColor,
183
SLOT(unaryOperatorClicked()));
184
powerButton = createButton(tr("x�"), operatorColor,
185
SLOT(unaryOperatorClicked()));
186
reciprocalButton = createButton(tr("1/x"), operatorColor,
187
SLOT(unaryOperatorClicked()));
188
equalButton = createButton(tr("="), operatorColor.light(120),
189
SLOT(equalClicked()));</pre>
190
<p>We define four colors by specifying the red, green, and blue components on a scale from 0 to 255. Then, for each button, we call the private <tt>createButton()</tt> function with the proper text label, the associated color, and a slot to connect to the button.</p>
191
<p>To make the <b>Clear All</b> and <b>=</b> buttons stand out, we call <a href="qcolor.html#light">QColor::light</a>() with a factor of 120%, making these buttons 20% brighter than their neighbors.</p>
192
<pre> QGridLayout *mainLayout = new QGridLayout;
193
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
195
mainLayout->addWidget(display, 0, 0, 1, 6);
196
mainLayout->addWidget(backspaceButton, 1, 0, 1, 2);
197
mainLayout->addWidget(clearButton, 1, 2, 1, 2);
198
mainLayout->addWidget(clearAllButton, 1, 4, 1, 2);
200
mainLayout->addWidget(clearMemoryButton, 2, 0);
201
mainLayout->addWidget(readMemoryButton, 3, 0);
202
mainLayout->addWidget(setMemoryButton, 4, 0);
203
mainLayout->addWidget(addToMemoryButton, 5, 0);
205
for (int i = 1; i < NumDigitButtons; ++i) {
206
int row = ((9 - i) / 3) + 2;
207
int column = ((i - 1) % 3) + 1;
208
mainLayout->addWidget(digitButtons[i], row, column);
211
mainLayout->addWidget(digitButtons[0], 5, 1);
212
mainLayout->addWidget(pointButton, 5, 2);
213
mainLayout->addWidget(changeSignButton, 5, 3);
215
mainLayout->addWidget(divisionButton, 2, 4);
216
mainLayout->addWidget(timesButton, 3, 4);
217
mainLayout->addWidget(minusButton, 4, 4);
218
mainLayout->addWidget(plusButton, 5, 4);
220
mainLayout->addWidget(squareRootButton, 2, 5);
221
mainLayout->addWidget(powerButton, 3, 5);
222
mainLayout->addWidget(reciprocalButton, 4, 5);
223
mainLayout->addWidget(equalButton, 5, 5);
224
setLayout(mainLayout);
226
setWindowTitle(tr("Calculator"));
228
<p>The layout is handled by a single <a href="qgridlayout.html">QGridLayout</a>. The <a href="qlayout.html#sizeConstraint-prop">QLayout::setSizeConstraint</a>() call ensures that the <tt>Calculator</tt> widget is always shown as its optimal size (its <a href="qwidget.html#sizeHint-prop">size hint</a>), preventing the user from resizing the calculator. The size hint is determined by the size and <a href="qwidget.html#sizePolicy-prop">size policy</a> of the child widgets.</p>
229
<p>Most child widgets occupy only one cell in the grid layout. For these, we only need to pass a row and a column to <a href="qgridlayout.html#addWidget">QGridLayout::addWidget</a>(). The <tt>display</tt>, <tt>backspaceButton</tt>, <tt>clearButton</tt>, and <tt>clearAllButton</tt> widgets occupy more than one column; for these we must also pass a row span and a column span.</p>
230
<pre> void Calculator::digitClicked()
232
Button *clickedButton = qobject_cast<Button *>(sender());
233
int digitValue = clickedButton->text().toInt();
234
if (display->text() == "0" && digitValue == 0.0)
237
if (waitingForOperand) {
239
waitingForOperand = false;
241
display->setText(display->text() + QString::number(digitValue));
243
<p>Pressing one of the calculator's digit buttons will emit the button's <a href="qabstractbutton.html#clicked">clicked()</a> signal, which will trigger the <tt>digitClicked()</tt> slot.</p>
244
<p>First, we find out which button sent the signal using <a href="qobject.html#sender">QObject::sender</a>(). This function returns the sender as a <a href="qobject.html">QObject</a> pointer. Since we know that the sender is a <tt>Button</tt> object, we can safely cast the <a href="qobject.html">QObject</a>. We could have used a C-style cast or a C++ <tt>static_cast<>()</tt>, but as a defensive programming technique we use a <a href="qobject.html#qobject_cast">qobject_cast</a>(). The advantage is that if the object has the wrong type, a null pointer is returned. Crashes due to null pointers are much easier to diagnose than crashes due to unsafe casts. Once we have the button, we extract the operator using <a href="qabstractbutton.html#text-prop">QToolButton::text</a>().</p>
245
<p>The slot needs to consider two situations in particular. If <tt>display</tt> contains "0" and the user clicks the <b>0</b> button, it would be silly to show "00". And if the calculator is in a state where it is waiting for a new operand, the new digit is the first digit of that new operand; in that case, any result of a previous calculation must be cleared first.</p>
246
<p>At the end, we append the new digit to the value in the display.</p>
247
<pre> void Calculator::unaryOperatorClicked()
249
Button *clickedButton = qobject_cast<Button *>(sender());
250
QString clickedOperator = clickedButton->text();
251
double operand = display->text().toDouble();
254
if (clickedOperator == tr("Sqrt")) {
255
if (operand < 0.0) {
259
result = sqrt(operand);
260
} else if (clickedOperator == tr("x�")) {
261
result = pow(operand, 2.0);
262
} else if (clickedOperator == tr("1/x")) {
263
if (operand == 0.0) {
267
result = 1.0 / operand;
269
display->setText(QString::number(result));
270
waitingForOperand = true;
272
<p>The <tt>unaryOperatorClicked()</tt> slot is called whenever one of the unary operator buttons is clicked. Again a pointer to the clicked button is retrieved using <a href="qobject.html#sender">QObject::sender</a>(). The operator is extracted from the button's text and stored in <tt>clickedOperator</tt>. The operand is obtained from <tt>display</tt>.</p>
273
<p>Then we perform the operation. If <b>Sqrt</b> is applied to a negative number or <b>1/x</b> to zero, we call <tt>abortOperation()</tt>. If everything goes well, we display the result of the operation in the line edit and we set <tt>waitingForOperand</tt> to <tt>true</tt>. This ensures that if the user types a new digit, the digit will be considered as a new operand, instead of being appended to the current value.</p>
274
<pre> void Calculator::additiveOperatorClicked()
276
Button *clickedButton = qobject_cast<Button *>(sender());
277
QString clickedOperator = clickedButton->text();
278
double operand = display->text().toDouble();</pre>
279
<p>The <tt>additiveOperatorClicked()</tt> slot is called when the user clicks the <b>+</b> or <b>-</b> button.</p>
280
<p>Before we can actually do something about the clicked operator, we must handle any pending operations. We start with the multiplicative operators, since these have higher precedence than additive operators:</p>
281
<pre> if (!pendingMultiplicativeOperator.isEmpty()) {
282
if (!calculate(operand, pendingMultiplicativeOperator)) {
286
display->setText(QString::number(factorSoFar));
287
operand = factorSoFar;
289
pendingMultiplicativeOperator.clear();
291
<p>If <b>�</b> or <b>�</b> has been clicked earlier, without clicking <b>=</b> afterward, the current value in the display is the right operand of the <b>�</b> or <b>�</b> operator and we can finally perform the operation and update the display.</p>
292
<pre> if (!pendingAdditiveOperator.isEmpty()) {
293
if (!calculate(operand, pendingAdditiveOperator)) {
297
display->setText(QString::number(sumSoFar));
301
<p>If <b>+</b> or <b>-</b> has been clicked earlier, <tt>sumSoFar</tt> is the left operand and the current value in the display is the right operand of the operator. If there is no pending additive operator, <tt>sumSoFar</tt> is simply set to be the text in the display.</p>
302
<pre> pendingAdditiveOperator = clickedOperator;
303
waitingForOperand = true;
305
<p>Finally, we can take care of the operator that was just clicked. Since we don't have the right-hand operand yet, we store the clicked operator in the <tt>pendingAdditiveOperator</tt> variable. We will apply the operation later, when we have a right operand, with <tt>sumSoFar</tt> as the left operand.</p>
306
<pre> void Calculator::multiplicativeOperatorClicked()
308
Button *clickedButton = qobject_cast<Button *>(sender());
309
QString clickedOperator = clickedButton->text();
310
double operand = display->text().toDouble();
312
if (!pendingMultiplicativeOperator.isEmpty()) {
313
if (!calculate(operand, pendingMultiplicativeOperator)) {
317
display->setText(QString::number(factorSoFar));
319
factorSoFar = operand;
322
pendingMultiplicativeOperator = clickedOperator;
323
waitingForOperand = true;
325
<p>The <tt>multiplicativeOperatorClicked()</tt> slot is similar to <tt>additiveOperatorClicked()</tt>. We don't need to worry about pending additive operators here, because multiplicative operators have precedence over additive operators.</p>
326
<pre> void Calculator::equalClicked()
328
double operand = display->text().toDouble();
330
if (!pendingMultiplicativeOperator.isEmpty()) {
331
if (!calculate(operand, pendingMultiplicativeOperator)) {
335
operand = factorSoFar;
337
pendingMultiplicativeOperator.clear();
339
if (!pendingAdditiveOperator.isEmpty()) {
340
if (!calculate(operand, pendingAdditiveOperator)) {
344
pendingAdditiveOperator.clear();
349
display->setText(QString::number(sumSoFar));
351
waitingForOperand = true;
353
<p>Like in <tt>additiveOperatorClicked()</tt>, we start by handing any pending multiplicative and additive operators. Then we display <tt>sumSoFar</tt> and reset the variable to zero. Resetting the variable to zero is necessary to avoid counting the value twice.</p>
354
<pre> void Calculator::pointClicked()
356
if (waitingForOperand)
357
display->setText("0");
358
if (!display->text().contains("."))
359
display->setText(display->text() + tr("."));
360
waitingForOperand = false;
362
<p>The <tt>pointClicked()</tt> slot adds a decimal point to the content in <tt>display</tt>.</p>
363
<pre> void Calculator::changeSignClicked()
365
QString text = display->text();
366
double value = text.toDouble();
368
if (value > 0.0) {
369
text.prepend(tr("-"));
370
} else if (value < 0.0) {
373
display->setText(text);
375
<p>The <tt>changeSignClicked()</tt> slot changes the sign of the value in <tt>display</tt>. If the current value is positive, we prepend a minus sign; if the current value is negative, we remove the first character from the value (the minus sign).</p>
376
<pre> void Calculator::backspaceClicked()
378
if (waitingForOperand)
381
QString text = display->text();
383
if (text.isEmpty()) {
384
text = "0";
385
waitingForOperand = true;
387
display->setText(text);
389
<p>The <tt>backspaceClicked()</tt> removes the rightmost character in the display. If we get an empty string, we show "0" and set <tt>waitingForOperand</tt> to <tt>true</tt>.</p>
390
<pre> void Calculator::clear()
392
if (waitingForOperand)
395
display->setText("0");
396
waitingForOperand = true;
398
<p>The <tt>clear()</tt> slot resets the current operand to zero. It is equivalent to clicking <b>Backspace</b> enough times to erase the entire operand.</p>
399
<pre> void Calculator::clearAll()
403
pendingAdditiveOperator.clear();
404
pendingMultiplicativeOperator.clear();
405
display->setText("0");
406
waitingForOperand = true;
408
<p>The <tt>clearAll()</tt> slot resets the calculator to its initial state.</p>
409
<pre> void Calculator::clearMemory()
414
void Calculator::readMemory()
416
display->setText(QString::number(sumInMemory));
417
waitingForOperand = true;
420
void Calculator::setMemory()
423
sumInMemory = display->text().toDouble();
426
void Calculator::addToMemory()
429
sumInMemory += display->text().toDouble();
431
<p>The <tt>clearMemory()</tt> slot erases the sum kept in memory, <tt>readMemory()</tt> displays the sum as an operand, <tt>setMemory()</tt> replace the sum in memory with the current sum, and <tt>addToMemory()</tt> adds the current value to the value in memory. For <tt>setMemory()</tt> and <tt>addToMemory()</tt>, we start by calling <tt>equalClicked()</tt> to update <tt>sumSoFar</tt> and the value in the display.</p>
432
<pre> Button *Calculator::createButton(const QString &text, const QColor &color,
435
Button *button = new Button(text, color);
436
connect(button, SIGNAL(clicked()), this, member);
439
<p>The private <tt>createButton()</tt> function is called from the constructor to create calculator buttons.</p>
440
<pre> void Calculator::abortOperation()
443
display->setText(tr("####"));
445
<p>The private <tt>abortOperation()</tt> function is called whenever a calculation fails. It resets the calculator state and displays "####".</p>
446
<pre> bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
448
if (pendingOperator == tr("+")) {
449
sumSoFar += rightOperand;
450
} else if (pendingOperator == tr("-")) {
451
sumSoFar -= rightOperand;
452
} else if (pendingOperator == tr("�")) {
453
factorSoFar *= rightOperand;
454
} else if (pendingOperator == tr("�")) {
455
if (rightOperand == 0.0)
457
factorSoFar /= rightOperand;
461
<p>The private <tt>calculate()</tt> function performs a binary operation. The right operand is given by <tt>rightOperand</tt>. For additive operators, the left operand is <tt>sumSoFar</tt>; for multiplicative operators, the left operand is <tt>factorSoFar</tt>. The function return <tt>false</tt> if a division by zero occurs.</p>
462
<pre> bool Calculator::eventFilter(QObject *target, QEvent *event)
464
if (target == display) {
465
if (event->type() == QEvent::MouseButtonPress
466
|| event->type() == QEvent::MouseButtonDblClick
467
|| event->type() == QEvent::MouseButtonRelease
468
|| event->type() == QEvent::ContextMenu) {
469
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
470
if (mouseEvent->buttons() & Qt::LeftButton) {
471
QPalette newPalette = palette();
472
newPalette.setColor(QPalette::Base,
473
display->palette().color(QPalette::Text));
474
newPalette.setColor(QPalette::Text,
475
display->palette().color(QPalette::Base));
476
display->setPalette(newPalette);
478
display->setPalette(palette());
483
return QDialog::eventFilter(target, event);
485
<p>The <tt>eventFilter()</tt> function is inherited from <a href="qobject.html">QObject</a>. In the constructor, we installed it on <tt>display</tt>. While the user holds the left mouse button pressed, we use an inverted color scheme. Any other events are ignored and simply passed on to the base class's <a href="qobject.html#eventFilter">eventFilter()</a> implementation.</p>
486
<a name="button-class-definition"></a>
487
<h2>Button Class Definition</h2>
488
<p>Let's now take a look at the <tt>Button</tt> class:</p>
489
<pre> class Button : public QToolButton
494
Button(const QString &text, const QColor &color, QWidget *parent = 0);
496
QSize sizeHint() const;
498
<p>The <tt>Button</tt> class has a convenience constructor that takes a text label and a color, and it reimplements <a href="qwidget.html#sizeHint-prop">QWidget::sizeHint</a>() to provide more space around the text than what <a href="qtoolbutton.html">QToolButton</a> normally provides.</p>
499
<a name="button-class-implementation"></a>
500
<h2>Button Class Implementation</h2>
501
<pre> Button::Button(const QString &text, const QColor &color, QWidget *parent)
502
: QToolButton(parent)
504
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
507
QPalette newPalette = palette();
508
newPalette.setColor(QPalette::Button, color);
509
setPalette(newPalette);
511
<p>The buttons' appearance is determined by the layout of the calculator widget through the size and <a href="qwidget.html#sizePolicy-prop">size policy</a> of the layout's child widgets. The call to the <a href="qwidget.html#sizePolicy-prop">setSizePolicy()</a> function in the constructor ensures that the button will expand horizontally to fill all the available space; by default, <a href="qtoolbutton.html">QToolButton</a>s don't expand to fill available space. Without this call, the different buttons in a same column would have different widths.</p>
512
<pre> QSize Button::sizeHint() const
514
QSize size = QToolButton::sizeHint();
515
size.rheight() += 20;
516
size.rwidth() = qMax(size.width(), size.height());
519
<p>In <a href="qwidget.html#sizeHint-prop">sizeHint()</a>, we try to return a size that looks good for most buttons. We reuse the size hint of the base class (<a href="qtoolbutton.html">QToolButton</a>) but modify it in the following ways:</p>
521
<li>We add 20 to the <a href="qsize.html#height">height</a> component of the size hint.</li>
522
<li>We make the <a href="qsize.html#width">width</a> component of the size hint at least as much as the <a href="qsize.html#width">height</a>.</li>
524
<p>This ensures that with most fonts, the digit and operator buttons will be square, without truncating the text on the <b>Backspace</b>, <b>Clear</b>, and <b>Clear All</b> buttons.</p>
525
<p>The screenshot below shows how the <tt>Calculator</tt> widget would would like if we <i>didn't</i> set the horizontal size policy to <a href="qsizepolicy.html#Policy-enum">QSizePolicy::Expanding</a> in the constructor and if we didn't reimplement <a href="qwidget.html#sizeHint-prop">QWidget::sizeHint</a>().</p>
526
<center><img src="images/calculator-ugly.png" alt="The Calculator example with default size policies and size hints" /></center><p>This completes the Calculator example. Trolltech will send a T-shirt to the first finder of a bug in the example.</p>
527
<p /><address><hr /><div align="center">
528
<table width="100%" cellspacing="0" border="0"><tr class="address">
529
<td width="30%">Copyright © 2005 <a href="trolltech.html">Trolltech</a></td>
530
<td width="40%" align="center"><a href="trademarks.html">Trademarks</a></td>
531
<td width="30%" align="right"><div align="right">Qt 4.0.0</div></td>
532
</tr></table></div></address></body>