diff options
Diffstat (limited to 'doc/src/examples/calculator.qdoc')
-rw-r--r-- | doc/src/examples/calculator.qdoc | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/doc/src/examples/calculator.qdoc b/doc/src/examples/calculator.qdoc new file mode 100644 index 0000000..2cae6ce --- /dev/null +++ b/doc/src/examples/calculator.qdoc @@ -0,0 +1,389 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example widgets/calculator + \title Calculator Example + + The example shows how to use signals and slots to implement the + functionality of a calculator widget, and how to use QGridLayout + to place child widgets in a grid. + + \image calculator-example.png Screenshot of the Calculator example + + The example consists of two classes: + + \list + \o \c Calculator is the calculator widget, with all the + calculator functionality. + \o \c Button is the widget used for each of the calculator + button. It derives from QToolButton. + \endlist + + We will start by reviewing \c Calculator, then we will take a + look at \c Button. + + \section1 Calculator Class Definition + + \snippet examples/widgets/calculator/calculator.h 0 + + The \c Calculator class provides a simple calculator widget. It + inherits from QDialog and has several private slots associated + with the calculator's buttons. QObject::eventFilter() is + reimplemented to handle mouse events on the calculator's display. + + Buttons are grouped in categories according to their behavior. + For example, all the digit buttons (labeled \gui 0 to \gui 9) + append a digit to the current operand. For these, we connect + multiple buttons to the same slot (e.g., \c digitClicked()). The + categories are digits, unary operators (\gui{Sqrt}, \gui{x\unicode{178}}, + \gui{1/x}), additive operators (\gui{+}, \gui{-}), and + multiplicative operators (\gui{\unicode{215}}, \gui{\unicode{247}}). The other buttons + have their own slots. + + \snippet examples/widgets/calculator/calculator.h 1 + \snippet examples/widgets/calculator/calculator.h 2 + + The private \c createButton() function is used as part of the + widget construction. \c abortOperation() is called whenever a + division by zero occurs or when a square root operation is + applied to a negative number. \c calculate() applies a binary + operator (\gui{+}, \gui{-}, \gui{\unicode{215}}, or \gui{\unicode{247}}). + + \snippet examples/widgets/calculator/calculator.h 3 + \snippet examples/widgets/calculator/calculator.h 4 + \snippet examples/widgets/calculator/calculator.h 5 + \snippet examples/widgets/calculator/calculator.h 6 + \snippet examples/widgets/calculator/calculator.h 7 + \snippet examples/widgets/calculator/calculator.h 8 + + These variables, together with the contents of the calculator + display (a QLineEdit), encode the state of the calculator: + + \list + \o \c sumInMemory contains the value stored in the calculator's memory + (using \gui{MS}, \gui{M+}, or \gui{MC}). + \o \c sumSoFar stores the value accumulated so far. When the user + clicks \gui{=}, \c sumSoFar is recomputed and shown on the + display. \gui{Clear All} resets \c sumSoFar to zero. + \o \c factorSoFar stores a temporary value when doing + multiplications and divisions. + \o \c pendingAdditiveOperator stores the last additive operator + clicked by the user. + \o \c pendingMultiplicativeOperator stores the last multiplicative operator + clicked by the user. + \o \c waitingForOperand is \c true when the calculator is + expecting the user to start typing an operand. + \endlist + + Additive and multiplicative operators are treated differently + because they have different precedences. For example, \gui{1 + 2 \unicode{247} + 3} is interpreted as \gui{1 + (2 \unicode{247} 3)} because \gui{\unicode{247}} has higher + precedence than \gui{+}. + + The table below shows the evolution of the calculator state as + the user enters a mathematical expression. + + \table + \header \o User Input \o Display \o Sum so Far \o Add. Op. \o Factor so Far \o Mult. Op. \o Waiting for Operand? + \row \o \o 0 \o 0 \o \o \o \o \c true + \row \o \gui{1} \o 1 \o 0 \o \o \o \o \c false + \row \o \gui{1 +} \o 1 \o 1 \o \gui{+} \o \o \o \c true + \row \o \gui{1 + 2} \o 2 \o 1 \o \gui{+} \o \o \o \c false + \row \o \gui{1 + 2 \unicode{247}} \o 2 \o 1 \o \gui{+} \o 2 \o \gui{\unicode{247}} \o \c true + \row \o \gui{1 + 2 \unicode{247} 3} \o 3 \o 1 \o \gui{+} \o 2 \o \gui{\unicode{247}} \o \c false + \row \o \gui{1 + 2 \unicode{247} 3 -} \o 1.66667 \o 1.66667 \o \gui{-} \o \o \o \c true + \row \o \gui{1 + 2 \unicode{247} 3 - 4} \o 4 \o 1.66667 \o \gui{-} \o \o \o \c false + \row \o \gui{1 + 2 \unicode{247} 3 - 4 =} \o -2.33333 \o 0 \o \o \o \o \c true + \endtable + + Unary operators, such as \gui Sqrt, require no special handling; + they can be applied immediately since the operand is already + known when the operator button is clicked. + + \snippet examples/widgets/calculator/calculator.h 9 + \codeline + \snippet examples/widgets/calculator/calculator.h 10 + + Finally, we declare the variables associated with the display and the + buttons used to display numerals. + + \section1 Calculator Class Implementation + + \snippet examples/widgets/calculator/calculator.cpp 0 + + In the constructor, we initialize the calculator's state. The \c + pendingAdditiveOperator and \c pendingMultiplicativeOperator + variables don't need to be initialized explicitly, because the + QString constructor initializes them to empty strings. + + \snippet examples/widgets/calculator/calculator.cpp 1 + \snippet examples/widgets/calculator/calculator.cpp 2 + + We create the QLineEdit representing the calculator's display and + set up some of its properties. In particular, we set it to be + read-only. + + We also enlarge \c{display}'s font by 8 points. + + \snippet examples/widgets/calculator/calculator.cpp 4 + + For each button, we call the private \c createButton() function with + the proper text label and a slot to connect to the button. + + \snippet examples/widgets/calculator/calculator.cpp 5 + \snippet examples/widgets/calculator/calculator.cpp 6 + + The layout is handled by a single QGridLayout. The + QLayout::setSizeConstraint() call ensures that the \c Calculator + widget is always shown as its optimal size (its + \l{QWidget::sizeHint()}{size hint}), preventing the user from + resizing the calculator. The size hint is determined by the size + and \l{QWidget::sizePolicy()}{size policy} of the child widgets. + + Most child widgets occupy only one cell in the grid layout. For + these, we only need to pass a row and a column to + QGridLayout::addWidget(). The \c display, \c backspaceButton, \c + clearButton, and \c clearAllButton widgets occupy more than one + column; for these we must also pass a row span and a column + span. + + \snippet examples/widgets/calculator/calculator.cpp 7 + + Pressing one of the calculator's digit buttons will emit the + button's \l{QToolButton::clicked()}{clicked()} signal, which will + trigger the \c digitClicked() slot. + + First, we find out which button sent the signal using + QObject::sender(). This function returns the sender as a QObject + pointer. Since we know that the sender is a \c Button object, we + can safely cast the QObject. We could have used a C-style cast or + a C++ \c static_cast<>(), but as a defensive programming + technique we use a \l qobject_cast(). 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 QToolButton::text(). + + The slot needs to consider two situations in particular. If \c + display contains "0" and the user clicks the \gui{0} 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. + + At the end, we append the new digit to the value in the display. + + \snippet examples/widgets/calculator/calculator.cpp 8 + \snippet examples/widgets/calculator/calculator.cpp 9 + + The \c unaryOperatorClicked() slot is called whenever one of the + unary operator buttons is clicked. Again a pointer to the clicked + button is retrieved using QObject::sender(). The operator is + extracted from the button's text and stored in \c + clickedOperator. The operand is obtained from \c display. + + Then we perform the operation. If \gui Sqrt is applied to a + negative number or \gui{1/x} to zero, we call \c + abortOperation(). If everything goes well, we display the result + of the operation in the line edit and we set \c waitingForOperand + to \c true. 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. + + \snippet examples/widgets/calculator/calculator.cpp 10 + \snippet examples/widgets/calculator/calculator.cpp 11 + + The \c additiveOperatorClicked() slot is called when the user + clicks the \gui{+} or \gui{-} button. + + 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: + + \snippet examples/widgets/calculator/calculator.cpp 12 + \snippet examples/widgets/calculator/calculator.cpp 13 + + If \gui{\unicode{215}} or \gui{\unicode{247}} has been clicked earlier, without clicking + \gui{=} afterward, the current value in the display is the right + operand of the \gui{\unicode{215}} or \gui{\unicode{247}} operator and we can finally + perform the operation and update the display. + + \snippet examples/widgets/calculator/calculator.cpp 14 + \snippet examples/widgets/calculator/calculator.cpp 15 + + If \gui{+} or \gui{-} has been clicked earlier, \c sumSoFar 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, \c sumSoFar is simply set to be the text in the + display. + + \snippet examples/widgets/calculator/calculator.cpp 16 + \snippet examples/widgets/calculator/calculator.cpp 17 + + 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 \c pendingAdditiveOperator variable. We will + apply the operation later, when we have a right operand, with \c + sumSoFar as the left operand. + + \snippet examples/widgets/calculator/calculator.cpp 18 + + The \c multiplicativeOperatorClicked() slot is similar to \c + additiveOperatorClicked(). We don't need to worry about pending + additive operators here, because multiplicative operators have + precedence over additive operators. + + \snippet examples/widgets/calculator/calculator.cpp 20 + + Like in \c additiveOperatorClicked(), we start by handing any + pending multiplicative and additive operators. Then we display \c + sumSoFar and reset the variable to zero. Resetting the variable + to zero is necessary to avoid counting the value twice. + + \snippet examples/widgets/calculator/calculator.cpp 22 + + The \c pointClicked() slot adds a decimal point to the content in + \c display. + + \snippet examples/widgets/calculator/calculator.cpp 24 + + The \c changeSignClicked() slot changes the sign of the value in + \c display. 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). + + \snippet examples/widgets/calculator/calculator.cpp 26 + + The \c backspaceClicked() removes the rightmost character in the + display. If we get an empty string, we show "0" and set \c + waitingForOperand to \c true. + + \snippet examples/widgets/calculator/calculator.cpp 28 + + The \c clear() slot resets the current operand to zero. It is + equivalent to clicking \gui Backspace enough times to erase the + entire operand. + + \snippet examples/widgets/calculator/calculator.cpp 30 + + The \c clearAll() slot resets the calculator to its initial state. + + \snippet examples/widgets/calculator/calculator.cpp 32 + + The \c clearMemory() slot erases the sum kept in memory, \c + readMemory() displays the sum as an operand, \c setMemory() + replace the sum in memory with the current sum, and \c + addToMemory() adds the current value to the value in memory. For + \c setMemory() and \c addToMemory(), we start by calling \c + equalClicked() to update \c sumSoFar and the value in the + display. + + \snippet examples/widgets/calculator/calculator.cpp 34 + + The private \c createButton() function is called from the + constructor to create calculator buttons. + + \snippet examples/widgets/calculator/calculator.cpp 36 + + The private \c abortOperation() function is called whenever a + calculation fails. It resets the calculator state and displays + "####". + + \snippet examples/widgets/calculator/calculator.cpp 38 + + The private \c calculate() function performs a binary operation. + The right operand is given by \c rightOperand. For additive + operators, the left operand is \c sumSoFar; for multiplicative + operators, the left operand is \c factorSoFar. The function + return \c false if a division by zero occurs. + + \section1 Button Class Definition + + Let's now take a look at the \c Button class: + + \snippet examples/widgets/calculator/button.h 0 + + The \c Button class has a convenience constructor that takes a + text label and a parent widget, and it reimplements QWidget::sizeHint() + to provide more space around the text than the amount QToolButton + normally provides. + + \section1 Button Class Implementation + + \snippet examples/widgets/calculator/button.cpp 0 + + The buttons' appearance is determined by the layout of the + calculator widget through the size and + \l{QWidget::sizePolicy}{size policy} of the layout's child + widgets. The call to the + \l{QWidget::setSizePolicy()}{setSizePolicy()} function in the + constructor ensures that the button will expand horizontally to + fill all the available space; by default, \l{QToolButton}s don't + expand to fill available space. Without this call, the different + buttons in a same column would have different widths. + + \snippet examples/widgets/calculator/button.cpp 1 + \snippet examples/widgets/calculator/button.cpp 2 + + In \l{QWidget::sizeHint()}{sizeHint()}, we try to return a size + that looks good for most buttons. We reuse the size hint of the + base class (QToolButton) but modify it in the following ways: + + \list + \o We add 20 to the \l{QSize::height()}{height} component of the size hint. + \o We make the \l{QSize::width()}{width} component of the size + hint at least as much as the \l{QSize::width()}{height}. + \endlist + + This ensures that with most fonts, the digit and operator buttons + will be square, without truncating the text on the + \gui{Backspace}, \gui{Clear}, and \gui{Clear All} buttons. + + The screenshot below shows how the \c Calculator widget would + look like if we \e didn't set the horizontal size policy to + QSizePolicy::Expanding in the constructor and if we didn't + reimplement QWidget::sizeHint(). + + \image calculator-ugly.png The Calculator example with default size policies and size hints + +*/ |