Qt - własny model po QAbstractItemModel

Odpowiedz Nowy wątek
2019-11-07 13:43
0

Tworzę sobie swój własny model który dziedziczy po QAbstractItemModel i pojawił się u mnie "mały" problem...

mam 2 klasy

  1. MainWindow
  2. MyModel

.1. klasa - MainWindow
zawartość pliku nagłówkowego mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTableView>

class mymodel;

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    mymodel *_myModel;
    QTableView *view;
};
#endif // MAINWINDOW_H

zawartość pliku żródłowego mainwindow.cpp

#include "mainwindow.h"
#include "mymodel.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    view = new QTableView();
}

MainWindow::~MainWindow()
{
}
  1. klasa - MyModel

zawartość pliku nagłówkowego mymodel.h

#ifndef MYMODEL_H
#define MYMODEL_H

#include <QAbstractItemModel>

class MyModel : public QAbstractItemModel
{
public:
    MyModel(QWidget *parent=nullptr);

    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
};

#endif // MYMODEL_H

zawartość pliku źródłowego mymodel.cpp

#include "mymodel.h"

MyModel::MyModel(QWidget *parent)
{

}

int MyModel::columnCount(const QModelIndex &parent) const
{
    return 3;
}

int MyModel::rowCount(const QModelIndex &parent) const
{
    return 4;
}

i teraz mam pytanie, w jaki sposób mogę pokazać ilość wierszy i kolumn w mainwindow ? Bo chciałbym aby widok wyświetlił model

wyprzedzam już pytania typu "po co robisz swój model" skoro są inne "gotowe" - akurat chcę się nauczyć robić własne modele i zrozumieć jak to działa


bla

Pozostało 580 znaków

2019-11-08 12:56
0

no właśnie z tym indexem mam problem, pomożecie ? Bo jak nie zrobię indexu, to w sumie nie będę wiedział co jakich danych w której konkretnej komórce się odwołać, bo w sumie te funkcje wymagają indexu, no ale nie tylko indexu


bla
edytowany 1x, ostatnio: zkubinski, 2019-11-08 12:58

Pozostało 580 znaków

2019-11-08 13:21
2

Żeby było jasne
QSqlQueryModel dostarcza model "read only" z jednego powodu. Autorzy nie wiedzę jakie sql query QSqlQueryModel dostanie (może to być SELECT z wieloma join), ergo nie są w stanie stwierdzić jak obsłużyć modyfikację.
W przypadku QSqlTableModel masz tabelę i nie znając jej szczegółów można ją dość łatwo modyfikować UPDATE table_name SET field1 = ? WHERE Clause id=?.

Teraz ty znając swoje swoją bazę danych i query, które chcesz użyć do pobierania danych. Możesz więc dziedziczyć po QSqlQueryModel i zaimplementować modyfikację danych przez użytkownika.
Najprościej będzie w setData robić odpowiedni UPDATE i po sukcesie odświeżać cały model.
Optymalizacje typu: zmiana wartości w komórce, usuwanie dodawanie wierszy, bez pełnego refresh modelu są bardzo trudne w tym przypadku.

IMO masz dziedziczyć po QSqlQueryModel i nadpisać metody:

  • flags - żeby poinformować: co ma być edytowalne, a co nie
  • setData - żeby obsłużyć zapis nowych danych najpierw beginResetModel(), potem UPDATE ... na bazie danych, a na koniec endResetModel().

Wydaje mis się, że to powinno wystarczyć.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 4x, ostatnio: MarekR22, 2019-11-08 16:37
a co to jest ten "commit" ? w słowniku znaczy "oddać". Jeżeli chodzi o metody flags i setData to mam je zaimplementowane tylko problem mam z dodawaniem i usuwaniem rekordów - zkubinski 2019-11-08 15:45
https://dev.mysql.com/doc/refman/8.0/en/commit.html ale chyba ci to nie będzie potrzebne. Poza tym radzę się zainteresować kontrolą wersji (git), wtedy te słowo też było by znajome. - MarekR22 2019-11-08 16:29
zacząłem się zastanawiać nad twoim patentem "odświeżenia" całego modelu, w sumie może warto spróbować czy coś mi z tego wyjdzie, bo mogę zrobić buttona który wykona zapytanie SQL "INSERT INTO rekord" i po wstawieniu rekordu odświeży widok. Jeżeli chodzi o git to słyszałem o tym, może warto już na tym etapie się z nim zapoznać - zkubinski 2019-11-08 21:08
Jeszcze bardzo bym prosił o informację jak sobie poradzić z tymi indexami, gdyby @MasterBLB podzielił się tą wiedzą z przykładami byłbym wdzięczny - zkubinski 2019-11-08 21:22

Pozostało 580 znaków

2019-11-09 00:02
1

Generalnie po to używa się nieco bardziej zaawansowanych, bazowych klas modeli aby właśnie nie potrzebować się pałować z implementacją:

QModelIndex QAbstractItemModel::index(int row, int column, const QModelIndex &parent = QModelIndex()) const

W tejże metodzie, przy pomocy createIndex() tworzysz QModelIndex dla podanych danych wejściowych. Prawdziwy dynks tkwi w zmapowaniu danych z QSqlQuery na 2-wymiarową strukturę jakiej używa QAbstractitemModel - a tutaj to już sam musisz sobie wymyślić jak odwzorować zapytanie dajmy na to "select count from table SomeTable where <some condition="condition">" na wiersz, kolumnę oraz rodzica.
Co jest oczywistym, to to, iż po każdej zmianie zapytania dotychczas potworzone QModelIndexy tracą cały sens, stąd wspomniałem o konieczności resetowania całego modelu w takim przypadku.

Suma sumarum, będziesz musiał na piechotę zrobić to, co już jest w QSqlQueryModelu.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]

Pozostało 580 znaków

2019-11-09 18:05
0

w sumie dla mnie jakiejś filozofii nie ma aby zliczyć ile jest wierszy i kolumn w bazie, bo to jest to samo co macierz (algorytm macierzy umiem zrobić) ale bardziej mnie zastanawia to, że jak sobie pozliczam ile mam tych wierszy i kolumn to jak to "pokazać" QModelIndex-owi i przekazać tej funkcji ? Druga sprawa, to jak stworzyć tego parenta (root index) ? Bo tam też jest taka funkcja

Domyślam się następujących rzeczy:

  1. Zliczyć w macierzy (bazie) ile jest wierszy i przekazać do tej funkcji - tylko skąd tego parenta wziąć ?

    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
  2. Zliczyć ile jest kolumn i przekazać to tej funkcji - analogicznie to co wyżej skąd tego parenta wziąć ?

    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
  3. Po zliczeniu wierszy i kolumn poniższa funkcja index pobierze sobie z automatu te dane, ponieważ rowCount i columnCount zwraca ile mają wierszy i kolumn - tylko znowu mam problem z tym parentem

    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
  4. Tego parenta chyba robi się tu i ta funkcja go zwraca i powyższe funkcje sobie to pobierają, jak to w klasie

    QModelIndex parent(const QModelIndex &index) const override;

Z pozostałymi funkcjami zobaczymy czy sobie sam poradzę...

Czy mogę prosić @MasterBLB o dalsze wyjaśnienie ?


bla

Pozostało 580 znaków

2019-11-09 18:39
0

Inaczej, nim się weźmiesz za model [email protected] zastanowić się, jakie QSqlQuery chcesz obsługiwać, i dać kilka przykładowych z całego spektrum przewidywanych. Wyjaśnienie dokładnej budowy bazy danych na którym to ma operować także może być potrzebne.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]

Pozostało 580 znaków

2019-11-09 18:45
0

zastanowić się, jakie QSqlQuery chcesz obsługiwać

czy masz na myśli to, czy moje zapytania będą zawierały "INNER JOIN" lub inne podobne skomplikowane zapytania ? Czy po prostu to będą zwykłe "SELECT" z jednej tabeli ?

dać kilka przykładowych z całego spektrum przewidywanych.

masz na myśli, że mam dać klika przykładowych zapytań ?


bla

Pozostało 580 znaków

2019-11-09 19:20
0

Tak i tak na oba pytania.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]

Pozostało 580 znaków

2019-11-10 02:24
0

@zkubinski:
parent ma znaczenie tylko w przypadku modeli hierarchicznych, jak np. podział administracyjny państwa gdzie np. Polska jest 'rodzicem' dla województw, województwa są 'rodzicami' dla powiatów itd.
Dla list czy tabel parent nie jest istotny, dlatego w takich przypadkach powinno się dziedziczyć po QAbstractListModel czy QAbstractTableModel, żeby nie wynajdować koła na nowo.


Wole wizerunek z nożem w zębach, przejść po trupie
Niż zgrywać ćwierćinteligenta z piórkiem w d.
W przypadku odwzorowań QSqlQuery na item model może się okazać, że ten parent() się jednak do czegoś przyda. Ale, póki autor nie zapoda zakresu i budowy bazy danych, to w ciemno nie zgadniemy czy będzie użyteczny. - MasterBLB 2019-11-10 13:08

Pozostało 580 znaków

2019-11-11 18:04
0

Kilka dni myślałem nad przykładem, bo chciałbym zrozumieć te indexy, parenty i resztę no i chyba wymyśliłem:
Poniżej baza ma następującą strukturę, nie jest to jakiś konkretny mój problem ale starałem się pomyśleć przykład tak aby posłużył mi jako wzór do moich przyszłych rozwiązań.

Główna tabela to tWypozyczone

screenshot-20191111175734.png

Natomiast przykładowe zapytanie to:

SELECT 
`myDB`.`tWypozyczone`.`pIdWypozyczone`,
`myDB`.`tUzytkownicy`.`pImie`,
`myDB`.`tUzytkownicy`.`pNazwisko`,
`myDB`.`tUzytkownicy`.`pLogin`
FROM
`myDB`.`tWypozyczone`
INNER JOIN
`myDB`.`tUzytkownicy`
ON
`myDB`.`tUzytkownicy`.`pIdUzytkownicy` = `myDB`.`tWypozyczone`.`pIdUzytkownicy`
ORDER BY
`myDB`.`tWypozyczone`.`pIdWypozyczone`
ASC

Wiem, że w tym przypadku mógłbym skorzystać z klasy QSqlRelationalTableModel ale chciałbym wiedzieć jak tworzyć własne modele. Zależy mi na tym aby zrozumieć jak tworzyć index na dane we własnym modelu.

Mogę też dać przykład "zapytania w zapytaniu" ale to już byłby zbyt zaawansowany poziom.


bla
edytowany 1x, ostatnio: zkubinski, 2019-11-11 18:06
Przykład OK, post będzie jutro. - MasterBLB 2019-11-12 02:13

Pozostało 580 znaków

2019-11-12 12:25
0

To tak - wykonanie QSqlQuery w rezultacie daje X wierszy z bazy, a każdy wiersz ma Y kolumn. Zatem pierwsza sprawa jaką będziesz potrzebował w implementacji funkcji index() to przeniesienie wyników do jakiejś pomocniczej tabeli, zamiast ciągle się pałować z query.next().
Mając tą tabelę bardzo prosto jest już podać dla createIndex(row, column) wymagane parametry - wiersz i kolumnę będziesz miał, a parent nie jest potrzebny, zatem można przesłać null.
Ponadto od razu będziesz też w stanie zaimplementować rowCount() i columnCount()
Jednakże twój model musi mieć dodatkowo metodę setQuery która będzie ową pomocniczą tablicę ustawiała, a po tym jak skończy robiła reset() modelu.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 1x, ostatnio: MasterBLB, 2019-11-13 11:47

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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