qt 6.5.1 original
222
examples/widgets/doc/dropsite.qdoc
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example draganddrop/dropsite
|
||||
\title Drop Site Example
|
||||
|
||||
\brief The example shows how to distinguish the various MIME formats available
|
||||
in a drag and drop operation.
|
||||
|
||||
\image dropsite-example.png Screenshot of the Drop Site example
|
||||
|
||||
The Drop Site example accepts drops from other applications, and displays
|
||||
the MIME formats provided by the drag object.
|
||||
|
||||
There are two classes, \c DropArea and \c DropSiteWindow, and a \c main()
|
||||
function in this example. A \c DropArea object is instantiated in
|
||||
\c DropSiteWindow; a \c DropSiteWindow object is then invoked in the
|
||||
\c main() function.
|
||||
|
||||
\section1 DropArea Class Definition
|
||||
|
||||
The \c DropArea class is a subclass of QLabel with a public slot,
|
||||
\c clear(), and a \c changed() signal.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.h DropArea header part1
|
||||
|
||||
In addition, \c DropArea contains reimplementations of four \l{QWidget}
|
||||
event handlers:
|
||||
|
||||
\list 1
|
||||
\li \l{QWidget::dragEnterEvent()}{dragEnterEvent()}
|
||||
\li \l{QWidget::dragMoveEvent()}{dragMoveEvent()}
|
||||
\li \l{QWidget::dragLeaveEvent()}{dragLeaveEvent()}
|
||||
\li \l{QWidget::dropEvent()}{dropEvent()}
|
||||
\endlist
|
||||
|
||||
These event handlers are further explained in the implementation of the
|
||||
\c DropArea class.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.h DropArea header part2
|
||||
|
||||
\section1 DropArea Class Implementation
|
||||
|
||||
In the \c DropArea constructor, we set the \l{QWidget::setMinimumSize()}
|
||||
{minimum size} to 200x200 pixels, the \l{QFrame::setFrameStyle()}
|
||||
{frame style} to both QFrame::Sunken and QFrame::StyledPanel, and we align
|
||||
its contents to the center.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp DropArea constructor
|
||||
|
||||
Also, we enable drop events in \c DropArea by setting the
|
||||
\l{QWidget::acceptDrops()}{acceptDrops} property to \c true. Then,
|
||||
we enable the \l{QWidget::autoFillBackground()}{autoFillBackground}
|
||||
property and invoke the \c clear() function.
|
||||
|
||||
The \l{QWidget::dragEnterEvent()}{dragEnterEvent()} event handler is
|
||||
called when a drag is in progress and the mouse enters the \c DropArea
|
||||
object. For the \c DropSite example, when the mouse enters \c DropArea,
|
||||
we set its text to "<drop content>" and highlight its background.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp dragEnterEvent() function
|
||||
|
||||
Then, we invoke \l{QDropEvent::acceptProposedAction()}
|
||||
{acceptProposedAction()} on \a event, setting the drop action to the one
|
||||
proposed. Lastly, we emit the \c changed() signal, with the data that was
|
||||
dropped and its MIME type information as a parameter.
|
||||
|
||||
For \l{QWidget::dragMoveEvent()}{dragMoveEvent()}, we just accept the
|
||||
proposed QDragMoveEvent object, \a event, with
|
||||
\l{QDropEvent::acceptProposedAction()}{acceptProposedAction()}.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp dragMoveEvent() function
|
||||
|
||||
The \c DropArea class's implementation of \l{QWidget::dropEvent()}
|
||||
{dropEvent()} extracts the \a{event}'s mime data and displays it
|
||||
accordingly.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp dropEvent() function part1
|
||||
|
||||
The \c mimeData object can contain one of the following objects: an image,
|
||||
HTML text, Markdown text, plain text, or a list of URLs.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp dropEvent() function part2
|
||||
|
||||
\list
|
||||
\li If \c mimeData contains an image, we display it in \c DropArea with
|
||||
\l{QLabel::setPixmap()}{setPixmap()}.
|
||||
\li If \c mimeData contains HTML, we display it with
|
||||
\l{QLabel::setText()}{setText()} and set \c{DropArea}'s text format
|
||||
as Qt::RichText.
|
||||
\li If \c mimeData contains Markdown, we display it with
|
||||
\l{QLabel::setText()}{setText()} and set \c{DropArea}'s text format
|
||||
as Qt::MarkdownText.
|
||||
\li If \c mimeData contains plain text, we display it with
|
||||
\l{QLabel::setText()}{setText()} and set \c{DropArea}'s text format
|
||||
as Qt::PlainText. In the event that \c mimeData contains URLs, we
|
||||
iterate through the list of URLs to display them on individual
|
||||
lines.
|
||||
\li If \c mimeData contains other types of objects, we set
|
||||
\c{DropArea}'s text, with \l{QLabel::setText()}{setText()} to
|
||||
"Cannot display data" to inform the user.
|
||||
\endlist
|
||||
|
||||
We then set \c{DropArea}'s \l{QWidget::backgroundRole()}{backgroundRole} to
|
||||
QPalette::Dark and we accept \c{event}'s proposed action.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp dropEvent() function part3
|
||||
|
||||
The \l{QWidget::dragLeaveEvent()}{dragLeaveEvent()} event handler is
|
||||
called when a drag is in progress and the mouse leaves the widget.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp dragLeaveEvent() function
|
||||
|
||||
For \c{DropArea}'s implementation, we clear invoke \c clear() and then
|
||||
accept the proposed event.
|
||||
|
||||
The \c clear() function sets the text in \c DropArea to "<drop content>"
|
||||
and sets the \l{QWidget::backgroundRole()}{backgroundRole} to
|
||||
QPalette::Dark. Lastly, it emits the \c changed() signal.
|
||||
|
||||
\snippet draganddrop/dropsite/droparea.cpp clear() function
|
||||
|
||||
\section1 DropSiteWindow Class Definition
|
||||
|
||||
The \c DropSiteWindow class contains a constructor and a public slot,
|
||||
\c updateFormatsTable().
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.h DropSiteWindow header
|
||||
|
||||
The class also contains a private instance of \c DropArea, \c dropArea,
|
||||
QLabel, \c abstractLabel, QTableWidget, \c formatsTable, QDialogButtonBox,
|
||||
\c buttonBox, and two QPushButton objects, \c clearButton and
|
||||
\c quitButton.
|
||||
|
||||
\section1 DropSiteWindow Class Implementation
|
||||
|
||||
In the constructor of \c DropSiteWindow, we instantiate \c abstractLabel
|
||||
and set its \l{QLabel::setWordWrap()}{wordWrap} property to \c true. We
|
||||
also call the \l{QLabel::adjustSize()}{adjustSize()} function to adjust
|
||||
\c{abstractLabel}'s size according to its contents.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp constructor part1
|
||||
|
||||
Then we instantiate \c dropArea and connect its \c changed() signal to
|
||||
\c{DropSiteWindow}'s \c updateFormatsTable() slot.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp constructor part2
|
||||
|
||||
We now set up the QTableWidget object, \c formatsTable. Its
|
||||
horizontal header is set using a QStringList object, \c labels. The number
|
||||
of columms are set to two and the table is not editable. Also, the
|
||||
\c{formatTable}'s horizontal header is formatted to ensure that its second
|
||||
column stretches to occupy additional space available.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp constructor part3
|
||||
|
||||
Three QPushButton objects, \c clearButton, \c copyButton, and \c quitButton,
|
||||
are instantiated and added to \c buttonBox - a QDialogButtonBox object. We
|
||||
use QDialogButtonBox here to ensure that the push buttons are presented in a
|
||||
layout that conforms to the platform's style.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp constructor part4
|
||||
|
||||
The \l{QPushButton::clicked()}{clicked()} signals for \c copyButton,
|
||||
\c clearButton, and \c quitButton are connected to \c copy(),
|
||||
\c clear() and \l{QWidget::close()}{close()}, respectively.
|
||||
|
||||
For the layout, we use a QVBoxLayout, \c mainLayout, to arrange our widgets
|
||||
vertically. We also set the window title to "Drop Site" and the minimum
|
||||
size to 350x500 pixels.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp constructor part5
|
||||
|
||||
We move on to the \c updateFormatsTable() function. This function updates
|
||||
the \c formatsTable, displaying the MIME formats of the object dropped onto
|
||||
the \c DropArea object. First, we set \l{QTableWidget}'s
|
||||
\l{QTableWidget::setRowCount()}{rowCount} property to 0. Then, we validate
|
||||
to ensure that the QMimeData object passed in is a valid object.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp updateFormatsTable() part1
|
||||
|
||||
Once we are sure that \c mimeData is valid, we iterate through its
|
||||
supported formats.
|
||||
|
||||
\note The \l{QMimeData::formats()}{formats()} function returns a
|
||||
QStringList object, containing all the formats supported by the
|
||||
\c mimeData.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp updateFormatsTable() part2
|
||||
|
||||
Within each iteration, we create a QTableWidgetItem, \c formatItem and we
|
||||
set its \l{QTableWidgetItem::setFlags()}{flags} to Qt::ItemIsEnabled, and
|
||||
its \l{QTableWidgetItem::setTextAlignment()}{text alignment} to Qt::AlignTop
|
||||
and Qt::AlignLeft.
|
||||
|
||||
A QString object, \c text, is customized to display data according to the
|
||||
contents of \c format. We invoke \l{QString}'s \l{QString::simplified()}
|
||||
{simplified()} function on \c text, to obtain a string that has no
|
||||
additional space before, after or in between words.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp updateFormatsTable() part3
|
||||
|
||||
If \c format contains a list of URLs, we iterate through them, using spaces
|
||||
to separate them. On the other hand, if \c format contains an image, we
|
||||
display the data by converting the text to hexadecimal.
|
||||
|
||||
\snippet draganddrop/dropsite/dropsitewindow.cpp updateFormatsTable() part4
|
||||
|
||||
Once \c text has been customized to contain the appropriate data, we insert
|
||||
both \c format and \c text into \c formatsTable with
|
||||
\l{QTableWidget::setItem()}{setItem()}. Lastly, we invoke
|
||||
\l{QTableView::resizeColumnToContents()}{resizeColumnToContents()} on
|
||||
\c{formatsTable}'s first column.
|
||||
|
||||
\section1 The main() Function
|
||||
|
||||
Within the \c main() function, we instantiate \c DropSiteWindow and invoke
|
||||
its \l{QWidget::show()}{show()} function.
|
||||
|
||||
\snippet draganddrop/dropsite/main.cpp main() function
|
||||
*/
|
BIN
examples/widgets/doc/images/addressbook-adddialog.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
examples/widgets/doc/images/addressbook-classes.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
examples/widgets/doc/images/addressbook-editdialog.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
examples/widgets/doc/images/addressbook-example.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/widgets/doc/images/addressbook-filemenu.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/widgets/doc/images/addressbook-newaddresstab.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
examples/widgets/doc/images/addressbook-signals.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
examples/widgets/doc/images/addressbook-toolsmenu.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/widgets/doc/images/analogclock-viewport.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
examples/widgets/doc/images/basicgraphicslayouts-example.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
examples/widgets/doc/images/basiclayouts-example.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/widgets/doc/images/calendar-example.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
examples/widgets/doc/images/collidingmice-example.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
examples/widgets/doc/images/completer-example-country.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
examples/widgets/doc/images/completer-example-word.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
examples/widgets/doc/images/completer-example.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
examples/widgets/doc/images/draganddroppuzzle-example.png
Normal file
After Width: | Height: | Size: 253 KiB |
BIN
examples/widgets/doc/images/dropsite-example.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
examples/widgets/doc/images/echoplugin.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
examples/widgets/doc/images/echopluginexample.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
examples/widgets/doc/images/fademessageeffect-example-faded.png
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
examples/widgets/doc/images/fademessageeffect-example.png
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
examples/widgets/doc/images/fridgemagnets-example.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
examples/widgets/doc/images/geometry.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
examples/widgets/doc/images/graphicsflowlayout-example.png
Normal file
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
examples/widgets/doc/images/icons_monkey.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
examples/widgets/doc/images/icons_monkey_mess.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
examples/widgets/doc/images/icons_qt_extended_16x16.png
Normal file
After Width: | Height: | Size: 563 B |
BIN
examples/widgets/doc/images/icons_qt_extended_17x17.png
Normal file
After Width: | Height: | Size: 605 B |
BIN
examples/widgets/doc/images/icons_qt_extended_32x32.png
Normal file
After Width: | Height: | Size: 916 B |
BIN
examples/widgets/doc/images/icons_qt_extended_33x33.png
Normal file
After Width: | Height: | Size: 975 B |
BIN
examples/widgets/doc/images/icons_qt_extended_48x48.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
examples/widgets/doc/images/icons_qt_extended_64x64.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
examples/widgets/doc/images/icons_qt_extended_8x8.png
Normal file
After Width: | Height: | Size: 340 B |
BIN
examples/widgets/doc/images/imagegestures-example.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
examples/widgets/doc/images/imageviewer-fit_to_window_1.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
examples/widgets/doc/images/imageviewer-fit_to_window_2.png
Normal file
After Width: | Height: | Size: 143 KiB |
BIN
examples/widgets/doc/images/imageviewer-original_size.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
examples/widgets/doc/images/imageviewer-zoom_in_1.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
examples/widgets/doc/images/imageviewer-zoom_in_2.png
Normal file
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 22 KiB |
BIN
examples/widgets/doc/images/itemviews-editabletreemodel.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
examples/widgets/doc/images/itemviewspuzzle-example.png
Normal file
After Width: | Height: | Size: 192 KiB |
BIN
examples/widgets/doc/images/layout1.png
Normal file
After Width: | Height: | Size: 106 B |
BIN
examples/widgets/doc/images/layout2.png
Normal file
After Width: | Height: | Size: 233 B |
BIN
examples/widgets/doc/images/mainwindow-demo.png
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
examples/widgets/doc/images/notepad.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
examples/widgets/doc/images/notepad1.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
examples/widgets/doc/images/notepad2.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
examples/widgets/doc/images/notepad3.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/widgets/doc/images/notepad4.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
examples/widgets/doc/images/notepad_menu.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
examples/widgets/doc/images/orderform-example.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
examples/widgets/doc/images/plugandpaint-plugindialog.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
examples/widgets/doc/images/plugandpaint.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
examples/widgets/doc/images/regexp-example.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
examples/widgets/doc/images/regularexpression-example.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
examples/widgets/doc/images/settingseditor-example.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
examples/widgets/doc/images/sipdialog-closed.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
examples/widgets/doc/images/sipdialog-opened.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
examples/widgets/doc/images/stylepluginexample.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
examples/widgets/doc/images/stylesheet-pagefold.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
examples/widgets/doc/images/systemtray-editor.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
examples/widgets/doc/images/systemtray-example.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
examples/widgets/doc/images/textedit-demo.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
examples/widgets/doc/images/treemodel-structure.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
examples/widgets/doc/images/treemodelcompleter-example.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
examples/widgets/doc/images/undoframeworkexample.png
Normal file
After Width: | Height: | Size: 18 KiB |
948
examples/widgets/doc/src/addressbook-tutorial.qdoc
Normal file
@ -0,0 +1,948 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\page tutorials-addressbook.html
|
||||
|
||||
\title Address Book Tutorial
|
||||
\ingroup examples-layout
|
||||
\brief An introduction to GUI programming, showing how to put together a
|
||||
simple yet fully-functioning application.
|
||||
|
||||
This tutorial is an introduction to GUI programming with the Qt
|
||||
cross-platform framework.
|
||||
|
||||
\image addressbook-tutorial-screenshot.png
|
||||
|
||||
\omit
|
||||
It doesn't cover everything; the emphasis is on teaching the programming
|
||||
philosophy of GUI programming, and Qt's features are introduced as needed.
|
||||
Some commonly used features are never used in this tutorial.
|
||||
\endomit
|
||||
|
||||
In this tutorial, you will learn about some of the basic
|
||||
components of Qt, including:
|
||||
|
||||
\list
|
||||
\li Widgets and layout managers
|
||||
\li Container classes
|
||||
\li Signals and slots
|
||||
\li Input and output devices
|
||||
\endlist
|
||||
|
||||
Tutorial contents:
|
||||
|
||||
\list 1
|
||||
\li \l{tutorials/addressbook/part1}{Designing the User Interface}
|
||||
\li \l{tutorials/addressbook/part2}{Adding Addresses}
|
||||
\li \l{tutorials/addressbook/part3}{Navigating between Entries}
|
||||
\li \l{tutorials/addressbook/part4}{Editing and Removing Addresses}
|
||||
\li \l{tutorials/addressbook/part5}{Adding a Find Function}
|
||||
\li \l{tutorials/addressbook/part6}{Loading and Saving}
|
||||
\li \l{tutorials/addressbook/part7}{Additional Features}
|
||||
\endlist
|
||||
|
||||
The tutorial source code is located in \c{tutorials/addressbook}.
|
||||
|
||||
Although this little application does not look much like a
|
||||
fully-fledged modern GUI application, it uses many of the basic
|
||||
elements that are used in more complex applications. After you
|
||||
have worked through this tutorial, we recommend reading the
|
||||
\l{mainwindows/application}{Application} example, which presents a
|
||||
small GUI application, with menus, toolbars, a status bar, and so
|
||||
on.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part1
|
||||
\title Part 1 - Designing the User Interface
|
||||
\brief Describes how to code the user interface of the Address Book Example.
|
||||
This first part covers the design of the basic graphical user
|
||||
interface (GUI) for our address book application.
|
||||
|
||||
The first step in creating a GUI program is to design the user
|
||||
interface. Here the our goal is to set up the labels and input
|
||||
fields to implement a basic address book. The figure below is a
|
||||
screenshot of the expected output.
|
||||
|
||||
\image addressbook-tutorial-part1-screenshot.png
|
||||
|
||||
We require two QLabel objects, \c nameLabel and \c addressLabel, as well
|
||||
as two input fields, a QLineEdit object, \c nameLine, and a QTextEdit
|
||||
object, \c addressText, to enable the user to enter a contact's name and
|
||||
address. The widgets used and their positions are shown in the figure
|
||||
below.
|
||||
|
||||
\image addressbook-tutorial-part1-labeled-screenshot.png
|
||||
|
||||
There are three files used to implement this address book:
|
||||
|
||||
\list
|
||||
\li \c{addressbook.h} - the definition file for the \c AddressBook
|
||||
class,
|
||||
\li \c{addressbook.cpp} - the implementation file for the
|
||||
\c AddressBook class, and
|
||||
\li \c{main.cpp} - the file containing a \c main() function, with
|
||||
an instance of \c AddressBook.
|
||||
\endlist
|
||||
|
||||
\section1 Qt Programming - Subclassing
|
||||
|
||||
When writing Qt programs, we usually subclass Qt objects to add
|
||||
functionality. This is one of the essential concepts behind creating
|
||||
custom widgets or collections of standard widgets. Subclassing to
|
||||
extend or change the behavior of a widget has the following advantages:
|
||||
|
||||
\list
|
||||
\li We can write implementations of virtual or pure virtual functions to
|
||||
obtain exactly what we need, falling back on the base class's implementation
|
||||
when necessary.
|
||||
\li It allows us to encapsulate parts of the user interface within a class,
|
||||
so that the other parts of the application don't need to know about the
|
||||
individual widgets in the user interface.
|
||||
\li The subclass can be used to create multiple custom widgets in the same
|
||||
application or library, and the code for the subclass can be reused in other
|
||||
projects.
|
||||
\endlist
|
||||
|
||||
Since Qt does not provide a specific address book widget, we subclass a
|
||||
standard Qt widget class and add features to it. The \c AddressBook class
|
||||
we create in this tutorial can be reused in situations where a basic address
|
||||
book widget is needed.
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
The \c{tutorials/addressbook/part1/addressbook.h} file is
|
||||
used to define the \c AddressBook class.
|
||||
|
||||
We start by defining \c AddressBook as a QWidget subclass and declaring
|
||||
a constructor. We also use the Q_OBJECT macro to indicate that the class
|
||||
uses internationalization and Qt's signals and slots features, even
|
||||
if we do not use all of these features at this stage.
|
||||
|
||||
\snippet tutorials/addressbook/part1/addressbook.h class definition
|
||||
|
||||
The class holds declarations of \c nameLine and \c addressText,
|
||||
the private instances of QLineEdit and QTextEdit mentioned
|
||||
earlier. The data stored in \c nameLine and \c addressText will
|
||||
be needed for many of the address book functions.
|
||||
|
||||
We don't include declarations of the QLabel objects we will use
|
||||
because we will not need to reference them once they have been
|
||||
created. The way Qt tracks the ownership of objects is explained
|
||||
in the next section.
|
||||
|
||||
The Q_OBJECT macro itself implements some of the more advanced features of Qt.
|
||||
For now, it is useful to think of the Q_OBJECT macro as a shortcut which allows
|
||||
us to use the \l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
|
||||
|
||||
We have now completed the \c addressbook.h file and we move on to
|
||||
implement the corresponding \c addressbook.cpp file.
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
The constructor of \c AddressBook accepts a QWidget parameter, \a parent.
|
||||
By convention, we pass this parameter to the base class's constructor.
|
||||
This concept of ownership, where a parent can have one or more children,
|
||||
is useful for grouping widgets in Qt. For example, if you delete a parent,
|
||||
all of its children will be deleted as well.
|
||||
|
||||
\snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
|
||||
|
||||
In this constructor, the QLabel objects \c nameLabel and \c
|
||||
addressLabel are instantiated, as well as \c nameLine and \c
|
||||
addressText. The \l{QObject::tr()}{tr()} function returns a
|
||||
translated version of the string, if there is one
|
||||
available. Otherwise it returns the string itself. This function
|
||||
marks its QString parameter as one that should be translated into
|
||||
other languages. It should be used wherever a translatable string
|
||||
appears.
|
||||
|
||||
When programming with Qt, it is useful to know how layouts work.
|
||||
Qt provides three main layout classes: QHBoxLayout, QVBoxLayout
|
||||
and QGridLayout to handle the positioning of widgets.
|
||||
|
||||
\image addressbook-tutorial-part1-labeled-layout.png
|
||||
|
||||
We use a QGridLayout to position our labels and input fields in a
|
||||
structured manner. QGridLayout divides the available space into a grid and
|
||||
places widgets in the cells we specify with row and column numbers. The
|
||||
diagram above shows the layout cells and the position of our widgets, and
|
||||
we specify this arrangement using the following code:
|
||||
|
||||
\snippet tutorials/addressbook/part1/addressbook.cpp layout
|
||||
|
||||
Notice that \c addressLabel is positioned using Qt::AlignTop as an
|
||||
additional argument. This is to make sure it is not vertically centered in
|
||||
cell (1,0). For a basic overview on Qt Layouts, refer to the
|
||||
\l{Layout Management} documentation.
|
||||
|
||||
In order to install the layout object onto the widget, we have to invoke
|
||||
the widget's \l{QWidget::setLayout()}{setLayout()} function:
|
||||
|
||||
\snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
|
||||
|
||||
Lastly, we set the widget's title to "Simple Address Book".
|
||||
|
||||
\section1 Running the Application
|
||||
|
||||
A separate file, \c main.cpp, is used for the \c main() function. Within
|
||||
this function, we instantiate a QApplication object, \c app. QApplication
|
||||
is responsible for various application-wide resources, such as the default
|
||||
font and cursor, and for running an event loop. Hence, there is always one
|
||||
QApplication object in every GUI application using Qt.
|
||||
|
||||
\snippet tutorials/addressbook/part1/main.cpp main function
|
||||
|
||||
We construct a new \c AddressBook widget on the stack and invoke
|
||||
its \l{QWidget::show()}{show()} function to display it.
|
||||
However, the widget will not be shown until the application's event loop
|
||||
is started. We start the event loop by calling the application's
|
||||
\l{QApplication::}{exec()} function; the result returned by this function
|
||||
is used as the return value from the \c main() function. At this point,
|
||||
it becomes apparent why we instantiated \c AddressBook on the stack: It
|
||||
will now go out of scope. Therefore, \c AddressBook and all its child widgets
|
||||
will be deleted, thus preventing memory leaks.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part2
|
||||
\title Part 2 - Adding Addresses
|
||||
\brief Describes the code for inserting records in the Address Book Example.
|
||||
|
||||
The next step in creating the address book is to implement some
|
||||
user interactions.
|
||||
|
||||
\image addressbook-tutorial-part2-add-contact.png
|
||||
|
||||
We will provide a push button that the user can click to add a new contact.
|
||||
Also, some form of data structure is needed to store these contacts in an
|
||||
organized way.
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
Now that we have the labels and input fields set up, we add push buttons to
|
||||
complete the process of adding a contact. This means that our
|
||||
\c addressbook.h file now has three QPushButton objects declared and three
|
||||
corresponding public slots.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.h slots
|
||||
|
||||
A slot is a function that responds to a particular signal. We will discuss
|
||||
this concept in further detail when implementing the \c AddressBook class.
|
||||
However, for an overview of Qt's signals and slots concept, you can refer
|
||||
to the \l{Signals and Slots} document.
|
||||
|
||||
Three QPushButton objects (\c addButton, \c submitButton, and
|
||||
\c cancelButton) are now included in our private variable declarations,
|
||||
along with \c nameLine and \c addressText.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
|
||||
|
||||
We need a container to store our address book contacts, so that we can
|
||||
traverse and display them. A QMap object, \c contacts, is used for this
|
||||
purpose as it holds a key-value pair: the contact's name as the \e key,
|
||||
and the contact's address as the \e{value}.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.h remaining private variables
|
||||
|
||||
We also declare two private QString objects, \c oldName and \c oldAddress.
|
||||
These objects are needed to hold the name and address of the contact that
|
||||
was last displayed, before the user clicked \uicontrol Add. So, when the user clicks
|
||||
\uicontrol Cancel, we can revert to displaying the details of the last contact.
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
Within the constructor of \c AddressBook, we set the \c nameLine and
|
||||
\c addressText to read-only, so that we can only display but not edit
|
||||
existing contact details.
|
||||
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
|
||||
|
||||
Then, we instantiate our push buttons: \c addButton, \c submitButton, and
|
||||
\c cancelButton.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
|
||||
|
||||
The \c addButton is displayed by invoking the \l{QPushButton::show()}
|
||||
{show()} function, while the \c submitButton and \c cancelButton are
|
||||
hidden by invoking \l{QPushButton::hide()}{hide()}. These two push
|
||||
buttons will only be displayed when the user clicks \uicontrol Add and this is
|
||||
handled by the \c addContact() function discussed below.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
|
||||
|
||||
We connect the push buttons' \l{QPushButton::clicked()}{clicked()} signal
|
||||
to their respective slots. The figure below illustrates this.
|
||||
|
||||
\image addressbook-tutorial-part2-signals-and-slots.png
|
||||
|
||||
Next, we arrange our push buttons neatly to the right of our address book
|
||||
widget, using a QVBoxLayout to line them up vertically.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
|
||||
|
||||
The \l{QBoxLayout::addStretch()}{addStretch()} function is used to ensure
|
||||
the push buttons are not evenly spaced, but arranged closer to the top of
|
||||
the widget. The figure below shows the difference between using
|
||||
\l{QBoxLayout::addStretch()}{addStretch()} and not using it.
|
||||
|
||||
\image addressbook-tutorial-part2-stretch-effects.png
|
||||
|
||||
We then add \c buttonLayout1 to \c mainLayout, using
|
||||
\l{QGridLayout::addLayout()}{addLayout()}. This gives us nested layouts
|
||||
as \c buttonLayout1 is now a child of \c mainLayout.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp grid layout
|
||||
|
||||
Our layout coordinates now look like this:
|
||||
|
||||
\image addressbook-tutorial-part2-labeled-layout.png
|
||||
|
||||
In the \c addContact() function, we store the last displayed contact
|
||||
details in \c oldName and \c oldAddress. Then we clear these input
|
||||
fields and turn off the read-only mode. The focus is set on \c nameLine
|
||||
and we display \c submitButton and \c cancelButton.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp addContact
|
||||
|
||||
The \c submitContact() function can be divided into three parts:
|
||||
|
||||
\list 1
|
||||
\li We extract the contact's details from \c nameLine and \c addressText
|
||||
and store them in QString objects. We also validate to make sure that the
|
||||
user did not click \uicontrol Submit with empty input fields; otherwise, a
|
||||
QMessageBox is displayed to remind the user for a name and address.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
|
||||
|
||||
\li We then proceed to check if the contact already exists. If it does not
|
||||
exist, we add the contact to \c contacts and we display a QMessageBox to
|
||||
inform the user that the contact has been added.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
|
||||
|
||||
If the contact already exists, again, we display a QMessageBox to inform
|
||||
the user about this, preventing the user from adding duplicate contacts.
|
||||
Our \c contacts object is based on key-value pairs of name and address,
|
||||
hence, we want to ensure that \e key is unique.
|
||||
|
||||
\li Once we have handled both cases mentioned above, we restore the push
|
||||
buttons to their normal state with the following code:
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
|
||||
|
||||
\endlist
|
||||
|
||||
The screenshot below shows the QMessageBox object we use to display
|
||||
information messages to the user.
|
||||
|
||||
\image addressbook-tutorial-part2-add-successful.png
|
||||
|
||||
The \c cancel() function restores the last displayed contact details and
|
||||
enables \c addButton, as well as hides \c submitButton and
|
||||
\c cancelButton.
|
||||
|
||||
\snippet tutorials/addressbook/part2/addressbook.cpp cancel
|
||||
|
||||
The general idea behind adding a contact is to give the user the
|
||||
flexibility to click \uicontrol Submit or \uicontrol Cancel at any time. The flowchart below
|
||||
further explains this concept:
|
||||
|
||||
\image addressbook-tutorial-part2-add-flowchart.png
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part3
|
||||
\title Part 3 - Navigating between Entries
|
||||
\brief Explains the code that enables navigating the contacts.
|
||||
|
||||
The address book is now about half complete. We should add the
|
||||
capability to navigate the contacts, but first we must
|
||||
decide what sort of a data structure we need for containing these
|
||||
contacts.
|
||||
|
||||
In the previous section, we used a QMap of key-value pairs with
|
||||
the contact's name as the \e key, and the contact's address as the
|
||||
\e value. This works well for our case. However, in order to
|
||||
navigate and display each entry, a little bit of enhancement is
|
||||
needed.
|
||||
|
||||
We enhance the QMap by making it replicate a data structure similar to a
|
||||
circularly-linked list, where all elements are connected, including the
|
||||
first element and the last element. The figure below illustrates this data
|
||||
structure.
|
||||
|
||||
\image addressbook-tutorial-part3-linkedlist.png
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
To add navigation functions to the address book, we must add two
|
||||
more slots to the \c AddressBook class: \c next() and \c
|
||||
previous() to the \c addressbook.h file:
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.h navigation functions
|
||||
|
||||
We also require another two QPushButton objects, so we declare \c nextButton
|
||||
and \c previousButton as private variables:
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
In the \c AddressBook constructor in \c addressbook.cpp, we instantiate
|
||||
\c nextButton and \c previousButton and disable them by default. This is
|
||||
because navigation is only enabled when there is more than one contact
|
||||
in the address book.
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
|
||||
|
||||
We then connect these push buttons to their respective slots:
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
|
||||
|
||||
The image below is the expected graphical user interface.
|
||||
|
||||
\image addressbook-tutorial-part3-screenshot.png
|
||||
|
||||
We follow basic conventions for \c next() and \c previous() functions by
|
||||
placing the \c nextButton on the right and the \c previousButton on the
|
||||
left. In order to achieve this intuitive layout, we use QHBoxLayout to
|
||||
place the widgets side-by-side:
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
|
||||
|
||||
The QHBoxLayout object, \c buttonLayout2, is then added to \c mainLayout.
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
|
||||
|
||||
The figure below shows the coordinates of the widgets in \c mainLayout.
|
||||
\image addressbook-tutorial-part3-labeled-layout.png
|
||||
|
||||
Within our \c addContact() function, we have to disable these buttons so
|
||||
that the user does not attempt to navigate while adding a contact.
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
|
||||
|
||||
Also, in our \c submitContact() function, we enable the navigation
|
||||
buttons, \c nextButton and \c previousButton, depending on the size
|
||||
of \c contacts. As mentioned earlier, navigation is only enabled when
|
||||
there is more than one contact in the address book. The following lines
|
||||
of code demonstrates how to do this:
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
|
||||
|
||||
We also include these lines of code in the \c cancel() function.
|
||||
|
||||
Recall that we intend to emulate a circularly-linked list with our QMap
|
||||
object, \c contacts. So, in the \c next() function, we obtain an iterator
|
||||
for \c contacts and then:
|
||||
|
||||
\list
|
||||
\li If the iterator is not at the end of \c contacts, we increment it
|
||||
by one.
|
||||
\li If the iterator is at the end of \c contacts, we move it to the
|
||||
beginning of \c contacts. This gives us the illusion that our QMap is
|
||||
working like a circularly-linked list.
|
||||
\endlist
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp next() function
|
||||
|
||||
Once we have iterated to the correct object in \c contacts, we display
|
||||
its contents on \c nameLine and \c addressText.
|
||||
|
||||
Similarly, for the \c previous() function, we obtain an iterator for
|
||||
\c contacts and then:
|
||||
|
||||
\list
|
||||
\li If the iterator is at the end of \c contacts, we clear the
|
||||
display and return.
|
||||
\li If the iterator is at the beginning of \c contacts, we move it to
|
||||
the end.
|
||||
\li We then decrement the iterator by one.
|
||||
\endlist
|
||||
|
||||
\snippet tutorials/addressbook/part3/addressbook.cpp previous() function
|
||||
|
||||
Again, we display the contents of the current object in \c contacts.
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part4
|
||||
\title Part 4 - Editing and Removing Addresses
|
||||
\brief Explains how to add edit and remove functionality.
|
||||
|
||||
Now we look at ways to modify the contents of contacts stored in
|
||||
the address book.
|
||||
|
||||
\image addressbook-tutorial-screenshot.png
|
||||
|
||||
We now have an address book that not only holds contacts in an
|
||||
organized manner, but also allows navigation. It would be
|
||||
convenient to include edit and remove functions so that a
|
||||
contact's details can be changed when needed. However, this
|
||||
requires a little improvement, in the form of enums. We defined
|
||||
two modes: \c{AddingMode} and \c{NavigationMode}, but they were
|
||||
not defined as enum values. Instead, we enabled and disabled the
|
||||
corresponding buttons manually, resulting in multiple lines of
|
||||
repeated code.
|
||||
|
||||
Here we define the \c Mode enum with three different values:
|
||||
|
||||
\list
|
||||
\li \c{NavigationMode},
|
||||
\li \c{AddingMode}, and
|
||||
\li \c{EditingMode}.
|
||||
\endlist
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
The \c addressbook.h file is updated to contain the \c Mode enum:
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.h Mode enum
|
||||
|
||||
We also add two new slots, \c editContact() and \c removeContact(), to
|
||||
our current list of public slots.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
|
||||
|
||||
In order to switch between modes, we introduce the \c updateInterface() function
|
||||
to control the enabling and disabling of all QPushButton objects. We also
|
||||
add two new push buttons, \c editButton and \c removeButton, for the edit
|
||||
and remove functions mentioned earlier.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part4/addressbook.h buttons declaration
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part4/addressbook.h mode declaration
|
||||
|
||||
Lastly, we declare \c currentMode to keep track of the enum's current mode.
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
We now implement the mode-changing features of the address
|
||||
book. The \c editButton and \c removeButton are instantiated and
|
||||
disabled by default. The address book starts with zero contacts
|
||||
in memory.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
|
||||
|
||||
These buttons are then connected to their respective slots, \c editContact()
|
||||
and \c removeContact(), and we add them to \c buttonLayout1.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
|
||||
|
||||
The \c editContact() function stores the contact's old details in
|
||||
\c oldName and \c oldAddress, before switching the mode to \c EditingMode.
|
||||
In this mode, the \c submitButton and \c cancelButton are both enabled,
|
||||
hence, the user can change the contact's details and click either button.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
|
||||
|
||||
The \c submitContact() function has been divided in two with an \c{if-else}
|
||||
statement. We check \c currentMode to see if it's in \c AddingMode. If it is,
|
||||
we proceed with our adding process.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
|
||||
|
||||
Otherwise, we check to see if \c currentMode is in \c EditingMode. If it
|
||||
is, we compare \c oldName with \c name. If the name has changed, we remove
|
||||
the old contact from \c contacts and insert the newly updated contact.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
|
||||
|
||||
If only the address has changed (i.e., \c oldAddress is not the same as \c address),
|
||||
we update the contact's address. Lastly, we set \c currentMode to
|
||||
\c NavigationMode. This is an important step as it re-enables all the
|
||||
disabled push buttons.
|
||||
|
||||
To remove a contact from the address book, we implement the
|
||||
\c removeContact() function. This function checks to see if the contact
|
||||
exists in \c contacts.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
|
||||
|
||||
If it does, we display a QMessageBox, to confirm the removal with the
|
||||
user. Once the user has confirmed, we call \c previous() to ensure that the
|
||||
user interface shows another contact, and we remove the contact using \l{QMap}'s
|
||||
\l{QMap::remove()}{remove()} function. As a courtesy, we display a QMessageBox
|
||||
to inform the user. Both the message boxes used in this function are shown below:
|
||||
|
||||
\image addressbook-tutorial-part4-remove.png
|
||||
|
||||
\section2 Updating the User Interface
|
||||
|
||||
We mentioned the \c updateInterface() function earlier as a means to
|
||||
enable and disable the push buttons depending on the current mode.
|
||||
The function updates the current mode according to the \c mode argument
|
||||
passed to it, assigning it to \c currentMode before checking its value.
|
||||
|
||||
Each of the push buttons is then enabled or disabled, depending on the
|
||||
current mode. The code for \c AddingMode and \c EditingMode is shown below:
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
|
||||
|
||||
For \c NavigationMode, however, we include conditions within the parameters
|
||||
of the QPushButton::setEnabled() function. This is to ensure that
|
||||
\c editButton and \c removeButton are enabled when there is at least one
|
||||
contact in the address book; \c nextButton and \c previousButton are only
|
||||
enabled when there is more than one contact in the address book.
|
||||
|
||||
\snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
|
||||
|
||||
By setting the mode and updating the user interface in the same
|
||||
function, we avoid the possibility of the user interface getting
|
||||
out of sync with the internal state of the application.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part5
|
||||
\title Part 5 - Adding a Find Function
|
||||
\brief Describes how to add a find function.
|
||||
|
||||
Here we look at ways to locate contacts and addresses in the
|
||||
address book.
|
||||
|
||||
\image addressbook-tutorial-part5-screenshot.png
|
||||
|
||||
As we add contacts to our address book, it becomes tedious to
|
||||
navigate the list with the \e Next and \e Previous buttons. A \e
|
||||
Find function would be more efficient. The screenshot above shows
|
||||
the \e Find button and its position on the panel of buttons.
|
||||
|
||||
When the user clicks on the \e Find button, it is useful to
|
||||
display a dialog that prompts for a contact's name. Qt provides
|
||||
QDialog, which we subclass here to implement a \c FindDialog
|
||||
class.
|
||||
|
||||
\section1 Defining the FindDialog Class
|
||||
|
||||
\image addressbook-tutorial-part5-finddialog.png
|
||||
|
||||
In order to subclass QDialog, we first include the header for QDialog in
|
||||
the \c finddialog.h file. Also, we use forward declaration to declare
|
||||
QLineEdit and QPushButton since we will be using those widgets in our
|
||||
dialog class.
|
||||
|
||||
As in our \c AddressBook class, the \c FindDialog class includes
|
||||
the Q_OBJECT macro and its constructor is defined to accept a parent
|
||||
QWidget, even though the dialog will be opened as a separate window.
|
||||
|
||||
\snippet tutorials/addressbook/part5/finddialog.h FindDialog header
|
||||
|
||||
We define a public function, \c getFindText(), to be used by classes that
|
||||
instantiate \c FindDialog. This function allows these classes to obtain the
|
||||
search string entered by the user. A public slot, \c findClicked(), is also
|
||||
defined to handle the search string when the user clicks the \uicontrol Find
|
||||
button.
|
||||
|
||||
Lastly, we define the private variables, \c findButton, \c lineEdit
|
||||
and \c findText, corresponding to the \uicontrol Find button, the line edit
|
||||
into which the user types the search string, and an internal string
|
||||
used to store the search string for later use.
|
||||
|
||||
\section1 Implementing the FindDialog Class
|
||||
|
||||
Within the constructor of \c FindDialog, we set up the private variables,
|
||||
\c lineEdit, \c findButton and \c findText. We use a QHBoxLayout to
|
||||
position the widgets.
|
||||
|
||||
\snippet tutorials/addressbook/part5/finddialog.cpp constructor
|
||||
|
||||
We set the layout and window title, as well as connect the signals to their
|
||||
respective slots. Notice that \c{findButton}'s \l{QPushButton::clicked()}
|
||||
{clicked()} signal is connected to \c findClicked() and
|
||||
\l{QDialog::accept()}{accept()}. The \l{QDialog::accept()}{accept()} slot
|
||||
provided by QDialog hides the dialog and sets the result code to
|
||||
\l{QDialog::}{Accepted}. We use this function to help \c{AddressBook}'s
|
||||
\c findContact() function know when the \c FindDialog object has been
|
||||
closed. We will explain this logic in further detail when discussing the
|
||||
\c findContact() function.
|
||||
|
||||
\image addressbook-tutorial-part5-signals-and-slots.png
|
||||
|
||||
In \c findClicked(), we validate \c lineEdit to ensure that the user
|
||||
did not click the \uicontrol Find button without entering a contact's name. Then, we set
|
||||
\c findText to the search string, extracted from \c lineEdit. After that,
|
||||
we clear the contents of \c lineEdit and hide the dialog.
|
||||
|
||||
\snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
|
||||
|
||||
The \c findText variable has a public getter function, \c getFindText(),
|
||||
associated with it. Since we only ever set \c findText directly in both the
|
||||
constructor and in the \c findClicked() function, we do not create a
|
||||
setter function to accompany \c getFindText().
|
||||
Because \c getFindText() is public, classes instantiating and using
|
||||
\c FindDialog can always access the search string that the user has
|
||||
entered and accepted.
|
||||
|
||||
\snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
To ensure we can use \c FindDialog from within our \c AddressBook class, we
|
||||
include \c finddialog.h in the \c addressbook.h file.
|
||||
|
||||
\snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
|
||||
|
||||
So far, all our address book features have a QPushButton and a
|
||||
corresponding slot. Similarly, for the \uicontrol Find feature we have
|
||||
\c findButton and \c findContact().
|
||||
|
||||
The \c findButton is declared as a private variable and the
|
||||
\c findContact() function is declared as a public slot.
|
||||
|
||||
\snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part5/addressbook.h findButton declaration
|
||||
|
||||
Lastly, we declare the private variable, \c dialog, which we will use to
|
||||
refer to an instance of \c FindDialog.
|
||||
|
||||
\snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
|
||||
|
||||
Once we have instantiated a dialog, we will want to use it more than once;
|
||||
using a private variable allows us to refer to it from more than one place
|
||||
in the class.
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
Within the \c AddressBook class's constructor, we instantiate our private
|
||||
objects, \c findButton and \c findDialog:
|
||||
|
||||
\snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
|
||||
|
||||
Next, we connect the \c{findButton}'s
|
||||
\l{QPushButton::clicked()}{clicked()} signal to \c findContact().
|
||||
|
||||
\snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
|
||||
|
||||
Now all that is left is the code for our \c findContact() function:
|
||||
|
||||
\snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
|
||||
|
||||
We start out by displaying the \c FindDialog instance, \c dialog. This is
|
||||
when the user enters a contact name to look up. Once the user clicks
|
||||
the dialog's \c findButton, the dialog is hidden and the result code is
|
||||
set to QDialog::Accepted. This ensures that
|
||||
our \c if statement is always true.
|
||||
|
||||
We then proceed to extract the search string, which in this case is
|
||||
\c contactName, using \c{FindDialog}'s \c getFindText() function. If the
|
||||
contact exists in our address book, we display it immediately. Otherwise,
|
||||
we display the QMessageBox shown below to indicate that their search
|
||||
failed.
|
||||
|
||||
\image addressbook-tutorial-part5-notfound.png
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part6
|
||||
\title Part 6 - Loading and Saving
|
||||
\brief Describes how to add save and load functionality.
|
||||
|
||||
This part covers the Qt file handling features we use to write
|
||||
loading and saving routines for the address book.
|
||||
|
||||
\image addressbook-tutorial-part6-screenshot.png
|
||||
|
||||
Although browsing and searching the contact list are useful
|
||||
features, our address book is not complete until we can save
|
||||
existing contacts and load them again at a later time.
|
||||
|
||||
Qt provides a number of classes for \l{Input/Output and Networking}
|
||||
{input and output}, but we have chosen to use two which are simple to use
|
||||
in combination: QFile and QDataStream.
|
||||
|
||||
A QFile object represents a file on disk that can be read from and written
|
||||
to. QFile is a subclass of the more general QIODevice class which
|
||||
represents many different kinds of devices.
|
||||
|
||||
A QDataStream object is used to serialize binary data so that it can be
|
||||
stored in a QIODevice and retrieved again later. Reading from a QIODevice
|
||||
and writing to it is as simple as opening the stream - with the respective
|
||||
device as a parameter - and reading from or writing to it.
|
||||
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
We declare two public slots, \c saveToFile() and \c loadFromFile(), as well
|
||||
as two QPushButton objects, \c loadButton and \c saveButton.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
In our constructor, we instantiate \c loadButton and \c saveButton.
|
||||
Ideally, it would be more user-friendly to set the push buttons' labels
|
||||
to "Load contacts from a file" and "Save contacts to a file". However, due
|
||||
to the size of our other push buttons, we set the labels to \uicontrol{Load...}
|
||||
and \uicontrol{Save...}. Fortunately, Qt provides a simple way to set tooltips with
|
||||
\l{QWidget::setToolTip()}{setToolTip()} and we use it in the following way
|
||||
for our push buttons:
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
|
||||
|
||||
Although it is not shown here, just like the other features we implemented,
|
||||
we add the push buttons to the layout panel on the right, \c buttonLayout1,
|
||||
and we connect the push buttons' \l{QPushButton::clicked()}{clicked()}
|
||||
signals to their respective slots.
|
||||
|
||||
For the saving feature, we first obtain \c fileName using
|
||||
QFileDialog::getSaveFileName(). This is a convenience function provided
|
||||
by QFileDialog, which pops up a modal file dialog and allows the user to
|
||||
enter a file name or select any existing \c{.abk} file. The \c{.abk} file
|
||||
is our Address Book extension that we create when we save contacts.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
|
||||
|
||||
The file dialog that pops up is displayed in the screenshot below:
|
||||
|
||||
\image addressbook-tutorial-part6-save.png
|
||||
|
||||
If \c fileName is not empty, we create a QFile object, \c file, with
|
||||
\c fileName. QFile works with QDataStream as QFile is a QIODevice.
|
||||
|
||||
Next, we attempt to open the file in \l{QIODeviceBase::}{WriteOnly} mode.
|
||||
If this is unsuccessful, we display a QMessageBox to inform the user.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
|
||||
|
||||
Otherwise, we instantiate a QDataStream object, \c out, to write the open
|
||||
file. QDataStream requires that the same version of the stream is used
|
||||
for reading and writing. We ensure that this is the case by setting the
|
||||
version used to the \l{QDataStream::Qt_4_5}{version introduced with Qt 4.5}
|
||||
before serializing the data to \c file.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
|
||||
|
||||
For the loading feature, we also obtain \c fileName using
|
||||
QFileDialog::getOpenFileName(). This function, the counterpart to
|
||||
QFileDialog::getSaveFileName(), also pops up the modal file dialog and
|
||||
allows the user to enter a file name or select any existing \c{.abk} file
|
||||
to load it into the address book.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
|
||||
|
||||
On Windows, for example, this function pops up a native file dialog, as
|
||||
shown in the following screenshot.
|
||||
|
||||
\image addressbook-tutorial-part6-load.png
|
||||
|
||||
If \c fileName is not empty, again, we use a QFile object, \c file, and
|
||||
attempt to open it in \l{QIODeviceBase::}{ReadOnly} mode. Similar to our
|
||||
implementation of \c saveToFile(), if this attempt is unsuccessful, we
|
||||
display a QMessageBox to inform the user.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
|
||||
|
||||
Otherwise, we instantiate a QDataStream object, \c in, set its version as
|
||||
above and read the serialized data into the \c contacts data structure.
|
||||
The \c contacts object is emptied before data is read into it to simplify
|
||||
the file reading process. A more advanced method would be to read the
|
||||
contacts into a temporary QMap object, and copy over non-duplicate contacts
|
||||
into \c contacts.
|
||||
|
||||
\snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
|
||||
|
||||
To display the contacts that have been read from the file, we must first
|
||||
validate the data obtained to ensure that the file we read from actually
|
||||
contains address book contacts. If it does, we display the first contact;
|
||||
otherwise, we display a QMessageBox to inform the user about the problem.
|
||||
Lastly, we update the interface to enable and disable the push buttons
|
||||
accordingly.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tutorials/addressbook/part7
|
||||
\title Part 7 - Additional Features
|
||||
\brief Describes how to export data in VCard format.
|
||||
|
||||
This part covers some additional features that make the address
|
||||
book more convenient for the frequent user.
|
||||
|
||||
\image addressbook-tutorial-part7-screenshot.png
|
||||
|
||||
Although our address book is useful in isolation, it would be
|
||||
better if we could exchange contact data with other applications.
|
||||
The vCard format is a popular file format that can be used for
|
||||
this purpose. Here we extend our address book client to allow
|
||||
contacts to be exported to vCard \c{.vcf} files.
|
||||
|
||||
\section1 Defining the AddressBook Class
|
||||
|
||||
We add a QPushButton object, \c exportButton, and a corresponding public
|
||||
slot, \c exportAsVCard() to our \c AddressBook class in the
|
||||
\c addressbook.h file.
|
||||
|
||||
\snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
|
||||
\dots
|
||||
\snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
|
||||
|
||||
\section1 Implementing the AddressBook Class
|
||||
|
||||
Within the \c AddressBook constructor, we connect \c{exportButton}'s
|
||||
\l{QPushButton::clicked()}{clicked()} signal to \c exportAsVCard().
|
||||
We also add this button to our \c buttonLayout1, the layout responsible
|
||||
for our panel of buttons on the right.
|
||||
|
||||
In our \c exportAsVCard() function, we start by extracting the contact's
|
||||
name into \c name. We declare \c firstName, \c lastName and \c nameList.
|
||||
Next, we look for the index of the first white space in \c name. If there
|
||||
is a white space, we split the contact's name into \c firstName and
|
||||
\c lastName. Then, we replace the space with an underscore ("_").
|
||||
Alternately, if there is no white space, we assume that the contact only
|
||||
has a first name.
|
||||
|
||||
\snippet tutorials/addressbook/part7/addressbook.cpp export function part1
|
||||
|
||||
As with the \c saveToFile() function, we open a file dialog to let the user
|
||||
choose a location for the file. Using the file name chosen, we create an
|
||||
instance of QFile to write to.
|
||||
|
||||
We attempt to open the file in \l{QIODeviceBase::}{WriteOnly} mode. If this
|
||||
process fails, we display a QMessageBox to inform the user about the
|
||||
problem and return. Otherwise, we pass the file as a parameter to a
|
||||
QTextStream object, \c out. Like QDataStream, the QTextStream class
|
||||
provides functionality to read and write plain text to files. As a result,
|
||||
the \c{.vcf} file generated can be opened for editing in a text editor.
|
||||
|
||||
\snippet tutorials/addressbook/part7/addressbook.cpp export function part2
|
||||
|
||||
We then write out a vCard file with the \c{BEGIN:VCARD} tag, followed by
|
||||
the \c{VERSION:2.1} tag. The contact's name is written with the \c{N:}
|
||||
tag. For the \c{FN:} tag, which fills in the "File as" property of a vCard,
|
||||
we have to check whether the contact has a last name or not. If the contact
|
||||
does, we use the details in \c nameList to fill it. Otherwise, we write
|
||||
\c firstName only.
|
||||
|
||||
\snippet tutorials/addressbook/part7/addressbook.cpp export function part3
|
||||
|
||||
We proceed to write the contact's address. The semicolons in the address
|
||||
are escaped with "\\", the newlines are replaced with semicolons, and the
|
||||
commas are replaced with spaces. Lastly, we write the \c{ADR;HOME:;}
|
||||
tag, followed by \c address and then the \c{END:VCARD} tag.
|
||||
|
||||
\snippet tutorials/addressbook/part7/addressbook.cpp export function part4
|
||||
|
||||
In the end, a QMessageBox is displayed to inform the user that the vCard
|
||||
has been successfully exported.
|
||||
|
||||
\e{vCard is a trademark of the \l{http://www.imc.org}
|
||||
{Internet Mail Consortium}}.
|
||||
*/
|
412
examples/widgets/doc/src/addressbook.qdoc
Normal file
@ -0,0 +1,412 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/addressbook
|
||||
\title Address Book
|
||||
\ingroup examples-itemviews
|
||||
\brief The address book example shows how to use proxy models to display
|
||||
different views onto data from a single model.
|
||||
|
||||
\image addressbook-example.png Screenshot of the Address Book example
|
||||
|
||||
This example provides an address book that allows contacts to be
|
||||
grouped alphabetically into 9 groups: ABC, DEF, GHI, ... , VW,
|
||||
..., XYZ. This is achieved by using multiple views on the same
|
||||
model, each of which is filtered using an instance of the
|
||||
QSortFilterProxyModel class.
|
||||
|
||||
|
||||
\section1 Overview
|
||||
|
||||
The address book contains 5 classes: \c MainWindow,
|
||||
\c AddressWidget, \c TableModel, \c NewAddressTab and
|
||||
\c AddDialog. The \c MainWindow class uses \c AddressWidget as
|
||||
its central widget and provides \uicontrol File and \uicontrol Tools menus.
|
||||
|
||||
\image addressbook-classes.png Diagram for Address Book example
|
||||
|
||||
The \c AddressWidget class is a QTabWidget subclass that is used
|
||||
to manipulate the 10 tabs displayed in the example: the 9
|
||||
alphabet group tabs and an instance of \c NewAddressTab.
|
||||
The \c NewAddressTab class is a subclass of QWidget that
|
||||
is only used whenever the address book is empty, prompting the
|
||||
user to add some contacts. \c AddressWidget also interacts with
|
||||
an instance of \c TableModel to add, edit and remove entries to
|
||||
the address book.
|
||||
|
||||
\c TableModel is a subclass of QAbstractTableModel that provides
|
||||
the standard model/view API to access data. It holds a list of
|
||||
added contacts.
|
||||
However, this data is not all visible in a single tab. Instead,
|
||||
QTableView is used to provide 9 different views of the same
|
||||
data, according to the alphabet groups.
|
||||
|
||||
QSortFilterProxyModel is the class responsible for filtering
|
||||
the contacts for each group of contacts. Each proxy model uses
|
||||
a QRegularExpression to filter out contacts that do not belong in the
|
||||
corresponding alphabetical group. The \c AddDialog class is
|
||||
used to obtain information from the user for the address book.
|
||||
This QDialog subclass is instantiated by \c NewAddressTab to
|
||||
add contacts, and by \c AddressWidget to add and edit contacts.
|
||||
|
||||
We begin by looking at the \c TableModel implementation.
|
||||
|
||||
|
||||
\section1 TableModel Class Definition
|
||||
|
||||
The \c TableModel class provides standard API to access data in
|
||||
its list of contacts by subclassing QAbstractTableModel. The
|
||||
basic functions that must be implemented in order to do so are:
|
||||
\c rowCount(), \c columnCount(), \c data(), \c headerData().
|
||||
For TableModel to be editable, it has to provide implementations
|
||||
\c insertRows(), \c removeRows(), \c setData() and \c flags()
|
||||
functions.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.h 0
|
||||
|
||||
Two constructors are used, a default constructor which uses
|
||||
\c TableModel's own \c {QList<Contact>} and one that takes
|
||||
\c {QList<Contact>} as an argument, for convenience.
|
||||
|
||||
|
||||
\section1 TableModel Class Implementation
|
||||
|
||||
We implement the two constructors as defined in the header file.
|
||||
The second constructor initializes the list of contacts in the
|
||||
model, with the parameter value.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 0
|
||||
|
||||
The \c rowCount() and \c columnCount() functions return the
|
||||
dimensions of the model. Whereas, \c rowCount()'s value will vary
|
||||
depending on the number of contacts added to the address book,
|
||||
\c columnCount()'s value is always 2 because we only need space
|
||||
for the \b Name and \b Address columns.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 1
|
||||
|
||||
The \c data() function returns either a \b Name or
|
||||
\b {Address}, based on the contents of the model index
|
||||
supplied. The row number stored in the model index is used to
|
||||
reference an item in the list of contacts. Selection is handled
|
||||
by the QItemSelectionModel, which will be explained with
|
||||
\c AddressWidget.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 2
|
||||
|
||||
The \c headerData() function displays the table's header,
|
||||
\b Name and \b Address. If you require numbered entries
|
||||
for your address book, you can use a vertical header which we
|
||||
have hidden in this example (see the \c AddressWidget
|
||||
implementation).
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 3
|
||||
|
||||
The \c insertRows() function is called before new data is added,
|
||||
otherwise the data will not be displayed. The
|
||||
\c beginInsertRows() and \c endInsertRows() functions are called
|
||||
to ensure all connected views are aware of the changes.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 4
|
||||
|
||||
The \c removeRows() function is called to remove data. Again,
|
||||
\l{QAbstractItemModel::}{beginRemoveRows()} and
|
||||
\l{QAbstractItemModel::}{endRemoveRows()} are called to ensure
|
||||
all connected views are aware of the changes.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 5
|
||||
|
||||
The \c setData() function is the function that inserts data into
|
||||
the table, item by item and not row by row. This means that to
|
||||
fill a row in the address book, \c setData() must be called
|
||||
twice, as each row has 2 columns. It is important to emit the
|
||||
\l{QAbstractItemModel::}{dataChanged()} signal as it tells all
|
||||
connected views to update their displays.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 6
|
||||
|
||||
The \c flags() function returns the item flags for the given
|
||||
index.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 7
|
||||
|
||||
We set the Qt::ItemIsEditable flag because we want to allow the
|
||||
\c TableModel to be edited. Although for this example we don't
|
||||
use the editing features of the QTableView object, we enable
|
||||
them here so that we can reuse the model in other programs.
|
||||
|
||||
The last function in \c {TableModel}, \c getContacts() returns the
|
||||
QList<Contact> object that holds all the contacts in the address
|
||||
book. We use this function later to obtain the list of contacts to
|
||||
check for existing entries, write the contacts to a file and read
|
||||
them back. Further explanation is given with \c AddressWidget.
|
||||
|
||||
\snippet itemviews/addressbook/tablemodel.cpp 8
|
||||
|
||||
|
||||
\section1 AddressWidget Class Definition
|
||||
|
||||
The \c AddressWidget class is technically the main class
|
||||
involved in this example as it provides functions to add, edit
|
||||
and remove contacts, to save the contacts to a file and to load
|
||||
them from a file.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.h 0
|
||||
|
||||
\c AddressWidget extends QTabWidget in order to hold 10 tabs
|
||||
(\c NewAddressTab and the 9 alphabet group tabs) and also
|
||||
manipulates \c table, the \c TableModel object, \c proxyModel,
|
||||
the QSortFilterProxyModel object that we use to filter the
|
||||
entries, and \c tableView, the QTableView object.
|
||||
|
||||
|
||||
\section1 AddressWidget Class Implementation
|
||||
|
||||
The \c AddressWidget constructor accepts a parent widget and
|
||||
instantiates \c NewAddressTab, \c TableModel and
|
||||
QSortFilterProxyModel. The \c NewAddressTab object, which is
|
||||
used to indicate that the address book is empty, is added
|
||||
and the rest of the 9 tabs are set up with \c setupTabs().
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 0
|
||||
|
||||
The \c setupTabs() function is used to set up the 9 alphabet
|
||||
group tabs, table views and proxy models in
|
||||
\c AddressWidget. Each proxy model in turn is set to filter
|
||||
contact names according to the relevant alphabet group using a
|
||||
case-insensitive QRegularExpression object. The
|
||||
table views are also sorted in ascending order using the
|
||||
corresponding proxy model's \l{QSortFilterProxyModel::}{sort()}
|
||||
function.
|
||||
|
||||
Each table view's \l{QTableView::}{selectionMode} is set to
|
||||
QAbstractItemView::SingleSelection and
|
||||
\l{QTableView::}{selectionBehavior} is set to
|
||||
QAbstractItemView::SelectRows, allowing the user to select
|
||||
all the items in one row at the same time. Each QTableView object
|
||||
is automatically given a QItemSelectionModel that keeps track
|
||||
of the selected indexes.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 1
|
||||
|
||||
The QItemSelectionModel class provides a
|
||||
\l{QItemSelectionModel::selectionChanged()}{selectionChanged}
|
||||
signal that is connected to \c{AddressWidget}'s
|
||||
\c selectionChanged() signal. We also connect
|
||||
QTabWidget::currentChanged() signal to the lambda expression which
|
||||
emits \c{AddressWidget}'s \c selectionChanged() as well. These
|
||||
connections are necessary to enable the \uicontrol{Edit Entry...} and
|
||||
\uicontrol{Remove Entry} actions in \c MainWindow's Tools menu.
|
||||
It is further explained in \c MainWindow's implementation.
|
||||
|
||||
Each table view in the address book is added as a tab to the
|
||||
QTabWidget with the relevant label, obtained from the QStringList
|
||||
of groups.
|
||||
|
||||
\image addressbook-signals.png Signals and Slots Connections
|
||||
|
||||
We provide two \c addEntry() functions: One which is intended to be
|
||||
used to accept user input, and the other which performs the actual
|
||||
task of adding new entries to the address book. We divide the
|
||||
responsibility of adding entries into two parts to allow
|
||||
\c newAddressTab to insert data without having to popup a dialog.
|
||||
|
||||
The first \c addEntry() function is a slot connected to the
|
||||
\c MainWindow's \uicontrol{Add Entry...} action. This function creates an
|
||||
\c AddDialog object and then calls the second \c addEntry()
|
||||
function to actually add the contact to \c table.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 2
|
||||
|
||||
Basic validation is done in the second \c addEntry() function to
|
||||
prevent duplicate entries in the address book. As mentioned with
|
||||
\c TableModel, this is part of the reason why we require the
|
||||
getter method \c getContacts().
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 3
|
||||
|
||||
If the model does not already contain an entry with the same name,
|
||||
we call \c setData() to insert the name and address into the
|
||||
first and second columns. Otherwise, we display a QMessageBox
|
||||
to inform the user.
|
||||
|
||||
\note The \c newAddressTab is removed once a contact is added
|
||||
as the address book is no longer empty.
|
||||
|
||||
Editing an entry is a way to update the contact's address only,
|
||||
as the example does not allow the user to change the name of an
|
||||
existing contact.
|
||||
|
||||
Firstly, we obtain the active tab's QTableView object using
|
||||
QTabWidget::currentWidget(). Then we extract the
|
||||
\c selectionModel from the \c tableView to obtain the selected
|
||||
indexes.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 4a
|
||||
|
||||
Next we extract data from the row the user intends to
|
||||
edit. This data is displayed in an instance of \c AddDialog
|
||||
with a different window title. The \c table is only
|
||||
updated if changes have been made to data in \c aDialog.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 4b
|
||||
|
||||
\image addressbook-editdialog.png Screenshot of Dialog to Edit a Contact
|
||||
|
||||
Entries are removed using the \c removeEntry() function.
|
||||
The selected row is removed by accessing it through the
|
||||
QItemSelectionModel object, \c selectionModel. The
|
||||
\c newAddressTab is re-added to the \c AddressWidget only if
|
||||
the user removes all the contacts in the address book.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 5
|
||||
|
||||
The \c writeToFile() function is used to save a file containing
|
||||
all the contacts in the address book. The file is saved in a
|
||||
custom \c{.dat} format. The contents of the list of contacts
|
||||
are written to \c file using QDataStream. If the file cannot be
|
||||
opened, a QMessageBox is displayed with the related error message.
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 6
|
||||
|
||||
The \c readFromFile() function loads a file containing all the
|
||||
contacts in the address book, previously saved using
|
||||
\c writeToFile(). QDataStream is used to read the contents of a
|
||||
\c{.dat} file into a list of contacts and each of these is added
|
||||
using \c addEntry().
|
||||
|
||||
\snippet itemviews/addressbook/addresswidget.cpp 7
|
||||
|
||||
|
||||
\section1 NewAddressTab Class Definition
|
||||
|
||||
The \c NewAddressTab class provides an informative tab telling
|
||||
the user that the address book is empty. It appears and
|
||||
disappears according to the contents of the address book, as
|
||||
mentioned in \c{AddressWidget}'s implementation.
|
||||
|
||||
\image addressbook-newaddresstab.png Screenshot of NewAddressTab
|
||||
|
||||
The \c NewAddressTab class extends QWidget and contains a QLabel
|
||||
and QPushButton.
|
||||
|
||||
\snippet itemviews/addressbook/newaddresstab.h 0
|
||||
|
||||
|
||||
\section1 NewAddressTab Class Implementation
|
||||
|
||||
The constructor instantiates the \c addButton,
|
||||
\c descriptionLabel and connects the \c{addButton}'s signal to
|
||||
the \c{addEntry()} slot.
|
||||
|
||||
\snippet itemviews/addressbook/newaddresstab.cpp 0
|
||||
|
||||
The \c addEntry() function is similar to \c AddressWidget's
|
||||
\c addEntry() in the sense that both functions instantiate an
|
||||
\c AddDialog object. Data from the dialog is extracted and sent
|
||||
to \c AddressWidget's \c addEntry() slot by emitting the
|
||||
\c sendDetails() signal.
|
||||
|
||||
\snippet itemviews/addressbook/newaddresstab.cpp 1
|
||||
|
||||
\image signals-n-slots-aw-nat.png
|
||||
|
||||
|
||||
\section1 AddDialog Class Definition
|
||||
|
||||
The \c AddDialog class extends QDialog and provides the user
|
||||
with a QLineEdit and a QTextEdit to input data into the
|
||||
address book.
|
||||
|
||||
\snippet itemviews/addressbook/adddialog.h 0
|
||||
|
||||
\image addressbook-adddialog.png
|
||||
|
||||
|
||||
\section1 AddDialog Class Implementation
|
||||
|
||||
The \c AddDialog's constructor sets up the user interface,
|
||||
creating the necessary widgets and placing them into layouts.
|
||||
|
||||
\snippet itemviews/addressbook/adddialog.cpp 0
|
||||
|
||||
To give the dialog the desired behavior, we connect the \uicontrol OK
|
||||
and \uicontrol Cancel buttons to the dialog's \l{QDialog::}{accept()} and
|
||||
\l{QDialog::}{reject()} slots. Since the dialog only acts as a
|
||||
container for name and address information, we do not need to
|
||||
implement any other functions for it.
|
||||
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
The \c MainWindow class extends QMainWindow and implements the
|
||||
menus and actions necessary to manipulate the address book.
|
||||
|
||||
\table
|
||||
\row \li \inlineimage addressbook-filemenu.png
|
||||
\li \inlineimage addressbook-toolsmenu.png
|
||||
\endtable
|
||||
|
||||
\snippet itemviews/addressbook/mainwindow.h 0
|
||||
|
||||
The \c MainWindow class uses an \c AddressWidget as its central
|
||||
widget and provides the File menu with \uicontrol Open, \uicontrol Close and
|
||||
\uicontrol Exit actions, as well as the \uicontrol Tools menu with
|
||||
\uicontrol{Add Entry...}, \uicontrol{Edit Entry...} and \uicontrol{Remove Entry}
|
||||
actions.
|
||||
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
The constructor for \c MainWindow instantiates AddressWidget,
|
||||
sets it as its central widget and calls the \c createMenus()
|
||||
function.
|
||||
|
||||
\snippet itemviews/addressbook/mainwindow.cpp 0
|
||||
|
||||
The \c createMenus() function sets up the \uicontrol File and
|
||||
\uicontrol Tools menus, connecting the actions to their respective slots.
|
||||
Both the \uicontrol{Edit Entry...} and \uicontrol{Remove Entry} actions are
|
||||
disabled by default as such actions cannot be carried out on an empty
|
||||
address book. They are only enabled when one or more contacts
|
||||
are added.
|
||||
|
||||
\snippet itemviews/addressbook/mainwindow.cpp 1a
|
||||
\dots
|
||||
\codeline
|
||||
\snippet itemviews/addressbook/mainwindow.cpp 1b
|
||||
|
||||
Apart from connecting all the actions' signals to their
|
||||
respective slots, we also connect \c AddressWidget's
|
||||
\c selectionChanged() signal to its \c updateActions() slot.
|
||||
|
||||
The \c openFile() function opens a custom \c{addressbook.dat} file that
|
||||
contains address book contacts. This function is a slot connected to
|
||||
\c openAct in the \uicontrol File menu.
|
||||
|
||||
\snippet itemviews/addressbook/mainwindow.cpp 2
|
||||
|
||||
The \c saveFile() function saves a custom \c{addressbook.dat} file that
|
||||
will contain the address book contacts. This function is a slot connected
|
||||
to \c saveAct in the \uicontrol File menu.
|
||||
|
||||
\snippet itemviews/addressbook/mainwindow.cpp 3
|
||||
|
||||
The \c updateActions() function enables and disables
|
||||
\uicontrol{Edit Entry...} and \uicontrol{Remove Entry} depending on the contents of
|
||||
the address book. If the address book is empty, these actions
|
||||
are disabled; otherwise, they are enabled. This function is a slot
|
||||
is connected to the \c AddressWidget's \c selectionChanged()
|
||||
signal.
|
||||
|
||||
\snippet itemviews/addressbook/mainwindow.cpp 4
|
||||
|
||||
|
||||
\section1 main() Function
|
||||
|
||||
The main function for the address book instantiates QApplication
|
||||
and opens a \c MainWindow before running the event loop.
|
||||
|
||||
\snippet itemviews/addressbook/main.cpp 0
|
||||
*/
|
26
examples/widgets/doc/src/affine.qdoc
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example painting/affine
|
||||
\title Affine Transformations
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates how affine transformations in QPainter works.
|
||||
|
||||
\brief In this example we show Qt's ability to perform affine transformations
|
||||
on painting operations.
|
||||
|
||||
\image affine-demo.png
|
||||
|
||||
Transformations can be performed on any kind of graphics drawn using QPainter.
|
||||
The transformations used to display the vector graphics, images, and text can be adjusted
|
||||
in the following ways:
|
||||
|
||||
\list
|
||||
\li Dragging the red circle in the centre of each drawing moves it to a new position.
|
||||
\li Dragging the displaced red circle causes the current drawing to be rotated about the
|
||||
central circle. Rotation can also be controlled with the \uicontrol Rotate slider.
|
||||
\li Scaling is controlled with the \uicontrol Scale slider.
|
||||
\li Each drawing can be sheared with the \uicontrol Shear slider.
|
||||
\endlist
|
||||
*/
|
134
examples/widgets/doc/src/analogclock.qdoc
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/analogclock
|
||||
\examplecategory {Graphics}
|
||||
\meta tags {widgets}
|
||||
|
||||
\title Analog Clock
|
||||
\ingroup examples-widgets
|
||||
\brief The Analog Clock example shows how to draw the contents of a
|
||||
custom widget.
|
||||
|
||||
\borderedimage analogclock-example.png
|
||||
\caption Screenshot of the Analog Clock example
|
||||
|
||||
This example also demonstrates how the transformation and scaling
|
||||
features of QPainter can be used to make drawing custom widgets
|
||||
easier.
|
||||
|
||||
\section1 AnalogClock Class Definition
|
||||
|
||||
The \c AnalogClock class provides a clock widget with hour and minute
|
||||
hands that is automatically updated every few seconds.
|
||||
We subclass \l QWidget and reimplement the standard
|
||||
\l{QWidget::paintEvent()}{paintEvent()} function to draw the clock face:
|
||||
|
||||
\snippet widgets/analogclock/analogclock.h 0
|
||||
|
||||
\section1 AnalogClock Class Implementation
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 1
|
||||
|
||||
When the widget is constructed, we set up a one-second timer to
|
||||
keep track of the current time, and we connect it to the standard
|
||||
\l{QWidget::update()}{update()} slot so that the clock face is
|
||||
updated when the timer emits the \l{QTimer::timeout()}{timeout()}
|
||||
signal.
|
||||
|
||||
Finally, we resize the widget so that it is displayed at a
|
||||
reasonable size.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 8
|
||||
\snippet widgets/analogclock/analogclock.cpp 10
|
||||
|
||||
The \c paintEvent() function is called whenever the widget's
|
||||
contents need to be updated. This happens when the widget is
|
||||
first shown, and when it is covered then exposed, but it is also
|
||||
executed when the widget's \l{QWidget::update()}{update()} slot
|
||||
is called. Since we connected the timer's
|
||||
\l{QTimer::timeout()}{timeout()} signal to this slot, it will be
|
||||
called at least once every five seconds.
|
||||
|
||||
Before we set up the painter and draw the clock, we first define
|
||||
two lists of \l {QPoint}s and two \l{QColor}s that will be used
|
||||
for the hour and minute hands. The minute hand's color has an
|
||||
alpha component of 191, meaning that it's 75% opaque.
|
||||
|
||||
We also determine the length of the widget's shortest side so that we
|
||||
can fit the clock face inside the widget. It is also useful to determine
|
||||
the current time before we start drawing.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 11
|
||||
\snippet widgets/analogclock/analogclock.cpp 12
|
||||
\snippet widgets/analogclock/analogclock.cpp 13
|
||||
\snippet widgets/analogclock/analogclock.cpp 14
|
||||
|
||||
The contents of custom widgets are drawn with a QPainter.
|
||||
Painters can be used to draw on any QPaintDevice, but they are
|
||||
usually used with widgets, so we pass the widget instance to the
|
||||
painter's constructor.
|
||||
|
||||
We call QPainter::setRenderHint() with QPainter::Antialiasing to
|
||||
turn on antialiasing. This makes drawing of diagonal lines much
|
||||
smoother.
|
||||
|
||||
The translation moves the origin to the center of the widget, and
|
||||
the scale operation ensures that the following drawing operations
|
||||
are scaled to fit within the widget. We use a scale factor that
|
||||
let's us use x and y coordinates between -100 and 100, and that
|
||||
ensures that these lie within the length of the widget's shortest
|
||||
side.
|
||||
|
||||
To make our code simpler, we will draw a fixed size clock face that will
|
||||
be positioned and scaled so that it lies in the center of the widget.
|
||||
|
||||
The painter takes care of all the transformations made during the
|
||||
paint event, and ensures that everything is drawn correctly. Letting
|
||||
the painter handle transformations is often easier than performing
|
||||
manual calculations just to draw the contents of a custom widget.
|
||||
|
||||
\image analogclock-viewport.png
|
||||
|
||||
We draw the hour hand first, using a formula that rotates the coordinate
|
||||
system counterclockwise by a number of degrees determined by the current
|
||||
hour and minute. This means that the hand will be shown rotated clockwise
|
||||
by the required amount.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 15
|
||||
\snippet widgets/analogclock/analogclock.cpp 16
|
||||
|
||||
We set the pen to be Qt::NoPen because we don't want any outline,
|
||||
and we use a solid brush with the color appropriate for
|
||||
displaying hours. Brushes are used when filling in polygons and
|
||||
other geometric shapes.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 17
|
||||
\snippet widgets/analogclock/analogclock.cpp 19
|
||||
|
||||
We save and restore the transformation matrix before and after the
|
||||
rotation because we want to place the minute hand without having to
|
||||
take into account any previous rotations.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 20
|
||||
\codeline
|
||||
\snippet widgets/analogclock/analogclock.cpp 21
|
||||
|
||||
We draw markers around the edge of the clock for each hour. We
|
||||
draw each marker then rotate the coordinate system so that the
|
||||
painter is ready for the next one.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 22
|
||||
\snippet widgets/analogclock/analogclock.cpp 23
|
||||
|
||||
The minute hand is rotated in a similar way to the hour hand.
|
||||
|
||||
\snippet widgets/analogclock/analogclock.cpp 25
|
||||
\codeline
|
||||
\snippet widgets/analogclock/analogclock.cpp 26
|
||||
|
||||
Again, we draw markers around the edge of the clock, but this
|
||||
time to indicate minutes. We skip multiples of 5 to avoid drawing
|
||||
minute markers on top of hour markers.
|
||||
*/
|
370
examples/widgets/doc/src/application.qdoc
Normal file
@ -0,0 +1,370 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example mainwindows/application
|
||||
\title Qt Widgets - Application Example
|
||||
\ingroup examples-mainwindow
|
||||
|
||||
\brief The Application example shows how to implement a standard
|
||||
widget application with menus, toolbars, and a status bar. The example
|
||||
itself is a simple text editor program built around QPlainTextEdit.
|
||||
|
||||
\image application.png Screenshot of the Application example
|
||||
|
||||
Nearly all of the code for the Application example is in the \c
|
||||
MainWindow class, which inherits QMainWindow. QMainWindow
|
||||
provides the framework for windows that have menus, toolbars,
|
||||
dock windows, and a status bar. The application provides
|
||||
\uicontrol{File}, \uicontrol{Edit}, and \uicontrol{Help} entries in the menu
|
||||
bar, with the following popup menus:
|
||||
|
||||
\image application-menus.png The Application example's menu system
|
||||
|
||||
The status bar at the bottom of the main window shows a
|
||||
description of the menu item or toolbar button under the cursor.
|
||||
|
||||
To keep the example simple, recently opened files aren't shown in
|
||||
the \uicontrol{File} menu, even though this feature is desired in 90%
|
||||
of applications. Furthermore, this example can only load one file at a
|
||||
time. The \l{mainwindows/mdi}{MDI} example shows how to lift these
|
||||
restrictions and how to implement recently opened files handling.
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
Here's the class definition:
|
||||
|
||||
\snippet mainwindows/application/mainwindow.h 0
|
||||
|
||||
The public API is restricted to the constructor. In the \c
|
||||
protected section, we reimplement QWidget::closeEvent() to detect
|
||||
when the user attempts to close the window, and warn the user
|
||||
about unsaved changes. In the \c{private slots} section, we
|
||||
declare slots that correspond to menu entries, as well as a
|
||||
mysterious \c documentWasModified() slot. Finally, in the \c
|
||||
private section of the class, we have various members that will
|
||||
be explained in due time.
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 0
|
||||
|
||||
We start by including \c <QtWidgets>, a header file that contains the
|
||||
definition of all classes in the Qt Core, Qt GUI and Qt Widgets
|
||||
modules. This saves us from the trouble of having to include
|
||||
every class individually. We also include \c mainwindow.h.
|
||||
|
||||
You might wonder why we don't include \c <QtWidgets> in \c
|
||||
mainwindow.h and be done with it. The reason is that including
|
||||
such a large header from another header file can rapidly degrade
|
||||
performances. Here, it wouldn't do any harm, but it's still
|
||||
generally a good idea to include only the header files that are
|
||||
strictly necessary from another header file.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 1
|
||||
\snippet mainwindows/application/mainwindow.cpp 2
|
||||
|
||||
In the constructor, we start by creating a QPlainTextEdit widget as a
|
||||
child of the main window (the \c this object). Then we call
|
||||
QMainWindow::setCentralWidget() to tell that this is going to be
|
||||
the widget that occupies the central area of the main window,
|
||||
between the toolbars and the status bar.
|
||||
|
||||
Then we call \c createActions() and \c createStatusBar(), two private
|
||||
functions that set up the user interface. After that, we call \c
|
||||
readSettings() to restore the user's preferences.
|
||||
|
||||
We establish a signal-slot connection between the QPlainTextEdit's
|
||||
document object and our \c documentWasModified() slot. Whenever
|
||||
the user modifies the text in the QPlainTextEdit, we want to update
|
||||
the title bar to show that the file was modified.
|
||||
|
||||
At the end, we set the window title using the private
|
||||
\c setCurrentFile() function. We'll come back to this later.
|
||||
|
||||
\target close event handler
|
||||
\snippet mainwindows/application/mainwindow.cpp 3
|
||||
\snippet mainwindows/application/mainwindow.cpp 4
|
||||
|
||||
When the user attempts to close the window, we call the private
|
||||
function \c maybeSave() to give the user the possibility to save
|
||||
pending changes. The function returns true if the user wants the
|
||||
application to close; otherwise, it returns false. In the first
|
||||
case, we save the user's preferences to disk and accept the close
|
||||
event; in the second case, we ignore the close event, meaning
|
||||
that the application will stay up and running as if nothing
|
||||
happened.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 5
|
||||
\snippet mainwindows/application/mainwindow.cpp 6
|
||||
|
||||
The \c newFile() slot is invoked when the user selects
|
||||
\uicontrol{File|New} from the menu. We call \c maybeSave() to save any
|
||||
pending changes and if the user accepts to go on, we clear the
|
||||
QPlainTextEdit and call the private function \c setCurrentFile() to
|
||||
update the window title and clear the
|
||||
\l{QWidget::windowModified}{windowModified} flag.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 7
|
||||
\snippet mainwindows/application/mainwindow.cpp 8
|
||||
|
||||
The \c open() slot is invoked when the user clicks
|
||||
\uicontrol{File|Open}. We pop up a QFileDialog asking the user to
|
||||
choose a file. If the user chooses a file (i.e., \c fileName is
|
||||
not an empty string), we call the private function \c loadFile()
|
||||
to actually load the file.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 9
|
||||
\snippet mainwindows/application/mainwindow.cpp 10
|
||||
|
||||
The \c save() slot is invoked when the user clicks
|
||||
\uicontrol{File|Save}. If the user hasn't provided a name for the file
|
||||
yet, we call \c saveAs(); otherwise, we call the private function
|
||||
\c saveFile() to actually save the file.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 11
|
||||
\snippet mainwindows/application/mainwindow.cpp 12
|
||||
|
||||
In \c saveAs(), we start by popping up a QFileDialog asking the
|
||||
user to provide a name. If the user clicks \uicontrol{Cancel}, the
|
||||
returned file name is empty, and we do nothing.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 13
|
||||
\snippet mainwindows/application/mainwindow.cpp 14
|
||||
|
||||
The application's About box is done using one statement, using
|
||||
the QMessageBox::about() static function and relying on its
|
||||
support for an HTML subset.
|
||||
|
||||
The \l{QObject::tr()}{tr()} call around the literal string marks
|
||||
the string for translation. It is a good habit to call
|
||||
\l{QObject::tr()}{tr()} on all user-visible strings, in case you
|
||||
later decide to translate your application to other languages.
|
||||
The \l{Internationalization with Qt} overview covers
|
||||
\l{QObject::tr()}{tr()} in more detail.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 15
|
||||
\snippet mainwindows/application/mainwindow.cpp 16
|
||||
|
||||
The \c documentWasModified() slot is invoked each time the text
|
||||
in the QPlainTextEdit changes because of user edits. We call
|
||||
QWidget::setWindowModified() to make the title bar show that the
|
||||
file was modified. How this is done varies on each platform.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 17
|
||||
\snippet mainwindows/application/mainwindow.cpp 18
|
||||
\dots
|
||||
\snippet mainwindows/application/mainwindow.cpp 22
|
||||
|
||||
The \c createActions() private function, which is called from the
|
||||
\c MainWindow constructor, creates \l{QAction}s and populates
|
||||
the menus and two toolbars. The code is very
|
||||
repetitive, so we show only the actions corresponding to
|
||||
\uicontrol{File|New}, \uicontrol{File|Open}, and \uicontrol{Help|About Qt}.
|
||||
|
||||
A QAction is an object that represents one user action, such as
|
||||
saving a file or invoking a dialog. An action can be put in a
|
||||
QMenu or a QToolBar, or both, or in any other widget that
|
||||
reimplements QWidget::actionEvent().
|
||||
|
||||
An action has a text that is shown in the menu, an icon, a
|
||||
shortcut key, a tooltip, a status tip (shown in the status bar),
|
||||
a "What's This?" text, and more. It emits a
|
||||
\l{QAction::triggered()}{triggered()} signal whenever the user
|
||||
invokes the action (e.g., by clicking the associated menu item or
|
||||
toolbar button).
|
||||
|
||||
Instances of QAction can be created by passing a parent QObject or
|
||||
by using one of the convenience functions of QMenu, QMenuBar or QToolBar.
|
||||
We create the actions that are in a menu as well as in a toolbar
|
||||
parented on the window to prevent ownership issues. For actions
|
||||
that are only in the menu, we use the convenience function
|
||||
QMenu::addAction(), which allows us to pass text, icon and the
|
||||
target object and its slot member function.
|
||||
|
||||
Creating toolbars is very similar to creating menus. The same
|
||||
actions that we put in the menus can be reused in the toolbars.
|
||||
After creating the action, we add it to the toolbar using
|
||||
QToolBar::addAction().
|
||||
|
||||
The code above contains one more idiom that must be explained.
|
||||
For some of the actions, we specify an icon as a QIcon to the
|
||||
QAction constructor. We use QIcon::fromTheme() to obtain
|
||||
the correct standard icon from the underlying window system.
|
||||
If that fails due to the platform not supporting it, we
|
||||
pass a file name as fallback. Here, the file name starts
|
||||
with \c{:}. Such file names aren't ordinary file names, but
|
||||
rather path in the executable's stored resources. We'll come back
|
||||
to this when we review the \c application.qrc file that's part of
|
||||
the project.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 23
|
||||
\snippet mainwindows/application/mainwindow.cpp 24
|
||||
|
||||
The \uicontrol{Edit|Cut} and \uicontrol{Edit|Copy} actions must be available
|
||||
only when the QPlainTextEdit contains selected text. We disable them
|
||||
by default and connect the QPlainTextEdit::copyAvailable() signal to
|
||||
the QAction::setEnabled() slot, ensuring that the actions are
|
||||
disabled when the text editor has no selection.
|
||||
|
||||
Just before we create the \uicontrol{Help} menu, we call
|
||||
QMenuBar::addSeparator(). This has no effect for most widget
|
||||
styles (e.g., Windows and \macos styles), but for some
|
||||
styles this makes sure that \uicontrol{Help} is pushed to the right
|
||||
side of the menu bar.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 32
|
||||
\snippet mainwindows/application/mainwindow.cpp 33
|
||||
|
||||
QMainWindow::statusBar() returns a pointer to the main window's
|
||||
QStatusBar widget. Like with \l{QMainWindow::menuBar()}, the
|
||||
widget is automatically created the first time the function is
|
||||
called.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 34
|
||||
\snippet mainwindows/application/mainwindow.cpp 36
|
||||
|
||||
The \c readSettings() function is called from the constructor to
|
||||
load the user's preferences and other application settings. The
|
||||
QSettings class provides a high-level interface for storing
|
||||
settings permanently on disk. On Windows, it uses the (in)famous
|
||||
Windows registry; on \macos, it uses the native XML-based
|
||||
CFPreferences API; on Unix/X11, it uses text files.
|
||||
|
||||
The QSettings constructor takes arguments that identify your
|
||||
company and the name of the product. This ensures that the
|
||||
settings for different applications are kept separately.
|
||||
|
||||
We use QSettings::value() to extract the value of the geometry setting.
|
||||
The second argument to QSettings::value() is
|
||||
optional and specifies a default value for the setting if there
|
||||
exists none. This value is used the first time the application is
|
||||
run.
|
||||
|
||||
We use QWidget::saveGeometry() and Widget::restoreGeometry() to
|
||||
save the position. They use an opaque QByteArray to store
|
||||
screen number, geometry and window state.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 37
|
||||
\snippet mainwindows/application/mainwindow.cpp 39
|
||||
|
||||
The \c writeSettings() function is called from \c closeEvent().
|
||||
Writing settings is similar to reading them, except simpler. The
|
||||
arguments to the QSettings constructor must be the same as in \c
|
||||
readSettings().
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 40
|
||||
\snippet mainwindows/application/mainwindow.cpp 41
|
||||
|
||||
The \c maybeSave() function is called to save pending changes. If
|
||||
there are pending changes, it pops up a QMessageBox giving the
|
||||
user to save the document. The options are QMessageBox::Yes,
|
||||
QMessageBox::No, and QMessageBox::Cancel. The \uicontrol{Yes} button is
|
||||
made the default button (the button that is invoked when the user
|
||||
presses \uicontrol{Return}) using the QMessageBox::Default flag; the
|
||||
\uicontrol{Cancel} button is made the escape button (the button that is
|
||||
invoked when the user presses \uicontrol{Esc}) using the
|
||||
QMessageBox::Escape flag.
|
||||
|
||||
The \c maybeSave() function returns \c true in all cases, except
|
||||
when the user clicks \uicontrol{Cancel} or saving the file fails.
|
||||
The caller must check the return value and stop whatever it was
|
||||
doing if the return value is \c false.
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 42
|
||||
\snippet mainwindows/application/mainwindow.cpp 43
|
||||
|
||||
In \c loadFile(), we use QFile and QTextStream to read in the
|
||||
data. The QFile object provides access to the bytes stored in a
|
||||
file.
|
||||
|
||||
We start by opening the file in read-only mode. The QFile::Text
|
||||
flag indicates that the file is a text file, not a binary file.
|
||||
On Unix and \macos, this makes no difference, but on Windows,
|
||||
it ensures that the "\\r\\n" end-of-line sequence is converted to
|
||||
"\\n" when reading.
|
||||
|
||||
If we successfully opened the file, we use a QTextStream object
|
||||
to read in the data. QTextStream automatically converts the 8-bit
|
||||
data into a Unicode QString and supports various encodings. If no
|
||||
encoding is specified, QTextStream assumes the file is encoded in
|
||||
UTF-8.
|
||||
|
||||
Since the call to QTextStream::readAll() might take some time, we
|
||||
set the cursor to be Qt::WaitCursor for the entire application
|
||||
while it goes on.
|
||||
|
||||
At the end, we call the private \c setCurrentFile() function,
|
||||
which we'll cover in a moment, and we display the string "File
|
||||
loaded" in the status bar for 2 seconds (2000 milliseconds).
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 44
|
||||
\snippet mainwindows/application/mainwindow.cpp 45
|
||||
|
||||
Saving a file is similar to loading one. We use QSaveFile to ensure
|
||||
all data are safely written and existing files are not damaged
|
||||
should writing fail.
|
||||
We use the QFile::Text flag to make sure that on Windows, "\\n"
|
||||
is converted into "\\r\\n" to conform to the Windows convention.
|
||||
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 46
|
||||
\snippet mainwindows/application/mainwindow.cpp 47
|
||||
|
||||
The \c setCurrentFile() function is called to reset the state of
|
||||
a few variables when a file is loaded or saved, or when the user
|
||||
starts editing a new file (in which case \c fileName is empty).
|
||||
We update the \c curFile variable, clear the
|
||||
QTextDocument::modified flag and the associated \c
|
||||
QWidget:windowModified flag, and update the window title to
|
||||
contain the new file name (or \c untitled.txt).
|
||||
|
||||
The \c strippedName() function call around \c curFile in the
|
||||
QWidget::setWindowTitle() call shortens the file name to exclude
|
||||
the path. Here's the function:
|
||||
|
||||
\snippet mainwindows/application/mainwindow.cpp 48
|
||||
\snippet mainwindows/application/mainwindow.cpp 49
|
||||
|
||||
\section1 The main() Function
|
||||
|
||||
The \c main() function for this application is typical of
|
||||
applications that contain one main window:
|
||||
|
||||
\snippet mainwindows/application/main.cpp 0
|
||||
|
||||
The main function uses QCommandLineParser to check whether some file
|
||||
argument was passed to the application and loads it via
|
||||
MainWindow::loadFile().
|
||||
|
||||
\section1 The Resource File
|
||||
|
||||
As you will probably recall, for some of the actions, we
|
||||
specified icons with file names starting with \c{:} and mentioned
|
||||
that such file names aren't ordinary file names, but path in the
|
||||
executable's stored resources. These resources are compiled
|
||||
|
||||
The resources associated with an application are specified in a
|
||||
\c .qrc file, an XML-based file format that lists files on the
|
||||
disk. Here's the \c application.qrc file that's used by the
|
||||
Application example:
|
||||
|
||||
\quotefile mainwindows/application/application.qrc
|
||||
|
||||
The \c .png files listed in the \c application.qrc file are files
|
||||
that are part of the Application example's source tree. Paths are
|
||||
relative to the directory where the \c application.qrc file is
|
||||
located (the \c mainwindows/application directory).
|
||||
|
||||
The resource file must be mentioned in the \c application.pro
|
||||
file so that \c qmake knows about it:
|
||||
|
||||
\snippet mainwindows/application/application.pro 0
|
||||
|
||||
\c qmake will produce make rules to generate a file called \c
|
||||
qrc_application.cpp that is linked into the application. This
|
||||
file contains all the data for the images and other resources as
|
||||
static C++ arrays of compressed binary data. See
|
||||
\l{resources.html}{The Qt Resource System} for more information
|
||||
about resources.
|
||||
*/
|
434
examples/widgets/doc/src/basicdrawing.qdoc
Normal file
@ -0,0 +1,434 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example painting/basicdrawing
|
||||
\title Basic Drawing Example
|
||||
\ingroup examples-painting
|
||||
\brief The Basic Drawing example shows how to display basic
|
||||
graphics primitives in a variety of styles using the QPainter
|
||||
class.
|
||||
|
||||
\brief The Basic Drawing example shows how to display basic graphics
|
||||
primitives in a variety of styles using the QPainter class.
|
||||
|
||||
QPainter performs low-level painting on widgets and other paint
|
||||
devices. The class can draw everything from simple lines to
|
||||
complex shapes like pies and chords. It can also draw aligned text
|
||||
and pixmaps. Normally, it draws in a "natural" coordinate system,
|
||||
but it can in addition do view and world transformation.
|
||||
|
||||
\image basicdrawing-example.png
|
||||
|
||||
The example provides a render area, displaying the currently
|
||||
active shape, and lets the user manipulate the rendered shape and
|
||||
its appearance using the QPainter parameters: The user can change
|
||||
the active shape (\uicontrol Shape), and modify the QPainter's pen (\uicontrol
|
||||
{Pen Width}, \uicontrol {Pen Style}, \uicontrol {Pen Cap}, \uicontrol {Pen Join}),
|
||||
brush (\uicontrol {Brush Style}) and render hints (\uicontrol
|
||||
Antialiasing). In addition the user can rotate a shape (\uicontrol
|
||||
Transformations); behind the scenes we use QPainter's ability to
|
||||
manipulate the coordinate system to perform the rotation.
|
||||
|
||||
The Basic Drawing example consists of two classes:
|
||||
|
||||
\list
|
||||
\li \c RenderArea is a custom widget that renders multiple
|
||||
copies of the currently active shape.
|
||||
\li \c Window is the application's main window displaying a
|
||||
\c RenderArea widget in addition to several parameter widgets.
|
||||
\endlist
|
||||
|
||||
First we will review the \c Window class, then we will take a
|
||||
look at the \c RenderArea class.
|
||||
|
||||
\section1 Window Class Definition
|
||||
|
||||
The Window class inherits QWidget, and is the application's main
|
||||
window displaying a \c RenderArea widget in addition to several
|
||||
parameter widgets.
|
||||
|
||||
\snippet painting/basicdrawing/window.h 0
|
||||
|
||||
We declare the various widgets, and three private slots updating
|
||||
the \c RenderArea widget: The \c shapeChanged() slot updates the
|
||||
\c RenderArea widget when the user changes the currently active
|
||||
shape. We call the \c penChanged() slot when either of the
|
||||
QPainter's pen parameters changes. And the \c brushChanged() slot
|
||||
updates the \c RenderArea widget when the user changes the
|
||||
painter's brush style.
|
||||
|
||||
\section1 Window Class Implementation
|
||||
|
||||
In the constructor we create and initialize the various widgets
|
||||
appearing in the main application window.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 1
|
||||
|
||||
First we create the \c RenderArea widget that will render the
|
||||
currently active shape. Then we create the \uicontrol Shape combobox,
|
||||
and add the associated items (i.e. the different shapes a QPainter
|
||||
can draw).
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 2
|
||||
|
||||
QPainter's pen is a QPen object; the QPen class defines how a
|
||||
painter should draw lines and outlines of shapes. A pen has
|
||||
several properties: Width, style, cap and join.
|
||||
|
||||
A pen's width can be \e zero or greater, but the most common width
|
||||
is zero. Note that this doesn't mean 0 pixels, but implies that
|
||||
the shape is drawn as smoothly as possible although perhaps not
|
||||
mathematically correct.
|
||||
|
||||
We create a QSpinBox for the \uicontrol {Pen Width} parameter.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 3
|
||||
|
||||
The pen style defines the line type. The default style is solid
|
||||
(Qt::SolidLine). Setting the style to none (Qt::NoPen) tells the
|
||||
painter to not draw lines or outlines. The pen cap defines how
|
||||
the end points of lines are drawn. And the pen join defines how
|
||||
two lines join when multiple connected lines are drawn. The cap
|
||||
and join only apply to lines with a width of 1 pixel or greater.
|
||||
|
||||
We create \l {QComboBox}es for each of the \uicontrol {Pen Style}, \uicontrol
|
||||
{Pen Cap} and \uicontrol {Pen Join} parameters, and adds the associated
|
||||
items (i.e the values of the Qt::PenStyle, Qt::PenCapStyle and
|
||||
Qt::PenJoinStyle enums respectively).
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 4
|
||||
|
||||
The QBrush class defines the fill pattern of shapes drawn by a
|
||||
QPainter. The default brush style is Qt::NoBrush. This style tells
|
||||
the painter to not fill shapes. The standard style for filling is
|
||||
Qt::SolidPattern.
|
||||
|
||||
We create a QComboBox for the \uicontrol {Brush Style} parameter, and add
|
||||
the associated items (i.e. the values of the Qt::BrushStyle enum).
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 5
|
||||
\snippet painting/basicdrawing/window.cpp 6
|
||||
|
||||
Antialiasing is a feature that "smoothes" the pixels to create
|
||||
more even and less jagged lines, and can be applied using
|
||||
QPainter's render hints. QPainter::RenderHints are used to specify
|
||||
flags to QPainter that may or may not be respected by any given
|
||||
engine.
|
||||
|
||||
We simply create a QCheckBox for the \uicontrol Antialiasing option.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 7
|
||||
|
||||
The \uicontrol Transformations option implies a manipulation of the
|
||||
coordinate system that will appear as if the rendered shape is
|
||||
rotated in three dimensions.
|
||||
|
||||
We use the QPainter::translate(), QPainter::rotate() and
|
||||
QPainter::scale() functions to implement this feature represented
|
||||
in the main application window by a simple QCheckBox.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 8
|
||||
|
||||
Then we connect the parameter widgets with their associated slots
|
||||
using the static QObject::connect() function, ensuring that the \c
|
||||
RenderArea widget is updated whenever the user changes the shape,
|
||||
or any of the other parameters.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 9
|
||||
\snippet painting/basicdrawing/window.cpp 10
|
||||
|
||||
Finally, we add the various widgets to a layout, and call the \c
|
||||
shapeChanged(), \c penChanged(), and \c brushChanged() slots to
|
||||
initialize the application. We also turn on antialiasing.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 11
|
||||
|
||||
The \c shapeChanged() slot is called whenever the user changes the
|
||||
currently active shape.
|
||||
|
||||
First we retrieve the shape the user has chosen using the
|
||||
QComboBox::itemData() function. This function returns the data for
|
||||
the given role in the given index in the combobox. We use
|
||||
QComboBox::currentIndex() to retrieve the index of the shape, and
|
||||
the role is defined by the Qt::ItemDataRole enum; \c IdRole is an
|
||||
alias for Qt::UserRole.
|
||||
|
||||
Note that Qt::UserRole is only the first role that can be used for
|
||||
application-specific purposes. If you need to store different data
|
||||
in the same index, you can use different roles by simply
|
||||
incrementing the value of Qt::UserRole, for example: 'Qt::UserRole
|
||||
+ 1' and 'Qt::UserRole + 2'. However, it is a good programming
|
||||
practice to give each role their own name: 'myFirstRole =
|
||||
Qt::UserRole + 1' and 'mySecondRole = Qt::UserRole + 2'. Even
|
||||
though we only need a single role in this particular example, we
|
||||
add the following line of code to the beginning of the \c
|
||||
window.cpp file.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 0
|
||||
|
||||
The QComboBox::itemData() function returns the data as a QVariant,
|
||||
so we need to cast the data to \c RenderArea::Shape. If there is
|
||||
no data for the given role, the function returns
|
||||
QVariant::Invalid.
|
||||
|
||||
In the end we call the \c RenderArea::setShape() slot to update
|
||||
the \c RenderArea widget.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 12
|
||||
|
||||
We call the \c penChanged() slot whenever the user changes any of
|
||||
the pen parameters. Again we use the QComboBox::itemData()
|
||||
function to retrieve the parameters, and then we call the \c
|
||||
RenderArea::setPen() slot to update the \c RenderArea widget.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 13
|
||||
|
||||
The brushChanged() slot is called whenever the user changes the
|
||||
brush parameter which we retrieve using the QComboBox::itemData()
|
||||
function as before.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 14
|
||||
|
||||
If the brush parameter is a gradient fill, special actions are
|
||||
required.
|
||||
|
||||
The QGradient class is used in combination with QBrush to specify
|
||||
gradient fills. Qt currently supports three types of gradient
|
||||
fills: linear, radial and conical. Each of these is represented by
|
||||
a subclass of QGradient: QLinearGradient, QRadialGradient and
|
||||
QConicalGradient.
|
||||
|
||||
So if the brush style is Qt::LinearGradientPattern, we first
|
||||
create a QLinearGradient object with interpolation area between
|
||||
the coordinates passed as arguments to the constructor. The
|
||||
positions are specified using logical coordinates. Then we set the
|
||||
gradient's colors using the QGradient::setColorAt() function. The
|
||||
colors is defined using stop points which are composed by a
|
||||
position (between 0 and 1) and a QColor. The set of stop points
|
||||
describes how the gradient area should be filled. A gradient can
|
||||
have an arbitrary number of stop points.
|
||||
|
||||
In the end we call \c RenderArea::setBrush() slot to update the \c
|
||||
RenderArea widget's brush with the QLinearGradient object.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 15
|
||||
|
||||
A similar pattern of actions, as the one used for QLinearGradient,
|
||||
is used in the cases of Qt::RadialGradientPattern and
|
||||
Qt::ConicalGradientPattern.
|
||||
|
||||
The only difference is the arguments passed to the constructor:
|
||||
Regarding the QRadialGradient constructor the first argument is
|
||||
the center, and the second the radial gradient's radius. The third
|
||||
argument is optional, but can be used to define the focal point of
|
||||
the gradient inside the circle (the default focal point is the
|
||||
circle center). Regarding the QConicalGradient constructor, the
|
||||
first argument specifies the center of the conical, and the second
|
||||
specifies the start angle of the interpolation.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 16
|
||||
|
||||
If the brush style is Qt::TexturePattern we create a QBrush from a
|
||||
QPixmap. Then we call \c RenderArea::setBrush() slot to update the
|
||||
\c RenderArea widget with the newly created brush.
|
||||
|
||||
\snippet painting/basicdrawing/window.cpp 17
|
||||
|
||||
Otherwise we simply create a brush with the given style and a
|
||||
green color, and then call \c RenderArea::setBrush() slot to
|
||||
update the \c RenderArea widget with the newly created brush.
|
||||
|
||||
\section1 RenderArea Class Definition
|
||||
|
||||
The \c RenderArea class inherits QWidget, and renders multiple
|
||||
copies of the currently active shape using a QPainter.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.h 0
|
||||
|
||||
First we define a public \c Shape enum to hold the different
|
||||
shapes that can be rendered by the widget (i.e the shapes that can
|
||||
be rendered by a QPainter). Then we reimplement the constructor as
|
||||
well as two of QWidget's public functions: \l
|
||||
{QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
|
||||
{QWidget::sizeHint()}{sizeHint()}.
|
||||
|
||||
We also reimplement the QWidget::paintEvent() function to be able
|
||||
to draw the currently active shape according to the specified
|
||||
parameters.
|
||||
|
||||
We declare several private slots: The \c setShape() slot changes
|
||||
the \c RenderArea's shape, the \c setPen() and \c setBrush() slots
|
||||
modify the widget's pen and brush, and the \c setAntialiased() and
|
||||
\c setTransformed() slots modify the widget's respective
|
||||
properties.
|
||||
|
||||
\section1 RenderArea Class Implementation
|
||||
|
||||
In the constructor we initialize some of the widget's variables.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 0
|
||||
|
||||
We set its shape to be a \uicontrol Polygon, its antialiased property to
|
||||
be false and we load an image into the widget's pixmap
|
||||
variable. In the end we set the widget's background role, defining
|
||||
the brush from the widget's \l {QWidget::palette}{palette} that
|
||||
will be used to render the background. QPalette::Base is typically
|
||||
white.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 2
|
||||
|
||||
The \c RenderArea inherits QWidget's \l
|
||||
{QWidget::sizeHint()}{sizeHint} property holding the recommended
|
||||
size for the widget. If the value of this property is an invalid
|
||||
size, no size is recommended.
|
||||
|
||||
The default implementation of the QWidget::sizeHint() function
|
||||
returns an invalid size if there is no layout for the widget, and
|
||||
returns the layout's preferred size otherwise.
|
||||
|
||||
Our reimplementation of the function returns a QSize with a 400
|
||||
pixels width and a 200 pixels height.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 1
|
||||
|
||||
\c RenderArea also inherits QWidget's
|
||||
\l{QWidget::minimumSizeHint()}{minimumSizeHint} property holding
|
||||
the recommended minimum size for the widget. Again, if the value
|
||||
of this property is an invalid size, no size is recommended.
|
||||
|
||||
The default implementation of QWidget::minimumSizeHint() returns
|
||||
an invalid size if there is no layout for the widget, and returns
|
||||
the layout's minimum size otherwise.
|
||||
|
||||
Our reimplementation of the function returns a QSize with a 100
|
||||
pixels width and a 100 pixels height.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 3
|
||||
\codeline
|
||||
\snippet painting/basicdrawing/renderarea.cpp 4
|
||||
\codeline
|
||||
\snippet painting/basicdrawing/renderarea.cpp 5
|
||||
|
||||
The public \c setShape(), \c setPen() and \c setBrush() slots are
|
||||
called whenever we want to modify a \c RenderArea widget's shape,
|
||||
pen or brush. We set the shape, pen or brush according to the
|
||||
slot parameter, and call QWidget::update() to make the changes
|
||||
visible in the \c RenderArea widget.
|
||||
|
||||
The QWidget::update() slot does not cause an immediate
|
||||
repaint; instead it schedules a paint event for processing when Qt
|
||||
returns to the main event loop.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 6
|
||||
\codeline
|
||||
\snippet painting/basicdrawing/renderarea.cpp 7
|
||||
|
||||
With the \c setAntialiased() and \c setTransformed() slots we
|
||||
change the state of the properties according to the slot
|
||||
parameter, and call the QWidget::update() slot to make the changes
|
||||
visible in the \c RenderArea widget.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 8
|
||||
|
||||
Then we reimplement the QWidget::paintEvent() function. The first
|
||||
thing we do is to create the graphical objects we will need to
|
||||
draw the various shapes.
|
||||
|
||||
We create a vector of four \l {QPoint}s. We use this vector to
|
||||
render the \uicontrol Points, \uicontrol Polyline and \uicontrol Polygon
|
||||
shapes. Then we create a QRect, defining a rectangle in the plane,
|
||||
which we use as the bounding rectangle for all the shapes excluding
|
||||
the \uicontrol Path and the \uicontrol Pixmap.
|
||||
|
||||
We also create a QPainterPath. The QPainterPath class provides a
|
||||
container for painting operations, enabling graphical shapes to be
|
||||
constructed and reused. A painter path is an object composed of a
|
||||
number of graphical building blocks, such as rectangles, ellipses,
|
||||
lines, and curves. For more information about the QPainterPath
|
||||
class, see the \l {painting/painterpaths}{Painter Paths}
|
||||
example. In this example, we create a painter path composed of one
|
||||
straight line and a Bezier curve.
|
||||
|
||||
In addition we define a start angle and an arc length that we will
|
||||
use when drawing the \uicontrol Arc, \uicontrol Chord and \uicontrol Pie shapes.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 9
|
||||
|
||||
We create a QPainter for the \c RenderArea widget, and set the
|
||||
painters pen and brush according to the \c RenderArea's pen and
|
||||
brush. If the \uicontrol Antialiasing parameter option is checked, we
|
||||
also set the painter's render hints. QPainter::Antialiasing
|
||||
indicates that the engine should antialias edges of primitives if
|
||||
possible.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 10
|
||||
|
||||
Finally, we render the multiple copies of the \c RenderArea's
|
||||
shape. The number of copies is depending on the size of the \c
|
||||
RenderArea widget, and we calculate their positions using two \c
|
||||
for loops and the widgets height and width.
|
||||
|
||||
For each copy we first save the current painter state (pushes the
|
||||
state onto a stack). Then we translate the coordinate system,
|
||||
using the QPainter::translate() function, to the position
|
||||
determined by the variables of the \c for loops. If we omit this
|
||||
translation of the coordinate system all the copies of the shape
|
||||
will be rendered on top of each other in the top left cormer of
|
||||
the \c RenderArea widget.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 11
|
||||
|
||||
If the \uicontrol Transformations parameter option is checked, we do an
|
||||
additional translation of the coordinate system before we rotate
|
||||
the coordinate system 60 degrees clockwise using the
|
||||
QPainter::rotate() function and scale it down in size using the
|
||||
QPainter::scale() function. In the end we translate the coordinate
|
||||
system back to where it was before we rotated and scaled it.
|
||||
|
||||
Now, when rendering the shape, it will appear as if it was rotated
|
||||
in three dimensions.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 12
|
||||
|
||||
Next, we identify the \c RenderArea's shape, and render it using
|
||||
the associated QPainter drawing function:
|
||||
|
||||
\list
|
||||
\li QPainter::drawLine(),
|
||||
\li QPainter::drawPoints(),
|
||||
\li QPainter::drawPolyline(),
|
||||
\li QPainter::drawPolygon(),
|
||||
\li QPainter::drawRect(),
|
||||
\li QPainter::drawRoundedRect(),
|
||||
\li QPainter::drawEllipse(),
|
||||
\li QPainter::drawArc(),
|
||||
\li QPainter::drawChord(),
|
||||
\li QPainter::drawPie(),
|
||||
\li QPainter::drawPath(),
|
||||
\li QPainter::drawText() or
|
||||
\li QPainter::drawPixmap()
|
||||
\endlist
|
||||
|
||||
Before we started rendering, we saved the current painter state
|
||||
(pushes the state onto a stack). The rationale for this is that we
|
||||
calculate each shape copy's position relative to the same point in
|
||||
the coordinate system. When translating the coordinate system, we
|
||||
lose the knowledge of this point unless we save the current
|
||||
painter state \e before we start the translating process.
|
||||
|
||||
\snippet painting/basicdrawing/renderarea.cpp 13
|
||||
|
||||
Then, when we are finished rendering a copy of the shape we can
|
||||
restore the original painter state, with its associated coordinate
|
||||
system, using the QPainter::restore() function. In this way we
|
||||
ensure that the next shape copy will be rendered in the correct
|
||||
position.
|
||||
|
||||
We could translate the coordinate system back using
|
||||
QPainter::translate() instead of saving the painter state. But
|
||||
since we in addition to translating the coordinate system (when
|
||||
the \uicontrol Transformation parameter option is checked) both rotate
|
||||
and scale the coordinate system, the easiest solution is to save
|
||||
the current painter state.
|
||||
*/
|
142
examples/widgets/doc/src/basicgraphicslayouts.qdoc
Normal file
@ -0,0 +1,142 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example graphicsview/basicgraphicslayouts
|
||||
\title Basic Graphics Layouts Example
|
||||
\ingroup examples-graphicsview-layout
|
||||
\brief Demonstrates how to create basic graphics layout.
|
||||
|
||||
The Basic Graphics Layouts example shows how to use the layout classes
|
||||
in QGraphicsView: QGraphicsLinearLayout and QGraphicsGridLayout.
|
||||
In addition to that it shows how to write your own custom layout item.
|
||||
|
||||
\image basicgraphicslayouts-example.png Screenshot of the Basic Layouts Example
|
||||
|
||||
\section1 Window Class Definition
|
||||
|
||||
The \c Window class is a subclass of QGraphicsWidget. It has a
|
||||
constructor with a QGraphicsWidget \a parent as its parameter.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/window.h 0
|
||||
|
||||
\section1 Window Class Implementation
|
||||
|
||||
The constructor of \c Window instantiates a QGraphicsLinearLayout object,
|
||||
\c windowLayout, with vertical orientation. We instantiate another
|
||||
QGraphicsLinearLayout object, \c linear, whose parent is \c windowLayout.
|
||||
Next, we create a \c LayoutItem object, \c item and add it to \c linear
|
||||
with the \l{QGraphicsLinearLayout::}{addItem()} function. We also provide
|
||||
\c item with a \l{QGraphicsLinearLayout::setStretchFactor()}
|
||||
{stretchFactor}.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/window.cpp 0
|
||||
|
||||
We repeat the process:
|
||||
|
||||
\list
|
||||
\li create a new \c LayoutItem,
|
||||
\li add the item \c linear, and
|
||||
\li provide a stretch factor.
|
||||
\endlist
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/window.cpp 1
|
||||
|
||||
We then add \c linear to \c windowLayout, nesting two
|
||||
QGraphicsLinearLayout objects. Apart from the QGraphicsLinearLayout, we
|
||||
also use a QGraphicsGridLayout object, \c grid, which is a 4x3 grid with
|
||||
some cells spanning to other rows.
|
||||
|
||||
We create seven \c LayoutItem objects and place them into \c grid with
|
||||
the \l{QGraphicsGridLayout::}{addItem()} function as shown in the code
|
||||
snippet below:
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/window.cpp 2
|
||||
|
||||
The first item we add to \c grid is placed in the top left cell,
|
||||
spanning four rows. The next two items are placed in the second column,
|
||||
and they span two rows. Each item's \l{QGraphicsWidget::}{maximumHeight()}
|
||||
and \l{QGraphicsWidget::}{minimumHeight()} are set to be equal so that
|
||||
they do not expand vertically. As a result, these items will not
|
||||
fit vertically in their cells. So, we specify that they should be
|
||||
vertically aligned in the center of the cell using Qt::AlignVCenter.
|
||||
|
||||
Finally, \c grid itself is added to \c windowLayout. Unlike
|
||||
QGridLayout::addItem(), QGraphicsGridLayout::addItem() requires a row
|
||||
and a column for its argument, specifying which cell the item should be
|
||||
positioned in. Also, if the \c rowSpan and \c columnSpan arguments
|
||||
are omitted, they will default to 1.
|
||||
|
||||
Note that we do not specify a parent for each \c LayoutItem that we
|
||||
construct, as all these items will be added to \c windowLayout. When we
|
||||
add an item to a layout, it will be automatically reparented to the widget
|
||||
on which the layout is installed.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/window.cpp 3
|
||||
|
||||
Now that we have set up \c grid and added it to \c windowLayout, we
|
||||
install \c windowLayout onto the window object using
|
||||
QGraphicsWidget::setLayout() and we set the window title.
|
||||
|
||||
\section1 LayoutItem Class Definition
|
||||
|
||||
The \c LayoutItem class is a subclass of QGraphicsLayoutItem and
|
||||
QGraphicsItem. It has a constructor, a destructor, and some required
|
||||
reimplementations.
|
||||
Since it inherits QGraphicsLayoutItem it must reimplement
|
||||
{QGraphicsLayoutItem::setGeometry()}{setGeometry()} and
|
||||
{QGraphicsLayoutItem::sizeHint()}{sizeHint()}.
|
||||
In addition to that it inherits QGraphicsItem, so it must reimplement
|
||||
{QGraphicsItem::boundingRect()}{boundingRect()} and
|
||||
{QGraphicsItem::paint()}{paint()}.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.h 0
|
||||
|
||||
The \c LayoutItem class also has a private instance of QPixmap, \c m_pix.
|
||||
|
||||
\section1 LayoutItem Class Implementation
|
||||
|
||||
In \c{LayoutItem}'s constructor, \c m_pix is instantiated and the
|
||||
\c{block.png} image is loaded into it.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.cpp 0
|
||||
|
||||
We use the Q_UNUSED() macro to prevent the compiler from generating
|
||||
warnings regarding unused parameters.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.cpp 1
|
||||
|
||||
The idea behind the \c paint() function is to paint the
|
||||
background rect then paint a rect around the pixmap.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.cpp 2
|
||||
|
||||
The reimplementation of \l{QGraphicsItem::}{boundingRect()}
|
||||
will set the top left corner at (0,0), and the size of it will be
|
||||
the size of the layout items
|
||||
\l{QGraphicsLayoutItem::}{geometry()}. This is the area that
|
||||
we paint within.
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.cpp 3
|
||||
|
||||
|
||||
The reimplementation of \l{QGraphicsLayoutItem::setGeometry()}{setGeometry()}
|
||||
simply calls its baseclass implementation. However, since this will change
|
||||
the boundingRect we must also call
|
||||
\l{QGraphicsItem::prepareGeometryChange()}{prepareGeometryChange()}.
|
||||
Finally, we move the item according to \c geom.topLeft().
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.cpp 4
|
||||
|
||||
|
||||
Since we don't want the size of the item to be smaller than the pixmap, we
|
||||
must make sure that we return a size hint that is larger than \c m_pix.
|
||||
We also add some extra space around for borders that we will paint later.
|
||||
Alternatively, you could scale the pixmap to prevent the item from
|
||||
becoming smaller than the pixmap.
|
||||
The preferred size is the same as the minimum size hint, while we set
|
||||
maximum to be a large value
|
||||
|
||||
\snippet graphicsview/basicgraphicslayouts/layoutitem.cpp 5
|
||||
|
||||
*/
|
170
examples/widgets/doc/src/basiclayouts.qdoc
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example layouts/basiclayouts
|
||||
\title Basic Layouts Example
|
||||
\brief Shows how to use the standard layout managers.
|
||||
|
||||
\e{Basic Layouts} shows how to use the standard layout managers that are
|
||||
available in Qt: QBoxLayout, QGridLayout, and QFormLayout.
|
||||
|
||||
\image basiclayouts-example.png Screenshot of the Basic Layouts example
|
||||
|
||||
The QBoxLayout class lines up widgets horizontally or vertically.
|
||||
QHBoxLayout and QVBoxLayout are convenience subclasses of QBoxLayout.
|
||||
QGridLayout lays out widgets in cells by dividing the available space
|
||||
into rows and columns. QFormLayout, on the other hand, sets its
|
||||
children in a two-column form with labels in the left column and
|
||||
input fields in the right column.
|
||||
|
||||
For more information, visit the \l{Layout Management} page.
|
||||
|
||||
\include examples-run.qdocinc
|
||||
|
||||
\section1 Dialog Class Definition
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.h 0
|
||||
|
||||
The \c Dialog class inherits QDialog. It is a custom widget that
|
||||
displays its child widgets using the geometry managers:
|
||||
QHBoxLayout, QVBoxLayout, QGridLayout, and QFormLayout.
|
||||
|
||||
There are four private functions to simplify the class
|
||||
constructor: the \c createMenu(), \c createHorizontalGroupBox(),
|
||||
\c createGridGroupBox(), and \c createFormGroupBox() functions create
|
||||
several widgets that the example uses to demonstrate how the layout
|
||||
affects their appearances.
|
||||
|
||||
\section1 Dialog Class Implementation
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 0
|
||||
|
||||
In the constructor, we first use the \c createMenu() function to
|
||||
create and populate a menu bar and the \c createHorizontalGroupBox()
|
||||
function to create a group box containing four buttons with a
|
||||
horizontal layout. Next, we use the \c createGridGroupBox() function
|
||||
to create a group box containing several line edits and a small text
|
||||
editor which are displayed in a grid layout. Finally, we use the
|
||||
\c createFormGroupBox() function to create a group box with
|
||||
three labels and three input fields: a line edit, a combo box, and
|
||||
a spin box.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 1
|
||||
|
||||
We also create a big text editor and a dialog button box. The
|
||||
QDialogButtonBox class is a widget that presents buttons in a
|
||||
layout that is appropriate to the current widget style. The
|
||||
preferred buttons can be specified as arguments to the
|
||||
constructor, using the QDialogButtonBox::StandardButtons enum.
|
||||
|
||||
Note that we don't have to specify a parent for the widgets when
|
||||
we create them. The reason is that all the widgets we create here
|
||||
will be added to a layout, and when we add a widget to a layout,
|
||||
it is automatically reparented to the widget the layout is
|
||||
installed on.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 2
|
||||
|
||||
The main layout is a QVBoxLayout object. QVBoxLayout is a
|
||||
convenience class for a box layout with vertical orientation.
|
||||
|
||||
In general, the QBoxLayout class takes the space it gets (from its
|
||||
parent layout or from the parent widget), divides it up into a
|
||||
series of boxes, and makes each managed widget fill one box. If
|
||||
the QBoxLayout's orientation is Qt::Horizontal the boxes are
|
||||
placed in a row. If the orientation is Qt::Vertical, the boxes are
|
||||
placed in a column. The corresponding convenience classes are
|
||||
QHBoxLayout and QVBoxLayout, respectively.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 3
|
||||
|
||||
When we call the QLayout::setMenuBar() function, the layout places
|
||||
the provided menu bar at the top of the parent widget, and outside
|
||||
the widget's \l {QWidget::contentsRect()}{content margins}. All
|
||||
child widgets are placed below the bottom edge of the menu bar.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 4
|
||||
|
||||
We use the QBoxLayout::addWidget() function to add the widgets to
|
||||
the end of the layout. Each widget will get at least its minimum size
|
||||
and at most its maximum size. It is possible to specify a stretch
|
||||
factor in the \l {QBoxLayout::addWidget()}{addWidget()} function,
|
||||
and any excess space is shared according to these stretch
|
||||
factors. If not specified, a widget's stretch factor is 0.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 5
|
||||
|
||||
We install the main layout on the \c Dialog widget using the
|
||||
QWidget::setLayout() function, and all of the layout's widgets are
|
||||
automatically reparented to be children of the \c Dialog widget.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 6
|
||||
|
||||
In the private \c createMenu() function we create a menu bar, and
|
||||
add a pull-down \uicontrol File menu containing an \uicontrol Exit option.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 7
|
||||
|
||||
When we create the horizontal group box, we use a QHBoxLayout as
|
||||
the internal layout. We create the buttons we want to put in the
|
||||
group box, add them to the layout and install the layout on the
|
||||
group box.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 8
|
||||
|
||||
In the \c createGridGroupBox() function we use a QGridLayout which
|
||||
lays out widgets in a grid. It takes the space made available to
|
||||
it (by its parent layout or by the parent widget), divides it up
|
||||
into rows and columns, and puts each widget it manages into the
|
||||
correct cell.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 9
|
||||
|
||||
For each row in the grid we create a label and an associated line
|
||||
edit, and add them to the layout. The QGridLayout::addWidget()
|
||||
function differ from the corresponding function in QBoxLayout: It
|
||||
needs the row and column specifying the grid cell to put the
|
||||
widget in.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 10
|
||||
|
||||
QGridLayout::addWidget() can in addition take arguments
|
||||
specifying the number of rows and columns the cell will be
|
||||
spanning. In this example, we create a small editor which spans
|
||||
three rows and one column.
|
||||
|
||||
For both the QBoxLayout::addWidget() and QGridLayout::addWidget()
|
||||
functions it is also possible to add a last argument specifying
|
||||
the widget's alignment. By default it fills the whole cell. But we
|
||||
could, for example, align a widget with the right edge by
|
||||
specifying the alignment to be Qt::AlignRight.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 11
|
||||
|
||||
Each column in a grid layout has a stretch factor. The stretch
|
||||
factor is set using QGridLayout::setColumnStretch() and determines
|
||||
how much of the available space the column will get over and above
|
||||
its necessary minimum.
|
||||
|
||||
In this example, we set the stretch factors for columns 1 and 2.
|
||||
The stretch factor is relative to the other columns in this grid;
|
||||
columns with a higher stretch factor take more of the available
|
||||
space. So column 2 in our grid layout will get more of the
|
||||
available space than column 1, and column 0 will not grow at all
|
||||
since its stretch factor is 0 (the default).
|
||||
|
||||
Columns and rows behave identically; there is an equivalent
|
||||
stretch factor for rows, as well as a QGridLayout::setRowStretch()
|
||||
function.
|
||||
|
||||
\snippet layouts/basiclayouts/dialog.cpp 12
|
||||
|
||||
In the \c createFormGroupBox() function, we use a QFormLayout
|
||||
to neatly arrange objects into two columns - name and field.
|
||||
There are three QLabel objects for names with three
|
||||
corresponding input widgets as fields: a QLineEdit, a QComboBox
|
||||
and a QSpinBox. Unlike QBoxLayout::addWidget() and
|
||||
QGridLayout::addWidget(), we use QFormLayout::addRow() to add widgets
|
||||
to the layout.
|
||||
*/
|
13
examples/widgets/doc/src/basicsortfiltermodel.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 itemviews/basicsortfiltermodel
|
||||
\title Basic Sort/Filter Model Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Basic Sort/Filter Model example illustrates how to use
|
||||
QSortFilterProxyModel to perform basic sorting and filtering.
|
||||
|
||||
\image basicsortfiltermodel-example.png Screenshot of the Basic Sort/Filter Model Example
|
||||
|
||||
*/
|
20
examples/widgets/doc/src/blurpicker.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 effects/blurpicker
|
||||
\title Blur Picker Effect Example
|
||||
\ingroup examples-graphicsview-graphicseffects
|
||||
\brief Demonstrates how to apply graphical effects on items in the view.
|
||||
|
||||
\image blurpickereffect-example.png
|
||||
|
||||
The Blur Picker example displays a circle of application icons.
|
||||
All icons are blurred, except the one on the bottom left side of
|
||||
the screen, which is the one in focus.
|
||||
Clicking anywhere on the left side of the screen moves the icon
|
||||
circle clockwise to the next icon
|
||||
Clicking on the right side advances the circle counterclockwise.
|
||||
|
||||
\sa QGraphicsBlurEffect
|
||||
*/
|
46
examples/widgets/doc/src/borderlayout.qdoc
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example layouts/borderlayout
|
||||
\title Border Layout Example
|
||||
\ingroup examples-layout
|
||||
\brief Shows how to arrange child widgets along a border.
|
||||
|
||||
\e{Border Layout} implements a layout that arranges child widgets to
|
||||
surround the main area.
|
||||
|
||||
\image borderlayout-example.png
|
||||
|
||||
The constructor of the Window class creates a QTextBrowser object,
|
||||
to which a BorderLayout named \c layout is added. The declaration
|
||||
of the BorderLayout class is quoted at the end of this document.
|
||||
|
||||
\quotefromfile layouts/borderlayout/window.cpp
|
||||
\skipto Window::Window()
|
||||
\printuntil BorderLayout
|
||||
|
||||
Several labeled widgets are added to \c layout with the orientation
|
||||
\c {Center}, \c {North}, \c {West}, \c {East 1}, \c {East 2}, and
|
||||
\c {South}.
|
||||
|
||||
\skipto layout->addWidget
|
||||
\printuntil setWindowTitle
|
||||
|
||||
createLabel() in class \c Window sets the text of the labeled widgets
|
||||
and the style.
|
||||
|
||||
\skipto QLabel *Window::createLabel
|
||||
\printuntil /^\}/
|
||||
|
||||
Class BorderLayout contains all the utilitarian functions for formatting
|
||||
the widgets it contains.
|
||||
|
||||
\quotefromfile layouts/borderlayout/borderlayout.h
|
||||
\skipto class
|
||||
\printuntil /^\}/
|
||||
|
||||
For more information, visit the \l{Layout Management} page.
|
||||
|
||||
\include examples-run.qdocinc
|
||||
*/
|
357
examples/widgets/doc/src/calculator.qdoc
Normal file
@ -0,0 +1,357 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/calculator
|
||||
\title Calculator Example
|
||||
\ingroup examples-widgets
|
||||
\ingroup examples-layout
|
||||
\brief 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.
|
||||
|
||||
\borderedimage calculator-example.png
|
||||
\caption Screenshot of the Calculator example
|
||||
|
||||
The example consists of two classes:
|
||||
|
||||
\list
|
||||
\li \c Calculator is the calculator widget, with all the
|
||||
calculator functionality.
|
||||
\li \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 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 \uicontrol 0 to \uicontrol 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 (\uicontrol{Sqrt}, \uicontrol{x\unicode{178}},
|
||||
\uicontrol{1/x}), additive operators (\uicontrol{+}, \uicontrol{-}), and
|
||||
multiplicative operators (\uicontrol{\unicode{215}}, \uicontrol{\unicode{247}}). The other buttons
|
||||
have their own slots.
|
||||
|
||||
\snippet widgets/calculator/calculator.h 1
|
||||
\snippet 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 (\uicontrol{+}, \uicontrol{-}, \uicontrol{\unicode{215}}, or \uicontrol{\unicode{247}}).
|
||||
|
||||
\snippet widgets/calculator/calculator.h 3
|
||||
\snippet widgets/calculator/calculator.h 4
|
||||
\snippet widgets/calculator/calculator.h 5
|
||||
\snippet widgets/calculator/calculator.h 6
|
||||
\snippet widgets/calculator/calculator.h 7
|
||||
\snippet widgets/calculator/calculator.h 8
|
||||
|
||||
These variables, together with the contents of the calculator
|
||||
display (a QLineEdit), encode the state of the calculator:
|
||||
|
||||
\list
|
||||
\li \c sumInMemory contains the value stored in the calculator's memory
|
||||
(using \uicontrol{MS}, \uicontrol{M+}, or \uicontrol{MC}).
|
||||
\li \c sumSoFar stores the value accumulated so far. When the user
|
||||
clicks \uicontrol{=}, \c sumSoFar is recomputed and shown on the
|
||||
display. \uicontrol{Clear All} resets \c sumSoFar to zero.
|
||||
\li \c factorSoFar stores a temporary value when doing
|
||||
multiplications and divisions.
|
||||
\li \c pendingAdditiveOperator stores the last additive operator
|
||||
clicked by the user.
|
||||
\li \c pendingMultiplicativeOperator stores the last multiplicative operator
|
||||
clicked by the user.
|
||||
\li \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, \uicontrol{1 + 2 \unicode{247}
|
||||
3} is interpreted as \uicontrol{1 + (2 \unicode{247} 3)} because \uicontrol{\unicode{247}} has higher
|
||||
precedence than \uicontrol{+}.
|
||||
|
||||
The table below shows the evolution of the calculator state as
|
||||
the user enters a mathematical expression.
|
||||
|
||||
\table
|
||||
\header \li User Input \li Display \li Sum so Far \li Add. Op. \li Factor so Far \li Mult. Op. \li Waiting for Operand?
|
||||
\row \li \li 0 \li 0 \li \li \li \li \c true
|
||||
\row \li \uicontrol{1} \li 1 \li 0 \li \li \li \li \c false
|
||||
\row \li \uicontrol{1 +} \li 1 \li 1 \li \uicontrol{+} \li \li \li \c true
|
||||
\row \li \uicontrol{1 + 2} \li 2 \li 1 \li \uicontrol{+} \li \li \li \c false
|
||||
\row \li \uicontrol{1 + 2 \unicode{247}} \li 2 \li 1 \li \uicontrol{+} \li 2 \li \uicontrol{\unicode{247}} \li \c true
|
||||
\row \li \uicontrol{1 + 2 \unicode{247} 3} \li 3 \li 1 \li \uicontrol{+} \li 2 \li \uicontrol{\unicode{247}} \li \c false
|
||||
\row \li \uicontrol{1 + 2 \unicode{247} 3 -} \li 1.66667 \li 1.66667 \li \uicontrol{-} \li \li \li \c true
|
||||
\row \li \uicontrol{1 + 2 \unicode{247} 3 - 4} \li 4 \li 1.66667 \li \uicontrol{-} \li \li \li \c false
|
||||
\row \li \uicontrol{1 + 2 \unicode{247} 3 - 4 =} \li -2.33333 \li 0 \li \li \li \li \c true
|
||||
\endtable
|
||||
|
||||
Unary operators, such as \uicontrol Sqrt, require no special handling;
|
||||
they can be applied immediately since the operand is already
|
||||
known when the operator button is clicked.
|
||||
|
||||
\snippet widgets/calculator/calculator.h 9
|
||||
\codeline
|
||||
\snippet 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 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.
|
||||
It is also possible to initialize those variable directly in the
|
||||
header. This is called \c member-initializaton and avoids a long
|
||||
initialization list.
|
||||
|
||||
\snippet widgets/calculator/calculator.cpp 1
|
||||
\snippet 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 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 widgets/calculator/calculator.cpp 5
|
||||
\snippet 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 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 \uicontrol{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 widgets/calculator/calculator.cpp 8
|
||||
\snippet 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 \uicontrol Sqrt is applied to a
|
||||
negative number or \uicontrol{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 widgets/calculator/calculator.cpp 10
|
||||
\snippet widgets/calculator/calculator.cpp 11
|
||||
|
||||
The \c additiveOperatorClicked() slot is called when the user
|
||||
clicks the \uicontrol{+} or \uicontrol{-} 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 widgets/calculator/calculator.cpp 12
|
||||
\snippet widgets/calculator/calculator.cpp 13
|
||||
|
||||
If \uicontrol{\unicode{215}} or \uicontrol{\unicode{247}} has been clicked earlier, without clicking
|
||||
\uicontrol{=} afterward, the current value in the display is the right
|
||||
operand of the \uicontrol{\unicode{215}} or \uicontrol{\unicode{247}} operator and we can finally
|
||||
perform the operation and update the display.
|
||||
|
||||
\snippet widgets/calculator/calculator.cpp 14
|
||||
\snippet widgets/calculator/calculator.cpp 15
|
||||
|
||||
If \uicontrol{+} or \uicontrol{-} 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 widgets/calculator/calculator.cpp 16
|
||||
\snippet 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 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 widgets/calculator/calculator.cpp 20
|
||||
|
||||
Like in \c additiveOperatorClicked(), we start by handling 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 widgets/calculator/calculator.cpp 22
|
||||
|
||||
The \c pointClicked() slot adds a decimal point to the content in
|
||||
\c display.
|
||||
|
||||
\snippet 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 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 widgets/calculator/calculator.cpp 28
|
||||
|
||||
The \c clear() slot resets the current operand to zero. It is
|
||||
equivalent to clicking \uicontrol Backspace enough times to erase the
|
||||
entire operand.
|
||||
|
||||
\snippet widgets/calculator/calculator.cpp 30
|
||||
|
||||
The \c clearAll() slot resets the calculator to its initial state.
|
||||
|
||||
\snippet 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 widgets/calculator/calculator.cpp 34
|
||||
|
||||
The private \c createButton() function is called from the
|
||||
constructor to create calculator buttons.
|
||||
|
||||
\snippet widgets/calculator/calculator.cpp 36
|
||||
|
||||
The private \c abortOperation() function is called whenever a
|
||||
calculation fails. It resets the calculator state and displays
|
||||
"####".
|
||||
|
||||
\snippet 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 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 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 widgets/calculator/button.cpp 1
|
||||
\snippet 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
|
||||
\li We add 20 to the \l{QSize::height()}{height} component of the size hint.
|
||||
\li 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
|
||||
\uicontrol{Backspace}, \uicontrol{Clear}, and \uicontrol{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().
|
||||
|
||||
\borderedimage calculator-ugly.png
|
||||
\caption The Calculator example with default size policies and size hints
|
||||
|
||||
*/
|
202
examples/widgets/doc/src/calendar.qdoc
Normal file
@ -0,0 +1,202 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example richtext/calendar
|
||||
\title Calendar Example
|
||||
\ingroup examples-richtext
|
||||
\brief The Calendar example shows how to create rich text content
|
||||
and display it using a rich text editor.
|
||||
|
||||
\brief The Calendar example shows how to create rich text content and display it using
|
||||
a rich text editor.
|
||||
|
||||
\image calendar-example.png
|
||||
|
||||
Specifically, the example demonstrates the following:
|
||||
|
||||
\list
|
||||
\li Use of a text editor with a text document
|
||||
\li Insertion of tables and frames into a document
|
||||
\li Navigation within a table
|
||||
\li Insert text in different styles
|
||||
\endlist
|
||||
|
||||
The rich text editor used to display the document is used within a main window
|
||||
application.
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
The \c MainWindow class provides a text editor widget and some controls to
|
||||
allow the user to change the month and year shown. The font size used for the
|
||||
text can also be adjusted.
|
||||
|
||||
\snippet richtext/calendar/mainwindow.h 0
|
||||
|
||||
The private \c insertCalendar() function performs most of the work, relying on
|
||||
the \c fontSize and \c selectedDate variables to write useful information to
|
||||
the \c editor.
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
The \c MainWindow constructor sets up the user interface and initializes
|
||||
variables used to generate a calendar for each month.
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 0
|
||||
|
||||
We begin by setting default values for the selected date that will be highlighted
|
||||
in the calendar and the font size to be used. Since we are using a QMainWindow
|
||||
for the user interface, we construct a widget for use as the central widget.
|
||||
|
||||
The user interface will include a line of controls above the generated calendar;
|
||||
we construct a label and a combobox to allow the month to be selected, and a
|
||||
spin box for the year. These widgets are configured to provide a reasonable range
|
||||
of values for the user to try:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 1
|
||||
|
||||
We use the \c selectedDate object to obtain the current month and year, and we
|
||||
set these in the combobox and spin box:
|
||||
|
||||
The font size is displayed in a spin box which we restrict to a sensible range
|
||||
of values:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 2
|
||||
|
||||
We construct an editor and use the \c insertCalendar() function to create
|
||||
a calendar for it. Each calendar is displayed in the same text editor; in
|
||||
this example we use a QTextBrowser since we do not allow the calendar to be
|
||||
edited.
|
||||
|
||||
The controls used to set the month, year, and font size will not have any
|
||||
effect on the appearance of the calendar unless we make some signal-slot
|
||||
connections:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 3
|
||||
|
||||
The signals are connected to some simple slots in the \c MainWindow class
|
||||
which we will describe later.
|
||||
|
||||
We create layouts to manage the widgets we constructed:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 4
|
||||
|
||||
Finally, the central widget is set for the window.
|
||||
|
||||
Each calendar is created for the editor by the \c insertCalendar() function
|
||||
which uses the date and font size, defined by the private \a selectedDate
|
||||
and \c fontSize variables, to produce a suitable plan for the specified
|
||||
month and year.
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 5
|
||||
|
||||
We begin by clearing the editor's rich text document, and obtain a text
|
||||
cursor from the editor that we will use to add content. We also create a
|
||||
QDate object based on the currently selected date.
|
||||
|
||||
The calendar is made up of a table with a gray background color that contains
|
||||
seven columns: one for each day of the week. It is placed in the center of the
|
||||
page with equal space to the left and right of it. All of these properties are
|
||||
set in a QTextTableFormat object:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 6
|
||||
|
||||
Each cell in the table will be padded and spaced to make the text easier to
|
||||
read.
|
||||
|
||||
We want the columns to have equal widths, so we provide a list containing
|
||||
percentage widths for each of them and set the constraints in the
|
||||
QTextTableFormat:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 7
|
||||
|
||||
The constraints used for the column widths are only useful if the table has
|
||||
an appropriate number of columns. With the format for the table defined, we
|
||||
construct a new table with one row and seven columns at the current cursor
|
||||
position:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 8
|
||||
|
||||
We only need one row to start with; more can be added as we need them. Using
|
||||
this approach means that we do not need to perform any date calculations
|
||||
until we add cells to the table.
|
||||
|
||||
When inserting objects into a document with the cursor's insertion functions,
|
||||
the cursor is automatically moved inside the newly inserted object. This means
|
||||
that we can immediately start modifying the table from within:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 9
|
||||
|
||||
Since the table has an outer frame, we obtain the frame and its format so that
|
||||
we can customize it. After making the changes we want, we set the frame's format
|
||||
using the modified format object. We have given the table an outer border one
|
||||
pixel wide.
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 10
|
||||
|
||||
In a similar way, we obtain the cursor's current character format and
|
||||
create customized formats based on it.
|
||||
|
||||
We do not set the format on the cursor because this would change the default
|
||||
character format; instead, we use the customized formats explicitly when we
|
||||
insert text. The following loop inserts the days of the week into the table
|
||||
as bold text:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 11
|
||||
|
||||
For each day of the week, we obtain an existing table cell in the first row
|
||||
(row 0) using the table's \l{QTextTable::cellAt()}{cellAt()} function. Since
|
||||
we start counting the days of the week at day 1 (Monday), we subtract 1 from
|
||||
\c weekDay to ensure that we obtain the cell for the correct column of the
|
||||
table.
|
||||
|
||||
Before text can be inserted into a cell, we must obtain a cursor with the
|
||||
correct position in the document. The cell provides a function for this
|
||||
purpose, and we use this cursor to insert text using the \c boldFormat
|
||||
character format that we created earlier:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 12
|
||||
|
||||
Inserting text into document objects usually follows the same pattern.
|
||||
Each object can provide a new cursor that corresponds to the first valid
|
||||
position within itself, and this can be used to insert new content. We
|
||||
continue to use this pattern as we insert the days of the month into the
|
||||
table.
|
||||
|
||||
Since every month has more than seven days, we insert a single row to begin
|
||||
and add days until we reach the end of the month. If the current date is
|
||||
encountered, it is inserted with a special format (created earlier) that
|
||||
makes it stand out:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 13
|
||||
|
||||
We add a new row to the table at the end of each week only if the next week
|
||||
falls within the currently selected month.
|
||||
|
||||
For each calendar that we create, we change the window title to reflect the
|
||||
currently selected month and year:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 14
|
||||
|
||||
The \c insertCalendar() function relies on up-to-date values for the month,
|
||||
year, and font size. These are set in the following slots:
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 15
|
||||
|
||||
The \c setFontSize() function simply changes the private \c fontSize variable
|
||||
before updating the calendar.
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 16
|
||||
|
||||
The \c setMonth slot is called when the QComboBox used to select the month is
|
||||
updated. The value supplied is the currently selected row in the combobox.
|
||||
We add 1 to this value to obtain a valid month number, and create a new QDate
|
||||
based on the existing one. The calendar is then updated to use this new date.
|
||||
|
||||
\snippet richtext/calendar/mainwindow.cpp 17
|
||||
|
||||
The \c setYear() slot is called when the QDateTimeEdit used to select the
|
||||
year is updated. The value supplied is a QDate object; this makes
|
||||
the construction of a new value for \c selectedDate simple. We update the
|
||||
calendar afterwards to use this new date.
|
||||
*/
|
268
examples/widgets/doc/src/calendarwidget.qdoc
Normal file
@ -0,0 +1,268 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\title Calendar Widget Example
|
||||
\example widgets/calendarwidget
|
||||
\ingroup examples-widgets
|
||||
\ingroup examples-layout
|
||||
\brief The Calendar Widget example shows use of QCalendarWidget.
|
||||
|
||||
\borderedimage calendarwidgetexample.png
|
||||
|
||||
QCalendarWidget displays one calendar month
|
||||
at a time and lets the user select a date.
|
||||
The calendar consists of four components: a navigation
|
||||
bar that lets the user change the month that is
|
||||
displayed, a grid where each cell represents one day
|
||||
in the month, and two headers that display weekday names
|
||||
and week numbers.
|
||||
|
||||
The Calendar Widget example displays a QCalendarWidget and lets the user
|
||||
configure its appearance and behavior using
|
||||
\l{QComboBox}es, \l{QCheckBox}es, and \l{QDateEdit}s. In
|
||||
addition, the user can influence the formatting of individual dates
|
||||
and headers.
|
||||
|
||||
The properties of the QCalendarWidget are summarized in the table
|
||||
below.
|
||||
|
||||
\table
|
||||
\header \li Property
|
||||
\li Description
|
||||
\row \li \l{QCalendarWidget::}{selectedDate}
|
||||
\li The currently selected date.
|
||||
\row \li \l{QCalendarWidget::}{minimumDate}
|
||||
\li The earliest date that can be selected.
|
||||
\row \li \l{QCalendarWidget::}{maximumDate}
|
||||
\li The latest date that can be selected.
|
||||
\row \li \l{QCalendarWidget::}{firstDayOfWeek}
|
||||
\li The day that is displayed as the first day of the week
|
||||
(usually Sunday or Monday).
|
||||
\row \li \l{QCalendarWidget::}{gridVisible}
|
||||
\li Whether the grid should be shown.
|
||||
\row \li \l{QCalendarWidget::}{selectionMode}
|
||||
\li Whether the user can select a date or not.
|
||||
\row \li \l{QCalendarWidget::}{horizontalHeaderFormat}
|
||||
\li The format of the day names in the horizontal header
|
||||
(e.g., "M", "Mon", or "Monday").
|
||||
\row \li \l{QCalendarWidget::}{verticalHeaderFormat}
|
||||
\li The format of the vertical header.
|
||||
\row \li \l{QCalendarWidget::}{navigationBarVisible}
|
||||
\li Whether the navigation bar at the top of the calendar
|
||||
widget is shown.
|
||||
\endtable
|
||||
|
||||
The example consists of one class, \c Window, which creates and
|
||||
lays out the QCalendarWidget and the other widgets that let the
|
||||
user configure the QCalendarWidget.
|
||||
|
||||
\section1 Window Class Definition
|
||||
|
||||
Here is the definition of the \c Window class:
|
||||
|
||||
\snippet widgets/calendarwidget/window.h 0
|
||||
\dots
|
||||
\snippet widgets/calendarwidget/window.h 1
|
||||
|
||||
As is often the case with classes that represent self-contained
|
||||
windows, most of the API is private. We will review the private
|
||||
members as we stumble upon them in the implementation.
|
||||
|
||||
\section1 Window Class Implementation
|
||||
|
||||
Let's now review the class implementation, starting with the constructor:
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 0
|
||||
|
||||
We start by creating the four \l{QGroupBox}es and their child
|
||||
widgets (including the QCalendarWidget) using four private \c
|
||||
create...GroupBox() functions, described below. Then we arrange
|
||||
the group boxes in a QGridLayout.
|
||||
|
||||
We set the grid layout's resize policy to QLayout::SetFixedSize to
|
||||
prevent the user from resizing the window. In that mode, the
|
||||
window's size is set automatically by QGridLayout based on the
|
||||
size hints of its contents widgets.
|
||||
|
||||
To ensure that the window isn't automatically resized every time
|
||||
we change a property of the QCalendarWidget (for example, hiding the
|
||||
navigation bar, the vertical header, or the grid), we set the
|
||||
minimum height of row 0 and the minimum width of column 0 to the
|
||||
initial size of the QCalendarWidget.
|
||||
|
||||
Let's move on to the \c createPreviewGroupBox() function:
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 9
|
||||
|
||||
The \uicontrol Preview group box contains only one widget: the
|
||||
QCalendarWidget. We set it up, connect its
|
||||
\l{QCalendarWidget::}{currentPageChanged()} signal to our \c
|
||||
reformatCalendarPage() slot to make sure that every new page gets
|
||||
the formatting specified by the user.
|
||||
|
||||
The \c createGeneralOptionsGroupBox() function is somewhat large
|
||||
and several widgets are set up in the same way. We will look at
|
||||
parts of its implementation here and skip the rest:
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 10
|
||||
\dots
|
||||
|
||||
We start with the setup of the \uicontrol{Week starts on} combobox.
|
||||
This combobox controls which day should be displayed as the first
|
||||
day of the week.
|
||||
|
||||
The QComboBox class lets us attach user data as a QVariant to
|
||||
each item. The data can later be retrieved with QComboBox's
|
||||
\l{QComboBox::}{itemData()} function. QVariant doesn't directly
|
||||
support the Qt::DayOfWeek data type, but it supports \c int, and
|
||||
C++ will happily convert any enum value to \c int.
|
||||
|
||||
\dots
|
||||
\snippet widgets/calendarwidget/window.cpp 11
|
||||
\dots
|
||||
|
||||
After having created the widgets, we connect the signals and slots. We
|
||||
connect the comboboxes to private slots of \c Window or to
|
||||
public slots provided by QComboBox.
|
||||
|
||||
\dots
|
||||
\snippet widgets/calendarwidget/window.cpp 12
|
||||
|
||||
At the end of the function, we call the slots that update the calendar to ensure
|
||||
that the QCalendarWidget is synchronized with the other widgets on startup.
|
||||
|
||||
Let's now take a look at the \c createDatesGroupBox() private function:
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 13
|
||||
|
||||
In this function, we create the \uicontrol {Minimum Date}, \uicontrol {Maximum Date},
|
||||
and \uicontrol {Current Date} editor widgets,
|
||||
which control the calendar's minimum, maximum, and selected dates.
|
||||
The calendar's minimum and maximum dates have already been
|
||||
set in \c createPrivewGroupBox(); we can then set the widgets
|
||||
default values to the calendars values.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 14
|
||||
\dots
|
||||
\snippet widgets/calendarwidget/window.cpp 15
|
||||
|
||||
We connect the \c currentDateEdit's
|
||||
\l{QDateEdit::}{dateChanged()} signal directly to the calendar's
|
||||
\l{QCalendarWidget::}{setSelectedDate()} slot. When the calendar's
|
||||
selected date changes, either as a result of a user action or
|
||||
programmatically, our \c selectedDateChanged() slot updates
|
||||
the \uicontrol {Current Date} editor. We also need to react when the user
|
||||
changes the \uicontrol{Minimum Date} and \uicontrol{Maximum Date} editors.
|
||||
|
||||
Here is the \c createTextFormatsGroup() function:
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 16
|
||||
|
||||
We set up the \uicontrol {Weekday Color} and \uicontrol {Weekend Color} comboboxes
|
||||
using \c createColorCombo(), which instantiates a QComboBox and
|
||||
populates it with colors ("Red", "Blue", etc.).
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 17
|
||||
|
||||
The \uicontrol {Header Text Format} combobox lets the user change the
|
||||
text format (bold, italic, or plain) used for horizontal and
|
||||
vertical headers. The \uicontrol {First Friday in blue} and \uicontrol {May 1
|
||||
in red} check box affect the rendering of specific dates.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 18
|
||||
|
||||
We connect the check boxes and comboboxes to various private
|
||||
slots. The \uicontrol {First Friday in blue} and \uicontrol {May 1 in red}
|
||||
check boxes are both connected to \c reformatCalendarPage(),
|
||||
which is also called when the calendar switches month.
|
||||
|
||||
\dots
|
||||
\snippet widgets/calendarwidget/window.cpp 19
|
||||
|
||||
At the end of \c createTextFormatsGroupBox(), we call private
|
||||
slots to synchronize the QCalendarWidget with the other widgets.
|
||||
|
||||
We're now done reviewing the four \c create...GroupBox()
|
||||
functions. Let's now take a look at the other private functions
|
||||
and slots.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 20
|
||||
|
||||
In \c createColorCombo(), we create a combobox and populate it with
|
||||
standard colors. The second argument to QComboBox::addItem()
|
||||
is a QVariant storing user data (in this case, QColor objects).
|
||||
|
||||
This function was used to set up the \uicontrol {Weekday Color}
|
||||
and \uicontrol {Weekend Color} comboboxes.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 1
|
||||
|
||||
When the user changes the \uicontrol {Week starts on} combobox's
|
||||
value, \c firstDayChanged() is invoked with the index of the
|
||||
combobox's new value. We retrieve the custom data item
|
||||
associated with the new current item using
|
||||
\l{QComboBox::}{itemData()} and cast it to a Qt::DayOfWeek.
|
||||
|
||||
\c selectionModeChanged(), \c horizontalHeaderChanged(), and \c
|
||||
verticalHeaderChanged() are very similar to \c firstDayChanged(),
|
||||
so they are omitted.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 2
|
||||
|
||||
The \c selectedDateChanged() updates the \uicontrol{Current Date}
|
||||
editor to reflect the current state of the QCalendarWidget.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 3
|
||||
|
||||
When the user changes the minimum date, we tell the
|
||||
QCalenderWidget. We also update the \uicontrol {Maximum Date} editor,
|
||||
because if the new minimum date is later than the current maximum
|
||||
date, QCalendarWidget will automatically adapt its maximum date
|
||||
to avoid a contradicting state.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 4
|
||||
|
||||
\c maximumDateChanged() is implemented similarly to \c
|
||||
minimumDateChanged().
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 5
|
||||
|
||||
Each combobox item has a QColor object as user data corresponding to the
|
||||
item's text. After fetching the colors from the comboboxes, we
|
||||
set the text format of each day of the week.
|
||||
|
||||
The text format of a column in the calendar is given as a
|
||||
QTextCharFormat, which besides the foreground color lets us
|
||||
specify various character formatting information. In this
|
||||
example, we only show a subset of the possibilities.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 6
|
||||
|
||||
\c weekendFormatChanged() is the same as \c
|
||||
weekdayFormatChanged(), except that it affects Saturday and
|
||||
Sunday instead of Monday to Friday.
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 7
|
||||
|
||||
The \c reformatHeaders() slot is called when the user
|
||||
changes the text format of
|
||||
the headers. We compare the current text of the \uicontrol {Header Text Format}
|
||||
combobox to determine which format to apply. (An alternative would
|
||||
have been to store \l{QTextCharFormat} values alongside the combobox
|
||||
items.)
|
||||
|
||||
\snippet widgets/calendarwidget/window.cpp 8
|
||||
|
||||
In \c reformatCalendarPage(), we set the text format of the first
|
||||
Friday in the month and May 1 in the current year. The text
|
||||
formats that are actually used depend on which check boxes are
|
||||
checked and what the weekday/weekend formats are.
|
||||
|
||||
QCalendarWidget lets us set the text format of individual dates
|
||||
with the \l{QCalendarWidget::}{setDateTextFormat()}. We chose to
|
||||
set the date formats when the calendar page changes - i.e. a new month is
|
||||
displayed - and when the weekday/weekend format is changed.
|
||||
We check which of the \c mayFirstCheckBox and \c firstDayCheckBox, if any,
|
||||
are checked and set the text formats accordingly.
|
||||
*/
|
251
examples/widgets/doc/src/charactermap.qdoc
Normal file
@ -0,0 +1,251 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/charactermap
|
||||
\title Character Map Example
|
||||
\ingroup examples-widgets
|
||||
\brief The Character Map example shows how to create a custom widget that can
|
||||
both display its own content and respond to user input.
|
||||
|
||||
The example displays an array of characters which the user can click on
|
||||
to enter text in a line edit. The contents of the line edit can then be
|
||||
copied into the clipboard, and pasted into other applications. The
|
||||
purpose behind this sort of tool is to allow users to enter characters
|
||||
that may be unavailable or difficult to locate on their keyboards.
|
||||
|
||||
\borderedimage charactermap-example.png
|
||||
\caption Screenshot of the Character Map example
|
||||
|
||||
The example consists of the following classes:
|
||||
|
||||
\list
|
||||
\li \c CharacterWidget displays the available characters in the current
|
||||
font and style.
|
||||
\li \c MainWindow provides a standard main window that contains font and
|
||||
style information, a view onto the characters, a line edit, and a push
|
||||
button for submitting text to the clipboard.
|
||||
\endlist
|
||||
|
||||
\section1 CharacterWidget Class Definition
|
||||
|
||||
The \c CharacterWidget class is used to display an array of characters in
|
||||
a user-specified font and style. For flexibility, we subclass QWidget and
|
||||
reimplement only the functions that we need to provide basic rendering
|
||||
and interaction features.
|
||||
|
||||
The class definition looks like this:
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.h 0
|
||||
|
||||
The widget does not contain any other widgets, so it must provide its own
|
||||
size hint to allow its contents to be displayed correctly.
|
||||
We reimplement \l{QWidget::paintEvent()} to draw custom content. We also
|
||||
reimplement \l{QWidget::mousePressEvent()} to allow the user to interact
|
||||
with the widget.
|
||||
|
||||
The updateFont() and updateStyle() slots are used to update the font and
|
||||
style of the characters in the widget whenever the user changes the
|
||||
settings in the application.
|
||||
The class defines the characterSelected() signal so that other parts
|
||||
of the application are informed whenever the user selects a character in
|
||||
the widget.
|
||||
As a courtesy, the widget provides a tooltip that shows the current
|
||||
character value. We reimplement the \l{QWidget::mouseMoveEvent()} event
|
||||
handler and define showToolTip() to enable this feature.
|
||||
|
||||
The \c columns, \c displayFont and \c currentKey private data members
|
||||
are used to record the number of columns to be shown, the current font,
|
||||
and the currently highlighted character in the widget.
|
||||
|
||||
\section1 CharacterWidget Class Implementation
|
||||
|
||||
Since the widget is to be used as a simple canvas, the constructor just
|
||||
calls the base class constructor and defines some default values for
|
||||
private data members.
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 0
|
||||
|
||||
We initialize \c currentKey with a value of -1 to indicate
|
||||
that no character is initially selected. We enable mouse tracking to
|
||||
allow us to follow the movement of the cursor across the widget.
|
||||
|
||||
The class provides two functions to allow the font and style to be set up.
|
||||
Each of these modify the widget's display font and call update():
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 1
|
||||
\codeline
|
||||
\snippet widgets/charactermap/characterwidget.cpp 2
|
||||
|
||||
We use a fixed size font for the display. Similarly, a fixed size hint is
|
||||
provided by the sizeHint() function:
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 3
|
||||
|
||||
Three standard event functions are implemented so that the widget
|
||||
can respond to clicks, provide tooltips, and render the available
|
||||
characters. The paintEvent() shows how the contents of the widget are
|
||||
arranged and displayed:
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 6
|
||||
|
||||
A QPainter is created for the widget and, in all cases, we ensure that the
|
||||
widget's background is painted. The painter's font is set to the
|
||||
user-specified display font.
|
||||
|
||||
The area of the widget that needs to be redrawn is used to determine which
|
||||
characters need to be displayed:
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 7
|
||||
|
||||
Using integer division, we obtain the row and column numbers of each
|
||||
characters that should be displayed, and we draw a square on the widget
|
||||
for each character displayed.
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 8
|
||||
\snippet widgets/charactermap/characterwidget.cpp 9
|
||||
|
||||
The symbols for each character in the array are drawn within each square,
|
||||
with the symbol for the most recently selected character displayed in red:
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 10
|
||||
|
||||
We do not need to take into account the difference between the area
|
||||
displayed in the viewport and the area we are drawing on because
|
||||
everything outside the visible area will be clipped.
|
||||
|
||||
The mousePressEvent() defines how the widget responds to mouse clicks.
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 5
|
||||
|
||||
We are only interested when the user clicks with the left mouse button
|
||||
over the widget. When this happens, we calculate which character was
|
||||
selected and emit the characterSelected() signal.
|
||||
The character's number is found by dividing the x and y-coordinates of
|
||||
the click by the size of each character's grid square. Since the number
|
||||
of columns in the widget is defined by the \c columns variable, we
|
||||
simply multiply the row index by that value and add the column number
|
||||
to obtain the character number.
|
||||
|
||||
If any other mouse button is pressed, the event is passed on to the
|
||||
QWidget base class. This ensures that the event can be handled properly
|
||||
by any other interested widgets.
|
||||
|
||||
The mouseMoveEvent() maps the mouse cursor's position in global
|
||||
coordinates to widget coordinates, and determines the character that
|
||||
was clicked by performing the calculation
|
||||
|
||||
\snippet widgets/charactermap/characterwidget.cpp 4
|
||||
|
||||
The tooltip is given a position defined in global coordinates.
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
The \c MainWindow class provides a minimal user interface for the example,
|
||||
with only a constructor, slots that respond to signals emitted by standard
|
||||
widgets, and some convenience functions that are used to set up the user
|
||||
interface.
|
||||
|
||||
The class definition looks like this:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.h 0
|
||||
|
||||
The main window contains various widgets that are used to control how
|
||||
the characters will be displayed, and defines the findFonts() function
|
||||
for clarity and convenience. The findStyles() slot is used by the widgets
|
||||
to determine the styles that are available, insertCharacter() inserts
|
||||
a user-selected character into the window's line edit, and
|
||||
updateClipboard() synchronizes the clipboard with the contents of the
|
||||
line edit.
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
In the constructor, we set up the window's central widget and fill it with
|
||||
some standard widgets (two comboboxes, a line edit, and a push button).
|
||||
We also construct a CharacterWidget custom widget, and add a QScrollArea
|
||||
so that we can view its contents:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 0
|
||||
|
||||
QScrollArea provides a viewport onto the \c CharacterWidget when we set
|
||||
its widget and handles much of the work needed to provide a scrolling
|
||||
viewport.
|
||||
|
||||
The font combo box is automatically populated with a list of available
|
||||
fonts. We list the available styles for the current font in the style
|
||||
combobox using the following function:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 1
|
||||
|
||||
The line edit and push button are used to supply text to the clipboard:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 2
|
||||
|
||||
We also obtain a clipboard object so that we can send text entered by the
|
||||
user to other applications.
|
||||
|
||||
Most of the signals emitted in the example come from standard widgets.
|
||||
We connect these signals to slots in this class, and to the slots provided
|
||||
by other widgets.
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 4
|
||||
|
||||
The font combobox's
|
||||
\l{QFontComboBox::currentFontChanged()}{currentFontChanged()} signal is
|
||||
connected to the findStyles() function so that the list of available styles
|
||||
can be shown for each font that is used. Since both the font and the style
|
||||
can be changed by the user, the font combobox's currentFontChanged() signal
|
||||
and the style combobox's
|
||||
\l{QComboBox::currentIndexChanged()}{currentIndexChanged()} are connected
|
||||
directly to the character widget.
|
||||
|
||||
The final two connections allow characters to be selected in the character
|
||||
widget, and text to be inserted into the clipboard:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 5
|
||||
|
||||
The character widget emits the characterSelected() custom signal when
|
||||
the user clicks on a character, and this is handled by the insertCharacter()
|
||||
function in this class. The clipboard is changed when the push button emits
|
||||
the clicked() signal, and we handle this with the updateClipboard() function.
|
||||
|
||||
The remaining code in the constructor sets up the layout of the central widget,
|
||||
and provides a window title:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 6
|
||||
|
||||
The font combobox is automatically populated with a list of available font
|
||||
families. The styles that can be used with each font are found by the
|
||||
findStyles() function. This function is called whenever the user selects a
|
||||
different font in the font combobox.
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 7
|
||||
|
||||
We begin by recording the currently selected style, and we clear the
|
||||
style combobox so that we can insert the styles associated with the
|
||||
current font family.
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 8
|
||||
|
||||
We use the font database to collect the styles that are available for the
|
||||
current font, and insert them into the style combobox. The current item is
|
||||
reset if the original style is not available for this font.
|
||||
|
||||
The last two functions are slots that respond to signals from the character
|
||||
widget and the main window's push button. The insertCharacter() function is
|
||||
used to insert characters from the character widget when the user clicks a
|
||||
character:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 9
|
||||
|
||||
The character is inserted into the line edit at the current cursor position.
|
||||
|
||||
The main window's "To clipboard" push button is connected to the
|
||||
updateClipboard() function so that, when it is clicked, the clipboard is
|
||||
updated to contain the contents of the line edit:
|
||||
|
||||
\snippet widgets/charactermap/mainwindow.cpp 10
|
||||
|
||||
We copy all the text from the line edit to the clipboard, but we do not clear
|
||||
the line edit.
|
||||
*/
|
58
examples/widgets/doc/src/chart.qdoc
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/chart
|
||||
\title Chart Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Chart example shows how to create a custom view for the model/view framework.
|
||||
|
||||
\image chart-example.png
|
||||
|
||||
In this example, the items in a table model are represented as slices in a pie chart,
|
||||
relying on the flexibility of the model/view architecture to handle custom editing
|
||||
and selection features.
|
||||
|
||||
\b{Note that you only need to create a new view class if your data requires a
|
||||
specialized representation.} You should first consider using a standard QListView,
|
||||
QTableView, or QTreeView with a custom QItemDelegate subclass if you need to
|
||||
represent data in a special way.
|
||||
|
||||
\omit
|
||||
\section1 PieView Class Definition
|
||||
|
||||
The \c PieView class is a subclass of QAbstractItemView. The base class provides
|
||||
much of the functionality required by view classes, so we only need to provide
|
||||
implementations for three public functions: visualRect(), scrollTo(), and
|
||||
indexAt(). However, the view needs to maintain strict control over its look and
|
||||
feel, so we also provide implementations for a number of other functions:
|
||||
|
||||
\snippet itemviews/chart/pieview.h 0
|
||||
|
||||
|
||||
|
||||
\section1 PieView Class Implementation
|
||||
|
||||
The paint event renders the data from the standard item model as a pie chart.
|
||||
We interpret the data in the following way:
|
||||
|
||||
\list
|
||||
\li Column 0 contains data in two different roles:
|
||||
The \l{Qt::ItemDataRole}{DisplayRole} contains a label, and the
|
||||
\l{Qt::ItemDataRole}{DecorationRole} contains the color of the pie slice.
|
||||
\li Column 1 contains a quantity which we will convert to the angular extent of
|
||||
the slice.
|
||||
\endlist
|
||||
|
||||
The figure is always drawn with the chart on the left and the key on
|
||||
the right. This means that we must try and obtain an area that is wider
|
||||
than it is tall. We do this by imposing a particular aspect ratio on
|
||||
the chart and applying it to the available vertical space. This ensures
|
||||
that we always obtain the maximum horizontal space for the aspect ratio
|
||||
used.
|
||||
We also apply fixed size margin around the figure.
|
||||
|
||||
We use logical coordinates to draw the chart and key, and position them
|
||||
on the view using viewports.
|
||||
\endomit
|
||||
*/
|
15
examples/widgets/doc/src/chip.qdoc
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example graphicsview/chip
|
||||
\title 40000 Chips
|
||||
\ingroup examples-graphicsview
|
||||
\brief Visualizes a huge graphic view scene with 40000 chip items.
|
||||
|
||||
This examples demonstrates Graphics View's powerful navigation
|
||||
and interaction features, allowing you to zoom and rotate each of four
|
||||
views independently, and you can select and move items around the scene.
|
||||
|
||||
\image chip-demo.png
|
||||
*/
|
167
examples/widgets/doc/src/classwizard.qdoc
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example dialogs/classwizard
|
||||
\title Class Wizard Example
|
||||
\ingroup examples-dialogs
|
||||
|
||||
\brief The Class Wizard example shows how to implement linear
|
||||
wizards using QWizard.
|
||||
|
||||
\image classwizard.png Screenshot of the Class Wizard example
|
||||
|
||||
Most wizards have a linear structure, with page 1 followed by
|
||||
page 2 and so on until the last page. Some wizards are more
|
||||
complex in that they allow different traversal paths based on the
|
||||
information provided by the user. The
|
||||
\l{dialogs/licensewizard}{License Wizard} example shows how to
|
||||
create such wizards.
|
||||
|
||||
The Class Wizard example consists of the following classes:
|
||||
|
||||
\list
|
||||
\li \c ClassWizard inherits QWizard and provides a
|
||||
three-step wizard that generates the skeleton of a C++ class
|
||||
based on the user's input.
|
||||
\li \c IntroPage, \c ClassInfoPage, \c CodeStylePage, \c
|
||||
OutputFilesPage, and \c ConclusionPage are QWizardPage
|
||||
subclasses that implement the wizard pages.
|
||||
\endlist
|
||||
|
||||
\section1 ClassWizard Class Definition
|
||||
|
||||
\image classwizard-flow.png The Class Wizard pages
|
||||
|
||||
We will see how to subclass QWizard to implement our own wizard.
|
||||
The concrete wizard class is called \c ClassWizard and provides
|
||||
five pages:
|
||||
|
||||
\list
|
||||
\li The first page is an introduction page, telling the user what
|
||||
the wizard is going to do.
|
||||
\li The second page asks for a class name and a base class, and
|
||||
allows the user to specify whether the class should have a \c
|
||||
Q_OBJECT macro and what constructors it should provide.
|
||||
\li The third page allows the user to set some options related to the code
|
||||
style, such as the macro used to protect the header file from
|
||||
multiple inclusion (e.g., \c MYDIALOG_H).
|
||||
\li The fourth page allows the user to specify the names of the
|
||||
output files.
|
||||
\li The fifth page is a conclusion page.
|
||||
\endlist
|
||||
|
||||
Although the program is just an example, if you press \uicontrol Finish
|
||||
(\uicontrol Done on \macos), actual C++ source files will actually be
|
||||
generated.
|
||||
|
||||
\section1 The ClassWizard Class
|
||||
|
||||
Here's the \c ClassWizard definition:
|
||||
|
||||
\snippet dialogs/classwizard/classwizard.h 0
|
||||
|
||||
The class reimplements QDialog's \l{QDialog::}{accept()} slot.
|
||||
This slot is called when the user clicks \uicontrol{Finish}.
|
||||
|
||||
Here's the constructor:
|
||||
|
||||
\snippet dialogs/classwizard/classwizard.cpp 1
|
||||
|
||||
We instantiate the five pages and insert them into the wizard
|
||||
using QWizard::addPage(). The order in which they are inserted
|
||||
is also the order in which they will be shown later on.
|
||||
|
||||
We call QWizard::setPixmap() to set the banner and the
|
||||
background pixmaps for all pages. The banner is used as a
|
||||
background for the page header when the wizard's style is
|
||||
\l{QWizard::}{ModernStyle}; the background is used as the
|
||||
dialog's background in \l{QWizard::}{MacStyle}. (See \l{Elements
|
||||
of a Wizard Page} for more information.)
|
||||
|
||||
\snippet dialogs/classwizard/classwizard.cpp 3
|
||||
\snippet dialogs/classwizard/classwizard.cpp 4
|
||||
\dots
|
||||
\snippet dialogs/classwizard/classwizard.cpp 5
|
||||
\snippet dialogs/classwizard/classwizard.cpp 6
|
||||
|
||||
If the user clicks \uicontrol Finish, we extract the information from
|
||||
the various pages using QWizard::field() and generate the files.
|
||||
The code is long and tedious (and has barely anything to do with
|
||||
noble art of designing wizards), so most of it is skipped here.
|
||||
See the actual example in the Qt distribution for the details if
|
||||
you're curious.
|
||||
|
||||
\section1 The IntroPage Class
|
||||
|
||||
The pages are defined in \c classwizard.h and implemented in \c
|
||||
classwizard.cpp, together with \c ClassWizard. We will start with
|
||||
the easiest page:
|
||||
|
||||
\snippet dialogs/classwizard/classwizard.h 1
|
||||
\codeline
|
||||
\snippet dialogs/classwizard/classwizard.cpp 7
|
||||
|
||||
A page inherits from QWizardPage. We set a
|
||||
\l{QWizardPage::}{title} and a
|
||||
\l{QWizard::WatermarkPixmap}{watermark pixmap}. By not setting
|
||||
any \l{QWizardPage::}{subTitle}, we ensure that no header is
|
||||
displayed for this page. (On Windows, it is customary for wizards
|
||||
to display a watermark pixmap on the first and last pages, and to
|
||||
have a header on the other pages.)
|
||||
|
||||
Then we create a QLabel and add it to a layout.
|
||||
|
||||
\section1 The ClassInfoPage Class
|
||||
|
||||
The second page is defined and implemented as follows:
|
||||
|
||||
\snippet dialogs/classwizard/classwizard.h 2
|
||||
\codeline
|
||||
\snippet dialogs/classwizard/classwizard.cpp 9
|
||||
\dots
|
||||
\snippet dialogs/classwizard/classwizard.cpp 12
|
||||
\dots
|
||||
\snippet dialogs/classwizard/classwizard.cpp 13
|
||||
|
||||
First, we set the page's \l{QWizardPage::}{title},
|
||||
\l{QWizardPage::}{subTitle}, and \l{QWizard::LogoPixmap}{logo
|
||||
pixmap}. The logo pixmap is displayed in the page's header in
|
||||
\l{QWizard::}{ClassicStyle} and \l{QWizard::}{ModernStyle}.
|
||||
|
||||
Then we create the child widgets, create \l{Registering and Using
|
||||
Fields}{wizard fields} associated with them, and put them into
|
||||
layouts. The \c className field is created with an asterisk (\c
|
||||
*) next to its name. This makes it a \l{mandatory fields}{mandatory field}, that
|
||||
is, a field that must be filled before the user can press the
|
||||
\uicontrol Next button (\uicontrol Continue on \macos). The fields' values
|
||||
can be accessed from any other page using QWizardPage::field(),
|
||||
or from the wizard code using QWizard::field().
|
||||
|
||||
\section1 The CodeStylePage Class
|
||||
|
||||
The third page is defined and implemented as follows:
|
||||
|
||||
\snippet dialogs/classwizard/classwizard.h 3
|
||||
\codeline
|
||||
\snippet dialogs/classwizard/classwizard.cpp 14
|
||||
\dots
|
||||
\snippet dialogs/classwizard/classwizard.cpp 15
|
||||
\codeline
|
||||
\snippet dialogs/classwizard/classwizard.cpp 16
|
||||
|
||||
The code in the constructor is very similar to what we did for \c
|
||||
ClassInfoPage, so we skipped most of it.
|
||||
|
||||
The \c initializePage() function is what makes this class
|
||||
interesting. It is reimplemented from QWizardPage and is used to
|
||||
initialize some of the page's fields with values from the
|
||||
previous page (namely, \c className and \c baseClass). For
|
||||
example, if the class name on page 2 is \c SuperDuperWidget, the
|
||||
default macro name on page 3 is \c SUPERDUPERWIDGET_H.
|
||||
|
||||
The \c OutputFilesPage and \c ConclusionPage classes are very
|
||||
similar to \c CodeStylePage, so we won't review them here.
|
||||
|
||||
\sa QWizard, {License Wizard Example}, {Trivial Wizard Example}
|
||||
*/
|
242
examples/widgets/doc/src/collidingmice-example.qdoc
Normal file
@ -0,0 +1,242 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example graphicsview/collidingmice
|
||||
\title Colliding Mice Example
|
||||
\brief Demonstrates how to animate items on a graphics view.
|
||||
\ingroup examples-graphicsview
|
||||
|
||||
The Colliding Mice example shows how to use the Graphics View
|
||||
framework to implement animated items and detect collision between
|
||||
items.
|
||||
|
||||
\image collidingmice-example.png
|
||||
|
||||
Graphics View provides the QGraphicsScene class for managing and
|
||||
interacting with a large number of custom-made 2D graphical items
|
||||
derived from the QGraphicsItem class, and a QGraphicsView widget
|
||||
for visualizing the items, with support for zooming and rotation.
|
||||
|
||||
The example consists of an item class and a main function:
|
||||
the \c Mouse class represents the individual mice extending
|
||||
QGraphicsItem, and the \c main() function provides the main
|
||||
application window.
|
||||
|
||||
We will first review the \c Mouse class to see how to animate
|
||||
items and detect item collisions, and then we will review the \c
|
||||
main() function to see how to put the items into a scene and how to
|
||||
implement the corresponding view.
|
||||
|
||||
\section1 Mouse Class Definition
|
||||
|
||||
The \c mouse class inherits from QGraphicsItem. The
|
||||
QGraphicsItem class is the base class for all graphical items in
|
||||
the Graphics View framework, and provides a light-weight
|
||||
foundation for writing your own custom items.
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.h 0
|
||||
|
||||
When writing a custom graphics item, you must implement
|
||||
QGraphicsItem's two pure virtual public functions: \l
|
||||
{QGraphicsItem::}{boundingRect()}, which returns an estimate of
|
||||
the area painted by the item, and \l {QGraphicsItem::}{paint()},
|
||||
which implements the actual painting. In addition, we reimplement
|
||||
the \l {QGraphicsItem::}{shape()} and \l {QGraphicsItem::}{advance()}.
|
||||
We reimplement \l {QGraphicsItem::}{shape()} to return an accurate
|
||||
shape of our mouse item; the default implementation simply returns
|
||||
the item's bounding rectangle. We reimplement \l {QGraphicsItem::}{advance()}
|
||||
to handle the animation so it all happens on one update.
|
||||
|
||||
\section1 Mouse Class Definition
|
||||
|
||||
When constructing a mouse item, we first ensure that all the item's
|
||||
private variables which were no yet initialized directly in the class
|
||||
are properly initialized:
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 0
|
||||
|
||||
To calculate the various components of the mouse's color, we use
|
||||
\l QRandomGenerator.
|
||||
|
||||
Then we call the \l {QGraphicsItem::setRotation()}{setRotation()} function
|
||||
inherited from QGraphicsItem. Items live in their own local
|
||||
coordinate system. Their coordinates are usually centered around
|
||||
(0, 0), and this is also the center for all transformations. By
|
||||
calling the item's \l {QGraphicsItem::setRotation()}{setRotation()} function
|
||||
we alter the direction in which the mouse will start moving.
|
||||
|
||||
When the QGraphicsScene decides to advance the scene by a frame, it will
|
||||
call QGraphicsItem::advance() on each of the items. This enables us to
|
||||
animate our mouse using our reimplementation of the advance() function.
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 4
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 5
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 6
|
||||
|
||||
First, we don't bother doing any advance if the step is \c 0. This is because
|
||||
advance() is called twice: once with step == \c 0, indicating that items
|
||||
are about to advance, and then with step == \c 1 for the actual advance.
|
||||
We also ensure that the mouse stays within a circle with a radius of 150 pixels.
|
||||
|
||||
Note the \l {QGraphicsItem::mapFromScene()}{mapFromScene()}
|
||||
function provided by QGraphicsItem. This function maps a position
|
||||
given in \e scene coordinates, to the item's coordinate system.
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 7
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 8
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 9
|
||||
\codeline
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 10
|
||||
|
||||
Then we try to avoid colliding with other mice.
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 11
|
||||
|
||||
Finally, we calculate the mouse's speed and its eye direction (for
|
||||
use when painting the mouse), and set its new position.
|
||||
|
||||
The position of an item describes its origin (local coordinate (0,
|
||||
0)) in the parent coordinates. The \l {QGraphicsItem::setPos()}
|
||||
function sets the position of the item to the given position in
|
||||
the parent's coordinate system. For items with no parent, the
|
||||
given position is interpreted as scene coordinates. QGraphicsItem
|
||||
also provides a \l {QGraphicsItem::}{mapToParent()} function to
|
||||
map a position given in item coordinates to the parent's
|
||||
coordinate system. If the item has no parent, the position will be
|
||||
mapped to the scene's coordinate system instead.
|
||||
|
||||
Then it is time to provide an implementation for the pure virtual
|
||||
functions inherited from QGraphicsItem. Let's first take a look at
|
||||
the \l {QGraphicsItem::}{boundingRect()} function:
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 1
|
||||
|
||||
The \l {QGraphicsItem::boundingRect()}{boundingRect()} function
|
||||
defines the outer bounds of the item as a rectangle. Note that the
|
||||
Graphics View framework uses the bounding rectangle to determine
|
||||
whether the item requires redrawing, so all painting must be
|
||||
done inside this rectangle.
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 3
|
||||
|
||||
The Graphics View framework calls the \l
|
||||
{QGraphicsItem::paint()}{paint()} function to paint the contents
|
||||
of the item; the function paints the item in local coordinates.
|
||||
|
||||
Note the painting of the ears: whenever a mouse item collides with
|
||||
other mice items its ears are filled with red; otherwise they are
|
||||
filled with dark yellow. We use the
|
||||
QGraphicsScene::collidingItems() function to check if there are
|
||||
any colliding mice. The actual collision detection is handled by
|
||||
the Graphics View framework using shape-shape intersection. All we
|
||||
have to do is to ensure that the QGraphicsItem::shape() function
|
||||
returns an accurate shape for our item:
|
||||
|
||||
\snippet graphicsview/collidingmice/mouse.cpp 2
|
||||
|
||||
Because the complexity of arbitrary shape-shape intersection grows
|
||||
with an order of magnitude when the shapes are complex, this
|
||||
operation can be noticeably time consuming. An alternative approach
|
||||
is to reimplement the \l
|
||||
{QGraphicsItem::collidesWithItem()}{collidesWithItem()} function
|
||||
to provide your own custom item and shape collision algorithm.
|
||||
|
||||
This completes the \c Mouse class implementation; it is now ready
|
||||
for use. Let's take a look at the \c main() function to see how to
|
||||
implement a scene for the mice and a view for displaying the
|
||||
contents of the scene.
|
||||
|
||||
\section1 The Main() Function
|
||||
|
||||
The \c main() function provides the main application window,
|
||||
as well as creating the items, their scene, and a corresponding view.
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 0
|
||||
|
||||
First, we create an application object and create the scene:
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 1
|
||||
|
||||
The QGraphicsScene class serves as a container for
|
||||
QGraphicsItems. It also provides functionality that lets you
|
||||
efficiently determine the location of items as well as determining
|
||||
which items are visible within an arbitrary area on the
|
||||
scene.
|
||||
|
||||
When creating a scene it is recommended to set the scene's
|
||||
rectangle; the rectangle that defines the extent of the
|
||||
scene. It is primarily used by QGraphicsView to determine the
|
||||
view's default scrollable area, and by QGraphicsScene to manage
|
||||
item indexing. If not explicitly set, the scene's default
|
||||
rectangle will be the largest bounding rectangle of all the items
|
||||
on the scene since the scene was created. This means that the
|
||||
rectangle will grow when items are added or moved in the scene,
|
||||
but it will never shrink.
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 2
|
||||
|
||||
The item index function is used to speed up item discovery. \l
|
||||
{QGraphicsScene::NoIndex}{NoIndex} implies that item location is
|
||||
of linear complexity, as all items on the scene are
|
||||
searched. Adding, moving and removing items, however, is done in
|
||||
constant time. This approach is ideal for dynamic scenes, where
|
||||
many items are added, moved or removed continuously. The
|
||||
alternative is \l {QGraphicsScene::BspTreeIndex}{BspTreeIndex},
|
||||
which makes use of a binary search to achieve item location
|
||||
algorithms that are of an order closer to logarithmic complexity.
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 3
|
||||
|
||||
Then we add the mice to the scene.
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 4
|
||||
|
||||
To be able to view the scene, we must also create a QGraphicsView
|
||||
widget. The QGraphicsView class visualizes the contents of a scene
|
||||
in a scrollable viewport. We also ensure that the contents are
|
||||
rendered using antialiasing, and we create the cheese background
|
||||
by setting the view's background brush.
|
||||
|
||||
The image used for the background is stored as a binary file in
|
||||
the application's executable using Qt's \l {The Qt Resource
|
||||
System}{resource system}. The QPixmap constructor accepts both
|
||||
file names that refer to actual files on disk and file names that
|
||||
refer to the application's embedded resources.
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 5
|
||||
|
||||
Then we set the cache mode; QGraphicsView can cache pre-rendered
|
||||
content in a pixmap, which is then drawn onto the viewport. The
|
||||
purpose of such caching is to speed up the total rendering time
|
||||
for areas that are slow to render, for example: texture, gradient, and
|
||||
alpha blended backgrounds. The \l
|
||||
{QGraphicsView::CacheMode}{CacheMode} property holds which parts
|
||||
of the view are cached, and the \l
|
||||
{QGraphicsView::CacheBackground}{CacheBackground} flag enables
|
||||
caching of the view's background.
|
||||
|
||||
By setting the \l {QGraphicsView::dragMode}{dragMode} property, we
|
||||
define what should happen when the user clicks on the scene
|
||||
background and drags the mouse. The \l
|
||||
{QGraphicsView::ScrollHandDrag}{ScrollHandDrag} flag makes the
|
||||
cursor change into a pointing hand, and dragging the mouse around
|
||||
will scroll the scrollbars.
|
||||
|
||||
\snippet graphicsview/collidingmice/main.cpp 6
|
||||
|
||||
In the end, we set the application window's title and size before
|
||||
we enter the main event loop using the QApplication::exec()
|
||||
function.
|
||||
|
||||
Finally, we create a QTimer and connect its timeout() signal to the
|
||||
advance() slot of the scene. Every time the timer fires, the scene
|
||||
will advance one frame.
|
||||
|
||||
We then tell the timer to fire every 1000/33 milliseconds. This will
|
||||
give us a frame rate of 30 frames a second, which is fast enough for most
|
||||
animations. Doing the animation with a single timer connection to advance the
|
||||
scene ensures that all the mice are moved at one point and, more
|
||||
importantly, only one update is sent to the screen after all the mice have
|
||||
moved.
|
||||
*/
|
131
examples/widgets/doc/src/coloreditorfactory.qdoc
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/coloreditorfactory
|
||||
\title Color Editor Factory Example
|
||||
\ingroup examples-itemviews
|
||||
\brief This example shows how to create an editor that can be used by
|
||||
a QItemDelegate.
|
||||
|
||||
\image coloreditorfactoryimage.png
|
||||
|
||||
When editing data in a QListView, QTableView, or QTreeView,
|
||||
editors are created and displayed by a \l{Delegate
|
||||
Classes}{delegate}. QItemDelegate, which is the default delegate
|
||||
used by Qt's \l{View Classes}{item views}, uses a
|
||||
QItemEditorFactory to create editors for it. A unique instance
|
||||
provided by QItemEditorFactory is by default installed on all
|
||||
item delegates.
|
||||
|
||||
An item editor factory contains a collection of
|
||||
QItemEditorCreatorBase instances, which are specialized factories
|
||||
that produce editors for one particular QVariant data type (all
|
||||
models in Qt store their data in \l{QVariant}s). An editor can be any
|
||||
Qt or custom widget.
|
||||
|
||||
In this example, we will create an editor (implemented in the \c
|
||||
ColorListEditor class) that can edit the QColor data type and be
|
||||
used by \l{QItemDelegate}s. We do this by creating a new
|
||||
QItemEditorCreatorBase that produces \c ColorListEditors and
|
||||
register it with a new factory, which we set as the default editor
|
||||
item factory (the unique factory instance). To test our editor, we
|
||||
have implemented the \c Window class, which displays a
|
||||
QTableWidget in which \l{QColor}s can be edited.
|
||||
|
||||
\section1 Window Class Implementation
|
||||
|
||||
In the Window class, we create the item editor creator
|
||||
base for our color editor and add it to the default factory.
|
||||
We also create a QTableWidget in which our editor can be
|
||||
tested. It is filled with some data and displayed in a window.
|
||||
|
||||
We take a closer look at the constructor:
|
||||
|
||||
\snippet itemviews/coloreditorfactory/window.cpp 0
|
||||
|
||||
The QStandardItemEditorCreator is a convenience class that
|
||||
inherits QItemEditorCreatorBase. Its constructor takes a template
|
||||
class, of which instances are returned from
|
||||
\l{QItemEditorCreatorBase::}{createWidget()}. The creator uses a
|
||||
constructor that takes a QWidget as its only parameter; the
|
||||
template class must provide this. This way, there is no need to
|
||||
subclass QStandardItemEditorCreator.
|
||||
|
||||
After the new factory has been set, all standard item delegates
|
||||
will use it (i.e, also delegates that were created before the new
|
||||
default factory was set).
|
||||
|
||||
The \c createGUI() function sets up the table and fills it
|
||||
with data.
|
||||
|
||||
\section1 ColorListEditor Definition
|
||||
|
||||
The ColorListEditor inherits QComboBox and lets the user
|
||||
select a QColor from its popup list.
|
||||
|
||||
\snippet itemviews/coloreditorfactory/colorlisteditor.h 0
|
||||
|
||||
QItemDelegate manages the interaction between the editor and
|
||||
the model, i.e., it retrieves data to edit from the model and
|
||||
store data from the editor in the model. The data that is edited
|
||||
by an editor is stored in the editor's user data property, and the
|
||||
delegate uses Qt's \l{Qt's Property System}{property system} to
|
||||
access it by name. We declare our user data property with the
|
||||
Q_PROPERTY macro. The property is set to be the user type with the
|
||||
USER keyword.
|
||||
|
||||
\section1 ColorListEditor Implementation
|
||||
|
||||
The constructor of \c ColorListEditor simply calls \c
|
||||
populateList(), which we will look at later. We move on to the
|
||||
\c color() function:
|
||||
|
||||
\snippet itemviews/coloreditorfactory/colorlisteditor.cpp 0
|
||||
|
||||
We return the data that is selected in the combobox. The data
|
||||
is stored in the Qt::DecorationRole as the color is then also
|
||||
displayed in the popup list (as shown in the image above).
|
||||
|
||||
\snippet itemviews/coloreditorfactory/colorlisteditor.cpp 1
|
||||
|
||||
The \c findData() function searches the items in the combobox
|
||||
and returns the index of the item that has \c color in the
|
||||
Qt::Decoration role.
|
||||
|
||||
\snippet itemviews/coloreditorfactory/colorlisteditor.cpp 2
|
||||
|
||||
Qt knows some predefined colors by name. We simply loop
|
||||
through these to fill our editor with items.
|
||||
|
||||
\section1 Further Customization of Item View Editors
|
||||
|
||||
You can customize Qt's \l{Model/View Programming}{model view
|
||||
framework} in many ways. The procedure shown in this example is
|
||||
usually sufficient to provide custom editors. Further
|
||||
customization is achieved by subclassing QItemEditorFactory
|
||||
and QItemEditorCreatorBase. It is also possible to subclass
|
||||
QItemDelegate if you don't wish to use a factory at all.
|
||||
|
||||
Possible suggestions are:
|
||||
|
||||
\list
|
||||
\li If the editor widget has no user property defined, the delegate
|
||||
asks the factory for the property name, which it in turn
|
||||
asks the item editor creator for. In this case, you can use
|
||||
the QItemEditorCreator class, which takes the property
|
||||
name to use for editing as a constructor argument.
|
||||
\li If the editor requires other constructors or other
|
||||
initialization than provided by QItemEditorCreatorBase, you
|
||||
must reimplement
|
||||
QItemEditorCreatorBase::createWidget().
|
||||
\li You could also subclass QItemEditorFactory if you only want
|
||||
to provide editors for certain kinds of data or use another
|
||||
method of creating the editors than using creator bases.
|
||||
\endlist
|
||||
|
||||
In this example, we use a standard QVariant data type. You can
|
||||
also use custom types. In the \l{Star Delegate Example}, we
|
||||
show how to store a custom data type in a QVariant and paint
|
||||
and edit it in a class that inherits QItemDelegate.
|
||||
*/
|
143
examples/widgets/doc/src/combowidgetmapper.qdoc
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/combowidgetmapper
|
||||
\title Combo Widget Mapper Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Combo Widget Mapper example shows how to use a custom delegate to
|
||||
map information from a model to specific widgets on a form.
|
||||
|
||||
\image combowidgetmapper-example.png
|
||||
|
||||
In the \l{Simple Widget Mapper Example}, we showed the basic use of a
|
||||
widget mapper to relate data exposed by a model to simple input widgets
|
||||
in a user interface. However, sometimes we want to use input widgets that
|
||||
expose data as choices to the user, such as QComboBox, and we need a way
|
||||
to relate their input to the values stored in the model.
|
||||
|
||||
This example is very similar to the \l{Simple Widget Mapper Example}.
|
||||
Again, we create a \c Window class with an almost identical user interface,
|
||||
except that, instead of providing a spin box so that each person's age
|
||||
can be entered, we provide a combo box to allow their addresses to be
|
||||
classified as "Home", "Work" or "Other".
|
||||
|
||||
\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 itemviews/combowidgetmapper/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 constructor of the \c Window class can be explained in three parts.
|
||||
In the first part, we set up the widgets used for the user interface:
|
||||
|
||||
\snippet itemviews/combowidgetmapper/window.cpp Set up widgets
|
||||
|
||||
Note that we set up the mapping the combo box in the same way as for other
|
||||
widgets, but that we apply its own model to it so that it will display
|
||||
data from its own model, the \c typeModel, rather than from the model
|
||||
containing data about each person.
|
||||
|
||||
Next, we set up the widget mapper, relating each input widget to a column
|
||||
in the model specified by the call to \l{QDataWidgetMapper::}{setModel()}:
|
||||
|
||||
\snippet itemviews/combowidgetmapper/window.cpp Set up the mapper
|
||||
|
||||
For the combo box, we pass an extra argument to tell the widget mapper
|
||||
which property to relate to values from the model. As a result, the user
|
||||
is able to select an item from the combo box, and the corresponding
|
||||
value stored in the widget's \c currentIndex property will be stored in
|
||||
the model.
|
||||
|
||||
\omit
|
||||
However, we also set a delegate on the mapper. As with \l{Delegate Classes},
|
||||
this changes the way that data is presented to the user. In this case, the
|
||||
delegate acts as a proxy between the mapper and the input widgets,
|
||||
translating the data into a suitable form for the combo box but not
|
||||
interfering with the other input widgets. The implementation is shown later.
|
||||
\endomit
|
||||
|
||||
The rest of the constructor is very similar to that of the
|
||||
\l{Simple Widget Mapper Example}:
|
||||
|
||||
\snippet itemviews/combowidgetmapper/window.cpp Set up connections and layouts
|
||||
|
||||
The model is initialized in the window's \c{setupModel()} function. Here,
|
||||
we create a standard model with 5 rows and 3 columns. In each row, we
|
||||
insert a name, address, and a value that indicates the type of address.
|
||||
The address types are stored in a string list model.
|
||||
|
||||
\snippet itemviews/combowidgetmapper/window.cpp Set up the model
|
||||
|
||||
As we insert each row into the model, like a record in a database, we
|
||||
store values that correspond to items in \c typeModel for each person's
|
||||
address type. When the widget mapper reads these values from the final
|
||||
column of each row, it will need to use them as references to values in
|
||||
\c typeModel, as shown in the following diagram. This is where the
|
||||
delegate is used.
|
||||
|
||||
\image widgetmapper-combo-mapping.png
|
||||
|
||||
We show the implementation of the \c{updateButtons()} slot for
|
||||
completeness:
|
||||
|
||||
\snippet itemviews/combowidgetmapper/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 itemviews/combowidgetmapper/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 itemviews/combowidgetmapper/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 itemviews/combowidgetmapper/delegate.cpp setModelData implementation
|
||||
\endomit
|
||||
|
||||
\section1 Summary and Further Reading
|
||||
|
||||
The use of a separate model for the combo box provides a menu of choices
|
||||
that are separate from the data stored in the main model. Using a named
|
||||
mapping that relates the combo box's \c currentIndex property to a column
|
||||
in the model effectively allows us to store a look-up value in the model.
|
||||
|
||||
However, when reading the model outside the context of the widget mapper,
|
||||
we need to know about the \c typeModel to make sense of these look-up
|
||||
values. It would be useful to be able to store both the data and the
|
||||
choices held by the \c typeModel in one place.
|
||||
This is covered by the \l{SQL Widget Mapper Example}.
|
||||
*/
|
219
examples/widgets/doc/src/completer.qdoc
Normal file
@ -0,0 +1,219 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example tools/completer
|
||||
\title Completer Example
|
||||
\ingroup examples-widgets-tools
|
||||
|
||||
\brief The Completer example shows how to provide string-completion facilities
|
||||
for an input widget based on data provided by a model.
|
||||
|
||||
\image completer-example.png
|
||||
|
||||
This example uses a custom item model, \c FileSystemModel, and a QCompleter object.
|
||||
QCompleter is a class that provides completions based on an item model. The
|
||||
type of model, the completion mode, and the case sensitivity can be
|
||||
selected using combo boxes.
|
||||
|
||||
\section1 The Resource File
|
||||
|
||||
The Completer example requires a resource file in order to store the
|
||||
\e{countries.txt} and \e{words.txt}. The resource file contains the
|
||||
following code:
|
||||
|
||||
\quotefile tools/completer/completer.qrc
|
||||
|
||||
\section1 FileSystemModel Class Definition
|
||||
|
||||
The \c FileSystemModel class is a subclass of QFileSystemModel, which provides a data
|
||||
model for the local filesystem.
|
||||
|
||||
\snippet tools/completer/fsmodel.h 0
|
||||
|
||||
This class only has a constructor and a \c data() function as it is only
|
||||
created to enable \c data() to return the entire file path for the
|
||||
display role, unlike \l{QFileSystemModel}'s \c data() function that only returns
|
||||
the folder and not the drive label. This is further explained in
|
||||
\c FileSystemModel's implementation.
|
||||
|
||||
\section1 FileSystemModel Class Implementation
|
||||
|
||||
The constructor for the \c FileSystemModel class is used to pass \a parent to
|
||||
QFileSystemModel.
|
||||
|
||||
\snippet tools/completer/fsmodel.cpp 0
|
||||
|
||||
As mentioned earlier, the \c data() function is reimplemented in order to
|
||||
get it to return the entire file parth for the display role. For example,
|
||||
with a QFileSystemModel, you will see "Program Files" in the view. However, with
|
||||
\c FileSystemModel, you will see "C:\\Program Files".
|
||||
|
||||
\snippet tools/completer/fsmodel.cpp 1
|
||||
|
||||
The Qt::EditRole, which QCompleter uses to look for matches, is left
|
||||
unchanged.
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
The \c MainWindow class is a subclass of QMainWindow and implements five
|
||||
private slots - \c about(), \c changeCase(), \c changeMode(), \c changeModel(),
|
||||
and \c changeMaxVisible().
|
||||
|
||||
\snippet tools/completer/mainwindow.h 0
|
||||
|
||||
Within the \c MainWindow class, we have two private functions:
|
||||
\c createMenu() and \c modelFromFile(). We also declare the private widgets
|
||||
needed - three QComboBox objects, a QCheckBox, a QCompleter, a QLabel, and
|
||||
a QLineEdit.
|
||||
|
||||
\snippet tools/completer/mainwindow.h 1
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
The constructor of \c MainWindow constructs a \c MainWindow with a parent
|
||||
widget and initializes the private members. The \c createMenu() function
|
||||
is then invoked.
|
||||
|
||||
We set up three QComboBox objects, \c modelComb, \c modeCombo and
|
||||
\c caseCombo. By default, the \c modelCombo is set to QFileSystemModel,
|
||||
the \c modeCombo is set to "Filtered Popup" and the \c caseCombo is set
|
||||
to "Case Insensitive".
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 0
|
||||
|
||||
The \c maxVisibleSpinBox is created and determines the number of visible
|
||||
item in the completer
|
||||
|
||||
The \c wrapCheckBox is then set up. This \c checkBox determines if the
|
||||
\c{completer}'s \l{QCompleter::setWrapAround()}{setWrapAround()} property
|
||||
is enabled or disabled.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 1
|
||||
|
||||
We instantiate \c contentsLabel and set its size policy to
|
||||
\l{QSizePolicy::Fixed}{fixed}. The combo boxes' \l{QComboBox::activated()}
|
||||
{activated()} signals are then connected to their respective slots.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 2
|
||||
|
||||
The \c lineEdit is set up and then we arrange all the widgets using a
|
||||
QGridLayout. The \c changeModel() function is called, to initialize the
|
||||
\c completer.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 3
|
||||
|
||||
The \c createMenu() function is used to instantiate the QAction objects
|
||||
needed to fill the \c fileMenu and \c helpMenu. The actions'
|
||||
\l{QAction::triggered()}{triggered()} signals are connected to their
|
||||
respective slots.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 4
|
||||
|
||||
The \c modelFromFile() function accepts the \a fileName of a file and
|
||||
processes it depending on its contents.
|
||||
|
||||
We first validate the \c file to ensure that it can be opened in
|
||||
QFile::ReadOnly mode. If this is unsuccessful, the function returns an
|
||||
empty QStringListModel.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 5
|
||||
|
||||
The mouse cursor is then overridden with Qt::WaitCursor before we fill
|
||||
a QStringList object, \c words, with the contents of \c file. Once this
|
||||
is done, we restore the mouse cursor.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 6
|
||||
|
||||
As mentioned earlier, the resources file contains two files -
|
||||
\e{countries.txt} and \e{words.txt}. If the \c file read is \e{words.txt},
|
||||
we return a QStringListModel with \c words as its QStringList and
|
||||
\c completer as its parent.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 7
|
||||
|
||||
If the \c file read is \e{countries.txt}, then we require a
|
||||
QStandardItemModel with \c words.count() rows, 2 columns, and \c completer
|
||||
as its parent.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 8
|
||||
|
||||
A standard line in \e{countries.txt} is:
|
||||
\quotation
|
||||
Norway NO
|
||||
\endquotation
|
||||
|
||||
Hence, to populate the QStandardItemModel object, \c m, we have to
|
||||
split the country name and its symbol. Once this is done, we return
|
||||
\c m.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 9
|
||||
|
||||
The \c changeMode() function sets the \c{completer}'s mode, depending on
|
||||
the value of \c index.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 10
|
||||
|
||||
The \c changeModel() function changes the item model used based on the
|
||||
model selected by the user.
|
||||
|
||||
A \c switch statement is used to change the item model based on the index
|
||||
of \c modelCombo. If \c case is 0, we use an unsorted QFileSystemModel, providing
|
||||
us with a file path excluding the drive label.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 11
|
||||
|
||||
Note that we create the model with \c completer as the parent as this
|
||||
allows us to replace the model with a new model. The \c completer will
|
||||
ensure that the old one is deleted the moment a new model is assigned
|
||||
to it.
|
||||
|
||||
If \c case is 1, we use the \c DirModel we defined earlier, resulting in
|
||||
full paths for the files.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 12
|
||||
|
||||
When \c case is 2, we attempt to complete names of countries. This requires
|
||||
a QTreeView object, \c treeView. The country names are extracted from
|
||||
\e{countries.txt} and set the popup used to display completions to
|
||||
\c treeView.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 13
|
||||
|
||||
The screenshot below shows the Completer with the country list model.
|
||||
|
||||
\image completer-example-country.png
|
||||
|
||||
If \c case is 3, we attempt to complete words. This is done using a
|
||||
QStringListModel that contains data extracted from \e{words.txt}. The
|
||||
model is sorted \l{QCompleter::CaseInsensitivelySortedModel}
|
||||
{case insensitively}.
|
||||
|
||||
The screenshot below shows the Completer with the word list model.
|
||||
|
||||
\image completer-example-word.png
|
||||
|
||||
Once the model type is selected, we call the \c changeMode() function and
|
||||
the \c changeCase() function and set the wrap option accordingly. The
|
||||
\c{wrapCheckBox}'s \l{QCheckBox::clicked()}{clicked()} signal is connected
|
||||
to the \c{completer}'s \l{QCompleter::setWrapAround()}{setWrapAround()}
|
||||
slot.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 14
|
||||
|
||||
The \c changeMaxVisible() update the maximum number of visible items in
|
||||
the completer.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 15
|
||||
|
||||
The \c about() function provides a brief description about the example.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 16
|
||||
|
||||
\section1 \c main() Function
|
||||
|
||||
The \c main() function instantiates QApplication and \c MainWindow and
|
||||
invokes the \l{QWidget::show()}{show()} function.
|
||||
|
||||
\snippet tools/completer/main.cpp 0
|
||||
*/
|
22
examples/widgets/doc/src/composition.qdoc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example painting/composition
|
||||
\title Composition Modes
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates how Composition Modes work in QPainter.
|
||||
|
||||
\brief This demo shows some of the more advanced composition modes supported by Qt.
|
||||
|
||||
\image composition-demo.png
|
||||
|
||||
The two most common forms of composition are \b{Source} and \b{SourceOver}.
|
||||
\b{Source} is used to draw opaque objects onto a paint device. In this mode,
|
||||
each pixel in the source replaces the corresponding pixel in the destination.
|
||||
In \b{SourceOver} composition mode, the source object is transparent and is
|
||||
drawn on top of the destination.
|
||||
|
||||
In addition to these standard modes, Qt defines the complete set of composition modes
|
||||
as defined by X. Porter and Y. Duff. See the QPainter documentation for details.
|
||||
*/
|
209
examples/widgets/doc/src/concentriccircles.qdoc
Normal file
@ -0,0 +1,209 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example painting/concentriccircles
|
||||
\title Concentric Circles Example
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates the improved quality that antialiasing and floating point precision gives.
|
||||
|
||||
\brief The Concentric Circles example shows the improved rendering
|
||||
quality that can be obtained using floating point precision and
|
||||
anti-aliasing when drawing custom widgets. The example also shows
|
||||
how to do simple animations.
|
||||
|
||||
The application's main window displays several widgets which are
|
||||
drawn using the various combinations of precision and
|
||||
anti-aliasing.
|
||||
|
||||
\image concentriccircles-example.png
|
||||
|
||||
Anti-aliasing is one of QPainter's render hints. The
|
||||
QPainter::RenderHints are used to specify flags to QPainter that
|
||||
may, or may not, be respected by any given
|
||||
engine. QPainter::Antialiasing indicates that the engine should
|
||||
anti-alias the edges of primitives if possible, i.e. put
|
||||
additional pixels around the original ones to smooth the edges.
|
||||
|
||||
The difference between floating point precision and integer
|
||||
precision is a matter of accuracy, and is visible in the
|
||||
application's main window: Even though the logic that is
|
||||
calculating the circles' geometry is the same, floating points
|
||||
ensure that the white spaces between each circle are of the same
|
||||
size, while integers make two and two circles appear as if they
|
||||
belong together. The reason is that the integer based precision
|
||||
rely on rounding off non-integer calculations.
|
||||
|
||||
The example consists of two classes:
|
||||
|
||||
\list
|
||||
\li \c CircleWidget is a custom widget which renders several animated
|
||||
concentric circles.
|
||||
\li \c Window is the application's main window displaying four \c
|
||||
{CircleWidget}s drawn using different combinations of precision
|
||||
and aliasing.
|
||||
\endlist
|
||||
|
||||
First we will review the CircleWidget class, then we will take a
|
||||
look at the Window class.
|
||||
|
||||
\section1 CircleWidget Class Definition
|
||||
|
||||
The CircleWidget class inherits QWidget, and is a custom widget
|
||||
which renders several animated concentric circles.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.h 0
|
||||
|
||||
We declare the \c floatBased and \c antialiased variables to hold
|
||||
whether an instance of the class should be rendered with integer
|
||||
or float based precision, and whether the rendering should be
|
||||
anti-aliased or not. We also declare functions setting each of
|
||||
these variables.
|
||||
|
||||
In addition we reimplement the QWidget::paintEvent() function to
|
||||
apply the various combinations of precision and anti-aliasing when
|
||||
rendering, and to support the animation. We reimplement the
|
||||
QWidget::minimumSizeHint() and QWidget::sizeHint() functions to
|
||||
give the widget a reasonable size within our application.
|
||||
|
||||
We declare the private \c nextAnimationFrame() slot, and the
|
||||
associated \c frameNo variable holding the number of "animation
|
||||
frames" for the widget, to facilitate the animation.
|
||||
|
||||
\section1 CircleWidget Class Implementation
|
||||
|
||||
In the constructor we make the widget's rendering integer based
|
||||
and aliased by default:
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 0
|
||||
|
||||
We initialize the widget's \c frameNo variable, and set the
|
||||
widget's background color using the QWidget::setBackgroundColor()
|
||||
function which takes a \l {QPalette::ColorRole}{color role} as
|
||||
argument; the QPalette::Base color role is typically white.
|
||||
|
||||
Then we set the widgets size policy using the
|
||||
QWidget::setSizePolicy() function. QSizePolicy::Expanding means
|
||||
that the widget's \l {QWidget::sizeHint()}{sizeHint()} is a
|
||||
sensible size, but that the widget can be shrunk and still be
|
||||
useful. The widget can also make use of extra space, so it should
|
||||
get as much space as possible.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 1
|
||||
\codeline
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 2
|
||||
|
||||
The public \c setFloatBased() and \c setAntialiased() functions
|
||||
update the widget's rendering preferences, i.e. whether the widget
|
||||
should be rendered with integer or float based precision, and
|
||||
whether the rendering should be anti-aliased or not.
|
||||
|
||||
The functions also generate a paint event by calling the
|
||||
QWidget::update() function, forcing a repaint of the widget with
|
||||
the new rendering preferences.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 3
|
||||
\codeline
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 4
|
||||
|
||||
The default implementations of the QWidget::minimumSizeHint() and
|
||||
QWidget::sizeHint() functions return invalid sizes if there is no
|
||||
layout for the widget, otherwise they return the layout's minimum and
|
||||
preferred size, respectively.
|
||||
|
||||
We reimplement the functions to give the widget minimum and
|
||||
preferred sizes which are reasonable within our application.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 5
|
||||
|
||||
The nextAnimationFrame() slot simply increments the \c frameNo
|
||||
variable's value, and calls the QWidget::update() function which
|
||||
schedules a paint event for processing when Qt returns to the main
|
||||
event loop.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 6
|
||||
|
||||
A paint event is a request to repaint all or part of the
|
||||
widget. The \c paintEvent() function is an event handler that can
|
||||
be reimplemented to receive the widget's paint events. We
|
||||
reimplement the event handler to apply the various combinations of
|
||||
precision and anti-aliasing when rendering the widget, and to
|
||||
support the animation.
|
||||
|
||||
First, we create a QPainter for the widget, and set its
|
||||
antialiased flag to the widget's preferred aliasing. We also
|
||||
translate the painters coordinate system, preparing to draw the
|
||||
widget's cocentric circles. The translation ensures that the
|
||||
center of the circles will be equivalent to the widget's center.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 7
|
||||
|
||||
When painting a circle, we use the number of "animation frames" to
|
||||
determine the alpha channel of the circle's color. The alpha
|
||||
channel specifies the color's transparency effect, 0 represents a
|
||||
fully transparent color, while 255 represents a fully opaque
|
||||
color.
|
||||
|
||||
\snippet painting/concentriccircles/circlewidget.cpp 8
|
||||
|
||||
If the calculated alpha channel is fully transparent, we don't
|
||||
draw anything since that would be equivalent to drawing a white
|
||||
circle on a white background. Instead we skip to the next circle
|
||||
still creating a white space. If the calculated alpha channel is
|
||||
fully opaque, we set the pen (the QColor passed to the QPen
|
||||
constructor is converted into the required QBrush by default) and
|
||||
draw the circle. If the widget's preferred precision is float
|
||||
based, we specify the circle's bounding rectangle using QRectF and
|
||||
double values, otherwise we use QRect and integers.
|
||||
|
||||
The animation is controlled by the public \c nextAnimationFrame()
|
||||
slot: Whenever the \c nextAnimationFrame() slot is called the
|
||||
number of frames is incremented and a paint event is
|
||||
scheduled. Then, when the widget is repainted, the alpha-blending
|
||||
of the circles' colors change and the circles appear as animated.
|
||||
|
||||
\section1 Window Class Definition
|
||||
|
||||
The Window class inherits QWidget, and is the application's main
|
||||
window rendering four \c {CircleWidget}s using different
|
||||
combinations of precision and aliasing.
|
||||
|
||||
\snippet painting/concentriccircles/window.h 0
|
||||
|
||||
We declare the various components of the main window, i.e., the text
|
||||
labels and a double array that will hold reference to the four \c
|
||||
{CircleWidget}s. In addition we declare the private \c
|
||||
createLabel() function to simplify the constructor.
|
||||
|
||||
\section1 Window Class Implementation
|
||||
|
||||
\snippet painting/concentriccircles/window.cpp 0
|
||||
|
||||
In the constructor, we first create the various labels and put
|
||||
them in a QGridLayout.
|
||||
|
||||
\snippet painting/concentriccircles/window.cpp 1
|
||||
|
||||
Then we create a QTimer. The QTimer class is a high-level
|
||||
programming interface for timers, and provides repetitive and
|
||||
single-shot timers.
|
||||
|
||||
We create a timer to facilitate the animation of our concentric
|
||||
circles; when we create the four CircleWidget instances (and add
|
||||
them to the layout), we connect the QTimer::timeout() signal to
|
||||
each of the widgets' \c nextAnimationFrame() slots.
|
||||
|
||||
\snippet painting/concentriccircles/window.cpp 2
|
||||
|
||||
Before we set the layout and window title for our main window, we
|
||||
make the timer start with a timeout interval of 100 milliseconds,
|
||||
using the QTimer::start() function. That means that the
|
||||
QTimer::timeout() signal will be emitted, forcing a repaint of the
|
||||
four \c {CircleWidget}s, every 100 millisecond which is the reason
|
||||
the circles appear as animated.
|
||||
|
||||
\snippet painting/concentriccircles/window.cpp 3
|
||||
|
||||
The private \c createLabel() function is implemented to simlify
|
||||
the constructor.
|
||||
*/
|
265
examples/widgets/doc/src/customsortfiltermodel.qdoc
Normal file
@ -0,0 +1,265 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/customsortfiltermodel
|
||||
\title Custom Sort/Filter Model Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Custom Sort/Filter Model example illustrates how to subclass
|
||||
QSortFilterProxyModel to perform advanced sorting and filtering.
|
||||
|
||||
\image customsortfiltermodel-example.png Screenshot of the Custom Sort/Filter Model Example
|
||||
|
||||
The QSortFilterProxyModel class provides support for sorting and
|
||||
filtering data passed between another model and a view.
|
||||
|
||||
The model transforms the structure of a source model by mapping
|
||||
the model indexes it supplies to new indexes, corresponding to
|
||||
different locations, for views to use. This approach allows a
|
||||
given source model to be restructured as far as views are
|
||||
concerned, without requiring any transformations on the underlying
|
||||
data and without duplicating the data in memory.
|
||||
|
||||
The Custom Sort/Filter Model example consists of two classes:
|
||||
|
||||
\list
|
||||
|
||||
\li The \c MySortFilterProxyModel class provides a custom proxy
|
||||
model.
|
||||
|
||||
\li The \c Window class provides the main application window,
|
||||
using the custom proxy model to sort and filter a standard
|
||||
item model.
|
||||
|
||||
\endlist
|
||||
|
||||
We will first take a look at the \c MySortFilterProxyModel class
|
||||
to see how the custom proxy model is implemented, then we will
|
||||
take a look at the \c Window class to see how the model is
|
||||
used. Finally we will take a quick look at the \c main() function.
|
||||
|
||||
\section1 MySortFilterProxyModel Class Definition
|
||||
|
||||
The \c MySortFilterProxyModel class inherits the
|
||||
QSortFilterProxyModel class.
|
||||
|
||||
Since QAbstractProxyModel and its subclasses are derived from
|
||||
QAbstractItemModel, much of the same advice about subclassing
|
||||
normal models also applies to proxy models.
|
||||
|
||||
On the other hand, it is worth noting that many of
|
||||
QSortFilterProxyModel's default implementations of functions are
|
||||
written so that they call the equivalent functions in the relevant
|
||||
source model. This simple proxying mechanism may need to be
|
||||
overridden for source models with more complex behavior. In this
|
||||
example we derive from the QSortFilterProxyModel class to ensure
|
||||
that our filter can recognize a valid range of dates, and to
|
||||
control the sorting behavior.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.h 0
|
||||
|
||||
We want to be able to filter our data by specifying a given period
|
||||
of time. For that reason, we implement the custom \c
|
||||
setFilterMinimumDate() and \c setFilterMaximumDate() functions as
|
||||
well as the corresponding \c filterMinimumDate() and \c
|
||||
filterMaximumDate() functions. We reimplement
|
||||
QSortFilterProxyModel's \l
|
||||
{QSortFilterProxyModel::filterAcceptsRow()}{filterAcceptsRow()}
|
||||
function to only accept rows with valid dates, and
|
||||
QSortFilterProxyModel::lessThan() to be able to sort the senders
|
||||
by their email addresses. Finally, we implement a \c dateInRange()
|
||||
convenience function that we will use to determine if a date is
|
||||
valid.
|
||||
|
||||
\section1 MySortFilterProxyModel Class Implementation
|
||||
|
||||
The \c MySortFilterProxyModel constructor is trivial, passing the
|
||||
parent parameter on to the base class constructor:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 0
|
||||
|
||||
The most interesting parts of the \c MySortFilterProxyModel
|
||||
implementation are the reimplementations of
|
||||
QSortFilterProxyModel's \l
|
||||
{QSortFilterProxyModel::filterAcceptsRow()}{filterAcceptsRow()}
|
||||
and \l {QSortFilterProxyModel::lessThan()}{lessThan()}
|
||||
functions. Let's first take a look at our customized \c lessThan()
|
||||
function.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 4
|
||||
|
||||
We want to sort the senders by their email addresses. The \l
|
||||
{QSortFilterProxyModel::}{lessThan()} function is used as the <
|
||||
operator when sorting. The default implementation handles a
|
||||
collection of types including QDateTime and String, but in order
|
||||
to be able to sort the senders by their email addresses we must
|
||||
first identify the address within the given string:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 6
|
||||
|
||||
We use QRegularExpression to define a pattern for the addresses we
|
||||
are looking for. The \l {QRegularExpression::match()}{match()} function
|
||||
returns a QRegularExpressionMatch object which contains the result of
|
||||
the matching. If there is a match,
|
||||
\l {QRegularExpressionMatch::hasMatch()}{hasMatch()} returns true. The
|
||||
result of the match can be retrieved with QRegularExpressionMatch's
|
||||
\l {QRegularExpressionMatch::captured()}{captured()} function.
|
||||
The entire match has index 0 and the parenthesized
|
||||
subexpressions have indexes starting from 1 (excluding
|
||||
non-capturing parentheses).
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3
|
||||
|
||||
The \l
|
||||
{QSortFilterProxyModel::filterAcceptsRow()}{filterAcceptsRow()}
|
||||
function, on the other hand, is expected to return true if the
|
||||
given row should be included in the model. In our example, a row
|
||||
is accepted if either the subject or the sender contains the given
|
||||
regular expression, and the date is valid.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 7
|
||||
|
||||
We use our custom \c dateInRange() function to determine if a date
|
||||
is valid.
|
||||
|
||||
To be able to filter our data by specifying a given period of
|
||||
time, we also implement functions for getting and setting the
|
||||
minimum and maximum dates:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 1
|
||||
\codeline
|
||||
\snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 2
|
||||
|
||||
The get functions, \c filterMinimumDate() and \c
|
||||
filterMaximumDate(), are trivial and implemented as inline
|
||||
function in the header file.
|
||||
|
||||
This completes our custom proxy model. Let's see how we can use it
|
||||
in an application.
|
||||
|
||||
\section1 Window Class Definition
|
||||
|
||||
The \c CustomFilter class inherits QWidget, and provides this
|
||||
example's main application window:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.h 0
|
||||
|
||||
We implement two private slots, \c textFilterChanged() and \c
|
||||
dateFilterChanged(), to respond to the user changing the filter
|
||||
pattern, case sensitivity, or any of the dates. In addition, we
|
||||
implement a public \c setSourceModel() convenience function to set
|
||||
up the model/ view relation.
|
||||
|
||||
\section1 Window Class Implementation
|
||||
|
||||
In this example, we have chosen to create and set the source model
|
||||
in the \c main () function (which we will come back to later). So
|
||||
when constructing the main application window, we assume that a
|
||||
source model already exists and start by creating an instance of
|
||||
our custom proxy model:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 0
|
||||
|
||||
We set the \l
|
||||
{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter}
|
||||
property that holds whether the proxy model is dynamically sorted
|
||||
and filtered. By setting this property to true, we ensure that the
|
||||
model is sorted and filtered whenever the contents of the source
|
||||
model change.
|
||||
|
||||
The main application window shows views of both the source model
|
||||
and the proxy model. The source view is quite simple:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 1
|
||||
|
||||
The QTreeView class provides a default model/view implementation
|
||||
of a tree view. Our view implements a tree representation of items
|
||||
in the application's source model.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 2
|
||||
|
||||
The QTreeView class provides a default model/view implementation
|
||||
of a tree view; our view implements a tree representation of items
|
||||
in the application's source model. We add our view widget to a
|
||||
layout that we install on a corresponding group box.
|
||||
|
||||
The proxy model view, on the other hand, contains several widgets
|
||||
controlling the various aspects of transforming the source model's
|
||||
data structure:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 3
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 4
|
||||
|
||||
Note that whenever the user changes one of the filtering options,
|
||||
we must explicitly reapply the filter. This is done by connecting
|
||||
the various editors to functions that update the proxy model.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 5
|
||||
|
||||
The sorting will be handled by the view. All we have to do is to
|
||||
enable sorting for our proxy view by setting the
|
||||
QTreeView::sortingEnabled property (which is false by
|
||||
default). Then we add all the filtering widgets and the proxy view
|
||||
to a layout that we install on a corresponding group box.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 6
|
||||
|
||||
Finally, after putting our two group boxes into another layout
|
||||
that we install on our main application widget, we customize the
|
||||
application window.
|
||||
|
||||
As mentioned above, we create the source model in the \c main ()
|
||||
function, calling the \c Window::setSourceModel() function to make
|
||||
the application use it:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 7
|
||||
|
||||
The QSortFilterProxyModel::setSourceModel() function makes the
|
||||
proxy model process the data in the given model, in this case out
|
||||
mail model. The \l {QAbstractItemView::}{setModel()} that the
|
||||
view widget inherits from the QAbstractItemModel class, sets the
|
||||
model for the view to present. Note that the latter function will
|
||||
also create and set a new selection model.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 8
|
||||
|
||||
The \c textFilterChanged() function is called whenever the user
|
||||
changes the filter pattern or the case sensitivity.
|
||||
|
||||
We first retrieve the preferred syntax (the FilterWidget::PatternSyntax
|
||||
enum is used to interpret the meaning of the given pattern), then
|
||||
we determine the preferred case sensitivity. Based on these
|
||||
preferences and the current filter pattern, we set the proxy
|
||||
model's \l {QSortFilterProxyModel::}{filterRegularExpression} property. The
|
||||
\l {QSortFilterProxyModel::}{filterRegularExpression} property holds the
|
||||
regular expression used to filter the contents of the source
|
||||
model. Note that calling QSortFilterProxyModel's \l
|
||||
{QSortFilterProxyModel::}{setFilterRegularExpression()} function also updates
|
||||
the model.
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/window.cpp 9
|
||||
|
||||
The \c dateFilterChanged() function is called whenever the user
|
||||
modifies the range of valid dates. We retrieve the new dates from
|
||||
the user interface, and call the corresponding functions (provided
|
||||
by our custom proxy model) to set the proxy model's minimum and
|
||||
maximum dates. As we explained above, calling these functions also
|
||||
updates the model.
|
||||
|
||||
\section1 The Main() Function
|
||||
|
||||
In this example, we have separated the application from the source
|
||||
model by creating the model in the \c main () function. First we
|
||||
create the application, then we create the source model:
|
||||
|
||||
\snippet itemviews/customsortfiltermodel/main.cpp 0
|
||||
|
||||
The \c createMailModel() function is a convenience function
|
||||
provided to simplify the constructor. All it does is to create and
|
||||
return a model describing a collection of emails. The model is an
|
||||
instance of the QStandardItemModel class, i.e., a generic model
|
||||
for storing custom data typically used as a repository for
|
||||
standard Qt data types. Each mail description is added to the
|
||||
model using \c addMail(), another convenience function. See \c
|
||||
{itemviews/customsortfiltermodel/main.cpp} for details.
|
||||
*/
|
29
examples/widgets/doc/src/deform.qdoc
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example painting/deform
|
||||
\title Vector Deformation
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates how to manipulate the elements of a QPainterPath.
|
||||
|
||||
\brief This example shows how to use advanced vector techniques to draw text
|
||||
using a \c QPainterPath.
|
||||
|
||||
\image deform-demo.png
|
||||
|
||||
We define a vector deformation field in the shape of a lens and apply
|
||||
this to all points in a path. This means that what is rendered on
|
||||
screen is not pixel manipulation, but modified vector representations of
|
||||
the glyphs themselves. This is visible from the high quality of the
|
||||
antialiased edges for the deformed glyphs.
|
||||
|
||||
To get a fairly complex path we allow the user to type in text and
|
||||
convert the text to paths. This is done using the
|
||||
QPainterPath::addText() function.
|
||||
|
||||
The lens is drawn using a single call to QPainter::drawEllipse(),
|
||||
using a QRadialGradient to fill it with a specialized color
|
||||
table, giving the effect of the sun's reflection and a drop
|
||||
shadow. The lens is cached as a pixmap for better performance.
|
||||
*/
|
812
examples/widgets/doc/src/diagramscene.qdoc
Normal file
@ -0,0 +1,812 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example graphicsview/diagramscene
|
||||
\title Diagram Scene Example
|
||||
\ingroup examples-graphicsview
|
||||
\brief Demonstrate how to use the Graphics View framework.
|
||||
|
||||
\image diagramscene.png
|
||||
|
||||
The Diagram Scene example is an application in which you can
|
||||
create a flowchart diagram. It is possible to add flowchart shapes
|
||||
and text and connect the shapes by arrows as shown in the image
|
||||
above. The shapes, arrows, and text can be given different
|
||||
colors, and it is possible to change the font, style, and
|
||||
underline of the text.
|
||||
|
||||
The Qt graphics view framework is designed to manage and display
|
||||
custom 2D graphics items. The main classes of the framework are
|
||||
QGraphicsItem, QGraphicsScene and QGraphicsView. The graphics
|
||||
scene manages the items and provides a surface for them.
|
||||
QGraphicsView is a widget that is used to render a scene on the
|
||||
screen. See the \l{Graphics View Framework} for a more detailed
|
||||
description of the framework.
|
||||
|
||||
In this example we show how to create such custom graphics
|
||||
scenes and items by implementing classes that inherit
|
||||
QGraphicsScene and QGraphicsItem.
|
||||
|
||||
In particular we show how to:
|
||||
|
||||
\list
|
||||
\li Create custom graphics items.
|
||||
\li Handle mouse events and movement of items.
|
||||
\li Implement a graphics scene that can manage our custom items.
|
||||
\li Custom painting of items.
|
||||
\li Create a movable and editable text item.
|
||||
\endlist
|
||||
|
||||
The example consists of the following classes:
|
||||
\list
|
||||
\li \c MainWindow creates the widgets and display
|
||||
them in a QMainWindow. It also manages the interaction
|
||||
between the widgets and the graphics scene, view and
|
||||
items.
|
||||
\li \c DiagramItem inherits QGraphicsPolygonItem and
|
||||
represents a flowchart shape.
|
||||
\li \c TextDiagramItem inherits QGraphicsTextItem and
|
||||
represents text items in the diagram. The class adds
|
||||
support for moving the item with the mouse, which is not
|
||||
supported by QGraphicsTextItem.
|
||||
\li \c Arrow inherits QGraphicsLineItem and is an arrow
|
||||
that connect two DiagramItems.
|
||||
\li \c DiagramScene inherits QGraphicsDiagramScene and
|
||||
provides support for \c DiagramItem, \c Arrow and
|
||||
\c DiagramTextItem (In addition to the support already
|
||||
handled by QGraphicsScene).
|
||||
\endlist
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.h 0
|
||||
|
||||
The \c MainWindow class creates and lays out the widgets in a
|
||||
QMainWindow. The class forwards input from the widgets to the
|
||||
DiagramScene. It also updates its widgets when the diagram
|
||||
scene's text item changes, or a diagram item or a diagram text item
|
||||
is inserted into the scene.
|
||||
|
||||
The class also deletes items from the scene and handles the
|
||||
z-ordering, which decides the order in which items are drawn when
|
||||
they overlap each other.
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
|
||||
We start with a look at the constructor:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 0
|
||||
|
||||
In the constructor we call methods to create the widgets and
|
||||
layouts of the example before we create the diagram scene.
|
||||
The toolbars must be created after the scene as they connect
|
||||
to its signals. We then lay the widgets out in the window.
|
||||
|
||||
We connect to the \c itemInserted() and \c textInserted() slots of
|
||||
the diagram scenes as we want to uncheck the buttons in the tool
|
||||
box when an item is inserted. When an item is selected in
|
||||
the scene we receive the \c itemSelected() signal. We use this to
|
||||
update the widgets that display font properties if the item
|
||||
selected is a \c DiagramTextItem.
|
||||
|
||||
The \c createToolBox() function creates and lays out the widgets
|
||||
of the \c toolBox QToolBox. We will not examine it with a
|
||||
high level of detail as it does not deal with graphics framework
|
||||
specific functionality. Here is its implementation:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 21
|
||||
|
||||
This part of the function sets up the tabbed widget item that
|
||||
contains the flowchart shapes. An exclusive QButtonGroup always
|
||||
keeps one button checked; we want the group to allow all buttons
|
||||
to be unchecked.
|
||||
We still use a button group since we can associate user
|
||||
data, which we use to store the diagram type, with each button.
|
||||
The \c createCellWidget() function sets up the buttons in the
|
||||
tabbed widget item and is examined later.
|
||||
|
||||
The buttons of the background tabbed widget item is set up in the
|
||||
same way, so we skip to the creation of the tool box:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 22
|
||||
|
||||
We set the preferred size of the toolbox as its maximum. This
|
||||
way, more space is given to the graphics view.
|
||||
|
||||
Here is the \c createActions() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 23
|
||||
|
||||
We show an example of the creation of an action. The
|
||||
functionality the actions trigger is discussed in the slots we
|
||||
connect the actions to. You can see the \l{Qt Widgets - Application
|
||||
Example}{application example} if you need a high-level
|
||||
introduction to actions.
|
||||
|
||||
The is the \c createMenus() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 24
|
||||
|
||||
We create the three menus' of the example.
|
||||
|
||||
The \c createToolbars() function sets up the examples tool
|
||||
bars. The three \l{QToolButton}s in the \c colorToolBar, the \c
|
||||
fontColorToolButton, \c fillColorToolButton, and \c
|
||||
lineColorToolButton, are interesting as we create icons for them
|
||||
by drawing on a QPixmap with a QPainter. We show how the \c
|
||||
fillColorToolButton is created. This button lets the user select a
|
||||
color for the diagram items.
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 25
|
||||
\dots
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 26
|
||||
|
||||
We set the menu of the tool button with
|
||||
\l{QToolButton::}{setMenu()}. We need the \c fillAction QAction
|
||||
object to always be pointing to the selected action of the menu.
|
||||
The menu is created with the \c createColorMenu() function and, as
|
||||
we shall see later, contains one menu item for each color that the
|
||||
items can have. When the user presses the button, which trigger
|
||||
the \l{QToolButton::}{clicked()} signal, we can set the color of
|
||||
the selected item to the color of \c fillAction. It is with \c
|
||||
createColorToolButtonIcon() we create the icon for the button.
|
||||
|
||||
\dots
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 27
|
||||
|
||||
Here is the \c createBackgroundCellWidget() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 28
|
||||
|
||||
This function creates \l{QWidget}s containing a tool button
|
||||
and a label. The widgets created with this function are used for
|
||||
the background tabbed widget item in the tool box.
|
||||
|
||||
Here is the \c createCellWidget() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 29
|
||||
|
||||
This function returns a QWidget containing a QToolButton with
|
||||
an image of one of the \c DiagramItems, i.e., flowchart shapes.
|
||||
The image is created by the \c DiagramItem through the \c image()
|
||||
function. The QButtonGroup class lets us attach an id (int) with
|
||||
each button; we store the diagram's type, i.e., the
|
||||
DiagramItem::DiagramType enum. We use the stored diagram type when
|
||||
we create new diagram items for the scene. The widgets created
|
||||
with this function is used in the tool box.
|
||||
|
||||
Here is the \c createColorMenu() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 30
|
||||
|
||||
This function creates a color menu that is used as the
|
||||
drop-down menu for the tool buttons in the \c colorToolBar. We
|
||||
create an action for each color that we add to the menu. We fetch
|
||||
the actions data when we set the color of items, lines, and text.
|
||||
|
||||
Here is the \c createColorToolButtonIcon() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 31
|
||||
|
||||
This function is used to create the QIcon of the \c
|
||||
fillColorToolButton, \c fontColorToolButton, and \c
|
||||
lineColorToolButton. The \a imageFile string is either the text,
|
||||
flood-fill, or line symbol that is used for the buttons. Beneath
|
||||
the image we draw a filled rectangle using \a color.
|
||||
|
||||
Here is the \c createColorIcon() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 32
|
||||
|
||||
This function creates an icon with a filled rectangle in the
|
||||
color of \a color. It is used for creating icons for the color
|
||||
menus in the \c fillColorToolButton, \c fontColorToolButton, and
|
||||
\c lineColorToolButton.
|
||||
|
||||
Here is the \c backgroundButtonGroupClicked() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 1
|
||||
|
||||
In this function we set the QBrush that is used to draw the
|
||||
background of the diagramscene. The background can be a grid of
|
||||
squares of blue, gray, or white tiles, or no grid at all. We have
|
||||
\l{QPixmap}s of the tiles from png files that we create the brush
|
||||
with.
|
||||
|
||||
When one of the buttons in the background tabbed widget item is
|
||||
clicked we change the brush; we find out which button it is by
|
||||
checking its text.
|
||||
|
||||
Here is the implementation of \c buttonGroupClicked():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 2
|
||||
|
||||
This slot is called when a button in \c buttonGroup is checked.
|
||||
When a button is checked the user can click on the graphics view
|
||||
and a \c DiagramItem of the selected type will be inserted into
|
||||
the \c DiagramScene. We must loop through the buttons in the group
|
||||
to uncheck other buttons as only one button is allowed to be
|
||||
checked at a time.
|
||||
|
||||
\c QButtonGroup assigns an id to each button. We have set the id
|
||||
of each button to the diagram type, as given by DiagramItem::DiagramType
|
||||
that will be inserted into the scene when it is clicked. We can
|
||||
then use the button id when we set the diagram type with
|
||||
\c setItemType(). In the case of text we assigned an id that has a
|
||||
value that is not in the DiagramType enum.
|
||||
|
||||
Here is the implementation of \c deleteItem():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 3
|
||||
|
||||
This slot deletes the selected item, if any, from the scene. It
|
||||
deletes the arrows first in order to avoid to delete them twice. If
|
||||
the item to be deleted is a \c DiagramItem, we also need to delete
|
||||
arrows connected to it; we don't want arrows in the scene that
|
||||
aren't connected to items in both ends.
|
||||
|
||||
This is the implementation of pointerGroupClicked():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 4
|
||||
|
||||
The \c pointerTypeGroup decides whether the scene is in ItemMove
|
||||
or InsertLine mode. This button group is exclusive, i.e., only
|
||||
one button is checked at any time. As with the \c buttonGroup above
|
||||
we have assigned an id to the buttons that matches values of the
|
||||
DiagramScene::Mode enum, so that we can use the id to set the
|
||||
correct mode.
|
||||
|
||||
Here is the \c bringToFront() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 5
|
||||
|
||||
Several items may collide, i.e., overlap, with each other in
|
||||
the scene. This slot is called when the user requests that an
|
||||
item should be placed on top of the items it collides with.
|
||||
\l{QGraphicsItem}{QGrapicsItems} have a z-value that decides the
|
||||
order in which items are stacked in the scene; you can think of it
|
||||
as the z-axis in a 3D coordinate system. When items collide the
|
||||
items with higher z-values will be drawn on top of items with
|
||||
lower values. When we bring an item to the front we can loop
|
||||
through the items it collides with and set a z-value that is
|
||||
higher than all of them.
|
||||
|
||||
Here is the \c sendToBack() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 6
|
||||
|
||||
This slot works in the same way as \c bringToFront() described
|
||||
above, but sets a z-value that is lower than items the item that
|
||||
should be send to the back collides with.
|
||||
|
||||
This is the implementation of \c itemInserted():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 7
|
||||
|
||||
This slot is called from the \c DiagramScene when an item has been
|
||||
added to the scene. We set the mode of the scene back to the mode
|
||||
before the item was inserted, which is ItemMove or InsertText
|
||||
depending on which button is checked in the \c pointerTypeGroup.
|
||||
We must also uncheck the button in the in the \c buttonGroup.
|
||||
|
||||
Here is the implementation of \c textInserted():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 8
|
||||
|
||||
We simply set the mode of the scene back to the mode it had before
|
||||
the text was inserted.
|
||||
|
||||
Here is the \c currentFontChanged() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 9
|
||||
|
||||
When the user requests a font change, by using one of the
|
||||
widgets in the \c fontToolBar, we create a new QFont object and
|
||||
set its properties to match the state of the widgets. This is done
|
||||
in \c handleFontChange(), so we simply call that slot.
|
||||
|
||||
Here is the \c fontSizeChanged() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 10
|
||||
|
||||
When the user requests a font change, by using one of the
|
||||
widgets in the \c fontToolBar, we create a new QFont object and
|
||||
set its properties to match the state of the widgets. This is done
|
||||
in \c handleFontChange(), so we simply call that slot.
|
||||
|
||||
Here is the implementation of \c sceneScaleChanged():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 11
|
||||
|
||||
The user can increase or decrease the scale, with the \c
|
||||
sceneScaleCombo, the scene is drawn in.
|
||||
It is not the scene itself that changes its scale, but only the
|
||||
view.
|
||||
|
||||
Here is the \c textColorChanged() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 12
|
||||
|
||||
This slot is called when an item in the drop-down menu of the \c
|
||||
fontColorToolButton is pressed. We need to change the icon on
|
||||
the button to the color of the selected QAction. We keep a pointer
|
||||
to the selected action in \c textAction. It is in \c
|
||||
textButtonTriggered() we change the text color to the color of \c
|
||||
textAction, so we call that slot.
|
||||
|
||||
Here is the \c itemColorChanged() implementation:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 13
|
||||
|
||||
This slot handles requests for changing the color of \c
|
||||
DiagramItems in the same manner as \c textColorChanged() does for
|
||||
\c DiagramTextItems.
|
||||
|
||||
Here is the implementation of \c lineColorChanged():
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 14
|
||||
|
||||
This slot handles requests for changing the color of \c Arrows in
|
||||
the same manner that \c textColorChanged() does it for \c
|
||||
DiagramTextItems.
|
||||
|
||||
Here is the \c textButtonTriggered() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 15
|
||||
|
||||
\c textAction points to the QAction of the currently selected menu item
|
||||
in the \c fontColorToolButton's color drop-down menu. We have set
|
||||
the data of the action to the QColor the action represents, so we
|
||||
can simply fetch this when we set the color of text with \c
|
||||
setTextColor().
|
||||
|
||||
Here is the \c fillButtonTriggered() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 16
|
||||
|
||||
\c fillAction points to the selected menu item in the drop-down
|
||||
menu of \c fillColorToolButton(). We can therefore use the data of
|
||||
this action when we set the item color with \c setItemColor().
|
||||
|
||||
Here is the \c lineButtonTriggered() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 17
|
||||
|
||||
\c lineAction point to the selected item in the drop-down menu of
|
||||
\c lineColorToolButton. We use its data when we set the arrow
|
||||
color with \c setLineColor().
|
||||
|
||||
Here is the \c handleFontChange() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 18
|
||||
|
||||
\c handleFontChange() is called when any of the widgets that show
|
||||
font properties changes. We create a new QFont object and set its
|
||||
properties based on the widgets. We then call the \c setFont()
|
||||
function of \c DiagramScene; it is the scene that set the font of
|
||||
the \c DiagramTextItems it manages.
|
||||
|
||||
Here is the \c itemSelected() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 19
|
||||
|
||||
This slot is called when an item in the \c DiagramScene is
|
||||
selected. In the case of this example it is only text items that
|
||||
emit signals when they are selected, so we do not need to check
|
||||
what kind of graphics \a item is.
|
||||
|
||||
We set the state of the widgets to match the properties of the
|
||||
font of the selected text item.
|
||||
|
||||
This is the \c about() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/mainwindow.cpp 20
|
||||
|
||||
This slot displays an about box for the example when the user
|
||||
selects the about menu item from the help menu.
|
||||
|
||||
\section1 DiagramScene Class Definition
|
||||
|
||||
The \c DiagramScene class inherits QGraphicsScene and adds
|
||||
functionality to handle \c DiagramItems, \c Arrows, and \c
|
||||
DiagramTextItems in addition to the items handled by its super
|
||||
class.
|
||||
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.h 0
|
||||
|
||||
In the \c DiagramScene a mouse click can give three different
|
||||
actions: the item under the mouse can be moved, an item may be
|
||||
inserted, or an arrow may be connected between to diagram items.
|
||||
Which action a mouse click has depends on the mode, given by the
|
||||
Mode enum, the scene is in. The mode is set with the \c setMode()
|
||||
function.
|
||||
|
||||
The scene also sets the color of its items and the font of its
|
||||
text items. The colors and font used by the scene can be set with
|
||||
the \c setLineColor(), \c setTextColor(), \c setItemColor() and \c
|
||||
setFont() functions. The type of \c DiagramItem, given by the
|
||||
DiagramItem::DiagramType function, to be created when an item is
|
||||
inserted is set with the \c setItemType() slot.
|
||||
|
||||
The \c MainWindow and \c DiagramScene share responsibility for
|
||||
the examples functionality. \c MainWindow handles the following
|
||||
tasks: the deletion of items, text, and arrows; moving diagram
|
||||
items to the back and front; and setting the scale of the scene.
|
||||
|
||||
\section1 DiagramScene Class Implementation
|
||||
|
||||
|
||||
We start with the constructor:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 0
|
||||
|
||||
The scene uses \c myItemMenu to set the context menu when it
|
||||
creates \c DiagramItems. We set the default mode to \c
|
||||
DiagramScene::MoveItem as this gives the default behavior of
|
||||
QGraphicsScene.
|
||||
|
||||
Here is the \c setLineColor() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 1
|
||||
|
||||
The \c isItemChange function returns true if an \c Arrow item is
|
||||
selected in the scene in which case we want to change its color.
|
||||
When the \c DiagramScene creates and adds new arrows to the scene
|
||||
it will also use the new \a color.
|
||||
|
||||
Here is the \c setTextColor() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 2
|
||||
|
||||
This function sets the color of \c DiagramTextItems equal to the
|
||||
way \c setLineColor() sets the color of \c Arrows.
|
||||
|
||||
Here is the \c setItemColor() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 3
|
||||
|
||||
This function sets the color the scene will use when creating
|
||||
\c DiagramItems. It also changes the color of a selected \c
|
||||
DiagramItem.
|
||||
|
||||
This is the implementation of \c setFont():
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 4
|
||||
|
||||
Set the font to use for new and selected, if a text item is
|
||||
selected, \c DiagramTextItems.
|
||||
|
||||
This is the implementation of \c editorLostFocus() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 5
|
||||
|
||||
\c DiagramTextItems emit a signal when they lose focus, which is
|
||||
connected to this slot. We remove the item if it has no text.
|
||||
If not, we would leak memory and confuse the user as the items
|
||||
will be edited when pressed on by the mouse.
|
||||
|
||||
The \c mousePressEvent() function handles mouse press event's
|
||||
different depending on which mode the \c DiagramScene is in. We
|
||||
examine its implementation for each mode:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 6
|
||||
|
||||
We simply create a new \c DiagramItem and add it to the scene at
|
||||
the position the mouse was pressed. Note that the origin of its
|
||||
local coordinate system will be under the mouse pointer position.
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 7
|
||||
|
||||
The user adds \c Arrows to the scene by stretching a line between
|
||||
the items the arrow should connect. The start of the line is fixed
|
||||
in the place the user clicked the mouse and the end follows the
|
||||
mouse pointer as long as the button is held down. When the user
|
||||
releases the mouse button an \c Arrow will be added to the scene
|
||||
if there is a \c DiagramItem under the start and end of the line.
|
||||
We will see how this is implemented later; here we simply add the
|
||||
line.
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 8
|
||||
|
||||
The \c DiagramTextItem is editable when the
|
||||
Qt::TextEditorInteraction flag is set, else it is movable by the
|
||||
mouse. We always want the text to be drawn on top of the other
|
||||
items in the scene, so we set the value to a number higher
|
||||
than other items in the scene.
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 9
|
||||
|
||||
We are in MoveItem mode if we get to the default switch; we
|
||||
can then call the QGraphicsScene implementation, which
|
||||
handles movement of items with the mouse. We make this call even
|
||||
if we are in another mode making it possible to add an item and
|
||||
then keep the mouse button pressed down and start moving
|
||||
the item. In the case of text items, this is not possible as they
|
||||
do not propagate mouse events when they are editable.
|
||||
|
||||
This is the \c mouseMoveEvent() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 10
|
||||
|
||||
We must draw the line if we are in InsertMode and the mouse button
|
||||
is pressed down (the line is not 0). As discussed in \c
|
||||
mousePressEvent() the line is drawn from the position the mouse
|
||||
was pressed to the current position of the mouse.
|
||||
|
||||
If we are in MoveItem mode, we call the QGraphicsScene
|
||||
implementation, which handles movement of items.
|
||||
|
||||
In the \c mouseReleaseEvent() function we need to check if an arrow
|
||||
should be added to the scene:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 11
|
||||
|
||||
First we need to get the items (if any) under the line's start
|
||||
and end points. The line itself is the first item at these points,
|
||||
so we remove it from the lists. As a precaution, we check if the
|
||||
lists are empty, but this should never happen.
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 12
|
||||
|
||||
Now we check if there are two different \c DiagramItems under
|
||||
the lines start and end points. If there are we can create an \c
|
||||
Arrow with the two items. The arrow is then added to each item and
|
||||
finally the scene. The arrow must be updated to adjust its start
|
||||
and end points to the items. We set the z-value of the arrow to
|
||||
-1000.0 because we always want it to be drawn under the items.
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 13
|
||||
|
||||
Here is the \c isItemChange() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramscene.cpp 14
|
||||
|
||||
The scene has single selection, i.e., only one item can be
|
||||
selected at any given time. The for loop will then loop one time
|
||||
with the selected item or none if no item is selected. \c
|
||||
isItemChange() is used to check whether a selected item exists
|
||||
and also is of the specified diagram \a type.
|
||||
|
||||
\section1 DiagramItem Class Definition
|
||||
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.h 0
|
||||
|
||||
The \c DiagramItem represents a flowchart shape in the \c
|
||||
DiagramScene. It inherits QGraphicsPolygonItem and has a polygon
|
||||
for each shape. The enum DiagramType has a value for each of the
|
||||
flowchart shapes.
|
||||
|
||||
The class has a list of the arrows that are connected to it.
|
||||
This is necessary because only the item knows when it is being
|
||||
moved (with the \c itemChanged() function) at which time the
|
||||
arrows must be updated. The item can also draw itself onto a
|
||||
QPixmap with the \c image() function. This is used for the tool
|
||||
buttons in \c MainWindow, see \c createColorToolButtonIcon() in
|
||||
\c MainWindow.
|
||||
|
||||
The Type enum is a unique identifier of the class. It is used by
|
||||
\c qgraphicsitem_cast(), which does dynamic casts of graphics
|
||||
items. The UserType constant is the minimum value a custom
|
||||
graphics item type can be.
|
||||
|
||||
\section1 DiagramItem Class Implementation
|
||||
|
||||
|
||||
We start with a look at the constructor:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 0
|
||||
|
||||
In the constructor we create the items polygon according to
|
||||
\a diagramType. \l{QGraphicsItem}s are not movable or selectable
|
||||
by default, so we must set these properties.
|
||||
|
||||
Here is the \c removeArrow() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 1
|
||||
|
||||
\c removeArrow() is used to remove \c Arrow items when they
|
||||
or \c DiagramItems they are connected to are removed from the
|
||||
scene.
|
||||
|
||||
Here is the \c removeArrows() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 2
|
||||
|
||||
This function is called when the item is removed from the scene
|
||||
and removes all arrows that are connected to this item. The arrow
|
||||
must be removed from the \c arrows list of both its start and end
|
||||
item. Since either the start or the end item is the object where
|
||||
this function is currently called, we have to make sure to work on
|
||||
a copy of arrows since removeArrow() is modifying this container.
|
||||
|
||||
Here is the \c addArrow() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 3
|
||||
|
||||
This function simply adds the \a arrow to the items \c arrows list.
|
||||
|
||||
Here is the \c image() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 4
|
||||
|
||||
This function draws the polygon of the item onto a QPixmap. In
|
||||
this example we use this to create icons for the tool buttons in
|
||||
the tool box.
|
||||
|
||||
Here is the \c contextMenuEvent() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 5
|
||||
|
||||
We show the context menu. As right mouse clicks, which shows the
|
||||
menu, don't select items by default we set the item selected with
|
||||
\l{QGraphicsItem::}{setSelected()}. This is necessary since an
|
||||
item must be selected to change its elevation with the
|
||||
\c bringToFront and \c sendToBack actions.
|
||||
|
||||
This is the implementation of \c itemChange():
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramitem.cpp 6
|
||||
|
||||
If the item has moved, we need to update the positions of the
|
||||
arrows connected to it. The implementation of QGraphicsItem does
|
||||
nothing, so we just return \a value.
|
||||
|
||||
\section1 DiagramTextItem Class Definition
|
||||
|
||||
The \c TextDiagramItem class inherits QGraphicsTextItem and
|
||||
adds the possibility to move editable text items. Editable
|
||||
QGraphicsTextItems are designed to be fixed in place and editing
|
||||
starts when the user single clicks on the item. With \c
|
||||
DiagramTextItem the editing starts with a double click leaving
|
||||
single click available to interact with and move it.
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramtextitem.h 0
|
||||
|
||||
We use \c itemChange() and \c focusOutEvent() to notify the
|
||||
\c DiagramScene when the text item loses focus and gets selected.
|
||||
|
||||
We reimplement the functions that handle mouse events to make it
|
||||
possible to alter the mouse behavior of QGraphicsTextItem.
|
||||
|
||||
\section1 DiagramTextItem Implementation
|
||||
|
||||
We start with the constructor:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramtextitem.cpp 0
|
||||
|
||||
We simply set the item movable and selectable, as these flags are
|
||||
off by default.
|
||||
|
||||
Here is the \c itemChange() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramtextitem.cpp 1
|
||||
|
||||
When the item is selected we emit the selectedChanged signal. The
|
||||
\c MainWindow uses this signal to update the widgets that display
|
||||
font properties to the font of the selected text item.
|
||||
|
||||
Here is the \c focusOutEvent() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramtextitem.cpp 2
|
||||
|
||||
\c DiagramScene uses the signal emitted when the text item loses
|
||||
focus to remove the item if it is empty, i.e., it contains no
|
||||
text.
|
||||
|
||||
This is the implementation of \c mouseDoubleClickEvent():
|
||||
|
||||
\snippet graphicsview/diagramscene/diagramtextitem.cpp 5
|
||||
|
||||
When we receive a double click event, we make the item editable by calling
|
||||
QGraphicsTextItem::setTextInteractionFlags(). We then forward the
|
||||
double-click to the item itself.
|
||||
|
||||
\section1 Arrow Class Definition
|
||||
|
||||
The \c Arrow class is a graphics item that connects two \c
|
||||
DiagramItems. It draws an arrow head to one of the items. To
|
||||
achieve this the item needs to paint itself and also re implement
|
||||
methods used by the graphics scene to check for collisions and
|
||||
selections. The class inherits QGraphicsLine item, and draws the
|
||||
arrowhead and moves with the items it connects.
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.h 0
|
||||
|
||||
The item's color can be set with \c setColor().
|
||||
|
||||
\c boundingRect() and \c shape() are reimplemented
|
||||
from QGraphicsLineItem and are used by the scene
|
||||
to check for collisions and selections.
|
||||
|
||||
Calling \c updatePosition() causes the arrow to recalculate its
|
||||
position and arrow head angle. \c paint() is reimplemented so that
|
||||
we can paint an arrow rather than just a line between items.
|
||||
|
||||
\c myStartItem and \c myEndItem are the diagram items that the
|
||||
arrow connects. The arrow is drawn with its head to the end item.
|
||||
\c arrowHead is a polygon with three vertices's we use to draw the
|
||||
arrow head.
|
||||
|
||||
\section1 Arrow Class Implementation
|
||||
|
||||
The constructor of the \c Arrow class looks like this:
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 0
|
||||
|
||||
We set the start and end diagram items of the arrow. The arrow
|
||||
head will be drawn where the line intersects the end item.
|
||||
|
||||
Here is the \c boundingRect() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 1
|
||||
|
||||
We need to reimplement this function because the arrow is
|
||||
larger than the bounding rectangle of the QGraphicsLineItem. The
|
||||
graphics scene uses the bounding rectangle to know which regions
|
||||
of the scene to update.
|
||||
|
||||
Here is the \c shape() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 2
|
||||
|
||||
The shape function returns a QPainterPath that is the exact
|
||||
shape of the item. The QGraphicsLineItem::shape() returns a path
|
||||
with a line drawn with the current pen, so we only need to add
|
||||
the arrow head. This function is used to check for collisions and
|
||||
selections with the mouse.
|
||||
|
||||
Here is the \c updatePosition() slot:
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 3
|
||||
|
||||
This slot updates the arrow by setting the start and end
|
||||
points of its line to the center of the items it connects.
|
||||
|
||||
Here is the \c paint() function:
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 4
|
||||
|
||||
If the start and end items collide we do not draw the arrow; the
|
||||
algorithm we use to find the point the arrow should be drawn at
|
||||
may fail if the items collide.
|
||||
|
||||
We first set the pen and brush we will use for drawing the arrow.
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 5
|
||||
|
||||
We then need to find the position at which to draw the
|
||||
arrowhead. The head should be drawn where the line and the end
|
||||
item intersects. This is done by taking the line between each
|
||||
point in the polygon and check if it intersects with the line of
|
||||
the arrow. Since the line start and end points are set to the
|
||||
center of the items the arrow line should intersect one and only
|
||||
one of the lines of the polygon. Note that the points in the
|
||||
polygon are relative to the local coordinate system of the item.
|
||||
We must therefore add the position of the end item to make the
|
||||
coordinates relative to the scene.
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 6
|
||||
|
||||
We calculate the angle between the x-axis and the line of the
|
||||
arrow. We need to turn the arrow head to this angle so that it
|
||||
follows the direction of the arrow. If the angle is negative we
|
||||
must turn the direction of the arrow.
|
||||
|
||||
We can then calculate the three points of the arrow head polygon.
|
||||
One of the points is the end of the line, which now is the
|
||||
intersection between the arrow line and the end polygon. Then we
|
||||
clear the \c arrowHead polygon from the previous calculated arrow
|
||||
head and set these new points.
|
||||
|
||||
\snippet graphicsview/diagramscene/arrow.cpp 7
|
||||
|
||||
If the line is selected, we draw two dotted lines that are
|
||||
parallel with the line of the arrow. We do not use the default
|
||||
implementation, which uses \l{QGraphicsItem::}{boundingRect()}
|
||||
because the QRect bounding rectangle is considerably larger than
|
||||
the line.
|
||||
*/
|