Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example sqlwidgetmapper
++ \title SQL Widget Mapper Example
++ \ingroup sql_examples
++ \examplecategory {Data Processing & I/O}
++
++ \brief The SQL Widget Mapper example shows how to use a map information from a
++ database to widgets on a form.
++
++ \image sql-widget-mapper.png {The main window displays the user name, the user address, and it classifies the address type.}
++
++ In the \l{Combo Widget Mapper Example}, we showed how to use a named
++ mapping between a widget mapper and a QComboBox widget with a special
++ purpose model to relate values in the model to a list of choices.
++
++ Again, we create a \c Window class with an almost identical user interface,
++ providing a combo box to allow their addresses to be classified as "Home",
++ "Work" or "Other". However, instead of using a separate model to hold these
++ address types, we use one database table to hold the example data and
++ another to hold the address types. In this way, we store all the
++ information in the same place.
++
++ \section1 Window Class Definition
++
++ The class provides a constructor, a slot to keep the buttons up to date,
++ and a private function to set up the model:
++
++ \snippet sqlwidgetmapper/window.h Window definition
++
++ In addition to the QDataWidgetMapper object and the controls used to make
++ up the user interface, we use a QStandardItemModel to hold our data and
++ a QStringListModel to hold information about the types of address that
++ can be applied to each person's data.
++
++ \section1 Window Class Implementation
++
++ The first act performed by the \c Window class constructor is to set up
++ the model used to hold the example data. Since this is a key part of the
++ example, we will look at this first.
++
++ The model is initialized in the window's \c{setupModel()} function. Here,
++ we create a SQLite database containing a "person" table with primary key,
++ name, address and type fields.
++
++ \snippet sqlwidgetmapper/window.cpp Set up the main table
++
++ On each row of the table, we insert default values for these fields,
++ including values for the address types that correspond to the address
++ types are stored in a separate table.
++
++ \image widgetmapper-sql-mapping-table.png {The main window displays a table that consists of the information stored in the database.}
++
++ We create an "addresstype" table containing the identifiers used in the
++ "person" table and the corresponding strings:
++
++ \snippet sqlwidgetmapper/window.cpp Set up the address type table
++
++ The "typeid" field in the "person" table is related to the contents of
++ the "addresstype" table via a relation in a QSqlRelationalTableModel.
++ This kind of model performs all the necessary work to store the data in
++ a database and also allows any relations to be used as models in their
++ own right.
++
++ In this case, we have defined a relation for the "typeid" field in the
++ "person" table that relates it to the "id" field in the "addresstype"
++ table and which causes the contents of the "description" field to be
++ used wherever the "typeid" is presented to the user. (See the
++ QSqlRelationalTableModel::setRelation() documentation for details.)
++
++ \image widgetmapper-sql-mapping.png {The table depicts the relationship between the "typeid" field and the "addresstype".}
++
++ The constructor of the \c Window class can be explained in three parts.
++ In the first part, we set up the model used to hold the data, then we set
++ up the widgets used for the user interface:
++
++ \snippet sqlwidgetmapper/window.cpp Set up widgets
++
++ We obtain a model for the combo box from the main model, based on the
++ relation we set up for the "typeid" field. The call to the combo box's
++ \l{QComboBox::}{setModelColumn()} selects the field in the field in the
++ model to display.
++
++ Note that this approach is similar to the one used in the
++ \l{Combo Widget Mapper Example} in that we set up a model for the
++ combo box. However, in this case, we obtain a model based on a relation
++ in the QSqlRelationalTableModel rather than create a separate one.
++
++ Next, we set up the widget mapper, relating each input widget to a field
++ in the model:
++
++ \snippet sqlwidgetmapper/window.cpp Set up the mapper
++
++ For the combo box, we already know the index of the field in the model
++ from the \c{setupModel()} function. We use a QSqlRelationalDelegate as
++ a proxy between the mapper and the input widgets to match up the "typeid"
++ values in the model with those in the combo box's model and populate the
++ combo box with descriptions rather than integer values.
++
++ As a result, the user is able to select an item from the combo box,
++ and the associated value is written back to the model.
++
++ The rest of the constructor sets up connections and layouts:
++
++ \snippet sqlwidgetmapper/window.cpp Set up connections and layouts
++
++ We show the implementation of the \c{updateButtons()} slot for
++ completeness:
++
++ \snippet sqlwidgetmapper/window.cpp Slot for updating the buttons
++
++ \omit
++ \section1 Delegate Class Definition and Implementation
++
++ The delegate we use to mediate interaction between the widget mapper and
++ the input widgets is a small QStyledItemDelegate subclass:
++
++ \snippet sqlwidgetmapper/delegate.h Delegate class definition
++
++ This provides implementations of the two standard functions used to pass
++ data between editor widgets and the model (see the \l{Delegate Classes}
++ documentation for a more general description of these functions).
++
++ Since we only provide an empty implementation of the constructor, we
++ concentrate on the other two functions.
++
++ The \l{QStyledItemDelegate::}{setEditorData()} implementation takes the data
++ referred to by the model index supplied and processes it according to
++ the presence of a \c currentIndex property in the editor widget:
++
++ \snippet sqlwidgetmapper/delegate.cpp setEditorData implementation
++
++ If, like QComboBox, the editor widget has this property, it is set using
++ the value from the model. Since we are passing around QVariant values,
++ the strings stored in the model are automatically converted to the integer
++ values needed for the \c currentIndex property.
++
++ As a result, instead of showing "0", "1" or "2" in the combo box, one of
++ its predefined set of items is shown. We call QStyledItemDelegate::setEditorData()
++ for widgets without the \c currentIndex property.
++
++ The \l{QStyledItemDelegate::}{setModelData()} implementation performs the reverse
++ process, taking the value stored in the widget's \c currentIndex property
++ and storing it back in the model:
++
++ \snippet sqlwidgetmapper/delegate.cpp setModelData implementation
++ \endomit
++
++ \section1 Summary and Further Reading
++
++ The use of a separate model for the combo box and a special delegate for the
++ widget mapper allows us to present a menu of choices to the user. Although
++ the choices are stored in the same database as the user's data, they are held
++ in a separate table. Using this approach, we can reconstructed complete records
++ at a later time while using database features appropriately.
++
++ If SQL models are not being used, it is still possible to use more than
++ one model to present choices to the user. This is covered by the
++ \l{Combo Widget Mapper Example}.
++ */