mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-05 00:35:27 +08:00
qt 6.5.1 original
This commit is contained in:
13
examples/corelib/ipc/CMakeLists.txt
Normal file
13
examples/corelib/ipc/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(NOT TARGET Qt6::Widgets)
|
||||
return()
|
||||
endif()
|
||||
if(QT_FEATURE_sharedmemory)
|
||||
qt_internal_add_example(sharedmemory)
|
||||
endif()
|
||||
if(QT_FEATURE_localserver AND TARGET Qt6::Network)
|
||||
qt_internal_add_example(localfortuneserver)
|
||||
qt_internal_add_example(localfortuneclient)
|
||||
endif()
|
5
examples/corelib/ipc/README
Normal file
5
examples/corelib/ipc/README
Normal file
@ -0,0 +1,5 @@
|
||||
These examples demonstrate IPC support in Qt.
|
||||
|
||||
|
||||
Documentation for these examples can be found via the Examples
|
||||
link in the main Qt documentation.
|
BIN
examples/corelib/ipc/doc/images/localfortuneclient-example.png
Normal file
BIN
examples/corelib/ipc/doc/images/localfortuneclient-example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
BIN
examples/corelib/ipc/doc/images/localfortuneserver-example.png
Normal file
BIN
examples/corelib/ipc/doc/images/localfortuneserver-example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
BIN
examples/corelib/ipc/doc/images/sharedmemory-example_1.png
Normal file
BIN
examples/corelib/ipc/doc/images/sharedmemory-example_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
examples/corelib/ipc/doc/images/sharedmemory-example_2.png
Normal file
BIN
examples/corelib/ipc/doc/images/sharedmemory-example_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
16
examples/corelib/ipc/doc/src/localfortuneclient.qdoc
Normal file
16
examples/corelib/ipc/doc/src/localfortuneclient.qdoc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example ipc/localfortuneclient
|
||||
\title Local Fortune Client Example
|
||||
\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}.
|
||||
|
||||
\image localfortuneclient-example.png Screenshot of the Local Fortune Client example
|
||||
|
||||
*/
|
15
examples/corelib/ipc/doc/src/localfortuneserver.qdoc
Normal file
15
examples/corelib/ipc/doc/src/localfortuneserver.qdoc
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example ipc/localfortuneserver
|
||||
\title Local Fortune Server Example
|
||||
\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}
|
||||
|
||||
\image localfortuneserver-example.png Screenshot of the Local Fortune Server example
|
||||
*/
|
107
examples/corelib/ipc/doc/src/sharedmemory.qdoc
Normal file
107
examples/corelib/ipc/doc/src/sharedmemory.qdoc
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example ipc/sharedmemory
|
||||
\title Shared Memory Example
|
||||
\ingroup examples-ipc
|
||||
\brief Demonstrates doing inter-process communication using shared memory with
|
||||
the QSharedMemory class.
|
||||
|
||||
The Shared Memory example shows how to use the QSharedMemory class
|
||||
to implement inter-process communication using shared memory. To
|
||||
build the example, run make. To run the example, start two instances
|
||||
of the executable. The main() function creates an \l {QApplication}
|
||||
{application} and an instance of our example's Dialog class. The
|
||||
dialog is displayed and then control is passed to the application in
|
||||
the standard way.
|
||||
|
||||
\snippet ipc/sharedmemory/main.cpp 0
|
||||
|
||||
Two instances of class Dialog appear.
|
||||
|
||||
\image sharedmemory-example_1.png Screenshot of the Shared Memory example
|
||||
|
||||
Class Dialog inherits QDialog. It encapsulates the user interface
|
||||
and an instance of QSharedMemory. It also has two public slots,
|
||||
loadFromFile() and loadFromMemory() that correspond to the two
|
||||
buttons on the dialog.
|
||||
|
||||
\snippet ipc/sharedmemory/dialog.h 0
|
||||
|
||||
The constructor builds the user interface widgets and connects the
|
||||
clicked() signal of each button to the corresponding slot function.
|
||||
|
||||
\snippet ipc/sharedmemory/dialog.cpp 0
|
||||
|
||||
Note that "QSharedMemoryExample" is passed to the \l {QSharedMemory}
|
||||
{QSharedMemory()} constructor to be used as the key. This will be
|
||||
used by the system as the identifier of the underlying shared memory
|
||||
segment.
|
||||
|
||||
Click the \tt {Load Image From File...} button on one of the
|
||||
dialogs. The loadFromFile() slot is invoked. First, it tests whether
|
||||
a shared memory segment is already attached to the process. If so,
|
||||
that segment is detached from the process, so we can be assured of
|
||||
starting off the example correctly.
|
||||
|
||||
\snippet ipc/sharedmemory/dialog.cpp 1
|
||||
|
||||
The user is then asked to select an image file using
|
||||
QFileDialog::getOpenFileName(). The selected file is loaded into a
|
||||
QImage. Using a QImage lets us ensure that the selected file is a
|
||||
valid image, and it also allows us to immediately display the image
|
||||
in the dialog using setPixmap().
|
||||
|
||||
Next the image is streamed into a QBuffer using a QDataStream. This
|
||||
gives us the size, which we then use to \l {QSharedMemory::}
|
||||
{create()} our shared memory segment. Creating a shared memory
|
||||
segment automatically \l {QSharedMemory::attach()} {attaches} the
|
||||
segment to the process. Using a QBuffer here lets us get a pointer
|
||||
to the image data, which we then use to do a memcopy() from the
|
||||
QBuffer into the shared memory segment.
|
||||
|
||||
\snippet ipc/sharedmemory/dialog.cpp 2
|
||||
|
||||
Note that we \l {QSharedMemory::} {lock()} the shared memory segment
|
||||
before we copy into it, and we \l {QSharedMemory::} {unlock()} it
|
||||
again immediately after the copy. This ensures we have exclusive
|
||||
access to the shared memory segment to do our memcopy(). If some
|
||||
other process has the segment lock, then our process will block
|
||||
until the lock becomes available.
|
||||
|
||||
Note also that the function does not \l {QSharedMemory::} {detach()}
|
||||
from the shared memory segment after the memcopy() and
|
||||
unlock(). Recall that when the last process detaches from a shared
|
||||
memory segment, the segment is released by the operating
|
||||
system. Since this process only one that is attached to the shared
|
||||
memory segment at the moment, if loadFromFile() detached from the
|
||||
shared memory segment, the segment would be destroyed before we get
|
||||
to the next step.
|
||||
|
||||
When the function returns, if the file you selected was qt.png, your
|
||||
first dialog looks like this.
|
||||
|
||||
\image sharedmemory-example_2.png Screenshot of the Shared Memory example
|
||||
|
||||
In the second dialog, click the \tt {Display Image From Shared
|
||||
Memory} button. The loadFromMemory() slot is invoked. It first \l
|
||||
{QSharedMemory::attach()} {attaches} the process to the same shared
|
||||
memory segment created by the first process. Then it \l
|
||||
{QSharedMemory::lock()} {locks} the segment for exclusive access and
|
||||
links a QBuffer to the image data in the shared memory segment. It
|
||||
then streams the data into a QImage and \l {QSharedMemory::unlock()}
|
||||
{unlocks} the segment.
|
||||
|
||||
\snippet ipc/sharedmemory/dialog.cpp 3
|
||||
|
||||
In this case, the function does \l {QSharedMemory::} {detach()} from
|
||||
the segment, because now we are effectively finished using
|
||||
it. Finally, the QImage is displayed. At this point, both dialogs
|
||||
should be showing the same image. When you close the first dialog,
|
||||
the Dialog destructor calls the QSharedMemory destructor, which
|
||||
detaches from the shared memory segment. Since this is the last
|
||||
process to be detached from the segment, the operating system will
|
||||
now release the shared memory.
|
||||
|
||||
*/
|
10
examples/corelib/ipc/ipc.pro
Normal file
10
examples/corelib/ipc/ipc.pro
Normal file
@ -0,0 +1,10 @@
|
||||
requires(qtHaveModule(widgets))
|
||||
|
||||
TEMPLATE = subdirs
|
||||
|
||||
qtConfig(sharedmemory): SUBDIRS = sharedmemory
|
||||
qtHaveModule(network) {
|
||||
QT_FOR_CONFIG += network
|
||||
|
||||
qtConfig(localserver): SUBDIRS += localfortuneserver localfortuneclient
|
||||
}
|
38
examples/corelib/ipc/localfortuneclient/CMakeLists.txt
Normal file
38
examples/corelib/ipc/localfortuneclient/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(localfortuneclient LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/ipc/localfortuneclient")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(localfortuneclient
|
||||
client.cpp client.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(localfortuneclient PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(localfortuneclient PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Network
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS localfortuneclient
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
115
examples/corelib/ipc/localfortuneclient/client.cpp
Normal file
115
examples/corelib/ipc/localfortuneclient/client.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtNetwork>
|
||||
|
||||
#include "client.h"
|
||||
|
||||
Client::Client(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
hostLineEdit(new QLineEdit("fortune")),
|
||||
getFortuneButton(new QPushButton(tr("Get Fortune"))),
|
||||
statusLabel(new QLabel(tr("This examples requires that you run the "
|
||||
"Local Fortune Server example as well."))),
|
||||
socket(new QLocalSocket(this))
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
QLabel *hostLabel = new QLabel(tr("&Server name:"));
|
||||
hostLabel->setBuddy(hostLineEdit);
|
||||
|
||||
statusLabel->setWordWrap(true);
|
||||
|
||||
getFortuneButton->setDefault(true);
|
||||
QPushButton *quitButton = new QPushButton(tr("Quit"));
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox;
|
||||
buttonBox->addButton(getFortuneButton, QDialogButtonBox::ActionRole);
|
||||
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
|
||||
|
||||
in.setDevice(socket);
|
||||
in.setVersion(QDataStream::Qt_5_10);
|
||||
|
||||
connect(hostLineEdit, &QLineEdit::textChanged,
|
||||
this, &Client::enableGetFortuneButton);
|
||||
connect(getFortuneButton, &QPushButton::clicked,
|
||||
this, &Client::requestNewFortune);
|
||||
connect(quitButton, &QPushButton::clicked, this, &Client::close);
|
||||
connect(socket, &QLocalSocket::readyRead, this, &Client::readFortune);
|
||||
connect(socket, &QLocalSocket::errorOccurred, this, &Client::displayError);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout(this);
|
||||
mainLayout->addWidget(hostLabel, 0, 0);
|
||||
mainLayout->addWidget(hostLineEdit, 0, 1);
|
||||
mainLayout->addWidget(statusLabel, 2, 0, 1, 2);
|
||||
mainLayout->addWidget(buttonBox, 3, 0, 1, 2);
|
||||
|
||||
setWindowTitle(QGuiApplication::applicationDisplayName());
|
||||
hostLineEdit->setFocus();
|
||||
}
|
||||
|
||||
void Client::requestNewFortune()
|
||||
{
|
||||
getFortuneButton->setEnabled(false);
|
||||
blockSize = 0;
|
||||
socket->abort();
|
||||
socket->connectToServer(hostLineEdit->text());
|
||||
}
|
||||
|
||||
void Client::readFortune()
|
||||
{
|
||||
if (blockSize == 0) {
|
||||
// Relies on the fact that QDataStream serializes a quint32 into
|
||||
// sizeof(quint32) bytes
|
||||
if (socket->bytesAvailable() < (int)sizeof(quint32))
|
||||
return;
|
||||
in >> blockSize;
|
||||
}
|
||||
|
||||
if (socket->bytesAvailable() < blockSize || in.atEnd())
|
||||
return;
|
||||
|
||||
QString nextFortune;
|
||||
in >> nextFortune;
|
||||
|
||||
if (nextFortune == currentFortune) {
|
||||
QTimer::singleShot(0, this, &Client::requestNewFortune);
|
||||
return;
|
||||
}
|
||||
|
||||
currentFortune = nextFortune;
|
||||
statusLabel->setText(currentFortune);
|
||||
getFortuneButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void Client::displayError(QLocalSocket::LocalSocketError socketError)
|
||||
{
|
||||
switch (socketError) {
|
||||
case QLocalSocket::ServerNotFoundError:
|
||||
QMessageBox::information(this, tr("Local Fortune Client"),
|
||||
tr("The host was not found. Please make sure "
|
||||
"that the server is running and that the "
|
||||
"server name is correct."));
|
||||
break;
|
||||
case QLocalSocket::ConnectionRefusedError:
|
||||
QMessageBox::information(this, tr("Local Fortune Client"),
|
||||
tr("The connection was refused by the peer. "
|
||||
"Make sure the fortune server is running, "
|
||||
"and check that the server name "
|
||||
"is correct."));
|
||||
break;
|
||||
case QLocalSocket::PeerClosedError:
|
||||
break;
|
||||
default:
|
||||
QMessageBox::information(this, tr("Local Fortune Client"),
|
||||
tr("The following error occurred: %1.")
|
||||
.arg(socket->errorString()));
|
||||
}
|
||||
|
||||
getFortuneButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void Client::enableGetFortuneButton()
|
||||
{
|
||||
getFortuneButton->setEnabled(!hostLineEdit->text().isEmpty());
|
||||
}
|
42
examples/corelib/ipc/localfortuneclient/client.h
Normal file
42
examples/corelib/ipc/localfortuneclient/client.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDataStream>
|
||||
#include <QLocalSocket>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Client : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Client(QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void requestNewFortune();
|
||||
void readFortune();
|
||||
void displayError(QLocalSocket::LocalSocketError socketError);
|
||||
void enableGetFortuneButton();
|
||||
|
||||
private:
|
||||
QLineEdit *hostLineEdit;
|
||||
QPushButton *getFortuneButton;
|
||||
QLabel *statusLabel;
|
||||
|
||||
QLocalSocket *socket;
|
||||
QDataStream in;
|
||||
quint32 blockSize;
|
||||
|
||||
QString currentFortune;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,8 @@
|
||||
HEADERS = client.h
|
||||
SOURCES = client.cpp \
|
||||
main.cpp
|
||||
QT += network widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/ipc/localfortuneclient
|
||||
INSTALLS += target
|
15
examples/corelib/ipc/localfortuneclient/main.cpp
Normal file
15
examples/corelib/ipc/localfortuneclient/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "client.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QGuiApplication::setApplicationDisplayName(Client::tr("Local Fortune Client"));
|
||||
Client client;
|
||||
client.show();
|
||||
return app.exec();
|
||||
}
|
38
examples/corelib/ipc/localfortuneserver/CMakeLists.txt
Normal file
38
examples/corelib/ipc/localfortuneserver/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(localfortuneserver LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/ipc/localfortuneserver")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(localfortuneserver
|
||||
main.cpp
|
||||
server.cpp server.h
|
||||
)
|
||||
|
||||
set_target_properties(localfortuneserver PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(localfortuneserver PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Network
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS localfortuneserver
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
HEADERS = server.h
|
||||
SOURCES = server.cpp \
|
||||
main.cpp
|
||||
QT += network widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/ipc/localfortuneserver
|
||||
INSTALLS += target
|
15
examples/corelib/ipc/localfortuneserver/main.cpp
Normal file
15
examples/corelib/ipc/localfortuneserver/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "server.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QGuiApplication::setApplicationDisplayName(Server::tr("Local Fortune Server"));
|
||||
Server server;
|
||||
server.show();
|
||||
return app.exec();
|
||||
}
|
70
examples/corelib/ipc/localfortuneserver/server.cpp
Normal file
70
examples/corelib/ipc/localfortuneserver/server.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtNetwork>
|
||||
|
||||
Server::Server(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
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."));
|
||||
|
||||
fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
|
||||
<< tr("You've got to think about tomorrow.")
|
||||
<< tr("You will be surprised by a loud noise.")
|
||||
<< tr("You will feel hungry again in another hour.")
|
||||
<< tr("You might have mail.")
|
||||
<< tr("You cannot kill time without injuring eternity.")
|
||||
<< tr("Computers are not intelligent. They only think they are.");
|
||||
|
||||
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);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(statusLabel);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
|
||||
setWindowTitle(QGuiApplication::applicationDisplayName());
|
||||
}
|
||||
|
||||
void Server::sendFortune()
|
||||
{
|
||||
QByteArray block;
|
||||
QDataStream out(&block, QIODevice::WriteOnly);
|
||||
out.setVersion(QDataStream::Qt_5_10);
|
||||
const int fortuneIndex = QRandomGenerator::global()->bounded(0, fortunes.size());
|
||||
const QString &message = fortunes.at(fortuneIndex);
|
||||
out << quint32(message.size());
|
||||
out << message;
|
||||
|
||||
QLocalSocket *clientConnection = server->nextPendingConnection();
|
||||
connect(clientConnection, &QLocalSocket::disconnected,
|
||||
clientConnection, &QLocalSocket::deleteLater);
|
||||
|
||||
clientConnection->write(block);
|
||||
clientConnection->flush();
|
||||
clientConnection->disconnectFromServer();
|
||||
}
|
30
examples/corelib/ipc/localfortuneserver/server.h
Normal file
30
examples/corelib/ipc/localfortuneserver/server.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QLocalServer;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Server : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Server(QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void sendFortune();
|
||||
|
||||
private:
|
||||
QLocalServer *server;
|
||||
QStringList fortunes;
|
||||
};
|
||||
|
||||
#endif
|
37
examples/corelib/ipc/sharedmemory/CMakeLists.txt
Normal file
37
examples/corelib/ipc/sharedmemory/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(sharedmemory LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/ipc/sharedmemory")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(sharedmemory
|
||||
dialog.cpp dialog.h dialog.ui
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(sharedmemory PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(sharedmemory PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS sharedmemory
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
155
examples/corelib/ipc/sharedmemory/dialog.cpp
Normal file
155
examples/corelib/ipc/sharedmemory/dialog.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "dialog.h"
|
||||
#include <QFileDialog>
|
||||
#include <QBuffer>
|
||||
|
||||
/*!
|
||||
\class Dialog
|
||||
|
||||
\brief This class is a simple example of how to use QSharedMemory.
|
||||
|
||||
It is a simple dialog that presents a few buttons. To compile the
|
||||
example, run make in qt/examples/ipc. Then run the executable twice
|
||||
to create two processes running the dialog. In one of the processes,
|
||||
press the button to load an image into a shared memory segment, and
|
||||
then select an image file to load. Once the first process has loaded
|
||||
and displayed the image, in the second process, press the button to
|
||||
read the same image from shared memory. The second process displays
|
||||
the same image loaded from its new loaction in shared memory.
|
||||
*/
|
||||
|
||||
/*!
|
||||
The class contains a data member \l {QSharedMemory} {sharedMemory},
|
||||
which is initialized with the key "QSharedMemoryExample" to force
|
||||
all instances of Dialog to access the same shared memory segment.
|
||||
The constructor also connects the clicked() signal from each of the
|
||||
three dialog buttons to the slot function appropriate for handling
|
||||
each button.
|
||||
*/
|
||||
//! [0]
|
||||
Dialog::Dialog(QWidget *parent)
|
||||
: QDialog(parent), sharedMemory("QSharedMemoryExample")
|
||||
{
|
||||
ui.setupUi(this);
|
||||
connect(ui.loadFromFileButton, &QPushButton::clicked,
|
||||
this, &Dialog::loadFromFile);
|
||||
connect(ui.loadFromSharedMemoryButton, &QPushButton::clicked,
|
||||
this, &Dialog::loadFromMemory);
|
||||
setWindowTitle(tr("SharedMemory Example"));
|
||||
}
|
||||
//! [0]
|
||||
|
||||
/*!
|
||||
This slot function is called when the \tt {Load Image From File...}
|
||||
button is pressed on the firs Dialog process. First, it tests
|
||||
whether the process is already connected to a shared memory segment
|
||||
and, if so, detaches from that segment. This ensures that we always
|
||||
start the example from the beginning if we run it multiple times
|
||||
with the same two Dialog processes. After detaching from an existing
|
||||
shared memory segment, the user is prompted to select an image file.
|
||||
The selected file is loaded into a QImage. The QImage is displayed
|
||||
in the Dialog and streamed into a QBuffer with a QDataStream.
|
||||
|
||||
Next, it gets a new shared memory segment from the system big enough
|
||||
to hold the image data in the QBuffer, and it locks the segment to
|
||||
prevent the second Dialog process from accessing it. Then it copies
|
||||
the image from the QBuffer into the shared memory segment. Finally,
|
||||
it unlocks the shared memory segment so the second Dialog process
|
||||
can access it.
|
||||
|
||||
After this function runs, the user is expected to press the \tt
|
||||
{Load Image from Shared Memory} button on the second Dialog process.
|
||||
|
||||
\sa loadFromMemory()
|
||||
*/
|
||||
//! [1]
|
||||
void Dialog::loadFromFile()
|
||||
{
|
||||
if (sharedMemory.isAttached())
|
||||
detach();
|
||||
|
||||
ui.label->setText(tr("Select an image file"));
|
||||
QString fileName = QFileDialog::getOpenFileName(0, QString(), QString(),
|
||||
tr("Images (*.png *.xpm *.jpg)"));
|
||||
QImage image;
|
||||
if (!image.load(fileName)) {
|
||||
ui.label->setText(tr("Selected file is not an image, please select another."));
|
||||
return;
|
||||
}
|
||||
ui.label->setPixmap(QPixmap::fromImage(image));
|
||||
//! [1] //! [2]
|
||||
|
||||
// load into shared memory
|
||||
QBuffer buffer;
|
||||
buffer.open(QBuffer::ReadWrite);
|
||||
QDataStream out(&buffer);
|
||||
out << image;
|
||||
int size = buffer.size();
|
||||
|
||||
if (!sharedMemory.create(size)) {
|
||||
if (sharedMemory.error() == QSharedMemory::AlreadyExists) {
|
||||
sharedMemory.attach();
|
||||
} else {
|
||||
ui.label->setText(tr("Unable to create or attach to shared memory segment: %1")
|
||||
.arg(sharedMemory.errorString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
sharedMemory.lock();
|
||||
char *to = (char*)sharedMemory.data();
|
||||
const char *from = buffer.data().data();
|
||||
memcpy(to, from, qMin(sharedMemory.size(), size));
|
||||
sharedMemory.unlock();
|
||||
}
|
||||
//! [2]
|
||||
|
||||
/*!
|
||||
This slot function is called in the second Dialog process, when the
|
||||
user presses the \tt {Load Image from Shared Memory} button. First,
|
||||
it attaches the process to the shared memory segment created by the
|
||||
first Dialog process. Then it locks the segment for exclusive
|
||||
access, copies the image data from the segment into a QBuffer, and
|
||||
streams the QBuffer into a QImage. Then it unlocks the shared memory
|
||||
segment, detaches from it, and finally displays the QImage in the
|
||||
Dialog.
|
||||
|
||||
\sa loadFromFile()
|
||||
*/
|
||||
//! [3]
|
||||
void Dialog::loadFromMemory()
|
||||
{
|
||||
if (!sharedMemory.attach()) {
|
||||
ui.label->setText(tr("Unable to attach to shared memory segment.\n" \
|
||||
"Load an image first."));
|
||||
return;
|
||||
}
|
||||
|
||||
QBuffer buffer;
|
||||
QDataStream in(&buffer);
|
||||
QImage image;
|
||||
|
||||
sharedMemory.lock();
|
||||
buffer.setData((char*)sharedMemory.constData(), sharedMemory.size());
|
||||
buffer.open(QBuffer::ReadOnly);
|
||||
in >> image;
|
||||
sharedMemory.unlock();
|
||||
|
||||
sharedMemory.detach();
|
||||
ui.label->setPixmap(QPixmap::fromImage(image));
|
||||
}
|
||||
//! [3]
|
||||
|
||||
/*!
|
||||
This private function is called by the destructor to detach the
|
||||
process from its shared memory segment. When the last process
|
||||
detaches from a shared memory segment, the system releases the
|
||||
shared memory.
|
||||
*/
|
||||
void Dialog::detach()
|
||||
{
|
||||
if (!sharedMemory.detach())
|
||||
ui.label->setText(tr("Unable to detach from shared memory."));
|
||||
}
|
||||
|
33
examples/corelib/ipc/sharedmemory/dialog.h
Normal file
33
examples/corelib/ipc/sharedmemory/dialog.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef DIALOG_H
|
||||
#define DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSharedMemory>
|
||||
#include "ui_dialog.h"
|
||||
|
||||
//! [0]
|
||||
class Dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Dialog(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void loadFromFile();
|
||||
void loadFromMemory();
|
||||
|
||||
private:
|
||||
void detach();
|
||||
|
||||
private:
|
||||
Ui::Dialog ui;
|
||||
QSharedMemory sharedMemory;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
||||
|
47
examples/corelib/ipc/sharedmemory/dialog.ui
Normal file
47
examples/corelib/ipc/sharedmemory/dialog.ui
Normal file
@ -0,0 +1,47 @@
|
||||
<ui version="4.0" >
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>451</width>
|
||||
<height>322</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QPushButton" name="loadFromFileButton" >
|
||||
<property name="text" >
|
||||
<string>Load Image From File...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>Launch two of these dialogs. In the first, press the top button and load an image from a file. In the second, press the bottom button and display the loaded image from shared memory.</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QPushButton" name="loadFromSharedMemoryButton" >
|
||||
<property name="text" >
|
||||
<string>Display Image From Shared Memory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
BIN
examples/corelib/ipc/sharedmemory/image.png
Normal file
BIN
examples/corelib/ipc/sharedmemory/image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
16
examples/corelib/ipc/sharedmemory/main.cpp
Normal file
16
examples/corelib/ipc/sharedmemory/main.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
#include "dialog.h"
|
||||
|
||||
//! [0]
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication application(argc, argv);
|
||||
Dialog dialog;
|
||||
dialog.show();
|
||||
return application.exec();
|
||||
}
|
||||
//! [0]
|
||||
|
BIN
examples/corelib/ipc/sharedmemory/qt.png
Normal file
BIN
examples/corelib/ipc/sharedmemory/qt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
16
examples/corelib/ipc/sharedmemory/sharedmemory.pro
Normal file
16
examples/corelib/ipc/sharedmemory/sharedmemory.pro
Normal file
@ -0,0 +1,16 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(filedialog))
|
||||
|
||||
SOURCES += main.cpp \
|
||||
dialog.cpp
|
||||
|
||||
HEADERS += dialog.h
|
||||
|
||||
# Forms and resources
|
||||
FORMS += dialog.ui
|
||||
|
||||
EXAMPLE_FILES = *.png
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/ipc/sharedmemory
|
||||
INSTALLS += target
|
Reference in New Issue
Block a user