Saving a qlistwidget after closing application - qt

I have a program that allows for a user to create a profile that saves values using qsettings, the user accesses their profile by clicking on the name in a qlistwidget. I am trying to save the names of the profiles by using a text file but I am having trouble saving more than one profile name at a time. thank you! here is the code:
for saving a profilename to the text document
void Profile::writeProfilenames()
{
QString profilename = ui->lineEdit_profilename->text();
profilename = profilename.simplified();
QFile pfile("profilenames.txt");
if (!pfile.open(QFile::WriteOnly | QIODevice::Text))
{
return;
}
QTextStream out(&pfile);
out << profilename;
pfile.flush();
pfile.close();
}
for retrieving the profile names from the document
void Profile::readProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QIODevice::ReadOnly |
QIODevice::Text))
{
return;
}
QString proname = pfile.readLine();
QListWidgetItem *itm = new QListWidgetItem;
itm->setText(proname);
ui->listWidget_profiles->insertItem(0,itm);
}
P.S. if you know of a better way to do this then feel free to share! (with example please)

I don't quite see why you're saving the list of names in a text file, while the settings themselves are saved in a platform-specific fashion using QSettings.
The code you show has several problems:
Presumably you don't want to "write" the name to the file, overwriting the existing contents at the beginning, but specifically to append to the file. You also must specify a writable path to the file, so far you're using the current working directory that is: variable, not under your control, and not necessarily writable. Your code also doesn't handle repeated names.
QFile is a proper C++ class, and embodies the RAII principles. You don't have to do anything to flush and close the file. The compiler takes care of generating the proper code for you. That's why you're using C++ and not C, after all. Yes, your code compiles, but it reads like C, and such verbosity is unnecessary and counterproductive.
You're only retrieving one name from the file. You want to retrieve all of them.
I'd say that you should dispense with the file access, set up your application's identification, a crucial prerequisite to using QSettings, and, finally, use them:
struct Profile {
QString name;
int age;
}
void saveProfiles(const QList<Profile> & profiles)
{
QSettings s;
s.beginWriteArray("profiles");
for (int i = 0; i < profiles.size(); ++i) {
s.setArrayIndex(i);
const Profile & p = profiles.at(i);
s.setValue("name", p.name);
s.setValue("age", p.age);
}
s.endArray(); //optional
}
QList<Profile> loadProfiles()
{
QList<Profile> profiles;
QSettings s;
int size = s.beginReadArray("profiles");
for (int i = 0; i < size; ++i) {
s.setArrayIndex(i);
Profile p;
p.name = s.value("name").toString();
p.age = s.value("age").toInt();
profiles << p;
}
s.endArray(); // optional
return profiles;
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
app.setOrganizationName("fluxD613"); // ideally use setOrganizationDomain instead
app.setApplicationName("fluxer");
...
return app.exec();
}

After a lot more research and trial and error I came up with the following code that does the trick:
this function is implemented when I close the profiles dialog window and return to the main window using QCloseEvent.
void Profile::writeProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QFile::WriteOnly | QIODevice::Text))
{
return;
}
for(int row = 0; row < ui->listWidget_profiles->count(); row++)
{
QListWidgetItem *item = ui->listWidget_profiles->item(row);
QTextStream out(&pfile);
out << item->text().simplified() << "\n";
}
pfile.close();
}
reading the list of profilenames is implemented when I open the dialog window just under ui->setup(this).
void Profile::readProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QIODevice::ReadOnly |
QIODevice::Text))
{
return;
}
QTextStream in(&pfile);
while (!in.atEnd())
{
QString line = in.readLine();
QListWidgetItem *item = new QListWidgetItem;
item->setText(line);
ui->listWidget_profiles->addItem(item);
}
pfile.close();
}
I am now working on making sure the user does not enter a profilename that already exists and deleting a profilename from the QListWidget.

Related

How to wait for Async lamda function to finish before returning value in a QT Web Assembly

so I wrote a programm for my thesis in Qt and now i am supposed to turn it into a working web assembly, which wasnt a real problem except for the filedownload part. I rewrote my filedownload method from:
QString costumfile::read(QString filename){
QString fileName = QFileDialog::getOpenFileName(nullptr, filename, "", "Text Files (*.txt )");
QFile file(filename);
qDebug()<<filename<<"filename";
if(!file.open(QFile::ReadOnly |
QFile::Text))
{
qDebug() << " Could not open the file for reading";
return "";
}
QTextStream in(&file);
QString myText = in.readAll();
//qDebug() << myText;
file.close();
return myText;
}
To this:
QString costumfile::read(QString filename)
{
QMessageBox msgBox;
QString textUser="Open" + filename;
msgBox.setText(textUser);
msgBox.exec();
QString text="hallo";
qDebug()<<filename;
auto fileContentReady = [&](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
msgBox.setText("Error");
msgBox.exec();
} else {
text=fileContent;
qDebug()<<text<<"texstis";
return fileContent;
}
return fileContent;
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
and the problem is that the return doesnt wait for the lambda function because its asynch...
I then tried using eventloops which works fine in the Destop applikation but isnt supported in the webassembly Applikation.
So does someone have a good idea how to wait for the fileContentReady Function?
As far as I know, Qt for WebAssembly currently does not support waiting using event loops (at least Qt 6.2 does not). See Qt wiki:
"Nested event loops are not supported. Applications should not call e.g. QDialog::exec() or create a new QEventLoop object."
https://wiki.qt.io/Qt_for_WebAssembly
So you would have to modify your method to handle the asynchronous call. What I mean is that whatever you want to do with the file, you can write directly into the fileContentReady lambda you have. If this is a generic function, you can let the caller register a done callback to execute when the file is ready. Something like:
QString costumfile::read(QString filename,
const std::function<void(const QString&)>& done)
{
...
auto fileContentReady = [=](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
// Report error
} else {
text=fileContent;
qDebug()<<text<<"texstis";
done(text);
}
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
// When calling costumfile::read
read(filename, [=] (const QString& text) {
// Do something with `text`
});
Also, about the usage of QMessageBox exec(). This can also cause problems as it internally creates a nested event loop which is not yet supported in Qt for WebAssembly. Instead use the show() method.
auto msgBox = new QMessageBox();
msgBox->setText(textUser);
connect(msgBox, &QMessageBox::finished, &QMessageBox::deleteLater);
msgBox->show();

How to save a frame using QMediaPlayer?

I want to save an image of a frame from a QMediaPlayer. After reading the documentation, I understood that I should use QVideoProbe. I am using the following code :
QMediaPlayer *player = new QMediaPlayer();
QVideoProbe *probe = new QVideoProbe;
connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
qDebug()<<probe->setSource(player); // Returns true, hopefully.
player->setVideoOutput(myVideoSurface);
player->setMedia(QUrl::fromLocalFile("observation.mp4"));
player->play(); // Start receving frames as they get presented to myVideoSurface
But unfortunately, probe->setSource(player) always returns false for me, and thus my slot processFrame is not triggered.
What am I doing wrong ? Does anybody have a working example of QVideoProbe ?
You're not doing anything wrong. As #DYangu pointed out, your media object instance does not support monitoring video. I had the same problem (and same for QAudioProbe but it doesn't interest us here). I found a solution by looking at this answer and this one.
The main idea is to subclass QAbstractVideoSurface. Once you've done that, it will call the method QAbstractVideoSurface::present(const QVideoFrame & frame) of your implementation of QAbstractVideoSurface and you will be able to process the frames of your video.
As it is said here, usually you will just need to reimplement two methods :
supportedPixelFormats so that the producer can select an appropriate format for the QVideoFrame
present which allows to display the frame
But at the time, I searched in the Qt source code and happily found this piece of code which helped me to do a full implementation. So, here is the full code for using a "video frame grabber".
VideoFrameGrabber.cpp :
#include "VideoFrameGrabber.h"
#include <QtWidgets>
#include <qabstractvideosurface.h>
#include <qvideosurfaceformat.h>
VideoFrameGrabber::VideoFrameGrabber(QWidget *widget, QObject *parent)
: QAbstractVideoSurface(parent)
, widget(widget)
, imageFormat(QImage::Format_Invalid)
{
}
QList<QVideoFrame::PixelFormat> VideoFrameGrabber::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
Q_UNUSED(handleType);
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB32
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555
<< QVideoFrame::Format_ARGB8565_Premultiplied
<< QVideoFrame::Format_BGRA32
<< QVideoFrame::Format_BGRA32_Premultiplied
<< QVideoFrame::Format_BGR32
<< QVideoFrame::Format_BGR24
<< QVideoFrame::Format_BGR565
<< QVideoFrame::Format_BGR555
<< QVideoFrame::Format_BGRA5658_Premultiplied
<< QVideoFrame::Format_AYUV444
<< QVideoFrame::Format_AYUV444_Premultiplied
<< QVideoFrame::Format_YUV444
<< QVideoFrame::Format_YUV420P
<< QVideoFrame::Format_YV12
<< QVideoFrame::Format_UYVY
<< QVideoFrame::Format_YUYV
<< QVideoFrame::Format_NV12
<< QVideoFrame::Format_NV21
<< QVideoFrame::Format_IMC1
<< QVideoFrame::Format_IMC2
<< QVideoFrame::Format_IMC3
<< QVideoFrame::Format_IMC4
<< QVideoFrame::Format_Y8
<< QVideoFrame::Format_Y16
<< QVideoFrame::Format_Jpeg
<< QVideoFrame::Format_CameraRaw
<< QVideoFrame::Format_AdobeDng;
}
bool VideoFrameGrabber::isFormatSupported(const QVideoSurfaceFormat &format) const
{
const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
const QSize size = format.frameSize();
return imageFormat != QImage::Format_Invalid
&& !size.isEmpty()
&& format.handleType() == QAbstractVideoBuffer::NoHandle;
}
bool VideoFrameGrabber::start(const QVideoSurfaceFormat &format)
{
const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
const QSize size = format.frameSize();
if (imageFormat != QImage::Format_Invalid && !size.isEmpty()) {
this->imageFormat = imageFormat;
imageSize = size;
sourceRect = format.viewport();
QAbstractVideoSurface::start(format);
widget->updateGeometry();
updateVideoRect();
return true;
} else {
return false;
}
}
void VideoFrameGrabber::stop()
{
currentFrame = QVideoFrame();
targetRect = QRect();
QAbstractVideoSurface::stop();
widget->update();
}
bool VideoFrameGrabber::present(const QVideoFrame &frame)
{
if (frame.isValid())
{
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
const QImage image(cloneFrame.bits(),
cloneFrame.width(),
cloneFrame.height(),
QVideoFrame::imageFormatFromPixelFormat(cloneFrame .pixelFormat()));
emit frameAvailable(image); // this is very important
cloneFrame.unmap();
}
if (surfaceFormat().pixelFormat() != frame.pixelFormat()
|| surfaceFormat().frameSize() != frame.size()) {
setError(IncorrectFormatError);
stop();
return false;
} else {
currentFrame = frame;
widget->repaint(targetRect);
return true;
}
}
void VideoFrameGrabber::updateVideoRect()
{
QSize size = surfaceFormat().sizeHint();
size.scale(widget->size().boundedTo(size), Qt::KeepAspectRatio);
targetRect = QRect(QPoint(0, 0), size);
targetRect.moveCenter(widget->rect().center());
}
void VideoFrameGrabber::paint(QPainter *painter)
{
if (currentFrame.map(QAbstractVideoBuffer::ReadOnly)) {
const QTransform oldTransform = painter->transform();
if (surfaceFormat().scanLineDirection() == QVideoSurfaceFormat::BottomToTop) {
painter->scale(1, -1);
painter->translate(0, -widget->height());
}
QImage image(
currentFrame.bits(),
currentFrame.width(),
currentFrame.height(),
currentFrame.bytesPerLine(),
imageFormat);
painter->drawImage(targetRect, image, sourceRect);
painter->setTransform(oldTransform);
currentFrame.unmap();
}
}
VideoFrameGrabber.h
#ifndef VIDEOFRAMEGRABBER_H
#define VIDEOFRAMEGRABBER_H
#include <QtWidgets>
class VideoFrameGrabber : public QAbstractVideoSurface
{
Q_OBJECT
public:
VideoFrameGrabber(QWidget *widget, QObject *parent = 0);
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;
bool isFormatSupported(const QVideoSurfaceFormat &format) const;
bool start(const QVideoSurfaceFormat &format);
void stop();
bool present(const QVideoFrame &frame);
QRect videoRect() const { return targetRect; }
void updateVideoRect();
void paint(QPainter *painter);
private:
QWidget *widget;
QImage::Format imageFormat;
QRect targetRect;
QSize imageSize;
QRect sourceRect;
QVideoFrame currentFrame;
signals:
void frameAvailable(QImage frame);
};
#endif //VIDEOFRAMEGRABBER_H
Note : in the .h, you will see I added a signal taking an image as a parameter. This will allow you to process your frame anywhere in your code. At the time, this signal took a QImage as a parameter, but you can of course take a QVideoFrame if you want to.
Now, we are ready to use this video frame grabber:
QMediaPlayer* player = new QMediaPlayer(this);
// no more QVideoProbe
VideoFrameGrabber* grabber = new VideoFrameGrabber(this);
player->setVideoOutput(grabber);
connect(grabber, SIGNAL(frameAvailable(QImage)), this, SLOT(processFrame(QImage)));
Now you just have to declare a slot named processFrame(QImage image) and you will receive a QImage each time you will enter the method present of your VideoFrameGrabber.
I hope that this will help you!
After Qt QVideoProbe documentation:
bool QVideoProbe::setSource(QMediaObject *mediaObject)
Starts monitoring the given mediaObject.
If there is no media object associated with mediaObject, or if it is
zero, this probe will be deactivated and this function wil return
true.
If the media object instance does not support monitoring video, this
function will return false.
Any previously monitored objects will no longer be monitored. Passing
in the same object will be ignored, but monitoring will continue.
So it seems your "media object instance does not support monitoring video"
TL;DR: https://gist.github.com/JC3/a7bab65acbd7659d1e57103d2b0021ba (only file)
I had a similar issue (5.15.2; although in my case I was on Windows, was definitely using the DirectShow back-end, the probe attachment was returning true, the sample grabber was in the graph, but the callback wasn't firing).
I never figured it out but needed to get something working so I kludged one out of a QAbstractVideoSurface, and it's been working well so far. It's a bit simpler than some of the other implementations in this post, and it's all in one file.
Note that Qt 5.15 or higher is required if you intend to both process frames and play them back with this, since the multi-surface QMediaPlayer::setVideoOutput wasn't added until 5.15. If all you want to do is process video you can still use the code below as a template for pre-5.15, just gut the formatSource_ parts.
Code:
VideoProbeSurface.h (the only file; link is to Gist)
#ifndef VIDEOPROBESURFACE_H
#define VIDEOPROBESURFACE_H
#include <QAbstractVideoSurface>
#include <QVideoSurfaceFormat>
class VideoProbeSurface : public QAbstractVideoSurface {
Q_OBJECT
public:
VideoProbeSurface (QObject *parent = nullptr)
: QAbstractVideoSurface(parent)
, formatSource_(nullptr)
{
}
void setFormatSource (QAbstractVideoSurface *source) {
formatSource_ = source;
}
QList<QVideoFrame::PixelFormat> supportedPixelFormats (QAbstractVideoBuffer::HandleType type) const override {
return formatSource_ ? formatSource_->supportedPixelFormats(type)
: QList<QVideoFrame::PixelFormat>();
}
QVideoSurfaceFormat nearestFormat (const QVideoSurfaceFormat &format) const override {
return formatSource_ ? formatSource_->nearestFormat(format)
: QAbstractVideoSurface::nearestFormat(format);
}
bool present (const QVideoFrame &frame) override {
emit videoFrameProbed(frame);
return true;
}
signals:
void videoFrameProbed (const QVideoFrame &frame);
private:
QAbstractVideoSurface *formatSource_;
};
#endif // VIDEOPROBESURFACE_H
I went for the quickest-to-write implementation possible so it just forwards supported pixel formats from another surface (my intent was to both probe and play back to a QVideoWidget) and you get whatever format you get. I just needed to grab subimages into QImages though, which handles most common formats. But you could modify this to force any formats you want (e.g. you might want to just return formats supported by QImage or filter out source formats not supported by QImage), etc.).
Example set up:
QMediaPlayer *player = ...;
QVideoWidget *widget = ...;
// forward surface formats provided by the video widget:
VideoProbeSurface *probe = new VideoProbeSurface(...);
probe->setFormatSource(widget->videoSurface());
// same signal signature as QVideoProbe's signal:
connect(probe, &VideoProbeSurface::videoFrameProbed, ...);
// the key move is to render to both the widget (for viewing)
// and probe (for processing). fortunately, QMediaPlayer can
// take a list:
player->setVideoOutput({ widget->videoSurface(), probe });
Notes
The only really sketchy thing I had to do was const_cast the QVideoFrame on the receiver side (for read-only access), since QVideoFrame::map() isn't const:
if (const_cast<QVideoFrame&>(frame).map(QAbstractVideoBuffer::ReadOnly)) {
...;
const_cast<QVideoFrame&>(frame).unmap();
}
But the real QVideoProbe would make you do the same thing so, I don't know what's up with that -- it's a strange API. I ran some tests with sw, native hw, and copy-back hw renderers and decoders and map/unmap in read mode seem to be functioning OK, so, whatever.
Performance-wise, the video will bog down if you spend too much time in the callback, so design accordingly. However, I didn't test QueuedConnection, so I don't know if that'd still have the issue (although the fact that the signal parameter is a reference would make me wary of trying it, as well as conceivable issues with the GPU releasing the memory before the slot ends up being called). I don't know how QVideoProbe behaves in this regard, either. I do know that, at least on my machine, I can pack and queue Full HD (1920 x 1080) resolution QImages to a thread pool for processing without slowing down the video.
You probably also want to implement some sort of auto-unmapper utility object for exception safe unmap(), etc. But again, that's not unique to this, same thing you'd have to do with QVideoProbe.
So hopefully that helps somebody else.
Example QImage Use
PS, example of packing arbitrarily-formatted QVideoFrames into a QImage in:
void MyVideoProcessor::onFrameProbed(const QVideoFrame &frame) {
if (const_cast<QVideoFrame&>(frame).map(QAbstractVideoBuffer::ReadOnly)) {
auto imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat());
QImage image(frame.bits(), frame.width(), frame.height(), frame.bytesPerLine(), imageFormat);
// *if* you want to use this elsewhere you must force detach:
image = image.copy();
// but if you don't need to use it past unmap(), you can just
// use the original image instead of a copy.
// <---- now do whatever with the image, e.g. save() it.
// if you *haven't* copied the image, then, before unmapping,
// kill any internal data pointers just to be safe:
image = QImage();
const_cast<QVideoFrame&>(frame).unmap();
}
}
Notes about that:
Constructing a QImage directly from the data is fast and essentially free: no copies are done.
The data buffers are only technically valid between map and unmap, so if you intend to use the QImage outside of that scope, you'll want to use copy() (or anything else that forces a detach) to force a deep copy.
You also probably want to ensure that the original not-copied QImage is destructed before calling unmap. It's unlikely to cause problems but it's always a good idea to minimize how many invalid pointers are hanging around at any given time, and also the QImage docs say "The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer". Best to be strict about it.

Reading from .can files

I want to read .can files in Qt, I found out it is similiar to ini files so i used QSettings::IniFormat, i look for 2 attributes( say "rate" and "name").
code:
for(int i=0; i<files.count();i++)
{
QSettings file(files[i], QSettings::IniFormat);
QStringList keys = file.allKeys();
foreach(const QString& key, keys)
{
if(key.endsWith("/rate"))
{
QString Rate = file.value(key).toString();
qDebug() << Rate;
}
if(key.endsWith("/name"))
{
QString name = file.value(key).toString();
qDebug()<<name;
}
Problem is my can files has lot of "name" attribute, so this method is returning all the "name" attributes. I want to store the "name" attribute which the program finds right after "rate", there can be "name" attribute before "rate", so i just want to store the attribute which the program finds immediately after it finds "rate".
I don't know about .can files, I searched a little about them but couldn't find anything about them related to ini format.
Anyways, I rewrote your code to output the very first name attribute it finds after each rate encountered.
bool rateAttrFound = false;
for(int i=0; i<files.count();i++)
{
QSettings file(files[i], QSettings::IniFormat);
QStringList keys = file.allKeys();
foreach(const QString& key, keys)
{
if(key.endsWith("/rate"))
rateAttrFound = true;
if(key.endsWith("/name"))
{
if(rateAttrFound){
qDebug() << file.value(key).toString();
rateAttrFound = false;
}
}
}
}

Multiple file insert in QTreewidget using Drag and Drop events

I am working in Qt4.7 on MAC OSx. I want to insert files in QTreewidget using the Drag and Drop events. I want to add multiple files at a time. I am using this:
void MainWindow::dragEnterEvent(QDragEnterEvent * e)
{
if(e->mimeData()->hasUrls())
{
e->acceptProposedAction();
}
}
void MainWindow::dropEvent(QDropEvent * e)
{
QTreeWidgetItem *Items = new QTreeWidgetItem(ui->treeWidget);
foreach(const QUrl &url,e->mimeData()->urls())
{
const QString &filename = url.toLocalFile();
qDebug() << "Dropped file:" << filename;
Items->setText(0,filename);
}
}
Using this, I am able to insert only one file at a time. Is there anyone who can help me out in this issue ? Your help will really appreciate.
Thanks,
Ashish.
The problem is that you create only one tree view item. However you need one per each Url you passed with the mime data:
void MainWindow::dropEvent(QDropEvent *e)
{
foreach(const QUrl &url, e->mimeData()->urls()) {
QString filename = url.toLocalFile();
qDebug() << "Dropped file:" << filename;
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
item->setText(0, filename);
}
}

Share multiple segment with QSharedMemory

i want to use QSharedMemory to share data between 2 applications using it for sharing one segment works perfectly but when i try 2 share more than one i have access just to the last one
this my code
sharedMemroy.cpp in the first application
void SharedMemory::loadIntoSharedMem(QString memoryKey,QString &data)
{
sharedMem.setKey(memoryKey);
if (sharedMem.isAttached())
{
sharedMem.detach();
}
if( data.length())
{
// load into shared memory
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << data;
int size = buffer.size();
if (!sharedMem.create(size)) {
qDebug()<<"Unable to create shared memory segment."<<sharedMem.isAttached()<<" "<<sharedMem.error();
}
sharedMem.lock();
char *to = (char*)sharedMem.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMem.size(), size));
sharedMem.unlock();
}
else
{
qDebug()<< "no data to share"
}
}
and in main
SharedMemory sh;
sh.loadIntoSharedMem("memo1",data1 );
sh.loadIntoSharedMem("memo2",data2 );
sh.loadIntoSharedMem("memo3",data3 );
and on showSharedData.cpp in the seconde application
QString ShowSharedMemory::loadFromSharedMem(QString memoryKey)
{
sharedMem.setKey(memoryKey);
if (!sharedMem.attach())
{
qDebug()<<"Unable to load!";
return"";
}
QBuffer buffer;
QDataStream in(&buffer);
QString text;
sharedMem.lock();
buffer.setData((char*)sharedMem.constData(), sharedMem.size());
buffer.open(QBuffer::ReadOnly);
in >> text;
sharedMem.unlock();
sharedMem.detach();
return text;
}
and in main
data1=showMemory.loadFromSharedMem("memo1");
data2=showMemory.loadFromSharedMem("memo2");
data3=showMemory.loadFromSharedMem("memo3");
thanks for your help
Your problem is that second write attempt overwrites all data. You need to implement cross-process containers (boost has some), like QList, if you want to share data via shared memory. It is hard topic.
I propose you to use sockets to send strings between processes. Or other platform depended mechanism (for example, pipes on windows).

Resources