int columnCount(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
zwracają ile jest kolumn i wierszy w płaskim modelu danych (głownie będzie to macierz)
Dla każdego modelu, nie tylko płaskiego. W przypadku modeli tabelarycznych dokumentacja radzi, żeby zwracać 0 jeśli parent
jest poprawny.
- metoda
Qt::ItemFlags flags(const QModelIndex &index) const override;
ustawia flagę która pozwala na edycję wybranych kolumn - domyślnie QTableView
jest w trybie nieedytowalnym. I żeby to zmienić używa się tej metody
Z tego co pamiętam to edycję można też wyłączyć z poziomu QTableView
bez konieczności ustawiania tego na sztywno w modelu. Ale mogę się mylić.
- Dla poniższych metod
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
moje domysły są takie -> w funkcji main
wywołujemy te metody podając im odpowiednie argumenty aby wiedziały co mają robić aby zwrócić "klasę/strukturę" z odpowiednim indexem. Piszę tak, bo nie wiem niczego na ten temat..
Zasadniczo to tych funkcji nie powinieneś w ogóle ręcznie wywoływać, bo poza komunikacją na linii model-widok nie ma to większego sensu.
- Po otrzymaniu właściwych indexów metoda
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
zwraca dane do widoku i je w nim wyświetla. Można te dane sobie wypisać w jakiejś funkcji
- Natomiast metoda
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
ustawia dane w modelu i te dane przekazuje również funkcji data
aby ustawiła je w widoku. Nie wiem też, jak miałby wyglądać zrzut tych danych z powrotem do pliku
Jak wyżej. Te funkcje służą przed wszystkim do komunikacji model<->widok czy model<->proxy. Ja ich nigdy nie wywołuje bezpośrednio, tylko dodaje do modelu wrappery o bardziej konkretnych nazwach, bez zabawy w konwersję z/na QVariant
czy przypominanie sobie z jaką role
mam je wywołać.
Nie rozumiem też jak mogę tworzyć samemu indexy za pomocą QModelIndex
Pytanie, do czego Ci to potrzebne ;)
Żeby zobaczyć jak zaimplementować model od zera możesz spojrzeć tutaj.
Masz tam przykładową implementację zarówno funkcji index
, jak i parent
.
Jeśli model ma formę tabelaryczną to dziedzicząc po QAbstractTableModel
w gratisie dostajesz domyślną implementację kilku metod jak np. index
czy parent
.
Ogółem trochę przekombinowałeś.
Pisane z palca, więc mogą się trafić jakieś przeoczenia ;)
class MyModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit MyModel(QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex{}) const override;
int columnCount(const QModelIndex& parent = QModelIndex{}) const override;
Qt::ItemFlags flags(const QModelIndext& index) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
private:
inline bool isValidIndex(const QModelIndex& index) const;
inline int getStringIndex(int row, int column) const;
static constexpr int numRows = 5;
static constexpr int numCols = 3;
QStringList texts;
};
implementacja
MyModel::MyModel(QObject* parent) : QAbstractTableModel(parent)
{
//Przykładowe dane
for (int r = 0; r < rowCount(); ++r) {
for (int c = 0; c < columnCount(); ++c) {
auto str = QString("row-%1, col-%2").arg(r).arg(c);
texts.push_back(str);
}
}
}
int MyModel::rowCount(const QModelIndex& parent) const
{
// jeśli model ma formę tabelaryczną to zwraca liczbę wierszy tylko jeśli parent.isValid() == false
return parent.isValid() ? 0 : numRows;
}
int MyModel::columnCount(const QModelIndex& parent) const
{
// ta sama zasada co w rowCount
return parent.isValid() ? 0 : numCols;
}
Qt::ItemFlags MyModel::flags(const QModelIndex& index) const
{
auto flags = QAbstractTableModel::flags(index);
// pozwalamy edytować wszystko oprócz pierwszej kolumny
if (isValidIndex(index) && index.column() != 0)
flags |= Qt::ItemIsEditable;
return flags;
}
QVariant MyModel::data(const QModelIndex& index, int role) const
{
if (isValidIndex(index)) {
if (role == Qt::DisplayRole) {
int idx = getStringIndex(index.row(), index.column());
return texts[idx];
}
}
return {};
}
bool MyModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (isValidIndex(index)) {
if (role == Qt::EditRole) {
int idx = getStringIndex(index.row(), index.column());
texts[idx] = value.toString();
return true;
}
}
return QAbstractTableModel::setData(index, value, role);
}
int MyModel::getStringIndex(int row, int column) const
{
return row * numCols + column;
}
bool MyModel::isValidIndex(const QModelIndex& index) const
{
return index.isValid() && index.row() < numRows && index.column() < numCols;
}