6.5.3 clean
@ -9,7 +9,6 @@ if(QT_FEATURE_animation)
|
||||
endif()
|
||||
add_subdirectory(desktop)
|
||||
add_subdirectory(dialogs)
|
||||
add_subdirectory(effects)
|
||||
qt_internal_add_example(gallery)
|
||||
add_subdirectory(gestures)
|
||||
add_subdirectory(graphicsview)
|
||||
@ -17,7 +16,6 @@ add_subdirectory(itemviews)
|
||||
add_subdirectory(layouts)
|
||||
add_subdirectory(painting)
|
||||
add_subdirectory(richtext)
|
||||
add_subdirectory(scroller)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(touch)
|
||||
add_subdirectory(tutorials)
|
||||
@ -28,6 +26,3 @@ endif()
|
||||
if(QT_FEATURE_cursor)
|
||||
add_subdirectory(mainwindows)
|
||||
endif()
|
||||
if(QT_FEATURE_opengl AND TARGET Qt6::Gui)
|
||||
qt_internal_add_example(windowcontainer)
|
||||
endif()
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Q_INIT_RESOURCE(easing);
|
||||
QApplication app(argc, argv);
|
||||
Window w;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example desktop/systray
|
||||
\title System Tray Icon Example
|
||||
\examplecategory {Desktop}
|
||||
\ingroup examples-widgets
|
||||
\brief The System Tray Icon example shows how to add an icon with a menu
|
||||
and popup messages to a desktop environment's system tray.
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_INIT_RESOURCE(systray);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if (!QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||
|
@ -2,12 +2,10 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(QT_FEATURE_wizard)
|
||||
qt_internal_add_example(classwizard)
|
||||
qt_internal_add_example(trivialwizard)
|
||||
if(Qt6::PrintSupport)
|
||||
qt_internal_add_example(licensewizard)
|
||||
endif()
|
||||
endif()
|
||||
qt_internal_add_example(extension)
|
||||
qt_internal_add_example(standarddialogs)
|
||||
qt_internal_add_example(tabdialog)
|
||||
if(QT_FEATURE_wizard AND TARGET Qt6::PrintSupport)
|
||||
qt_internal_add_example(licensewizard)
|
||||
endif()
|
||||
|
@ -1,55 +0,0 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(classwizard LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/dialogs/classwizard")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(classwizard
|
||||
classwizard.cpp classwizard.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(classwizard PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(classwizard PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(classwizard_resource_files
|
||||
"images/background.png"
|
||||
"images/banner.png"
|
||||
"images/logo1.png"
|
||||
"images/logo2.png"
|
||||
"images/logo3.png"
|
||||
"images/watermark1.png"
|
||||
"images/watermark2.png"
|
||||
)
|
||||
|
||||
qt_add_resources(classwizard "classwizard"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${classwizard_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS classwizard
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -1,394 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "classwizard.h"
|
||||
|
||||
//! [0] //! [1]
|
||||
ClassWizard::ClassWizard(QWidget *parent)
|
||||
: QWizard(parent)
|
||||
{
|
||||
addPage(new IntroPage);
|
||||
addPage(new ClassInfoPage);
|
||||
addPage(new CodeStylePage);
|
||||
addPage(new OutputFilesPage);
|
||||
addPage(new ConclusionPage);
|
||||
//! [0]
|
||||
|
||||
setPixmap(QWizard::BannerPixmap, QPixmap(":/images/banner.png"));
|
||||
setPixmap(QWizard::BackgroundPixmap, QPixmap(":/images/background.png"));
|
||||
|
||||
setWindowTitle(tr("Class Wizard"));
|
||||
//! [2]
|
||||
}
|
||||
//! [1] //! [2]
|
||||
|
||||
//! [3]
|
||||
void ClassWizard::accept()
|
||||
//! [3] //! [4]
|
||||
{
|
||||
QByteArray className = field("className").toByteArray();
|
||||
QByteArray baseClass = field("baseClass").toByteArray();
|
||||
QByteArray macroName = field("macroName").toByteArray();
|
||||
QByteArray baseInclude = field("baseInclude").toByteArray();
|
||||
|
||||
QString outputDir = field("outputDir").toString();
|
||||
QString header = field("header").toString();
|
||||
QString implementation = field("implementation").toString();
|
||||
//! [4]
|
||||
|
||||
QByteArray block;
|
||||
|
||||
if (field("comment").toBool()) {
|
||||
block += "/*\n";
|
||||
block += " " + header.toLatin1() + '\n';
|
||||
block += "*/\n";
|
||||
block += '\n';
|
||||
}
|
||||
if (field("protect").toBool()) {
|
||||
block += "#ifndef " + macroName + '\n';
|
||||
block += "#define " + macroName + '\n';
|
||||
block += '\n';
|
||||
}
|
||||
if (field("includeBase").toBool()) {
|
||||
block += "#include " + baseInclude + '\n';
|
||||
block += '\n';
|
||||
}
|
||||
|
||||
block += "class " + className;
|
||||
if (!baseClass.isEmpty())
|
||||
block += " : public " + baseClass;
|
||||
block += '\n';
|
||||
block += "{\n";
|
||||
|
||||
/* qmake ignore Q_OBJECT */
|
||||
|
||||
if (field("qobjectMacro").toBool()) {
|
||||
block += " Q_OBJECT\n";
|
||||
block += '\n';
|
||||
}
|
||||
block += "public:\n";
|
||||
|
||||
if (field("qobjectCtor").toBool()) {
|
||||
block += " " + className + "(QObject *parent = nullptr);\n";
|
||||
} else if (field("qwidgetCtor").toBool()) {
|
||||
block += " " + className + "(QWidget *parent = nullptr);\n";
|
||||
} else if (field("defaultCtor").toBool()) {
|
||||
block += " " + className + "();\n";
|
||||
if (field("copyCtor").toBool()) {
|
||||
block += " " + className + "(const " + className + " &other);\n";
|
||||
block += '\n';
|
||||
block += " " + className + " &operator=" + "(const " + className
|
||||
+ " &other);\n";
|
||||
}
|
||||
}
|
||||
block += "};\n";
|
||||
|
||||
if (field("protect").toBool()) {
|
||||
block += '\n';
|
||||
block += "#endif\n";
|
||||
}
|
||||
|
||||
QFile headerFile(outputDir + '/' + header);
|
||||
if (!headerFile.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QMessageBox::warning(nullptr, QObject::tr("Simple Wizard"),
|
||||
QObject::tr("Cannot write file %1:\n%2")
|
||||
.arg(headerFile.fileName())
|
||||
.arg(headerFile.errorString()));
|
||||
return;
|
||||
}
|
||||
headerFile.write(block);
|
||||
|
||||
block.clear();
|
||||
|
||||
if (field("comment").toBool()) {
|
||||
block += "/*\n";
|
||||
block += " " + implementation.toLatin1() + '\n';
|
||||
block += "*/\n";
|
||||
block += '\n';
|
||||
}
|
||||
block += "#include \"" + header.toLatin1() + "\"\n";
|
||||
block += '\n';
|
||||
|
||||
if (field("qobjectCtor").toBool()) {
|
||||
block += className + "::" + className + "(QObject *parent)\n";
|
||||
block += " : " + baseClass + "(parent)\n";
|
||||
block += "{\n";
|
||||
block += "}\n";
|
||||
} else if (field("qwidgetCtor").toBool()) {
|
||||
block += className + "::" + className + "(QWidget *parent)\n";
|
||||
block += " : " + baseClass + "(parent)\n";
|
||||
block += "{\n";
|
||||
block += "}\n";
|
||||
} else if (field("defaultCtor").toBool()) {
|
||||
block += className + "::" + className + "()\n";
|
||||
block += "{\n";
|
||||
block += " // missing code\n";
|
||||
block += "}\n";
|
||||
|
||||
if (field("copyCtor").toBool()) {
|
||||
block += "\n";
|
||||
block += className + "::" + className + "(const " + className
|
||||
+ " &other)\n";
|
||||
block += "{\n";
|
||||
block += " *this = other;\n";
|
||||
block += "}\n";
|
||||
block += '\n';
|
||||
block += className + " &" + className + "::operator=(const "
|
||||
+ className + " &other)\n";
|
||||
block += "{\n";
|
||||
if (!baseClass.isEmpty())
|
||||
block += " " + baseClass + "::operator=(other);\n";
|
||||
block += " // missing code\n";
|
||||
block += " return *this;\n";
|
||||
block += "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
QFile implementationFile(outputDir + '/' + implementation);
|
||||
if (!implementationFile.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QMessageBox::warning(nullptr, QObject::tr("Simple Wizard"),
|
||||
QObject::tr("Cannot write file %1:\n%2")
|
||||
.arg(implementationFile.fileName())
|
||||
.arg(implementationFile.errorString()));
|
||||
return;
|
||||
}
|
||||
implementationFile.write(block);
|
||||
|
||||
//! [5]
|
||||
QDialog::accept();
|
||||
//! [5] //! [6]
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
IntroPage::IntroPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Introduction"));
|
||||
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark1.png"));
|
||||
|
||||
label = new QLabel(tr("This wizard will generate a skeleton C++ class "
|
||||
"definition, including a few functions. You simply "
|
||||
"need to specify the class name and set a few "
|
||||
"options to produce a header file and an "
|
||||
"implementation file for your new C++ class."));
|
||||
label->setWordWrap(true);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(label);
|
||||
setLayout(layout);
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8] //! [9]
|
||||
ClassInfoPage::ClassInfoPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
//! [8]
|
||||
setTitle(tr("Class Information"));
|
||||
setSubTitle(tr("Specify basic information about the class for which you "
|
||||
"want to generate skeleton source code files."));
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo1.png"));
|
||||
|
||||
//! [10]
|
||||
classNameLabel = new QLabel(tr("&Class name:"));
|
||||
classNameLineEdit = new QLineEdit;
|
||||
classNameLabel->setBuddy(classNameLineEdit);
|
||||
|
||||
baseClassLabel = new QLabel(tr("B&ase class:"));
|
||||
baseClassLineEdit = new QLineEdit;
|
||||
baseClassLabel->setBuddy(baseClassLineEdit);
|
||||
|
||||
qobjectMacroCheckBox = new QCheckBox(tr("Generate Q_OBJECT ¯o"));
|
||||
|
||||
//! [10]
|
||||
groupBox = new QGroupBox(tr("C&onstructor"));
|
||||
//! [9]
|
||||
|
||||
qobjectCtorRadioButton = new QRadioButton(tr("&QObject-style constructor"));
|
||||
qwidgetCtorRadioButton = new QRadioButton(tr("Q&Widget-style constructor"));
|
||||
defaultCtorRadioButton = new QRadioButton(tr("&Default constructor"));
|
||||
copyCtorCheckBox = new QCheckBox(tr("&Generate copy constructor and "
|
||||
"operator="));
|
||||
|
||||
defaultCtorRadioButton->setChecked(true);
|
||||
|
||||
connect(defaultCtorRadioButton, &QAbstractButton::toggled,
|
||||
copyCtorCheckBox, &QWidget::setEnabled);
|
||||
|
||||
//! [11] //! [12]
|
||||
registerField("className*", classNameLineEdit);
|
||||
registerField("baseClass", baseClassLineEdit);
|
||||
registerField("qobjectMacro", qobjectMacroCheckBox);
|
||||
//! [11]
|
||||
registerField("qobjectCtor", qobjectCtorRadioButton);
|
||||
registerField("qwidgetCtor", qwidgetCtorRadioButton);
|
||||
registerField("defaultCtor", defaultCtorRadioButton);
|
||||
registerField("copyCtor", copyCtorCheckBox);
|
||||
|
||||
QVBoxLayout *groupBoxLayout = new QVBoxLayout;
|
||||
//! [12]
|
||||
groupBoxLayout->addWidget(qobjectCtorRadioButton);
|
||||
groupBoxLayout->addWidget(qwidgetCtorRadioButton);
|
||||
groupBoxLayout->addWidget(defaultCtorRadioButton);
|
||||
groupBoxLayout->addWidget(copyCtorCheckBox);
|
||||
groupBox->setLayout(groupBoxLayout);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->addWidget(classNameLabel, 0, 0);
|
||||
layout->addWidget(classNameLineEdit, 0, 1);
|
||||
layout->addWidget(baseClassLabel, 1, 0);
|
||||
layout->addWidget(baseClassLineEdit, 1, 1);
|
||||
layout->addWidget(qobjectMacroCheckBox, 2, 0, 1, 2);
|
||||
layout->addWidget(groupBox, 3, 0, 1, 2);
|
||||
setLayout(layout);
|
||||
//! [13]
|
||||
}
|
||||
//! [13]
|
||||
|
||||
//! [14]
|
||||
CodeStylePage::CodeStylePage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Code Style Options"));
|
||||
setSubTitle(tr("Choose the formatting of the generated code."));
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo2.png"));
|
||||
|
||||
commentCheckBox = new QCheckBox(tr("&Start generated files with a "
|
||||
//! [14]
|
||||
"comment"));
|
||||
commentCheckBox->setChecked(true);
|
||||
|
||||
protectCheckBox = new QCheckBox(tr("&Protect header file against multiple "
|
||||
"inclusions"));
|
||||
protectCheckBox->setChecked(true);
|
||||
|
||||
macroNameLabel = new QLabel(tr("&Macro name:"));
|
||||
macroNameLineEdit = new QLineEdit;
|
||||
macroNameLabel->setBuddy(macroNameLineEdit);
|
||||
|
||||
includeBaseCheckBox = new QCheckBox(tr("&Include base class definition"));
|
||||
baseIncludeLabel = new QLabel(tr("Base class include:"));
|
||||
baseIncludeLineEdit = new QLineEdit;
|
||||
baseIncludeLabel->setBuddy(baseIncludeLineEdit);
|
||||
|
||||
connect(protectCheckBox, &QAbstractButton::toggled,
|
||||
macroNameLabel, &QWidget::setEnabled);
|
||||
connect(protectCheckBox, &QAbstractButton::toggled,
|
||||
macroNameLineEdit, &QWidget::setEnabled);
|
||||
connect(includeBaseCheckBox, &QAbstractButton::toggled,
|
||||
baseIncludeLabel, &QWidget::setEnabled);
|
||||
connect(includeBaseCheckBox, &QAbstractButton::toggled,
|
||||
baseIncludeLineEdit, &QWidget::setEnabled);
|
||||
|
||||
registerField("comment", commentCheckBox);
|
||||
registerField("protect", protectCheckBox);
|
||||
registerField("macroName", macroNameLineEdit);
|
||||
registerField("includeBase", includeBaseCheckBox);
|
||||
registerField("baseInclude", baseIncludeLineEdit);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->setColumnMinimumWidth(0, 20);
|
||||
layout->addWidget(commentCheckBox, 0, 0, 1, 3);
|
||||
layout->addWidget(protectCheckBox, 1, 0, 1, 3);
|
||||
layout->addWidget(macroNameLabel, 2, 1);
|
||||
layout->addWidget(macroNameLineEdit, 2, 2);
|
||||
layout->addWidget(includeBaseCheckBox, 3, 0, 1, 3);
|
||||
layout->addWidget(baseIncludeLabel, 4, 1);
|
||||
layout->addWidget(baseIncludeLineEdit, 4, 2);
|
||||
//! [15]
|
||||
setLayout(layout);
|
||||
}
|
||||
//! [15]
|
||||
|
||||
//! [16]
|
||||
void CodeStylePage::initializePage()
|
||||
{
|
||||
QString className = field("className").toString();
|
||||
macroNameLineEdit->setText(className.toUpper() + "_H");
|
||||
|
||||
QString baseClass = field("baseClass").toString();
|
||||
|
||||
includeBaseCheckBox->setChecked(!baseClass.isEmpty());
|
||||
includeBaseCheckBox->setEnabled(!baseClass.isEmpty());
|
||||
baseIncludeLabel->setEnabled(!baseClass.isEmpty());
|
||||
baseIncludeLineEdit->setEnabled(!baseClass.isEmpty());
|
||||
|
||||
QRegularExpression rx("Q[A-Z].*");
|
||||
if (baseClass.isEmpty()) {
|
||||
baseIncludeLineEdit->clear();
|
||||
} else if (rx.match(baseClass).hasMatch()) {
|
||||
baseIncludeLineEdit->setText('<' + baseClass + '>');
|
||||
} else {
|
||||
baseIncludeLineEdit->setText('"' + baseClass.toLower() + ".h\"");
|
||||
}
|
||||
}
|
||||
//! [16]
|
||||
|
||||
OutputFilesPage::OutputFilesPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Output Files"));
|
||||
setSubTitle(tr("Specify where you want the wizard to put the generated "
|
||||
"skeleton code."));
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo3.png"));
|
||||
|
||||
outputDirLabel = new QLabel(tr("&Output directory:"));
|
||||
outputDirLineEdit = new QLineEdit;
|
||||
outputDirLabel->setBuddy(outputDirLineEdit);
|
||||
|
||||
headerLabel = new QLabel(tr("&Header file name:"));
|
||||
headerLineEdit = new QLineEdit;
|
||||
headerLabel->setBuddy(headerLineEdit);
|
||||
|
||||
implementationLabel = new QLabel(tr("&Implementation file name:"));
|
||||
implementationLineEdit = new QLineEdit;
|
||||
implementationLabel->setBuddy(implementationLineEdit);
|
||||
|
||||
registerField("outputDir*", outputDirLineEdit);
|
||||
registerField("header*", headerLineEdit);
|
||||
registerField("implementation*", implementationLineEdit);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->addWidget(outputDirLabel, 0, 0);
|
||||
layout->addWidget(outputDirLineEdit, 0, 1);
|
||||
layout->addWidget(headerLabel, 1, 0);
|
||||
layout->addWidget(headerLineEdit, 1, 1);
|
||||
layout->addWidget(implementationLabel, 2, 0);
|
||||
layout->addWidget(implementationLineEdit, 2, 1);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
//! [17]
|
||||
void OutputFilesPage::initializePage()
|
||||
{
|
||||
QString className = field("className").toString();
|
||||
headerLineEdit->setText(className.toLower() + ".h");
|
||||
implementationLineEdit->setText(className.toLower() + ".cpp");
|
||||
outputDirLineEdit->setText(QDir::toNativeSeparators(QDir::tempPath()));
|
||||
}
|
||||
//! [17]
|
||||
|
||||
ConclusionPage::ConclusionPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Conclusion"));
|
||||
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark2.png"));
|
||||
|
||||
label = new QLabel;
|
||||
label->setWordWrap(true);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(label);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void ConclusionPage::initializePage()
|
||||
{
|
||||
QString finishText = wizard()->buttonText(QWizard::FinishButton);
|
||||
finishText.remove('&');
|
||||
label->setText(tr("Click %1 to generate the class skeleton.")
|
||||
.arg(finishText));
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CLASSWIZARD_H
|
||||
#define CLASSWIZARD_H
|
||||
|
||||
#include <QWizard>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QRadioButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class ClassWizard : public QWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClassWizard(QWidget *parent = nullptr);
|
||||
|
||||
void accept() override;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
class IntroPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntroPage(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
};
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
class ClassInfoPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClassInfoPage(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QLabel *classNameLabel;
|
||||
QLabel *baseClassLabel;
|
||||
QLineEdit *classNameLineEdit;
|
||||
QLineEdit *baseClassLineEdit;
|
||||
QCheckBox *qobjectMacroCheckBox;
|
||||
QGroupBox *groupBox;
|
||||
QRadioButton *qobjectCtorRadioButton;
|
||||
QRadioButton *qwidgetCtorRadioButton;
|
||||
QRadioButton *defaultCtorRadioButton;
|
||||
QCheckBox *copyCtorCheckBox;
|
||||
};
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
class CodeStylePage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CodeStylePage(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void initializePage() override;
|
||||
|
||||
private:
|
||||
QCheckBox *commentCheckBox;
|
||||
QCheckBox *protectCheckBox;
|
||||
QCheckBox *includeBaseCheckBox;
|
||||
QLabel *macroNameLabel;
|
||||
QLabel *baseIncludeLabel;
|
||||
QLineEdit *macroNameLineEdit;
|
||||
QLineEdit *baseIncludeLineEdit;
|
||||
};
|
||||
//! [3]
|
||||
|
||||
class OutputFilesPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OutputFilesPage(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void initializePage() override;
|
||||
|
||||
private:
|
||||
QLabel *outputDirLabel;
|
||||
QLabel *headerLabel;
|
||||
QLabel *implementationLabel;
|
||||
QLineEdit *outputDirLineEdit;
|
||||
QLineEdit *headerLineEdit;
|
||||
QLineEdit *implementationLineEdit;
|
||||
};
|
||||
|
||||
class ConclusionPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConclusionPage(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void initializePage() override;
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,10 +0,0 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = classwizard.h
|
||||
SOURCES = classwizard.cpp \
|
||||
main.cpp
|
||||
RESOURCES = classwizard.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/dialogs/classwizard
|
||||
INSTALLS += target
|
@ -1,11 +0,0 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>images/background.png</file>
|
||||
<file>images/banner.png</file>
|
||||
<file>images/logo1.png</file>
|
||||
<file>images/logo2.png</file>
|
||||
<file>images/logo3.png</file>
|
||||
<file>images/watermark1.png</file>
|
||||
<file>images/watermark2.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 15 KiB |
@ -1,28 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
#include <QLibraryInfo>
|
||||
|
||||
#include "classwizard.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_INIT_RESOURCE(classwizard);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
QString translatorFileName = QLatin1String("qtbase_");
|
||||
translatorFileName += QLocale::system().name();
|
||||
QTranslator *translator = new QTranslator(&app);
|
||||
if (translator->load(translatorFileName, QLibraryInfo::path(QLibraryInfo::TranslationsPath)))
|
||||
app.installTranslator(translator);
|
||||
#endif
|
||||
|
||||
ClassWizard wizard;
|
||||
wizard.show();
|
||||
return app.exec();
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
QT_FOR_CONFIG += widgets
|
||||
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = classwizard \
|
||||
extension \
|
||||
licensewizard \
|
||||
SUBDIRS = licensewizard \
|
||||
standarddialogs \
|
||||
tabdialog \
|
||||
trivialwizard
|
||||
|
@ -1,37 +0,0 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(extension LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/dialogs/extension")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(extension
|
||||
finddialog.cpp finddialog.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(extension PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(extension PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS extension
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -1,9 +0,0 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = finddialog.h
|
||||
SOURCES = finddialog.cpp \
|
||||
main.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/dialogs/extension
|
||||
INSTALLS += target
|
@ -1,77 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "finddialog.h"
|
||||
|
||||
//! [0]
|
||||
FindDialog::FindDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
label = new QLabel(tr("Find &what:"));
|
||||
lineEdit = new QLineEdit;
|
||||
label->setBuddy(lineEdit);
|
||||
|
||||
caseCheckBox = new QCheckBox(tr("Match &case"));
|
||||
fromStartCheckBox = new QCheckBox(tr("Search from &start"));
|
||||
fromStartCheckBox->setChecked(true);
|
||||
|
||||
//! [1]
|
||||
findButton = new QPushButton(tr("&Find"));
|
||||
findButton->setDefault(true);
|
||||
|
||||
moreButton = new QPushButton(tr("&More"));
|
||||
moreButton->setCheckable(true);
|
||||
//! [0]
|
||||
moreButton->setAutoDefault(false);
|
||||
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
extension = new QWidget;
|
||||
|
||||
wholeWordsCheckBox = new QCheckBox(tr("&Whole words"));
|
||||
backwardCheckBox = new QCheckBox(tr("Search &backward"));
|
||||
searchSelectionCheckBox = new QCheckBox(tr("Search se&lection"));
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
buttonBox = new QDialogButtonBox(Qt::Vertical);
|
||||
buttonBox->addButton(findButton, QDialogButtonBox::ActionRole);
|
||||
buttonBox->addButton(moreButton, QDialogButtonBox::ActionRole);
|
||||
|
||||
connect(moreButton, &QAbstractButton::toggled, extension, &QWidget::setVisible);
|
||||
|
||||
QVBoxLayout *extensionLayout = new QVBoxLayout;
|
||||
extensionLayout->setContentsMargins(QMargins());
|
||||
extensionLayout->addWidget(wholeWordsCheckBox);
|
||||
extensionLayout->addWidget(backwardCheckBox);
|
||||
extensionLayout->addWidget(searchSelectionCheckBox);
|
||||
extension->setLayout(extensionLayout);
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
QHBoxLayout *topLeftLayout = new QHBoxLayout;
|
||||
topLeftLayout->addWidget(label);
|
||||
topLeftLayout->addWidget(lineEdit);
|
||||
|
||||
QVBoxLayout *leftLayout = new QVBoxLayout;
|
||||
leftLayout->addLayout(topLeftLayout);
|
||||
leftLayout->addWidget(caseCheckBox);
|
||||
leftLayout->addWidget(fromStartCheckBox);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
mainLayout->addLayout(leftLayout, 0, 0);
|
||||
mainLayout->addWidget(buttonBox, 0, 1);
|
||||
mainLayout->addWidget(extension, 1, 0, 1, 2);
|
||||
mainLayout->setRowStretch(2, 1);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
setWindowTitle(tr("Extension"));
|
||||
//! [4] //! [5]
|
||||
extension->hide();
|
||||
}
|
||||
//! [5]
|
@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef FINDDIALOG_H
|
||||
#define FINDDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QDialogButtonBox;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class FindDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FindDialog(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
QLineEdit *lineEdit;
|
||||
QCheckBox *caseCheckBox;
|
||||
QCheckBox *fromStartCheckBox;
|
||||
QCheckBox *wholeWordsCheckBox;
|
||||
QCheckBox *searchSelectionCheckBox;
|
||||
QCheckBox *backwardCheckBox;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QPushButton *findButton;
|
||||
QPushButton *moreButton;
|
||||
QWidget *extension;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
@ -1,16 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "finddialog.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
FindDialog dialog;
|
||||
|
||||
dialog.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -288,9 +288,12 @@ void ConclusionPage::initializePage()
|
||||
"You can use this software for 30 days and make one "
|
||||
"backup, but you are not allowed to distribute it.");
|
||||
} else if (wizard()->hasVisitedPage(LicenseWizard::Page_Details)) {
|
||||
//! [accessField]
|
||||
const QString emailAddress = field("details.email").toString();
|
||||
licenseText = tr("<u>First-Time License Agreement:</u> "
|
||||
"You can use this software subject to the license "
|
||||
"you will receive by email.");
|
||||
"you will receive by email sent to %1.").arg(emailAddress);
|
||||
//! [accessField]
|
||||
} else {
|
||||
licenseText = tr("<u>Upgrade License Agreement:</u> "
|
||||
"This software is licensed under the terms of your "
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_INIT_RESOURCE(licensewizard);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
|
@ -86,10 +86,12 @@ int main(int argc, char *argv[])
|
||||
app.installTranslator(translator);
|
||||
#endif
|
||||
|
||||
//! [linearAddPage]
|
||||
QWizard wizard;
|
||||
wizard.addPage(createIntroPage());
|
||||
wizard.addPage(createRegistrationPage());
|
||||
wizard.addPage(createConclusionPage());
|
||||
//! [linearAddPage]
|
||||
|
||||
wizard.setWindowTitle("Trivial Wizard");
|
||||
wizard.show();
|
||||
|
@ -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
|
||||
*/
|