- 1. Project structure
- 2. mainwindow.ui
- 3. PicDataBase.pro
- 4. main.cpp
- 5. database.h
- 6. database.cpp
- 7. mainwindow.h
- 8. mainwindow.cpp
- 9. Result
- 10. Video
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.
mainwindow.ui
In the designer's apply this form of the application window.
PicDataBase.pro
In profile, the application is mandatory connect sql module for working with databases.
main.cpp
The file is created by default and is not subject to change.
database.h
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 { Q_OBJECT public: explicit DataBase(QObject *parent = 0); ~DataBase(); void connectToDataBase(); private: QSqlDatabase db; private: 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
database.cpp
#include "database.h" DataBase::DataBase(QObject *parent) : QObject(parent) { } DataBase::~DataBase() { } void DataBase::connectToDataBase() { if(!QFile("C:/example/" DATABASE_NAME).exists()){ this->restoreDataBase(); } else { this->openDataBase(); } } bool DataBase::restoreDataBase() { if(this->openDataBase()){ return (this->createTable()) ? true : false; } else { qDebug() << "Не удалось восстановить базу данных"; return false; } return false; } bool DataBase::openDataBase() { db = QSqlDatabase::addDatabase("QSQLITE"); db.setHostName(DATABASE_HOSTNAME); db.setDatabaseName("C:/example/" DATABASE_NAME); if(db.open()){ return true; } else { return false; } } void DataBase::closeDataBase() { db.close(); } 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()); if(!query.exec()){ 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; data.append(name); data.append(pic); if(insertIntoTable(data)) return true; else return false; }
mainwindow.h
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.
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QSqlTableModel> #include <QModelIndex> #include "database.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); 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); private: Ui::MainWindow *ui; DataBase *db; QSqlTableModel *model; private: void setupModel(const QString &tableName, const QStringList &headers); void createUI(); }; #endif // MAINWINDOW_H
mainwindow.cpp
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) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); db = new DataBase(); db->connectToDataBase(); this->setupModel(TABLE, QStringList() << trUtf8("id") << trUtf8("Имя изображения") << trUtf8("изображение") ); this->createUI(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::setupModel(const QString &tableName, const QStringList &headers) { model = new QSqlTableModel(this); model->setTable(tableName); /* Set the columns names in a table with sorted data * */ for(int i = 0, j = 0; i < model->columnCount(); i++, j++){ model->setHeaderData(i,Qt::Horizontal,headers[j]); } } void MainWindow::createUI() { ui->tableView->setModel(model); ui->tableView->setColumnHidden(0, true); // Hide the column id Records ui->tableView->setColumnHidden(2, true); // Hide the column with image ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableView->resizeColumnsToContents(); 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))); model->select(); } 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); model->select(); } 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()); ui->picLabel->setPixmap(outPixmap.scaled(400,300)); }
Result
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.
Здравствуйте, при сборке выдаёт две такие ошибки C:\untitled1\mainwindow.cpp:99: ошибка: C2039: picLabel: Ґ пў«пҐвбп з«Ґ®¬ "Ui::MainWindow" C:\untitled1\mainwindow.cpp:99: ошибка: C2227: ўла ¦ҐЁҐ б«Ґў ®в "->setPixmap" ¤®«¦® гЄ §лў вм вЁЇ Є« бб , бвагЄвгал Ё«Ё ®ЎкҐ¤ЁҐЁп «ЁЎ® гЁўҐаб «мл© вЁЇ Как это исправить, помогите пожалуйста
И ещё не могли бы подсказать что нужно изменить в коде чтобы по нажатию на кнопку в БД загружался не скриншот, а выбранные и уже существующие изображения?
Заранее спасибо!
Интерфейс приложения сделать через графический дизайнер так, как сделано в данной статье. Убедиться, что существует QLabel в интерфейсе, с таким же названием, как в этой статье.
Создать QPixmap из файла, указав путь к файлу.
Спасибо большое! Но если я правильно понял, то для каждого файла нужно будет описывать каждый раз путь? А можно сделать как-то так чтобы можно было выбирать их?
Используйте QFileDialog класс. У него есть статические методы, которые позволяют открыть диалог, в котором можно выбрать либо один файл, либо несколько файлов.
Например, чтобы забрать имя одного файла:
Или нескольких файлов:
Ну и закидываете это всё в QPixmap, ну а дальше уже как по накатанной.
Так не верно?
Нет. не верно. Ошибка вот в этой строке:
Выше я показывал, как что нужно путь передавать в качестве аргумента
То есть
Здравствуйте, также реализовывал приложение и понадобилось сохранить картинку. Но я брал напрямую через буфер
Но при вставке данных в таблицу возникает ошибка
QSqlError("1", "Unable to execute statement", "unrecognized token: \"\u001A\"")
также вот вывод текста самого запроса
"Insert into commands_one (name, seq, pic) values ('bnbvn','\n1. bvnb\n2. bvnb', �PNG\r\n\u001A\n );"
Перед этим приложение работало отлично, ошибка связана именно с добавлением данного поля
Добрый день!
Подготовьте изображение к вставке в базу данных через 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..
Hello.
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.
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.
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
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
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"
Hello!
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).
Update.
Мистика какая-то, решил перепроверить еще раз все работает (в замешательстве если честно), вот код:
Может база не открылась в прошлый раз. Либо пересобрали проект. хз, если честно ))