Qt/C++ - Lesson 029. Picture in database in Qt – Saving and Loading

BLOB, QPixmap, Qt, SQL, SQLite, база данных, изображение

Images in the database can be stored in BLOB format ( Binary Large Object ), that is an array of binary data format. BLOB format is also suitable for storing audio and video data in databases.

Consider the saving and loading of the image from the database as an example of the next application that screenshot of your computer screen will be saved in the database and displayed in a special a QLabel , when the corresponding entry is selected in a QTableView , which will display all the records of the images stored in the database .

Thus we have a database table with the following fields:

  • id (INTEGER) - id;
  • Name (VARCHAR(255)) - the name stored in the database file data;
  • Pic (BLOB) - a field for storing images in the database.

If you do not go into detail in the lesson, the most valuable information on this topic at the end of mainwindow.cpp file in the following methods:

  • MainWindow::on_screenButton_clicked()
  • MainWindow::slotCurrentPic(QModelIndex index)

Project structure

  • PicDataBase.pro - the profile of the project;
  • database.h - header file wrapper class for working with the database;
  • database.cpp - file source wrapper class codes for the work with the database;
  • mainwindow.h - header file of the main application window;
  • mainwindow.cpp - file source code of the main application window;
  • mainwindow.ui - form the main application window;
  • main.cpp - the main file of the application source code.


In the designer's apply this form of the application window.


In profile, the application is mandatory connect sql module for working with databases.


The file is created by default and is not subject to change.


To work with a database using already familiar class-wrapper DataBase.

ATTENTION!!! - The database file is created in the folder C:/example , so the correct method or DataBase::connectToDataBase() or create an example folder on drive C.

#ifndef DATABASE_H
#define DATABASE_H

#include <QObject>
#include <QSql>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDatabase>
#include <QFile>
#include <QDate>
#include <QDebug>

#define DATABASE_HOSTNAME   "ScreenDataBase"
#define DATABASE_NAME       "Screen.db"

#define TABLE                   "ScreenTable"       
#define TABLE_NAME              "Name"              
#define TABLE_PIC               "Pic"               

class DataBase : public QObject
    explicit DataBase(QObject *parent = 0);
    void connectToDataBase();

    QSqlDatabase    db;

    bool openDataBase();        
    bool restoreDataBase();     
    void closeDataBase();       
    bool createTable();        

public slots:
    bool insertIntoTable(const QVariantList &data);     
    bool insertIntoTable(const QString &name, const QByteArray &pic);

#endif // DATABASE_H


#include "database.h"

DataBase::DataBase(QObject *parent) : QObject(parent)




void DataBase::connectToDataBase()
    if(!QFile("C:/example/" DATABASE_NAME).exists()){
    } else {

bool DataBase::restoreDataBase()
        return (this->createTable()) ? true : false;
    } else {
        qDebug() << "Не удалось восстановить базу данных";
        return false;
    return false;

bool DataBase::openDataBase()
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("C:/example/" DATABASE_NAME);
        return true;
    } else {
        return false;

void DataBase::closeDataBase()

bool DataBase::createTable()
    QSqlQuery query;
    if(!query.exec( "CREATE TABLE " TABLE " ("
                            "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                            TABLE_NAME     " VARCHAR(255)    NOT NULL,"
                            TABLE_PIC      " BLOB            NOT NULL"
                        " )"
        qDebug() << "DataBase: error of create " << TABLE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    return false;

bool DataBase::insertIntoTable(const QVariantList &data)
    QSqlQuery query;
    query.prepare("INSERT INTO " TABLE " ( " TABLE_NAME ", "
                                             TABLE_PIC " ) "
                  "VALUES (:Name, :Pic)");
    query.bindValue(":Name",        data[0].toString());
    query.bindValue(":Pic",         data[1].toByteArray());

        qDebug() << "error insert into " << TABLE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    return false;

bool DataBase::insertIntoTable(const QString &name, const QByteArray &pic)
    QVariantList data;

        return true;
        return false;


In addition to the usual facilities of DataBase and QSqlTableModel , and model tuning techniques and concepts that were used in previous articles for QSqlRelationalTableModel and QSqlQueryModel , in this file there are slots to handle clicking on the button and click on the record in the table.

The first slot carries creating screenshot of the screen and add it to the database, and the second slot reconstructs the image from the database, taking it from QSqlTableModel object in QTableView and placing it in QLabel in the main application window.


#include <QMainWindow>
#include <QSqlTableModel>
#include <QModelIndex>

#include "database.h"

namespace Ui {
class MainWindow;

class MainWindow : public QMainWindow

    explicit MainWindow(QWidget *parent = 0);

private slots:
    // Slot to record screenshots into the database
    void on_screenButton_clicked();
    // The slot for the getting of image from the database
    void slotCurrentPic(QModelIndex index);

    Ui::MainWindow *ui;
    DataBase        *db;
    QSqlTableModel  *model;

    void setupModel(const QString &tableName, const QStringList &headers);
    void createUI();

#endif // MAINWINDOW_H


All main work with the database, and the image is made in the following techniques:

  • MainWindow::on_screenButton_clicked()
  • MainWindow::slotCurrentPic(QModelIndex index)
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QApplication>
#include <QBuffer>
#include <QScreen>

MainWindow::MainWindow(QWidget *parent) :
    ui(new Ui::MainWindow)

    db = new DataBase();

                     QStringList() << trUtf8("id")
                                   << trUtf8("Имя изображения")
                                   << trUtf8("изображение")


    delete ui;

void MainWindow::setupModel(const QString &tableName, const QStringList &headers)
    model = new QSqlTableModel(this);

    /* Set the columns names in a table with sorted data
     * */
    for(int i = 0, j = 0; i < model->columnCount(); i++, j++){

void MainWindow::createUI()
    ui->tableView->setColumnHidden(0, true);    // Hide the column id Records
    ui->tableView->setColumnHidden(2, true);    // Hide the column with image
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);  // editing is not allowed
    ui->tableView->horizontalHeader()->setStretchLastSection(true);     // Stretch the last column of around tableView

    /* Connect the signal to change the selection of the current row in the table 
     * to the slot to set the image picLabel
     * */
    connect(ui->tableView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
            this, SLOT(slotCurrentPic(QModelIndex)));


void MainWindow::on_screenButton_clicked()
    /* Make a screenshot of the screen and save it as QByteArray object
     * */
    QScreen *screen = QApplication::primaryScreen();    // Take a screen object
    QPixmap inPixmap = screen->grabWindow( 0 );         // Keeping it in the image of the object QPixmap
    QByteArray inByteArray;                             // Create QByteArray object to save the image
    QBuffer inBuffer( &inByteArray );                   // Saving images produced through the buffer
    inBuffer.open( QIODevice::WriteOnly );              // Open buffer
    inPixmap.save( &inBuffer, "PNG" );                  // Write inPixmap in inByteArray

    // Write a screenshot of the database
    db->insertIntoTable(QDateTime::currentDateTime().toString("dd.MM.yyyy_hh:mm:ss.png"), inByteArray);


void MainWindow::slotCurrentPic(QModelIndex index)
    QPixmap outPixmap = QPixmap(); // Create QPixmap, which will be placed in picLabel
    /* Taking the image data from the table as QByteArray and put them in QPixmap
     * */
    outPixmap.loadFromData(model->data(model->index(index.row(), 2)).toByteArray());


The result is an application that allows you to save screen screenshots in the database and restore this image by displaying it in QLabel window.


We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
Support the author Donate

Здравствуйте, при сборке выдаёт две такие ошибки C:\untitled1\mainwindow.cpp:99: ошибка: C2039: picLabel: ­Ґ пў«пҐвбп з«Ґ­®¬ "Ui::MainWindow" C:\untitled1\mainwindow.cpp:99: ошибка: C2227: ўла ¦Ґ­ЁҐ б«Ґў  ®в "->setPixmap" ¤®«¦­® гЄ §лў вм ­  вЁЇ Є« бб , бвагЄвгал Ё«Ё ®ЎкҐ¤Ё­Ґ­Ёп «ЁЎ® ­  г­ЁўҐаб «м­л© вЁЇ Как это исправить, помогите пожалуйста


И ещё не могли бы подсказать что нужно изменить в коде чтобы по нажатию на кнопку в БД загружался не скриншот, а выбранные и уже существующие изображения?
Заранее спасибо!

Интерфейс приложения сделать через графический дизайнер так, как сделано в данной статье. Убедиться, что существует QLabel в интерфейсе, с таким же названием, как в этой статье.

Создать QPixmap из файла, указав путь к файлу.

QPixmap pixmap("/path/to/file.png");

Спасибо большое! Но если я правильно понял, то для каждого файла нужно будет описывать каждый раз путь? А можно сделать как-то так чтобы можно было выбирать их?

Используйте QFileDialog класс. У него есть статические методы, которые позволяют открыть диалог, в котором можно выбрать либо один файл, либо несколько файлов.

Например, чтобы забрать имя одного файла:

QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
                                                tr("Images (*.png *.xpm *.jpg)"));

Или нескольких файлов:

QStringList files = QFileDialog::getOpenFileNames(
                        "Select one or more files to open",
                        "Images (*.png *.xpm *.jpg)");

Ну и закидываете это всё в QPixmap, ну а дальше уже как по накатанной.

QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "/home", tr("Images (*.png *.xpm *.jpg)")); 
QPixmap inixmap = fileName; // Сохраняем его в изображение объекта QPixmap; 
QByteArray inByteArray; // Создаём объект QByteArray для сохранения изображения QBuffer 
inBuffer( &inByteArray ); 
inBuffer.open( QIODevice::WriteOnly ); // Открываем буффер 
inixmap.save( &inBuffer, "*.png *.xpm *.jpg" ); 
db->insertIntoTable(QDateTime::currentDateTime().toString("DSC02442.png"), inByteArray); 

Так не верно?

Нет. не верно. Ошибка вот в этой строке:

QPixmap inixmap = fileName; // Сохраняем его в изображение объекта QPixmap; 

Выше я показывал, как что нужно путь передавать в качестве аргумента

QPixmap pixmap("/path/to/file.png");

То есть

QPixmap inixmap(fileName);
  • #
  • Jan. 21, 2018, 2:29 p.m.

Здравствуйте, также реализовывал приложение и понадобилось сохранить картинку. Но я брал напрямую через буфер

QPixmap pix(clipboard->pixmap());

            QBuffer inBuffer( &picture);
            inBuffer.open( QIODevice::WriteOnly );
            pix.save( &inBuffer, "PNG" );

Picture имеет тип QByteArray как и у Вас. При проверке наличии данных через консоль
qDebug() << "Здесь картинка из буфера:" << picture;
Содержимое отображается

Но при вставке данных в таблицу возникает ошибка

QSqlError("1", "Unable to execute statement", "unrecognized token: \"\u001A\"")

qDebug() << "That's pictire in binary code" <<picture;
str = "Insert into commands_" + profile_name +" (name, seq, pic) values (" + name + "," + content + ", " +picture+" );";
qDebug() << str;
if (query.exec(str))
qDebug() << "OK";

В таблице создано 1 поле для картинки qr = "CREATE TABLE commands_" +p[1] + " (name text NOT NULL, seq text NOT NULL, pic BLOB NOT NULL);";
  • #
  • Jan. 21, 2018, 2:31 p.m.

также вот вывод  текста самого запроса

"Insert into commands_one (name, seq, pic) values ('bnbvn','\n1. bvnb\n2. bvnb', �PNG\r\n\u001A\n );"

  • #
  • Jan. 21, 2018, 2:32 p.m.

Перед этим приложение работало отлично, ошибка связана именно с добавлением данного поля

Добрый день!
Подготовьте изображение к вставке в базу данных через bind, как сделано в методе insertIntoTable, в данном примере.
Больше похоже на то, что вылетает неожиданный символа при попытке вставки в базу данных, bind может нивелировать эту проблему.


Hi, could you please show how to delete file from image Blob?  also if the same image exist in Blob then don't over write..


You can use QSqlQuery for delete record with blob image. But you need know id of this record.

For example
bool DataBase::removeRecord(const int id)
    QSqlQuery query;
    query.prepare("DELETE FROM " TABLE " WHERE id= :ID ;");
    query.bindValue(":ID", id);
        qDebug() << "error delete row " << TABLE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    return false;
For check of existing row you can use select sql request in QSqlQuery

thanks, but Id should be the same the one as i select the image in tree view.

Yes. But, if you use QSqlTableModel for TreeView, that you have id of image, I think. Or You should create hidden column with Id of image.


Thanks, It would be really kool, if you fix the code, i am trying but as i am new i dont understand.

my problem is:  i want to delete the selected image from tree view.  and second problem is, i want to add an image, if that image is already exists. it should not shows into data base also not appear into tree view .. here are the files https://drive.google.com/file/d/1z7GG48GYkk4A3lsDKF9P6OqxHQ5ye_Fb/view

I will see to these sources, but i have a little free time during the week usually. I will not promise anything.


Thanks, i will be very glad :)  no problem take your time.


Hello Evileg if you could please make it in this weekend, i would be very glad :)

You have model for Picture List and you use id in first column. It means, you can use this model for getting ID of this picture.

model->data(model->index(selectedRow, 0)).toInt();
You need just to get this selectedRow , when you click in the table, this table can to invoke signal clicked(const QModelIndex & index ). You can get row from index. Via index.row()

Thanks for the help, but i still dont get that. i tried to complie it but i got errors. i want to share you my project file once again. here is my Email: soz7557@thi.de due to  privacy if you please send me msg i will send you the files on email. Thanks


Here i upload my code : https://stackoverflow.com/questions/49112880/qtableview-delete-selected-file-from-sql-database

1) You need create variable for storing of ID in MainWindow

int m_selectedId {0};
2) store this variable
void MainWindow::slotCurrentPic(QModelIndex index)
    m_selectedId = model->data(model->index(index.row(), 0)).toInt();

3) Delete ID
void MainWindow::on_Delete_Button_clicked(QModelIndex index)

And please, ask your next questions on the forum

Thanks but Now i have an error again id is not decleared parameter


My question is now, i am able to delete the images, but my Table view is not updating untill if dont do other function in my Gui

void MainWindow::on_Delete_Button_clicked()

QMessageBox::StandardButton reply;
     reply = QMessageBox::question(this, "Delete", "Do you really want to delete?",
     if (reply == QMessageBox::Yes) {
       qDebug() << "Yes was clicked";
       QSqlRecord record;
           int i = ui->tableView->currentIndex().row(); 
           record = model->record(i);
    else {
       qDebug() << "Yes was *not* clicked";



I think, you should to select one more your model.


Hello EVILEG,  i am having new problem. with data base,  please help to solve this issue

Data Base error

QSqlDatabasePrivate::database: unable to open database: " out of memory Error opening database "

Path work directory: "AIC_tool_DB/"

QFSFileEngine::open: No file name specified

QSqlQuery::prepare: database not open

error insert info ScreenTable

"No query Unable to fetch row"


It can be anything. In fact, you missed rightly path to your database, I think.

Hello Evileg,  i hope you are doing great.  i want to add a Search function in this data base.  i have a Lind Edit. and i want to write  22.01.2018_18:00 and it shows me that picture.   please help how will the code for that


Добрый день Евгений. Спасибо за пример, все понятно. Попытался сделать по аналогии сохранение в базе MySQL заготовок отчетов excel, но MySQL ругается на нарушение в строке запроса. Я подозреваю, что видимо я не правильно читаю файл отчета. Я его читаю в масиив QByteArray и уже его пытаюсь передать через bindValue. Если не трудно ткните куда посмотреть реализацию. (Делал такое на VC++ 6.0, там работает без проблем, но хочу перейти на QT).
Мистика какая-то, решил перепроверить еще раз все работает (в замешательстве если честно), вот код:

QString m_file_name = QFileDialog::getOpenFileName(this, "Open file...", ".", "*.*");

    QFile qfile(m_file_name);

    QByteArray inByte;

    QBuffer inBuffer(&inByte);


        inByte = qfile.readAll();

        QVariant data(inByte);

        QString m_sql = "INSERT INTO file_data (file_data) VALUES(:data)";

        QSqlQuery query;


        query.bindValue(":data", data);

            QMessageBox::warning(nullptr, "error", query.lastError().text());


Может база не открылась в прошлый раз. Либо пересобрали проект. хз, если честно ))


Only authorized users can post comments.
Please, Log in or Sign up

Hello, Dear Users of EVILEG!!!

If the site helped you, then support the development of the site financially, please.

You can do it by following ways:

Thank you, Evgenii Legotckoi

April 1, 2020, 8:03 a.m.
Dmitry Kozhinov

C++ - Test 001. The first program and data types

  • Result:40points,
  • Rating points-8
March 30, 2020, 12:47 p.m.

C++ - Test 001. The first program and data types

  • Result:60points,
  • Rating points-1
March 29, 2020, 12:14 p.m.

C++ - Тест 003. Условия и циклы

  • Result:71points,
  • Rating points1
Last comments
April 3, 2020, 8:06 a.m.
Konstantin Grudnitskiy

Я надеюсь вы уже разобрались в чем дело, но если вдруг нет, то проблема состоит в том, что вы пытаетесь запустить программу из интерпретатора питона. Файл main.py это уже готова…
April 3, 2020, 6:18 a.m.
Konstantin Grudnitskiy

>>> text = 'hello world'>>> ' '.join(word for word in text.split()[:-1])'hello'>>> def remove_last_word(text):... return text and ' '.join(word for word in text.s…
March 27, 2020, 2:40 p.m.
Evgenij Legotskoj

Добрый день. В конце пятой статьи скачать можете.
March 27, 2020, 2:28 p.m.
mkdir _

Здравствуйте, а можно, пожалуйста, ссылку на целые исходники, если есть?
March 27, 2020, 4:36 a.m.
Evgenij Legotskoj

Скорее всего также, как и для установки всех остальных переменых в CMake, через использование set
Now discuss on the forum
April 5, 2020, 5:09 a.m.

Попробуйте CQtDeployer или windeployqt.
April 5, 2020, 2:35 a.m.

Так работает console.log(textEmail.text) var str = textEmail.text; var n = str.search(/^((([0-9A-Za-z]{1}[-0-9A-z\.]{1,}[0-9A-Za-z]{1})|([0-9А-Яа-я]{1}[-0-9А-я\.]{1,}[…
April 3, 2020, 12:53 p.m.

Само собою на компе этого незаметно.
April 3, 2020, 8:48 a.m.

Евгений, добрый день. Спасибо!
April 3, 2020, 7:52 a.m.

да вроде много чего установленно, если неправильный путь указать то же самое, пробовал запустить видео через плей лист (по примерам из док)и из него назад путь взять, не получилось
© EVILEG 2015-2019
Recommend hosting TIMEWEB