doc/src/examples/calculator.qdoc
branchRCL_3
changeset 8 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
       
     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 */