- 1. Жоба құрылымы
- 2. mainwindow.ui
- 3. PicDataBase.pro
- 4. main.cpp
- 5. дерекқор.h
- 6. database.cpp
- 7. mainwindow.h
- 8. mainwindow.cpp
- 9. Барлығы
- 10. Бейне оқулық
Мәліметтер қорындағы суретті BLOB форматында (ағыл. Binary Large Object - екілік үлкен нысан), яғни екілік деректер массивінің форматында сақтауға болады. BLOB пішімі дерекқорларда аудио және бейне деректерді сақтау үшін де қолайлы.
Мысал ретінде келесі қолданбаны пайдаланып дерекқордан суретті сақтауды және қалпына келтіруді қарастырыңыз, онда компьютер экранындағы скриншот дерекқорға сақталады және ішінде сәйкес жазба таңдалған кезде арнайы QLabel -де көрсетіледі. QTableView , ол дерекқорда сақталған кескіндер туралы барлық жазбаларды көрсетеді.
Осылайша, дерекқорда келесі өрістері бар кесте бар:
- id (INTEGER) - id жазбалары;
- Аты (VARCHAR(255)) - деректер қорында сақталған файлдың аты;
- Pic (BLOB) - мәліметтер базасында суреттерді сақтауға арналған өріс.
Егер сабақта егжей-тегжейлі айтылмаса, онда осы тақырып бойынша ең құнды ақпарат mainwindow.cpp файлының соңында келесі әдістерде:
- MainWindow::on_screenButton_clicked()
- MainWindow::slotCurrentPic(QModelIndex индексі)
Жоба құрылымы
- PicDataBase .pro - жоба профилі;
- database.h – деректер қорымен жұмыс істеуге арналған тұрақты орауыш класының тақырып файлы;
- database.cpp - деректер қорымен жұмыс істеуге арналған орауыш класының бастапқы код файлы;
- mainwindow.h - қолданбаның негізгі терезесінің тақырып файлы;
- mainwindow.cpp - қолданбаның негізгі терезесінің бастапқы код файлы;
- mainwindow.ui - қолданбаның негізгі терезесінің пішіні;
- main.cpp - қолданбаның негізгі бастапқы файлы.
mainwindow.ui
Конструкторда қолданбалы терезенің келесі формасын белгілейміз.
PicDataBase.pro
Қолданба профилінде мәліметтер қорымен жұмыс істеуге арналған sql модулін қосу керек.
main.cpp
Файл әдепкі бойынша жасалады және өзгертілмейді.
дерекқор.h
Деректер қорымен жұмыс істеу үшін мен бұрыннан таныс DataBase орауыш класын қолданамын.
НАЗАР АУДАРЫҢЫЗ!!! - дерекқор файлы C:/example қалтасында жасалған, сондықтан DataBase::connectToDataBase() әдісін түзетіңіз немесе 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" // Третья колонка // Первая колонка содержит 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
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() { /* В данном случае используется формирование сырого 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
Кәдімгі DataBase және QSqlTableModel нысандарына, сонымен қатар QSqlRelationalTableModel туралы алдыңғы мақалаларда пайдаланылған үлгі мен көріністі орнату әдістеріне қосымша және QSqlQueryModel , бұл файлда түймелерді басу және жазбаларды басу үшін слоттар бар кестеде.
Бірінші слот экранның скриншотын түсіріп, оны дерекқорға қосады, ал екінші ұяшық QTableView ішіндегі QSqlTableModel нысанынан алып, оны * ішіне орналастыру арқылы дерекқордан кескінді қалпына келтіреді. QLabel * қолданбаның негізгі терезесінде .
#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
Мәліметтер қорымен және кескінмен барлық негізгі жұмыс келесі әдістермен орындалады:
- MainWindow::on_screenButton_clicked()
- MainWindow::slotCurrentPic(QModelIndex индексі)
#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)); }
Барлығы
Нәтижесінде экранның скриншоттарын дерекқорда сақтауға және бұл суретті қолданба терезесінің QLabel -де көрсету арқылы қалпына келтіруге мүмкіндік беретін қосымшаны аламыз. Сондай-ақ, қосымшаның жұмысы туралы пікірлерді бейне оқулықтан тыңдай аласыз.
Здравствуйте, при сборке выдаёт две такие ошибки 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.
Мистика какая-то, решил перепроверить еще раз все работает (в замешательстве если честно), вот код:
Может база не открылась в прошлый раз. Либо пересобрали проект. хз, если честно ))