文章的目的为了记录使用QT QML开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C++ QT QML 开发(四)复杂控件--Listview
开源 C++ QT QML 开发(五)复杂控件--Gridview
开源 C++ QT QML 开发(十一)通讯--TCP服务器端
开源 C++ QT QML 开发(十二)通讯--TCP客户端
开源 C++ QT QML 开发(十五)通讯--http下载
推荐链接:
开源 C# 快速开发(十六)数据库--sqlserver增删改查
本章节主要内容是:Qml使用共享内存实现IPC通讯。例子为2个进程,通过创建共享内存,实现了双向实时通讯。
共享内存(QSharedMemory)主要用于进程间通信(IPC),允许不同的进程访问和操作同一块内存区域。
主要用途:
- 进程间数据共享
多个进程可以读取和写入同一块内存
适用于需要高效数据传输的场景
避免进程间复杂的数据序列化和反序列化
- 大数据传输
适合传输较大的数据块(如图像、音频等)
比传统的IPC方式(如信号/槽、TCP)更高效
- 系统级数据交换
不同应用程序之间的数据交换
插件系统间的通信
服务进程与客户端进程的数据共享
- 实时数据同步
需要快速响应的实时系统
监控系统数据共享
多进程协作处理
1.代码分析
2.所有源码
3.效果演示
一、代码分析1. main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "SharedMemoryManager.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // 启用高DPI缩放
QGuiApplication app(argc, argv); // 创建GUI应用实例
// 注册共享内存管理器到QML
SharedMemoryManager sharedMemoryManager; // 创建共享内存管理器实例
QQmlApplicationEngine engine; // 创建QML引擎
engine.rootContext()->setContextProperty("sharedMemoryManager", &sharedMemoryManager); // 注册到QML上下文
engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // 加载QML文件
if (engine.rootObjects().isEmpty()) // 检查加载是否成功
return -1;
return app.exec(); // 进入事件循环
}
函数分析:
应用初始化:设置高DPI支持,创建应用实例
对象注册:将C++对象暴露给QML引擎
资源加载:从qrc资源文件加载QML界面
错误处理:检查QML加载是否成功
-
SharedMemoryManager.h
#ifndef SHAREDMEMORYMANAGER_H
#define SHAREDMEMORYMANAGER_H#include <QObject>
#include <QSharedMemory>
#include <QTimer>
#include <QBuffer>
#include <QDataStream>
#include <QDateTime>class SharedMemoryManager : public QObject
{
Q_OBJECT
// QML属性声明
Q_PROPERTY(QString status READ status NOTIFY statusChanged) // 状态属性
Q_PROPERTY(QString lastMessage READ lastMessage NOTIFY lastMessageChanged) // 最后消息属性
Q_PROPERTY(bool hasNewMessage READ hasNewMessage NOTIFY hasNewMessageChanged) // 新消息标志属性public:
explicit SharedMemoryManager(QObject *parent = nullptr); // 构造函数
~SharedMemoryManager(); // 析构函数// 属性读取函数 QString status() const { return m_status; } QString lastMessage() const { return m_lastMessage; } bool hasNewMessage() const { return m_hasNewMessage; }
public slots:
void sendMessage(const QString &message); // 发送消息槽函数
void receiveMessage(); // 接收消息槽函数
void clearStatus(); // 清除状态槽函数
void startNewInstance(); // 启动新实例槽函数private slots:
void checkSharedMemory(); // 检查共享内存私有槽函数private:
void setupSharedMemory(); // 设置共享内存私有函数
void updateStatus(const QString &status); // 更新状态私有函数// 成员变量 QSharedMemory *m_sharedMemory; // 共享内存指针 QTimer *m_checkTimer; // 检查定时器 QString m_status; // 状态字符串 QString m_lastMessage; // 最后消息内容 bool m_hasNewMessage; // 新消息标志 static const QString SHARED_MEMORY_KEY; // 共享内存键值常量
signals:
// 信号声明
void statusChanged(); // 状态改变信号
void lastMessageChanged(); // 最后消息改变信号
void hasNewMessageChanged(); // 新消息标志改变信号
void newMessageReceived(const QString &message, const QString ×tamp); // 新消息接收信号
};#endif // SHAREDMEMORYMANAGER_H
-
SharedMemoryManager.cpp
构造函数
SharedMemoryManager::SharedMemoryManager(QObject *parent)
: QObject(parent) // 调用父类构造函数
, m_sharedMemory(new QSharedMemory(SHARED_MEMORY_KEY, this)) // 创建共享内存对象
, m_checkTimer(new QTimer(this)) // 创建定时器对象
, m_hasNewMessage(false) // 初始化新消息标志
{
setupSharedMemory(); // 初始化共享内存连接
connect(m_checkTimer, &QTimer::timeout, this, &SharedMemoryManager::checkSharedMemory); // 连接定时器信号
m_checkTimer->start(1000); // 启动定时器,每秒检查一次
}
析构函数
cpp
SharedMemoryManager::~SharedMemoryManager()
{
if (m_sharedMemory->isAttached()) { // 检查是否已附加到共享内存
m_sharedMemory->detach(); // 分离共享内存
}
}
共享内存设置函数
void SharedMemoryManager::setupSharedMemory()
{
// 尝试创建1024字节的共享内存
if (!m_sharedMemory->create(1024) && m_sharedMemory->error() == QSharedMemory::AlreadyExists) {
// 创建失败,但原因是已存在 → 尝试附加
if (m_sharedMemory->attach()) {
updateStatus("已连接到现有共享内存"); // 附加成功
} else {
updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString()); // 附加失败
}
} else if (m_sharedMemory->isAttached()) {
// 创建成功 → 新创建共享内存
updateStatus("已创建新的共享内存");
} else {
// 创建失败且原因不是已存在 → 其他错误
updateStatus("无法创建共享内存: " + m_sharedMemory->errorString());
}
}
发送消息函数
void SharedMemoryManager::sendMessage(const QString &message)
{
// 1. 连接检查
if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {
updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());
return;
}
// 2. 输入验证
if (message.isEmpty()) {
updateStatus("消息不能为空!");
return;
}
// 3. 数据序列化
QBuffer buffer;
buffer.open(QBuffer::ReadWrite); // 打开缓冲区
QDataStream out(&buffer); // 创建数据流
// 序列化消息和时间戳
out << message;
out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
// 4. 写入共享内存
m_sharedMemory->lock(); // 加锁
char *to = static_cast<char*>(m_sharedMemory->data()); // 获取共享内存指针
const char *from = buffer.data().data(); // 获取缓冲区数据指针
memcpy(to, from, qMin(m_sharedMemory->size(), static_cast<int>(buffer.size()))); // 内存拷贝
m_sharedMemory->unlock(); // 解锁
// 5. 状态更新
updateStatus("消息已发送: " + message);
m_hasNewMessage = false; // 重置新消息标志
emit hasNewMessageChanged(); // 发射标志改变信号
}
接收消息函数
void SharedMemoryManager::receiveMessage()
{
// 1. 连接检查
if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {
updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());
return;
}
// 2. 读取数据
m_sharedMemory->lock();
QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());
m_sharedMemory->unlock();
// 3. 数据反序列化
QBuffer buffer(&byteArray);
buffer.open(QBuffer::ReadOnly);
QDataStream in(&buffer);
QString message;
QString timestamp;
in >> message >> timestamp; // 反序列化消息和时间戳
// 4. 处理结果
if (message.isEmpty()) {
updateStatus("没有可用的消息");
} else {
m_lastMessage = QString("[%1] %2").arg(timestamp, message); // 格式化消息
emit lastMessageChanged(); // 发射消息改变信号
emit newMessageReceived(message, timestamp); // 发射新消息接收信号
updateStatus("收到新消息: " + message);
m_hasNewMessage = false; // 重置新消息标志
emit hasNewMessageChanged(); // 发射标志改变信号
}
}
定时检查函数
void SharedMemoryManager::checkSharedMemory()
{
// 静默连接检查
if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {
return;
}
// 读取和解析数据
m_sharedMemory->lock();
QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());
m_sharedMemory->unlock();
QBuffer buffer(&byteArray);
buffer.open(QBuffer::ReadOnly);
QDataStream in(&buffer);
QString message;
QString timestamp;
in >> message >> timestamp;
// 检测新消息
if (!message.isEmpty() && !m_hasNewMessage) {
m_hasNewMessage = true; // 设置新消息标志
emit hasNewMessageChanged(); // 发射标志改变信号
}
}
启动新实例函数
void SharedMemoryManager::startNewInstance()
{
QProcess *newProcess = new QProcess(this);
QString program = QCoreApplication::applicationFilePath(); // 获取当前程序路径
bool success = newProcess->startDetached(program); // 分离模式启动新进程
if (success) {
updateStatus("新实例启动成功");
qDebug() << "启动新实例成功";
} else {
updateStatus("无法启动新实例");
qDebug() << "启动新实例失败";
}
}
状态管理函数
void SharedMemoryManager::clearStatus()
{
updateStatus("就绪");
m_hasNewMessage = false;
emit hasNewMessageChanged();
}
void SharedMemoryManager::updateStatus(const QString &status)
{
if (m_status != status) { // 只在状态改变时更新
m_status = status;
emit statusChanged(); // 发射状态改变信号
}
}
前台QML文件分析
main.qml 主要组件和函数
应用窗口定义
ApplicationWindow {
id: window
width: 700
height: 700
minimumWidth: 600
minimumHeight: 600
title: "QML 共享内存演示 - PID: " + Qt.application.pid
visible: true
Material.theme: Material.Light
Material.accent: Material.Blue
}
背景设置
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#f5f7fa" }
GradientStop { position: 1.0; color: "#c3cfe2" }
}
}
头部标题组件
Item {
Layout.fillWidth: true
Layout.preferredHeight: 80
Rectangle {
anchors.fill: parent
color: Material.color(Material.Blue, Material.Shade50)
radius: 15
border.color: Material.color(Material.Blue, Material.Shade200)
border.width: 2
layer.enabled: true
layer.effect: DropShadow { // 阴影效果
transparentBorder: true
radius: 8
samples: 17
color: "#40000000"
}
// ... 内部布局
}
}
状态卡片组件
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 70
radius: 12
color: "white"
border.color: sharedMemoryManager.hasNewMessage ? "#4CAF50" : "#E0E0E0" // 条件样式
border.width: sharedMemoryManager.hasNewMessage ? 2 : 1
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
radius: 6
samples: 13
color: "#20000000"
}
// ... 状态显示逻辑
}
控制面板按钮函数
Button {
text: "🚀 启动新实例"
Material.background: Material.Blue
Material.foreground: "white"
font.bold: true
onClicked: sharedMemoryManager.startNewInstance() // 调用C++函数
}
发送消息功能
TextField {
id: messageInput
Layout.fillWidth: true
placeholderText: "💭 输入要发送的消息..."
text: "👋 你好!这是来自进程 " + Qt.application.pid + " 的消息"
font.pixelSize: 14
background: Rectangle {
radius: 8
border.color: messageInput.activeFocus ? Material.color(Material.Blue) : "#E0E0E0"
border.width: 2
color: messageInput.activeFocus ? "#E3F2FD" : "#FAFAFA" // 焦点状态样式
}
}
Button {
text: "📨 发送消息"
onClicked: {
if (messageInput.text.trim() !== "") { // 输入验证
sharedMemoryManager.sendMessage(messageInput.text) // 调用发送函数
messageInput.clear()
}
}
}
接收消息显示
TextArea {
id: receivedText
readOnly: true
placeholderText: "💬 接收到的消息将显示在这里..."
wrapMode: Text.Wrap
font.pixelSize: 13
selectByMouse: true
textFormat: TextEdit.RichText // 支持富文本显示
}
自动接收定时器
Timer {
id: autoReceiveTimer
interval: 1500 // 1.5秒间隔
repeat: true
onTriggered: sharedMemoryManager.receiveMessage() // 定时调用接收函数
}
消息接收处理函数
Connections {
target: sharedMemoryManager
onNewMessageReceived: {
var timestamp = new Date().toLocaleTimeString(Qt.locale(), "hh:mm:ss")
var formattedMessage = `<div style="margin: 8px 0; padding: 8px; background: #E8F5E8; border-radius: 6px; border-left: 4px solid #4CAF50;">
<div style="font-weight: bold; color: #2E7D32;">📩 新消息 [${timestamp}]</div>
<div style="color: #1B5E20; margin-top: 4px;">${message}</div>
<div style="font-size: 11px; color: #689F38; margin-top: 2px;">⏰ ${timestamp}</div>
</div>`
if (receivedText.text === receivedText.placeholderText) {
receivedText.text = formattedMessage
} else {
receivedText.text += formattedMessage
}
receivedText.cursorPosition = receivedText.length // 自动滚动到底部
}
}
键盘快捷键
Shortcut {
sequence: "Ctrl+N"
onActivated: sharedMemoryManager.startNewInstance() // 启动新实例快捷键
}
Shortcut {
sequence: "Ctrl+S"
onActivated: {
if (messageInput.text.trim() !== "") {
sharedMemoryManager.sendMessage(messageInput.text) // 发送消息快捷键
messageInput.clear()
}
}
}
二、所有源码
SharedMemoryManager.h文件源码
#ifndef SHAREDMEMORYMANAGER_H
#define SHAREDMEMORYMANAGER_H
#include <QObject>
#include <QSharedMemory>
#include <QTimer>
#include <QBuffer>
#include <QDataStream>
#include <QDateTime>
class SharedMemoryManager : public QObject
{
Q_OBJECT
Q_PROPERTY(QString status READ status NOTIFY statusChanged)
Q_PROPERTY(QString lastMessage READ lastMessage NOTIFY lastMessageChanged)
Q_PROPERTY(bool hasNewMessage READ hasNewMessage NOTIFY hasNewMessageChanged)
public:
explicit SharedMemoryManager(QObject *parent = nullptr);
~SharedMemoryManager();
QString status() const { return m_status; }
QString lastMessage() const { return m_lastMessage; }
bool hasNewMessage() const { return m_hasNewMessage; }
public slots:
void sendMessage(const QString &message);
void receiveMessage();
void clearStatus();
private slots:
void checkSharedMemory();
private:
void setupSharedMemory();
void updateStatus(const QString &status);
QSharedMemory *m_sharedMemory;
QTimer *m_checkTimer;
QString m_status;
QString m_lastMessage;
bool m_hasNewMessage;
static const QString SHARED_MEMORY_KEY;
signals:
void statusChanged();
void lastMessageChanged();
void hasNewMessageChanged();
void newMessageReceived(const QString &message, const QString ×tamp);
};
#endif // SHAREDMEMORYMANAGER_H
SharedMemoryManager.cpp文件源码
#include "SharedMemoryManager.h"
const QString SharedMemoryManager::SHARED_MEMORY_KEY = "QMLSharedMemoryDemo";
SharedMemoryManager::SharedMemoryManager(QObject *parent)
: QObject(parent)
, m_sharedMemory(new QSharedMemory(SHARED_MEMORY_KEY, this))
, m_checkTimer(new QTimer(this))
, m_hasNewMessage(false)
{
setupSharedMemory();
connect(m_checkTimer, &QTimer::timeout, this, &SharedMemoryManager::checkSharedMemory);
m_checkTimer->start(1000); // 每秒检查一次
}
SharedMemoryManager::~SharedMemoryManager()
{
if (m_sharedMemory->isAttached()) {
m_sharedMemory->detach();
}
}
void SharedMemoryManager::setupSharedMemory()
{
if (!m_sharedMemory->create(1024) && m_sharedMemory->error() == QSharedMemory::AlreadyExists) {
if (m_sharedMemory->attach()) {
updateStatus("已连接到现有共享内存");
} else {
updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());
}
} else if (m_sharedMemory->isAttached()) {
updateStatus("已创建新的共享内存");
} else {
updateStatus("无法创建共享内存: " + m_sharedMemory->errorString());
}
}
void SharedMemoryManager::sendMessage(const QString &message)
{
if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {
updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());
return;
}
if (message.isEmpty()) {
updateStatus("消息不能为空!");
return;
}
// 准备数据
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
// 写入消息和时间戳
out << message;
out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
// 写入共享内存
m_sharedMemory->lock();
char *to = static_cast<char*>(m_sharedMemory->data());
const char *from = buffer.data().data();
memcpy(to, from, qMin(m_sharedMemory->size(), static_cast<int>(buffer.size())));
m_sharedMemory->unlock();
updateStatus("消息已发送: " + message);
m_hasNewMessage = false;
emit hasNewMessageChanged();
}
void SharedMemoryManager::receiveMessage()
{
if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {
updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());
return;
}
// 从共享内存读取数据
m_sharedMemory->lock();
QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());
m_sharedMemory->unlock();
QBuffer buffer(&byteArray);
buffer.open(QBuffer::ReadOnly);
QDataStream in(&buffer);
QString message;
QString timestamp;
in >> message >> timestamp;
if (message.isEmpty()) {
updateStatus("没有可用的消息");
} else {
m_lastMessage = QString("[%1] %2").arg(timestamp, message);
emit lastMessageChanged();
emit newMessageReceived(message, timestamp);
updateStatus("收到新消息: " + message);
m_hasNewMessage = false;
emit hasNewMessageChanged();
}
}
void SharedMemoryManager::checkSharedMemory()
{
if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {
return;
}
m_sharedMemory->lock();
QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());
m_sharedMemory->unlock();
QBuffer buffer(&byteArray);
buffer.open(QBuffer::ReadOnly);
QDataStream in(&buffer);
QString message;
QString timestamp;
in >> message >> timestamp;
if (!message.isEmpty() && !m_hasNewMessage) {
m_hasNewMessage = true;
emit hasNewMessageChanged();
}
}
void SharedMemoryManager::clearStatus()
{
updateStatus("就绪");
m_hasNewMessage = false;
emit hasNewMessageChanged();
}
void SharedMemoryManager::updateStatus(const QString &status)
{
if (m_status != status) {
m_status = status;
emit statusChanged();
}
}
main.qml文件源码
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow {
id: window
width: 600
height: 500
title: "QML 共享内存演示"
visible: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// 状态显示
Rectangle {
Layout.fillWidth: true
height: 50
color: sharedMemoryManager.hasNewMessage ? "lightgreen" : "lightgray"
border.color: "gray"
radius: 5
RowLayout {
anchors.fill: parent
anchors.margins: 10
Label {
text: "状态:"
font.bold: true
}
Label {
Layout.fillWidth: true
text: sharedMemoryManager.status
elide: Text.ElideRight
}
Button {
text: "清除"
onClicked: sharedMemoryManager.clearStatus()
}
}
}
// 发送消息区域
GroupBox {
Layout.fillWidth: true
title: "发送消息"
ColumnLayout {
width: parent.width
TextField {
id: messageInput
Layout.fillWidth: true
placeholderText: "输入要发送的消息..."
text: "你好,这是来自QML共享内存的消息!"
}
Button {
Layout.alignment: Qt.AlignRight
text: "发送消息"
highlighted: true
onClicked: {
sharedMemoryManager.sendMessage(messageInput.text)
messageInput.clear()
}
}
}
}
// 接收消息区域
GroupBox {
Layout.fillWidth: true
Layout.fillHeight: true
title: "接收消息"
ColumnLayout {
width: parent.width
height: parent.height
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
TextArea {
id: receivedText
readOnly: true
placeholderText: "接收到的消息将显示在这里..."
text: sharedMemoryManager.lastMessage
wrapMode: Text.Wrap
}
}
RowLayout {
Layout.fillWidth: true
Button {
text: "接收消息"
onClicked: sharedMemoryManager.receiveMessage()
}
Button {
text: "清空"
onClicked: receivedText.clear()
}
Item { Layout.fillWidth: true }
Label {
text: sharedMemoryManager.hasNewMessage ? "● 有新消息" : "○ 无新消息"
color: sharedMemoryManager.hasNewMessage ? "green" : "gray"
}
}
}
}
// 消息历史
GroupBox {
Layout.fillWidth: true
Layout.preferredHeight: 120
title: "消息历史"
ListView {
id: messageHistory
anchors.fill: parent
clip: true
model: ListModel {}
delegate: Rectangle {
width: parent.width
height: 40
color: index % 2 === 0 ? "white" : "#f0f0f0"
Column {
anchors.fill: parent
anchors.margins: 5
Text {
text: message
font.bold: true
}
Text {
text: "时间: " + timestamp
font.pixelSize: 10
color: "gray"
}
}
}
}
}
}
// 新消息接收处理
Connections {
target: sharedMemoryManager
onNewMessageReceived: {
messageHistory.model.append({
message: message,
timestamp: timestamp
})
}
}
// 初始化完成提示
Component.onCompleted: {
console.log("QML共享内存演示程序已启动")
}
}
main.cpp文件源码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "SharedMemoryManager.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
// 注册共享内存管理器到QML
SharedMemoryManager sharedMemoryManager;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("sharedMemoryManager", &sharedMemoryManager);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
三、效果演示
将工程复制1个,然后打开2个工程,先运行第1个工程打开第1个进程,再把2个工程右键设为活动运行后则打开第2个进程,可以2个进程之间通过共享内存通讯。
