6.6.1 original

This commit is contained in:
kleuter
2023-12-04 18:42:35 +01:00
parent 9bf343ceed
commit 8490fae44c
607 changed files with 15608 additions and 14647 deletions

View File

@ -4,7 +4,7 @@
#ifndef BINDABLESUBSCRIPTION_H
#define BINDABLESUBSCRIPTION_H
#include <QPointer>
#include <QBindable>
#include <QProperty>
class BindableUser;

View File

@ -4,6 +4,7 @@
#ifndef BINDABLEUSER_H
#define BINDABLEUSER_H
#include <QBindable>
#include <QLocale>
#include <QProperty>

View File

@ -6,15 +6,15 @@
#include "bindableuser.h"
#include <QApplication>
#include <QButtonGroup>
#include <QBindable>
#include <QLabel>
#include <QLocale>
#include <QPushButton>
#include <QRadioButton>
#include <QSpinBox>
#include <QProperty>
#include <QString>
#include <QDateTimeEdit>
#include <QBindable>
using namespace Qt::StringLiterals;
int main(int argc, char *argv[])
{
@ -27,38 +27,38 @@ int main(int argc, char *argv[])
// when subscription is out of scope so is window
// Initialize subscription data
QRadioButton *monthly = w.findChild<QRadioButton *>("btnMonthly");
QRadioButton *monthly = w.findChild<QRadioButton *>(u"btnMonthly"_s);
QObject::connect(monthly, &QRadioButton::clicked, [&] {
subscription.setDuration(BindableSubscription::Monthly);
});
QRadioButton *quarterly = w.findChild<QRadioButton *>("btnQuarterly");
QRadioButton *quarterly = w.findChild<QRadioButton *>(u"btnQuarterly"_s);
QObject::connect(quarterly, &QRadioButton::clicked, [&] {
subscription.setDuration(BindableSubscription::Quarterly);
});
QRadioButton *yearly = w.findChild<QRadioButton *>("btnYearly");
QRadioButton *yearly = w.findChild<QRadioButton *>(u"btnYearly"_s);
QObject::connect(yearly, &QRadioButton::clicked, [&] {
subscription.setDuration(BindableSubscription::Yearly);
});
// Initialize user data
QPushButton *germany = w.findChild<QPushButton *>("btnGermany");
QPushButton *germany = w.findChild<QPushButton *>(u"btnGermany"_s);
QObject::connect(germany, &QPushButton::clicked, [&] {
user.setCountry(BindableUser::Country::Germany);
});
QPushButton *finland = w.findChild<QPushButton *>("btnFinland");
QPushButton *finland = w.findChild<QPushButton *>(u"btnFinland"_s);
QObject::connect(finland, &QPushButton::clicked, [&] {
user.setCountry(BindableUser::Country::Finland);
});
QPushButton *norway = w.findChild<QPushButton *>("btnNorway");
QPushButton *norway = w.findChild<QPushButton *>(u"btnNorway"_s);
QObject::connect(norway, &QPushButton::clicked, [&] {
user.setCountry(BindableUser::Country::Norway);
});
QSpinBox *ageSpinBox = w.findChild<QSpinBox *>("ageSpinBox");
QSpinBox *ageSpinBox = w.findChild<QSpinBox *>(u"ageSpinBox"_s);
QBindable<int> ageBindable(ageSpinBox, "value");
user.bindableAge().setBinding([ageBindable](){ return ageBindable.value();});
QLabel *priceDisplay = w.findChild<QLabel *>("priceDisplay");
QLabel *priceDisplay = w.findChild<QLabel *>(u"priceDisplay"_s);
// Track price changes
//! [update-ui]

View File

@ -3,7 +3,8 @@
/*!
\example bindableproperties
\title Bindable Properties Example
\examplecategory {Data Processing & I/O}
\title Bindable Properties
\brief Demonstrates how the usage of bindable properties can simplify
your C++ code.

View File

@ -6,11 +6,14 @@
#include "user.h"
#include <QApplication>
#include <QButtonGroup>
#include <QLabel>
#include <QLocale>
#include <QPushButton>
#include <QRadioButton>
#include <QSpinBox>
#include <QString>
using namespace Qt::StringLiterals;
int main(int argc, char *argv[])
{
@ -24,40 +27,40 @@ int main(int argc, char *argv[])
SubscriptionWindow w;
// Initialize subscription data
QRadioButton *monthly = w.findChild<QRadioButton *>("btnMonthly");
QRadioButton *monthly = w.findChild<QRadioButton *>(u"btnMonthly"_s);
QObject::connect(monthly, &QRadioButton::clicked, &subscription, [&] {
subscription.setDuration(Subscription::Monthly);
});
QRadioButton *quarterly = w.findChild<QRadioButton *>("btnQuarterly");
QRadioButton *quarterly = w.findChild<QRadioButton *>(u"btnQuarterly"_s);
QObject::connect(quarterly, &QRadioButton::clicked, &subscription, [&] {
subscription.setDuration(Subscription::Quarterly);
});
QRadioButton *yearly = w.findChild<QRadioButton *>("btnYearly");
QRadioButton *yearly = w.findChild<QRadioButton *>(u"btnYearly"_s);
QObject::connect(yearly, &QRadioButton::clicked, &subscription, [&] {
subscription.setDuration(Subscription::Yearly);
});
// Initialize user data
QPushButton *germany = w.findChild<QPushButton *>("btnGermany");
QPushButton *germany = w.findChild<QPushButton *>(u"btnGermany"_s);
QObject::connect(germany, &QPushButton::clicked, &user, [&] {
user.setCountry(User::Country::Germany);
});
QPushButton *finland = w.findChild<QPushButton *>("btnFinland");
QPushButton *finland = w.findChild<QPushButton *>(u"btnFinland"_s);
QObject::connect(finland, &QPushButton::clicked, &user, [&] {
user.setCountry(User::Country::Finland);
});
QPushButton *norway = w.findChild<QPushButton *>("btnNorway");
QPushButton *norway = w.findChild<QPushButton *>(u"btnNorway"_s);
QObject::connect(norway, &QPushButton::clicked, &user, [&] {
user.setCountry(User::Country::Norway);
});
QSpinBox *ageSpinBox = w.findChild<QSpinBox *>("ageSpinBox");
QSpinBox *ageSpinBox = w.findChild<QSpinBox *>(u"ageSpinBox"_s);
QObject::connect(ageSpinBox, &QSpinBox::valueChanged, &user, [&](int value) {
user.setAge(value);
});
// Initialize price data
QLabel *priceDisplay = w.findChild<QLabel *>("priceDisplay");
QLabel *priceDisplay = w.findChild<QLabel *>(u"priceDisplay"_s);
priceDisplay->setText(QString::number(subscription.price()));
priceDisplay->setEnabled(subscription.isValid());

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -3,14 +3,16 @@
/*!
\example ipc/localfortuneclient
\title Local Fortune Client Example
\examplecategory {Connectivity}
\title Local Fortune Client
\ingroup examples-ipc
\brief Demonstrates using QLocalSocket for a simple local service client.
The Local Fortune Client example shows how to create a client for a simple
local service using QLocalSocket. It is intended to be run alongside the
\l{Local Fortune Server Example}.
\l{Local Fortune Server} example.
\image localfortuneclient-example.png Screenshot of the Local Fortune Client example
\image localfortuneclient-example.png Screenshot of the Local Fortune Client
example
*/

View File

@ -3,13 +3,14 @@
/*!
\example ipc/localfortuneserver
\title Local Fortune Server Example
\examplecategory {Connectivity}
\title Local Fortune Server
\ingroup examples-ipc
\brief Demonstrates using QLocalServer and QLocalSocket for serving a simple local service.
The Local Fortune Server example shows how to create a server for a simple
local service. It is intended to be run alongside the
\l{Local Fortune Client Example}
\l{Local Fortune Client} example.
\image localfortuneserver-example.png Screenshot of the Local Fortune Server example
*/

View File

@ -3,10 +3,11 @@
/*!
\example ipc/sharedmemory
\title Shared Memory Example
\examplecategory {Data Processing & I/O}
\title IPC: Shared Memory
\ingroup examples-ipc
\brief Demonstrates doing inter-process communication using shared memory with
the QSharedMemory class.
\brief Demonstrates how to share image data between different processes
using the Shared Memory IPC mechanism.
The Shared Memory example shows how to use the QSharedMemory class
to implement inter-process communication using shared memory. To

View File

@ -1,14 +1,19 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include <QtNetwork>
#include "client.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGuiApplication>
#include <QMessageBox>
#include <QTimer>
using namespace Qt::StringLiterals;
Client::Client(QWidget *parent)
: QDialog(parent),
hostLineEdit(new QLineEdit("fortune")),
hostLineEdit(new QLineEdit(u"fortune"_s)),
getFortuneButton(new QPushButton(tr("Get Fortune"))),
statusLabel(new QLabel(tr("This examples requires that you run the "
"Local Fortune Server example as well."))),
@ -28,7 +33,7 @@ Client::Client(QWidget *parent)
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
in.setDevice(socket);
in.setVersion(QDataStream::Qt_5_10);
in.setVersion(QDataStream::Qt_6_0);
connect(hostLineEdit, &QLineEdit::textChanged,
this, &Client::enableGetFortuneButton);

View File

@ -4,15 +4,12 @@
#ifndef CLIENT_H
#define CLIENT_H
#include <QDialog>
#include <QDataStream>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QLocalSocket>
QT_BEGIN_NAMESPACE
class QLabel;
class QLineEdit;
class QPushButton;
QT_END_NAMESPACE
#include <QPushButton>
class Client : public QDialog
{

View File

@ -1,10 +1,10 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "client.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);

View File

@ -1,10 +1,10 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "server.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);

View File

@ -3,27 +3,33 @@
#include "server.h"
#include <QtWidgets>
#include <QtNetwork>
#include <QDialogButtonBox>
#include <QGuiApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QLocalSocket>
#include <QMessageBox>
#include <QPushButton>
#include <QRandomGenerator>
using namespace Qt::StringLiterals;
static const QString idleStateText = QObject::tr("Press \"Listen\" to start the server");
Server::Server(QWidget *parent)
: QDialog(parent)
: QDialog(parent),
server(new QLocalServer(this)),
hostLineEdit(new QLineEdit(u"fortune"_s)),
statusLabel(new QLabel(idleStateText)),
listenButton(new QPushButton(tr("Listen"))),
stopListeningButton(new QPushButton(tr("Stop Listening")))
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
server = new QLocalServer(this);
if (!server->listen("fortune")) {
QMessageBox::critical(this, tr("Local Fortune Server"),
tr("Unable to start the server: %1.")
.arg(server->errorString()));
close();
return;
}
QLabel *statusLabel = new QLabel;
statusLabel->setWordWrap(true);
statusLabel->setText(tr("The server is running.\n"
"Run the Local Fortune Client example now."));
stopListeningButton->setDisabled(true);
fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
<< tr("You've got to think about tomorrow.")
@ -33,28 +39,71 @@ Server::Server(QWidget *parent)
<< tr("You cannot kill time without injuring eternity.")
<< tr("Computers are not intelligent. They only think they are.");
QLabel *hostLabel = new QLabel(tr("Server name:"));
connect(server, &QLocalServer::newConnection, this, &Server::sendFortune);
connect(hostLineEdit, &QLineEdit::textChanged, this, &Server::toggleListenButton);
connect(listenButton, &QPushButton::clicked, this, &Server::listenToServer);
connect(stopListeningButton, &QPushButton::clicked,this, &Server::stopListening);
QPushButton *quitButton = new QPushButton(tr("Quit"));
quitButton->setAutoDefault(false);
connect(quitButton, &QPushButton::clicked, this, &Server::close);
connect(server, &QLocalServer::newConnection, this, &Server::sendFortune);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(quitButton);
buttonLayout->addStretch(1);
QDialogButtonBox *buttonBox = new QDialogButtonBox;
buttonBox->addButton(listenButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(stopListeningButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(buttonLayout);
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(hostLabel, 0, 0);
mainLayout->addWidget(hostLineEdit, 0, 1);
mainLayout->addWidget(statusLabel, 2, 0, 3, 2);
mainLayout->addWidget(buttonBox, 10, 0, 2, 2);
setWindowTitle(QGuiApplication::applicationDisplayName());
hostLineEdit->setFocus();
}
void Server::listenToServer()
{
name = hostLineEdit->text();
if (!server->listen(name)) {
QMessageBox::critical(this, tr("Local Fortune Server"),
tr("Unable to start the server: %1.")
.arg(server->errorString()));
name.clear();
return;
}
statusLabel->setText(tr("The server is running.\n"
"Run the Local Fortune Client example now."));
toggleListenButton();
}
void Server::stopListening()
{
server->close();
name.clear();
statusLabel->setText(idleStateText);
toggleListenButton();
}
void Server::toggleListenButton()
{
if (server->isListening()) {
listenButton->setDisabled(true);
stopListeningButton->setEnabled(true);
} else {
listenButton->setEnabled(!hostLineEdit->text().isEmpty());
stopListeningButton->setDisabled(true);
}
}
void Server::sendFortune()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_10);
out.setVersion(QDataStream::Qt_6_0);
const int fortuneIndex = QRandomGenerator::global()->bounded(0, fortunes.size());
const QString &message = fortunes.at(fortuneIndex);
out << quint32(message.size());

View File

@ -4,27 +4,33 @@
#ifndef SERVER_H
#define SERVER_H
#include <QApplication>
#include <QDialog>
QT_BEGIN_NAMESPACE
class QLabel;
class QPushButton;
class QLocalServer;
QT_END_NAMESPACE
#include <QLabel>
#include <QLineEdit>
#include <QLocalServer>
#include <QPushButton>
class Server : public QDialog
{
Q_OBJECT
Q_DECLARE_TR_FUNCTIONS(Server)
public:
explicit Server(QWidget *parent = nullptr);
private slots:
void sendFortune();
private:
void sendFortune();
void toggleListenButton();
void listenToServer();
void stopListening();
QLocalServer *server;
QLineEdit *hostLineEdit;
QLabel *statusLabel;
QPushButton *listenButton;
QPushButton *stopListeningButton;
QStringList fortunes;
QString name;
};
#endif

View File

@ -2,8 +2,12 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "dialog.h"
#include <QFileDialog>
#include <QBuffer>
#include <QFileDialog>
#include <QNativeIpcKey>
using namespace Qt::StringLiterals;
/*!
\class Dialog
@ -29,8 +33,9 @@
each button.
*/
//! [0]
Dialog::Dialog(QWidget *parent)
: QDialog(parent), sharedMemory("QSharedMemoryExample")
: QDialog(parent), sharedMemory(QNativeIpcKey(u"QSharedMemoryExample"_s))
{
ui.setupUi(this);
connect(ui.loadFromFileButton, &QPushButton::clicked,

View File

@ -6,6 +6,7 @@
#include <QDialog>
#include <QSharedMemory>
#include "ui_dialog.h"
//! [0]
@ -13,21 +14,21 @@ class Dialog : public QDialog
{
Q_OBJECT
public:
public:
Dialog(QWidget *parent = nullptr);
public slots:
public slots:
void loadFromFile();
void loadFromMemory();
private:
private:
void detach();
private:
private:
Ui::Dialog ui;
QSharedMemory sharedMemory;
};
//! [0]
#endif
#endif // DIALOG_H

View File

@ -1,9 +1,10 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "dialog.h"
#include <QApplication>
//! [0]
int main(int argc, char *argv[])
{

View File

@ -3,8 +3,9 @@
/*!
\example mimetypes/mimetypebrowser
\examplecategory {Data Processing & I/O}
\ingroup examples-mimetype
\title MIME Type Browser Example
\title MIME Type Browser
\brief Shows the hierarchy of MIME types and
can be used to determine the MIME type of a file.

View File

@ -4,10 +4,8 @@
#include "mainwindow.h"
#include <QApplication>
#include <QScreen>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QScreen>
int main(int argc, char *argv[])
{

View File

@ -4,23 +4,18 @@
#include "mainwindow.h"
#include "mimetypemodel.h"
#include <QAction>
#include <QApplication>
#include <QFileDialog>
#include <QFileInfo>
#include <QInputDialog>
#include <QItemSelectionModel>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QSplitter>
#include <QStatusBar>
#include <QTextEdit>
#include <QTreeView>
#include <QFileInfo>
#include <QItemSelectionModel>
#include <QMimeDatabase>
#include <QMimeType>
#include <QSplitter>
#include <QStatusBar>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@ -45,7 +40,8 @@ MainWindow::MainWindow(QWidget *parent)
findAction->setShortcuts(QKeySequence::Find);
m_findNextAction = findMenu->addAction(tr("Find &Next"), this, &MainWindow::findNext);
m_findNextAction->setShortcuts(QKeySequence::FindNext);
m_findPreviousAction = findMenu->addAction(tr("Find &Previous"), this, &MainWindow::findPrevious);
m_findPreviousAction = findMenu->addAction(tr("Find &Previous"), this,
&MainWindow::findPrevious);
m_findPreviousAction->setShortcuts(QKeySequence::FindPrevious);
menuBar()->addMenu(tr("&About"))->addAction(tr("&About Qt"), qApp, &QApplication::aboutQt);
@ -54,8 +50,8 @@ MainWindow::MainWindow(QWidget *parent)
setCentralWidget(centralSplitter);
m_treeView->setUniformRowHeights(true);
m_treeView->setModel(m_model);
const auto items = m_model->findItems("application/octet-stream", Qt::MatchContains | Qt::MatchFixedString | Qt::MatchRecursive);
const auto flags = Qt::MatchContains | Qt::MatchFixedString | Qt::MatchRecursive;
const auto items = m_model->findItems("application/octet-stream", flags);
if (!items.isEmpty())
m_treeView->expand(m_model->indexFromItem(items.constFirst()));
@ -93,7 +89,8 @@ void MainWindow::detectFile()
const QModelIndex index = mimeType.isValid()
? m_model->indexForMimeType(mimeType.name()) : QModelIndex();
if (index.isValid()) {
statusBar()->showMessage(tr("\"%1\" is of type \"%2\"").arg(fi.fileName(), mimeType.name()));
statusBar()->showMessage(tr("\"%1\" is of type \"%2\"").arg(fi.fileName(),
mimeType.name()));
selectAndGoTo(index);
} else {
QMessageBox::information(this, tr("Unknown File Type"),
@ -138,8 +135,8 @@ void MainWindow::find()
m_findMatches.clear();
m_findIndex = 0;
const QList<QStandardItem *> items =
m_model->findItems(value, Qt::MatchContains | Qt::MatchFixedString | Qt::MatchRecursive);
const auto flags = Qt::MatchContains | Qt::MatchFixedString | Qt::MatchRecursive;
const QList<QStandardItem *> items = m_model->findItems(value, flags);
for (const QStandardItem *item : items)
m_findMatches.append(m_model->indexFromItem(item));
statusBar()->showMessage(tr("%n mime types match \"%1\".", 0, m_findMatches.size()).arg(value));

View File

@ -4,12 +4,11 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QAction>
#include <QMainWindow>
#include <QModelIndexList>
QT_FORWARD_DECLARE_CLASS(QAction)
QT_FORWARD_DECLARE_CLASS(QTextEdit)
QT_FORWARD_DECLARE_CLASS(QTreeView)
#include <QTextEdit>
#include <QTreeView>
class MimetypeModel;

View File

@ -4,14 +4,14 @@
#ifndef MIMETYPEMODEL_H
#define MIMETYPEMODEL_H
#include <QStandardItemModel>
#include <QCoreApplication>
#include <QHash>
QT_FORWARD_DECLARE_CLASS(QMimeType)
#include <QMimeType>
#include <QStandardItemModel>
class MimetypeModel : public QStandardItemModel
{
Q_OBJECT
Q_DECLARE_TR_FUNCTIONS(MimetypeModel)
public:
enum Columns { NameColumn, ColumnCount };

View File

@ -5,6 +5,7 @@
\title Qt Android Notifier
\example platform/androidnotifier
\examplecategory {Mobile}
\brief Demonstrates calling Java code from Qt in an Android application.
\ingroup androidplatform

View File

@ -20,13 +20,14 @@ qt_standard_project_setup()
qt_add_executable(convert
cborconverter.cpp cborconverter.h
converter.h
converter.cpp converter.h
datastreamconverter.cpp datastreamconverter.h
debugtextdumper.cpp debugtextdumper.h
jsonconverter.cpp jsonconverter.h
main.cpp
nullconverter.cpp nullconverter.h
textconverter.cpp textconverter.h
variantorderedmap.h
xmlconverter.cpp xmlconverter.h
)

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "cborconverter.h"
#include "variantorderedmap.h"
#include <QCborArray>
#include <QCborMap>
@ -9,6 +10,7 @@
#include <QCborStreamWriter>
#include <QCborValue>
#include <QDataStream>
#include <QDebug>
#include <QFile>
#include <QFloat16>
#include <QMetaType>
@ -57,9 +59,9 @@ QT_END_NAMESPACE
// non-string keys in CBOR maps (QVariantMap can't handle those). Instead, we
// have our own set of converter functions so we can keep the keys properly.
//! [0]
static QVariant convertCborValue(const QCborValue &value);
//! [0]
static QVariant convertCborMap(const QCborMap &map)
{
VariantOrderedMap result;
@ -87,8 +89,9 @@ static QVariant convertCborValue(const QCborValue &value)
return value.toVariant();
}
//! [0]
enum TrimFloatingPoint { Double, Float, Float16 };
//! [1]
enum TrimFloatingPoint { Double, Float, Float16 };
static QCborValue convertFromVariant(const QVariant &v, TrimFloatingPoint fpTrimming)
{
if (v.userType() == QMetaType::QVariantList) {
@ -140,20 +143,6 @@ const char *CborDiagnosticDumper::optionsHelp() const
return diagnosticHelp;
}
bool CborDiagnosticDumper::probeFile(QIODevice *f) const
{
Q_UNUSED(f);
return false;
}
QVariant CborDiagnosticDumper::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
Q_UNREACHABLE();
Q_UNUSED(f);
Q_UNUSED(outputConverter);
return QVariant();
}
void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{
@ -178,9 +167,8 @@ void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents,
}
}
fprintf(stderr, "Unknown CBOR diagnostic option '%s'. Available options are:\n%s",
qPrintable(s), diagnosticHelp);
exit(EXIT_FAILURE);
qFatal("Unknown CBOR diagnostic option '%s'. Available options are:\n%s",
qPrintable(s), diagnosticHelp);
}
QTextStream out(f);
@ -221,7 +209,6 @@ bool CborConverter::probeFile(QIODevice *f) const
return f->isReadable() && f->peek(3) == QByteArray("\xd9\xd9\xf7", 3);
}
//! [2]
QVariant CborConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
const char *ptr = nullptr;
@ -239,28 +226,25 @@ QVariant CborConverter::loadFile(QIODevice *f, const Converter *&outputConverter
QCborValue contents = QCborValue::fromCbor(reader);
qint64 offset = reader.currentOffset();
if (reader.lastError()) {
fprintf(stderr, "Error loading CBOR contents (byte %lld): %s\n", offset,
qPrintable(reader.lastError().toString()));
fprintf(stderr, " bytes: %s\n",
(ptr ? mapped.mid(offset, 9) : f->read(9)).toHex(' ').constData());
exit(EXIT_FAILURE);
qFatal().nospace()
<< "Error loading CBOR contents (byte " << offset
<< "): " << reader.lastError().toString()
<< "\n bytes: " << (ptr ? mapped.mid(offset, 9) : f->read(9));
} else if (offset < mapped.size() || (!ptr && f->bytesAvailable())) {
fprintf(stderr, "Warning: bytes remaining at the end of the CBOR stream\n");
qWarning("Warning: bytes remaining at the end of the CBOR stream");
}
if (outputConverter == nullptr)
outputConverter = &cborDiagnosticDumper;
else if (outputConverter == null)
else if (isNull(outputConverter))
return QVariant();
else if (!outputConverter->outputOptions().testFlag(SupportsArbitraryMapKeys))
return contents.toVariant();
return convertCborValue(contents);
}
//! [2]
//! [3]
void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) const
{
//! [3]
bool useSignature = true;
bool useIntegers = true;
enum { Yes, No, Always } useFloat16 = Yes, useFloat = Yes;
@ -315,11 +299,10 @@ void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStri
}
}
fprintf(stderr, "Unknown CBOR format option '%s'. Valid options are:\n%s",
qPrintable(s), cborOptionHelp);
exit(EXIT_FAILURE);
qFatal("Unknown CBOR format option '%s'. Valid options are:\n%s",
qPrintable(s), cborOptionHelp);
}
//! [4]
QCborValue v =
convertFromVariant(contents,
useFloat16 == Always ? Float16 : useFloat == Always ? Float : Double);
@ -336,4 +319,3 @@ void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStri
opts |= QCborValue::UseFloat16;
v.toCbor(writer, opts);
}
//! [4]

View File

@ -14,8 +14,6 @@ public:
Directions directions() const override;
Options outputOptions() const override;
const char *optionsHelp() const override;
bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
};

View File

@ -11,6 +11,7 @@ target.path = $$[QT_INSTALL_EXAMPLES]/corelib/serialization/convert
INSTALLS += target
SOURCES += main.cpp \
converter.cpp \
cborconverter.cpp \
datastreamconverter.cpp \
debugtextdumper.cpp \
@ -27,4 +28,5 @@ HEADERS += \
jsonconverter.h \
nullconverter.h \
textconverter.h \
variantorderedmap.h \
xmlconverter.h

View File

@ -0,0 +1,44 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "converter.h"
//! [0]
Converter::Converter()
{
converters().append(this);
}
Converter::~Converter()
{
converters().removeAll(this);
}
QList<const Converter *> &Converter::converters()
{
Q_CONSTINIT static QList<const Converter *> store;
return store;
}
const QList<const Converter *> &Converter::allConverters()
{
return converters();
}
//! [0]
// Some virtual methods that Converter classes needn't override, when not relevant:
Converter::Options Converter::outputOptions() const { return {}; }
const char *Converter::optionsHelp() const { return nullptr; }
bool Converter::probeFile(QIODevice *) const { return false; }
// The virtual method they should override if they claim to support In:
QVariant Converter::loadFile(QIODevice *, const Converter *&outputConverter) const
{
Q_ASSERT(!directions().testFlag(Converter::Direction::In));
// For those that don't, this should never be called.
Q_UNIMPLEMENTED();
// But every implementation should at least do this:
if (!outputConverter)
outputConverter = this;
return QVariant();
}

View File

@ -6,31 +6,19 @@
#include <QIODevice>
#include <QList>
#include <QPair>
#include <QStringList>
#include <QVariant>
#include <QVariantMap>
class VariantOrderedMap : public QList<QPair<QVariant, QVariant>>
{
public:
VariantOrderedMap() = default;
VariantOrderedMap(const QVariantMap &map)
{
reserve(map.size());
for (auto it = map.begin(); it != map.end(); ++it)
append({it.key(), it.value()});
}
};
using Map = VariantOrderedMap;
Q_DECLARE_METATYPE(Map)
//! [0]
class Converter
{
static QList<const Converter *> &converters();
protected:
Converter();
static bool isNull(const Converter *converter); // in nullconverter.cpp
public:
static Converter *null;
static const QList<const Converter *> &allConverters();
enum class Direction { In = 1, Out = 2, InOut = In | Out };
Q_DECLARE_FLAGS(Directions, Direction)
@ -42,15 +30,16 @@ public:
virtual QString name() const = 0;
virtual Directions directions() const = 0;
virtual Options outputOptions() const = 0;
virtual const char *optionsHelp() const = 0;
virtual bool probeFile(QIODevice *f) const = 0;
virtual QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const = 0;
virtual Options outputOptions() const;
virtual const char *optionsHelp() const;
virtual bool probeFile(QIODevice *f) const;
virtual QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const;
virtual void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Options)
//! [0]
#endif // CONVERTER_H

View File

@ -3,6 +3,7 @@
#include "datastreamconverter.h"
#include "debugtextdumper.h"
#include "variantorderedmap.h"
#include <QDataStream>
@ -79,10 +80,8 @@ QVariant DataStreamConverter::loadFile(QIODevice *f, const Converter *&outputCon
outputConverter = &debugTextDumper;
char c;
if (f->read(sizeof(signature) - 1) != signature || !f->getChar(&c) || (c != 'l' && c != 'B')) {
fprintf(stderr, "Could not load QDataStream file: invalid signature.\n");
exit(EXIT_FAILURE);
}
if (f->read(sizeof(signature) - 1) != signature || !f->getChar(&c) || (c != 'l' && c != 'B'))
qFatal("Could not load QDataStream file: invalid signature.");
QDataStream ds(f);
ds.setByteOrder(c == 'l' ? QDataStream::LittleEndian : QDataStream::BigEndian);
@ -124,15 +123,13 @@ void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents,
continue;
}
fprintf(stderr, "Invalid version number '%s': must be a number from 1 to %d.\n",
qPrintable(pair.last()), QDataStream::Qt_DefaultCompiledVersion);
exit(EXIT_FAILURE);
qFatal("Invalid version number '%s': must be a number from 1 to %d.",
qPrintable(pair.last()), QDataStream::Qt_DefaultCompiledVersion);
}
}
fprintf(stderr, "Unknown QDataStream formatting option '%s'. Available options are:\n%s",
qFatal("Unknown QDataStream formatting option '%s'. Available options are:\n%s",
qPrintable(option), dataStreamOptionHelp);
exit(EXIT_FAILURE);
}
char c = order == QDataStream::LittleEndian ? 'l' : 'B';

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "debugtextdumper.h"
#include "variantorderedmap.h"
#include <QDebug>
#include <QTextStream>
@ -58,29 +59,13 @@ Converter::Options DebugTextDumper::outputOptions() const
return SupportsArbitraryMapKeys;
}
const char *DebugTextDumper::optionsHelp() const
{
return nullptr;
}
bool DebugTextDumper::probeFile(QIODevice *f) const
{
Q_UNUSED(f);
return false;
}
QVariant DebugTextDumper::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
Q_UNREACHABLE();
Q_UNUSED(f);
Q_UNUSED(outputConverter);
return QVariant();
}
void DebugTextDumper::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{
Q_UNUSED(options);
if (!options.isEmpty()) {
qFatal("Unknown option '%s' to debug text output. This format has no options.",
qPrintable(options.first()));
}
QString s = dumpVariant(contents);
s[s.size() - 1] = u'\n'; // replace the comma with newline

View File

@ -13,9 +13,6 @@ public:
QString name() const override;
Directions directions() const override;
Options outputOptions() const override;
const char *optionsHelp() const override;
bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -5,78 +5,152 @@
\example serialization/convert
\examplecategory {Data Processing & I/O}
\meta tag {network}
\title Convert Example
\title Serialization Converter
\brief The Convert example demonstrates how to convert between different
serialization formats.
\brief How to convert between different serialization formats.
The Convert example converts between the serialization formats JSON, CBOR,
XML, QDataStream and text. It can also auto detect the format being used.
Not all formats support both input and output, and they have different
sets of which types they support. QDataStream and XML are the richest,
followed by CBOR, then JSON, and then the plain text one.
This example converts between JSON, CBOR, XML, QDataStream and some simple
text formats. It can auto-detect the format being used, or be told which
format to use. Not all formats support both input and output, and they have
different sets of which content datatypes they support. QDataStream and XML
are the richest, followed by CBOR, then JSON, and then the plain text
formats. Conversion via the less capable formats is apt to lose structure
from the data.
\image convert.png
\sa {Parsing and displaying CBOR data}, {JSON Save Game}
\section1 The Converter Class
The Converter class is the abstract superclass for all the converters to
and from all the formats. They all convert to and from the QVariant class,
which is used to represent all the datastructures internally.
The Converter class is the abstract superclass for all the converters to and
from all the formats. They all convert from or to the QVariant class, which
is used to represent all the datastructures internally.
\snippet serialization/convert/converter.h 0
The Converter constructor and destructor manage a list of available
converters used by the main program so that it knows what converters are
available. Each converter type defines a static instance that ensures it is
constructed and thus available to the main program via this list. The \c
allConverters() method provides \c main()'s code with access to the list.
\snippet serialization/convert/converter.cpp 0
The name() function returns the name of the converter. The directions()
function is used to determine if a converter can be used for input, output,
or both. The outputOptions() and optionsHelp() functions are used to get
and query which options are used by the different converters. The
probeFile() function is used to determine if a file has the same file
format as the converter. The loadFile() function deserializes the given
file, while the saveFile() serializes to the given file.
or both. These enable the main program to report what converters are
available in its help text for the command-line options to select input and
output formats.
\section1 The CborConverter Class
\snippet serialization/convert/main.cpp 0
The optionsHelp() function is used to report the various command-line
options supported by the available formats, when queried using its \c
{--format-options <format>} command-line option.
\snippet serialization/convert/main.cpp 1
The outputOptions() function reports the output capabilities of a converter.
At present the only optional feature is support for arbitrary keys in
mappings from keys to values. An input converter's loadFile() can use this
information to tailor the form in which it presents the data it has read, to
be as faithfully represented by the output converter as its capabilities
permit.
The probeFile() function is used to determine if a file matches the format
of the converter. The main program uses this to determine what format to use
when reading or writing a file, based on its name and potentially content,
when the user has not specified the format to use on the command-line.
The loadFile() function deserializes data. The caller tells loadFile() which
serializer it intends to use, so that loadFile() can query its
outputOptions() to determine the form in which to represent the loaded data.
If the caller hasn't settled on a choice of output converter, loadFile()
supplies it with a default output converter suitable to the data it is
returning.
The saveFile() function serializes data. It is passed options from the
command-line, as described by loadHelp(), that can tune the details of how
it represents the data when saving to file.
Both loadFile() and saveFile() can be used with an arbitrary \l QIODevice.
This means that a Converter could also be used with a network socket or
other source of data, to read from or write to. In the present program, the
main program always passes a \l QFile, accessing either a file on disk or
one of the standard streams of the process.
\section2 The Available Converters
Several converters are supported, illustrating how the converter program
could be adapted to other formats, should the need arise. See the source
code for each for its details. The CBOR converters serve as a relatively
full-featured illustration of the ways converters can work, that we'll look
into in more detail below. This table summarizes the available converters:
\table
\header \li Class \li mode \li format
\row \li CborConverter \li In/Out \li CBOR
\row \li CborDiagnosticDumper \li Out \li CBOR diagnostic
\row \li DataStreamConverter \li In/Out \li QDataStream
\row \li DebugTextDumper \li Out \li Lossless, non-standard, human-readable
\row \li JsonConverter \li In/Out \li JSON
\row \li NullConverter \li Out \li No output
\row \li TextConverter \li In/Out \li Structured plain text
\row \li XmlConverter \li In/Out \li XML
\endtable
Those that support input use themselves as loadFile()'s fallback converter,
except for the CBOR and QDataStream converters, which use their respective
output-only dumper companion classes. The null converter can be used as
output converter when running the program for the sake of any validation or
verification that an input converter may perform.
\section2 The CborConverter and CborDiagnosticDumper Classes
The CborConverter class supports serializing to and from the CBOR format.
It supports various options to configure the output of floating point values
and a \c{signature} option to determine whether to start its output with a
CBOR tag that serves as a file header, identifying the file as containing
CBOR data.
The CborConverter class shows how to serialize to and from the CBOR-format.
There is also a CborDiagnosticDumper class to output in CBOR diagnostic
notation. That is similar to JSON, but not exactly, because it allows
displaying the contents of a CBOR stream losslessly, while a conversion
to JSON is lossy.
notation. It does not support loading data. The form of its output can be
configured using two options. One selects whether to use the (more verbose)
extended CBOR diagnostic format. The other control whether each CBOR value
appears on a separate line.
The plain diagnostic notation is similar to JSON, but not exactly, because
it supports displaying the contents of a CBOR stream losslessly, while a
conversion to JSON can be lossy. CborConverter's loadFile() uses
CborDiagnosticDumper for the fallback output converter, if its caller hasn't
determined the output format for itself.
The convertCborValue(), convertCborMap() and convertCborArray() helper
functions are used to convert a QCborValue to a QVariant, for the benefit of
CborConverter::loadFile().
The convertCborValue() function is used to convert a QCborValue to a
QVariant. It uses the helper functions convertCborMap() and
convertCborArray().
\snippet serialization/convert/cborconverter.cpp 0
A CBOR-file is read using loadFile() function.
\snippet serialization/convert/cborconverter.cpp 2
The convertFromVariant() function is used to convert a QVariant to a
QCborValue.
\snippet serialization/convert/cborconverter.cpp 1
QCborValue for output by the \c saveFile() of either class.
A CBOR-file is written using the saveFile() function.
\snippet serialization/convert/cborconverter.cpp 3
\snippet serialization/convert/cborconverter.cpp 4
\snippet serialization/convert/cborconverter.cpp 1
\sa {CBOR Support in Qt}
\section1 The DataStreamConverter Class
\section1 The convert program
The DataStreamConverter class is used to serialize to and from the
QDataStream format. There is also the DebugTextDumper class for outputting
the data lossless in a non-standardized human readable format.
The \c main() function sets up a \l QApplication and a \l QCommandLineParser
to make sense of the options the user has specified and provide help if the
user asks for it. It uses the values obtained for the various \l
QCommandLineOption instances describing the user's choices, plus the
positional arguments for file names, to prepare the converters it will use.
\section1 The JsonConverter Class
It then uses its input converter to load data (and possibly resolve its
choice of output converter, if it hasn't selected one yet) and its output
converter to serialize that data, taking account of any output options the
user has supplied on the command-line.
The JsonConverter class is used to serialize to and from the JSON-format.
\sa {JSON Support in Qt}
\section1 The XmlConverter Class
The XmlConverter class is used to serialize to and from the XML-format.
\section1 The TextConverter Class
The TextConverter class is used to serialize to and from a text format.
\section1 The NullConverter Class
The NullConverter class is an output serializer that does nothing.
\snippet serialization/convert/main.cpp 2
*/

View File

@ -18,10 +18,8 @@ static const char jsonOptionHelp[] = "compact=no|yes Use compact JS
static QJsonDocument convertFromVariant(const QVariant &v)
{
QJsonDocument doc = QJsonDocument::fromVariant(v);
if (!doc.isObject() && !doc.isArray()) {
fprintf(stderr, "Could not convert contents to JSON.\n");
exit(EXIT_FAILURE);
}
if (!doc.isObject() && !doc.isArray())
qFatal("Could not convert contents to JSON.");
return doc;
}
@ -35,11 +33,6 @@ Converter::Directions JsonConverter::directions() const
return Direction::InOut;
}
Converter::Options JsonConverter::outputOptions() const
{
return {};
}
const char *JsonConverter::optionsHelp() const
{
return jsonOptionHelp;
@ -75,11 +68,10 @@ QVariant JsonConverter::loadFile(QIODevice *f, const Converter *&outputConverter
if (doc.isNull())
doc = QJsonDocument::fromJson(f->readAll(), &error);
if (error.error) {
fprintf(stderr, "Could not parse JSON content: offset %d: %s",
error.offset, qPrintable(error.errorString()));
exit(EXIT_FAILURE);
qFatal("Could not parse JSON content: offset %d: %s",
error.offset, qPrintable(error.errorString()));
}
if (outputConverter == null)
if (isNull(outputConverter))
return QVariant();
return doc.toVariant();
}
@ -94,9 +86,8 @@ void JsonConverter::saveFile(QIODevice *f, const QVariant &contents,
} else if (s == "compact=yes"_L1) {
format = QJsonDocument::Compact;
} else {
fprintf(stderr, "Unknown option '%s' to JSON output. Valid options are:\n%s",
qPrintable(s), jsonOptionHelp);
exit(EXIT_FAILURE);
qFatal("Unknown option '%s' to JSON output. Valid options are:\n%s",
qPrintable(s), jsonOptionHelp);
}
}

View File

@ -12,7 +12,6 @@ class JsonConverter : public Converter
public:
QString name() const override;
Directions directions() const override;
Options outputOptions() const override;
const char *optionsHelp() const override;
bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;

View File

@ -1,4 +1,5 @@
// Copyright (C) 2018 Intel Corporation.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "converter.h"
@ -13,27 +14,57 @@
using namespace Qt::StringLiterals;
static QList<const Converter *> *availableConverters;
Converter::Converter()
static const Converter *prepareConverter(QString format, Converter::Direction direction,
QFile *stream)
{
if (!availableConverters)
availableConverters = new QList<const Converter *>;
availableConverters->append(this);
}
const bool out = direction == Converter::Direction::Out;
const QIODevice::OpenMode mode = out
? QIODevice::WriteOnly | QIODevice::Truncate
: QIODevice::ReadOnly;
const char *dirn = out ? "output" : "input";
Converter::~Converter()
{
availableConverters->removeAll(this);
if (stream->fileName().isEmpty())
stream->open(out ? stdout : stdin, mode);
else
stream->open(mode);
if (!stream->isOpen()) {
qFatal("Could not open \"%s\" for %s: %s",
qPrintable(stream->fileName()), dirn, qPrintable(stream->errorString()));
} else if (format == "auto"_L1) {
for (const Converter *conv : Converter::allConverters()) {
if (conv->directions().testFlag(direction) && conv->probeFile(stream))
return conv;
}
if (out) // Failure to identify output format can be remedied by loadFile().
return nullptr;
// Input format, however, we must know before we can call that:
qFatal("Could not determine input format. Specify it with the -I option.");
} else {
for (const Converter *conv : Converter::allConverters()) {
if (conv->name() == format) {
if (!conv->directions().testFlag(direction)) {
qWarning("File format \"%s\" cannot be used for %s",
qPrintable(format), dirn);
continue; // on the off chance there's another with the same name
}
return conv;
}
}
qFatal("Unknown %s file format \"%s\"", dirn, qPrintable(format));
}
Q_UNREACHABLE_RETURN(nullptr);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
//! [0]
QStringList inputFormats;
QStringList outputFormats;
for (const Converter *conv : std::as_const(*availableConverters)) {
for (const Converter *conv : Converter::allConverters()) {
auto direction = conv->directions();
QString name = conv->name();
if (direction.testFlag(Converter::Direction::In))
@ -41,13 +72,14 @@ int main(int argc, char *argv[])
if (direction.testFlag(Converter::Direction::Out))
outputFormats << name;
}
//! [0]
inputFormats.sort();
outputFormats.sort();
inputFormats.prepend("auto"_L1);
outputFormats.prepend("auto"_L1);
QCommandLineParser parser;
parser.setApplicationDescription("Qt file format conversion tool"_L1);
parser.setApplicationDescription("Qt serialization format conversion tool"_L1);
parser.addHelpOption();
QCommandLineOption inputFormatOption(QStringList{ "I"_L1, "input-format"_L1 });
@ -86,110 +118,38 @@ int main(int argc, char *argv[])
if (parser.isSet(formatOptionsOption)) {
QString format = parser.value(formatOptionsOption);
for (const Converter *conv : std::as_const(*availableConverters)) {
//! [1]
for (const Converter *conv : Converter::allConverters()) {
if (conv->name() == format) {
const char *help = conv->optionsHelp();
if (help) {
printf("The following options are available for format '%s':\n\n%s",
qPrintable(format), help);
qInfo("The following options are available for format '%s':\n\n%s",
qPrintable(format), help);
} else {
printf("Format '%s' supports no options.\n", qPrintable(format));
qInfo("Format '%s' supports no options.", qPrintable(format));
}
return EXIT_SUCCESS;
}
}
//! [1]
fprintf(stderr, "Unknown file format '%s'\n", qPrintable(format));
return EXIT_FAILURE;
}
const Converter *inconv = nullptr;
QString format = parser.value(inputFormatOption);
if (format != "auto"_L1) {
for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->name() == format) {
inconv = conv;
break;
}
}
if (!inconv) {
fprintf(stderr, "Unknown file format \"%s\"\n", qPrintable(format));
return EXIT_FAILURE;
}
}
const Converter *outconv = nullptr;
format = parser.value(outputFormatOption);
if (format != "auto"_L1) {
for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->name() == format) {
outconv = conv;
break;
}
}
if (!outconv) {
fprintf(stderr, "Unknown file format \"%s\"\n", qPrintable(format));
return EXIT_FAILURE;
}
qFatal("Unknown file format '%s'", qPrintable(format));
}
//! [2]
QStringList files = parser.positionalArguments();
QFile input(files.value(0));
QFile output(files.value(1));
const Converter *inconv = prepareConverter(parser.value(inputFormatOption),
Converter::Direction::In, &input);
const Converter *outconv = prepareConverter(parser.value(outputFormatOption),
Converter::Direction::Out, &output);
if (input.fileName().isEmpty())
input.open(stdin, QIODevice::ReadOnly);
else
input.open(QIODevice::ReadOnly);
if (!input.isOpen()) {
fprintf(stderr, "Could not open \"%s\" for reading: %s\n",
qPrintable(input.fileName()), qPrintable(input.errorString()));
return EXIT_FAILURE;
}
if (output.fileName().isEmpty())
output.open(stdout, QIODevice::WriteOnly | QIODevice::Truncate);
else
output.open(QIODevice::WriteOnly | QIODevice::Truncate);
if (!output.isOpen()) {
fprintf(stderr, "Could not open \"%s\" for writing: %s\n",
qPrintable(output.fileName()), qPrintable(output.errorString()));
return EXIT_FAILURE;
}
if (!inconv) {
// probe the input to find a file format
for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->directions().testFlag(Converter::Direction::In)
&& conv->probeFile(&input)) {
inconv = conv;
break;
}
}
if (!inconv) {
fprintf(stderr, "Could not determine input format. pass -I option.\n");
return EXIT_FAILURE;
}
}
if (!outconv) {
// probe the output to find a file format
for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->directions().testFlag(Converter::Direction::Out)
&& conv->probeFile(&output)) {
outconv = conv;
break;
}
}
}
// now finally perform the conversion
// Now finally perform the conversion:
QVariant data = inconv->loadFile(&input, outconv);
Q_ASSERT_X(outconv, "Converter Tool",
Q_ASSERT_X(outconv, "Serialization Converter",
"Internal error: converter format did not provide default");
outconv->saveFile(&output, data, parser.values(optionOption));
return EXIT_SUCCESS;
//! [2]
}

View File

@ -6,7 +6,10 @@
using namespace Qt::StringLiterals;
static NullConverter nullConverter;
Converter *Converter::null = &nullConverter;
bool Converter::isNull(const Converter *converter)
{
return converter == &nullConverter;
}
QString NullConverter::name() const
{
@ -23,32 +26,12 @@ Converter::Options NullConverter::outputOptions() const
return SupportsArbitraryMapKeys;
}
const char *NullConverter::optionsHelp() const
{
return nullptr;
}
bool NullConverter::probeFile(QIODevice *f) const
{
Q_UNUSED(f);
return false;
}
QVariant NullConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
Q_UNUSED(f);
Q_UNUSED(outputConverter);
outputConverter = this;
return QVariant();
}
void NullConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{
if (!options.isEmpty()) {
fprintf(stderr, "Unknown option '%s' to null output. This format has no options.\n",
qPrintable(options.first()));
exit(EXIT_FAILURE);
qFatal("Unknown option '%s' to null output. This format has no options.",
qPrintable(options.first()));
}
Q_UNUSED(f);

View File

@ -13,9 +13,6 @@ public:
QString name() const override;
Directions directions() const override;
Options outputOptions() const override;
const char *optionsHelp() const override;
bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
};

View File

@ -54,16 +54,6 @@ Converter::Directions TextConverter::directions() const
return Direction::InOut;
}
Converter::Options TextConverter::outputOptions() const
{
return {};
}
const char *TextConverter::optionsHelp() const
{
return nullptr;
}
bool TextConverter::probeFile(QIODevice *f) const
{
if (QFile *file = qobject_cast<QFile *>(f))
@ -98,9 +88,8 @@ void TextConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{
if (!options.isEmpty()) {
fprintf(stderr, "Unknown option '%s' to text output. This format has no options.\n",
qPrintable(options.first()));
exit(EXIT_FAILURE);
qFatal("Unknown option '%s' to text output. This format has no options.",
qPrintable(options.first()));
}
QTextStream out(f);

View File

@ -12,8 +12,6 @@ class TextConverter : public Converter
public:
QString name() const override;
Directions directions() const override;
Options outputOptions() const override;
const char *optionsHelp() const override;
bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents,

View File

@ -0,0 +1,24 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef VARIANTORDEREDMAP_H
#define VARIANTORDEREDMAP_H
#include <QList>
#include <QPair>
#include <QVariant>
#include <QVariantMap>
class VariantOrderedMap : public QList<QPair<QVariant, QVariant>>
{
public:
VariantOrderedMap() = default;
VariantOrderedMap(const QVariantMap &map)
{
reserve(map.size());
for (auto it = map.begin(); it != map.end(); ++it)
append({it.key(), it.value()});
}
};
#endif // VARIANTORDEREDMAP_H

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "xmlconverter.h"
#include "variantorderedmap.h"
#include <QBitArray>
#include <QtCborCommon>
@ -48,9 +49,8 @@ static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options option
break;
}
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
}
xml.readNext();
@ -90,9 +90,8 @@ static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml,
break;
}
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
}
return { key, value };
@ -134,9 +133,8 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
break;
}
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
}
xml.readNext();
@ -153,9 +151,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
if (name == "map"_L1)
return mapFromXml(xml, options);
if (name != "value"_L1) {
fprintf(stderr, "%lld:%lld: Invalid XML key '%s'.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(name.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML key '%s'.",
xml.lineNumber(), xml.columnNumber(), qPrintable(name.toString()));
}
QXmlStreamAttributes attrs = xml.attributes();
@ -168,9 +165,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
if (xml.isCDATA() || xml.isCharacters() || xml.isEndElement())
break;
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(name.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(name.toString()));
}
QStringView text = xml.text();
@ -190,9 +186,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
// let's see floating point
double d = text.toDouble(&ok);
if (!ok) {
fprintf(stderr, "%lld:%lld: Invalid XML: could not interpret '%s' as a number.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML: could not interpret '%s' as a number.",
xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
}
result = d;
}
@ -206,9 +201,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
} else if (encoding.isEmpty() || encoding == "base64"_L1) {
result = QByteArray::fromBase64(data);
} else {
fprintf(stderr, "%lld:%lld: Invalid XML: unknown encoding '%s' for bytes.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(encoding.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML: unknown encoding '%s' for bytes.",
xml.lineNumber(), xml.columnNumber(), qPrintable(encoding.toString()));
}
} else if (type == "string"_L1) {
result = text.toString();
@ -227,9 +221,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
} else if (c == '0') {
++n;
} else if (!c.isSpace()) {
fprintf(stderr, "%lld:%lld: Invalid XML: invalid bit string '%s'.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML: invalid bit string '%s'.",
xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
}
}
ba.resize(n);
@ -247,16 +240,14 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
else
id = QMetaType::fromName(type.toLatin1()).id();
if (id == QMetaType::UnknownType) {
fprintf(stderr, "%lld:%lld: Invalid XML: unknown type '%s'.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML: unknown type '%s'.",
xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
}
result = text.toString();
if (!result.convert(QMetaType(id))) {
fprintf(stderr, "%lld:%lld: Invalid XML: could not parse content as type '%s'.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML: could not parse content as type '%s'.",
xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
}
}
@ -265,9 +256,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
} while (xml.isComment() || xml.isWhitespace());
if (!xml.isEndElement()) {
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(name.toString()));
exit(EXIT_FAILURE);
qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(name.toString()));
}
xml.readNext();
@ -387,8 +377,7 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
xml.writeAttribute(typeString, QString::fromLatin1(typeName));
xml.writeCharacters(copy.toString());
} else {
fprintf(stderr, "XML: don't know how to serialize type '%s'.\n", typeName);
exit(EXIT_FAILURE);
qFatal("XML: don't know how to serialize type '%s'.", typeName);
}
}
}
@ -434,10 +423,8 @@ QVariant XmlConverter::loadFile(QIODevice *f, const Converter *&outputConverter)
QXmlStreamReader xml(f);
xml.readNextStartElement();
QVariant v = variantFromXml(xml, outputConverter->outputOptions());
if (xml.hasError()) {
fprintf(stderr, "XML error: %s", qPrintable(xml.errorString()));
exit(EXIT_FAILURE);
}
if (xml.hasError())
qFatal("XML error: %s", qPrintable(xml.errorString()));
return v;
}
@ -452,9 +439,8 @@ void XmlConverter::saveFile(QIODevice *f, const QVariant &contents,
} else if (s == "compact=yes"_L1) {
compact = true;
} else {
fprintf(stderr, "Unknown option '%s' to XML output. Valid options are:\n%s",
qPrintable(s), xmlOptionHelp);
exit(EXIT_FAILURE);
qFatal("Unknown option '%s' to XML output. Valid options are:\n%s",
qPrintable(s), xmlOptionHelp);
}
}

View File

@ -4,10 +4,9 @@
/*!
\example serialization/savegame
\examplecategory {Data Processing & I/O}
\title JSON Save Game Example
\title Saving and Loading a Game
\brief The JSON Save Game example demonstrates how to save and load a
small game using QJsonDocument, QJsonObject and QJsonArray.
\brief How to save and load a game using Qt's JSON or CBOR classes.
Many games provide save functionality, so that the player's progress through
the game can be saved and loaded at a later time. The process of saving a

View File

@ -3,6 +3,7 @@
/*!
\example threads/mandelbrot
\examplecategory {Data Processing & I/O}
\title Mandelbrot
\ingroup qtconcurrent-mtexamples

View File

@ -3,8 +3,8 @@
/*!
\example threads/queuedcustomtype
\title Queued Custom Type Example
\brief Demonstrates multi-thread programming using Qt.
\examplecategory {Data Processing & I/O}
\title Queued Custom Type
\ingroup qtconcurrent-mtexamples
\brief The Queued Custom Type example shows how to send custom types between

View File

@ -3,13 +3,13 @@
/*!
\example threads/semaphores
\title Semaphores Example
\brief Demonstrates multi-thread programming using Qt.
\examplecategory {Data Processing & I/O}
\title Producer and Consumer using Semaphores
\ingroup qtconcurrent-mtexamples
\brief The Semaphores example shows how to use QSemaphore to control
access to a circular buffer shared by a producer thread and a
consumer thread.
\brief The Producer and Consumer using Semaphores example shows how
to use QSemaphore to control access to a circular buffer shared
by a producer thread and a consumer thread.
The producer writes data to the buffer until it reaches the end
of the buffer, at which point it restarts from the beginning,
@ -30,7 +30,7 @@
An alternative to using QSemaphore to solve the producer-consumer
problem is to use QWaitCondition and QMutex. This is what the
\l{Wait Conditions Example} does.
\l{Producer and Consumer using Wait Conditions} example does.
\section1 Global Variables

View File

@ -3,13 +3,13 @@
/*!
\example threads/waitconditions
\title Wait Conditions Example
\brief Demonstrates multi-thread programming using Qt.
\examplecategory {Data Processing & I/O}
\title Producer and Consumer using Wait Conditions
\ingroup qtconcurrent-mtexamples
\brief The Wait Conditions example shows how to use QWaitCondition and
QMutex to control access to a circular buffer shared by a
producer thread and a consumer thread.
\brief The Producer and Consumer using Wait Conditions example shows
how to use QWaitCondition and QMutex to control access to a circular
buffer shared by a producer thread and a consumer thread.
The producer writes data to the buffer until it reaches the end
of the buffer, at which point it restarts from the beginning,
@ -30,7 +30,7 @@
An alternative to using QWaitCondition and QMutex to solve the
producer-consumer problem is to use QSemaphore. This is what the
\l{Semaphores Example} does.
\l{Producer and Consumer using Semaphores} example does.
\section1 Global Variables

View File

@ -6,6 +6,7 @@
#include "renderthread.h"
#include <QCoreApplication>
#include <QPixmap>
#include <QWidget>
@ -16,7 +17,7 @@ QT_END_NAMESPACE
//! [0]
class MandelbrotWidget : public QWidget
{
Q_OBJECT
Q_DECLARE_TR_FUNCTIONS(MandelbrotWidget)
public:
MandelbrotWidget(QWidget *parent = nullptr);
@ -36,11 +37,9 @@ protected:
bool event(QEvent *event) override;
#endif
private slots:
private:
void updatePixmap(const QImage &image, double scaleFactor);
void zoom(double zoomFactor);
private:
void scroll(int deltaX, int deltaY);
#ifndef QT_NO_GESTURES
bool gestureEvent(QGestureEvent *event);

View File

@ -1,12 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include <QPainter>
#include <QTime>
#include "block.h"
#include "window.h"
#include <QApplication>
#include <QBrush>
#include <QImage>
#include <QPainter>
#include <QPen>
#include <QPointF>
#include <QRect>
QImage createImage(int width, int height)
{
QImage image(width, height, QImage::Format_RGB16);
@ -43,8 +48,8 @@ QImage createImage(int width, int height)
int x = 0;
int y = 0;
int starWidth = image.width()/3;
int starHeight = image.height()/3;
const int starWidth = image.width()/3;
const int starHeight = image.height()/3;
QRect rect(x, y, starWidth, starHeight);

View File

@ -1,22 +1,19 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "block.h"
#include "renderthread.h"
#include <QRandomGenerator>
#include <QRgb>
RenderThread::RenderThread(QObject *parent)
: QThread(parent)
{
m_abort = false;
}
RenderThread::~RenderThread()
{
mutex.lock();
m_abort = true;
mutex.unlock();
wait();
}
@ -27,27 +24,26 @@ void RenderThread::processImage(const QImage &image)
return;
m_image = image;
m_abort = false;
start();
}
void RenderThread::run()
{
int size = qMax(m_image.width()/20, m_image.height()/20);
const int size = qMax(m_image.width()/20, m_image.height()/20);
for (int s = size; s > 0; --s) {
for (int c = 0; c < 400; ++c) {
//![processing the image (start)]
int x1 = qMax(0, QRandomGenerator::global()->bounded(m_image.width()) - s/2);
int x2 = qMin(x1 + s/2 + 1, m_image.width());
int y1 = qMax(0, QRandomGenerator::global()->bounded(m_image.height()) - s/2);
int y2 = qMin(y1 + s/2 + 1, m_image.height());
const int x1 = qMax(0, QRandomGenerator::global()->bounded(m_image.width()) - s/2);
const int x2 = qMin(x1 + s/2 + 1, m_image.width());
const int y1 = qMax(0, QRandomGenerator::global()->bounded(m_image.height()) - s/2);
const int y2 = qMin(y1 + s/2 + 1, m_image.height());
int n = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int i = y1; i < y2; ++i) {
for (int j = x1; j < x2; ++j) {
QRgb pixel = m_image.pixel(j, i);
const QRgb pixel = m_image.pixel(j, i);
red += qRed(pixel);
green += qGreen(pixel);
blue += qBlue(pixel);
@ -55,20 +51,13 @@ void RenderThread::run()
}
}
//![processing the image (finish)]
Block block(QRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1),
const Block block(QRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1),
QColor(red/n, green/n, blue/n));
emit sendBlock(block);
if (m_abort)
if (isInterruptionRequested())
return;
msleep(10);
}
}
}
//![processing the image (finish)]
void RenderThread::stopProcess()
{
mutex.lock();
m_abort = true;
mutex.unlock();
}

View File

@ -5,9 +5,9 @@
#define RENDERTHREAD_H
#include <QImage>
#include <QMutex>
#include <QThread>
#include "block.h"
class Block;
//! [RenderThread class definition]
class RenderThread : public QThread
@ -23,16 +23,11 @@ public:
signals:
void sendBlock(const Block &block);
public slots:
void stopProcess();
protected:
void run();
private:
bool m_abort;
QImage m_image;
QMutex mutex;
};
//! [RenderThread class definition]

View File

@ -1,8 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "block.h"
#include "renderthread.h"
#include "window.h"
#include <QtWidgets>
#include <QFileDialog>
#include <QGuiApplication>
#include <QHBoxLayout>
#include <QImageReader>
#include <QPainter>
#include <QScreen>
#include <QVBoxLayout>
//! [Window constructor start]
Window::Window(QWidget *parent)
@ -20,7 +29,7 @@ Window::Window(QWidget *parent)
connect(loadButton, &QPushButton::clicked,
this, QOverload<>::of(&Window::loadImage));
connect(resetButton, &QPushButton::clicked,
thread, &RenderThread::stopProcess);
thread, &RenderThread::requestInterruption);
connect(thread, &RenderThread::finished,
this, &Window::resetUi);
//! [set up widgets and connections] //! [connecting signal with custom type]
@ -51,13 +60,13 @@ void Window::loadImage()
if (format.toLower() == format)
formats.append(QLatin1String("*.") + QString::fromLatin1(format));
QString newPath = QFileDialog::getOpenFileName(this, tr("Open Image"),
const QString newPath = QFileDialog::getOpenFileName(this, tr("Open Image"),
path, tr("Image files (%1)").arg(formats.join(' ')));
if (newPath.isEmpty())
return;
QImage image(newPath);
const QImage image(newPath);
if (!image.isNull()) {
loadImage(image);
path = newPath;
@ -67,7 +76,7 @@ void Window::loadImage()
void Window::loadImage(const QImage &image)
{
QImage useImage;
QRect space = QGuiApplication::primaryScreen()->availableGeometry();
const QRect space = QGuiApplication::primaryScreen()->availableGeometry();
if (image.width() > 0.75*space.width() || image.height() > 0.75*space.height())
useImage = image.scaled(0.75*space.width(), 0.75*space.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);

View File

@ -4,13 +4,14 @@
#ifndef WINDOW_H
#define WINDOW_H
#include <QImage>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
#include <QWidget>
#include "renderthread.h"
QT_BEGIN_NAMESPACE
class QLabel;
class QPushButton;
QT_END_NAMESPACE
class Block;
class RenderThread;
//! [Window class definition]
class Window : public QWidget

View File

@ -7,9 +7,9 @@
#include <stdlib.h>
//! [0]
const int DataSize = 100000;
constexpr int DataSize = 100000;
const int BufferSize = 8192;
constexpr int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize);

View File

@ -5,5 +5,3 @@ if(NOT TARGET Qt6::Widgets)
return()
endif()
qt_internal_add_example(contiguouscache)
qt_internal_add_example(customtype)
qt_internal_add_example(customtypesending)

View File

@ -1,37 +0,0 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(customtype LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/tools/customtype")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(customtype
main.cpp
message.cpp message.h
)
set_target_properties(customtype PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(customtype PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS customtype
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -1,8 +0,0 @@
HEADERS = message.h
SOURCES = main.cpp \
message.cpp
QT += widgets
# install
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/tools/customtype
INSTALLS += target

View File

@ -1,37 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QCoreApplication>
#include <QDebug>
#include <QVariant>
#include "message.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QStringList headers;
headers << "Subject: Hello World"
<< "From: address@example.com";
QString body = "This is a test.\r\n";
//! [printing a custom type]
Message message(body, headers);
qDebug() << "Original:" << message;
//! [printing a custom type]
//! [storing a custom value]
QVariant stored;
stored.setValue(message);
//! [storing a custom value]
qDebug() << "Stored:" << stored;
//! [retrieving a custom value]
Message retrieved = qvariant_cast<Message>(stored);
qDebug() << "Retrieved:" << retrieved;
retrieved = qvariant_cast<Message>(stored);
qDebug() << "Retrieved:" << retrieved;
//! [retrieving a custom value]
return 0;
}

View File

@ -1,38 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "message.h"
#include <QDebug>
Message::Message(const QString &body, const QStringList &headers)
: m_body(body), m_headers(headers)
{
}
//! [custom type streaming operator]
QDebug operator<<(QDebug dbg, const Message &message)
{
QDebugStateSaver saver(dbg);
QList<QStringView> pieces = message.body().split(u"\r\n", Qt::SkipEmptyParts);
if (pieces.isEmpty())
dbg.nospace() << "Message()";
else if (pieces.size() == 1)
dbg.nospace() << "Message(" << pieces.first() << ")";
else
dbg.nospace() << "Message(" << pieces.first() << " ...)";
return dbg;
}
//! [custom type streaming operator]
//! [getter functions]
QStringView Message::body() const
{
return m_body;
}
QStringList Message::headers() const
{
return m_headers;
}
//! [getter functions]

View File

@ -1,38 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MESSAGE_H
#define MESSAGE_H
#include <QMetaType>
#include <QStringList>
//! [custom type definition]
class Message
{
public:
Message() = default;
~Message() = default;
Message(const Message &) = default;
Message &operator=(const Message &) = default;
Message(const QString &body, const QStringList &headers);
QStringView body() const;
QStringList headers() const;
private:
QString m_body;
QStringList m_headers;
};
//! [custom type definition]
//! [custom type meta-type declaration]
Q_DECLARE_METATYPE(Message);
//! [custom type meta-type declaration]
//! [custom type streaming operator]
QDebug operator<<(QDebug dbg, const Message &message);
//! [custom type streaming operator]
#endif

View File

@ -1,38 +0,0 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(customtypesending LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/tools/customtypesending")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(customtypesending
main.cpp
message.cpp message.h
window.cpp window.h
)
set_target_properties(customtypesending PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(customtypesending PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS customtypesending
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -1,10 +0,0 @@
HEADERS = message.h \
window.h
SOURCES = main.cpp \
message.cpp \
window.cpp
QT += widgets
# install
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/tools/customtypesending
INSTALLS += target

View File

@ -1,31 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "message.h"
#include "window.h"
//! [main function]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStringList headers;
headers << "Subject: Hello World"
<< "From: address@example.com";
QString body = "This is a test.\r\n";
Message message(body, headers);
Window window1;
window1.setMessage(message);
Window window2;
QObject::connect(&window1, &Window::messageSent,
&window2, &Window::setMessage);
QObject::connect(&window2, &Window::messageSent,
&window1, &Window::setMessage);
window1.show();
window2.show();
return app.exec();
}
//! [main function]

View File

@ -1,19 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "message.h"
Message::Message(const QString &body, const QStringList &headers)
: m_body(body), m_headers(headers)
{
}
QString Message::body() const
{
return m_body;
}
QStringList Message::headers() const
{
return m_headers;
}

View File

@ -1,34 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MESSAGE_H
#define MESSAGE_H
#include <QMetaType>
#include <QStringList>
//! [custom type definition]
class Message
{
public:
Message() = default;
~Message() = default;
Message(const Message &) = default;
Message &operator=(const Message &) = default;
Message(const QString &body, const QStringList &headers);
QString body() const;
QStringList headers() const;
private:
QString m_body;
QStringList m_headers;
};
//! [custom type definition]
//! [custom type meta-type declaration]
Q_DECLARE_METATYPE(Message);
//! [custom type meta-type declaration]
#endif

View File

@ -1,43 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "window.h"
//! [Window constructor]
Window::Window(QWidget *parent)
: QWidget(parent), editor(new QTextEdit(this))
{
QPushButton *sendButton = new QPushButton(tr("&Send message"));
connect(sendButton, &QPushButton::clicked,
this, &Window::sendMessage);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(sendButton);
buttonLayout->addStretch();
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(editor);
layout->addLayout(buttonLayout);
setWindowTitle(tr("Custom Type Sending"));
}
//! [Window constructor]
//! [sending a message]
void Window::sendMessage()
{
thisMessage = Message(editor->toPlainText(), thisMessage.headers());
emit messageSent(thisMessage);
}
//! [sending a message]
//! [receiving a message]
void Window::setMessage(const Message &message)
{
thisMessage = message;
editor->setPlainText(thisMessage.body());
}
//! [receiving a message]

View File

@ -1,35 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include "message.h"
QT_FORWARD_DECLARE_CLASS(QTextEdit)
//! [Window class definition]
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = nullptr);
signals:
void messageSent(const Message &message);
public slots:
void setMessage(const Message &message);
private slots:
void sendMessage();
private:
Message thisMessage;
QTextEdit *editor;
};
//! [Window class definition]
#endif

View File

@ -1,111 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example tools/customtype
\title Custom Type Example
\brief The Custom Type example shows how to integrate a custom type into Qt's
meta-object system.
Contents:
\tableofcontents
\section1 Overview
Qt provides a range of standard value types that are used to provide
rich and meaningful APIs. These types are integrated with the meta-object
system, enabling them to be stored in QVariant objects, written out in
debugging information and sent between components in signal-slot
communication.
Custom types can also be integrated with the meta-object system as long as
they are written to conform to some simple guidelines. In this example, we
introduce a simple \c Message class, we describe how we make it work with
QVariant, and we show how it can be extended to generate a printable
representation of itself for use in debugging output.
\section1 The Message Class Definition
The \c Message class is a simple value class that contains two pieces
of information (a QString and a QStringList), each of which can be read
using trivial getter functions:
\snippet tools/customtype/message.h custom type definition
The default constructor, copy constructor and destructor are
all required, and must be public, if the type is to be integrated into the
meta-object system. Other than this, we are free to implement whatever we
need to make the type do what we want, so we also include a constructor
that lets us set the type's data members.
To enable the type to be used with QVariant, we declare it using the
Q_DECLARE_METATYPE() macro:
\snippet tools/customtype/message.h custom type meta-type declaration
We do not need to write any additional code to accompany this macro.
To allow us to see a readable description of each \c Message object when it
is sent to the debug output stream, we define a streaming operator:
\snippet tools/customtype/message.h custom type streaming operator
This facility is useful if you need to insert tracing statements in your
code for debugging purposes.
\section1 The Message Class Implementation
The streaming operator is implemented in the following way:
\snippet tools/customtype/message.cpp custom type streaming operator
Here, we want to represent each value depending on how many lines are stored
in the message body. We stream text to the QDebug object passed to the
operator and return the QDebug object obtained from its maybeSpace() member
function; this is described in more detail in the
\l{Creating Custom Qt Types#Making the Type Printable}{Creating Custom Qt Types}
document.
We include the code for the getter functions for completeness:
\snippet tools/customtype/message.cpp getter functions
With the type fully defined, implemented, and integrated with the
meta-object system, we can now use it.
\section1 Using the Message
In the example's \c{main()} function, we show how a \c Message object can
be printed to the console by sending it to the debug stream:
\snippet tools/customtype/main.cpp printing a custom type
You can use the type with QVariant in exactly the same way as you would
use standard Qt value types. Here's how to store a value using the
QVariant::setValue() function:
\snippet tools/customtype/main.cpp storing a custom value
Alternatively, the QVariant::fromValue() function can be used if
you are using a compiler without support for member template
functions.
The value can be retrieved using the QVariant::value() member template
function:
\snippet tools/customtype/main.cpp retrieving a custom value
\section1 Further Reading
The custom \c Message type can also be used with direct signal-slot
connections.
To register a custom type for use with queued signals and slots, such as
those used in cross-thread communication, see the
\l{Queued Custom Type Example}.
More information on using custom types with Qt can be found in the
\l{Creating Custom Qt Types} document.
*/

View File

@ -1,6 +1,4 @@
requires(qtHaveModule(widgets))
TEMPLATE = subdirs
SUBDIRS = contiguouscache \
customtype \
customtypesending
SUBDIRS = contiguouscache

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -4,6 +4,7 @@
/*!
\example http
\examplecategory {Networking}
\examplecategory {Web Technologies}
\meta tags {http,network,https,proxy}
\title HTTP Client
\ingroup examples-network

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example serialization/rsslisting
\example rsslisting
\examplecategory {Networking}
\meta tag {serialization}
\title A minimal RSS listing application
@ -31,11 +31,11 @@
former. For the sake of illustration, it gives the widget the Qt blog's URL
as default value for the resource to check.
\snippet serialization/rsslisting/main.cpp 0
\snippet rsslisting/main.cpp 0
\section1 The RSSListing class
\snippet serialization/rsslisting/rsslisting.h 0
\snippet rsslisting/rsslisting.h 0
The widget itself provides a simple user interface for specifying the URL to
fetch and, once available updates are displayed, controlling the downloading
@ -51,7 +51,7 @@
\section2 Construction
\snippet serialization/rsslisting/rsslisting.cpp setup
\snippet rsslisting/rsslisting.cpp setup
The constructor sets up the assorted components of the widget and connects
their various signals to the slots it shall use to handle them.
@ -69,7 +69,7 @@
\section2 The slots
\snippet serialization/rsslisting/rsslisting.cpp slots
\snippet rsslisting/rsslisting.cpp slots
All slots are kept simple by delegating any hard work to private methods.
@ -94,7 +94,7 @@
\section2 The get() method
\snippet serialization/rsslisting/rsslisting.cpp get
\snippet rsslisting/rsslisting.cpp get
The private \c get() method is used by the \c fetch() slot to initiate an
HTTP GET request. It first clears the XML stream reader and, if a reply is
@ -106,7 +106,7 @@
\section2 The parseXml() method
\snippet serialization/rsslisting/rsslisting.cpp parse
\snippet rsslisting/rsslisting.cpp parse
When data is received, and thus made available to the XML stream reader, \c
parseXml() reads from the XML stream, checking for \c item elements and,

View File

@ -26,17 +26,17 @@ protected:
};
// TorrentViewDelegate is used to draw the progress bars.
class TorrentViewDelegate : public QItemDelegate
class TorrentViewDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
inline TorrentViewDelegate(MainWindow *mainWindow) : QItemDelegate(mainWindow) {}
inline TorrentViewDelegate(MainWindow *mainWindow) : QStyledItemDelegate(mainWindow) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index ) const override
{
if (index.column() != 2) {
QItemDelegate::paint(painter, option, index);
QStyledItemDelegate::paint(painter, option, index);
return;
}

View File

@ -6,6 +6,7 @@
\title Hello GLES3 Example
\ingroup examples-widgets-opengl
\examplecategory {Graphics & Multimedia}
\examplecategory {Mobile}
\brief Demonstrates OpenGL ES 3.0 functions via QOpenGLExtraFunctions.

View File

@ -3,19 +3,19 @@
#include "mainwindow.h"
#include "window.h"
#include <QApplication>
#include <QKeySequence>
#include <QMenuBar>
#include <QMenu>
#include <QMessageBox>
MainWindow::MainWindow()
{
QMenuBar *menuBar = new QMenuBar;
QMenu *menuWindow = menuBar->addMenu(tr("&Window"));
QAction *addNew = new QAction(menuWindow);
addNew->setText(tr("Add new"));
menuWindow->addAction(addNew);
connect(addNew, &QAction::triggered, this, &MainWindow::onAddNew);
setMenuBar(menuBar);
QMenu *menuWindow = menuBar()->addMenu(tr("&Window"));
menuWindow->addAction(tr("Add new"), QKeySequence(Qt::CTRL | Qt::Key_N),
this, &MainWindow::onAddNew);
menuWindow->addAction(tr("Quit"), QKeySequence(Qt::CTRL | Qt::Key_Q),
qApp, QApplication::closeAllWindows);
onAddNew();
}
@ -23,8 +23,8 @@ MainWindow::MainWindow()
void MainWindow::onAddNew()
{
if (!centralWidget())
setCentralWidget(new Window(this));
setCentralWidget(new Window);
else
QMessageBox::information(nullptr, tr("Cannot add new window"),
QMessageBox::information(this, tr("Cannot Add New Window"),
tr("Already occupied. Undock first."));
}

View File

@ -1,9 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "glwidget.h"
#include "window.h"
#include "mainwindow.h"
#include "glwidget.h"
#include <QSlider>
#include <QVBoxLayout>
#include <QHBoxLayout>
@ -11,9 +10,18 @@
#include <QPushButton>
#include <QApplication>
#include <QMessageBox>
#include <QMainWindow>
Window::Window(MainWindow *mw)
: mainWindow(mw)
static QMainWindow *findMainWindow()
{
for (auto *w : QApplication::topLevelWidgets()) {
if (auto *mw = qobject_cast<QMainWindow *>(w))
return mw;
}
return nullptr;
}
Window::Window()
{
glWidget = new GLWidget;
@ -28,22 +36,19 @@ Window::Window(MainWindow *mw)
connect(zSlider, &QSlider::valueChanged, glWidget, &GLWidget::setZRotation);
connect(glWidget, &GLWidget::zRotationChanged, zSlider, &QSlider::setValue);
QVBoxLayout *mainLayout = new QVBoxLayout;
QHBoxLayout *container = new QHBoxLayout;
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QWidget *w = new QWidget;
QHBoxLayout *container = new QHBoxLayout(w);
container->addWidget(glWidget);
container->addWidget(xSlider);
container->addWidget(ySlider);
container->addWidget(zSlider);
QWidget *w = new QWidget;
w->setLayout(container);
mainLayout->addWidget(w);
dockBtn = new QPushButton(tr("Undock"), this);
connect(dockBtn, &QPushButton::clicked, this, &Window::dockUndock);
mainLayout->addWidget(dockBtn);
setLayout(mainLayout);
xSlider->setValue(15 * 16);
ySlider->setValue(345 * 16);
zSlider->setValue(0 * 16);
@ -64,7 +69,7 @@ QSlider *Window::createSlider()
void Window::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Escape)
if (isWindow() && e->key() == Qt::Key_Escape)
close();
else
QWidget::keyPressEvent(e);
@ -72,26 +77,37 @@ void Window::keyPressEvent(QKeyEvent *e)
void Window::dockUndock()
{
if (parent()) {
setParent(nullptr);
setAttribute(Qt::WA_DeleteOnClose);
move(QGuiApplication::primaryScreen()->size().width() / 2 - width() / 2,
QGuiApplication::primaryScreen()->size().height() / 2 - height() / 2);
dockBtn->setText(tr("Dock"));
show();
} else {
if (!mainWindow->centralWidget()) {
if (mainWindow->isVisible()) {
setAttribute(Qt::WA_DeleteOnClose, false);
dockBtn->setText(tr("Undock"));
mainWindow->setCentralWidget(this);
} else {
QMessageBox::information(nullptr, tr("Cannot dock"),
tr("Main window already closed"));
}
} else {
QMessageBox::information(nullptr, tr("Cannot dock"),
tr("Main window already occupied"));
}
}
if (parent())
undock();
else
dock();
}
void Window::dock()
{
auto *mainWindow = findMainWindow();
if (mainWindow == nullptr || !mainWindow->isVisible()) {
QMessageBox::information(this, tr("Cannot Dock"),
tr("Main window already closed"));
return;
}
if (mainWindow->centralWidget()) {
QMessageBox::information(this, tr("Cannot Dock"),
tr("Main window already occupied"));
return;
}
setAttribute(Qt::WA_DeleteOnClose, false);
dockBtn->setText(tr("Undock"));
mainWindow->setCentralWidget(this);
}
void Window::undock()
{
setParent(nullptr);
setAttribute(Qt::WA_DeleteOnClose);
const auto geometry = screen()->availableGeometry();
move(geometry.x() + (geometry.width() - width()) / 2,
geometry.y() + (geometry.height() - height()) / 2);
dockBtn->setText(tr("Dock"));
show();
}

View File

@ -10,14 +10,13 @@ QT_FORWARD_DECLARE_CLASS(QSlider)
QT_FORWARD_DECLARE_CLASS(QPushButton)
class GLWidget;
class MainWindow;
class Window : public QWidget
{
Q_OBJECT
public:
Window(MainWindow *mw);
Window();
protected:
void keyPressEvent(QKeyEvent *event) override;
@ -26,6 +25,8 @@ private slots:
void dockUndock();
private:
void dock();
void undock();
QSlider *createSlider();
GLWidget *glWidget;
@ -33,7 +34,6 @@ private:
QSlider *ySlider;
QSlider *zSlider;
QPushButton *dockBtn;
MainWindow *mainWindow;
};
#endif

View File

@ -115,7 +115,7 @@
\section1 Delegate Class Definition and Implementation
The delegate we use to mediate interaction between the widget mapper and
the input widgets is a small QItemDelegate subclass:
the input widgets is a small QStyledItemDelegate subclass:
\snippet sqlwidgetmapper/delegate.h Delegate class definition
@ -126,7 +126,7 @@
Since we only provide an empty implementation of the constructor, we
concentrate on the other two functions.
The \l{QItemDelegate::}{setEditorData()} implementation takes the data
The \l{QStyledItemDelegate::}{setEditorData()} implementation takes the data
referred to by the model index supplied and processes it according to
the presence of a \c currentIndex property in the editor widget:
@ -138,10 +138,10 @@
values needed for the \c currentIndex property.
As a result, instead of showing "0", "1" or "2" in the combo box, one of
its predefined set of items is shown. We call QItemDelegate::setEditorData()
its predefined set of items is shown. We call QStyledItemDelegate::setEditorData()
for widgets without the \c currentIndex property.
The \l{QItemDelegate::}{setModelData()} implementation performs the reverse
The \l{QStyledItemDelegate::}{setModelData()} implementation performs the reverse
process, taking the value stored in the widget's \c currentIndex property
and storing it back in the model:

View File

@ -454,13 +454,15 @@ void Dialog::warningMessage()
tr("Delete the only copy of your movie manuscript?"), { }, this);
msgBox.setInformativeText(tr("You've been working on this manuscript for 738 days now. Hang in there!"));
msgBox.setDetailedText("\"A long time ago in a galaxy far, far away....\"");
msgBox.addButton(tr("&Keep"), QMessageBox::AcceptRole);
msgBox.addButton(tr("Delete"), QMessageBox::DestructiveRole);
if (msgBox.exec() == QMessageBox::AcceptRole)
auto *keepButton = msgBox.addButton(tr("&Keep"), QMessageBox::AcceptRole);
auto *deleteButton = msgBox.addButton(tr("Delete"), QMessageBox::DestructiveRole);
msgBox.exec();
if (msgBox.clickedButton() == keepButton)
warningLabel->setText(tr("Keep"));
else
else if (msgBox.clickedButton() == deleteButton)
warningLabel->setText(tr("Delete"));
else
warningLabel->setText("");
}
void Dialog::errorMessage()

View File

@ -7,13 +7,13 @@
\examplecategory {User Interface Components}
\ingroup examples-itemviews
\brief This example shows how to create an editor that can be used by
a QItemDelegate.
a QStyledItemDelegate.
\image coloreditorfactoryimage.png
When editing data in a QListView, QTableView, or QTreeView,
editors are created and displayed by a \l{Delegate
Classes}{delegate}. QItemDelegate, which is the default delegate
Classes}{delegate}. QStyledItemDelegate, which is the default delegate
used by Qt's \l{View Classes}{item views}, uses a
QItemEditorFactory to create editors for it. A unique instance
provided by QItemEditorFactory is by default installed on all
@ -27,7 +27,7 @@
In this example, we will create an editor (implemented in the \c
ColorListEditor class) that can edit the QColor data type and be
used by \l{QItemDelegate}s. We do this by creating a new
used by \l{QStyledItemDelegate}s. We do this by creating a new
QItemEditorCreatorBase that produces \c ColorListEditors and
register it with a new factory, which we set as the default editor
item factory (the unique factory instance). To test our editor, we
@ -67,7 +67,7 @@
\snippet itemviews/coloreditorfactory/colorlisteditor.h 0
QItemDelegate manages the interaction between the editor and
QStyledItemDelegate manages the interaction between the editor and
the model, i.e., it retrieves data to edit from the model and
store data from the editor in the model. The data that is edited
by an editor is stored in the editor's user data property, and the
@ -106,7 +106,7 @@
usually sufficient to provide custom editors. Further
customization is achieved by subclassing QItemEditorFactory
and QItemEditorCreatorBase. It is also possible to subclass
QItemDelegate if you don't wish to use a factory at all.
QStyledItemDelegate if you don't wish to use a factory at all.
Possible suggestions are:
@ -128,5 +128,5 @@
In this example, we use a standard QVariant data type. You can
also use custom types. In the \l{Star Delegate Example}, we
show how to store a custom data type in a QVariant and paint
and edit it in a class that inherits QItemDelegate.
and edit it in a class that inherits QStyledItemDelegate.
*/

View File

@ -88,7 +88,7 @@
\section1 Delegate Class Definition and Implementation
The delegate we use to mediate interaction between the widget mapper and
the input widgets is a small QItemDelegate subclass:
the input widgets is a small QStyledItemDelegate subclass:
\snippet itemviews/combowidgetmapper/delegate.h Delegate class definition
@ -99,7 +99,7 @@
Since we only provide an empty implementation of the constructor, we
concentrate on the other two functions.
The \l{QItemDelegate::}{setEditorData()} implementation takes the data
The \l{QStyledItemDelegate::}{setEditorData()} implementation takes the data
referred to by the model index supplied and processes it according to
the presence of a \c currentIndex property in the editor widget:
@ -111,10 +111,10 @@
values needed for the \c currentIndex property.
As a result, instead of showing "0", "1" or "2" in the combo box, one of
its predefined set of items is shown. We call QItemDelegate::setEditorData()
its predefined set of items is shown. We call QStyledItemDelegate::setEditorData()
for widgets without the \c currentIndex property.
The \l{QItemDelegate::}{setModelData()} implementation performs the reverse
The \l{QStyledItemDelegate::}{setModelData()} implementation performs the reverse
process, taking the value stored in the widget's \c currentIndex property
and storing it back in the model:

View File

@ -4,7 +4,7 @@
/*!
\example widgets/lineedits
\title Line Edits Example
\examplecateogry {User Interface Components}
\examplecategory {User Interface Components}
\ingroup examples-widgets
\brief The Line Edits example demonstrates the many ways that QLineEdit
can be used, and shows the effects of various properties and validators

View File

@ -1,375 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example widgets/tooltips
\title Tool Tips Example
\examplecategory {User Interface Components}
\ingroup examples-widgets
\brief The Tool Tips example shows how to provide static and dynamic tool
tips for an application's widgets.
The simplest and most common way to set a widget's tool tip is by
calling its QWidget::setToolTip() function (static tool
tips). Then the tool tip is shown whenever the cursor points at
the widget. We show how to do this with our application's tool
buttons. But it is also possible to show different tool tips
depending on the cursor's position (dynamic tooltips). This
approach uses mouse tracking and event handling to determine what
widgets are located under the cursor at any point in time, and
displays their tool tips. The tool tips for the shape items in our
application are implemented using the latter approach.
\image tooltips-example.png
With the \c Tooltips application the user can create new shape
items with the provided tool buttons, and move the items around
using the mouse. Tooltips are provided whenever the cursor is
pointing to a shape item or one of the buttons.
The Tooltips example consists of two classes:
\list
\li \c ShapeItem is a custom widget representing one single shape item.
\li \c SortingBox inherits from QWidget and is the application's main
widget.
\endlist
First we will review the \c SortingBox class, then we will take a
look at the \c ShapeItem class.
\section1 SortingBox Class Definition
\snippet widgets/tooltips/sortingbox.h 0
The \c SortingBox class inherits QWidget, and it is the Tooltips
application's main widget. We reimplement several of the event
handlers.
The \c event() function provides tooltips, the \c resize()
function makes sure the application appears consistently when the
user resizes the main widget, and the \c paintEvent() function
displays the shape items within the \c SortingBox widget. The
mouse event handlers are reimplemented to make the user able to
move the items around.
In addition we need three private slots to make the user able to
create new shape items.
\snippet widgets/tooltips/sortingbox.h 1
We also create several private functions: We use the \c
initialItemPosition(), \c initialItemColor() and \c
createToolButton() functions when we are constructing the widget,
and we use the \c updateButtonGeometry() function whenever the
user is resizing the application's main widget.
The \c itemAt() function determines if there is a shape item at a
particular position, and the \c moveItemTo() function moves an
item to a new position. We use the \c createShapeItem(), \c
randomItemPosition() and \c randomItemColor() functions to create
new shape items.
\snippet widgets/tooltips/sortingbox.h 2
We keep all the shape items in a QList, and we keep three
QPainterPath objects holding the shapes of a circle, a square and
a triangle. We also need to have a pointer to an item when it is
moving, and we need to know its previous position.
\section1 SortingBox Class Implementation
\snippet widgets/tooltips/sortingbox.cpp 0
In the constructor, we first set the Qt::WA_StaticContents
attribute on the widget. This attribute indicates that the widget
contents are north-west aligned and static. On resize, such a
widget will receive paint events only for the newly visible part
of itself.
\snippet widgets/tooltips/sortingbox.cpp 1
To be able to show the appropriate tooltips while the user is
moving the cursor around, we need to enable mouse tracking for the
widget.
If mouse tracking is disabled (the default), the widget only
receives mouse move events when at least one mouse button is
pressed while the mouse is being moved. If mouse tracking is
enabled, the widget receives mouse move events even if no buttons
are pressed.
\snippet widgets/tooltips/sortingbox.cpp 2
A widget's background role defines the brush from the widget's
palette that is used to render the background, and QPalette::Base
is typically white.
\snippet widgets/tooltips/sortingbox.cpp 3
After creating the application's tool buttons using the private \c
createToolButton() function, we construct the shapes of a circle,
a square and a triangle using QPainterPath.
The QPainterPath class provides a container for painting
operations, enabling graphical shapes to be constructed and
reused. The main advantage of painter paths over normal drawing
operations is that complex shapes only need to be created once,
but they can be drawn many times using only calls to
QPainter::drawPath().
\snippet widgets/tooltips/sortingbox.cpp 4
Then we set the window title, resize the widget to a suitable
size, and finally create three initial shape items using the
private \c createShapeItem(), \c initialItemPosition() and \c
initialItemColor() functions.
\snippet widgets/tooltips/sortingbox.cpp 27
In the destructor, we delete all shape items.
\snippet widgets/tooltips/sortingbox.cpp 5
QWidget::event() is the main event handler and receives all the
widget's events. Normally, we recommend reimplementing one of the
specialized event handlers instead of this function. But here we
want to catch the QEvent::ToolTip events, and since these are
rather rare, there exists no specific event handler. For that
reason we reimplement the main event handler, and the first thing
we need to do is to determine the event's type:
\snippet widgets/tooltips/sortingbox.cpp 6
If the type is QEvent::ToolTip, we cast the event to a QHelpEvent,
otherwise we propagate the event using the QWidget::event()
function.
The QHelpEvent class provides an event that is used to request
helpful information about a particular point in a widget.
For example, the QHelpEvent::pos() function returns the event's
position relative to the widget to which the event is dispatched.
Here we use this information to determine if the position of the
event is contained within the area of any of the shape items. If
it is, we display the shape item's tooltip at the position of the
event. If not, we hide the tooltip and explicitly ignore the event.
This makes sure that the calling code does not start any tooltip
specific modes as a result of the event. Note that the
QToolTip::showText() function needs the event's position in global
coordinates provided by QHelpEvent::globalPos().
\snippet widgets/tooltips/sortingbox.cpp 7
The \c resizeEvent() function is reimplemented to receive the
resize events dispatched to the widget. It makes sure that the
tool buttons keep their position relative to the main widget when
the widget is resized. We want the buttons to always be vertically
aligned in the application's bottom right corner, so each time the
main widget is resized we update the buttons geometry.
\snippet widgets/tooltips/sortingbox.cpp 8
The \c paintEvent() function is reimplemented to receive paint
events for the widget. We create a QPainter for the \c SortingBox
widget, and run through the list of created shape items, drawing
each item at its defined position.
\snippet widgets/tooltips/sortingbox.cpp 9
The painter will by default draw all the shape items at position
(0,0) in the \c SortingBox widget. The QPainter::translate()
function translates the coordinate system by the given offset,
making each shape item appear at its defined position. But
remember to translate the coordinate system back when the item is
drawn, otherwise the next shape item will appear at a position
relative to the item drawn last.
\snippet widgets/tooltips/sortingbox.cpp 10
The QPainter::setBrush() function sets the current brush used by
the painter. When the provided argument is a QColor, the function
calls the appropriate QBrush constructor which creates a brush with
the specified color and Qt::SolidPattern style. The
QPainter::drawPath() function draws the given path using the
current pen for outline and the current brush for filling.
\snippet widgets/tooltips/sortingbox.cpp 11
The \c mousePressEvent() function is reimplemented to receive the
mouse press events dispatched to the widget. It determines if an
event's position is contained within the area of any of the shape
items, using the private \c itemAt() function.
If an item covers the position, we store a pointer to that item
and the event's position. If several of the shape items cover the
position, we store the pointer to the uppermost item. Finally, we
move the shape item's pointer to the end of the list, and make
a call to the QWidget::update() function to make the item appear
on top.
The QWidget::update() function does not cause an immediate
repaint; instead it schedules a paint event for processing when Qt
returns to the main event loop.
\snippet widgets/tooltips/sortingbox.cpp 12
The \c mouseMoveEvent() function is reimplemented to receive mouse
move events for the widget. If the left mouse button is pressed
and there exists a shape item in motion, we use the private \c
moveItemTo() function to move the item with an offset
corresponding to the offset between the positions of the current
mouse event and the previous one.
\snippet widgets/tooltips/sortingbox.cpp 13
The \c mouseReleaseEvent() function is reimplemented to receive
the mouse release events dispatched to the widget. If the left
mouse button is pressed and there exists a shape item in motion,
we use the private \c moveItemTo() function to move the item like
we did in \c mouseMoveEvent(). But then we remove the pointer to
the item in motion, making the shape item's position final for
now. To move the item further, the user will need to press the
left mouse button again.
\snippet widgets/tooltips/sortingbox.cpp 14
\codeline
\snippet widgets/tooltips/sortingbox.cpp 15
\codeline
\snippet widgets/tooltips/sortingbox.cpp 16
The \c createNewCircle(), \c createNewSquare() and \c
createNewTriangle() slots simply create new shape items, using the
private \c createShapeItem(), \c randomItemPosition() and \c
randomItemColor() functions.
\snippet widgets/tooltips/sortingbox.cpp 17
In the \c itemAt() function, we run through the list of created
shape items to check if the given position is contained within the
area of any of the shape items.
For each shape item we use the QPainterPath::contains() function
to find out if the item's painter path contains the position. If
it does we return the index of the item, otherwise we return
-1. We run through the list backwards to get the index of the
uppermost shape item in case several items cover the position.
\snippet widgets/tooltips/sortingbox.cpp 18
The \c moveItemTo() function moves the shape item in motion, and
the parameter \c pos is the position of a mouse event. First we
calculate the offset between the parameter \c pos and the previous
mouse event position. Then we add the offset to the current
position of the item in motion.
It is tempting to simply set the position of the item to be the
parameter \c pos. But an item's position defines the top left
corner of the item's bounding rectangle, and the parameter \c pos
can be any point; The suggested shortcut would cause the item to
jump to a position where the cursor is pointing to the bounding
rectangle's top left corner, regardless of the item's previous
position.
\snippet widgets/tooltips/sortingbox.cpp 19
Finally, we update the previous mouse event position, and make a
call to the QWidget::update() function to make the item appear at
its new position.
\snippet widgets/tooltips/sortingbox.cpp 20
In the \c updateButtonGeometry() function we set the geometry for
the given button. The parameter coordinates define the bottom
right corner of the button. We use these coordinates and the
button's size hint to determine the position of the upper left
corner. This position, and the button's width and height, are the
arguments required by the QWidget::setGeometry() function.
In the end, we calculate and return the y-coordinate of the bottom
right corner of the next button. We use the QWidget::style()
function to retrieve the widget's GUI style, and then
QStyle::pixelMetric() to determine the widget's preferred default
spacing between its child widgets.
\snippet widgets/tooltips/sortingbox.cpp 21
The \c createShapeItem() function creates a single shape item. It
sets the path, tooltip, position and color, using the item's own
functions. In the end, the function appends the new item's pointer
to the list of shape items, and calls QWidget::update() to make
it appear with the other items within the \c SortingBox widget.
\snippet widgets/tooltips/sortingbox.cpp 22
The \c createToolButton() function is called from the \c
SortingBox constructor. We create a tool button with the given
tooltip and icon. The button's parent is the \c SortingBox widget,
and its size is 32 x 32 pixels. Before we return the button, we
connect it to the given slot.
\snippet widgets/tooltips/sortingbox.cpp 23
The \c initialItemPosition() function is also called from the
constructor. We want the three first items to initially be
centered in the middle of the \c SortingBox widget, and we use
this function to calculate their positions.
\snippet widgets/tooltips/sortingbox.cpp 24
Whenever the user creates a new shape item, we want the new item
to appear at a random position, and we use the \c
randomItemPosition() function to calculate such a position. We
make sure that the item appears within the visible area of the
\c SortingBox widget, using the widget's current width and height
when calculating the random coordinates.
\snippet widgets/tooltips/sortingbox.cpp 25
As with \c initialItemPosition(), the \c initialItemColor()
function is called from the constructor. The purposes of both
functions are purely cosmetic: We want to control the initial
position and color of the three first items.
\snippet widgets/tooltips/sortingbox.cpp 26
Finally the \c randomItemColor() function is implemented to give
the shape items the user creates, a random color.
\section1 ShapeItem Class Definition
\snippet widgets/tooltips/shapeitem.h 0
The \c ShapeItem class is a custom widget representing one single
shape item. The widget has a path, a position, a color and a
tooltip. We need functions to set or modify these objects, as well
as functions that return them. We make the latter functions \c
const to prohibit any modifications of the objects,
i.e. prohibiting unauthorized manipulation of the shape items
appearance.
\section1 ShapeItem Class Implementation
\snippet widgets/tooltips/shapeitem.cpp 0
\codeline
\snippet widgets/tooltips/shapeitem.cpp 1
\codeline
\snippet widgets/tooltips/shapeitem.cpp 2
\codeline
\snippet widgets/tooltips/shapeitem.cpp 3
This first group of functions simply return the objects that are
requested. The objects are returned as constants, i.e. they cannot
be modified.
\snippet widgets/tooltips/shapeitem.cpp 4
\codeline
\snippet widgets/tooltips/shapeitem.cpp 5
\codeline
\snippet widgets/tooltips/shapeitem.cpp 6
\codeline
\snippet widgets/tooltips/shapeitem.cpp 7
The last group of functions set or modify the shape item's path,
position, color and tooltip, respectively.
*/

View File

@ -12,5 +12,4 @@ qt_internal_add_example(shortcuteditor)
qt_internal_add_example(sliders)
qt_internal_add_example(spinboxes)
qt_internal_add_example(tablet)
qt_internal_add_example(tooltips)
qt_internal_add_example(windowflags)

View File

@ -1,52 +0,0 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(tooltips LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/widgets/tooltips")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(tooltips
main.cpp
shapeitem.cpp shapeitem.h
sortingbox.cpp sortingbox.h
)
set_target_properties(tooltips PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(tooltips PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
# Resources:
set(tooltips_resource_files
"images/circle.png"
"images/square.png"
"images/triangle.png"
)
qt_add_resources(tooltips "tooltips"
PREFIX
"/"
FILES
${tooltips_resource_files}
)
install(TARGETS tooltips
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 B

View File

@ -1,14 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "sortingbox.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SortingBox sortingBox;
sortingBox.show();
return app.exec();
}

View File

@ -1,60 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "shapeitem.h"
//! [0]
QPainterPath ShapeItem::path() const
{
return myPath;
}
//! [0]
//! [1]
QPoint ShapeItem::position() const
{
return myPosition;
}
//! [1]
//! [2]
QColor ShapeItem::color() const
{
return myColor;
}
//! [2]
//! [3]
QString ShapeItem::toolTip() const
{
return myToolTip;
}
//! [3]
//! [4]
void ShapeItem::setPath(const QPainterPath &path)
{
myPath = path;
}
//! [4]
//! [5]
void ShapeItem::setToolTip(const QString &toolTip)
{
myToolTip = toolTip;
}
//! [5]
//! [6]
void ShapeItem::setPosition(const QPoint &position)
{
myPosition = position;
}
//! [6]
//! [7]
void ShapeItem::setColor(const QColor &color)
{
myColor = color;
}
//! [7]

View File

@ -1,33 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef SHAPEITEM_H
#define SHAPEITEM_H
#include <QColor>
#include <QPainterPath>
#include <QPoint>
//! [0]
class ShapeItem
{
public:
void setPath(const QPainterPath &path);
void setToolTip(const QString &toolTip);
void setPosition(const QPoint &position);
void setColor(const QColor &color);
QPainterPath path() const;
QPoint position() const;
QColor color() const;
QString toolTip() const;
private:
QPainterPath myPath;
QPoint myPosition;
QColor myColor;
QString myToolTip;
};
//! [0]
#endif

View File

@ -1,277 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "sortingbox.h"
#include <QMouseEvent>
#include <QIcon>
#include <QPainter>
#include <QRandomGenerator>
#include <QStyle>
#include <QToolButton>
#include <QToolTip>
//! [0]
SortingBox::SortingBox(QWidget *parent)
: QWidget(parent)
{
//! [0] //! [1]
setMouseTracking(true);
//! [1] //! [2]
setBackgroundRole(QPalette::Base);
//! [2]
itemInMotion = nullptr;
//! [3]
newCircleButton = createToolButton(tr("New Circle"),
QIcon(":/images/circle.png"),
&SortingBox::createNewCircle);
newSquareButton = createToolButton(tr("New Square"),
QIcon(":/images/square.png"),
&SortingBox::createNewSquare);
newTriangleButton = createToolButton(tr("New Triangle"),
QIcon(":/images/triangle.png"),
&SortingBox::createNewTriangle);
circlePath.addEllipse(QRect(0, 0, 100, 100));
squarePath.addRect(QRect(0, 0, 100, 100));
qreal x = trianglePath.currentPosition().x();
qreal y = trianglePath.currentPosition().y();
trianglePath.moveTo(x + 120 / 2, y);
trianglePath.lineTo(0, 100);
trianglePath.lineTo(120, 100);
trianglePath.lineTo(x + 120 / 2, y);
//! [3] //! [4]
setWindowTitle(tr("Tool Tips"));
resize(500, 300);
createShapeItem(circlePath, tr("Circle"), initialItemPosition(circlePath),
initialItemColor());
createShapeItem(squarePath, tr("Square"), initialItemPosition(squarePath),
initialItemColor());
createShapeItem(trianglePath, tr("Triangle"),
initialItemPosition(trianglePath), initialItemColor());
}
//! [4]
//! [27]
SortingBox::~SortingBox()
{
qDeleteAll(shapeItems);
}
//! [27]
//! [5]
bool SortingBox::event(QEvent *event)
{
//! [5] //! [6]
if (event->type() == QEvent::ToolTip) {
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int index = itemAt(helpEvent->pos());
if (index != -1) {
QToolTip::showText(helpEvent->globalPos(), shapeItems[index]->toolTip());
} else {
QToolTip::hideText();
event->ignore();
}
return true;
}
return QWidget::event(event);
}
//! [6]
//! [7]
void SortingBox::resizeEvent(QResizeEvent * /* event */)
{
int margin = style()->pixelMetric(QStyle::PM_LayoutTopMargin);
int x = width() - margin;
int y = height() - margin;
y = updateButtonGeometry(newCircleButton, x, y);
y = updateButtonGeometry(newSquareButton, x, y);
updateButtonGeometry(newTriangleButton, x, y);
}
//! [7]
//! [8]
void SortingBox::paintEvent(QPaintEvent * /* event */)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
for (const ShapeItem *shapeItem : std::as_const(shapeItems)) {
//! [8] //! [9]
painter.translate(shapeItem->position());
//! [9] //! [10]
painter.setBrush(shapeItem->color());
painter.drawPath(shapeItem->path());
painter.translate(-shapeItem->position());
}
}
//! [10]
//! [11]
void SortingBox::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
int index = itemAt(event->position().toPoint());
if (index != -1) {
itemInMotion = shapeItems[index];
previousPosition = event->position().toPoint();
shapeItems.move(index, shapeItems.size() - 1);
update();
}
}
}
//! [11]
//! [12]
void SortingBox::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && itemInMotion)
moveItemTo(event->position().toPoint());
}
//! [12]
//! [13]
void SortingBox::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && itemInMotion) {
moveItemTo(event->position().toPoint());
itemInMotion = nullptr;
}
}
//! [13]
//! [14]
void SortingBox::createNewCircle()
{
static int count = 1;
createShapeItem(circlePath, tr("Circle <%1>").arg(++count),
randomItemPosition(), randomItemColor());
}
//! [14]
//! [15]
void SortingBox::createNewSquare()
{
static int count = 1;
createShapeItem(squarePath, tr("Square <%1>").arg(++count),
randomItemPosition(), randomItemColor());
}
//! [15]
//! [16]
void SortingBox::createNewTriangle()
{
static int count = 1;
createShapeItem(trianglePath, tr("Triangle <%1>").arg(++count),
randomItemPosition(), randomItemColor());
}
//! [16]
//! [17]
qsizetype SortingBox::itemAt(const QPoint &pos)
{
for (qsizetype i = shapeItems.size() - 1; i >= 0; --i) {
const ShapeItem *item = shapeItems[i];
if (item->path().contains(pos - item->position()))
return i;
}
return -1;
}
//! [17]
//! [18]
void SortingBox::moveItemTo(const QPoint &pos)
{
QPoint offset = pos - previousPosition;
itemInMotion->setPosition(itemInMotion->position() + offset);
//! [18] //! [19]
previousPosition = pos;
update();
}
//! [19]
//! [20]
int SortingBox::updateButtonGeometry(QToolButton *button, int x, int y)
{
QSize size = button->sizeHint();
button->setGeometry(x - size.rwidth(), y - size.rheight(),
size.rwidth(), size.rheight());
return y - size.rheight()
- style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing);
}
//! [20]
//! [21]
void SortingBox::createShapeItem(const QPainterPath &path,
const QString &toolTip, const QPoint &pos,
const QColor &color)
{
ShapeItem *shapeItem = new ShapeItem;
shapeItem->setPath(path);
shapeItem->setToolTip(toolTip);
shapeItem->setPosition(pos);
shapeItem->setColor(color);
shapeItems.append(shapeItem);
update();
}
//! [21]
//! [22]
template<typename PointerToMemberFunction>
QToolButton *SortingBox::createToolButton(const QString &toolTip,
const QIcon &icon, const PointerToMemberFunction &member)
{
QToolButton *button = new QToolButton(this);
button->setToolTip(toolTip);
button->setIcon(icon);
button->setIconSize(QSize(32, 32));
connect(button, &QToolButton::clicked, this, member);
return button;
}
//! [22]
//! [23]
QPoint SortingBox::initialItemPosition(const QPainterPath &path)
{
int x;
int y = (height() - qRound(path.controlPointRect().height()) / 2);
if (shapeItems.size() == 0)
x = ((3 * width()) / 2 - qRound(path.controlPointRect().width())) / 2;
else
x = (width() / shapeItems.size()
- qRound(path.controlPointRect().width())) / 2;
return QPoint(x, y);
}
//! [23]
//! [24]
QPoint SortingBox::randomItemPosition()
{
return QPoint(QRandomGenerator::global()->bounded(width() - 120), QRandomGenerator::global()->bounded(height() - 120));
}
//! [24]
//! [25]
QColor SortingBox::initialItemColor()
{
return QColor::fromHsv(((shapeItems.size() + 1) * 85) % 256, 255, 190);
}
//! [25]
//! [26]
QColor SortingBox::randomItemColor()
{
return QColor::fromHsv(QRandomGenerator::global()->bounded(256), 255, 190);
}
//! [26]

View File

@ -1,71 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef SORTINGBOX_H
#define SORTINGBOX_H
#include "shapeitem.h"
#include <QWidget>
QT_BEGIN_NAMESPACE
class QAction;
class QPoint;
class QToolButton;
QT_END_NAMESPACE
//! [0]
class SortingBox : public QWidget
{
Q_OBJECT
public:
SortingBox(QWidget *parent = nullptr);
~SortingBox();
protected:
bool event(QEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private slots:
void createNewCircle();
void createNewSquare();
void createNewTriangle();
//! [0]
//! [1]
private:
int updateButtonGeometry(QToolButton *button, int x, int y);
void createShapeItem(const QPainterPath &path, const QString &toolTip,
const QPoint &pos, const QColor &color);
qsizetype itemAt(const QPoint &pos);
void moveItemTo(const QPoint &pos);
QPoint initialItemPosition(const QPainterPath &path);
QPoint randomItemPosition();
QColor initialItemColor();
QColor randomItemColor();
template<typename PointerToMemberFunction>
QToolButton *createToolButton(const QString &toolTip, const QIcon &icon,
//! [1]
const PointerToMemberFunction &member);
//! [2]
QList<ShapeItem *> shapeItems;
QPainterPath circlePath;
QPainterPath squarePath;
QPainterPath trianglePath;
QPoint previousPosition;
ShapeItem *itemInMotion;
QToolButton *newCircleButton;
QToolButton *newSquareButton;
QToolButton *newTriangleButton;
};
//! [2]
#endif

View File

@ -1,12 +0,0 @@
QT += widgets
HEADERS = shapeitem.h \
sortingbox.h
SOURCES = main.cpp \
shapeitem.cpp \
sortingbox.cpp
RESOURCES = tooltips.qrc
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/widgets/tooltips
INSTALLS += target

View File

@ -1,7 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/circle.png</file>
<file>images/square.png</file>
<file>images/triangle.png</file>
</qresource>
</RCC>

View File

@ -9,5 +9,4 @@ SUBDIRS = analogclock \
sliders \
spinboxes \
tablet \
tooltips \
windowflags