- 1. Projektstruktur
- 2. mainwindow.ui
- 3. PicDataBase.pro
- 4. main.cpp
- 5. database.h
- 6. datenbank.cpp
- 7. mainwindow.h
- 8. mainwindow.cpp
- 9. Ergebnis
- 10. Videoanleitung
Das Bild in der Datenbank kann im Format BLOB ( Binary Large Object ) gespeichert werden, dh im Format eines Arrays von Binärdaten. Das BLOB -Format eignet sich auch zum Speichern von Audio- und Videodaten in Datenbanken.
Betrachten wir das Speichern und Wiederherstellen eines Bildes aus einer Datenbank am Beispiel der folgenden Anwendung, bei der ein Screenshot vom Computerbildschirm in der Datenbank gespeichert und in einem speziellen QLabel angezeigt wird, wenn der entsprechende Datensatz in * ausgewählt wird * QTableView **, das alle in der Datenbank gespeicherten Bilddatensätze anzeigt.
Somit haben wir eine Tabelle in der Datenbank mit den folgenden Feldern:
- id (INTEGER) - Datensatz-ID;
- Name (VARCHAR (255)) - Name der in der Datenbank gespeicherten Datei;
- Pic (BLOB) - Feld zum Speichern von Bildern in der Datenbank.
Wenn Sie nicht im Detail auf die Lektion eingehen, dann finden Sie die wertvollsten Informationen zu diesem Thema am Ende der Datei mainwindow.cpp in den folgenden Methoden:
- MainWindow::on_screenButton_clicked()
- MainWindow::slotCurrentPic(QModelIndex index)
Projektstruktur
- PicDataBase .pro - Projektprofil;
- database.h - Header-Datei der unveränderlichen Wrapper-Klasse für die Arbeit mit der Datenbank;
- database.cpp - Datei mit Quellcodes einer Wrapper-Klasse zum Arbeiten mit einer Datenbank;
- mainwindow.h - Header-Datei des Hauptanwendungsfensters;
- mainwindow.cpp -Datei mit Quellcodes des Hauptfensters der Anwendung;
- mainwindow.ui - die Form des Hauptanwendungsfensters;
- main.cpp - die Hauptquellcodedatei für die Anwendung.
mainwindow.ui
Skizzieren Sie im Designer die folgende Anwendungsfensterform.
PicDataBase.pro
Im Anwendungsprofil müssen wir das sql -Modul verbinden, um mit Datenbanken zu arbeiten.
main.cpp
Die Datei wird standardmäßig erstellt und kann nicht geändert werden.
database.h
Um mit der Datenbank zu arbeiten, verwende ich die bereits bekannte DataBase Wrapper-Klasse.
AUFMERKSAMKEIT!!! - die Datenbankdatei wird im Ordner C: / example erstellt, also korrigieren Sie entweder die Methode DataBase :: connectToDataBase () oder erstellen Sie einen example Ordner auf dem * C * Antrieb.
#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" // Третья колонка // Первая колонка содержит Autoincrement ID 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
datenbank.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() { /* В данном случае используется формирование сырого SQL-запроса * с последующим его выполнением. * */ 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) { /* Запрос SQL формируется из QVariantList, * в который передаются данные для вставки в таблицу. * */ QSqlQuery query; /* В начале SQL запрос формируется с ключами, * которые потом связываются методом bindValue * для подстановки данных из QVariantList * */ query.prepare("INSERT INTO " TABLE " ( " TABLE_NAME ", " TABLE_PIC " ) " "VALUES (:Name, :Pic)"); query.bindValue(":Name", data[0].toString()); query.bindValue(":Pic", data[1].toByteArray()); // После чего выполняется запросом методом exec() 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
Neben den bekannten DataBase - und [QSqlTableModel]-Objekten (https://evileg.com/de/post/62/), sowie den Methoden zum Einstellen des Modells und der Ansicht, die in früheren Artikeln zu QSqlRelationalTableModel und QSqlQueryModel , diese Datei enthält Slots für die Handhabung des Klickens auf eine Schaltfläche und klicken Sie auf einen Eintrag in der Tabelle.
Der erste Slot erstellt einen Screenshot des Bildschirms und fügt ihn der Datenbank hinzu, und der zweite Slot stellt das Bild aus der Datenbank wieder her, indem er es aus dem QSqlTableModel Objekt in der QTableView nimmt und in das * QLabel * im Hauptanwendungsfenster ...
#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: // Слот для записи скриншота в базу данных void on_screenButton_clicked(); // Слот для получения изображения из базы данных void slotCurrentPic(QModelIndex index); private: Ui::MainWindow *ui; /* В проекте используются объекты для взаимодействия с информацией в базе данных * и моделью представления таблицы базы данных * */ DataBase *db; QSqlTableModel *model; private: /* Также присутствуют два метода, которые формируют модель * и внешний вид TableView * */ void setupModel(const QString &tableName, const QStringList &headers); void createUI(); }; #endif // MAINWINDOW_H
mainwindow.cpp
Die gesamte Hauptarbeit mit der Datenbank und dem Bild wird mit den folgenden Methoden erledigt:
- 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); /* Устанавливаем названия колонок в таблице с сортировкой данных * */ 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); // Устанавливаем модель на TableView ui->tableView->setColumnHidden(0, true); // Скрываем колонку с id записей ui->tableView->setColumnHidden(2, true); // Скрываем колонку с изображением // Разрешаем выделение строк ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); // Устанавливаем режим выделения лишь одной строки в таблице ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); // Устанавливаем размер колонок по содержимому ui->tableView->resizeColumnsToContents(); ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); // Запрещаем редактирование ui->tableView->horizontalHeader()->setStretchLastSection(true); // Растягиваем последнюю колонку по всему tableView /* Подключаем сигнал об изменении выбора текущей строки в таблицу * к СЛОТу для установки изображения в picLabel * */ connect(ui->tableView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentPic(QModelIndex))); model->select(); // Делаем выборку данных из таблицы } void MainWindow::on_screenButton_clicked() { /* Делаем скриншот экрана и сохраняем его в объект QByteArray, * для этого ... * */ QScreen *screen = QApplication::primaryScreen(); // Берём объект экрана QPixmap inPixmap = screen->grabWindow( 0 ); // Сохраняем его в изображение объекта QPixmap QByteArray inByteArray; // Создаём объект QByteArray для сохранения изображения QBuffer inBuffer( &inByteArray ); // Сохранение изображения производим через буффер inBuffer.open( QIODevice::WriteOnly ); // Открываем буффер inPixmap.save( &inBuffer, "PNG" ); // Записываем inPixmap в inByteArray // Записываем скриншот в базу данных db->insertIntoTable(QDateTime::currentDateTime().toString("dd.MM.yyyy_hh:mm:ss.png"), inByteArray); // Делаем выборку таблицы из Базы Данных model->select(); } void MainWindow::slotCurrentPic(QModelIndex index) { QPixmap outPixmap = QPixmap(); // Создаём QPixmap, который будет помещаться в picLabel /* Забираем данные об изображении из таблицы в качестве QByteArray * и помещаем их в QPixmap * */ outPixmap.loadFromData(model->data(model->index(index.row(), 2)).toByteArray()); // Устанавливаем изображение в picLabel ui->picLabel->setPixmap(outPixmap.scaled(400,300)); }
Ergebnis
Als Ergebnis erhalten wir eine Anwendung, mit der Sie Screenshots des Bildschirms in der Datenbank speichern und dieses Bild wiederherstellen können, indem Sie es im QLabel des Anwendungsfensters anzeigen. Sie können auch Kommentare zur Bedienung der Anwendung im Video-Tutorial hören.
Здравствуйте, при сборке выдаёт две такие ошибки 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.
Мистика какая-то, решил перепроверить еще раз все работает (в замешательстве если честно), вот код:
Может база не открылась в прошлый раз. Либо пересобрали проект. хз, если честно ))