Currently I am using QLabel
s to display images on the GUI Application I am developing. It works by when the user clicks on the "Add Graphic" button, a new dynamic label is created and appears on the window. When the user double clicks the label, the file dialog opens and the user can select the image to display which works fine.
The requirement of the application is to restore the image when the application shuts down so that the user doesn't have to input the image again, which I am struggling to come up with a solution. I'm trying to use QBuffer
s and QSettings
to restore the images but there is a line of code which just crashes the application.
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
readSettings();
ui->setupUi(this);
// Set up the window size
this->setWindowTitle(QString::fromUtf8("Raspberry PI GUI v1.0"));
this->resize(800, 400);
// Add label Button
button = new QPushButton("Add Graphic", this);
button->setGeometry(QRect(QPoint(10, 20), QSize(200, 50)));
button->show();
QObject::connect(button, SIGNAL(pressed()), this, SLOT(input_label()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::input_label()
{
Label *label = new Label(this);
label->setText("New Graphic");
label->show();
}
void MainWindow::writeSettings()
{
QByteArray bArray;
QBuffer buffer(&bArray);
buffer.open(QIODevice::WriteOnly);
this->label->pixmap()->save(&buffer, "PNG"); // This line of code is crashing everything
QSettings settings("Save state", "GUIApp");
settings.beginGroup("MainWindow");
settings.setValue("image", bArray);
}
void MainWindow::readSettings()
{
QSettings settings("Save state", "GUIApp");
settings.beginGroup("MainWindow");
QByteArray image = settings.value("image", QByteArray()).toByteArray();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
writeSettings();
event->accept();
}
label.cpp
#include "label.h"
//---------------------------------------
// Deconstructor
//---------------------------------------
Label::~Label()
{
}
void Label::mousePressEvent(QMouseEvent *event)
{
// Move the coordinates on the main window
m_nMouseClick_X_Coordinate = event->x();
m_nMouseClick_Y_Coordinate = event->y();
}
void Label::mouseMoveEvent(QMouseEvent *event)
{
//-------------------------------------------------------------
// Allow the user to drag the graphics on the Display
//-------------------------------------------------------------
move(event->globalX()-m_nMouseClick_X_Coordinate-m_pParentWidget->geometry().x(),
event->globalY()-m_nMouseClick_Y_Coordinate-m_pParentWidget->geometry().y());
}
void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
//QByteArray bArray;
//QBuffer buffer(&bArray);
//buffer.open(QIODevice::WriteOnly);
//--------------------------------
// Open file dialog
//--------------------------------
QFileDialog dialog(this);
dialog.setNameFilter(tr("Images(*.png, *.dxf, *.jpg"));
dialog.setViewMode(QFileDialog::Detail);
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Images"),
"/home",
tr("Image Files (*.png *.jpg *.bmp)"));
if (!fileName.isEmpty())
{
QImage image(fileName);
Label::setPixmap(fileName);
Label::adjustSize();
}
}
QLabel::pixmap
returns a null pointer if no pixmap has been set. In the same way, you should check if your properties file has the image
entry set, and only in that case restore the image.
void MainWindow::writeSettings()
{
if (this->label->pixmap() != nullptr) {
QByteArray bArray;
QBuffer buffer(&bArray);
buffer.open(QIODevice::WriteOnly);
this->label->pixmap()->save(&buffer, "PNG");
QSettings settings("Save state", "GUIApp");
settings.beginGroup("MainWindow");
settings.setValue("image", bArray);
}
}
void MainWindow::readSettings()
{
QSettings settings("Save state", "GUIApp");
settings.beginGroup("MainWindow");
QByteArray image = settings.value("image").toByteArray();
if (!image.isNull()) {
QPixmap pixmap;
if (pixmap.loadFromData(image)) {
this->label->setPixmap(pixmap);
}
}
}
Update
When you create the QLabel
you are storing it in a local variable, but it is never assigned to this->label
, thus you probably are accessing garbage when doing any this->label->...
operation.
void MainWindow::input_label()
{
Label *label = new Label(this);
label->setText("New Graphic");
label->show();
this->label = label; // try with this
}
This is a workaround, if this works you must check the rest of logic since then you can be adding several QLabel
s, but only saving the last one... the same when restoring the state: this->label
may not be created, so you must create it, as well as to initialize this->label
to nullptr
in the constructor.
Several labels
For several labels, I'd suggest having a QList<QLabel*>
container instead of the single QLabel
member, and saving all of them. When restoring, just programmatically insert a new label before restoring the image.
class MainWindow ... {
// ...
QList<QLabel*> labels;
// ...
}
void MainWindow::input_label()
{
QLabel *label = new QLabel(this);
label->setText("New Graphic");
label->show();
this->labels.append(label);
}
void MainWindow::writeSettings()
{
int i = 1;
Q_FOREACH(auto label, labels) { // save all existing labels with an image
if (label->pixmap() != nullptr) {
QByteArray bArray;
QBuffer buffer(&bArray);
buffer.open(QIODevice::WriteOnly);
label->pixmap()->save(&buffer, "PNG");
QSettings settings("Save state", "GUIApp");
settings.beginGroup("MainWindow");
settings.setValue(QString("image-%1").arg(i), bArray);
++i;
}
}
}
void MainWindow::readSettings()
{
QSettings settings("Save state", "GUIApp");
settings.beginGroup("MainWindow");
int i = 1;
while (true) {
QByteArray image = settings.value(QString("image-%1").arg(i)).toByteArray();
if (!image.isNull()) {
QPixmap pixmap;
if (pixmap.loadFromData(image)) {
input_label(); // add new label
this->labels.back()->setPixmap(pixmap);
}
} else break; // no more images
++i;
}
}