Różnica w działaniu pomiędzy QStandardItemModel i QTableView

1

Cześć, robię swój model dziedzicząc po QStandardItemModel. Próbuję zrozumieć jak się tworzy własny model i napotkałem problem, że nie chce mi działać funkcja Qt::ItemFlags DataModel::flags i funkcja QVariant DataModel::data - dlaczego ? Co zrobiłem źle ?

wygląd modelu -> plik DataModel.h

class DataModel : public QStandardItemModel
{
    Q_OBJECT

public:
    DataModel(QObject *parent=nullptr);

private:
    // QAbstractItemModel interface
    virtual int rowCount(const QModelIndex &parent) const override;
    virtual int columnCount(const QModelIndex &parent) const override;
    virtual QVariant data(const QModelIndex &index, int role) const override;
    virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override;
    virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
    virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) override;
    virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
};

plik DataModel.cpp

#include "datamodel.h"
#include <QDebug>

DataModel::DataModel(QObject *parent) : QStandardItemModel(parent)
{

}

int DataModel::rowCount(const QModelIndex &parent) const
{
    return 3;
}

int DataModel::columnCount(const QModelIndex &parent) const
{
    return 4;
}

QVariant DataModel::data(const QModelIndex &index, int role) const //ta funkcja nie wyświetla danych w widoku
{
    if(role==Qt::DisplayRole){
        if(index.row()==0 && index.column()==0){
            QVariant data;
            data="pierwszy wpis";
            return data;
        }
    }
    return QVariant();
}

bool DataModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    return true;
}

QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(role==Qt::DisplayRole && orientation==Qt::Horizontal){
        return QString("Nagłówek %1").arg(section+1);
        }

    if(role==Qt::DisplayRole && orientation==Qt::Vertical){
            return QString("%1").arg(section+1);
        }

    return QVariant();
}

bool DataModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
    if(role==Qt::DisplayRole && orientation==Qt::Horizontal){
        if(section==0){
            emit setHeaderData(section, orientation, value, role);
            return true;
        }
    }

    return true;
}

Qt::ItemFlags DataModel::flags(const QModelIndex &index) const //ta funkcja nie daje pola do edycji
{
    Qt::ItemFlags flag = QStandardItemModel::flags(index);

    if(index.column()==0){
        flag |= Qt::ItemIsEditable;

        return flag;
    }

    return flag;
}

plik mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}
{
    this->resize(500,400);
    mainWidget = new QWidget(this);

    mainVlayout = new QVBoxLayout(mainWidget);
    bttHlayout = new QHBoxLayout();

    myModel = new DataModel(this); //tutaj jest mój model
    tableView = new QTableView(this);
    tableView->setModel(myModel);

    bttAddRecord = new QPushButton(this);
    bttAddRecord->setText(QString(tr("Dodaj rekord")));

    bttClose = new QPushButton(this);
    bttClose->setText(QString(tr("Zamknij")));

    mainVlayout->addWidget(tableView);
    mainVlayout->addLayout(bttHlayout);

    bttHlayout->addWidget(bttAddRecord);
    bttHlayout->addWidget(bttClose);

    this->setCentralWidget(mainWidget);

    QObject::connect(bttClose, &QPushButton::clicked, this, &MainWindow::close);
}

1

Dobra, doszedłem czemu nie działało, trzeba doimplementować funkcje parent & index

plik datamodel.cpp

QModelIndex DataModel::parent(const QModelIndex &child) const
{
    Q_UNUSED(child);

    return QModelIndex();
}

QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
{
    QModelIndex index;
    index=createIndex(row,column,nullptr);

    return index;
}

wiem, że wygląda to prostacko ale mam pytanie - jak POPRAWNIE zaimplementować parent & index dla tabeli ? Wiem, że tabela nie ma czegoś takiego jak parent i ta funkcja sprawdza się dla danych typu lista. Czy ktoś coś podpowie i podzieli się wiedzą ?

2

Nie musisz: zapoznaj się z: https://felgo.com/doc/qt/modelview/

1

@_13th_Dragon:
czytałem ale nie widzę niczego co mogłoby mi pomóc. Z drugiej strony może ktoś mi wyjaśni jedną z wielu nieścisłości, której nie rozumiem.

napisałem taką funkcję, która owszem działa poprawnie ale w pewnych warunkach, ta funkcja to możliwość edycji pól i wygląda ona tak:

Qt::ItemFlags DataModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags flag = QAbstractItemModel::flags(index);

    if(index.column()==0){
        flag |= Qt::ItemIsEditable;

        return flag;
    }

    return flag;
}

a teraz czego nie rozumiem. Mam dwie funkcje index & parent i powyższa funkcja flags DZIAŁA na kodzie poniżej

QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
{
    return createIndex(row,column,nullptr);
}

QModelIndex DataModel::parent(const QModelIndex &child) const
{
    Q_UNUSED(child);
    return QModelIndex();
}

i pytanie odnośnie tego wątku jest takie. Dlaczego funkcja flags NIE DZIAŁA na kodzie poniżej ? Dodam, że zmienne parent i child poprawnie wskazują wiersze i kolumny.

QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
{
    return createIndex(row,column,&parent);
}

QModelIndex DataModel::parent(const QModelIndex &child) const
{
    if(!child.isValid()){
        return QModelIndex();
    }

    return child;
}

wiem, że czegoś nie rozumiem. Ale serio, chciałbym aby ktoś mi to wyjaśnił w kilku zdaniach co tu się odwala.

0

Skoro nie jesteś w stanie przeczytać ze zrozumieniem kompletnego sprawdzonego przykładu z podanego źródła, to czemu uważasz że będziesz w stanie przeczytać że zrozumieniem fragment kodu który tu dostaniesz?
Wg mnie musisz zacząć się uczyć wg następującego planu:

  • Język polski, czytanie ze zrozumieniem
  • Podstawy języka C++
  • Jakiś kurs z podstaw Qt

Dopiero po rzetelnym przejściu wyżej wspomnianych kursów będziemy w stanie ci pomóc.

0

@zkubinski: a jest jakiś powód czemu chcesz użyć QStandardItemModel, zamiast QAbstractTableModel?

1
Riddle napisał(a):

@zkubinski: a jest jakiś powód czemu chcesz użyć QStandardItemModel, zamiast QAbstractTableModel?

ogólnie to chcę dobrze zrozumieć robienie niestandardowych modeli. I teraz żebyśmy się dobrze zrozumieli. Zacząłem od QStandardItemModel ale zmiękłem, bo żeby to podklasować i dobrze złożyć w całość, to trzeba jeszcze skorzystać z klasy QStandardItem. Więc zmiękłem, to zdecydowałem się, że zamiast wykorzystać klasę QStandardItemModel, to robię własną klasę na podstawie QAbstractItemModel. Ale próbuję dociec jak napisać funkcję index i parent. Teraz tytuł powinieniem zmienić z QStandardItemModel na QAbstractItemModel

2

Pierszy poważny problem: class DataModel : public QStandardItemModel.
Radzę przeczytać do czego służy QStandardItemModel zanim się go użyje.
Ta klasa nie jest przeznaczona do dziedziczenia.
Na pierwszy rzut oka powinieneś zainteresować się QAbstractTableModel (sekcja subclassing wyjaśnia co trzeba zrobić).

bool DataModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
    if(role==Qt::DisplayRole && orientation==Qt::Horizontal){
        if(section==0){
            emit setHeaderData(section, orientation, value, role);
            return true;
        }
    }

    return true;
}

Ta rekursja pokazuje, że nie rozumiesz podostaw Qt i może nawet podstaw programowania w C++, a bierzesz się za Q*ItemModel
Ta rekursja jest nieskończona! Pewnie masz stackoverflow.

Jeszcze użycie tego emit :(

0

@MarekR22:

Ta rekursja pokazuje, że nie rozumiesz podostaw Qt i może nawet podstaw programowania w C++, a bierzesz się za Q*ItemModel

możliwe, tyle, że i tak napisałem to na pałę, bo nigdzie nie mogę znaleźć przykładu jak się tym obsłużyć - jeżeli ktoś ma, to podrzuci ? Ale na tym forum otrzymanie rzetelnych info graniczy z cudem...

Ta rekursja jest nieskończona!

a tego to nie wiedziałem... bo jakoś nie widać, żeby to wywoływało się nieskończenie wiele razy... bo na pewno to nie działa wcale ;)

ierszy poważny problem: class DataModel : public QStandardItemModel.

ok, w pewnym momencie się połapałem, że zrobiłem COŚ źle bo coś po prostu mi nie szło

Radzę przeczytać do czego służy QStandardItemModel zanim się go użyje.

QStandardItemModel can be used as a repository for standard Qt data types. It is one of the Model/View Classes and is part of Qt's model/view framework.

dla mnie jest to mdłe tłumaczenie, które nic nie wnosi - czepiam się tego -> for standard Qt data types co to znaczy standardowe typy danych Qt ? Nie wiem co wy z tego rozumiecie, bo ja kompletnie NIC... Czy naprostuje ktoś tutaj ?

Na pierwszy rzut oka powinieneś zainteresować się QAbstractTableModel

Na pierwszy rzut oka, to masz całkowitą rację. I tutaj, tak na chłopski rozum wypada powiedzieć że:

  1. Jeżeli dane są reprezentowane w formie tabeli I NIE CHCESZ SIĘ BAWIĆ W TWORZENIE WŁASNEGO MODELU, to użyj QAbstractTableModel - bo ma już zaimplementowany parent & index
  2. Jeżeli dane są reprezentowane w formie listy to skorzystaj QAbstractListModel
  3. Jeżeli dane są reprezentowane w formie bazy danych, to skorzystaj z QSqlQueryModel

Dalej już nie chce mi się wypisywać, ale są też gotowe modele do wyświetlania listy plików etc....

Wszystkie powyższe modele łączy jedno - jeżeli nie chcesz się grzebać z tworzeniem modelu od podstaw, to użyj jednego z powyższych i zapomnij o problemach. Jeżeli jesteś hard i szukasz problemu, to użyj QAbstractItemModel bo tutaj trzeba robić wszystko od podstaw i ma się pełną kontrolę nad tym co chce się uzyskać w efekcie finalnym. No mnie bardzo zaciekawiła ten ostatni abstrakcyjny model tj. QAbstractItemModel bo chcę się nauczyć go robić, przynajmniej by wypadało to umieć. No to jak ? Pomoże ktoś ? Czy olewamy delikwenta i niech sobie radzi sam ?

2
zkubinski napisał(a):

No mnie bardzo zaciekawiła ten ostatni abstrakcyjny model tj. QAbstractItemModel bo chcę się nauczyć go robić, przynajmniej by wypadało to umieć. No to jak ? Pomoże ktoś ? Czy olewamy delikwenta i niech sobie radzi sam ?

Zaciekawił Cię prawie trzy lata temu (temat). Co się przez ten czas stało z całą wiedzą przekazaną przez forumowiczów?

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