Evgenii Legotckoi
Evgenii Legotckoi25 ноября 2015 г. 8:17

Qt/C++ - Урок 029. Изображение в базе данных в Qt – Сохранение и Восстановление

Изображение в базе данных может быть сохранено в формате BLOB (англ. Binary Large Object - двоичный большой объект), то есть в формате массива двоичных данных. Формат BLOB также подходит для сохранения аудио и видео данных в базах данных.

Рассмотрим сохранение и восстановление изображения из базы данных на примере следующего приложения, в котором скриншот с экрана компьютера будет сохраняться в базе данных и выводиться в специальный QLabel , когда соответствующая запись будет выбрана в QTableView , который будет отображать все записи об изображения, хранящихся в базе данных.

Таким образом имеем таблицу в базе данных со следующими полями:

  • id (INTEGER) - id записи;
  • Name (VARCHAR(255)) - название хранящегося в базе данных файла;
  • Pic (BLOB) - поле для хранения изображений в базе данных.

Если не вдаваться подробно в урок, то самая ценная информация по данной теме в конце файла mainwindow.cpp в следующих методах:

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

Структура проекта

  • PicDataBase .pro - профайл проекта;
  • database.h - заголовочный файл бессменного класса обёртки для работы с базой данных;
  • database.cpp - файл исходных кодов класса-обёртки для работы с базой данных;
  • mainwindow.h - заголовочный файл основного окна приложения;
  • mainwindow.cpp -файл исходных кодов основного окна приложения;
  • mainwindow.ui - форма главного окна приложения;
  • main.cpp - основной файл исходных кодов приложения.

mainwindow.ui

В дизайнере  набрасываем следующую форму окна приложения.

PicDataBase.pro

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

main.cpp

Файл создан по умолчанию и не подвергается изменениям.

database.h

Для работы с базой данных использую уже привычный класс-обёртку DataBase .

ВНИМАНИЕ!!! - файл базы данных создается в папке C:/example , поэтому или поправьте метод DataBase::connectToDataBase() или создайте папку example на диске 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 , в данном файле присутствуют слоты для обработки нажатия по кнопке и клику по записи в таблице.

Первый слот выполняет создание скриншота экрана и добавление его в базу данных, а второй слот восстанавливает изображение из базы данных, беря его из объекта QSqlTableModel в QTableView и помещая его в 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 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));
}

Итог

В результате получаем приложение, которое позволяет сохранять скриншоты экрана в базе данных и восстанавливать данное изображение, отображая его в QLabel окна приложения. Также комментарии по работе приложения Вы можете услышать в видеоуроке.

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

t
  • 20 мая 2017 г. 17:46

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

t
  • 20 мая 2017 г. 17:53

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

Evgenii Legotckoi
  • 20 мая 2017 г. 23:54

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

Evgenii Legotckoi
  • 20 мая 2017 г. 23:57

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

QPixmap pixmap("/path/to/file.png");
t
  • 21 мая 2017 г. 6:46

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

Evgenii Legotckoi
  • 21 мая 2017 г. 12:34

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

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

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

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

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

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

t
  • 21 мая 2017 г. 18:33
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); 
model->select();

Так не верно?

Evgenii Legotckoi
  • 23 мая 2017 г. 2:19

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

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

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

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

То есть

QPixmap inixmap(fileName);
F
  • 21 января 2018 г. 14:29

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

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);";
F
  • 21 января 2018 г. 14:31

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

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

F
  • 21 января 2018 г. 14:32

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

Evgenii Legotckoi
  • 21 января 2018 г. 15:42

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

s
  • 22 февраля 2018 г. 11:42

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..

Evgenii Legotckoi
  • 22 февраля 2018 г. 17:22

Hello.

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);
    if(!query.exec()){
        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
s
  • 25 февраля 2018 г. 19:55

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

Evgenii Legotckoi
  • 26 февраля 2018 г. 2:13

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.

s
  • 26 февраля 2018 г. 4:42

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
Evgenii Legotckoi
  • 26 февраля 2018 г. 5:08

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

s
  • 26 февраля 2018 г. 7:09

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

s
  • 2 марта 2018 г. 8:29

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

Evgenii Legotckoi
  • 3 марта 2018 г. 6:45

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()
s
  • 5 марта 2018 г. 7:02

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

s
  • 5 марта 2018 г. 9:39

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

Evgenii Legotckoi
  • 5 марта 2018 г. 15:55

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)
{
    db->removeRecord(id);
}

And please, ask your next questions on the forum
s
  • 6 марта 2018 г. 3:56

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

s
  • 7 марта 2018 г. 4:58

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?",
                                   QMessageBox::Yes|QMessageBox::No);
     if (reply == QMessageBox::Yes) {
       qDebug() << "Yes was clicked";
       QSqlRecord record;
           int i = ui->tableView->currentIndex().row(); 
           record = model->record(i);
           db->removeRecord(record.value("id").toInt(false));
           ui->tableView->reset();
        }
    else {
       qDebug() << "Yes was *not* clicked";

  }
}

 

Evgenii Legotckoi
  • 7 марта 2018 г. 6:03

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

model->select();
s
  • 20 марта 2018 г. 5:42

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"

Evgenii Legotckoi
  • 20 марта 2018 г. 17:00

Hello!

It can be anything. In fact, you missed rightly path to your database, I think.
s
  • 12 апреля 2018 г. 4:57

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

s
  • 6 октября 2019 г. 11:27
  • (ред.)

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

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

    QFile qfile(m_file_name);

    QByteArray inByte;

    QBuffer inBuffer(&inByte);

    if(qfile.open(QIODevice::ReadOnly)){

        inByte = qfile.readAll();

        QVariant data(inByte);

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

        QSqlQuery query;

        query.prepare(m_sql);

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

        if(!query.exec()){
            QMessageBox::warning(nullptr, "error", query.lastError().text());
        }

        qfile.close();
    }    
Evgenii Legotckoi
  • 6 октября 2019 г. 13:44

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50баллов,
  • Очки рейтинга-4
m
  • molni99
  • 26 октября 2024 г. 7:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 26 октября 2024 г. 7:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10
Последние комментарии
ИМ
Игорь Максимов22 ноября 2024 г. 17:51
Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 октября 2024 г. 19:37
Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 октября 2024 г. 14:19
Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5 октября 2024 г. 13:51
Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55 июля 2024 г. 17:02
QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Сейчас обсуждают на форуме
m
moogo22 ноября 2024 г. 13:17
Mosquito Spray System Effective Mosquito Systems for Backyard | Eco-Friendly Misting Control Device & Repellent Spray - Moogo ; Upgrade your backyard with our mosquito-repellent device! Our misters conce…
Evgenii Legotckoi
Evgenii Legotckoi24 июня 2024 г. 21:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 ноября 2024 г. 12:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject4 июня 2022 г. 9:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…

Следите за нами в социальных сетях