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/questions/24201822/show-image-in-a-column-of-qtableview-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
  1. "Nadal nie działa" to nie jest opis problemu. Co się wyświetla, w miejscu, gdzie powinien być obrazek?
  2. Nie ustawiłeś kolumny, dla której ma być wyświetlany obrazek. m_imageColumn (nie dopisałem settera)
  3. Umiesz używać debugger-a, sprawdzałeś jak co działa? Czy zmienna array ma rozsądną zawartość?
  4. Pisałem o możliwych problemach w komentarzu

Tu masz brakujące akcesory dla property:

     Q_PROPERTY(int imageColumn READ imageColumn WRITE setSmageColumn NOTIFY imageColumnChanged)
....
    int imageColumn() const { return m_imageColumn; }

    void setSmageColumn(int col)
    {
        if (col != m_imageColumn) {
             auto oldCol = m_imageColumn;
             m_imageColumn = col;
             emit imageColumnChanged(col);
             auto lastRow = rowCount() - 1;
             if (lastRow >= 0) {
                 auto roles = QVecotr<int> { Qt::DisplayRole, Qt::DecorationRole };
                 emit dataChanged(index(0, oldCol), index(lastRow, oldCol), roles);
                 emit dataChanged(index(0, col), index(lastRow, col), roles); 
             }
        }
    }
1

Po kosmetycznych poprawkach wszystko działa (przetestowałem):

#ifndef SQLBLOBDECODERMODEL_H
#define SQLBLOBDECODERMODEL_H

#include <QIdentityProxyModel>

class SqlBlobDecoderModel : public QIdentityProxyModel
{
    Q_OBJECT

    Q_PROPERTY(int imageColumn READ imageColumn WRITE setImageColumn NOTIFY imageColumnChanged)
public:
    using QIdentityProxyModel::QIdentityProxyModel;

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

    int imageColumn() const;
    void setImageColumn(int col);

signals:
    void imageColumnChanged(int col);

private:
    bool isColumnWithImageBlob(const QModelIndex &index) const;
    QPixmap imageFromBlobIn(const QModelIndex &index) const;

private:
    int m_imageColumn = 0;
};

#endif // SQLBLOBDECODERMODEL_H
#include "sqlblobdecodermodel.h"
#include <QDebug>
#include <QPixmap>

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;
}

int SqlBlobDecoderModel::imageColumn() const
{
    return m_imageColumn;
}

void SqlBlobDecoderModel::setImageColumn(int col)
{
    if (m_imageColumn != col) {
        auto oldCol = m_imageColumn;
        m_imageColumn = col;
        emit imageColumnChanged(col);
        auto lastRow = rowCount() - 1;
        if (lastRow >= 0 && col >= 0 && col < columnCount()) {
            auto roles = QVector<int> { Qt::DisplayRole, Qt::DecorationRole };
            emit dataChanged(index(0, oldCol), index(lastRow, oldCol), roles);
            emit dataChanged(index(0, col), index(lastRow, col), roles);
        }
    }
}

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

QPixmap SqlBlobDecoderModel::imageFromBlobIn(const QModelIndex &index) const
{
    auto array = QIdentityProxyModel::data(index, Qt::DisplayRole).toByteArray();
    if (array.isNull()) {
        qDebug() << "No data for pixmap";
        return {};
    }
    QPixmap pixmap;
    if (!pixmap.loadFromData(array,"PNG",Qt::AutoColor)) {
        qDebug() << "failed load pixmap";
    }
    return pixmap.scaled(64, 64, Qt::KeepAspectRatio);
}

Jedyny problem to, wielkość obrazka i sposób jego wyświetlenia, ale to już inna bajka.
screenshot-20190330095240.png

0
MarekR22 napisał(a):
  1. "Nadal nie działa" to nie jest opis problemu. Co się wyświetla, w miejscu, gdzie powinien być obrazek?
  2. Nie ustawiłeś kolumny, dla której ma być wyświetlany obrazek. m_imageColumn (nie dopisałem settera)
  3. Umiesz używać debugger-a, sprawdzałeś jak co działa? Czy zmienna array ma rozsądną zawartość?
  4. Pisałem o możliwych problemach w komentarzu

Tu masz brakujące akcesory dla property:

     Q_PROPERTY(int imageColumn READ imageColumn WRITE setSmageColumn NOTIFY imageColumnChanged)
....
    int imageColumn() const { return m_imageColumn; }

    void setSmageColumn(int col)
    {
        if (col != m_imageColumn) {
             auto oldCol = m_imageColumn;
             m_imageColumn = col;
             emit imageColumnChanged(col);
             auto lastRow = rowCount() - 1;
             if (lastRow >= 0) {
                 auto roles = QVecotr<int> { Qt::DisplayRole, Qt::DecorationRole };
                 emit dataChanged(index(0, oldCol), index(lastRow, oldCol), roles);
                 emit dataChanged(index(0, col), index(lastRow, col), roles); 
             }
        }
    }

Debuggera nie ogarniam, próbowałem się nauczyć ale te poradniki to szkoda gadać...

nie puszcza mi ustawienia na public signals

public signals:
    void imageColumnChanged(int);

i pokazuje expected : before signals :/ oraz undefinied reference do tego imageColumnChanged(int)

///EDIT
sekundka , nie zauważyłem kodu z godz 9 już sprawdzam bo ta odpowiedz byla do wczesniejszego postu

0

@MarekR22:
nadal nie wiem co jest grane, czy wgl to dobrze wywołuje no bo jest tak:

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);

1 bo w 1 kolumnie jest blob

i wyskakuje error w konsoli na dole że:
QFSFileEngine: No file name specified

1
Xezolpl napisał(a):

Debuggera nie ogarniam, próbowałem się nauczyć ale te poradniki to szkoda gadać...

Bardzo bardzo niedobrze. Prawda jest taka, że ilość używania debuggera jest odwrotnie proporcjonalna do umiejętności (pod warunkiem, że ktoś umie używać debugger-a).
Świetne narzędzie do nauki podstaw, więc wówczas powinno się go używać bardzo dużo.
Jak ma się już doświadczenie, umie pisać testy, to debugger jest potrzebny sporadycznie.

Nie jest to trudne. Szkolenie też nie jest potrzebne, wystarczy próbować i klikać.

0
MarekR22 napisał(a):
Xezolpl napisał(a):

Debuggera nie ogarniam, próbowałem się nauczyć ale te poradniki to szkoda gadać...

Bardzo bardzo niedobrze. Prawda jest taka, że ilość używania debuggera jest odwrotnie proporcjonalna do umiejętności (pod warunkiem, że ktoś umie używać debugger-a).
Świetne narzędzie do nauki podstaw, więc wówczas powinno się go używać bardzo dużo.
Jak ma się już doświadczenie, umie pisać testy, to debugger jest potrzebny sporadycznie.

Nie jest to trudne. Szkolenie też nie jest potrzebne, wystarczy próbować i klikać.

Co do tego wywołania to jest prawidłowo? Bo raczej przez to tylko może być źle, bloby w bazie działają poprawnie, tak jak reszta.

1

Ja bym to zrobił tak, stworzył sobie klasę dziedziczącą po QStyledItemDelegate i przesłonił metody
paint() i sizeHint()
w sizeHint pobierasz z bazy i sprawdzasz rozmiar BLOB'a, zwracasz jako rozmiar pixmapy a w paint() rysujesz ową pixmapę :)
I w końcu ui->tableView->setItemDelegate(myDelegate) i gotowe.

0
Xezolpl napisał(a):

@MarekR22:
nadal nie wiem co jest grane, czy wgl to dobrze wywołuje no bo jest tak:

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);

1 bo w 1 kolumnie jest blob

i wyskakuje error w konsoli na dole że:
QFSFileEngine: No file name specified

napisałem:

MarekR22 napisał(a):
  1. Nie ustawiłeś kolumny, dla której ma być wyświetlany obrazek. m_imageColumn (nie dopisałem settera)

Po co iterujesz po elementach tabeli?

0
MarekR22 napisał(a):

Po kosmetycznych poprawkach wszystko działa (przetestowałem):

#ifndef SQLBLOBDECODERMODEL_H
#define SQLBLOBDECODERMODEL_H

#include <QIdentityProxyModel>

class SqlBlobDecoderModel : public QIdentityProxyModel
{
    Q_OBJECT

    Q_PROPERTY(int imageColumn READ imageColumn WRITE setImageColumn NOTIFY imageColumnChanged)
public:
    using QIdentityProxyModel::QIdentityProxyModel;

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

    int imageColumn() const;
    void setImageColumn(int col);

signals:
    void imageColumnChanged(int col);

private:
    bool isColumnWithImageBlob(const QModelIndex &index) const;
    QPixmap imageFromBlobIn(const QModelIndex &index) const;

private:
    int m_imageColumn = 0;
};

#endif // SQLBLOBDECODERMODEL_H
#include "sqlblobdecodermodel.h"
#include <QDebug>
#include <QPixmap>

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;
}

int SqlBlobDecoderModel::imageColumn() const
{
    return m_imageColumn;
}

void SqlBlobDecoderModel::setImageColumn(int col)
{
    if (m_imageColumn != col) {
        auto oldCol = m_imageColumn;
        m_imageColumn = col;
        emit imageColumnChanged(col);
        auto lastRow = rowCount() - 1;
        if (lastRow >= 0 && col >= 0 && col < columnCount()) {
            auto roles = QVector<int> { Qt::DisplayRole, Qt::DecorationRole };
            emit dataChanged(index(0, oldCol), index(lastRow, oldCol), roles);
            emit dataChanged(index(0, col), index(lastRow, col), roles);
        }
    }
}

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

QPixmap SqlBlobDecoderModel::imageFromBlobIn(const QModelIndex &index) const
{
    auto array = QIdentityProxyModel::data(index, Qt::DisplayRole).toByteArray();
    if (array.isNull()) {
        qDebug() << "No data for pixmap";
        return {};
    }
    QPixmap pixmap;
    if (!pixmap.loadFromData(array,"PNG",Qt::AutoColor)) {
        qDebug() << "failed load pixmap";
    }
    return pixmap.scaled(64, 64, Qt::KeepAspectRatio);
}

Jedyny problem to, wielkość obrazka i sposób jego wyświetlenia, ale to już inna bajka.
screenshot-20190330095240.png

Mógłbyś wstawić kod wywołujący to ? Skoro u cb działa to spróbuję znaleźć błąd u mnie.

2

imgdelegate.h

#ifndef IMGDELEGATE_H
#define IMGDELEGATE_H

#include <QStyledItemDelegate>
#include <QSize>
#include <QPixmap>
#include <QPainter>

class ImgDelegate : public QStyledItemDelegate
{
public:
    ImgDelegate(QObject * parent = nullptr);

    void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
    QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const;
};

#endif

imgdelegate.cpp

#include "imgdelegate.h"
#include <QSqlQuery>
#include <QDebug>

ImgDelegate::ImgDelegate(QObject * parent)
        : QStyledItemDelegate(parent)
{
}

QSize ImgDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    return QSize(32,32);
}

void ImgDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    QString type = index.model()->data(index).typeName();
    if(!type.compare("QByteArray"))
    {
        QByteArray ba = index.data(Qt::DisplayRole).toByteArray();
        QPixmap pm = QPixmap();
        pm.loadFromData(ba);
        painter->drawPixmap(option.rect, pm);
        return;
    } else {
        QStyledItemDelegate::paint(painter, option, index);
        return;
    }
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "imgdelegate.h"
#include "imgmodel.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("localhost");
    db.setUserName("testuser");
    db.setPassword("password");
    db.setDatabaseName("zadanie");
    db.open();

    model = new QSqlTableModel(this);
    model->setTable("Studenci");

    //resize table cells
    QHeaderView *vh = ui->tableView->verticalHeader();
    vh->setSectionResizeMode(QHeaderView::Fixed);
    vh->setDefaultSectionSize(80);

    ui->tableView->setModel(model);
    ui->tableView->setItemDelegate(new ImgDelegate(this));
    model->select();
}

MainWindow::~MainWindow()
{
    delete ui;
    db.close();
    delete model;
}

efekt:
8888.png

2

@MasterBLB

void ImgDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    auto value = index.data();
    if(value.type() == QVaraint::ByteArray) // wada: "QVaraint::ByteArray" jest oznaczone jako "obsolete"
    {
        auto dbBlob = value.toByteArray();
 
// albo:

void ImgDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    auto value = index.data();
    if(value.type() == static_cast<QVariant::Type>(QMetaType::QByteArray)) // wada: potrzebny static_cast, dziwne Qt powinno dostarczać operator, żeby nie było tego problemu.
    {
        auto dbBlob = value.toByteArray();
0
au7h napisał(a):

Mam to wszystko w programie u siebie i jest baza wywołana i jest model i wszystko i nadal nic już wszystko próbowałem

void Supplies_menu::table_display(int typ)
{
    ////STWORZENIE TABELI
    Adding *add = new Adding(rec,this);
    add->database_open();
    add->getDatabase(db2);


    QSqlQuery *query2= new QSqlQuery();
    if(typ==0)
    {
        query2->prepare("SELECT * FROM produkty ORDER BY weight");
                ui->tableView->sortByColumn(8);
    }
    else if(typ==1)
    {
        query2->prepare("SELECT * FROM produkty WHERE type=1 ORDER BY weight");
        ui->tableView->sortByColumn(8);
    }
    else if(typ==2)
    {
        query2->prepare("SELECT * FROM produkty WHERE type=2 ORDER BY weight");
        ui->tableView->sortByColumn(8);
    }
    else if(typ==3)
    {
        query2->prepare("SELECT * FROM produkty WHERE type=3 ORDER BY weight");
        ui->tableView->sortByColumn(8);
    }
    else if(typ==4)
    {
        query2->prepare("SELECT * FROM produkty WHERE type=4 ORDER BY weight");
        ui->tableView->sortByColumn(8);
    }
    query2->exec();
    MySqlTableModel *model = new MySqlTableModel(this,db2);
    model->select();



    /// STYLIZACJA TABELI I WKLADANIE BAZY DANYCH


    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->wywSetQuery(*query2);

    ui->tableView->setModel(model);
    ui->tableView->hideColumn(0);
    ui->tableView->hideColumn(3);
    ui->tableView->hideColumn(10);
    ui->tableView->resizeColumnsToContents();
    ui->tableView->setColumnWidth(1,35);
    ui->tableView->setColumnWidth(2,222);
    ui->tableView->setColumnWidth(8,110);
    ui->tableView->setColumnWidth(9,75);
    ui->tableView->resizeRowsToContents();



    add->database_close();

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

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

    blobDetector->setImageColumn(1);
    ui->tableView->setModel(model);

    ui->tableView->setSortingEnabled(true);
    ui->tableView->sortByColumn(8,Qt::DescendingOrder);
    ui->tableView->setModel(model);
    ui->tableView->setItemDelegate(new ImgDelegate(this));

    model->select();

}

troche haos i powtórzenia bo miałem wcześniej na blobDetectorze który jest tą klasą od @MarekR22 a jeszcze wczceśniej modelem był m który miał source z model. Ale mimo tych selectów których nie miałem normalnie, nic to nie działa, i też w sumie nie rozumiem jak ma działać skoro te funkcje ma napisane ale nie wyłowywane?

3

Wygląda to tak, że klepiesz wszystko "na pałę" bez zrozumienia co jest do czego.
Po co wciskasz ImgDelegate skoro masz SqlBlobDecoderModel? Zdecyduj się, albo jedno albo drugie.
Dlaczego mimo posiadania SqlBlobDecoderModel dalej dla QTableView ustawiasz jako source model QSqlTableModel?
QSqlTableModel ma funkcję void QSqlTableModel::setFilter(const QString &filter), gdzie wartość filter jest traktowana jako argument WHERE w zapytaniu SQL. Ręczne klepanie zapytań jest zbędne.

0
tajny_agent napisał(a):

Wygląda to tak, że klepiesz wszystko "na pałę" bez zrozumienia co jest do czego.
Po co wciskasz ImgDelegate skoro masz SqlBlobDecoderModel? Zdecyduj się, albo jedno albo drugie.
Dlaczego mimo posiadania SqlBlobDecoderModel dalej dla QTableView ustawiasz jako source model QSqlTableModel?
QSqlTableModel ma funkcję void QSqlTableModel::setFilter(const QString &filter), gdzie wartość filter jest traktowana jako argument WHERE w zapytaniu SQL. Ręczne klepanie zapytań jest zbędne.

Serio, no nie widać, waszym doświadczonym okiem jakiegoś... tego czegoś co przeoczyłem czy coś że te bloby się prawidłowo nie wyświetlają? Bo ja już nie mam sił męczę się z tym już 2 tygodnie, wszystko już próbowałem

1

A jesteś pewny, że te bloby rzeczywiście zawierają to co mają zawierać?
Oczyść kod, skup się na jednym rozwiązaniu i posprawdzaj sobie (chociażby przez qDebug()) co się dzieje.

0
tajny_agent napisał(a):

A jesteś pewny, że te bloby rzeczywiście zawierają to co mają zawierać?
Oczyść kod, skup się na jednym rozwiązaniu i posprawdzaj sobie (chociażby przez qDebug()) co się dzieje.

Czyli to co mam powinno działać. dobra spróbuję oczyścić ten kod, to był mój właściwie pierwszy samodzielny program bez przepisywania kodu z poradnika tylko już sam się na ile dawałem radę robić dlatego kod jest cały zasyfiony, chyba zastanowię się nad przepisaniem tego od podstaw zostawiając tylko ui, bo nazwenictwo jak już we wcześniejszych postach już mi pisaliście, jest do bani i nawet ja nie wiem co dana funkcja robi bez sprawdzenia jej kodu. W każdym razie dziękuję za pomoc i odezwę się jak tylko skończę :)

Edit: A co do blobów, tak zawierają to co mają zawierać gdyż mam funkcję pokazującą dany obiekt w programie wraz z jego ikoną (odczytywane z bazy).
Tak wygląda u mnie blob:

2

Skróciłem nieco kod klasy, ostatecznie wygląda tak (można nawet wywalić wszystko z sizeHint bo nie jest ona wywoływana dopóki nie zrobisz na tabeli np. ui->tableView->resizeRowsToContents();

ImgDelegate.h

#ifndef IMGDELEGATE_H
#define IMGDELEGATE_H
#include <QStyledItemDelegate>
#include <QSize>
#include <QPixmap>
#include <QPainter>

class ImgDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit ImgDelegate(QObject * parent = nullptr);
    void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
    QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const override;
};
#endif

ImgDelegate.cpp

#include "imgdelegate.h"

ImgDelegate::ImgDelegate(QObject * parent)
    : QStyledItemDelegate(parent){}

QSize ImgDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{

    if(index.model()->data(index).type() == QVariant::ByteArray)
        return QSize(80, 80); //tutaj zamiast zwracać 80, 80 możesz pobierać wielkość obrazka i ustawiać rozmiar komorki tabeli
    else
        return QStyledItemDelegate::sizeHint(option, index);
}

void ImgDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    if (index.model()->data(index).type() == QVariant::ByteArray)
    {
        QPixmap pm;
        pm.loadFromData(index.data().toByteArray());
        painter->drawPixmap(option.rect, pm);
    } else {
        QStyledItemDelegate::paint(painter, option, index);
    }
}
1

Tak, przepisanie aplikacji jest nieuniknione, po pierwsze baza danych musi być SQLITE - nie MYSQL na którym robiłem bo był poradnik u zelenta... a po drugie ten kod jest dosłownie śmieszny, i da się go skrócić 2-5 krotnie xD ale dużo się robiąc to nauczyłem więc będzie tylko lepiej.

0

UPDATE

O kuźde ile ja się z tym męczyłem...
Zadziałał sposób @MarekR22 , w końcu po chyba setkach prób ogarnąłem że w mojej klasie MySqlTableModel jest już funkcja data, która błędnie interpretowała tego QByteArraya; No takiego facepalma to jeszcze w życiu nie miałem, chyba mi czoło pęknie, ale mimo wszystko dziękuję wam wszystkim :3

///Wasze sposoby chyba też działały by, ale już wybrałem ten bo zadziałał jako pierwszy po usunięciu tej funkcji.

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