Problem z edycją/akutalizacją we własnym modelu

0

Witam,
głównie mam problem z uaktualnianiem danych w QTableView wykorzytując do tego własny model danych dziedziączący po QStandardItemModel.

Pierwszy raz muszę tworzyć własny model danych, gdyż dotychczas korzystałem np. z QSqlQueryModel lub QSqlTableModel i z tego co się na ten temat dowiedziałem, w celu przygotowania własnego modelu należy nadpisać wirtualne metody setData() i flags(), Dodatkowo w przypadku uaktualniania danych w QTableView należy wykorzystać sygnał datachanged().. (i to ten aspekt stanowi u mnie problem ponieważ sama edycja danych jako tako działa..)

Mój kod (część) wygląda następująco:

Qt::ItemFlags NewTestModel::flags(const QModelIndex &index) const
 {
     Qt::ItemFlags flags = QStandardItemModel::flags(index);
     if (index.column() == 5)
     {
         flags |= Qt::ItemIsEditable;
         return flags;
     }
     return  QAbstractItemModel::flags(index); 
 }

 bool NewTestModel::setData(const QModelIndex &index, const QVariant &value, int /* role */)
 {
     if(index.column() != 5)
         return false;

     QModelIndex ctResultIndex = NewTestModel::index(index.row(), 4);
     int result_id = data(ctResultIndex).toInt();

     bool ok;
     if (index.column() == 5) {

         QModelIndex top= createIndex(index.row(),index.column());
         ok = setTotalValue(result_id, value.toString());

         if(ok)
         {
             //tutaj robiłem różne kombinacje..
             //emit dataChanged(index, index);
             QAbstractItemModel::emit dataChanged(top, top);
         }
         //emit signalrepaint(row,col);       //kolejna próba obejścia problemu.. 
         qDebug() << "---------------";
         qDebug() << "value: " << value.toString();
         qDebug() << "result_id: " << result_id;
         qDebug() << "column: " << index.column();
         qDebug() << "row: " << index.row();
     }
     return ok;
 }

Ogólnie przejrzałem kilkadziesiąt stron/przykładów z sieci, jak powinno wyglądać rozwiązanie tej aktualizacji i wydaje mi się, że mam to zrobione poprawnie..(a jednak to nie działa :P więc musi czegoś brakować..).

Próbowałem obejść jakoś ten problem i znalazłem "jakieś" rozwiązanie, tylko wydaje mi się ono mało zgodne ze sztuką.. Przy pierwszym tworzeniu modelu dane są do niego dodawane z wykorzystaniem metody setItem: __resultsModel->setItem(i, k, new QStandardItem(res.value(k).toString()));__ Z racji tego początkowo emitowałem sygnał __signalrepaint()__ który napany przez slot umożliwiał "odświeżanie" modelu -- tworzył go ponownie od zera. To w tej chwili zdaje egzamin, ale czy dla większej ilości danych (np. macierzy 5000x15) to zda egzamin? (nie "przytnie" to aplikacji ?)

Ale to nie wszystko.. Jak widać powyżej ostatecznie emitowałem sygnał o postaci: __signalrepaint(row,col);__ Chciałem w ten sposób przekazać tylko informacje w jakiej komórce wiersza należy dokonać edycji danych i następnie wykonać uaktualnienie. Jednak poniższy kod nie działa poprawnie (nie powoduje żadnych zmian... pewnie czegoś brakuje...):

void NewTable::UpdateData(const QModelIndex & indexA, const QModelIndex & indexB)
{
    qDebug() << "różne kombinowanie..";

    int col = indexA.column();
    int fila = indexA.row();

    qDebug() << "col:" << col;
    qDebug() << "row" << row;

    //int valor1 = 1;
    //qDebug() << "valor1" << valor1;
    //resultsTV->model()->setData(resultsTV->model()->index(row,col),valor1+10);

    if(col == 1 || col == 5)
    {
        int valor1 = resultsTV->model()->data(resultsTV->model()->index(row,4)).toInt();
        int valor2 = resultsTV->model()->data(resultsTV->model()->index(row,5)).toInt();
        qDebug() << "****^^^^****";
        qDebug() << "valor1: " << valor1;
        qDebug() << "valor2: " << valor2;

        resultsTV->model()->setData(resultsTV->model()->index(row,col+1),1*valor1);
        //resultsTV->model()->setData(resultsTV->model()->index(row,col + 2),(20*valor1/valor2));
    }
}

Podsumowując:: czekam na jakiekolwiek sugestie/rozwiązania powyżej przedstawionego problemu.

0

Straszny masz bałagan w tym kodzie (te nadmiarowe if-y tego dowodzą, na dodatel po co są te dodatkowe QModelIndex?).
Tu masz przykład modelu tabeli, który komuś kiedyś napisałem (brakuje tylko emit dataChanged, więc poniżej jest poprawka). Przykład jest na tyle prosty, że powinieneś bez problemu zrozumieć co trzeba zrobić.

bool EditableMask::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role!=Qt::EditRole)
        return false;
    bool ok = false;
    int x = value.toInt(&ok);
    if (ok) {
        mData[index.row()+mOffset][index.column()+mOffset] = x;
        emit dataChanged(index, index);
        return true;
    }
    return false;
}
0

@MarekR22 -- dzięki przede wszystkim za zainteresowanie oraz za podesłanie linka do całości Twojego kodu :)

Po krótkiej analizie podesłanego przez Ciebie kodu, oraz przejrzeniu jeszcze raz materiałów z sieci doszedłem do pewnej konkluzji, która pokazuje (chyba) że robię błąd w samym podejściu do tematu..

Czy "kroki", które należy wykonać do osiągnięcia końcowego celu mają wyglądać mniej więcej tak:

  1. Pobranie danych z bazy danych np. do QStringList
  2. Uzupełniony QStringList ustawiamy jako model
  3. Edytujemy/Uaktualniamy model z poziomu QTableView

?

Tylko co zrobić, jeśli chce (musze) przygotować specyficzny* model do wyświetlania go w QTableView (*specyficzni to taki, który nie mogę otrzymać bezpośrednio z zapytania SQL do bazy, tylko muszę go niejako "ręcznie" sklejać do porządanego wyglądu.. W tym celu korzystam z QStandardItem tworząc przy pomocy setItem porządany przeze mnie model.. Inaczej niestety nie wiem jak rozwiązać ten problem..)

0

Ogólnie model to tylko taki adaptor. Dane możesz trzymać w dowolnej formie, model ma je jedynie dostarczyć w odpowiednie formie, która będzie zrozumiała do widoku.
QStandardItemModel to taka uniwersalna forma danych przydatna, gdy jeśli danych jest mało i chce się uniknąć pisania własnego modelu. Dziedziczenie po tej klasie w zasadzie nie ma sensu.

Zamiast pisać JAK coś chcesz zrobić (w zasadzie trudno zrozumieć o co ci chodzi), napisz CO chcesz zrobić uzyskać.

0

Ogólnie chce wyciągnąć z bazy danych pewne wyniki i przedstawić je w tabeli (wybrałem tutaj QTableView). Dane będą pochodzić z wielu tabel (tutaj w większośći sprawę załatwiają INNER JOINy), ale niestety muszę "ręcznie" przerabiać ich "wygląd" aby ostatecznie przedstawić je w tabeli.. (tzn. przedstawiam wiersze jako kolumny.. ogólnie ciężko to wytłumaczyć.. ale kolega z grupy pisał o tym tutaj na forum ( Przetworzenie wyników z tabel ) i z tego co wiem nie można tego wykonać przy pomocy zapytania SQL). Następnie w owej tabeli chciałbym wprowadzić edycje dla kilku kolumn, tak aby aktualizacja danych przebiegała zarówno w bazie danych jak i w QTableView..

Moja wiedza w ogóle na temat Qt jest początkująca.. i jedyne rozwiązanie jakie znalazłem to właśnie stworzenie takowego modelu poprzez wstawianie (setItem) danych w odpowiednie miejsce w owym modelu/tabeli..

0

to się na pewno da się zrobić zapytaniem sql tyle, że to nie będzie prosty JOIN WHERE.
Niestety SQL nie jest moją mocną stroną.
Może warto przenieść wątek do Bazy danych albo tam zadać pytanie.

0

Z tym, że ten wątek który podesłałem w linku był właśnie w tym dziale, i osoby tam się wypowiadające twierdziły, że nie da się tego wykonać... (ja sam też po kilku próbach się poddałem..). Poza tym szukałem pomocy w tym temacie również na innym forum .. i efektów nie było.. Być może jakaś bardziej zaawansowana baza danych (może Oracla) da radę wykonać takie zapytanie.. ale tutaj chodzi typowo o MySql'a..

Wracając do tematu modelu danych w Qt.. pozostaje mi chyba zostać przy akutalnym rozwiązaniu z QStandardItemModel i QStandardItem.. (bo to na ten moment spełnia moje wymagania.. Obawiam się jednak kwestii wydajności stosowania tego modelu, bowiem sam pisałeś: "QStandardItemModel to taka uniwersalna forma danych przydatna, gdy jeśli danych jest mało.." Robiłem mały test i po odpaleniu aplikacji (samej tabeli) o rozmiarze 5x10 (macierz) wykorzystywane jest 12MB RAMu.. Wydawało mi się to dużo, więc zrobiłem test na tabeli 50x130 i zużycie RAMu wzrosło do 18MB więc chyba nie jest tak źle.. (czy może się myle ?)

0

Sorry, że post pod postem, ale mam pytanie a nie chce otwierać niepotrzebne nowego wątku..

Chodzi mi o kwestie modelu.. Jak go zbudować, aby przybrał następującą postać:

1, Jan, Kowalski, Adres, Miasto, ,,,
2, Adam, Nowak, Adres, Miasto, ..
...

czyli dane pochodzące z bazy danych mają zostać tak zapisane, aby mogły stanowić model. Pewnie można wykorzystać QSqlQuery ale jest coś alternatywnego ? Myślałem o QStringList'cie ale tego chyba nie można uzyskać za pomocą tego typu..

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