mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-06 17:25:24 +08:00
qt 6.5.1 original
This commit is contained in:
24
examples/sql/doc/src/books.qdoc
Normal file
24
examples/sql/doc/src/books.qdoc
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example books
|
||||
\title Books
|
||||
\ingroup sql_examples
|
||||
\brief Shows how to use Qt SQL classes with a model/view framework.
|
||||
|
||||
The Books example shows how Qt's SQL classes can be used with the model/view
|
||||
framework to create rich user interfaces for information stored in a database.
|
||||
|
||||
\borderedimage books-demo.png
|
||||
|
||||
Information about a collection of books is held in a database. The books are
|
||||
catalogued by author, title, genre, and year of publication. Although each of
|
||||
these fields can be displayed and edited using standard widgets, an additional
|
||||
field describing an arbitrary rating for the book needs something extra.
|
||||
|
||||
Books are rated using a system where each is allocated a number of stars; the
|
||||
more a book has, the better it is supposed to be. By clicking on a cell
|
||||
containing the rating, the number of stars can be modified, and the rating in
|
||||
the database is updated.
|
||||
*/
|
174
examples/sql/doc/src/cachedtable.qdoc
Normal file
174
examples/sql/doc/src/cachedtable.qdoc
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example cachedtable
|
||||
\title Cached Table Example
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The Cached Table example shows how a table view can be used to access a database,
|
||||
caching any changes to the data until the user explicitly submits them using a
|
||||
push button.
|
||||
|
||||
\borderedimage cachedtable-example.png
|
||||
|
||||
The example consists of a single class, \c TableEditor, which is a
|
||||
custom dialog widget that allows the user to modify data stored in
|
||||
a database. We will first review the class definition and how to
|
||||
use the class, then we will take a look at the implementation.
|
||||
|
||||
\section1 TableEditor Class Definition
|
||||
|
||||
The \c TableEditor class inherits QWidget making the table editor
|
||||
widget a top-level dialog window.
|
||||
|
||||
\snippet cachedtable/tableeditor.h 0
|
||||
|
||||
The \c TableEditor constructor takes two arguments: The first is a
|
||||
reference to the database table the \c TableEditor object will operate
|
||||
on. The other is a pointer to the parent widget and is passed on to the
|
||||
base class constructor.
|
||||
|
||||
Note the QSqlTableModel variable declaration: As we will see in
|
||||
this example, the QSqlTableModel class can be used to provide data
|
||||
to view classes such as QTableView. The QSqlTableModel class
|
||||
provides an editable data model making it possible to read and
|
||||
write database records from a single table. It is build on top of
|
||||
the lower-level QSqlQuery class which provides means of executing
|
||||
and manipulating SQL statements.
|
||||
|
||||
We are also going to show how a table view can be used to cache
|
||||
any changes to the data until the user explicitly requests to
|
||||
submit them. For that reason we need to declare a \c submit() slot
|
||||
in addition to the model and the editor's buttons.
|
||||
|
||||
\table 100%
|
||||
\header \li Connecting to a Database
|
||||
\row
|
||||
\li
|
||||
|
||||
Before we can use the \c TableEditor class, we must create a
|
||||
connection to the database containing the table we want to edit:
|
||||
|
||||
\snippet cachedtable/main.cpp 0
|
||||
|
||||
The \c createConnection() function is a helper function provided
|
||||
for convenience. It is defined in the \c connection.h file which
|
||||
is located in the \c sql example directory (all the examples in
|
||||
the \c sql directory use this function to connect to a database).
|
||||
|
||||
\snippet connection.h 0
|
||||
|
||||
The \c createConnection function opens a connection to an
|
||||
in-memory SQLITE database and creates a test table. If you want
|
||||
to use another database, simply modify this function's code.
|
||||
\endtable
|
||||
|
||||
\section1 TableEditor Class Implementation
|
||||
|
||||
The class implementation consists of only two functions, the
|
||||
constructor and the \c submit() slot. In the constructor we create
|
||||
and customize the data model and the various window elements:
|
||||
|
||||
\snippet cachedtable/tableeditor.cpp 0
|
||||
|
||||
First we create the data model and set the SQL database table we
|
||||
want the model to operate on. Note that the
|
||||
QSqlTableModel::setTable() function does not select data from the
|
||||
table; it only fetches its field information. For that reason we
|
||||
call the QSqlTableModel::select() function later on, populating
|
||||
the model with data from the table. The selection can be
|
||||
customized by specifying filters and sort conditions (see the
|
||||
QSqlTableModel class documentation for more details).
|
||||
|
||||
We also set the model's edit strategy. The edit strategy dictates
|
||||
when the changes done by the user in the view, are actually
|
||||
applied to the database. Since we want to cache the changes in the
|
||||
table view (i.e. in the model) until the user explicitly submits
|
||||
them, we choose the QSqlTableModel::OnManualSubmit strategy. The
|
||||
alternatives are QSqlTableModel::OnFieldChange and
|
||||
QSqlTableModel::OnRowChange.
|
||||
|
||||
Finally, we set up the labels displayed in the view header using
|
||||
the \l {QSqlQueryModel::setHeaderData()}{setHeaderData()} function
|
||||
that the model inherits from the QSqlQueryModel class.
|
||||
|
||||
\snippet cachedtable/tableeditor.cpp 1
|
||||
|
||||
Then we create a table view. The QTableView class provides a
|
||||
default model/view implementation of a table view, i.e. it
|
||||
implements a table view that displays items from a model. It also
|
||||
allows the user to edit the items, storing the changes in the
|
||||
model. To create a read only view, set the proper flag using the
|
||||
\l {QAbstractItemView::editTriggers}{editTriggers} property the
|
||||
view inherits from the QAbstractItemView class.
|
||||
|
||||
To make the view present our data, we pass our model to the view
|
||||
using the \l {QAbstractItemView::setModel()}{setModel()} function.
|
||||
|
||||
\snippet cachedtable/tableeditor.cpp 2
|
||||
|
||||
The \c {TableEditor}'s buttons are regular QPushButton objects. We
|
||||
add them to a button box to ensure that the buttons are presented
|
||||
in a layout that is appropriate to the current widget style. The
|
||||
rationale for this is that dialogs and message boxes typically
|
||||
present buttons in a layout that conforms to the interface
|
||||
guidelines for that platform. Invariably, different platforms have
|
||||
different layouts for their dialogs. QDialogButtonBox allows a
|
||||
developer to add buttons to it and will automatically use the
|
||||
appropriate layout for the user's desktop environment.
|
||||
|
||||
Most buttons for a dialog follow certain roles. When adding a
|
||||
button to a button box using the \l
|
||||
{QDialogButtonBox}{addButton()} function, the button's role must
|
||||
be specified using the QDialogButtonBox::ButtonRole
|
||||
enum. Alternatively, QDialogButtonBox provides several standard
|
||||
buttons (e.g. \uicontrol OK, \uicontrol Cancel, \uicontrol Save) that you can
|
||||
use. They exist as flags so you can OR them together in the
|
||||
constructor.
|
||||
|
||||
\snippet cachedtable/tableeditor.cpp 3
|
||||
|
||||
We connect the \uicontrol Quit button to the table editor's \l
|
||||
{QWidget::close()}{close()} slot, and the \uicontrol Submit button to
|
||||
our private \c submit() slot. The latter slot will take care of
|
||||
the data transactions. Finally, we connect the \uicontrol Revert button
|
||||
to our model's \l {QSqlTableModel::revertAll()}{revertAll()} slot,
|
||||
reverting all pending changes (i.e., restoring the original data).
|
||||
|
||||
\snippet cachedtable/tableeditor.cpp 4
|
||||
|
||||
In the end we add the button box and the table view to a layout,
|
||||
install the layout on the table editor widget, and set the
|
||||
editor's window title.
|
||||
|
||||
\snippet cachedtable/tableeditor.cpp 5
|
||||
|
||||
The \c submit() slot is called whenever the users hit the \uicontrol
|
||||
Submit button to save their changes.
|
||||
|
||||
First, we begin a transaction on the database using the
|
||||
QSqlDatabase::transaction() function. A database transaction is a
|
||||
unit of interaction with a database management system or similar
|
||||
system that is treated in a coherent and reliable way independent
|
||||
of other transactions. A pointer to the used database can be
|
||||
obtained using the QSqlTableModel::database() function.
|
||||
|
||||
Then, we try to submit all the pending changes, i.e. the model's
|
||||
modified items. If no error occurs, we commit the transaction to
|
||||
the database using the QSqlDatabase::commit() function (note that
|
||||
on some databases, this function will not work if there is an
|
||||
active QSqlQuery on the database). Otherwise we perform a rollback
|
||||
of the transaction using the QSqlDatabase::rollback() function and
|
||||
post a warning to the user.
|
||||
|
||||
\table 100%
|
||||
\row
|
||||
\li
|
||||
\b {See also:}
|
||||
|
||||
A complete list of Qt's SQL \l {Database Classes}, and the \l
|
||||
{Model/View Programming} documentation.
|
||||
|
||||
\endtable
|
||||
*/
|
522
examples/sql/doc/src/drilldown.qdoc
Normal file
522
examples/sql/doc/src/drilldown.qdoc
Normal file
@ -0,0 +1,522 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example drilldown
|
||||
\title Drill Down Example
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The Drill Down example shows how to read data from a database as
|
||||
well as submit changes, using the QSqlRelationalTableModel and
|
||||
QDataWidgetMapper classes.
|
||||
|
||||
\borderedimage drilldown-example.png Screenshot of the Drill Down Example
|
||||
|
||||
When running the example application, a user can retrieve
|
||||
information about each item by clicking the corresponding image.
|
||||
The application pops up an information window displaying the data,
|
||||
and allows the users to alter the description as well as the image.
|
||||
The main view will be updated when the users submit their changes.
|
||||
|
||||
The example consists of three classes:
|
||||
|
||||
\list
|
||||
\li \c ImageItem is a custom graphics item class used to
|
||||
display the images.
|
||||
|
||||
\li \c View is the main application widget allowing the user to
|
||||
browse through the various items.
|
||||
|
||||
\li \c InformationWindow displays the requested information,
|
||||
allowing the users to alter it and submit their changes to the
|
||||
database.
|
||||
\endlist
|
||||
|
||||
We will first take a look at the \c InformationWindow class to see
|
||||
how you can read and modify data from a database. Then we will
|
||||
review the main application widget, i.e., the \c View class, and
|
||||
the associated \c ImageItem class.
|
||||
|
||||
\section1 InformationWindow Class Definition
|
||||
|
||||
The \c InformationWindow class is a custom widget inheriting
|
||||
QWidget:
|
||||
|
||||
\snippet drilldown/informationwindow.h 0
|
||||
|
||||
When we create an information window, we pass the associated
|
||||
item ID, a parent, and a pointer to the database, to the
|
||||
constructor. We will use the database pointer to populate our
|
||||
window with data, while passing the parent parameter on to the
|
||||
base class. The ID is stored for future reference.
|
||||
|
||||
Once a window is created, we will use the public \c id() function
|
||||
to locate it whenever information for the given location is
|
||||
requested. We will also use the ID to update the main application
|
||||
widget when the users submit their changes to the database, i.e.,
|
||||
we will emit a signal carrying the ID and file name as parameters
|
||||
whenever the users changes the associated image.
|
||||
|
||||
\snippet drilldown/informationwindow.h 1
|
||||
|
||||
Since we allow the users to alter some of the data, we
|
||||
must provide functionality for reverting and submitting their
|
||||
changes. The \c enableButtons() slot is provided for convenience
|
||||
to enable and disable the various buttons when required.
|
||||
|
||||
\snippet drilldown/informationwindow.h 2
|
||||
|
||||
The \c createButtons() function is also a convenience function,
|
||||
provided to simplify the constructor. As mentioned above we store
|
||||
the item ID for future reference. We also store the name of
|
||||
the currently displayed image file to be able to determine when to
|
||||
emit the \c imageChanged() signal.
|
||||
|
||||
The information window uses the QLabel class to display the name of
|
||||
an item. The associated image file is displayed using a QComboBox
|
||||
instance while the description is displayed using QTextEdit. In
|
||||
addition, the window has three buttons to control the data flow and
|
||||
whether the window is shown or not.
|
||||
|
||||
Finally, we declare a \e mapper. The QDataWidgetMapper class
|
||||
provides mapping between a section of a data model to widgets. We
|
||||
will use the mapper to extract data from the given database,
|
||||
updating the database whenever the user modifies the data.
|
||||
|
||||
\section1 InformationWindow Class Implementation
|
||||
|
||||
The constructor takes three arguments: an item ID, a database
|
||||
pointer and a parent widget. The database pointer is actually a
|
||||
pointer to a QSqlRelationalTableModel object providing an editable
|
||||
data model (with foreign key support) for our database table.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 0
|
||||
\snippet drilldown/informationwindow.cpp 1
|
||||
|
||||
First we create the various widgets required to display the data
|
||||
contained in the database. Most of the widgets are created in a
|
||||
straight forward manner. But note the combobox displaying the
|
||||
name of the image file:
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 2
|
||||
|
||||
In this example, information about the items are stored in a
|
||||
database table called "items". When creating the model,
|
||||
we will use a foreign key to establish a relation between this
|
||||
table and a second data base table, "images", containing the names
|
||||
of the available image files. We will get back to how this is done
|
||||
when reviewing the \c View class. The rationale for creating such
|
||||
a relation though, is that we want to ensure that the user only
|
||||
can choose between predefined image files.
|
||||
|
||||
The model corresponding to the "images" database table, is
|
||||
available through the QSqlRelationalTableModel's \l
|
||||
{QSqlRelationalTableModel::}{relationModel()} function, requiring
|
||||
the foreign key (in this case the "imagefile" column number) as
|
||||
argument. We use QComboBox's \l {QComboBox::}{setModel()} function
|
||||
to make the combobox use the "images" model. And, since this model
|
||||
has two columns ("itemid" and "file"), we also specify which
|
||||
column we want to be visible using the QComboBox::setModelColumn()
|
||||
function.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 3
|
||||
|
||||
Then we create the mapper. The QDataWidgetMapper class allows us
|
||||
to create data-aware widgets by mapping them to sections of an
|
||||
item model.
|
||||
|
||||
The \l {QDataWidgetMapper::}{addMapping()} function adds a mapping
|
||||
between the given widget and the specified section of the
|
||||
model. If the mapper's orientation is horizontal (the default) the
|
||||
section is a column in the model, otherwise it is a row. We call
|
||||
the \l {QDataWidgetMapper::}{setCurrentIndex()} function to
|
||||
initialize the widgets with the data associated with the given
|
||||
item ID. Every time the current index changes, all the widgets
|
||||
are updated with the contents from the model.
|
||||
|
||||
We also set the mapper's submit policy to
|
||||
QDataWidgetMapper::ManualSubmit. This means that no data is
|
||||
submitted to the database until the user expliclity requests a
|
||||
submit (the alternative is QDataWidgetMapper::AutoSubmit,
|
||||
automatically submitting changes when the corresponding widget
|
||||
loses focus). Finally, we specify the item delegate the mapper
|
||||
view should use for its items. The QSqlRelationalDelegate class
|
||||
represents a delegate that unlike the default delegate, enables
|
||||
combobox functionality for fields that are foreign keys into other
|
||||
tables (like "imagefile" in our "items" table).
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 4
|
||||
|
||||
Finally, we connect the "something's changed" signals in the
|
||||
editors to our custom \c enableButtons slot, enabling the users
|
||||
to either submit or revert their changes.
|
||||
We need to use lambdas for connecting the \c enableButtons slot
|
||||
because its signature does not match \c QTextEdit::textChanged
|
||||
and \c QComboBox::currentIndexChanged.
|
||||
Since the latter has another overload with the signature
|
||||
\c {const QString &} and the selected signal would be ambiguous,
|
||||
we need to use \c QOverload<int>::of to select a specific overload
|
||||
for \c currentIndexChanged.
|
||||
|
||||
We add all the widgets into a layout, store the item ID and the
|
||||
name of the displayed image file for future reference, and set
|
||||
the window title and initial size.
|
||||
|
||||
|
||||
Note that we also set the Qt::Window window flag to indicate that
|
||||
our widget is in fact a window, with a window system frame and a
|
||||
title bar.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 5
|
||||
|
||||
When a window is created, it is not deleted until the main
|
||||
application exits (i.e., if the user closes the information
|
||||
window, it is only hidden). For this reason we do not want to
|
||||
create more than one \c InformationWindow object for each
|
||||
item, and we provide the public \c id() function to be able to
|
||||
determine whether a window already exists for a given location
|
||||
when the user requests information about it.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 6
|
||||
|
||||
The \c revert() slot is triggered whenever the user hits the \uicontrol
|
||||
Revert button.
|
||||
|
||||
Since we set the QDataWidgetMapper::ManualSubmit submit policy,
|
||||
none of the user's changes are written back to the model unless
|
||||
the user expliclity choose to submit all of them. Nevertheless, we
|
||||
can use the QDataWidgetMapper's \l {QDataWidgetMapper::}{revert()}
|
||||
slot to reset the editor widgets, repopulating all widgets with
|
||||
the current data of the model.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 7
|
||||
|
||||
Likewise, the \c submit() slot is triggered whenever the users
|
||||
decide to submit their changes by pressing the \uicontrol Submit button.
|
||||
|
||||
We use QDataWidgetMapper's \l {QDataWidgetMapper::}{submit()} slot
|
||||
to submit all changes from the mapped widgets to the model,
|
||||
i.e. to the database. For every mapped section, the item delegate
|
||||
will then read the current value from the widget and set it in the
|
||||
model. Finally, the \e model's \l {QAbstractItemModel::}{submit()}
|
||||
function is invoked to let the model know that it should submit
|
||||
whatever it has cached to the permanent storage.
|
||||
|
||||
Note that before any data is submitted, we check if the user has
|
||||
chosen another image file using the previously stored \c
|
||||
displayedImage variable as reference. If the current and stored
|
||||
file names differ, we store the new file name and emit the \c
|
||||
imageChanged() signal.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 8
|
||||
|
||||
The \c createButtons() function is provided for convenience, i.e.,
|
||||
to simplify the constructor.
|
||||
|
||||
We make the \uicontrol Close button the default button, i.e., the button
|
||||
that is pressed when the user presses \uicontrol Enter, and connect its
|
||||
\l {QPushButton::}{clicked()} signal to the widget's \l
|
||||
{QWidget::}{close()} slot. As mentioned above closing the window
|
||||
only hides the widget; it is not deleted. We also connect the \uicontrol
|
||||
Submit and \uicontrol Revert buttons to the corresponding \c submit()
|
||||
and \c revert() slots.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 9
|
||||
|
||||
The QDialogButtonBox class is a widget that presents buttons in a
|
||||
layout that is appropriate to the current widget style. Dialogs
|
||||
like our information window, typically present buttons in a layout
|
||||
that conforms to the interface guidelines for that
|
||||
platform. Invariably, different platforms have different layouts
|
||||
for their dialogs. QDialogButtonBox allows us to add buttons,
|
||||
automatically using the appropriate layout for the user's desktop
|
||||
environment.
|
||||
|
||||
Most buttons for a dialog follow certain roles. We give the \uicontrol
|
||||
Submit and \uicontrol Revert buttons the \l
|
||||
{QDialogButtonBox::ButtonRole}{reset} role, i.e., indicating that
|
||||
pressing the button resets the fields to the default values (in
|
||||
our case the information contained in the database). The \l
|
||||
{QDialogButtonBox::ButtonRole}{reject} role indicates that
|
||||
clicking the button causes the dialog to be rejected. On the other
|
||||
hand, since we only hide the information window, any changes that
|
||||
the user has made will be preserved until the user explicitly
|
||||
reverts or submits them.
|
||||
|
||||
\snippet drilldown/informationwindow.cpp 10
|
||||
|
||||
The \c enableButtons() slot is called to enable the buttons
|
||||
whenever the user changes the presented data. Likewise, when the
|
||||
user chooses to submit the changes, the buttons are disabled to
|
||||
indicate that the current data is stored in the database.
|
||||
|
||||
This completes the \c InformationWindow class. Let's take a look
|
||||
at how we have used it in our example application.
|
||||
|
||||
\section1 View Class Definition
|
||||
|
||||
The \c View class represents the main application window and
|
||||
inherits QGraphicsView:
|
||||
|
||||
\snippet drilldown/view.h 0
|
||||
\codeline
|
||||
\snippet drilldown/view.h 1
|
||||
|
||||
The QGraphicsView class is part of the \l {Graphics View
|
||||
Framework} which we will use to display the images. To be able to
|
||||
respond to user interaction by displaying the appropriate
|
||||
information window when the image is clicked, we reimplement
|
||||
QGraphicsView's \l{QGraphicsView::}{mouseReleaseEvent()} function.
|
||||
|
||||
Note that the constructor expects the names of two database
|
||||
tables: One containing the detailed information about the items,
|
||||
and another containing the names of the available image files. We
|
||||
also provide a private \c updateImage() slot to catch \c
|
||||
{InformationWindow}'s \c imageChanged() signal that is emitted
|
||||
whenever the user changes an image associated with the item.
|
||||
|
||||
\snippet drilldown/view.h 2
|
||||
|
||||
The \c addItems() function is a convenience function provided to
|
||||
simplify the constructor. It is called only once, creating the
|
||||
various items and adding them to the view.
|
||||
|
||||
The \c findWindow() function, on the other hand, is frequently
|
||||
used. It is called from the \c showInformation() function to
|
||||
determine whether a window is already created for the given
|
||||
item (whenever we create an \c InformationWindow object, we
|
||||
store a reference to it in the \c informationWindows list). The
|
||||
latter function is in turn called from our custom \c
|
||||
mouseReleaseEvent() implementation.
|
||||
|
||||
\snippet drilldown/view.h 3
|
||||
|
||||
Finally, we declare a QSqlRelationalTableModel pointer. As
|
||||
previously mentioned, the QSqlRelationalTableModel class provides
|
||||
an editable data model with foreign key support. There are a
|
||||
couple of things you should keep in mind when using the
|
||||
QSqlRelationalTableModel class: The table must have a primary key
|
||||
declared and this key cannot contain a relation to another table,
|
||||
that is, it cannot be a foreign key. Also note that if a relational
|
||||
table contains keys that refer to non-existent rows in the
|
||||
referenced table, the rows containing the invalid keys will not be
|
||||
exposed through the model. It is the user's or the database's
|
||||
responsibility to maintain referential integrity.
|
||||
|
||||
\section1 View Class Implementation
|
||||
|
||||
Although the constructor requests the names of both the table
|
||||
containing office details as well as the table containing the
|
||||
names of the available image files, we only have to create a
|
||||
QSqlRelationalTableModel object for the "items" table:
|
||||
|
||||
\snippet drilldown/view.cpp 0
|
||||
|
||||
The reason is that once we have a model with the item details,
|
||||
we can create a relation to the available image files using
|
||||
QSqlRelationalTableModel's \l
|
||||
{QSqlRelationalTableModel::}{setRelation()} function. This
|
||||
function creates a foreign key for the given model column. The key
|
||||
is specified by the provided QSqlRelation object constructed by
|
||||
the name of the table the key refers to, the field the key is
|
||||
mapping to and the field that should be presented to the user.
|
||||
|
||||
Note that setting the table only specifies which table the model
|
||||
operates on, i.e., we must explicitly call the model's \l
|
||||
{QSqlRelationalTableModel::}{select()} function to populate our
|
||||
model.
|
||||
|
||||
\snippet drilldown/view.cpp 1
|
||||
|
||||
Then we create the contents of our view, i.e., the scene and its
|
||||
items. The labels are regular QGraphicsTextItem objects, whereas
|
||||
the images are instances of the \c ImageItem class, derived from
|
||||
QGraphicsPixmapItem. We will get back to this shortly when reviewing
|
||||
the \c addItems() function.
|
||||
|
||||
Finally, we set the main application widget's size constraints and
|
||||
window title.
|
||||
|
||||
\snippet drilldown/view.cpp 3
|
||||
|
||||
The \c addItems() function is called only once when creating the main
|
||||
application window. For each row in the database table, we first
|
||||
extract the corresponding record using the model's
|
||||
\l {QSqlRelationalTableModel::}{record()} function. The QSqlRecord
|
||||
class encapsulates both the functionality and characteristics of a
|
||||
database record, and supports adding and removing fields as well
|
||||
as setting and retrieving field values. The QSqlRecord::value()
|
||||
function returns the value of the field with the given name or
|
||||
index as a QVariant object.
|
||||
|
||||
For each record, we create a label item as well as an image item,
|
||||
calculate their position and add them to the scene. The image
|
||||
items are represented by instances of the \c ImageItem class. The
|
||||
reason we must create a custom item class is that we want to catch
|
||||
the item's hover events, animating the item when the mouse cursor
|
||||
is hovering over the image (by default, no items accept hover
|
||||
events). Please see the \l{Graphics View Framework} documentation
|
||||
and the \l{Graphics View Examples} for more details.
|
||||
|
||||
\snippet drilldown/view.cpp 5
|
||||
|
||||
We reimplement QGraphicsView's \l
|
||||
{QGraphicsView::}{mouseReleaseEvent()} event handler to respond to
|
||||
user interaction. If the user clicks any of the image items, this
|
||||
function calls the private \c showInformation() function to pop up
|
||||
the associated information window.
|
||||
|
||||
The \l {Graphics View Framework} provides the qgraphicsitem_cast()
|
||||
function to determine whether the given QGraphicsItem instance is
|
||||
of a given type. Note that if the event is not related to any of
|
||||
our image items, we pass it on to the base class implementation.
|
||||
|
||||
\snippet drilldown/view.cpp 6
|
||||
|
||||
The \c showInformation() function is given an \c ImageItem object
|
||||
as argument, and starts off by extracting the item's item ID.
|
||||
|
||||
Then it determines if there already is created an information
|
||||
window for this location.
|
||||
If no window for the given location exists, we create one by
|
||||
passing the item ID, a pointer to the model, and our view as a
|
||||
parent, to the \c InformationWindow constructor. Note that we
|
||||
connect the information window's \c imageChanged() signal to \e
|
||||
this widget's \c updateImage() slot, before we give it a suitable
|
||||
position and add it to the list of existing windows.
|
||||
If there is a window for the given location, and that window is
|
||||
visible, it ensures that the window is raised to the top of the
|
||||
widget stack and activated. If it is hidden, calling its \l
|
||||
{QWidget::}{show()} slot gives the same result.
|
||||
|
||||
|
||||
\snippet drilldown/view.cpp 7
|
||||
|
||||
The \c updateImage() slot takes an item ID and the name of an
|
||||
image file as arguments. It filters out the image items, and
|
||||
updates the one that correspond to the given item ID, with the
|
||||
provided image file.
|
||||
|
||||
\snippet drilldown/view.cpp 8
|
||||
|
||||
The \c findWindow() function simply searches through the list of
|
||||
existing windows, returning a pointer to the window that matches
|
||||
the given item ID, or \nullptr if the window doesn't exists.
|
||||
|
||||
Finally, let's take a quick look at our custom \c ImageItem class:
|
||||
|
||||
\section1 ImageItem Class Definition
|
||||
|
||||
The \c ImageItem class is provided to facilitate animation of the
|
||||
image items. It inherits QGraphicsPixmapItem and reimplements its
|
||||
hover event handlers:
|
||||
|
||||
\snippet drilldown/imageitem.h 0
|
||||
|
||||
We declare a \c Type enum value for our custom item and reimplement
|
||||
\l{QGraphicsItem::}{type()}. This is done so we can safely use
|
||||
qgraphicsitem_cast().
|
||||
In addition, we implement a public \c id() function to be able to
|
||||
identify the associated location and a public \c adjust() function
|
||||
that can be called to ensure that the image item is given the
|
||||
preferred size regardless of the original image file.
|
||||
|
||||
The animation is implemented using the QTimeLine class together
|
||||
with the event handlers and the private \c setFrame() slot: The
|
||||
image item will expand when the mouse cursor hovers over it,
|
||||
returning back to its original size when the cursor leaves its
|
||||
borders.
|
||||
|
||||
Finally, we store the item ID that this particular record is
|
||||
associated with as well as a z-value. In the \l {Graphics View
|
||||
Framework}, an item's z-value determines its position in the item
|
||||
stack. An item of high z-value will be drawn on top of an item
|
||||
with a lower z-value if they share the same parent item. We also
|
||||
provide an \c updateItemPosition() function to refresh the view
|
||||
when required.
|
||||
|
||||
\section1 ImageItem Class Implementation
|
||||
|
||||
The \c ImageItem class is really only a QGraphicsPixmapItem with
|
||||
some additional features, i.e., we can pass most of the
|
||||
constructor's arguments (the pixmap, parent and scene) on to the
|
||||
base class constructor:
|
||||
|
||||
\snippet drilldown/imageitem.cpp 0
|
||||
|
||||
Then we store the ID for future reference, and ensure that our
|
||||
image item will accept hover events. Hover events are delivered
|
||||
when there is no current mouse grabber item. They are sent when the
|
||||
mouse cursor enters an item, when it moves around inside the item,
|
||||
and when the cursor leaves an item. As we mentioned earlier, none
|
||||
of the \l {Graphics View Framework}'s items accept hover
|
||||
event's by default.
|
||||
|
||||
The QTimeLine class provides a timeline for controlling
|
||||
animations. Its \l {QTimeLine::}{duration} property holds the
|
||||
total duration of the timeline in milliseconds. By default, the
|
||||
time line runs once from the beginning and towards the end. The
|
||||
QTimeLine::setFrameRange() function sets the timeline's frame
|
||||
counter; when the timeline is running, the \l
|
||||
{QTimeLine::}{frameChanged()} signal is emitted each time the
|
||||
frame changes. We set the duration and frame range for our
|
||||
animation, and connect the time line's \l
|
||||
{QTimeLine::}{frameChanged()} and \l {QTimeLine::}{finished()}
|
||||
signals to our private \c setFrame() and \c updateItemPosition()
|
||||
slots.
|
||||
|
||||
Finally, we call \c adjust() to ensure that the item is given the
|
||||
preferred size.
|
||||
|
||||
\snippet drilldown/imageitem.cpp 1
|
||||
\codeline
|
||||
\snippet drilldown/imageitem.cpp 2
|
||||
|
||||
Whenever the mouse cursor enters or leaves the image item, the
|
||||
corresponding event handlers are triggered: We first set the time
|
||||
line's direction, making the item expand or shrink,
|
||||
respectively. Then we alter the item's z-value if it is not already
|
||||
set to the expected value.
|
||||
|
||||
In the case of hover \e enter events, we immediately update the
|
||||
item's position since we want the item to appear on top of all
|
||||
other items as soon as it starts expanding. In the case of hover
|
||||
\e leave events, on the other hand, we postpone the actual update
|
||||
to achieve the same result. But remember that when we constructed
|
||||
our item, we connected the time line's \l
|
||||
{QTimeLine::}{finished()} signal to the \c updateItemPosition()
|
||||
slot. In this way the item is given the correct position in the
|
||||
item stack once the animation is completed. Finally, if the time
|
||||
line is not already running, we start it.
|
||||
|
||||
\snippet drilldown/imageitem.cpp 3
|
||||
|
||||
When the time line is running, it triggers the \c setFrame() slot
|
||||
whenever the current frame changes due to the connection we
|
||||
created in the item constructor. It is this slot that controls the
|
||||
animation, expanding or shrinking the image item step by step.
|
||||
|
||||
We first call the \c adjust() function to ensure that we start off
|
||||
with the item's original size. Then we scale the item with a
|
||||
factor depending on the animation's progress (using the \c frame
|
||||
parameter). Note that by default, the transformation will be
|
||||
relative to the item's top-left corner. Since we want the item to
|
||||
be transformed relative to its center, we must translate the
|
||||
coordinate system before we scale the item.
|
||||
|
||||
In the end, only the following convenience functions remain:
|
||||
|
||||
\snippet drilldown/imageitem.cpp 4
|
||||
\codeline
|
||||
\snippet drilldown/imageitem.cpp 5
|
||||
\codeline
|
||||
\snippet drilldown/imageitem.cpp 6
|
||||
|
||||
The \c adjust() function defines and applies a transformation
|
||||
matrix, ensuring that our image item appears with the preferred
|
||||
size regardless of the size of the source image. The \c id()
|
||||
function is trivial, and is simply provided to be able to identify
|
||||
the item. In the \c updateItemPosition() slot we call the
|
||||
QGraphicsItem::setZValue() function, setting the elevation of the
|
||||
item.
|
||||
*/
|
20
examples/sql/doc/src/masterdetail.qdoc
Normal file
20
examples/sql/doc/src/masterdetail.qdoc
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example masterdetail
|
||||
\title Master Detail Example
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The Master Detail Example shows how to present data from different
|
||||
data sources in the same application. The album titles, and the
|
||||
corresponding artists and release dates, are kept in a
|
||||
database, while each album's tracks are stored in an XML
|
||||
file.
|
||||
|
||||
The example also shows how to add as well as remove data from both
|
||||
the database and the associated XML file using the API provided by
|
||||
the Qt SQL and Qt XML modules, respectively.
|
||||
|
||||
\borderedimage masterdetail-example.png
|
||||
*/
|
14
examples/sql/doc/src/querymodel.qdoc
Normal file
14
examples/sql/doc/src/querymodel.qdoc
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example querymodel
|
||||
\title Query Model Example
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The Query Model example shows how to make customized versions of
|
||||
data obtained from a SQL query, using a model that encapsulates
|
||||
the query and table views to display the results.
|
||||
|
||||
\borderedimage querymodel-example.png
|
||||
*/
|
13
examples/sql/doc/src/relationaltablemodel.qdoc
Normal file
13
examples/sql/doc/src/relationaltablemodel.qdoc
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example relationaltablemodel
|
||||
\title Relational Table Model Example
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The Relational Table Model example shows how to use table views with a relational
|
||||
model to visualize the relations between items in a database.
|
||||
|
||||
\borderedimage relationaltablemodel-example.png
|
||||
*/
|
13
examples/sql/doc/src/sqlbrowser.qdoc
Normal file
13
examples/sql/doc/src/sqlbrowser.qdoc
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example sqlbrowser
|
||||
\title SQL Browser
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The SQL Browser example shows how a data browser can be used to visualize
|
||||
the results of SQL statements on a live database.
|
||||
|
||||
\borderedimage sqlbrowser-demo.png
|
||||
*/
|
162
examples/sql/doc/src/sqlwidgetmapper.qdoc
Normal file
162
examples/sql/doc/src/sqlwidgetmapper.qdoc
Normal file
@ -0,0 +1,162 @@
|
||||
// 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
|
||||
|
||||
\brief The SQL Widget Mapper example shows how to use a map information from a
|
||||
database to widgets on a form.
|
||||
|
||||
\borderedimage sql-widget-mapper.png
|
||||
|
||||
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.
|
||||
|
||||
\borderedimage widgetmapper-sql-mapping-table.png
|
||||
|
||||
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.)
|
||||
|
||||
\borderedimage widgetmapper-sql-mapping.png
|
||||
|
||||
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 is very similar to that of the
|
||||
\l{Simple Widget Mapper Example}:
|
||||
|
||||
\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 QItemDelegate 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{QItemDelegate::}{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 QItemDelegate::setEditorData()
|
||||
for widgets without the \c currentIndex property.
|
||||
|
||||
The \l{QItemDelegate::}{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}.
|
||||
*/
|
13
examples/sql/doc/src/tablemodel.qdoc
Normal file
13
examples/sql/doc/src/tablemodel.qdoc
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example tablemodel
|
||||
\title Table Model Example
|
||||
\ingroup sql_examples
|
||||
|
||||
\brief The Table Model example shows how to use a specialized SQL table model with table
|
||||
views to edit information in a database.
|
||||
|
||||
\borderedimage tablemodel-example.png
|
||||
*/
|
Reference in New Issue
Block a user