6.5.3 clean
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example draganddrop/dropsite
|
||||
\title Drop Site Example
|
||||
\examplecategory {User Interface Components}
|
||||
|
||||
\brief The example shows how to distinguish the various MIME formats available
|
||||
in a drag and drop operation.
|
||||
|
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 253 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 192 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 46 KiB |
@ -1,948 +0,0 @@
|
||||
// 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}}.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/addressbook
|
||||
\title Address Book
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The address book example shows how to use proxy models to display
|
||||
different views onto data from a single model.
|
||||
|
@ -4,8 +4,9 @@
|
||||
/*!
|
||||
\example painting/affine
|
||||
\title Affine Transformations
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates how affine transformations in QPainter works.
|
||||
\brief Demonstrates how affine transformations in QPainter work.
|
||||
|
||||
\brief In this example we show Qt's ability to perform affine transformations
|
||||
on painting operations.
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
/*!
|
||||
\example widgets/analogclock
|
||||
\examplecategory {Graphics}
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\meta tags {widgets}
|
||||
|
||||
\title Analog Clock
|
||||
|
@ -1,370 +0,0 @@
|
||||
// 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.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/basicdrawing
|
||||
\title Basic Drawing Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief The Basic Drawing example shows how to display basic
|
||||
graphics primitives in a variety of styles using the QPainter
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/basicgraphicslayouts
|
||||
\title Basic Graphics Layouts Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-graphicsview-layout
|
||||
\brief Demonstrates how to create basic graphics layout.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example layouts/basiclayouts
|
||||
\title Basic Layouts Example
|
||||
\examplecategory {User Interface Components}
|
||||
\brief Shows how to use the standard layout managers.
|
||||
|
||||
\e{Basic Layouts} shows how to use the standard layout managers that are
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/basicsortfiltermodel
|
||||
\title Basic Sort/Filter Model Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The Basic Sort/Filter Model example illustrates how to use
|
||||
QSortFilterProxyModel to perform basic sorting and filtering.
|
||||
|
@ -1,46 +0,0 @@
|
||||
// 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
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/calculator
|
||||
\title Calculator Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\ingroup examples-layout
|
||||
\brief The example shows how to use signals and slots to implement the
|
||||
|
@ -1,202 +0,0 @@
|
||||
// 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.
|
||||
*/
|
@ -3,6 +3,7 @@
|
||||
|
||||
/*!
|
||||
\title Calendar Widget Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\example widgets/calendarwidget
|
||||
\ingroup examples-widgets
|
||||
\ingroup examples-layout
|
||||
|
@ -1,251 +0,0 @@
|
||||
// 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.
|
||||
*/
|
@ -1,58 +0,0 @@
|
||||
// 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
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/chip
|
||||
\title 40000 Chips
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-graphicsview
|
||||
\brief Visualizes a huge graphic view scene with 40000 chip items.
|
||||
|
||||
|
@ -1,167 +0,0 @@
|
||||
// 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}
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/collidingmice
|
||||
\title Colliding Mice Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\brief Demonstrates how to animate items on a graphics view.
|
||||
\ingroup examples-graphicsview
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/coloreditorfactory
|
||||
\title Color Editor Factory Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief This example shows how to create an editor that can be used by
|
||||
a QItemDelegate.
|
||||
|
@ -4,20 +4,14 @@
|
||||
/*!
|
||||
\example itemviews/combowidgetmapper
|
||||
\title Combo Widget Mapper Example
|
||||
\examplecategory {User Interface Components}
|
||||
\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,
|
||||
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".
|
||||
@ -65,8 +59,7 @@
|
||||
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}:
|
||||
The rest of the constructor sets up connections and layouts:
|
||||
|
||||
\snippet itemviews/combowidgetmapper/window.cpp Set up connections and layouts
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example tools/completer
|
||||
\title Completer Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets-tools
|
||||
|
||||
\brief The Completer example shows how to provide string-completion facilities
|
||||
@ -45,7 +46,7 @@
|
||||
\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,
|
||||
get it to return the entire file path 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".
|
||||
|
||||
@ -201,7 +202,7 @@
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 14
|
||||
|
||||
The \c changeMaxVisible() update the maximum number of visible items in
|
||||
The \c changeMaxVisible() updates the maximum number of visible items in
|
||||
the completer.
|
||||
|
||||
\snippet tools/completer/mainwindow.cpp 15
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/composition
|
||||
\title Composition Modes
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates how Composition Modes work in QPainter.
|
||||
|
||||
@ -18,5 +19,5 @@
|
||||
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.
|
||||
as defined by T. Porter and T. Duff. See the QPainter documentation for details.
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/concentriccircles
|
||||
\title Concentric Circles Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates the improved quality that antialiasing and floating point precision gives.
|
||||
|
||||
@ -13,7 +14,7 @@
|
||||
how to do simple animations.
|
||||
|
||||
The application's main window displays several widgets which are
|
||||
drawn using the various combinations of precision and
|
||||
drawn using various combinations of precision and
|
||||
anti-aliasing.
|
||||
|
||||
\image concentriccircles-example.png
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/customsortfiltermodel
|
||||
\title Custom Sort/Filter Model Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The Custom Sort/Filter Model example illustrates how to subclass
|
||||
QSortFilterProxyModel to perform advanced sorting and filtering.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/deform
|
||||
\title Vector Deformation
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief Demonstrates how to manipulate the elements of a QPainterPath.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/diagramscene
|
||||
\title Diagram Scene Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-graphicsview
|
||||
\brief Demonstrate how to use the Graphics View framework.
|
||||
|
||||
@ -12,7 +13,7 @@
|
||||
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
|
||||
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.
|
||||
|
||||
@ -121,9 +122,7 @@
|
||||
|
||||
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.
|
||||
connect the actions to.
|
||||
|
||||
The is the \c createMenus() function:
|
||||
|
||||
@ -289,7 +288,7 @@
|
||||
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.
|
||||
We must also uncheck the button in the \c buttonGroup.
|
||||
|
||||
Here is the implementation of \c textInserted():
|
||||
|
||||
|
@ -1,51 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/digitalclock
|
||||
\title Digital Clock Example
|
||||
\ingroup examples-widgets
|
||||
\brief The Digital Clock example shows how to use QLCDNumber to display a
|
||||
number with LCD-like digits.
|
||||
|
||||
\borderedimage digitalclock-example.png
|
||||
\caption Screenshot of the Digital Clock example
|
||||
|
||||
This example also demonstrates how QTimer can be used to update a widget
|
||||
at regular intervals.
|
||||
|
||||
\section1 DigitalClock Class Definition
|
||||
|
||||
The \c DigitalClock class provides a clock widget showing the time with
|
||||
hours and minutes separated by a blinking colon. We subclass QLCDNumber
|
||||
and implement a private slot called \c showTime() to update the clock
|
||||
display:
|
||||
|
||||
\snippet widgets/digitalclock/digitalclock.h 0
|
||||
|
||||
\section1 DigitalClock Class Implementation
|
||||
|
||||
\snippet widgets/digitalclock/digitalclock.cpp 0
|
||||
|
||||
In the constructor, we first change the look of the LCD numbers. The
|
||||
QLCDNumber::Filled style produces raised segments filled with the
|
||||
foreground color (typically black). We also set up a one-second timer
|
||||
to keep track of the current time, and we connect
|
||||
its \l{QTimer::timeout()}{timeout()} signal to the private \c showTime() slot
|
||||
so that the display is updated every second. Then, we
|
||||
call the \c showTime() slot; without this call, there would be a one-second
|
||||
delay at startup before the time is shown.
|
||||
|
||||
\snippet widgets/digitalclock/digitalclock.cpp 1
|
||||
\snippet widgets/digitalclock/digitalclock.cpp 2
|
||||
|
||||
The \c showTime() slot is called whenever the clock display needs
|
||||
to be updated.
|
||||
|
||||
The current time is converted into a string with the format "hh:mm".
|
||||
When QTime::second() is a even number, the colon in the string is
|
||||
replaced with a space. This makes the colon appear and vanish every
|
||||
other second.
|
||||
|
||||
Finally, we call QLCDNumber::display() to update the widget.
|
||||
*/
|
@ -1,49 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/dirview
|
||||
\title Dir View Example
|
||||
\ingroup examples-itemviews
|
||||
\brief This example demonstrates the usage of a tree view, and smooth flicking on a touchscreen.
|
||||
|
||||
The Dir View example shows a tree view of the local file
|
||||
system. It uses the QFileSystemModel class to provide file
|
||||
and directory information.
|
||||
|
||||
\borderedimage dirview-example.png
|
||||
|
||||
\quotefromfile itemviews/dirview/main.cpp
|
||||
\skipto QCommandLineParser parser
|
||||
\printuntil parser.positionalArguments
|
||||
|
||||
The example supports a number of command line options.
|
||||
These options include:
|
||||
\list
|
||||
\li Application description
|
||||
\li -help option
|
||||
\li -version option
|
||||
\li if the optionc {-c} is specified, the application will not
|
||||
use custom directory options
|
||||
\endlist
|
||||
|
||||
\skipto QFileSystemModel
|
||||
\printuntil tree.setModel
|
||||
|
||||
Declares \c model as data model for reading the local filesystem.
|
||||
\c model.setRootPath("") sets the current folder as the folder from
|
||||
which \c model will start reading.
|
||||
QTreeView object \c tree visualizes the filesystem in a tree structure.
|
||||
|
||||
\skipto tree.setAnimated(false)
|
||||
\printuntil tree.setColumnWidth
|
||||
|
||||
Sets layout options for animation, indentation, sorting, and sizing of the
|
||||
filesystem tree.
|
||||
|
||||
\skipto QScroller::grabGesture
|
||||
\printuntil QScroller::grabGesture
|
||||
|
||||
Creates a \l QScroller instance to recognize gestures on touchscreens,
|
||||
so that you can flick the tree view with your finger.
|
||||
*/
|
@ -1,140 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example mainwindows/dockwidgets
|
||||
\title Dock Widgets Example
|
||||
\ingroup examples-mainwindow
|
||||
|
||||
\brief The Dock Widgets example shows how to add dock windows to an
|
||||
application. It also shows how to use Qt's rich text engine.
|
||||
|
||||
\image dockwidgets-example.png Screenshot of the Dock Widgets example
|
||||
|
||||
The application presents a simple business letter template, and has
|
||||
a list of customer names and addresses and a list of standard
|
||||
phrases in two dock windows. The user can click a customer to have
|
||||
their name and address inserted into the template, and click one or
|
||||
more of the standard phrases. Errors can be corrected by clicking
|
||||
the Undo button. Once the letter has been prepared it can be printed
|
||||
or saved as HTML.
|
||||
|
||||
\section1 MainWindow Class Definition
|
||||
|
||||
Here's the class definition:
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.h 0
|
||||
|
||||
We will now review each function in turn.
|
||||
|
||||
\section1 MainWindow Class Implementation
|
||||
|
||||
\snippet mainwindows/dockwidgets/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 having to include
|
||||
every class individually and is especially convenient if we add new
|
||||
widgets. We also include \c mainwindow.h.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 1
|
||||
|
||||
In the constructor, we start by creating a QTextEdit widget. Then we call
|
||||
QMainWindow::setCentralWidget(). This function passes ownership of
|
||||
the QTextEdit to the \c MainWindow and tells the \c MainWindow that
|
||||
the QTextEdit will occupy the \c MainWindow's central area.
|
||||
|
||||
Then we call \c createActions(), \c createMenus(), \c
|
||||
createToolBars(), \c createStatusBar(), and \c createDockWindows()
|
||||
to set up the user interface. Finally we call \c setWindowTitle() to
|
||||
give the application a title, and \c newLetter() to create a new
|
||||
letter template.
|
||||
|
||||
We won't quote the \c createActions(), \c createMenus(), \c
|
||||
createToolBars(), and \c createStatusBar() functions since they
|
||||
follow the same pattern as all the other Qt examples.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 9
|
||||
|
||||
We create the customers dock window first, and in addition to a
|
||||
window title, we also pass it a \c this pointer so that it becomes a
|
||||
child of \c MainWindow. Normally we don't have to pass a parent
|
||||
because widgets are parented automatically when they are laid out:
|
||||
but dock windows aren't laid out using layouts.
|
||||
|
||||
We've chosen to restrict the customers dock window to the left and
|
||||
right dock areas. (So the user cannot drag the dock window to the
|
||||
top or bottom dock areas.) The user can drag the dock window out of
|
||||
the dock areas entirely so that it becomes a free floating window.
|
||||
We can change this (and whether the dock window is moveable or
|
||||
closable) using QDockWidget::setFeatures().
|
||||
|
||||
Once we've created the dock window we create a list widget with the
|
||||
dock window as parent, then we populate the list and make it the
|
||||
dock window's widget. Finally we add the dock widget to the \c
|
||||
MainWindow using \c addDockWidget(), choosing to put it in the right
|
||||
dock area.
|
||||
|
||||
We undertake a similar process for the paragraphs dock window,
|
||||
except that we don't restrict which dock areas it can be dragged to.
|
||||
|
||||
Finally we set up the signal-slot connections. If the user clicks a
|
||||
customer or a paragraph their \c currentTextChanged() signal will be
|
||||
emitted and we connect these to \c insertCustomer() and
|
||||
addParagraph() passing the text that was clicked.
|
||||
|
||||
We briefly discuss the rest of the implementation, but have now
|
||||
covered everything relating to dock windows.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 2
|
||||
|
||||
In this function we clear the QTextEdit so that it is empty. Next we
|
||||
create a QTextCursor on the QTextEdit. We move the cursor to the
|
||||
start of the document and create and format a frame. We then create
|
||||
some character formats and a table format. We insert a table into
|
||||
the document and insert the company's name and address into a table
|
||||
using the table and character formats we created earlier. Then we
|
||||
insert the skeleton of the letter including two markers \c NAME and
|
||||
\c ADDRESS. We will also use the \c{Yours sincerely,} text as a marker.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 6
|
||||
|
||||
If the user clicks a customer we split the customer details into
|
||||
pieces. We then look for the \c NAME marker using the \c find()
|
||||
function. This function selects the text it finds, so when we call
|
||||
\c insertText() with the customer's name the name replaces the marker.
|
||||
We then look for the \c ADDRESS marker and replace it with each line
|
||||
of the customer's address. Notice that we wrapped all the insertions
|
||||
between a \c beginEditBlock() and \c endEditBlock() pair. This means
|
||||
that the entire name and address insertion is treated as a single
|
||||
operation by the QTextEdit, so a single undo will revert all the
|
||||
insertions.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 7
|
||||
|
||||
This function works in a similar way to \c insertCustomer(). First
|
||||
we look for the marker, in this case, \c {Yours sincerely,}, and then
|
||||
replace it with the standard paragraph that the user clicked. Again
|
||||
we use a \c beginEditBlock() ... \c endEditBlock() pair so that the
|
||||
insertion can be undone as a single operation.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 3
|
||||
|
||||
Qt's QTextDocument class makes printing documents easy. We simply
|
||||
take the QTextEdit's QTextDocument, set up the printer and print the
|
||||
document.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 4
|
||||
|
||||
QTextEdit can output its contents in HTML format, so we prompt the
|
||||
user for the name of an HTML file and if they provide one we simply
|
||||
write the QTextEdit's contents in HTML format to the file.
|
||||
|
||||
\snippet mainwindows/dockwidgets/mainwindow.cpp 5
|
||||
|
||||
If the focus is in the QTextEdit, pressing \uicontrol Ctrl+Z undoes as
|
||||
expected. But for the user's convenience we provide an
|
||||
application-wide undo function that simply calls the QTextEdit's
|
||||
undo: this means that the user can undo regardless of where the
|
||||
focus is in the application.
|
||||
*/
|
@ -1,18 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example draganddrop/puzzle
|
||||
\title Drag and Drop Puzzle Example
|
||||
|
||||
\brief The Drag and Drop Puzzle example demonstrates a way of using the drag and drop system with
|
||||
item view widgets.
|
||||
|
||||
\image draganddroppuzzle-example.png
|
||||
|
||||
This example is an implementation of a simple jigsaw puzzle game using Qt's
|
||||
drag and drop API.
|
||||
The \l{Item Views Puzzle Example}{Item View Puzzle} example shows
|
||||
many of the same features, but takes an alternative approach that uses Qt's
|
||||
model/view framework to manage drag and drop operations.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/dragdroprobot
|
||||
\title Drag and Drop Robot Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-graphicsview
|
||||
\brief Demonstrates how to drag and drop items in a graphics view.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example draganddrop/draggableicons
|
||||
\title Draggable Icons Example
|
||||
\examplecategory {User Interface Components}
|
||||
|
||||
\brief The Draggable Icons example shows how to drag and drop image data between widgets
|
||||
in the same application, and between different applications.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example draganddrop/draggabletext
|
||||
\title Draggable Text Example
|
||||
\examplecategory {User Interface Components}
|
||||
\brief Illustrates how to drag and drop text between widgets.
|
||||
|
||||
\brief The Draggable Text example shows how to drag and drop textual data between widgets
|
||||
|
@ -1,91 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example layouts/dynamiclayouts
|
||||
\title Dynamic Layouts Example
|
||||
\brief Shows how to re-orient widgets in running applications.
|
||||
|
||||
\e{Dynamic Layouts} implements dynamically placed widgets within running
|
||||
applications. The widget placement depends on whether \c Horizontal or \c
|
||||
Vertical is chosen.
|
||||
|
||||
\borderedimage dynamiclayouts-example.png
|
||||
For more information, visit the \l{Layout Management} page.
|
||||
|
||||
\section1 Dialog Constructor
|
||||
|
||||
To begin with, the application creates the UI components by calling the
|
||||
following methods:
|
||||
|
||||
\list
|
||||
\li createRotatableGroupBox()
|
||||
\li createOptionsGroupBox()
|
||||
\li createButtonBox()
|
||||
\endlist
|
||||
|
||||
It then adds the UI components to a GridLayout (\c mainLayout).
|
||||
|
||||
Finally, \c Dialog::rotateWidgets() is called.
|
||||
|
||||
\quotefromfile layouts/dynamiclayouts/dialog.cpp
|
||||
\skipuntil createRotatableGroupBox
|
||||
\printuntil setWindowTitle
|
||||
|
||||
\section1 Creating the Main Widgets
|
||||
|
||||
The \c createRotatableGroupBox() method creates a rotatable group box,
|
||||
then adds a series of widgets:
|
||||
|
||||
\list
|
||||
\li QSpinBox
|
||||
\li QSlider
|
||||
\li QDial
|
||||
\li QProgressBar
|
||||
\endlist
|
||||
|
||||
It goes on to add signals and slots to each widget, and assigns
|
||||
a QGridLayout called \a rotatableLayout.
|
||||
|
||||
\skipto Dialog::createRotatableGroupBox
|
||||
\printuntil /^\}/
|
||||
|
||||
\section1 Adding Options
|
||||
|
||||
\c createOptionsGroupBox() creates the following widgets:
|
||||
\list
|
||||
\li \c optionsGroupBox
|
||||
\li \c buttonsOrientationLabel
|
||||
\li \c buttonsOrientationComboBox. The orientation of the ComboBox is either
|
||||
\c horizontal (default value) or \c vertical. These two values
|
||||
are added during the startup of the application. It is not possible
|
||||
to leave the option empty.
|
||||
\endlist
|
||||
|
||||
\skipto Dialog::createOptionsGroupBox()
|
||||
\printuntil /^\}/
|
||||
|
||||
\section1 Adding Buttons
|
||||
|
||||
createButtonBox() constructs a QDialogButtonBox called \c buttonBox
|
||||
to which are added a \c closeButton, a \c helpButton and a
|
||||
\c rotateWidgetsButton.
|
||||
It then assigns a signal and a slot to each button in \c buttonBox.
|
||||
|
||||
\skipto Dialog::createButtonBox()
|
||||
\printuntil /^\}/
|
||||
|
||||
|
||||
\section1 Rotating the Widgets
|
||||
|
||||
Removes the current widgets and activates the next widget.
|
||||
|
||||
\quotefromfile layouts/dynamiclayouts/dialog.cpp
|
||||
\skipto Dialog::rotateWidgets()
|
||||
\printuntil rotatableLayout->addWidget(rotatableWidgets[i]
|
||||
\printuntil }
|
||||
\printuntil }
|
||||
|
||||
\include examples-run.qdocinc
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example animation/easing
|
||||
\title Easing Curves Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
|
||||
\brief The Easing Curves example shows how to use easing curves to
|
||||
control the speed of an animation.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example tools/echoplugin
|
||||
\title Echo Plugin Example
|
||||
\examplecategory {Data Processing & I/O}
|
||||
\ingroup examples-widgets-tools
|
||||
\ingroup examples-layout
|
||||
|
||||
@ -175,7 +176,5 @@
|
||||
create plugins.
|
||||
|
||||
We give an example of a plugin that extends Qt in the \l{Style
|
||||
Plugin Example}{style plugin} example. The \l{Plug & Paint
|
||||
Example}{plug and paint} example shows how to create static
|
||||
plugins.
|
||||
Plugin Example}{style plugin} example.
|
||||
*/
|
||||
|
@ -4,9 +4,10 @@
|
||||
/*!
|
||||
\example itemviews/editabletreemodel
|
||||
\title Editable Tree Model Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief This example shows how to implement a simple item-based tree model that can
|
||||
be used with other classes the model/view framework.
|
||||
be used with other classes in the model/view framework.
|
||||
|
||||
\image itemviews-editabletreemodel.png
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/elasticnodes
|
||||
\title Elastic Nodes Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-graphicsview
|
||||
\brief Demonstrates how to interact with graphical items in a scene.
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example graphicsview/embeddeddialogs
|
||||
\title Embedded Dialogs
|
||||
\ingroup examples-graphicsview-layout
|
||||
\brief Demonstrates how to embed dialogs into a graphics view.
|
||||
|
||||
This example shows how to embed standard dialogs into
|
||||
Graphics View. It also shows how you can customize the
|
||||
proxy class and add window shadows.
|
||||
|
||||
\image embeddeddialogs-demo.png
|
||||
*/
|
@ -1,121 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example dialogs/extension
|
||||
\title Extension Example
|
||||
\ingroup examples-dialogs
|
||||
|
||||
\brief The Extension example shows how to add an extension to a QDialog
|
||||
using the QAbstractButton::toggled() signal and the
|
||||
QWidget::setVisible() slot.
|
||||
|
||||
\image extension-example.png Screenshot of the Extension example
|
||||
|
||||
The Extension application lets the user add search parameters in
|
||||
a dialog and launch a simple or advanced search.
|
||||
|
||||
The simple search has two options: \uicontrol {Match case} and \uicontrol
|
||||
{Search from start}. The advanced search offers search for \uicontrol {Whole words},
|
||||
\uicontrol {Search backward}, and \uicontrol {Search selection}. The
|
||||
application starts with simple search as the default. Click the \uicontrol More button
|
||||
to show the advanced search options:
|
||||
|
||||
\image extension_more.png Screenshot of the Extension example
|
||||
|
||||
\section1 FindDialog Class Definition
|
||||
|
||||
The \c FindDialog class inherits QDialog. QDialog is the
|
||||
base class for dialog windows. A dialog window is a top-level
|
||||
window mostly used for short-term tasks and brief communications
|
||||
with the user.
|
||||
|
||||
\snippet dialogs/extension/finddialog.h 0
|
||||
|
||||
The \c FindDialog widget is the main application widget, and
|
||||
displays the application's search options and controlling
|
||||
buttons.
|
||||
|
||||
In addition to the constructor, there are several child widgets:
|
||||
|
||||
\list
|
||||
\li A QLineEdit with an associated QLabel to let the
|
||||
user type a word to search for.
|
||||
\li Several \l {QCheckBox}{QCheckBox}es to facilitate the search options.
|
||||
\li Three \l {QPushButton}{QPushButton}s:
|
||||
\list
|
||||
\li the \uicontrol Find button to start a search
|
||||
\li the \uicontrol More button to enable an advanced search
|
||||
\li a QWidget representing the application's extension part
|
||||
\endlist
|
||||
\endlist
|
||||
|
||||
\section1 FindDialog Class Implementation
|
||||
|
||||
Create the standard child widgets for the simple search in the constructor:
|
||||
the QLineEdit with the associated QLabel, two {QCheckBox}es and all the
|
||||
\l {QPushButton}{QPushButton}s.
|
||||
|
||||
\snippet dialogs/extension/finddialog.cpp 0
|
||||
|
||||
This snippet illustrates how you can define a shortcut key
|
||||
for a widget. A shortcut should be defined by putting the ampersand
|
||||
character (\c &) in front of the letter that should
|
||||
become the shortcut.
|
||||
For example, for \uicontrol {Find what}, pressing \uicontrol Alt
|
||||
and \uicontrol w transfers focus to the QLineEdit widget.
|
||||
Shortcuts can also be used for checking on or off a checkmark.
|
||||
For example, pressing \uicontrol Alt and \uicontrol c puts the check mark
|
||||
on \uicontrol {Match Case} if it was unchecked and vice versa.
|
||||
It is the QLabel::setBuddy() method that links a widget to the shortcut
|
||||
character if it has been defined.
|
||||
|
||||
Set the \uicontrol Find button's default property to true, using the
|
||||
QPushButton::setDefault() function. Then the push button will be
|
||||
pressed if the user presses the Enter (or Return) key. Note that a
|
||||
QDialog can only have one default button.
|
||||
|
||||
\snippet dialogs/extension/finddialog.cpp 2
|
||||
|
||||
Create the extension widget, and the \l {QCheckBox}{QCheckBox}es associated
|
||||
with the advanced search options.
|
||||
|
||||
\snippet dialogs/extension/finddialog.cpp 3
|
||||
|
||||
Now that the extension widget is created, connect the \uicontrol
|
||||
More button's \l{QAbstractButton::toggled()}{toggled()} signal to
|
||||
the extension widget's \l{QWidget::setVisible()}{setVisible()} slot.
|
||||
|
||||
The QAbstractButton::toggled() signal is emitted whenever a
|
||||
checkable button changes its state. The signal's argument is true
|
||||
if the button is checked, or false if the button is unchecked. The
|
||||
QWidget::setVisible() slot sets the widget's visible status. If
|
||||
the status is true the widget is shown, otherwise the widget is
|
||||
hidden.
|
||||
|
||||
Since the \uicontrol More button is checkable, the connection makes
|
||||
sure that the extension widget is shown depending on the state of
|
||||
the \uicontrol More button.
|
||||
|
||||
Create checkboxes associated with the advanced search options in
|
||||
a layout installed on the extension widget.
|
||||
|
||||
\snippet dialogs/extension/finddialog.cpp 4
|
||||
|
||||
Before creating the main layout, create several child layouts
|
||||
for the widgets. First align the QLabel and its buddy, the
|
||||
QLineEdit, using a QHBoxLayout. Then align the QLabel and the QLineEdit
|
||||
vertically with the checkboxes associated with the simple search,
|
||||
using a QVBoxLayout. Create also a QVBoxLayout for the buttons.
|
||||
Finally, lay out the two latter layouts and the extension widget
|
||||
using a QGridLayout.
|
||||
|
||||
\snippet dialogs/extension/finddialog.cpp 5
|
||||
|
||||
Hide the extension widget using the QWidget::hide()
|
||||
function, making the application only show the simple search
|
||||
options when it starts. When the user wants to access the advanced
|
||||
search options, the dialog only needs to change the visibility of
|
||||
the extension widget. Qt's layout management takes care of the
|
||||
dialog's appearance.
|
||||
*/
|
@ -1,15 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example effects/fademessage
|
||||
\title Fade Message Effect Example
|
||||
\ingroup examples-graphicsview-graphicseffects
|
||||
\brief Demonstrates how to apply effects on items in the view.
|
||||
|
||||
\div { style="text-align: left"}
|
||||
\inlineimage fademessageeffect-example.png
|
||||
\inlineimage fademessageeffect-example-faded.png
|
||||
\enddiv
|
||||
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/fetchmore
|
||||
\title Fetch More Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The Fetch More example shows how to add items to an item view
|
||||
model on demand.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example layouts/flowlayout
|
||||
\title Flow Layout Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-layout
|
||||
\brief Shows how to arrange widgets for different window sizes.
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example painting/fontsampler
|
||||
\title Font Sampler Example
|
||||
\ingroup examples-painting
|
||||
\brief The Font Sampler example shows how to preview and print multi-page documents.
|
||||
|
||||
The Font Sampler example shows how to preview and print multi-page documents.
|
||||
|
||||
\image fontsampler-example.png
|
||||
*/
|
@ -1,338 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example draganddrop/fridgemagnets
|
||||
\title Fridge Magnets Example
|
||||
\brief The Fridge Magnets example illustrates how to move around several types of
|
||||
MIME-encoded data with drag and drop.
|
||||
|
||||
The Fridge Magnets example shows how to supply more than one type
|
||||
of MIME-encoded data with a drag and drop operation.
|
||||
|
||||
\image fridgemagnets-example.png
|
||||
|
||||
With this application the user can play around with a collection
|
||||
of fridge magnets, using drag and drop to form new sentences from
|
||||
the words on the magnets. The example consists of two classes:
|
||||
|
||||
\list
|
||||
\li \c DragLabel is a custom widget representing one
|
||||
single fridge magnet.
|
||||
\li \c DragWidget provides the main application window.
|
||||
\endlist
|
||||
|
||||
We will first take a look at the \c DragLabel class, then we will
|
||||
examine the \c DragWidget class.
|
||||
|
||||
\section1 DragLabel Class Definition
|
||||
|
||||
Each fridge magnet is represented by an instance of the \c
|
||||
DragLabel class:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/draglabel.h 0
|
||||
|
||||
Each instance of this QLabel subclass will be used to display an
|
||||
pixmap generated from a text string. Since we cannot store both
|
||||
text and a pixmap in a standard label, we declare a private variable
|
||||
to hold the original text, and we define an additional member
|
||||
function to allow it to be accessed.
|
||||
|
||||
\section1 DragLabel Class Implementation
|
||||
|
||||
In the \c DragLabel constructor, we first create a QImage object
|
||||
on which we will draw the fridge magnet's text and frame:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/draglabel.cpp 0
|
||||
|
||||
Its size depends on the current font size, and its format is
|
||||
QImage::Format_ARGB32_Premultiplied; i.e., the image is stored
|
||||
using a premultiplied 32-bit ARGB format (0xAARRGGBB).
|
||||
|
||||
We then construct a font object that uses the application's
|
||||
default font, and set its style strategy. The style strategy tells
|
||||
the font matching algorithm what type of fonts should be used to
|
||||
find an appropriate default family. The QFont::ForceOutline forces
|
||||
the use of outline fonts.
|
||||
|
||||
To draw the text and frame onto the image, we use the QPainter
|
||||
class. QPainter provides highly optimized methods to do most of
|
||||
the drawing GUI programs require. It can draw everything from
|
||||
simple lines to complex shapes like pies and chords. It can also
|
||||
draw aligned text and pixmaps.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/draglabel.cpp 1
|
||||
|
||||
A painter can be activated by passing a paint device to the
|
||||
constructor, or by using the \l{QPainter::}{begin()} method as we
|
||||
do in this example. The \l{QPainter::}{end()} method deactivates
|
||||
it. Note that the latter function is called automatically upon
|
||||
destruction when the painter is activated by its constructor. The
|
||||
QPainter::Antialiasing render hint ensures that the paint engine
|
||||
will antialias the edges of primitives if possible.
|
||||
|
||||
When the painting is done, we convert our image to a pixmap using
|
||||
QPixmap's \l {QPixmap::}{fromImage()} method. This method also
|
||||
takes an optional flags argument, and converts the given image to
|
||||
a pixmap using the specified flags to control the conversion (the
|
||||
flags argument is a bitwise-OR of the Qt::ImageConversionFlags;
|
||||
passing 0 for flags sets all the default options).
|
||||
|
||||
\snippet draganddrop/fridgemagnets/draglabel.cpp 2
|
||||
|
||||
Finally, we set the label's \l{QLabel::pixmap}{pixmap property}
|
||||
and store the label's text for later use.
|
||||
|
||||
\e{Note that setting the pixmap clears any previous content, including
|
||||
any text previously set using QLabel::setText(), and disables
|
||||
the label widget's buddy shortcut, if any.}
|
||||
|
||||
\section1 DragWidget Class Definition
|
||||
|
||||
The \c DragWidget class inherits QWidget, providing support for
|
||||
drag and drop operations:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.h 0
|
||||
|
||||
To make the widget responsive to drag and drop operations, we simply
|
||||
reimplement the \l{QWidget::}{dragEnterEvent()},
|
||||
\l{QWidget::}{dragMoveEvent()} and \l{QWidget::}{dropEvent()} event
|
||||
handlers inherited from QWidget.
|
||||
|
||||
We also reimplement \l{QWidget::}{mousePressEvent()} to make the
|
||||
widget responsive to mouse clicks. This is where we will write code
|
||||
to start drag and drop operations.
|
||||
|
||||
\section1 DragWidget Class Implementation
|
||||
|
||||
In the constructor, we first open the file containing the words on
|
||||
our fridge magnets:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 0
|
||||
|
||||
QFile is an I/O device for reading and writing text and binary
|
||||
files and resources, and may be used by itself or in combination
|
||||
with QTextStream or QDataStream. We have chosen to read the
|
||||
contents of the file using the QTextStream class that provides a
|
||||
convenient interface for reading and writing text.
|
||||
|
||||
We then create the fridge magnets. As long as there is data (the
|
||||
QTextStream::atEnd() method returns true if there is no more data
|
||||
to be read from the stream), we read one line at a time using
|
||||
QTextStream's \l {QTextStream::}{readLine()} method.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 1
|
||||
|
||||
For each line, we create a \c DragLabel object using the read line
|
||||
as text, we calculate its position and ensure that it is visible by
|
||||
calling the QWidget::show() method. We set the Qt::WA_DeleteOnClose
|
||||
attribute on each label to ensure that any unused labels will be
|
||||
deleted; we will need to create new labels and delete old ones when
|
||||
they are dragged around, and this ensures that the example does not
|
||||
leak memory.
|
||||
|
||||
We also set the \c FridgeMagnets widget's palette, minimum size
|
||||
and window title.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 2
|
||||
|
||||
Finally, to enable our user to move the fridge magnets around, we
|
||||
must also set the \c FridgeMagnets widget's
|
||||
\l{QWidget::acceptDrops}{acceptDrops} property.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 3
|
||||
|
||||
Setting this property to true announces to the system that this
|
||||
widget \e may be able to accept drop events (events that are sent
|
||||
when drag and drop actions are completed). Later, we will
|
||||
implement the functions that ensure that the widget accepts the
|
||||
drop events it is interested in.
|
||||
|
||||
\section2 Dragging
|
||||
|
||||
Let's take a look at the \l{QWidget::}{mousePressEvent()} event
|
||||
handler, where drag and drop operations begin:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 13
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 14
|
||||
|
||||
Mouse events occur when a mouse button is pressed or released
|
||||
inside a widget, or when the mouse cursor is moved. By
|
||||
reimplementing the \l{QWidget::}{mousePressEvent()} method we
|
||||
ensure that we will receive mouse press events for the widget
|
||||
containing the fridge magnets.
|
||||
|
||||
Whenever we receive such an event, we first check to see if the
|
||||
position of the click coincides with one of the labels. If not,
|
||||
we simply return.
|
||||
|
||||
If the user clicked a label, we determine the position of the
|
||||
\e{hot spot} (the position of the click relative to the top-left
|
||||
corner of the label). We create a byte array to store the label's
|
||||
text and the hot spot, and we use a QDataStream object to stream
|
||||
the data into the byte array.
|
||||
|
||||
With all the information in place, we create a new QMimeData object.
|
||||
As mentioned above, QMimeData objects associate the data that they
|
||||
hold with the corresponding MIME types to ensure that information
|
||||
can be safely transferred between applications. The
|
||||
\l{QMimeData::}{setData()} method sets the data associated with a
|
||||
given MIME type. In our case, we associate our item data with the
|
||||
custom \c application/x-fridgemagnet type.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 15
|
||||
|
||||
Note that we also associate the magnet's text with the
|
||||
\c text/plain MIME type using QMimeData's \l{QMimeData::}{setText()}
|
||||
method. Below, we will see how our widget detects both these MIME
|
||||
types with its event handlers.
|
||||
|
||||
Finally, we create a QDrag object. It is the QDrag class that
|
||||
handles most of the details of a drag and drop operation,
|
||||
providing support for MIME-based drag and drop data transfer. The
|
||||
data to be transferred by the drag and drop operation is contained
|
||||
in a QMimeData object. When we call QDrag's
|
||||
\l{QDrag::}{setMimeData()} method the ownership of our item data is
|
||||
transferred to the QDrag object.
|
||||
|
||||
We call the \l{QDrag::}{setPixmap()} function to set the pixmap used
|
||||
to represent the data during the drag and drop operation.
|
||||
Typically, this pixmap shows an icon that represents the MIME type
|
||||
of the data being transferred, but any pixmap can be used. In this
|
||||
example, we simply use the pixmap used by the label itself to make
|
||||
it look like the fridge magnet itself is being moved.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 16
|
||||
|
||||
We also specify the cursor's hot spot, its position relative to the
|
||||
top-level corner of the drag pixmap, to be the point we calculated
|
||||
above. This makes the process of dragging the label feel more natural
|
||||
because the cursor always points to the same place on the label
|
||||
during the drag operation.
|
||||
|
||||
We start the drag operation using QDrag's \l{QDrag::}{exec()} function,
|
||||
requesting that the magnet is copied when the drag is completed.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 17
|
||||
|
||||
The function returns the drop action actually performed by the user
|
||||
(this can be either a copy or a move action in this case); if this
|
||||
action is equal to Qt::MoveAction we will close the activated
|
||||
fridge magnet widget because we will create a new one to replace it
|
||||
(see the \l{drop}{dropEvent()} implementation). Otherwise, if
|
||||
the drop is outside our main widget, we simply show the widget in
|
||||
its original position.
|
||||
|
||||
\section2 Dropping
|
||||
|
||||
When a a drag and drop action enters our widget, we will receive a
|
||||
drag enter \e event. QDragEnterEvent inherits most of its
|
||||
functionality from QDragMoveEvent, which in turn inherits most of
|
||||
its functionality from QDropEvent. Note that we must accept this
|
||||
event in order to receive the drag move events that are sent while
|
||||
the drag and drop action is in progress. The drag enter event is
|
||||
always immediately followed by a drag move event.
|
||||
|
||||
In our \c dragEnterEvent() implementation, we first determine
|
||||
whether we support the event's MIME type or not:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 4
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 5
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 6
|
||||
|
||||
If the type is \c application/x-fridgemagnet and the event
|
||||
origins from any of this application's fridge magnet widgets, we
|
||||
first set the event's drop action using the
|
||||
QDropEvent::setDropAction() method. An event's drop action is the
|
||||
action to be performed on the data by the target. Qt::MoveAction
|
||||
indicates that the data is moved from the source to the target.
|
||||
|
||||
Then we call the event's \l {QDragMoveEvent::}{accept()} method to
|
||||
indicate that we have handled the event. In general, unaccepted
|
||||
events might be propagated to the parent widget. If the event
|
||||
origins from any other widget, we simply accept the proposed
|
||||
action.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 7
|
||||
|
||||
We also accept the proposed action if the event's MIME type is \c
|
||||
text/plain, i.e., if QMimeData::hasText() returns true. If the
|
||||
event has any other type, on the other hand, we call the event's
|
||||
\l {QDragMoveEvent::}{ignore()} method allowing the event to be
|
||||
propagated further.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 8
|
||||
|
||||
Drag move events occur when the cursor enters a widget, when it
|
||||
moves within the widget, and when a modifier key is pressed on the
|
||||
keyboard while the widget has focus. Our widget will receive drag
|
||||
move events repeatedly while a drag is within its boundaries. We
|
||||
reimplement the \l {QWidget::}{dragMoveEvent()} method, and
|
||||
examine the event in the exact same way as we did with drag enter
|
||||
events.
|
||||
|
||||
Note that the \l{QWidget::}{dropEvent()} event handler behaves
|
||||
slightly differently: We first get hold of the event's MIME
|
||||
data.
|
||||
|
||||
\target drop
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 9
|
||||
|
||||
The QMimeData class provides a container for data that
|
||||
records information about its MIME type. QMimeData objects
|
||||
associate the data that they hold with the corresponding MIME
|
||||
types to ensure that information can be safely transferred between
|
||||
applications, and copied around within the same application.
|
||||
|
||||
We retrieve the data associated with the \c application/x-fridgemagnet
|
||||
MIME type using a data stream in order to create a new \c DragLabel
|
||||
object.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 10
|
||||
|
||||
The QDataStream class provides serialization of binary data to a
|
||||
QIODevice (a data stream is a binary stream of encoded information
|
||||
which is completely independent of the host computer's operating
|
||||
system, CPU or byte order).
|
||||
|
||||
Finally, we create a label and move it to the event's position:
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 11
|
||||
|
||||
If the source of the event is also the widget receiving the
|
||||
drop event, we set the event's drop action to Qt::MoveAction and
|
||||
call the event's \l{QDragMoveEvent::}{accept()}
|
||||
method. Otherwise, we simply accept the proposed action. This
|
||||
means that labels are moved rather than copied in the same
|
||||
window. However, if we drag a label to a second instance of the
|
||||
Fridge Magnets example, the default action is to copy it, leaving
|
||||
the original in the first instance.
|
||||
|
||||
If the event's MIME type is \c text/plain (i.e., if
|
||||
QMimeData::hasText() returns true) we retrieve its text and split
|
||||
it into words. For each word we create a new \c DragLabel action,
|
||||
and show it at the event's position plus an offset depending on
|
||||
the number of words in the text. In the end we accept the proposed
|
||||
action. This lets the user drop selected text from a text editor or
|
||||
Web browser onto the widget to add more fridge magnets.
|
||||
|
||||
\snippet draganddrop/fridgemagnets/dragwidget.cpp 12
|
||||
|
||||
If the event has any other type, we call the event's
|
||||
\l{QDragMoveEvent::}{ignore()} method allowing the event to be
|
||||
propagated further.
|
||||
|
||||
\section1 Summary
|
||||
|
||||
We set our main widget's \l{QWidget::}{acceptDrops} property
|
||||
and reimplemented QWidget's \l{QWidget::}{dragEnterEvent()},
|
||||
\l{QWidget::}{dragMoveEvent()} and \l{QWidget::}{dropEvent()} event
|
||||
handlers to support content dropped on our widget.
|
||||
|
||||
In addition, we reimplemented the \l{QWidget::}{mousePressEvent()}
|
||||
function to let the user pick up fridge magnets in the first place.
|
||||
|
||||
Because data is communicated using drag and drop operations and
|
||||
encoded using MIME types, you can run more than one instance of this
|
||||
example, and transfer magnets between them.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/frozencolumn
|
||||
\title Frozen Column Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief This example demonstrates how to freeze a column within a QTableView.
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
\example gallery
|
||||
\meta {tag} {gallery}
|
||||
\title Widgets Gallery Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Widgets Gallery example shows widgets relevant for designing UIs.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/gradients
|
||||
\title Gradients
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief Shows how gradients can be used with QPainter.
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example graphicsview/flowlayout
|
||||
\title Graphics View Flow Layout Example
|
||||
\ingroup examples-graphicsview-layout
|
||||
\brief Demonstrates flow layout on a graphics view scene.
|
||||
|
||||
The Graphics View Flow Layout example shows the use of a flow layout
|
||||
in a Graphics View widget.
|
||||
|
||||
\image graphicsflowlayout-example.png
|
||||
|
||||
This example uses a Graphics View to display the widget, which is a more
|
||||
customizable approach than displaying the flow layout in the application
|
||||
window (See \l {Flow Layout Example}).
|
||||
|
||||
Graphics View Flow Layout snippet:
|
||||
|
||||
\snippet graphicsview/flowlayout/main.cpp 1
|
||||
|
||||
Flow Layout Example snippet:
|
||||
|
||||
\snippet layouts/flowlayout/main.cpp 1
|
||||
|
||||
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example graphicsview/simpleanchorlayout
|
||||
\title Simple Anchor Layout Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-graphicsview-layout
|
||||
\brief Demonstrates anchor layout on a graphics view scene.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/groupbox
|
||||
\title Group Box Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Group Box example shows how to use the different kinds of group
|
||||
boxes in Qt.
|
||||
|
@ -1,805 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/icons
|
||||
\title Icons Example
|
||||
\ingroup examples-widgets
|
||||
\brief The Icons example shows how QIcon can generate pixmaps reflecting
|
||||
an icon's state, mode and size.
|
||||
|
||||
These pixmaps are generated from the set of pixmaps made available to the
|
||||
icon, and are used by Qt widgets to show an icon representing a particular
|
||||
action.
|
||||
|
||||
\image icons-example.png Screenshot of the Icons example
|
||||
|
||||
Contents:
|
||||
|
||||
\tableofcontents
|
||||
|
||||
\section1 QIcon Overview
|
||||
|
||||
The QIcon class provides scalable icons in different modes and
|
||||
states. An icon's state and mode are depending on the intended use
|
||||
of the icon. Qt currently defines four modes:
|
||||
|
||||
\table
|
||||
\header \li Mode \li Description
|
||||
\row
|
||||
\li QIcon::Normal
|
||||
\li Display the pixmap when the user is not interacting with the
|
||||
icon, but the functionality represented by the icon is
|
||||
available.
|
||||
\row
|
||||
\li QIcon::Active
|
||||
\li Display the pixmap when the functionality represented by the
|
||||
icon is available and the user is interacting with the icon,
|
||||
for example, moving the mouse over it or clicking it.
|
||||
\row
|
||||
\li QIcon::Disabled
|
||||
\li Display the pixmap when the functionality represented by
|
||||
the icon is not available.
|
||||
\row
|
||||
\li QIcon::Selected
|
||||
\li Display the pixmap when the icon is selected.
|
||||
\endtable
|
||||
|
||||
QIcon's states are QIcon::On and QIcon::Off, which will display
|
||||
the pixmap when the widget is in the respective state. The most
|
||||
common usage of QIcon's states are when displaying checkable tool
|
||||
buttons or menu entries (see QAbstractButton::setCheckable() and
|
||||
QAction::setCheckable()). When a tool button or menu entry is
|
||||
checked, the QIcon's state is \l{QIcon::}{On}, otherwise it's
|
||||
\l{QIcon::}{Off}. You can, for example, use the QIcon's states to
|
||||
display differing pixmaps depending on whether the tool button or
|
||||
menu entry is checked or not.
|
||||
|
||||
A QIcon can generate smaller, larger, active, disabled, and
|
||||
selected pixmaps from the set of pixmaps it is given. Such
|
||||
pixmaps are used by Qt widgets to show an icon representing a
|
||||
particular action.
|
||||
|
||||
\section1 Overview of the Icons Application
|
||||
|
||||
With the Icons application you get a preview of an icon's
|
||||
generated pixmaps reflecting its different states, modes and size.
|
||||
|
||||
When an image is loaded into the application, it is converted into
|
||||
a pixmap and becomes a part of the set of pixmaps available to the
|
||||
icon. An image can be excluded from this set by checking off the
|
||||
related checkbox. The application provides a sub directory
|
||||
containing sets of images explicitly designed to illustrate how Qt
|
||||
renders an icon in different modes and states.
|
||||
|
||||
The application allows you to manipulate the icon size with some
|
||||
predefined sizes and a spin box. The predefined sizes are style
|
||||
dependent, but most of the styles have the same values. Only the
|
||||
\macos style differs by using 32 pixels instead of 16 pixels
|
||||
for toolbar buttons. You can navigate between the available styles
|
||||
using the \uicontrol View menu.
|
||||
|
||||
\image icons-view-menu.png Screenshot of the View menu
|
||||
|
||||
The \uicontrol View menu also provide the option to make the application
|
||||
guess the icon state and mode from an image's file name. The \uicontrol
|
||||
File menu provide the options of adding an image and removing all
|
||||
images. These last options are also available through a context
|
||||
menu that appears if you press the right mouse button within the
|
||||
table of image files. In addition, the \uicontrol File menu provide an
|
||||
\uicontrol Exit option, and the \uicontrol Help menu provide information about
|
||||
the example and about Qt.
|
||||
|
||||
\image icons_find_normal.png Screenshot of the Find Files
|
||||
|
||||
The screenshot above shows the application with one image file
|
||||
loaded. The \uicontrol {Guess Image Mode/State} is enabled and the
|
||||
style is Plastique.
|
||||
|
||||
When QIcon is provided with only one available pixmap, that
|
||||
pixmap is used for all the states and modes. In this case the
|
||||
pixmap's icon mode is set to normal, and the generated pixmaps
|
||||
for the normal and active modes will look the same. But in
|
||||
disabled and selected mode, Qt will generate a slightly different
|
||||
pixmap.
|
||||
|
||||
The next screenshot shows the application with an additional file
|
||||
loaded, providing QIcon with two available pixmaps. Note that the
|
||||
new image file's mode is set to disabled. When rendering the \uicontrol
|
||||
Disabled mode pixmaps, Qt will now use the new image. We can see
|
||||
the difference: The generated disabled pixmap in the first
|
||||
screenshot is slightly darker than the pixmap with the originally
|
||||
set disabled mode in the second screenshot.
|
||||
|
||||
\image icons_find_normal_disabled.png Screenshot of the Find Files
|
||||
|
||||
When Qt renders the icon's pixmaps it searches through the set of
|
||||
available pixmaps following a particular algorithm. The algorithm
|
||||
is documented in QIcon, but we will describe some particular cases
|
||||
below.
|
||||
|
||||
\image icons_monkey_active.png Screenshot of the Find Files
|
||||
|
||||
In the screenshot above, we have set \c monkey_on_32x32 to be an
|
||||
Active/On pixmap and \c monkey_off_64x64 to be Normal/Off. To
|
||||
render the other six mode/state combinations, QIcon uses the
|
||||
search algorithm described in the table below:
|
||||
|
||||
\table 100%
|
||||
\header \li{2,1} Requested Pixmap \li {8,1} Preferred Alternatives (mode/state)
|
||||
\header \li Mode \li State \li 1 \li 2 \li 3 \li 4 \li 5 \li 6 \li 7 \li 8
|
||||
\row \li{1,2} Normal \li Off \li \b N0 \li A0 \li N1 \li A1 \li D0 \li S0 \li D1 \li S1
|
||||
\row \li On \li N1 \li \b A1 \li N0 \li A0 \li D1 \li S1 \li D0 \li S0
|
||||
\row \li{1,2} Active \li Off \li A0 \li \b N0 \li A1 \li N1 \li D0 \li S0 \li D1 \li S1
|
||||
\row \li On \li \b A1 \li N1 \li A0 \li N0 \li D1 \li S1 \li D0 \li S0
|
||||
\row \li{1,2} Disabled \li Off \li D0 \li \b {N0'} \li A0' \li D1 \li N1' \li A1' \li S0' \li S1'
|
||||
\row \li On \li D1 \li N1' \li \b {A1'} \li D0 \li N0' \li A0' \li S1' \li S0'
|
||||
\row \li{1,2} Selected \li Off \li S0 \li \b {N0''} \li A0'' \li S1 \li N1'' \li A1'' \li D0'' \li D1''
|
||||
\row \li On \li S1 \li N1'' \li \b {A1''} \li S0 \li N0'' \li A0'' \li D1'' \li D0''
|
||||
\endtable
|
||||
|
||||
In the table, "0" and "1" stand for "Off" and "On", respectively.
|
||||
Single quotes indicates that QIcon generates a disabled ("grayed
|
||||
out") version of the pixmap; similarly, double quuote indicate
|
||||
that QIcon generates a selected ("blued out") version of the
|
||||
pixmap.
|
||||
|
||||
The alternatives used in the screenshot above are shown in bold.
|
||||
For example, the Disabled/Off pixmap is derived by graying out
|
||||
the Normal/Off pixmap (\c monkey_off_64x64).
|
||||
|
||||
In the next screenshots, we loaded the whole set of monkey
|
||||
images. By checking or unchecking file names from the image list,
|
||||
we get different results:
|
||||
|
||||
\table
|
||||
\row
|
||||
\li \inlineimage icons_monkey.png Screenshot of the Monkey Files
|
||||
\li \inlineimage icons_monkey_mess.png Screenshot of the Monkey Files
|
||||
\endtable
|
||||
|
||||
For any given mode/state combination, it is possible to specify
|
||||
several images at different resolutions. When rendering an
|
||||
icon, QIcon will automatically pick the most suitable image
|
||||
and scale it down if necessary. (QIcon never scales up images,
|
||||
because this rarely looks good.)
|
||||
|
||||
The screenshots below shows what happens when we provide QIcon
|
||||
with three images (\c qt_extended_16x16.png, \c qt_extended_32x32.png, \c
|
||||
qt_extended_48x48.png) and try to render the QIcon at various
|
||||
resolutions:
|
||||
|
||||
\table
|
||||
\row
|
||||
\li
|
||||
\li \inlineimage icons_qt_extended_8x8.png Qt Extended icon at 8 x 8
|
||||
\li \inlineimage icons_qt_extended_16x16.png Qt Extended icon at 16 x 16
|
||||
\li \inlineimage icons_qt_extended_17x17.png Qt Extended icon at 17 x 17
|
||||
\row
|
||||
\li
|
||||
\li 8 x 8
|
||||
\li \b {16 x 16}
|
||||
\li 17 x 17
|
||||
\row
|
||||
\li \inlineimage icons_qt_extended_32x32.png Qt Extended icon at 32 x 32
|
||||
\li \inlineimage icons_qt_extended_33x33.png Qt Extended icon at 33 x 33
|
||||
\li \inlineimage icons_qt_extended_48x48.png Qt Extended icon at 48 x 48
|
||||
\li \inlineimage icons_qt_extended_64x64.png Qt Extended icon at 64 x 64
|
||||
\row
|
||||
\li \b {32 x 32}
|
||||
\li 33 x 33
|
||||
\li \b {48 x 48}
|
||||
\li 64 x 64
|
||||
\endtable
|
||||
|
||||
For sizes up to 16 x 16, QIcon uses \c qt_extended_16x16.png and
|
||||
scales it down if necessary. For sizes between 17 x 17 and 32 x
|
||||
32, it uses \c qt_extended_32x32.png. For sizes above 32 x 32, it uses
|
||||
\c qt_extended_48x48.png.
|
||||
|
||||
\section1 Line-by-Line Walkthrough
|
||||
|
||||
The Icons example consists of four classes:
|
||||
|
||||
\list
|
||||
\li \c MainWindow inherits QMainWindow and is the main application
|
||||
window.
|
||||
\li \c IconPreviewArea is a custom widget that displays all
|
||||
combinations of states and modes for a given icon.
|
||||
\li \c IconSizeSpinBox is a subclass of QSpinBox that lets the
|
||||
user enter icon sizes (e.g., "48 x 48").
|
||||
\li \c ImageDelegate is a subclass of QStyledItemDelegate that
|
||||
provides comboboxes for letting the user set the mode and state
|
||||
associated with an image.
|
||||
\endlist
|
||||
|
||||
We will start by reviewing the \c IconPreviewArea class before we
|
||||
take a look at the \c MainWindow class. Finally, we will review the
|
||||
\c IconSizeSpinBox and \c ImageDelegate classes.
|
||||
|
||||
\section2 IconPreviewArea Class Definition
|
||||
|
||||
An \c IconPreviewArea widget consists of a group box containing a grid of
|
||||
QLabel widgets displaying headers and pixmaps.
|
||||
|
||||
\image icons_preview_area.png Screenshot of IconPreviewArea.
|
||||
|
||||
\snippet widgets/icons/iconpreviewarea.h 0
|
||||
|
||||
The \c IconPreviewArea class inherits QWidget. It displays the
|
||||
generated pixmaps corresponding to an icon's possible states and
|
||||
modes at a given size.
|
||||
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 42
|
||||
|
||||
We would like the table columns to be in the order QIcon::Normal,
|
||||
QIcon::Active, QIcon::Disabled, QIcon::Selected and the rows in the order
|
||||
QIcon::Off, QIcon::On, which does not match the enumeration. The above code
|
||||
provides arrays allowing to map from enumeration value to row/column
|
||||
(by using QList::indexOf()) and back by using the array index and lists
|
||||
of the matching strings. Qt's containers can be easily populated by
|
||||
using C++ 11 initializer lists.
|
||||
|
||||
We need two public functions to set the current icon and the
|
||||
icon's size. In addition the class has three private functions: We
|
||||
use the \c createHeaderLabel() and \c createPixmapLabel()
|
||||
functions when constructing the preview area, and we need the \c
|
||||
updatePixmapLabels() function to update the preview area when
|
||||
the icon or the icon's size has changed.
|
||||
|
||||
The \c NumModes and \c NumStates constants reflect \l{QIcon}'s
|
||||
number of currently defined modes and states.
|
||||
|
||||
\section2 IconPreviewArea Class Implementation
|
||||
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 0
|
||||
|
||||
In the constructor we create the labels displaying the headers and
|
||||
the icon's generated pixmaps, and add them to a grid layout.
|
||||
|
||||
When creating the header labels, we make sure the enums \c
|
||||
NumModes and \c NumStates defined in the \c .h file, correspond
|
||||
with the number of labels that we create. Then if the enums at
|
||||
some point are changed, the \c Q_ASSERT() macro will alert that this
|
||||
part of the \c .cpp file needs to be updated as well.
|
||||
|
||||
If the application is built in debug mode, the \c Q_ASSERT()
|
||||
macro will expand to
|
||||
|
||||
\code
|
||||
if (!condition)
|
||||
qFatal("ASSERT: "condition" in file ...");
|
||||
\endcode
|
||||
|
||||
In release mode, the macro simply disappear. The mode can be set
|
||||
in the application's \c .pro file. One way to do so is to add an
|
||||
option to \c qmake when building the application:
|
||||
|
||||
\code
|
||||
qmake "CONFIG += debug" icons.pro
|
||||
\endcode
|
||||
|
||||
or
|
||||
|
||||
\code
|
||||
qmake "CONFIG += release" icons.pro
|
||||
\endcode
|
||||
|
||||
Another approach is to add this line directly to the \c .pro
|
||||
file.
|
||||
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 1
|
||||
\codeline
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 2
|
||||
|
||||
The public \c setIcon() and \c setSize() functions change the icon
|
||||
or the icon size, and make sure that the generated pixmaps are
|
||||
updated.
|
||||
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 3
|
||||
\codeline
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 4
|
||||
|
||||
We use the \c createHeaderLabel() and \c createPixmapLabel()
|
||||
functions to create the preview area's labels displaying the
|
||||
headers and the icon's generated pixmaps. Both functions return
|
||||
the QLabel that is created.
|
||||
|
||||
\snippet widgets/icons/iconpreviewarea.cpp 5
|
||||
|
||||
We use the private \c updatePixmapLabel() function to update the
|
||||
generated pixmaps displayed in the preview area.
|
||||
|
||||
For each mode, and for each state, we retrieve a pixmap using the
|
||||
QIcon::pixmap() function, which generates a pixmap corresponding
|
||||
to the given state, mode and size. We pass the QWindows instance
|
||||
obtained by calling QWidget::windowHandle() on the top level
|
||||
widget (QWidget::nativeParentWidget()) in order to retrieve
|
||||
the pixmap that matches best.
|
||||
We format a tooltip displaying size, actual size and device pixel
|
||||
ratio.
|
||||
|
||||
\section2 MainWindow Class Definition
|
||||
|
||||
The \c MainWindow widget consists of three main elements: an
|
||||
images group box, an icon size group box and a preview area.
|
||||
|
||||
\image icons-example.png Screenshot of the Icons example
|
||||
|
||||
\snippet widgets/icons/mainwindow.h 0
|
||||
|
||||
The MainWindow class inherits from QMainWindow. We reimplement the
|
||||
constructor, and declare several private slots:
|
||||
|
||||
\list
|
||||
\li The \c about() slot simply provides information about the example.
|
||||
\li The \c changeStyle() slot changes the application's GUI style and
|
||||
adjust the style dependent size options.
|
||||
\li The \c changeSize() slot changes the size of the preview area's icon.
|
||||
\li The \c changeIcon() slot updates the set of pixmaps available to the
|
||||
icon displayed in the preview area.
|
||||
\li The \c addSampleImages() slot allows the user to load a new image
|
||||
from the samples provided into the application.
|
||||
\li The \c addOtherImages() slot allows the user to load a new image from
|
||||
the directory obtained by calling
|
||||
QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).
|
||||
\li The \c screenChanged() updates the display in the \uicontrol{High DPI}
|
||||
group box to correctly display the parameters of the current screen
|
||||
the window is located on.
|
||||
\endlist
|
||||
|
||||
In addition we declare several private functions to simplify the
|
||||
constructor.
|
||||
|
||||
\section2 MainWindow Class Implementation
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 0
|
||||
|
||||
In the constructor we first create the main window's central
|
||||
widget and its child widgets, and put them in a grid layout. Then
|
||||
we create the menus with their associated entries and actions.
|
||||
|
||||
We set the window title and determine the current style for the
|
||||
application. We also enable the icon size spin box by clicking the
|
||||
associated radio button, making the current value of the spin box
|
||||
the icon's initial size.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 1
|
||||
|
||||
The \c about() slot displays a message box using the static
|
||||
QMessageBox::about() function. In this example it displays a
|
||||
simple box with information about the example.
|
||||
|
||||
The \c about() function looks for a suitable icon in four
|
||||
locations: It prefers its parent's icon if that exists. If it
|
||||
doesn't, the function tries the top-level widget containing
|
||||
parent, and if that fails, it tries the active window. As a last
|
||||
resort it uses the QMessageBox's Information icon.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 2
|
||||
|
||||
In the \c changeStyle() slot we first check the slot's
|
||||
parameter. If it is false we immediately return, otherwise we find
|
||||
out which style to change to, i.e. which action that triggered the
|
||||
slot, using the QObject::sender() function.
|
||||
|
||||
This function returns the sender as a QObject pointer. Since we
|
||||
know that the sender is a QAction 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.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 3
|
||||
\snippet widgets/icons/mainwindow.cpp 4
|
||||
|
||||
Once we have the action, we extract the style name using
|
||||
QAction::data(). Then we create a QStyle object using the static
|
||||
QStyleFactory::create() function.
|
||||
|
||||
Although we can assume that the style is supported by the
|
||||
QStyleFactory: To be on the safe side, we use the \c Q_ASSERT()
|
||||
macro to check if the created style is valid before we use the
|
||||
QApplication::setStyle() function to set the application's GUI
|
||||
style to the new style. QApplication will automatically delete
|
||||
the style object when a new style is set or when the application
|
||||
exits.
|
||||
|
||||
The predefined icon size options provided in the application are
|
||||
style dependent, so we need to update the labels in the icon size
|
||||
group box and in the end call the \c changeSize() slot to update
|
||||
the icon's size.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 5
|
||||
|
||||
The \c changeSize() slot sets the size for the preview area's
|
||||
icon.
|
||||
|
||||
It is invoked by the QButtonGroup whose members are radio buttons for
|
||||
controlling the icon size. In \c createIconSizeGroupBox(), each button is
|
||||
assigned a QStyle::PixelMetric value as an id, which is passed as a
|
||||
parameter to the slot.
|
||||
|
||||
The special value \c OtherSize indicates that the spin box is
|
||||
enabled. If it is, we extract the extent of the new size from the
|
||||
box. If it's not, we query the style for the metric. Then we create
|
||||
a QSize object based on the extent, and use that object to set the
|
||||
size of the preview area's icon.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 12
|
||||
|
||||
The function \c addImages() is called by the slot addSampleImages()
|
||||
passing the samples directory, or by the slot addOtherImages()
|
||||
passing the directory obtained by querying
|
||||
QStandardPaths::standardLocations().
|
||||
|
||||
The first thing we do is to show a file dialog to the user.
|
||||
We initialize it to show the filters returned by
|
||||
QImageReader::supportedMimeTypes().
|
||||
|
||||
For each of the files the file dialog returns, we add a row to the
|
||||
table widget. The table widget is listing the images the user has
|
||||
loaded into the application.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 13
|
||||
|
||||
We retrieve the image name using the QFileInfo::baseName()
|
||||
function that returns the base name of the file without the path,
|
||||
and create the first table widget item in the row.
|
||||
We check if a high resolution version of the image exists (identified by
|
||||
the suffix \c @2x on the base name) and display that along with the size
|
||||
in the tooltip.
|
||||
|
||||
We add the file's complete name to the item's data. Since an item can
|
||||
hold several information pieces, we need to assign the file name a role
|
||||
that will distinguish it from other data. This role can be Qt::UserRole
|
||||
or any value above it.
|
||||
|
||||
We also make sure that the item is not editable by removing the
|
||||
Qt::ItemIsEditable flag. Table items are editable by default.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 15
|
||||
|
||||
Then we create the second and third items in the row making the
|
||||
default mode Normal and the default state Off. But if the \uicontrol
|
||||
{Guess Image Mode/State} option is checked, and the file name
|
||||
contains "_act", "_dis", or "_sel", the modes are changed to
|
||||
Active, Disabled, or Selected. And if the file name contains
|
||||
"_on", the state is changed to On. The sample files in the
|
||||
example's \c images subdirectory respect this naming convention.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 18
|
||||
|
||||
In the end we add the items to the associated row, and use the
|
||||
QTableWidget::openPersistentEditor() function to create
|
||||
comboboxes for the mode and state columns of the items.
|
||||
|
||||
Due to the connection between the table widget's \l
|
||||
{QTableWidget::itemChanged()}{itemChanged()} signal and the \c
|
||||
changeIcon() slot, the new image is automatically converted into a
|
||||
pixmap and made part of the set of pixmaps available to the icon
|
||||
in the preview area. So, corresponding to this fact, we need to
|
||||
make sure that the new image's check box is enabled.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 6
|
||||
|
||||
The \c changeIcon() slot is called when the user alters the set
|
||||
of images listed in the QTableWidget, to update the QIcon object
|
||||
rendered by the \c IconPreviewArea.
|
||||
|
||||
We first create a QIcon object, and then we run through the
|
||||
QTableWidget, which lists the images the user has loaded into the
|
||||
application.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 8
|
||||
|
||||
We also extract the image file's name using the
|
||||
QTableWidgetItem::data() function. This function takes a
|
||||
Qt::DataItemRole as an argument to retrieve the right data
|
||||
(remember that an item can hold several pieces of information)
|
||||
and returns it as a QVariant. Then we use the
|
||||
QVariant::toString() function to get the file name as a QString.
|
||||
|
||||
To create a pixmap from the file, we need to first create an
|
||||
image and then convert this image into a pixmap using
|
||||
QPixmap::fromImage(). Once we have the final pixmap, we add it,
|
||||
with its associated mode and state, to the QIcon's set of
|
||||
available pixmaps.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 11
|
||||
|
||||
After running through the entire list of images, we change the
|
||||
icon of the preview area to the one we just created.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 20
|
||||
|
||||
In the \c removeAllImages() slot, we simply set the table widget's
|
||||
row count to zero, automatically removing all the images the user
|
||||
has loaded into the application. Then we update the set of pixmaps
|
||||
available to the preview area's icon using the \c changeIcon()
|
||||
slot.
|
||||
|
||||
\image icons_images_groupbox.png Screenshot of the images group box
|
||||
|
||||
The \c createImagesGroupBox() function is implemented to simplify
|
||||
the constructor. The main purpose of the function is to create a
|
||||
QTableWidget that will keep track of the images the user has
|
||||
loaded into the application.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 21
|
||||
|
||||
First we create a group box that will contain the table widget.
|
||||
Then we create a QTableWidget and customize it to suit our
|
||||
purposes.
|
||||
|
||||
We call QAbstractItemView::setSelectionMode() to prevent the user
|
||||
from selecting items.
|
||||
|
||||
The QAbstractItemView::setItemDelegate() call sets the item
|
||||
delegate for the table widget. We create a \c ImageDelegate that
|
||||
we make the item delegate for our view.
|
||||
|
||||
The QStyledItemDelegate class can be used to provide an editor for an item view
|
||||
class that is subclassed from QAbstractItemView. Using a delegate
|
||||
for this purpose allows the editing mechanism to be customized and
|
||||
developed independently from the model and view.
|
||||
|
||||
In this example we derive \c ImageDelegate from QStyledItemDelegate.
|
||||
QStyledItemDelegate usually provides line editors, while our subclass
|
||||
\c ImageDelegate, provides comboboxes for the mode and state
|
||||
fields.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 22
|
||||
|
||||
Then we customize the QTableWidget's horizontal header, and hide
|
||||
the vertical header.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 24
|
||||
|
||||
At the end, we connect the QTableWidget::itemChanged() signal to
|
||||
the \c changeIcon() slot to ensure that the preview area is in
|
||||
sync with the image table.
|
||||
|
||||
\image icons_size_groupbox.png Screenshot of the icon size group box
|
||||
|
||||
The \c createIconSizeGroupBox() function is called from the
|
||||
constructor. It creates the widgets controlling the size of the
|
||||
preview area's icon.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 26
|
||||
|
||||
First we create a group box that will contain all the widgets;
|
||||
then we create the radio buttons and the spin box. We add the
|
||||
radio buttons to an instance of QButtonGroup, using the value
|
||||
of the QStyle::PixelMetric they represent as an integer id.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 40
|
||||
|
||||
We introduce an enumeration constant \c OtherSize to represent
|
||||
a custom size.
|
||||
|
||||
The spin box is not a regular QSpinBox but an \c IconSizeSpinBox.
|
||||
The \c IconSizeSpinBox class inherits QSpinBox and reimplements
|
||||
two functions: QSpinBox::textFromValue() and
|
||||
QSpinBox::valueFromText(). The \c IconSizeSpinBox is designed to
|
||||
handle icon sizes, e.g., "32 x 32", instead of plain integer
|
||||
values.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 27
|
||||
|
||||
Then we connect all of the radio buttons
|
||||
\l{QRadioButton::toggled()}{toggled()} signals and the spin box's
|
||||
\l {QSpinBox::valueChanged()}{valueChanged()} signal to the \c
|
||||
changeSize() slot to make sure that the size of the preview
|
||||
area's icon is updated whenever the user changes the icon size.
|
||||
In the end we put the widgets in a layout that we install on the
|
||||
group box.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 28
|
||||
|
||||
In the \c createActions() function we create and customize all the
|
||||
actions needed to implement the functionality associated with the
|
||||
menu entries in the application.
|
||||
|
||||
In particular we create the \c styleActionGroup based on the
|
||||
currently available GUI styles using
|
||||
QStyleFactory. QStyleFactory::keys() returns a list of valid keys,
|
||||
typically including "windows" and "fusion". Depending on the platform,
|
||||
"windowsvista" and "macos" may be available.
|
||||
|
||||
We create one action for each key, and adds the action to the
|
||||
action group. Also, for each action, we call QAction::setData()
|
||||
with the style name. We will retrieve it later using
|
||||
QAction::data().
|
||||
|
||||
As we go along, we create the \uicontrol File, \uicontrol View and
|
||||
\uicontrol Help menus and add the actions to them.
|
||||
|
||||
The QMenu class provides a menu widget for use in menu bars,
|
||||
context menus, and other popup menus. We put each menu in the
|
||||
application's menu bar, which we retrieve using
|
||||
QMainWindow::menuBar().
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 30
|
||||
|
||||
QWidgets have a \l{QWidget::contextMenuPolicy}{contextMenuPolicy}
|
||||
property that controls how the widget should behave when the user
|
||||
requests a context menu (e.g., by right-clicking). We set the
|
||||
QTableWidget's context menu policy to Qt::ActionsContextMenu,
|
||||
meaning that the \l{QAction}s associated with the widget should
|
||||
appear in its context menu.
|
||||
|
||||
Then we add the \uicontrol{Add Image} and \uicontrol{Remove All Images}
|
||||
actions to the table widget. They will then appear in the table
|
||||
widget's context menu.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 31
|
||||
|
||||
In the \c checkCurrentStyle() function we go through the group of
|
||||
style actions, looking for the current GUI style.
|
||||
|
||||
For each action, we first extract the style name using
|
||||
QAction::data(). Since this is only a QStyleFactory key (e.g.,
|
||||
"macos"), we cannot compare it directly to the current
|
||||
style's class name. We need to create a QStyle object using the
|
||||
static QStyleFactory::create() function and compare the class
|
||||
name of the created QStyle object with that of the current style.
|
||||
As soon as we are done with a QStyle candidate, we delete it.
|
||||
|
||||
For all QObject subclasses that use the \c Q_OBJECT macro, the
|
||||
class name of an object is available through its
|
||||
\l{QObject::metaObject()}{meta-object}.
|
||||
|
||||
We can assume that the style is supported by
|
||||
QStyleFactory, but to be on the safe side we use the \c
|
||||
Q_ASSERT() macro to make sure that QStyleFactory::create()
|
||||
returned a valid pointer.
|
||||
|
||||
\snippet widgets/icons/mainwindow.cpp 44
|
||||
|
||||
We overload the show() function to set up the updating of the
|
||||
current screen in \c screenChanged(). After calling QWidget::show(),
|
||||
the QWindow associated with the QWidget is created and we can
|
||||
connect to its QWindow::screenChanged() signal.
|
||||
|
||||
\section2 IconSizeSpinBox Class Definition
|
||||
|
||||
\snippet widgets/icons/iconsizespinbox.h 0
|
||||
|
||||
The \c IconSizeSpinBox class is a subclass of QSpinBox. A plain
|
||||
QSpinBox can only handle integers. But since we want to display
|
||||
the spin box's values in a more sophisticated way, we need to
|
||||
subclass QSpinBox and reimplement the QSpinBox::textFromValue()
|
||||
and QSpinBox::valueFromText() functions.
|
||||
|
||||
\image icons_size_spinbox.png Screenshot of the icon size spinbox
|
||||
|
||||
\section2 IconSizeSpinBox Class Implementation
|
||||
|
||||
\snippet widgets/icons/iconsizespinbox.cpp 0
|
||||
|
||||
The constructor is trivial.
|
||||
|
||||
\snippet widgets/icons/iconsizespinbox.cpp 2
|
||||
|
||||
QSpinBox::textFromValue() is used by the spin box whenever it
|
||||
needs to display a value. The default implementation returns a
|
||||
base 10 representation of the \c value parameter.
|
||||
|
||||
Our reimplementation returns a QString of the form "32 x 32".
|
||||
|
||||
\snippet widgets/icons/iconsizespinbox.cpp 1
|
||||
|
||||
The QSpinBox::valueFromText() function is used by the spin box
|
||||
whenever it needs to interpret text typed in by the user. Since
|
||||
we reimplement the \c textFromValue() function we also need to
|
||||
reimplement the \c valueFromText() function to interpret the
|
||||
parameter text and return the associated int value.
|
||||
|
||||
We parse the text using a regular expression (a QRegularExpression). We
|
||||
define an expression that matches one or several digits,
|
||||
optionally followed by whitespace, an "x" or the times symbol,
|
||||
whitespace and one or several digits again.
|
||||
|
||||
The first digits of the regular expression are captured using
|
||||
parentheses. This enables us to use the QRegularExpressionMatch::captured()
|
||||
or QRegularExpressionMatch::capturedTexts() functions to extract the matched
|
||||
characters. If the first and second numbers of the spin box value
|
||||
differ (e.g., "16 x 24"), we use the first number.
|
||||
|
||||
When the user presses \uicontrol Enter, QSpinBox first calls
|
||||
QSpinBox::valueFromText() to interpret the text typed by the
|
||||
user, then QSpinBox::textFromValue() to present it in a canonical
|
||||
format (e.g., "16 x 16").
|
||||
|
||||
\section2 ImageDelegate Class Definition
|
||||
|
||||
\snippet widgets/icons/imagedelegate.h 0
|
||||
|
||||
The \c ImageDelegate class is a subclass of QStyledItemDelegate. The
|
||||
QStyledItemDelegate class provides display and editing facilities for
|
||||
data items from a model. A single QStyledItemDelegate object is
|
||||
responsible for all items displayed in a item view (in our case,
|
||||
a QTableWidget).
|
||||
|
||||
A QStyledItemDelegate can be used to provide an editor for an item view
|
||||
class that is subclassed from QAbstractItemView. Using a delegate
|
||||
for this purpose allows the editing mechanism to be customized and
|
||||
developed independently from the model and view.
|
||||
|
||||
\snippet widgets/icons/imagedelegate.h 1
|
||||
|
||||
The default implementation of QStyledItemDelegate creates a QLineEdit.
|
||||
Since we want the editor to be a QComboBox, we need to subclass
|
||||
QStyledItemDelegate and reimplement the QStyledItemDelegate::createEditor(),
|
||||
QStyledItemDelegate::setEditorData() and QStyledItemDelegate::setModelData()
|
||||
functions.
|
||||
|
||||
\snippet widgets/icons/imagedelegate.h 2
|
||||
|
||||
The \c emitCommitData() slot is used to emit the
|
||||
QImageDelegate::commitData() signal with the appropriate
|
||||
argument.
|
||||
|
||||
\section2 ImageDelegate Class Implementation
|
||||
|
||||
\snippet widgets/icons/imagedelegate.cpp 0
|
||||
|
||||
The constructor is trivial.
|
||||
|
||||
\snippet widgets/icons/imagedelegate.cpp 1
|
||||
|
||||
The default QStyledItemDelegate::createEditor() implementation returns
|
||||
the widget used to edit the item specified by the model and item
|
||||
index for editing. The parent widget and style option are used to
|
||||
control the appearance of the editor widget.
|
||||
|
||||
Our reimplementation creates and populates a combobox instead of
|
||||
the default line edit. The contents of the combobox depends on
|
||||
the column in the table for which the editor is requested. Column
|
||||
1 contains the QIcon modes, whereas column 2 contains the QIcon
|
||||
states.
|
||||
|
||||
In addition, we connect the combobox's \l
|
||||
{QComboBox::activated()}{activated()} signal to the \c
|
||||
emitCommitData() slot to emit the
|
||||
QAbstractItemDelegate::commitData() signal whenever the user
|
||||
chooses an item using the combobox. This ensures that the rest of
|
||||
the application notices the change and updates itself.
|
||||
|
||||
\snippet widgets/icons/imagedelegate.cpp 2
|
||||
|
||||
The QStyledItemDelegate::setEditorData() function is used by
|
||||
QTableWidget to transfer data from a QTableWidgetItem to the
|
||||
editor. The data is stored as a string; we use
|
||||
QComboBox::findText() to locate it in the combobox.
|
||||
|
||||
Delegates work in terms of models, not items. This makes it
|
||||
possible to use them with any item view class (e.g., QListView,
|
||||
QListWidget, QTreeView, etc.). The transition between model and
|
||||
items is done implicitly by QTableWidget; we don't need to worry
|
||||
about it.
|
||||
|
||||
\snippet widgets/icons/imagedelegate.cpp 3
|
||||
|
||||
The QStyledItemDelegate::setEditorData() function is used by QTableWidget
|
||||
to transfer data back from the editor to the \l{QTableWidgetItem}.
|
||||
|
||||
\snippet widgets/icons/imagedelegate.cpp 4
|
||||
|
||||
The \c emitCommitData() slot simply emit the
|
||||
QAbstractItemDelegate::commitData() signal for the editor that
|
||||
triggered the slot. This signal must be emitted when the editor
|
||||
widget has completed editing the data, and wants to write it back
|
||||
into the model.
|
||||
|
||||
\section2 The Implementation of the Function main()
|
||||
|
||||
\snippet widgets/icons/main.cpp 45
|
||||
|
||||
We use QCommandLineParser to handle any command line options or parameters
|
||||
passed to the application. Then, we resize the main window according
|
||||
to the available screen geometry and show it.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/imagecomposition
|
||||
\title Image Composition Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\ingroup examples-layout
|
||||
\brief Shows how composition modes work in QPainter.
|
||||
|
@ -1,320 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/imageviewer
|
||||
\title Image Viewer Example
|
||||
\ingroup examples-widgets
|
||||
\brief The example shows how to combine QLabel and QScrollArea to
|
||||
display an image.
|
||||
|
||||
QLabel is typically used for displaying text,
|
||||
but it can also display an image. QScrollArea provides a
|
||||
scrolling view around another widget. If the child widget exceeds
|
||||
the size of the frame, QScrollArea automatically provides scroll
|
||||
bars.
|
||||
|
||||
The example demonstrates how QLabel's ability to scale its
|
||||
contents (QLabel::scaledContents), and QScrollArea's ability to
|
||||
automatically resize its contents (QScrollArea::widgetResizable),
|
||||
can be used to implement zooming and scaling features. In
|
||||
addition the example shows how to use QPainter to print an image.
|
||||
|
||||
\borderedimage imageviewer-example.png
|
||||
\caption Screenshot of the Image Viewer example
|
||||
|
||||
With the Image Viewer application, the users can view an image of
|
||||
their choice. The \uicontrol File menu gives the user the possibility
|
||||
to:
|
||||
|
||||
\list
|
||||
\li \uicontrol{Open...} - Open an image file
|
||||
\li \uicontrol{Print...} - Print an image
|
||||
\li \uicontrol{Exit} - Exit the application
|
||||
\endlist
|
||||
|
||||
Once an image is loaded, the \uicontrol View menu allows the users to:
|
||||
|
||||
\list
|
||||
\li \uicontrol{Zoom In} - Scale the image up by 25%
|
||||
\li \uicontrol{Zoom Out} - Scale the image down by 25%
|
||||
\li \uicontrol{Normal Size} - Show the image at its original size
|
||||
\li \uicontrol{Fit to Window} - Stretch the image to occupy the entire window
|
||||
\endlist
|
||||
|
||||
In addition the \uicontrol Help menu provides the users with information
|
||||
about the Image Viewer example in particular, and about Qt in
|
||||
general.
|
||||
|
||||
\section1 ImageViewer Class Definition
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.h 0
|
||||
|
||||
The \c ImageViewer class inherits from QMainWindow. We reimplement
|
||||
the constructor, and create several private slots to facilitate
|
||||
the menu entries. In addition we create four private functions.
|
||||
|
||||
We use \c createActions() and \c createMenus() when constructing
|
||||
the \c ImageViewer widget. We use the \c updateActions() function
|
||||
to update the menu entries when a new image is loaded, or when
|
||||
the \uicontrol {Fit to Window} option is toggled. The zoom slots use \c
|
||||
scaleImage() to perform the zooming. In turn, \c
|
||||
scaleImage() uses \c adjustScrollBar() to preserve the focal point after
|
||||
scaling an image.
|
||||
|
||||
\section1 ImageViewer Class Implementation
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 0
|
||||
|
||||
In the constructor we first create the label and the scroll area.
|
||||
|
||||
We set \c {imageLabel}'s size policy to \l
|
||||
{QSizePolicy::Ignored}{ignored}, making the users able to scale
|
||||
the image to whatever size they want when the \uicontrol {Fit to Window}
|
||||
option is turned on. Otherwise, the default size polizy (\l
|
||||
{QSizePolicy::Preferred}{preferred}) will make scroll bars appear
|
||||
when the scroll area becomes smaller than the label's minimum size
|
||||
hint.
|
||||
|
||||
We ensure that the label will scale its contents to fill all
|
||||
available space, to enable the image to scale properly when
|
||||
zooming. If we omitted to set the \c {imageLabel}'s \l
|
||||
{QLabel::scaledContents}{scaledContents} property, zooming in
|
||||
would enlarge the QLabel, but leave the pixmap at
|
||||
its original size, exposing the QLabel's background.
|
||||
|
||||
We make \c imageLabel the scroll area's child widget, and we make
|
||||
\c scrollArea the central widget of the QMainWindow. At the end
|
||||
we create the associated actions and menus, and customize the \c
|
||||
{ImageViewer}'s appearance.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 1
|
||||
|
||||
In the \c open() slot, we show a file dialog to the user. We compile
|
||||
a list of mime types for use as a filter by querying QImageReader
|
||||
for the available mime type names.
|
||||
|
||||
We show the file dialog until a valid file name is entered or
|
||||
the user cancels.
|
||||
|
||||
The function \c loadFile() is used to load the image.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 2
|
||||
|
||||
In the \c loadFile() function, we instantiate a QImageReader
|
||||
and enable automatic transformations by calling
|
||||
QImageReader::setAutoTransform(). For files in JPEG format,
|
||||
this ensures that portrait mode images of digital cameras are shown
|
||||
correctly by applying the appropriate orientation read from the
|
||||
EXIF meta data stored in the image file.
|
||||
|
||||
We then load the image using QImageReader::read(). If this returns
|
||||
a null image, indicating that the file is not an image file,
|
||||
we use a QMessageBox to alert the user.
|
||||
|
||||
The QMessageBox class provides a modal dialog with a short
|
||||
message, an icon, and some buttons. As with QFileDialog the
|
||||
easiest way to create a QMessageBox is to use its static
|
||||
convenience functions. QMessageBox provides a range of different
|
||||
messages arranged along two axes: severity (question,
|
||||
information, warning and critical) and complexity (the number of
|
||||
necessary response buttons). In this particular example an
|
||||
information message with an \uicontrol OK button (the default) is
|
||||
sufficient, since the message is part of a normal operation.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 4
|
||||
|
||||
If the format is supported, we display the image in \c imageLabel
|
||||
by setting the label's \l {QLabel::pixmap}{pixmap}. Then we enable
|
||||
the \uicontrol Print and \uicontrol {Fit to Window} menu entries and update
|
||||
the rest of the view menu entries. The \uicontrol Open and \uicontrol Exit
|
||||
entries are enabled by default.
|
||||
|
||||
If the \uicontrol {Fit to Window} option is turned off, the
|
||||
QScrollArea::widgetResizable property is \c false and it is
|
||||
our responsibility (not QScrollArea's) to give the QLabel a
|
||||
reasonable size based on its contents. We call
|
||||
\{QWidget::adjustSize()}{adjustSize()} to achieve this, which is
|
||||
essentially the same as
|
||||
|
||||
\code
|
||||
imageLabel->resize(imageLabel->pixmap()->size());
|
||||
\endcode
|
||||
|
||||
In the \c print() slot, we first make sure that an image has been
|
||||
loaded into the application:
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 5
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 6
|
||||
|
||||
If the application is built in debug mode, the \c Q_ASSERT() macro
|
||||
will expand to
|
||||
|
||||
\code
|
||||
if (imageLabel->pixmap().isNull())
|
||||
qFatal("ASSERT: "imageLabel->pixmap().isNull()" in file ...");
|
||||
\endcode
|
||||
|
||||
In release mode, the macro simply disappear. The mode can be set
|
||||
in the application's \c .pro file. One way to do so is to add an
|
||||
option to \uicontrol qmake when building the application:
|
||||
|
||||
\code
|
||||
qmake "CONFIG += debug" foo.pro
|
||||
\endcode
|
||||
|
||||
or
|
||||
|
||||
\code
|
||||
qmake "CONFIG += release" foo.pro
|
||||
\endcode
|
||||
|
||||
Another approach is to add this line directly to the \c .pro
|
||||
file.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 7
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 8
|
||||
|
||||
Then we present a print dialog allowing the user to choose a
|
||||
printer and to set a few options. We construct a painter with a
|
||||
QPrinter as the paint device. We set the painter's window
|
||||
and viewport in such a way that the image is as large as possible
|
||||
on the paper, but without altering its
|
||||
\l{Qt::KeepAspectRatio}{aspect ratio}.
|
||||
|
||||
In the end we draw the pixmap at position (0, 0).
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 9
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 10
|
||||
|
||||
We implement the zooming slots using the private \c scaleImage()
|
||||
function. We set the scaling factors to 1.25 and 0.8,
|
||||
respectively. These factor values ensure that a \uicontrol {Zoom In}
|
||||
action and a \uicontrol {Zoom Out} action will cancel each other (since
|
||||
1.25 * 0.8 == 1), and in that way the normal image size can be
|
||||
restored using the zooming features.
|
||||
|
||||
The screenshots below show an image in its normal size, and the
|
||||
same image after zooming in:
|
||||
|
||||
\table
|
||||
\row
|
||||
\li \inlineimage imageviewer-original_size.png
|
||||
\li \inlineimage imageviewer-zoom_in_1.png
|
||||
\li \inlineimage imageviewer-zoom_in_2.png
|
||||
\endtable
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 11
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 12
|
||||
|
||||
When zooming, we use the QLabel's ability to scale its contents.
|
||||
Such scaling doesn't change the actual size hint of the contents.
|
||||
And since the \l {QLabel::adjustSize()}{adjustSize()} function
|
||||
use those size hint, the only thing we need to do to restore the
|
||||
normal size of the currently displayed image is to call \c
|
||||
adjustSize() and reset the scale factor to 1.0.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 13
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 14
|
||||
|
||||
The \c fitToWindow() slot is called each time the user toggled
|
||||
the \uicontrol {Fit to Window} option. If the slot is called to turn on
|
||||
the option, we tell the scroll area to resize its child widget
|
||||
with the QScrollArea::setWidgetResizable() function. Then we
|
||||
disable the \uicontrol {Zoom In}, \uicontrol {Zoom Out} and \uicontrol {Normal
|
||||
Size} menu entries using the private \c updateActions() function.
|
||||
|
||||
If the \l {QScrollArea::widgetResizable} property is set to \c
|
||||
false (the default), the scroll area honors the size of its child
|
||||
widget. If this property is set to \c true, the scroll area will
|
||||
automatically resize the widget in order to avoid scroll bars
|
||||
where they can be avoided, or to take advantage of extra space.
|
||||
But the scroll area will honor the minimum size hint of its child
|
||||
widget independent of the widget resizable property. So in this
|
||||
example we set \c {imageLabel}'s size policy to \l
|
||||
{QSizePolicy::Ignored}{ignored} in the constructor, to avoid that
|
||||
scroll bars appear when the scroll area becomes smaller than the
|
||||
label's minimum size hint.
|
||||
|
||||
The screenshots below shows an image in its normal size, and the
|
||||
same image with the \uicontrol {Fit to window} option turned on.
|
||||
Enlarging the window will stretch the image further, as shown in
|
||||
the third screenshot.
|
||||
|
||||
\table
|
||||
\row
|
||||
\li \inlineimage imageviewer-original_size.png
|
||||
\li \inlineimage imageviewer-fit_to_window_1.png
|
||||
\li \inlineimage imageviewer-fit_to_window_2.png
|
||||
\endtable
|
||||
|
||||
If the slot is called to turn off the option, the
|
||||
{QScrollArea::setWidgetResizable} property is set to \c false. We
|
||||
also restore the image pixmap to its normal size by adjusting the
|
||||
label's size to its content. And in the end we update the view
|
||||
menu entries.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 15
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 16
|
||||
|
||||
We implement the \c about() slot to create a message box
|
||||
describing what the example is designed to show.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 17
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 18
|
||||
|
||||
In the private \c createAction() function, we create the
|
||||
actions providing the application features and populate
|
||||
a menu with them.
|
||||
|
||||
We assign a short-cut key to each action and connect them to the
|
||||
appropriate slots. We only enable the \c openAct and \c exitAct at
|
||||
the time of creation, the others are updated once an image has
|
||||
been loaded into the application. In addition we make the \c
|
||||
fitToWindowAct \l {QAction::checkable}{checkable}.
|
||||
|
||||
The QMenu class provides a menu widget for use in menu bars,
|
||||
context menus, and other popup menus. The QMenuBar class provides
|
||||
a horizontal menu bar that consists of a list of pull-down menu
|
||||
items. So we put the menus in the \c {ImageViewer}'s
|
||||
menu bar which we retrieve with the QMainWindow::menuBar()
|
||||
function.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 21
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 22
|
||||
|
||||
The private \c updateActions() function enables or disables the
|
||||
\uicontrol {Zoom In}, \uicontrol {Zoom Out} and \uicontrol {Normal Size} menu
|
||||
entries depending on whether the \uicontrol {Fit to Window} option is
|
||||
turned on or off.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 23
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 24
|
||||
|
||||
In \c scaleImage(), we use the \c factor parameter to calculate
|
||||
the new scaling factor for the displayed image, and resize \c
|
||||
imageLabel. Since we set the
|
||||
\l{QLabel::scaledContents}{scaledContents} property to \c true in
|
||||
the constructor, the call to QWidget::resize() will scale the
|
||||
image displayed in the label. We also adjust the scroll bars to
|
||||
preserve the focal point of the image.
|
||||
|
||||
At the end, if the scale factor is less than 33.3% or greater
|
||||
than 300%, we disable the respective menu entry to prevent the
|
||||
image pixmap from becoming too large, consuming too much
|
||||
resources in the window system.
|
||||
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 25
|
||||
\snippet widgets/imageviewer/imageviewer.cpp 26
|
||||
|
||||
Whenever we zoom in or out, we need to adjust the scroll bars in
|
||||
consequence. It would have been tempting to simply call
|
||||
|
||||
\code
|
||||
scrollBar->setValue(int(factor * scrollBar->value()));
|
||||
\endcode
|
||||
|
||||
but this would make the top-left corner the focal point, not the
|
||||
center. Therefore we need to take into account the scroll bar
|
||||
handle's size (the \l{QScrollBar::pageStep}{page step}).
|
||||
*/
|
@ -1,15 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/interview
|
||||
\title Interview
|
||||
\ingroup examples-itemviews
|
||||
\brief This example demonstrates the usage of the model/view framework.
|
||||
|
||||
\brief The Interview example explores the flexibility and scalability of the
|
||||
model/view framework by presenting an infinitely deep data structure using a model
|
||||
and three different types of view.
|
||||
|
||||
\image interview-demo.png
|
||||
*/
|
@ -1,19 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/puzzle
|
||||
\title Item Views Puzzle Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Puzzle example shows how to enable drag and drop with a custom model
|
||||
to allow items to be transferred between a view and another widget.
|
||||
|
||||
\image itemviewspuzzle-example.png
|
||||
|
||||
This example is an implementation of a simple jigsaw puzzle game using the
|
||||
built-in support for drag and drop provided by Qt's model/view framework.
|
||||
The \l{Drag and Drop Puzzle Example}{Drag and Drop Puzzle} example shows
|
||||
many of the same features, but takes an alternative approach that uses Qt's
|
||||
drag and drop API at the application level to handle drag and drop
|
||||
operations.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example dialogs/licensewizard
|
||||
\title License Wizard Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-dialogs
|
||||
|
||||
\brief The License Wizard example shows how to implement complex wizards in
|
||||
@ -13,7 +14,7 @@
|
||||
|
||||
Most wizards have a linear structure, with page 1 followed by
|
||||
page 2 and so on until the last page. The
|
||||
\l{dialogs/classwizard}{Class Wizard} example shows how to create
|
||||
\l{dialogs/trivialwizard}{Trivial Wizard} example shows how to create
|
||||
such wizards.
|
||||
|
||||
Some wizards are more complex in that they allow different
|
||||
@ -191,5 +192,5 @@
|
||||
option and disconnect the \c printButtonClicked() slot.
|
||||
\endlist
|
||||
|
||||
\sa QWizard, {Class Wizard Example}, {Trivial Wizard Example}
|
||||
\sa QWizard, {Trivial Wizard Example}
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/lineedits
|
||||
\title Line Edits Example
|
||||
\examplecateogry {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Line Edits example demonstrates the many ways that QLineEdit
|
||||
can be used, and shows the effects of various properties and validators
|
||||
|
@ -1,13 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example mainwindows/mainwindow
|
||||
\title Main Window
|
||||
\ingroup examples-mainwindow
|
||||
|
||||
\brief The Main Window example shows Qt's extensive support for tool bars,
|
||||
dock windows, menus, and other standard application features.
|
||||
|
||||
\image mainwindow-demo.png
|
||||
*/
|
@ -1,14 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example mainwindows/mdi
|
||||
\title MDI Example
|
||||
\ingroup examples-mainwindow
|
||||
|
||||
\brief The MDI example shows how to implement a Multiple Document Interface using Qt's
|
||||
QMdiArea class.
|
||||
|
||||
\image mdi-example.png
|
||||
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example mainwindows/menus
|
||||
\title Menus Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-mainwindow
|
||||
\ingroup examples-layout
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example widgets/movie
|
||||
\title Movie Example
|
||||
\ingroup examples-widgets
|
||||
\brief The Movie example demonstrates how to use QMovie and QLabel to
|
||||
display animations.
|
||||
|
||||
QMovie is mostly useful if one wants to play
|
||||
a simple animation without the added complexity of a multimedia
|
||||
framework to install and deploy.
|
||||
|
||||
\borderedimage movie-example.png
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example richtext/orderform
|
||||
\title Order Form Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-richtext
|
||||
\brief The Order Form example shows how to generate rich text
|
||||
documents by combining a simple template with data input by the
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/painterpaths
|
||||
\title Painter Paths Example
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief The Painter Paths example shows how painter paths can be
|
||||
used to beuild complex shapes for rendering.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example painting/pathstroke
|
||||
\title Path Stroking
|
||||
\examplecategory {Graphics & Multimedia}
|
||||
\ingroup examples-painting
|
||||
\brief The Path Stroking example shows various types of pens that
|
||||
can be used with QPainter.
|
||||
|
@ -1,231 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/pixelator
|
||||
\title Pixelator Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Pixelator example shows how delegates can be used to customize the way that
|
||||
items are rendered in standard item views.
|
||||
|
||||
\image pixelator-example.png
|
||||
|
||||
By default, QTreeView, QTableView, and QListView use a standard item delegate
|
||||
to display and edit a set of common data types that are sufficient for many
|
||||
applications. However, an application may need to represent items of data in a
|
||||
particular way, or provide support for rendering more specialized data types,
|
||||
and this often requires the use of a custom delegate.
|
||||
|
||||
In this example, we show how to use custom delegates to modify the appearance
|
||||
of standard views. To do this, we implement the following components:
|
||||
|
||||
\list
|
||||
\li A model which represents each pixel in an image as an item of data, where each
|
||||
item contains a value for the brightness of the corresponding pixel.
|
||||
\li A custom delegate that uses the information supplied by the model to represent
|
||||
each pixel as a black circle on a white background, where the radius of the
|
||||
circle corresponds to the darkness of the pixel.
|
||||
\endlist
|
||||
|
||||
This example may be useful for developers who want to implement their own table
|
||||
models or custom delegates. The process of creating custom delegates for editing
|
||||
item data is covered in the \l{Spin Box Delegate Example}{Spin Box Delegate}
|
||||
example.
|
||||
|
||||
\section1 ImageModel Class Definition
|
||||
|
||||
The \c ImageModel class is defined as follows:
|
||||
|
||||
\snippet itemviews/pixelator/imagemodel.h 0
|
||||
|
||||
Since we only require a simple, read-only table model, we only need to implement
|
||||
functions to indicate the dimensions of the image and supply data to other
|
||||
components.
|
||||
|
||||
\section1 ImageModel Class Implementation
|
||||
|
||||
The constructor is trivial:
|
||||
|
||||
\snippet itemviews/pixelator/imagemodel.cpp 0
|
||||
|
||||
The \c setImage() function sets the image that will be used by the model:
|
||||
|
||||
\snippet itemviews/pixelator/imagemodel.cpp 1
|
||||
|
||||
The QAbstractItemModel::reset() call tells the view(s) that the model
|
||||
has changed.
|
||||
|
||||
The \c rowCount() and \c columnCount() functions return the height and width of
|
||||
the image respectively:
|
||||
|
||||
\snippet itemviews/pixelator/imagemodel.cpp 2
|
||||
\snippet itemviews/pixelator/imagemodel.cpp 3
|
||||
|
||||
Since the image is a simple two-dimensional structure, the \c parent arguments
|
||||
to these functions are unused. They both simply return the relevant size from
|
||||
the underlying image object.
|
||||
|
||||
The \c data() function returns data for the item that corresponds to a given
|
||||
model index in a format that is suitable for a particular role:
|
||||
|
||||
\snippet itemviews/pixelator/imagemodel.cpp 4
|
||||
|
||||
In this implementation, we only check that the model index is valid, and that
|
||||
the role requested is the \l{Qt::ItemDataRole}{DisplayRole}. If so, the function
|
||||
returns the grayscale value of the relevant pixel in the image; otherwise, a null
|
||||
model index is returned.
|
||||
|
||||
This model can be used with QTableView to display the integer brightness values
|
||||
for the pixels in the image. However, we will implement a custom delegate to
|
||||
display this information in a more artistic way.
|
||||
|
||||
The \c headerData() function is also reimplemented:
|
||||
|
||||
\snippet itemviews/pixelator/imagemodel.cpp 5
|
||||
|
||||
We return (1, 1) as the size hint for a header item. If we
|
||||
didn't, the headers would default to a larger size, preventing
|
||||
us from displaying really small items (which can be specified
|
||||
using the \uicontrol{Pixel size} combobox).
|
||||
|
||||
\section1 PixelDelegate Class Definition
|
||||
|
||||
The \c PixelDelegate class is defined as follows:
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.h 0
|
||||
|
||||
This class provides only basic features for a delegate so, unlike the
|
||||
\l{Spin Box Delegate Example}{Spin Box Delegate} example, we subclass
|
||||
QAbstractItemDelegate instead of QItemDelegate.
|
||||
|
||||
We only need to reimplement \l{QAbstractItemDelegate::paint()}{paint()} and
|
||||
\l{QAbstractItemDelegate::sizeHint()}{sizeHint()} in this class.
|
||||
However, we also provide a delegate-specific \c setPixelSize() function so
|
||||
that we can change the delegate's behavior via the signals and slots mechanism.
|
||||
|
||||
\section1 PixelDelegate Class Implementation
|
||||
|
||||
The \c PixelDelegate constructor is used to set up a default value for
|
||||
the size of each "pixel" that it renders. The base class constructor is
|
||||
also called to ensure that the delegate is set up with a parent object,
|
||||
if one is supplied:
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 0
|
||||
|
||||
Each item is rendered by the delegate's
|
||||
\l{QAbstractItemDelegate::paint()}{paint()} function. The view calls this
|
||||
function with a ready-to-use QPainter object, style information that the
|
||||
delegate should use to correctly draw the item, and an index to the item in
|
||||
the model:
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 1
|
||||
|
||||
The first task the delegate has to perform is to draw the item's background
|
||||
correctly. Usually, selected items appear differently to non-selected items,
|
||||
so we begin by testing the state passed in the style option and filling the
|
||||
background if necessary.
|
||||
|
||||
The radius of each circle is calculated in the following lines of code:
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 3
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 4
|
||||
|
||||
First, the largest possible radius of the circle is determined by taking the
|
||||
smallest dimension of the style option's \c rect attribute.
|
||||
Using the model index supplied, we obtain a value for the brightness of the
|
||||
relevant pixel in the image. The radius of the circle is calculated by
|
||||
scaling the brightness to fit within the item and subtracting it from the
|
||||
largest possible radius.
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 5
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 6
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 7
|
||||
|
||||
We save the painter's state, turn on antialiasing (to obtain smoother
|
||||
curves), and turn off the pen.
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 8
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 9
|
||||
|
||||
The foreground of the item (the circle representing a pixel) must be
|
||||
rendered using an appropriate brush. For unselected items, we will use a
|
||||
solid black brush; selected items are drawn using a predefined brush from
|
||||
the style option's palette.
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 10
|
||||
|
||||
Finally, we paint the circle within the rectangle specified by the style
|
||||
option and we call \l{QPainter::}{restore()} on the painter.
|
||||
|
||||
The \c paint() function does not have to be particularly complicated; it is
|
||||
only necessary to ensure that the state of the painter when the function
|
||||
returns is the same as it was when it was called. This usually
|
||||
means that any transformations applied to the painter must be preceded by
|
||||
a call to QPainter::save() and followed by a call to QPainter::restore().
|
||||
|
||||
The delegate's \l{QAbstractItemDelegate::}{sizeHint()} function
|
||||
returns a size for the item based on the predefined pixel size, initially set
|
||||
up in the constructor:
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 11
|
||||
|
||||
The delegate's size is updated whenever the pixel size is changed.
|
||||
We provide a custom slot to do this:
|
||||
|
||||
\snippet itemviews/pixelator/pixeldelegate.cpp 12
|
||||
|
||||
\section1 Using The Custom Delegate
|
||||
|
||||
In this example, we use a main window to display a table of data, using the
|
||||
custom delegate to render each cell in a particular way. Much of the
|
||||
\c MainWindow class performs tasks that are not related to item views. Here,
|
||||
we only quote the parts that are relevant. You can look at the rest of the
|
||||
implementation by following the links to the code at the top of this
|
||||
document.
|
||||
|
||||
In the constructor, we set up a table view, turn off its grid, and hide its
|
||||
headers:
|
||||
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 0
|
||||
\dots
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 1
|
||||
|
||||
This enables the items to be drawn without any gaps between them. Removing
|
||||
the headers also prevents the user from adjusting the sizes of individual
|
||||
rows and columns.
|
||||
|
||||
We also set the minimum section size to 1 on the headers. If we
|
||||
didn't, the headers would default to a larger size, preventing
|
||||
us from displaying really small items (which can be specified
|
||||
using the \uicontrol{Pixel size} combobox).
|
||||
|
||||
The custom delegate is constructed with the main window as its parent, so
|
||||
that it will be deleted correctly later, and we set it on the table view.
|
||||
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 2
|
||||
|
||||
Each item in the table view will be rendered by the \c PixelDelegate
|
||||
instance.
|
||||
|
||||
We construct a spin box to allow the user to change the size of each "pixel"
|
||||
drawn by the delegate:
|
||||
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 3
|
||||
|
||||
This spin box is connected to the custom slot we implemented in the
|
||||
\c PixelDelegate class. This ensures that the delegate always draws each
|
||||
pixel at the currently specified size:
|
||||
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 4
|
||||
\dots
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 5
|
||||
|
||||
We also connect the spin box to a slot in the \c MainWindow class. This
|
||||
forces the view to take into account the new size hints for each item;
|
||||
these are provided by the delegate in its \c sizeHint() function.
|
||||
|
||||
\snippet itemviews/pixelator/mainwindow.cpp 6
|
||||
|
||||
We explicitly resize the columns and rows to match the
|
||||
\uicontrol{Pixel size} combobox.
|
||||
*/
|
@ -1,527 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example tools/plugandpaint/app
|
||||
\title Plug & Paint Example
|
||||
\ingroup examples-widgets-tools
|
||||
|
||||
\brief Demonstrates how to extend Qt applications using plugins.
|
||||
|
||||
\image plugandpaint.png Screenshot of the Plug & Paint example
|
||||
|
||||
A plugin is a dynamic library that can be loaded at run-time to
|
||||
extend an application. Qt makes it possible to create custom
|
||||
plugins and to load them using QPluginLoader. To ensure that
|
||||
plugins don't get lost, it is also possible to link them
|
||||
statically to the executable. The Plug & Paint example uses
|
||||
plugins to support custom brushes, shapes, and image filters. A
|
||||
single plugin can provide multiple brushes, shapes, and/or
|
||||
filters.
|
||||
|
||||
If you want to learn how to make your own application extensible
|
||||
through plugins, we recommend that you start by reading this
|
||||
overview, which explains how to make an application use plugins.
|
||||
Afterwards, you can read the
|
||||
\l{tools/plugandpaint/plugins/basictools}{Basic Tools} and
|
||||
\l{tools/plugandpaint/plugins/extrafilters}{Extra Filters}
|
||||
overviews, which show how to implement static and dynamic
|
||||
plugins, respectively.
|
||||
|
||||
Plug & Paint consists of the following classes:
|
||||
|
||||
\list
|
||||
\li \c MainWindow is a QMainWindow subclass that provides the menu
|
||||
system and that contains a \c PaintArea as the central widget.
|
||||
\li \c PaintArea is a QWidget that allows the user to draw using a
|
||||
brush and to insert shapes.
|
||||
\li \c PluginDialog is a dialog that shows information about the
|
||||
plugins detected by the application.
|
||||
\li \c BrushInterface, \c ShapeInterface, and \c FilterInterface are
|
||||
abstract base classes that can be implemented by plugins to
|
||||
provide custom brushes, shapes, and image filters.
|
||||
\endlist
|
||||
|
||||
\section1 The Plugin Interfaces
|
||||
|
||||
We will start by reviewing the interfaces defined in \c
|
||||
interfaces.h. These interfaces are used by the Plug & Paint
|
||||
application to access extra functionality. They are implemented
|
||||
in the plugins.
|
||||
|
||||
|
||||
\snippet tools/plugandpaint/app/interfaces.h 0
|
||||
|
||||
The \c BrushInterface class declares four pure virtual functions.
|
||||
The first pure virtual function, \c brushes(), returns a list of
|
||||
strings that identify the brushes provided by the plugin. By
|
||||
returning a QStringList instead of a QString, we make it possible
|
||||
for a single plugin to provide multiple brushes. The other
|
||||
functions have a \c brush parameter to identify which brush
|
||||
(among those returned by \c brushes()) is used.
|
||||
|
||||
\c mousePress(), \c mouseMove(), and \c mouseRelease() take a
|
||||
QPainter and one or two \l{QPoint}s, and return a QRect
|
||||
identifying which portion of the image was altered by the brush.
|
||||
|
||||
The class also has a virtual destructor. Interface classes
|
||||
usually don't need such a destructor (because it would make
|
||||
little sense to \c delete the object that implements the
|
||||
interface through a pointer to the interface), but some compilers
|
||||
emit a warning for classes that declare virtual functions but no
|
||||
virtual destructor. We provide the destructor to keep these
|
||||
compilers happy.
|
||||
|
||||
\snippet tools/plugandpaint/app/interfaces.h 1
|
||||
|
||||
The \c ShapeInterface class declares a \c shapes() function that
|
||||
works the same as \c{BrushInterface}'s \c brushes() function, and
|
||||
a \c generateShape() function that has a \c shape parameter.
|
||||
Shapes are represented by a QPainterPath, a data type that can
|
||||
represent arbitrary 2D shapes or combinations of shapes. The \c
|
||||
parent parameter can be used by the plugin to pop up a dialog
|
||||
asking the user to specify more information.
|
||||
|
||||
\snippet tools/plugandpaint/app/interfaces.h 2
|
||||
|
||||
The \c FilterInterface class declares a \c filters() function
|
||||
that returns a list of filter names, and a \c filterImage()
|
||||
function that applies a filter to an image.
|
||||
|
||||
\snippet tools/plugandpaint/app/interfaces.h 4
|
||||
|
||||
To make it possible to query at run-time whether a plugin
|
||||
implements a given interface, we must use the \c
|
||||
Q_DECLARE_INTERFACE() macro. The first argument is the name of
|
||||
the interface. The second argument is a string identifying the
|
||||
interface in a unique way. By convention, we use a "Java package
|
||||
name" syntax to identify interfaces. If we later change the
|
||||
interfaces, we must use a different string to identify the new
|
||||
interface; otherwise, the application might crash. It is therefore
|
||||
a good idea to include a version number in the string, as we did
|
||||
above.
|
||||
|
||||
The \l{tools/plugandpaint/plugins/basictools}{Basic Tools} plugin
|
||||
and the \l{tools/plugandpaint/plugins/extrafilters}{Extra Filters}
|
||||
plugin shows how to derive from \c BrushInterface, \c
|
||||
ShapeInterface, and \c FilterInterface.
|
||||
|
||||
A note on naming: It might have been tempting to give the \c
|
||||
brushes(), \c shapes(), and \c filters() functions a more generic
|
||||
name, such as \c keys() or \c features(). However, that would
|
||||
have made multiple inheritance impractical. When creating
|
||||
interfaces, we should always try to give unique names to the pure
|
||||
virtual functions.
|
||||
|
||||
\section1 The MainWindow Class
|
||||
|
||||
The \c MainWindow class is a standard QMainWindow subclass, as
|
||||
found in many of the other examples (e.g.,
|
||||
\l{mainwindows/application}{Application}). Here, we'll
|
||||
concentrate on the parts of the code that are related to plugins.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 4
|
||||
|
||||
The \c loadPlugins() function is called from the \c MainWindow
|
||||
constructor to detect plugins and update the \uicontrol{Brush},
|
||||
\uicontrol{Shapes}, and \uicontrol{Filters} menus. We start by handling static
|
||||
plugins (available through QPluginLoader::staticInstances())
|
||||
|
||||
To the application that uses the plugin, a Qt plugin is simply a
|
||||
QObject. That QObject implements plugin interfaces using multiple
|
||||
inheritance.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 5
|
||||
|
||||
The next step is to load dynamic plugins. We initialize the \c
|
||||
pluginsDir member variable to refer to the \c plugins
|
||||
subdirectory of the Plug & Paint example. On Unix, this is just a
|
||||
matter of initializing the QDir variable with
|
||||
QApplication::applicationDirPath(), the path of the executable
|
||||
file, and to do a \l{QDir::cd()}{cd()}. On Windows and \macos,
|
||||
this file is usually located in a subdirectory, so we need to
|
||||
take this into account.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 6
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 7
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 8
|
||||
|
||||
We use QDir::entryList() to get a list of all files in that
|
||||
directory. Then we iterate over the result using a range-based for loop
|
||||
and try to load the plugin using QPluginLoader.
|
||||
|
||||
The QObject provided by the plugin is accessible through
|
||||
QPluginLoader::instance(). If the dynamic library isn't a Qt
|
||||
plugin, or if it was compiled against an incompatible version of
|
||||
the Qt library, QPluginLoader::instance() returns a null pointer.
|
||||
|
||||
If QPluginLoader::instance() is non-null, we add it to the menus.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 9
|
||||
|
||||
At the end, we enable or disable the \uicontrol{Brush}, \uicontrol{Shapes},
|
||||
and \uicontrol{Filters} menus based on whether they contain any items.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 10
|
||||
|
||||
For each plugin (static or dynamic), we check which interfaces it
|
||||
implements using \l qobject_cast(). First, we try to cast the
|
||||
plugin instance to a \c BrushInterface; if it works, we call the
|
||||
private function \c addToMenu() with the list of brushes returned
|
||||
by \c brushes(). Then we do the same with the \c ShapeInterface
|
||||
and the \c FilterInterface.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 3
|
||||
|
||||
The \c aboutPlugins() slot is called on startup and can be
|
||||
invoked at any time through the \uicontrol{About Plugins} action. It
|
||||
pops up a \c PluginDialog, providing information about the loaded
|
||||
plugins.
|
||||
|
||||
\image plugandpaint-plugindialog.png Screenshot of the Plugin dialog
|
||||
|
||||
|
||||
The \c addToMenu() function is called from \c loadPlugin() to
|
||||
create \l{QAction}s for custom brushes, shapes, or filters and
|
||||
add them to the relevant menu. The QAction is created with the
|
||||
plugin from which it comes from as the parent; this makes it
|
||||
convenient to get access to the plugin later.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 0
|
||||
|
||||
The \c changeBrush() slot is invoked when the user chooses one of
|
||||
the brushes from the \uicontrol{Brush} menu. We start by finding out
|
||||
which action invoked the slot using QObject::sender(). Then we
|
||||
get the \c BrushInterface out of the plugin (which we
|
||||
conveniently passed as the QAction's parent) and we call \c
|
||||
PaintArea::setBrush() with the \c BrushInterface and the string
|
||||
identifying the brush. Next time the user draws on the paint
|
||||
area, \c PaintArea will use this brush.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 1
|
||||
|
||||
The \c insertShape() is invoked when the use chooses one of the
|
||||
shapes from the \uicontrol{Shapes} menu. We retrieve the QAction that
|
||||
invoked the slot, then the \c ShapeInterface associated with that
|
||||
QAction, and finally we call \c ShapeInterface::generateShape()
|
||||
to obtain a QPainterPath.
|
||||
|
||||
\snippet tools/plugandpaint/app/mainwindow.cpp 2
|
||||
|
||||
The \c applyFilter() slot is similar: We retrieve the QAction
|
||||
that invoked the slot, then the \c FilterInterface associated to
|
||||
that QAction, and finally we call \c
|
||||
FilterInterface::filterImage() to apply the filter onto the
|
||||
current image.
|
||||
|
||||
\section1 The PaintArea Class
|
||||
|
||||
The \c PaintArea class contains some code that deals with \c
|
||||
BrushInterface, so we'll review it briefly.
|
||||
|
||||
\snippet tools/plugandpaint/app/paintarea.cpp 0
|
||||
|
||||
In \c setBrush(), we simply store the \c BrushInterface and the
|
||||
brush that are given to us by \c MainWindow.
|
||||
|
||||
\snippet tools/plugandpaint/app/paintarea.cpp 1
|
||||
|
||||
In the \l{QWidget::mouseMoveEvent()}{mouse move event handler},
|
||||
we call the \c BrushInterface::mouseMove() function on the
|
||||
current \c BrushInterface, with the current brush. The mouse
|
||||
press and mouse release handlers are very similar.
|
||||
|
||||
\section1 The PluginDialog Class
|
||||
|
||||
The \c PluginDialog class provides information about the loaded
|
||||
plugins to the user. Its constructor takes a path to the plugins
|
||||
and a list of plugin file names. It calls \c findPlugins()
|
||||
to fill the QTreeWdiget with information about the plugins:
|
||||
|
||||
\snippet tools/plugandpaint/app/plugindialog.cpp 0
|
||||
|
||||
The \c findPlugins() is very similar to \c
|
||||
MainWindow::loadPlugins(). It uses QPluginLoader to access the
|
||||
static and dynamic plugins. Its helper function \c
|
||||
populateTreeWidget() uses \l qobject_cast() to find out which
|
||||
interfaces are implemented by the plugins:
|
||||
|
||||
\snippet tools/plugandpaint/app/plugindialog.cpp 1
|
||||
|
||||
\section1 Importing Static Plugins
|
||||
|
||||
The \l{tools/plugandpaint/plugins/basictools}{Basic Tools} plugin
|
||||
is built as a static plugin, to ensure that it is always
|
||||
available to the application. This requires using the
|
||||
Q_IMPORT_PLUGIN() macro somewhere in the application (in a \c
|
||||
.cpp file) and specifying the plugin in the \c .pro file.
|
||||
|
||||
For Plug & Paint, we have chosen to put Q_IMPORT_PLUGIN() in \c
|
||||
main.cpp:
|
||||
|
||||
\snippet tools/plugandpaint/app/main.cpp 0
|
||||
|
||||
The argument to Q_IMPORT_PLUGIN() is the plugin name, which corresponds
|
||||
with the name of the class that declares metadata for the plugin with
|
||||
Q_PLUGIN_METADATA().
|
||||
|
||||
In the \c .pro file, we need to specify the static library.
|
||||
Here's the project file for building Plug & Paint:
|
||||
|
||||
\snippet tools/plugandpaint/app/app.pro 0
|
||||
|
||||
The \c LIBS line variable specifies the library \c pnp_basictools
|
||||
located in the \c ../plugandpaint/plugins/basictools directory.
|
||||
(Although the \c LIBS syntax has a distinct Unix flavor, \c qmake
|
||||
supports it on all platforms.)
|
||||
|
||||
The \c CONFIG() code at the end is necessary for this example
|
||||
because the example is part of the Qt distribution and Qt can be
|
||||
configured to be built simultaneously in debug and in release
|
||||
modes. You don't need to for your own plugin applications.
|
||||
|
||||
This completes our review of the Plug & Paint application. At
|
||||
this point, you might want to take a look at the
|
||||
\l{tools/plugandpaint/plugins/basictools}{Basic Tools} example
|
||||
plugin.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tools/plugandpaint/plugins/basictools
|
||||
\title Plug & Paint Basic Tools Example
|
||||
\brief A plugin providing the basic tools for painting functionality.
|
||||
|
||||
\image plugandpaint.png Screenshot of the Plug & Paint example
|
||||
|
||||
The Basic Tools example is a static plugin for the
|
||||
\l{tools/plugandpaint/app}{Plug & Paint} example. It provides a set
|
||||
of basic brushes, shapes, and filters. Through the Basic Tools
|
||||
example, we will review the four steps involved in writing a Qt
|
||||
plugin:
|
||||
|
||||
\list 1
|
||||
\li Declare a plugin class.
|
||||
\li Implement the interfaces provided by the plugin.
|
||||
\li Export the plugin using the Q_PLUGIN_METADATA() macro.
|
||||
\li Build the plugin using an adequate \c .pro file.
|
||||
\endlist
|
||||
|
||||
\section1 Declaration of the Plugin Class
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.h 0
|
||||
|
||||
We start by including \c interfaces.h, which defines the plugin
|
||||
interfaces for the \l{tools/plugandpaint/app}{Plug & Paint}
|
||||
application. For the \c #include to work, we need to add an \c
|
||||
INCLUDEPATH entry to the \c .pro file with the path to the
|
||||
header file.
|
||||
|
||||
The \c BasicToolsPlugin class is a QObject subclass that
|
||||
implements the \c BrushInterface, the \c ShapeInterface, and the
|
||||
\c FilterInterface. This is done through multiple inheritance.
|
||||
The \c Q_INTERFACES() macro is necessary to tell \l{moc}, Qt's
|
||||
meta-object compiler, that the base classes are plugin
|
||||
interfaces. Without the \c Q_INTERFACES() macro, we couldn't use
|
||||
\l qobject_cast() in the \l{tools/plugandpaint/app}{Plug & Paint}
|
||||
application to detect interfaces.
|
||||
For an explanation for the \c Q_PLUGIN_METADATA() macro see
|
||||
\l {Exporting the Plugin}.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.h 2
|
||||
|
||||
In the \c public section of the class, we declare all the
|
||||
functions from the three interfaces.
|
||||
|
||||
\section1 Implementation of the Brush Interface
|
||||
|
||||
Let's now review the implementation of the \c BasicToolsPlugin
|
||||
member functions inherited from \c BrushInterface.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 0
|
||||
|
||||
The \c brushes() function returns a list of brushes provided by
|
||||
this plugin. We provide three brushes: \uicontrol{Pencil}, \uicontrol{Air
|
||||
Brush}, and \uicontrol{Random Letters}.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 1
|
||||
|
||||
On a mouse press event, we just call \c mouseMove() to draw the
|
||||
spot where the event occurred.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 2
|
||||
|
||||
In \c mouseMove(), we start by saving the state of the QPainter
|
||||
and we compute a few variables that we'll need later.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 3
|
||||
|
||||
Then comes the brush-dependent part of the code:
|
||||
|
||||
\list
|
||||
\li If the brush is \uicontrol{Pencil}, we just call
|
||||
QPainter::drawLine() with the current QPen.
|
||||
|
||||
\li If the brush is \uicontrol{Air Brush}, we start by setting the
|
||||
painter's QBrush to Qt::Dense6Pattern to obtain a dotted
|
||||
pattern. Then we draw a circle filled with that QBrush several
|
||||
times, resulting in a thick line.
|
||||
|
||||
\li If the brush is \uicontrol{Random Letters}, we draw a random letter
|
||||
at the new cursor position. Most of the code is for setting
|
||||
the font to be bold and larger than the default font and for
|
||||
computing an appropriate bounding rect.
|
||||
\endlist
|
||||
|
||||
At the end, we restore the painter state to what it was upon
|
||||
entering the function and we return the bounding rectangle.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 4
|
||||
|
||||
When the user releases the mouse, we do nothing and return an
|
||||
empty QRect.
|
||||
|
||||
\section1 Implementation of the Shape Interface
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 5
|
||||
|
||||
The plugin provides three shapes: \uicontrol{Circle}, \uicontrol{Star}, and
|
||||
\uicontrol{Text...}. The three dots after \uicontrol{Text} are there because
|
||||
the shape pops up a dialog asking for more information. We know
|
||||
that the shape names will end up in a menu, so we include the
|
||||
three dots in the shape name.
|
||||
|
||||
A cleaner but more complicated design would have been to
|
||||
distinguish between the internal shape name and the name used in
|
||||
the user interface.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 6
|
||||
|
||||
The \c generateShape() creates a QPainterPath for the specified
|
||||
shape. If the shape is \uicontrol{Text}, we pop up a QInputDialog to
|
||||
let the user enter some text.
|
||||
|
||||
\section1 Implementation of the Filter Interface
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 7
|
||||
|
||||
The plugin provides three filters: \uicontrol{Invert Pixels}, \uicontrol{Swap
|
||||
RGB}, and \uicontrol{Grayscale}.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp 8
|
||||
|
||||
The \c filterImage() function takes a filter name and a QImage as
|
||||
parameters and returns an altered QImage. The first thing we do
|
||||
is to convert the image to a 32-bit RGB format, to ensure that
|
||||
the algorithms will work as expected. For example,
|
||||
QImage::invertPixels(), which is used to implement the
|
||||
\uicontrol{Invert Pixels} filter, gives counterintuitive results for
|
||||
8-bit images, because they invert the indices into the color
|
||||
table instead of inverting the color table's entries.
|
||||
|
||||
\section1 Exporting the Plugin
|
||||
|
||||
To finally export your plugin you just have to add the
|
||||
\c Q_PLUGIN_METADATA() macro right next to the \c Q_OBJECT() macro
|
||||
into the header file of the plugin.
|
||||
It must contain the plugins IID and optionally a filename pointing
|
||||
to a json file containing the metadata for the plugin.
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictoolsplugin.h 4
|
||||
|
||||
Within this example the json file does not need to export any metadata,
|
||||
so it just contains an empty json object.
|
||||
|
||||
\code
|
||||
{}
|
||||
\endcode
|
||||
|
||||
\section1 The .pro File
|
||||
|
||||
Here's the project file for building the Basic Tools plugin:
|
||||
|
||||
\snippet tools/plugandpaint/plugins/basictools/basictools.pro 0
|
||||
|
||||
The \c .pro file differs from typical \c .pro files in many
|
||||
respects. First, it starts with a \c TEMPLATE entry specifying \c
|
||||
lib. (The default template is \c app.) It also adds \c plugin to
|
||||
the \c CONFIG variable. This is necessary on some platforms to
|
||||
avoid generating symbolic links with version numbers in the file
|
||||
name, which is appropriate for most dynamic libraries but not for
|
||||
plugins.
|
||||
|
||||
To make the plugin a static plugin, all that is required is to
|
||||
specify \c static in addition to \c plugin. The
|
||||
\l{tools/plugandpaint/plugins/extrafilters}{Extra Filters} plugin,
|
||||
which is compiled as a dynamic plugin, doesn't specify \c static
|
||||
in its \c .pro file.
|
||||
|
||||
The \c INCLUDEPATH variable sets the search paths for global
|
||||
headers (i.e., header files included using \c{#include <...>}).
|
||||
We add \c ../../app to the list, so that we can include
|
||||
\c <interfaces.h>.
|
||||
|
||||
The \c TARGET variable specifies which name we want to give the
|
||||
target library. We use \c pnp_ as the prefix to show that the
|
||||
plugin is designed to work with Plug & Paint. On Unix, \c lib is
|
||||
also prepended to that name. On all platforms, a
|
||||
platform-specific suffix is appended (e.g., \c .dll on Windows,
|
||||
\c .a on Linux).
|
||||
|
||||
The \c CONFIG() code at the end is necessary for this example
|
||||
because the example is part of the Qt distribution and Qt can be
|
||||
configured to be built simultaneously in debug and in release
|
||||
modes. You don't need to for your own plugins.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example tools/plugandpaint/plugins/extrafilters
|
||||
\title Plug & Paint Extra Filters Example
|
||||
\brief A plugin providing the extra filters.
|
||||
|
||||
\image plugandpaint.png Screenshot of the Plug & Paint example
|
||||
|
||||
The Extra Filters example is a plugin for the
|
||||
\l{tools/plugandpaint/app}{Plug & Paint} example. It provides a set
|
||||
of filters in addition to those provided by the
|
||||
\l{tools/plugandpaint/plugins/basictools}{Basic Tools} plugin.
|
||||
|
||||
Since the approach is identical to
|
||||
\l{tools/plugandpaint/plugins/basictools}{Basic Tools}, we won't
|
||||
review the code here. The only part of interest is the
|
||||
\c .pro file, since Extra Filters is a dynamic plugin
|
||||
(\l{tools/plugandpaint/plugins/basictools}{Basic Tools} is
|
||||
linked statically into the Plug & Paint executable).
|
||||
|
||||
Here's the project file for building the Extra Filters plugin:
|
||||
|
||||
\snippet tools/plugandpaint/plugins/extrafilters/extrafilters.pro 0
|
||||
|
||||
The \c .pro file differs from typical \c .pro files in many
|
||||
respects. First, it starts with a \c TEMPLATE entry specifying \c
|
||||
lib. (The default template is \c app.) It also adds \c plugin to
|
||||
the \c CONFIG variable. This is necessary on some platforms to
|
||||
avoid generating symbolic links with version numbers in the file
|
||||
name, which is appropriate for most dynamic libraries but not for
|
||||
plugins.
|
||||
|
||||
The \c INCLUDEPATH variable sets the search paths for global
|
||||
headers (i.e., header files included using \c{#include <...>}).
|
||||
We add \c ../../app to the list, so that we can include
|
||||
\c <interfaces.h>.
|
||||
|
||||
The \c TARGET variable specifies which name we want to give the
|
||||
target library. We use \c pnp_ as the prefix to show that the
|
||||
plugin is designed to work with Plug & Paint. On Unix, \c lib is
|
||||
also prepended to that name. On all platforms, a
|
||||
platform-specific suffix is appended (e.g., \c .dll on Windows,
|
||||
\c .so on Linux).
|
||||
|
||||
The \c DESTDIR variable specifies where we want to install the
|
||||
plugin. We put it in Plug & Paint's \c plugins subdirectory,
|
||||
since that's where the application looks for dynamic plugins.
|
||||
|
||||
The \c CONFIG() code at the end is necessary for this example
|
||||
because the example is part of the Qt distribution and Qt can be
|
||||
configured to be built simultaneously in debug and in release
|
||||
modes. You don't need to for your own plugins.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example tools/regularexpression
|
||||
\title QRegularExpression Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets-tools
|
||||
|
||||
\brief The QRegularExpression example shows how regular expressions in Qt are
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
/*!
|
||||
\example desktop/screenshot
|
||||
\title Screenshot Example
|
||||
\title Taking a Screenshot
|
||||
\examplecategory {Desktop}
|
||||
\ingroup examples-desktop
|
||||
\brief The Screenshot example shows how to take a screenshot of the
|
||||
desktop.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/scribble
|
||||
\title Scribble Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Scribble example shows how to reimplement some of QWidget's
|
||||
event handlers to receive the events generated for the
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example tools/settingseditor
|
||||
\title Settings Editor Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets-tools
|
||||
|
||||
\brief The Settings Editor example shows how Qt's standard settings support is used in an
|
||||
|
@ -3,17 +3,19 @@
|
||||
|
||||
/*!
|
||||
\example widgets/shapedclock
|
||||
\title Shaped Clock Example
|
||||
\title Translucent Background
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Shaped Clock example shows how to apply a translucent background
|
||||
and a widget mask to a top-level widget to produce a shaped window.
|
||||
\brief The example shows how to make a round window with a translucent
|
||||
background.
|
||||
|
||||
\borderedimage shapedclock-example.png
|
||||
|
||||
Widget masks are used to customize the shapes of top-level widgets by
|
||||
restricting the area available for painting and mouse input. Using a
|
||||
translucent background facilitates partially transparent windows and smooth
|
||||
edges. On most window systems, setting certain window flags will cause the
|
||||
Widgets that set their background to be translucent will be transparent for all
|
||||
unpainted pixels, and the background will shine through pixels painted with an
|
||||
opacity of less than 100%. Pixels that are not painted at all will also not
|
||||
receive any mouse input. This can be used to customize the shapes of top-level
|
||||
widgets. On most window systems, setting certain window flags will cause the
|
||||
window decoration (title bar, window frame, buttons) to be disabled,
|
||||
allowing specially-shaped windows to be created. In this example, we use
|
||||
this feature to create a circular window containing an analog clock.
|
||||
@ -30,12 +32,10 @@
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.h 0
|
||||
|
||||
The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as
|
||||
that found in the \c AnalogClock class, with one important exception: we
|
||||
now must also draw background (the clock face) ourselves, since the widget
|
||||
background is just transparent. We implement \l{QWidget::sizeHint()}{sizeHint()}
|
||||
so that we don't have to resize the widget explicitly. We also provide an event
|
||||
handler for resize events. This allows us to update the mask if the clock is resized.
|
||||
The \l{QWidget::paintEvent()}{paintEvent()} implementation draws an analog clock
|
||||
on a semi-transparent background (the clock face). In addition, we implement
|
||||
\l{QWidget::sizeHint()}{sizeHint()} so that we don't have to resize the widget
|
||||
explicitly.
|
||||
|
||||
Since the window containing the clock widget will have no title bar, we provide
|
||||
implementations for \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} and
|
||||
@ -45,8 +45,9 @@
|
||||
|
||||
\section1 ShapedClock Class Implementation
|
||||
|
||||
The \c ShapedClock constructor performs many of the same tasks as the \c AnalogClock
|
||||
constructor. We set up a timer and connect it to the widget's update() slot:
|
||||
The \c ShapedClock constructor sets up a timer and connect it to the widget's
|
||||
update() slot. In addition, we add an action to the widget, which will automatically
|
||||
become available through a context menu when right-clicking on the widget.
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 0
|
||||
|
||||
@ -77,49 +78,14 @@
|
||||
cursor position in global coordinates. If we drag the widget, we also accept the event.
|
||||
|
||||
The \c paintEvent() function is mainly the same as described in the
|
||||
\l{Analog Clock} example. The one addition is that we
|
||||
use QPainter::drawEllipse() to draw a round clock face with the current
|
||||
palette's default background color. We make the clock face a bit smaller
|
||||
than the widget mask, so that the anti-aliased, semi-transparent pixels on
|
||||
the edge are not clipped away by the widget mask. This gives the shaped
|
||||
window smooth edges on the screen.
|
||||
\l{Analog Clock} example. The one addition is that we use QPainter::drawEllipse() to
|
||||
draw a round clock face. We reduce the painter's opacity to 90%, and use the palette's
|
||||
default background color.
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 3
|
||||
|
||||
In the \c resizeEvent() handler, we re-use some of the code from the \c
|
||||
paintEvent() to determine the region of the widget that is visible to the
|
||||
user. This tells the system the area where mouse clicks should go to us,
|
||||
and not to whatever window is behind us:
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 4
|
||||
|
||||
Since the clock face is a circle drawn in the center of the widget, this is the region
|
||||
we use as the mask.
|
||||
|
||||
Although the lack of a window frame may make it difficult for the user to resize the
|
||||
widget on some platforms, it will not necessarily be impossible. The \c resizeEvent()
|
||||
function ensures that the widget mask will always be updated if the widget's dimensions
|
||||
change, and additionally ensures that it will be set up correctly when the widget is
|
||||
first displayed.
|
||||
|
||||
Finally, we implement the \c sizeHint() for the widget so that it is given a reasonable
|
||||
default size when it is first shown:
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 5
|
||||
|
||||
\section1 Notes on Widget Masks
|
||||
|
||||
Widget masks are used to hint to the window system that the application
|
||||
does not want mouse events for areas outside the mask. On most systems,
|
||||
they also result in coarse visual clipping. To get smooth window edges, one
|
||||
should use translucent background and anti-aliased painting, as shown in
|
||||
this example.
|
||||
|
||||
Since QRegion allows arbitrarily complex regions to be created, widget masks can be
|
||||
made to suit the most unconventionally-shaped windows, and even allow widgets to be
|
||||
displayed with holes in them.
|
||||
|
||||
Widget masks can also be constructed by using the contents of pixmap to define the
|
||||
opaque part of the widget. For a pixmap with an alpha channel, a suitable mask can be
|
||||
obtained with QPixmap::mask().
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 4
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/shortcuteditor
|
||||
\title Shortcut Editor Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Shortcut Editor example shows how to create a basic, read-write
|
||||
hierarchical model to use with Qt's standard view and QKeySequenceEdit
|
||||
|
@ -1,256 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/simpledommodel
|
||||
\title Simple DOM Model Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Simple DOM Model example shows how an existing class can be adapted for use with
|
||||
the model/view framework.
|
||||
|
||||
\image simpledommodel-example.png
|
||||
|
||||
Qt provides two complementary sets of classes for reading XML files: The classes based
|
||||
around QXmlReader provide a SAX-style API for incremental reading of large files, and
|
||||
the classes based around QDomDocument enable developers to access the contents of XML
|
||||
files using a Document Object Model (DOM) API.
|
||||
|
||||
In this example, we create a model that uses the DOM API to expose the structure and
|
||||
contents of XML documents to views via the standard QAbstractModel interface.
|
||||
|
||||
\section1 Design and Concepts
|
||||
|
||||
Reading an XML document with Qt's DOM classes is a straightforward process. Typically,
|
||||
the contents of a file are supplied to QDomDocument, and nodes are accessed using the
|
||||
functions provided by QDomNode and its subclasses.
|
||||
|
||||
\omit
|
||||
For example, the following code
|
||||
snippet reads the contents of a file into a QDomDocument object and traverses the
|
||||
document, reading all the plain text that can be found:
|
||||
|
||||
\snippet doc/src/snippets/code/doc_src_examples_simpledommodel.cpp 0
|
||||
|
||||
In principle, the functions provided by QDomNode can be used to navigate from any
|
||||
given starting point in a document to the piece of data requested by another component.
|
||||
Since QDomDocument maintains information about the structure of a document, we can
|
||||
use this to implement the required virtual functions in a QAbstractItemModel subclass.
|
||||
\endomit
|
||||
|
||||
The aim is to use the structure provided by QDomDocument by wrapping QDomNode objects
|
||||
in item objects similar to the \c TreeItem objects used in the
|
||||
\l{Simple Tree Model Example}{Simple Tree Model} example.
|
||||
|
||||
\section1 DomModel Class Definition
|
||||
|
||||
Let us begin by examining the \c DomModel class:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.h 0
|
||||
|
||||
The class definition contains all the basic functions that are needed for a
|
||||
read-only model. Only the constructor and \c document() function are specific to
|
||||
this model. The private \c domDocument variable is used to hold the document
|
||||
that is exposed by the model; the \c rootItem variable contains a pointer to
|
||||
the root item in the model.
|
||||
|
||||
\section1 DomItem Class Definition
|
||||
|
||||
The \c DomItem class is used to hold information about a specific QDomNode in
|
||||
the document:
|
||||
|
||||
\snippet itemviews/simpledommodel/domitem.h 0
|
||||
|
||||
Each \c DomItem provides a wrapper for a QDomNode obtained from the underlying
|
||||
document which contains a reference to the node, it's location in the parent node's
|
||||
list of child nodes, and a pointer to a parent wrapper item.
|
||||
|
||||
The \c parent(), \c child(), and \c row() functions are convenience functions for
|
||||
the \c DomModel to use that provide basic information about the item to be discovered
|
||||
quickly. The node() function provides access to the underlying QDomNode object.
|
||||
|
||||
As well as the information supplied in the constructor, the class maintains a cache
|
||||
of information about any child items. This is used to provide a collection of
|
||||
persistent item objects that the model can identify consistently and improve the
|
||||
performance of the model when accessing child items.
|
||||
|
||||
\section1 DomItem Class Implementation
|
||||
|
||||
Since the \c DomItem class is only a thin wrapper around QDomNode objects, with a
|
||||
few additional features to help improve performance and memory usage, we can provide
|
||||
a brief outline of the class before discussing the model itself.
|
||||
|
||||
The constructor simply records details of the QDomNode that needs to be wrapped:
|
||||
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 0
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 1
|
||||
|
||||
As a result, functions to provide the parent wrapper, the row number occupied by
|
||||
the item in its parent's list of children, and the underlying QDomNode for each item
|
||||
are straightforward to write:
|
||||
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 4
|
||||
\codeline
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 6
|
||||
\codeline
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 3
|
||||
|
||||
It is necessary to maintain a collection of items which can be consistently identified
|
||||
by the model. For that reason, we maintain a hash of child wrapper items that, to
|
||||
minimize memory usage, is initially empty. The model uses the item's \c child()
|
||||
function to help create model indexes, and this constructs wrappers for the children
|
||||
of the item's QDomNode, relating the row number of each child to the newly-constructed
|
||||
wrapper:
|
||||
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 5
|
||||
|
||||
If a QDomNode was previously wrapped, the cached wrapper is returned; otherwise, a
|
||||
new wrapper is constructed and stored for valid children, and zero is returned for
|
||||
invalid ones.
|
||||
|
||||
The class's destructor deletes all the child items of the wrapper:
|
||||
|
||||
\snippet itemviews/simpledommodel/domitem.cpp 2
|
||||
|
||||
These, in turn, will delete their children and free any QDomNode objects in use.
|
||||
|
||||
\section1 DomModel Class Implementation
|
||||
|
||||
The structure provided by the \c DomItem class makes the implementation of \c DomModel
|
||||
similar to the \c TreeModel shown in the
|
||||
\l{Simple Tree Model Example}{Simple Tree Model} example.
|
||||
|
||||
The constructor accepts an existing document and a parent object for the model:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 0
|
||||
|
||||
A shallow copy of the document is stored for future reference, and a root item is
|
||||
created to provide a wrapper around the document. We assign the root item a row
|
||||
number of zero only to be consistent since the root item will have no siblings.
|
||||
|
||||
Since the model only contains information about the root item, the destructor only
|
||||
needs to delete this one item:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 1
|
||||
|
||||
All of the child items in the tree will be deleted by the \c DomItem destructor as
|
||||
their parent items are deleted.
|
||||
|
||||
\section2 Basic Properties of The Model
|
||||
|
||||
Some aspects of the model do not depend on the structure of the underlying document,
|
||||
and these are simple to implement.
|
||||
|
||||
The number of columns exposed by the model is returned by the \c columnCount()
|
||||
function:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 2
|
||||
|
||||
This value is fixed, and does not depend on the location or type of the underlying
|
||||
node in the document. We will use these three columns to display different kinds of
|
||||
data from the underlying document.
|
||||
|
||||
Since we only implement a read-only model, the \c flags() function is straightforward
|
||||
to write:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 5
|
||||
|
||||
Since the model is intended for use in a tree view, the \c headerData() function only
|
||||
provides a horizontal header:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 6
|
||||
|
||||
The model presents the names of nodes in the first column, element attributes in the
|
||||
second, and any node values in the third.
|
||||
|
||||
\section2 Navigating The Document
|
||||
|
||||
The index() function creates a model index for the item with the given row, column,
|
||||
and parent in the model:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 7
|
||||
|
||||
The function first has to relate the parent index to an item that contains a node
|
||||
from the underlying document. If the parent index is invalid, it refers to the root
|
||||
node in the document, so we retrieve the root item that wraps it; otherwise, we
|
||||
obtain a pointer to the relevant item using the QModelIndex::internalPointer()
|
||||
function. We are able to extract a pointer in this way because any valid model index
|
||||
will have been created by this function, and we store pointers to item objects in
|
||||
any new indexes that we create with QAbstractItemModel::createIndex():
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 8
|
||||
|
||||
A child item for the given row is provided by the parent item's \c child() function.
|
||||
If a suitable child item was found then we call
|
||||
\l{QAbstractItemModel::createIndex()}{createIndex()} to produce a model index for the
|
||||
requested row and column, passing a pointer to the child item for it to store
|
||||
internally. If no suitable child item is found, an invalid model index is returned.
|
||||
|
||||
Note that the items themselves maintain ownership of their child items. This means
|
||||
that the model does not need to keep track of the child items that have been created,
|
||||
and can let the items themselves tidy up when they are deleted.
|
||||
|
||||
The number of rows beneath a given item in the model is returned by the \c rowCount()
|
||||
function, and is the number of child nodes contained by the node that corresponds to
|
||||
the specified model index:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 10
|
||||
|
||||
To obtain the relevant node in the underlying document, we access the item via the
|
||||
internal pointer stored in the model index. If an invalid index is supplied, the
|
||||
root item is used instead. We use the item's \c node() function to access the node
|
||||
itself, and simply count the number of child nodes it contains.
|
||||
|
||||
Since the model is used to represent a hierarchical data structure, it needs to
|
||||
provide an implementation for the \c parent() function. This returns a model index
|
||||
that corresponds to the parent of a child model index supplied as its argument:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 9
|
||||
|
||||
For valid indexes other than the index corresponding to the root item, we obtain
|
||||
a pointer to the relevant item using the method described in the \c index() function,
|
||||
and use the item's \c parent() function to obtain a pointer to the parent item.
|
||||
|
||||
If no valid parent item exists, or if the parent item is the root item, we can simply
|
||||
follow convention and return an invalid model index. For all other parent items, we
|
||||
create a model index containing the appropriate row and column numbers, and a pointer
|
||||
to the parent item we just obtained.
|
||||
|
||||
Data is provided by the \c data() function. For simplicity, we only provide data for
|
||||
the \l{Qt::DisplayRole}{display role}, returning an invalid variant for all other
|
||||
requests:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 3
|
||||
|
||||
As before, we obtain an item pointer for the index supplied, and use it to obtain
|
||||
the underlying document node. Depending on the column specified, the data we return
|
||||
is obtained in different ways:
|
||||
|
||||
\snippet itemviews/simpledommodel/dommodel.cpp 4
|
||||
|
||||
For the first column, we return the node's name. For the second column, we read any
|
||||
attributes that the node may have, and return a string that contains a space-separated
|
||||
list of attribute-value assignments. For the third column, we return any value that
|
||||
the node may have; this allows the contents of text nodes to be displayed in a view.
|
||||
|
||||
If data from any other column is requested, an invalid variant is returned.
|
||||
|
||||
\section1 Implementation Notes
|
||||
|
||||
Ideally, we would rely on the structure provided by QDomDocument to help us write
|
||||
the \l{QAbstractItemModel::parent()}{parent()} and
|
||||
\l{QAbstractItemModel::index()}{index()} functions that are required when subclassing
|
||||
QAbstractItemModel. However, since Qt's DOM classes use their own system for
|
||||
dynamically allocating memory for DOM nodes, we cannot guarantee that the QDomNode
|
||||
objects returned for a given piece of information will be the same for subsequent
|
||||
accesses to the document.
|
||||
|
||||
We use item wrappers for each QDomNode to provide consistent pointers that the model
|
||||
can use to navigate the document structure.
|
||||
\omit
|
||||
Since these items contain value references to the QDomNode objects themselves, this
|
||||
has the side effect that the DOM nodes themselves can be used to reliably navigate
|
||||
the document [not sure about this - QDom* may return different QDomNode objects for
|
||||
the same piece of information]. However, this advantage is redundant since we need to
|
||||
use wrapper items to obtain it. [Possible use of QDomNode cache in the model itself.]
|
||||
\endomit
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/simpletreemodel
|
||||
\title Simple Tree Model Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\ingroup examples-layout
|
||||
\brief The Simple Tree Model example shows how to use a hierarchical model
|
||||
|
@ -1,101 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example itemviews/simplewidgetmapper
|
||||
\title Simple Widget Mapper Example
|
||||
\ingroup examples-itemviews
|
||||
\brief The Simple Widget Mapper example shows how to use a widget mapper to display
|
||||
data from a model in a collection of widgets.
|
||||
|
||||
\image simplewidgetmapper-example.png
|
||||
|
||||
The QDataWidgetMapper class allows information obtained from a
|
||||
\l{Model Classes}{model} to be viewed and edited in a collection of
|
||||
widgets instead of in an \l{View Classes}{item view}.
|
||||
Any model derived from QAbstractItemModel can be used as the source of
|
||||
data and almost any input widget can be used to display it.
|
||||
|
||||
The example itself is very simple: we create \c Window, a QWidget subclass
|
||||
that we use to hold the widgets used to present the data, and show it. The
|
||||
\c Window class will provide buttons that the user can click to show
|
||||
different records from the model.
|
||||
|
||||
\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/simplewidgetmapper/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.
|
||||
We could use a custom model, but this standard implementation is sufficient
|
||||
for our purposes.
|
||||
|
||||
\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/simplewidgetmapper/window.cpp Set up widgets
|
||||
|
||||
We also set up the buddy relationships between various labels and the
|
||||
corresponding input widgets.
|
||||
|
||||
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/simplewidgetmapper/window.cpp Set up the mapper
|
||||
|
||||
We also connect the mapper to the \uicontrol{Next} and \uicontrol{Previous} buttons
|
||||
via its \l{QDataWidgetMapper::}{toNext()} and
|
||||
\l{QDataWidgetMapper::}{toPrevious()} slots. The mapper's
|
||||
\l{QDataWidgetMapper::}{currentIndexChanged()} signal is connected to the
|
||||
\c{updateButtons()} slot in the window which we'll show later.
|
||||
|
||||
In the final part of the constructor, we set up the layout, placing each
|
||||
of the widgets in a grid (we could also use a QFormLayout for this):
|
||||
|
||||
\snippet itemviews/simplewidgetmapper/window.cpp Set up the layout
|
||||
|
||||
Lastly, we set the window title and initialize the mapper by setting it to
|
||||
refer to the first row in the model.
|
||||
|
||||
The model is initialized in the window's \c{setupModel()} function. Here,
|
||||
we create a standard model with 5 rows and 3 columns, and we insert some
|
||||
sample names, addresses and ages into each row:
|
||||
|
||||
\snippet itemviews/simplewidgetmapper/window.cpp Set up the model
|
||||
|
||||
As a result, each row can be treated like a record in a database, and the
|
||||
widget mapper will read the data from each row, using the column numbers
|
||||
specified earlier to access the correct data for each widget. This is
|
||||
shown in the following diagram:
|
||||
|
||||
\image widgetmapper-simple-mapping.png
|
||||
|
||||
Since the user can navigate using the buttons in the user interface, the
|
||||
example is fully-functional at this point, but to make it a bit more
|
||||
user-friendly, we implement the \c{updateButtons()} slot to show when the
|
||||
user is viewing the first or last records:
|
||||
|
||||
\snippet itemviews/simplewidgetmapper/window.cpp Slot for updating the buttons
|
||||
|
||||
If the mapper is referring to the first row in the model, the \uicontrol{Previous}
|
||||
button is disabled. Similarly, the \uicontrol{Next} button is disabled if the
|
||||
mapper reaches the last row in the model.
|
||||
|
||||
\section1 More Complex Mappings
|
||||
|
||||
The QDataWidgetMapper class makes it easy to relate information from a
|
||||
model to widgets in a user interface. However, it is sometimes necessary
|
||||
to use input widgets which offer choices to the user, such as QComboBox,
|
||||
in conjunction with a widget mapper.
|
||||
|
||||
In these situations, although the mapping to input widgets remains simple,
|
||||
more work needs to be done to expose additional data to the widget mapper.
|
||||
This is covered by the \l{Combo Widget Mapper Example}{Combo Widget Mapper}
|
||||
and \l{SQL Widget Mapper Example}{SQL Widget Mapper}
|
||||
examples.
|
||||
*/
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/sliders
|
||||
\title Sliders Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Sliders example shows how to use the different types of sliders
|
||||
available in Qt: QSlider, QScrollBar and QDial.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/spinboxdelegate
|
||||
\title Spin Box Delegate Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The Spin Box Delegate example shows how to create an editor for a custom delegate in
|
||||
the model/view framework by reusing a standard Qt editor widget.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example widgets/spinboxes
|
||||
\title Spin Boxes Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-widgets
|
||||
\brief The Spin Boxes example shows how to use the many different types of
|
||||
spin boxes available in Qt, from a simple QSpinBox widget to more complex
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/spreadsheet
|
||||
\title Spreadsheet
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The Spreadsheet example shows how to create a simple spreadsheet application.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example dialogs/standarddialogs
|
||||
\title Standard Dialogs Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-dialogs
|
||||
|
||||
\brief The Standard Dialogs example shows the standard dialogs that are provided by Qt.
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example itemviews/stardelegate
|
||||
\title Star Delegate Example
|
||||
\examplecategory {User Interface Components}
|
||||
\ingroup examples-itemviews
|
||||
\brief The Star Delegate example shows how to create a delegate that
|
||||
can paint itself and that supports editing.
|
||||
|