6.6.1 original
@ -4,7 +4,7 @@
|
||||
#ifndef BINDABLESUBSCRIPTION_H
|
||||
#define BINDABLESUBSCRIPTION_H
|
||||
|
||||
#include <QPointer>
|
||||
#include <QBindable>
|
||||
#include <QProperty>
|
||||
|
||||
class BindableUser;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef BINDABLEUSER_H
|
||||
#define BINDABLEUSER_H
|
||||
|
||||
#include <QBindable>
|
||||
#include <QLocale>
|
||||
#include <QProperty>
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 15 KiB |
@ -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
|
||||
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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[])
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -4,10 +4,8 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
#include <QScreen>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 };
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
44
examples/corelib/serialization/convert/converter.cpp
Normal 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();
|
||||
}
|
@ -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
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 7.5 KiB |
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
24
examples/corelib/serialization/convert/variantorderedmap.h
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
/*!
|
||||
\example threads/mandelbrot
|
||||
\examplecategory {Data Processing & I/O}
|
||||
\title Mandelbrot
|
||||
\ingroup qtconcurrent-mtexamples
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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}"
|
||||
)
|
@ -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
|
@ -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;
|
||||
}
|
@ -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]
|
@ -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
|
@ -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}"
|
||||
)
|
@ -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
|
@ -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]
|
@ -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;
|
||||
}
|
@ -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
|
@ -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]
|
@ -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
|
@ -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.
|
||||
*/
|
@ -1,6 +1,4 @@
|
||||
requires(qtHaveModule(widgets))
|
||||
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = contiguouscache \
|
||||
customtype \
|
||||
customtypesending
|
||||
SUBDIRS = contiguouscache
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example http
|
||||
\examplecategory {Networking}
|
||||
\examplecategory {Web Technologies}
|
||||
\meta tags {http,network,https,proxy}
|
||||
\title HTTP Client
|
||||
\ingroup examples-network
|
||||
|
@ -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,
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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."));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
@ -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)
|
||||
|
@ -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}"
|
||||
)
|
Before Width: | Height: | Size: 165 B |
Before Width: | Height: | Size: 94 B |
Before Width: | Height: | Size: 170 B |
@ -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();
|
||||
}
|
@ -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]
|
@ -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
|
@ -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]
|
@ -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
|
@ -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
|
@ -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>
|
@ -9,5 +9,4 @@ SUBDIRS = analogclock \
|
||||
sliders \
|
||||
spinboxes \
|
||||
tablet \
|
||||
tooltips \
|
||||
windowflags
|
||||
|