Jak wywołać obrazek z bloba w QSqlTableModelu wyświetlanym w QTableViewie?

0

Witam, mam bloby ze zdjęć w bazie danych, baze danych wywołuje jako QSqlTableModel i daje do tableViewa. Tam jest kolumna właśnie z tymi blobami, tylko pokazuje się właśnie jako blob, nie jako ikona. Da się to jakoś dynamicznie przekształcić dla każdego rekordu, nadal w QSqlTableModelu?

2

Przed wrzuceniem zawartości do tabeli "przepuść" zawartość bloba przez QPixmap albo QImage i wyświetl je w tabeli zamiast bloba.

0
BartoSAS napisał(a):

Przed wrzuceniem zawartości do tabeli "przepuść" zawartość bloba przez QPixmap albo QImage i wyświetl je w tabeli zamiast bloba.

Skleiłem coś takiego, nie wiem czy zadziała

 int n= model->rowCount();
    for (int i=0;i<=n;i++)
    {
        QByteArray byteArr =  model->record(i).value("img").toByteArray();
        QImage image; image.loadFromData(byteArr);
        model->record(i).setValue("img",image);
    }
0
BartoSAS napisał(a):

Sprawdź sposób stąd:
https://stackoverflow.com/que[...]tableview-from-qsqltablemodel

Nie wiem, jak to zrobić bo po pierwsze działam na blobach nie ścieżkach do plików, a dwa nie mogę dostać QModelIndex, znaczy nie wiem jak dostać bo mam

QSqlTableModel::record(i).value("img");
0

Nie zagłębiałem się zbytnio w Qt::DecorationRole, ale chyba może być problem z pozycjonowaniem takiej ikony w komórce.

Myślę, że tutaj najlepszym rozwiązaniem jest własny "delegat" (dziedziczący z QStyledItemDelegate) Przykład

1

QSqlTableModel jest do obsługi tabeli, ten model nie ma pojęcia jak obsłużyć obrazek z blob-a, ani podczas zapisu ani odczytu, bo niby na jakiej podstawie.

Są dwa wyjścia.

  • Dziedziczysz po QSqlTableModel
  • Albo dziedziczysz po QIdentityProxyModel, by potem połączyć to QSqlTableModel (IMO lepsze rozwiązanie) - patrz dokumentacja QIdentityProxyModel.

i próbujesz zmienić zachowanie QAbstractItemModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const.
względnie jeszcze QAbstractItemModel::flags(const QModelIndex &index) const.

Po prostu w implementacji data jak trafiasz na bloba z bazy danych to konwertujesz to na QPixmap, a w przypadku flagi blokujesz edycję itp.

Nic trudnego, a będzie na pewno działać.

class SqlBlobDecoderModel : public QIdentityProxyModel
{
    Q_OBJECT
public:
    Q_PROPERTY(int imageColumn MEMBER m_imageColumn NOTIFY imageColumnChanged)

    using QIdentityProxyModel::QIdentityProxyModel;

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
        if (!isColumnWithImageBlob(index))
            return QIdentityProxyModel::data(index, role);
        if (role == Qt::DecorationRole)
            return imageFromBlobIn(index);
        if (role == Qt::DisplayRole)
            return QString();
        return QIdentityProxyModel::data(index, role);
    }

    Qt::ItemFlags flags(const QModelIndex &index) const {
        if (!isColumnWithImageBlob(index)) {
            return QIdentityProxyModel::flags(index);
        }
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
    }

    bool isColumnWithImageBlob(const QModelIndex &index) const {
        return index.column() == m_imageColumn;
    }

    QPixmap imageFromBlobIn(const QModelIndex &index) const {
        auto array = index.data(Qt::DisplayRole /* ? */).toByteArray(); // nie wiem jaka wartość ma tu być, pewnie Qt::DisplayRole
        QPixmap pixmap;
        pixmap.loadFromData(array,"PNG",Qt::AutoColor);
        return pixmap;
    }

public signals:
    void imageColumnChanged(int);

private:
    int m_imageColumn = 0;
};
0
MarekR22 napisał(a):

QSqlTableModel jest do obsługi tabeli, ten model nie ma pojęcia jak obsłużyć obrazek z blob-a, ani podczas zapisu ani odczytu, bo niby na jakiej podstawie.

Są dwa wyjścia.

  • Dziedziczysz po QSqlTableModel
  • Albo dziedziczysz po QIdentityProxyModel, by potem połączyć to QSqlTableModel (IMO lepsze rozwiązanie) - patrz dokumentacja QIdentityProxyModel.

i próbujesz zmienić zachowanie QAbstractItemModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const.
względnie jeszcze QAbstractItemModel::flags(const QModelIndex &index) const.

Po prostu w implementacji data jak trafiasz na bloba z bazy danych to konwertujesz to na QPixmap, a w przypadku flagi blokujesz edycję itp.

Nic trudnego, a będzie na pewno działać.

class SqlBlobDecoderModel : public QIdentityProxyModel
{
    Q_OBJECT
public:
    Q_PROPERTY(int imageColumn MEMBER m_imageColumn NOTIFY imageColumnChanged)

    using QIdentityProxyModel::QIdentityProxyModel;

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
        if (!isColumnWithImageBlob(index))
            return QIdentityProxyModel::data(index, role);
        if (role == Qt::DecorationRole)
            return imageFromBlobIn(index);
        if (role == Qt::DisplayRole)
            return QString();
        return QIdentityProxyModel::data(index, role);
    }

    Qt::ItemFlags flags(const QModelIndex &index) const {
        if (!isColumnWithImageBlob(index)) {
            return QIdentityProxyModel::flags(index);
        }
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
    }

    bool isColumnWithImageBlob(const QModelIndex &index) const {
        return index.column() == m_imageColumn;
    }

    QPixmap imageFromBlobIn(const QModelIndex &index) const {
        auto array = index.data(Qt::DisplayRole /* ? */).toByteArray(); // nie wiem jaka wartość ma tu być, pewnie Qt::DisplayRole
        QPixmap pixmap;
        pixmap.loadFromData(array,"PNG",Qt::AutoColor);
        return pixmap;
    }

public signals:
    void imageColumnChanged(int);

private:
    int m_imageColumn = 0;
};

Przepraszam, miałem chwilową przerwę w programowaniu, wróciłem kończyć program, dziękuję za tak piękny kod, lecz ja nawet nie wiem gdzie go użyć. Kod ok rozumiem, zwraca pixmapa, i później zwróci mi go do tabeli, i bez jakichś setPixmap() czy tym podobnych on będzie działał już od razu? Gdzie mam użyć tą klasę i wywołać data w mojej QSqlTableModel - MySqlTableModel który już ma swoją funkcję data() czy gdzieś później w kodzie, przed wywołaniem wszystkiego do tableViewa?

1

QIdentityProxyModel to jest model proxy, czyli taki pośrednik.
Czyli to moje SqlBlobDecoderModel wstawiasz miedzy swój QSqlTaleModel, a widok QTableView.

auto sqlModel = new QSqlTaleModel(...);
...

auto blobDecoder = SqlBlobDecoderModel(this);
blobDecoder->setSourceModel(sqlModel);

ui->tableView->setModel(blobDecoder); // tu wczesniej było sqlModel 

Ot cała filozofia (i właściwe podejście do OOP).

0
MarekR22 napisał(a):

QIdentityProxyModel to jest model proxy, czyli taki pośrednik.
Czyli to moje SqlBlobDecoderModel wstawiasz miedzy swój QSqlTaleModel, a widok QTableView.

auto sqlModel = new QSqlTaleModel(...);
...

auto blobDecoder = SqlBlobDecoderModel(this);
blobDecoder->setSourceModel(sqlModel);

ui->tableView->setModel(blobDecoder); // tu wczesniej było sqlModel 

Ot cała filozofia (i właściwe podejście do OOP).

... Nadal nie działa, nie wiem co robię źle,

QSortFilterProxyModel *m=new QSortFilterProxyModel(this);
    m->setDynamicSortFilter(true);
    m->setSourceModel(model);

    SqlBlobDecoderModel *blobDetector= new SqlBlobDecoderModel(this);
    blobDetector->setSourceModel(m);

    int max = blobDetector->rowCount();
    for(int i=1;i<=max;i++)
    {
        QModelIndex idx;
        idx = blobDetector->index(i,1);
        blobDetector->data(idx,Qt::DecorationRole);
    }

    ui->tableView->setModel(blobDetector);
    ui->tableView->setSortingEnabled(true);
    ui->tableView->sortByColumn(8,Qt::DescendingOrder);
    for(int i=1;i<=max;i++)
    {
        QModelIndex idx;
        idx = blobDetector->index(i,1);
        blobDetector->data(idx,Qt::DecorationRole);
    }

}

a tak klasa

#ifndef SQLBLOBDECODERMODEL_H
#define SQLBLOBDECODERMODEL_H

#include <QIdentityProxyModel>
#include <QPixmap>
class SqlBlobDecoderModel : public QIdentityProxyModel
{
    Q_OBJECT
public:
    Q_PROPERTY(int imageColumn MEMBER m_imageColumn NOTIFY imageColumnChanged)
//QSqlBLobDecoderModel()
        SqlBlobDecoderModel(QObject *parent);
        SqlBlobDecoderModel();
    using QIdentityProxyModel::QIdentityProxyModel;

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;

    Qt::ItemFlags flags(const QModelIndex &index) const ;

    bool isColumnWithImageBlob(const QModelIndex &index) const ;

    QPixmap imageFromBlobIn(const QModelIndex &index) const ;

private:
    int m_imageColumn = 0;

};

#endif // SQLBLOBDECODERMODEL_H

i cpp klasy

#include "sqlblobdecodermodel.h"

    SqlBlobDecoderModel::SqlBlobDecoderModel(QObject *parent)
    {
    ;
    }
    QVariant SqlBlobDecoderModel::data(const QModelIndex &index, int role) const {
        if (!isColumnWithImageBlob(index))
            return QIdentityProxyModel::data(index, role);
        if (role == Qt::DecorationRole)
            return imageFromBlobIn(index);
        if (role == Qt::DisplayRole)
            return QString();
        return QIdentityProxyModel::data(index, role);
    }

    Qt::ItemFlags SqlBlobDecoderModel::flags(const QModelIndex &index) const {
        if (!isColumnWithImageBlob(index)) {
            return QIdentityProxyModel::flags(index);
        }
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
    }

    bool SqlBlobDecoderModel::isColumnWithImageBlob(const QModelIndex &index) const {
        return index.column() == m_imageColumn;
    }

    QPixmap SqlBlobDecoderModel::imageFromBlobIn(const QModelIndex &index) const {
        auto array = index.data(Qt::DisplayRole /* ? */).toByteArray(); // nie wiem jaka wartość ma tu być, pewnie Qt::DisplayRole
        QPixmap pixmap;
        pixmap.loadFromData(array,"PNG",Qt::AutoColor);
        return pixmap;
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0