Dane usuwające się bez zaznaczenia w tabeli

1

Mam do was jedno pytanie. Tylko ciekawe czy będą z waszej strony dobre odpowiedzi, bez głupich docinek.

Więc tak. Mam w programie tabelę która wygląda jak na zrzucie poniżej

screenshot-20220920221422.png

i teraz problem jest taki. Jak kliknę przyciski usuń mimo, że nic nie jest przeze mnie zaznaczone, to usuwa się pierwszy rekord, a jak klikam jeszcze raz przycisk usuń to usuwa się następna pozycja z listy.

Pytanie jest takie. Czy jest jakiś sposób na to aby bez zaznaczenia nic nie mogło się usunąć ?

2
zkubinski napisał(a):

Mam do was jedno pytanie. Tylko ciekawe czy będą z waszej strony dobre odpowiedzi, bez głupich docinek.

Nie da się odpowiedzieć na tak zadane pytanie w sposób, który będzie dla Ciebie użyteczny w jakimkolwiek stopniu, bo nie przedstawiłeś nawet 1% wymaganych informacji… Weź to odpal spod debuggera, i popatrz, co się dzieje i dlaczego, a potem to napraw. Nie można udzielić więcej rad, bo tu się nawet nie ma do czego odnieść…

Najlepsza możliwa odpowiedź na Twoje pytanie:

Czy jest jakiś sposób na to aby bez zaznaczenia nic nie mogło się usunąć ?

brzmi „tak, jest jakiś sposób”. Pewnie odbierzesz to jako docinkę — nie dziwi mnie to, sam bym tak to odebrał — ale naprawdę nie da się lepiej nie mając od Ciebie żadnych informacji…

2

No zapewne ktoś napisał taki kod, który nie obsługuje poprawnie zaznaczania.
Trzeba to naprawić.
Odpowiedź jest celowo tak samo wartościowa jak pytanie.

1

@Althorion:

Nie da się odpowiedzieć na tak zadane pytanie w sposób, który będzie dla Ciebie użyteczny w jakimkolwiek stopniu, bo nie przedstawiłeś nawet 1% wymaganych informacji…

więc jak mam napisać pytanie aby było 100% wymaganych informacji ? Zadałem pytanie w taki sposób w jaki widzę problem... Hmm nie wiem jak trafić właściwie z pytaniem

@MarekR22:

No zapewne ktoś napisał taki kod, który nie obsługuje poprawnie zaznaczania.
Trzeba to naprawić.

ogólnie to się zastanawiam czy mój problem nie będzie związany z QItemSelection ? Tyle, że ja mam tam widok, a nie model.

1

więc jak mam napisać pytanie aby było 100% wymaganych informacji ?

Odpalić kod spod debuggera, zobaczyć co powoduje wybór rekordu do usunięcia, porównać zachowanie w sytuacji z zaznaczonym i nie zaznaczonym rekordem, dodać odpowiedni guard. Prawdopodobnie to już samo z siebie zadziała i nie będzie trzeba pytać, ale jeśli nie — to nam przedstawiasz te ww. informacje (co powoduje wybór rekordu u Ciebie w kodzie, jak się zachowuje przy zaznaczeniu, jak się zachowuje przy braku zaznaczenia, jakiego zrobiłeś guarda), i być może będziemy w stanie Cię nakierować.

ogólnie to się zastanawiam czy mój problem nie będzie związany z QItemSelection ?

Może być związany. Weź debugger, popatrz co się dzieje, zrozum co się dzieje, i popraw.

0
zkubinski napisał(a):

więc jak mam napisać pytanie aby było 100% wymaganych informacji ? Zadałem pytanie w taki sposób w jaki widzę problem... Hmm nie wiem jak trafić właściwie z pytaniem

Np w tym przypadku podać kod odpalający się po naciśnięciu <Usuń> oraz wszystkie deklaracje zmiennych które w tym kodzie występują.

zkubinski napisał(a):

ogólnie to się zastanawiam czy mój problem nie będzie związany z QItemSelection ? Tyle, że ja mam tam widok, a nie model.

Usuwać musisz z modelu.

zkubinski napisał(a):

... Tylko ciekawe czy będą z waszej strony dobre odpowiedzi, bez głupich docinek.

To powyższe zdanie właśnie jest tym głupim docinkiem - więc już się nie uda bo już to zrobiłeś.

1

dobra w związku z tematem postanowiłem opublikować kod

może ktoś mi doradzi:

  1. co robię źle z tym usuwaniem ? (pytanie jak w temacie)
  2. czy warto dodać QItemSelection ? (jeżeli tego brakuje, to możliwe, że taka funkcjonalność ulepszyłaby ten program)
  3. czy przy okazji by ktoś wyjaśnił o co chodzi z QItemSelection ? Do czego to w ogóle służy ? (Z dokumentacji wiem, że do zaznaczania wybranych pozycji w modelu) - może ktoś bardziej rozjaśni tą myśl na jakimś przykładzie - niekoniecznie chodzi o kod ale byłoby miło kod zobaczyć ?
0
zkubinski napisał(a):

może ktoś bardziej rozjaśni tą myśl na jakimś przykładzie.

Otwórz eksploratora plików w nim otwórz jakiś folder zawierający dużo plików np. c:\windows
Kliknij w jakiś plik w górnej części okna, po czym kliknij z <Shift> na jakiś inny plik w dolnej części okna, potem poklikaj z <Ctrl> na zaznaczone bądź nie pliki.

1
zkubinski napisał(a):
  1. co robię źle z tym usuwaniem ? (pytanie jak w temacie)

Wskaż może plik i miejsce ( nr linii), gdzie jest wykonywane to usuwanie. Po wejściu do Twojego projektu poczułem się bardzo zagubiony ....

1

@Robert Karpiński:

Wskaż może plik i miejsce ( nr linii), gdzie jest wykonywane to usuwanie. Po wejściu do Twojego projektu poczułem się bardzo zagubiony ....

xD

myślałem, że skompilujecie program, odpalicie, wybierzecie z menu edycja->dodaj->wybierzesz dowolny formularz i zaczniecie naciskać "usuń"

no dobra, tak poważnie to dowolny plik modelu, chociażby sqlquerymodelaccessories.cpp bo w sumie tam jest cała mechanika za dodawanie i usuwanie danych z formularza i bazy

funkcja myRemoveRow() nr linii 205 - ale to już zależy od pliku jaki uruchomisz

void SqlQueryModelAccessories::myRemoveRow()
{
    QModelIndex getIDfromTable;
    QVariant getIDtoRemove;

    QSqlQuery currentID, removeRow;
    QString strGetCurrentID = "SELECT pIDAkcesoriow FROM tRodzajAkcesoriow";
    currentID.prepare(strGetCurrentID);

    int i=0;

    if(currentID.exec()){
        if(currentID.isSelect()){
            if(currentID.isActive()){
                while (currentID.next()){
                    i=currentID.at();
                    if(i==this->row){
                        getIDfromTable=index(i,0,QModelIndex());
                        getIDtoRemove=getIDfromTable.data();
                    }
                }
            }
        }
    }

    QString strRemoveRow = "DELETE FROM tRodzajAkcesoriow WHERE pIDAkcesoriow = (?)";
    removeRow.prepare(strRemoveRow);
    removeRow.addBindValue(getIDtoRemove.toString(),QSql::In);
    removeRow.exec();

    refresh();
}
1

nawet skompilowalem ale okazuje się ze aplikacja wymaga pliku dbSpIT.db a nigdzie w kodzie nie ma "CREATE TABLE" wiec same tabele się nie tworzą :(

0

dobra, plik bazy danych poniżej - przepraszam za niedopatrzenie - lipa, że nie można innych formatów plików umieścić, niż autor sobie założył, bo mały plik musiałem zapakować... dbSpIT.7z

1

Już sama sygnatura funkcji pokazuje, że coś jest nie halo. void SqlQueryModelPeripherial::myRemoveRow() Usuń wiersz, ale który?
Ta funkcja jest bezpośrednio podpięta pod sygnał clicked dla przycisku Usuń.

Skoro w ogóle nie używasz informacji z widoku to skąd zdziwienie, że usuwa się nie to co trzeba?

0

@tajny_agent:

Już sama sygnatura funkcji pokazuje, że coś jest nie halo. void SqlQueryModelPeripherial::myRemoveRow() Usuń wiersz, ale który?

ogólnie usuwać usuwa, to co się wskaże i działa to poprawnie, tylko problem jest taki, że jak właśnie otworzysz okienko z formularzem, jeszcze nic nie zaznaczając na formularzu, to pobierany jest pierwszy wiersz, bo wykonuję zapytanie SELECT pIDstatusWypoz FROM tStatusWypoz i po usunięciu będzie to znowu inny wiersz porządkowo pierwszy od góry. Dlatego zastanawiam się czy by mi nie pomogło QItemSelection ?

Skoro w ogóle nie używasz informacji z widoku to skąd zdziwienie, że usuwa się nie to co trzeba?

a jak mogę to użyć ? Na czuja domyślam się co chcesz powiedzieć ale nie wiem co dokładnie masz na myśli ?

0

Problem jaki widzę jest taki. A co jak getIDtoRemove nie zostanie ustalone, albo this->row jest nieaktualne ?
Wszak usuwanie z DB jest wykonywane zawsze.

 if(currentID.exec()){
        if(currentID.isSelect()){
            if(currentID.isActive()){
                while (currentID.next()){
                    i=currentID.at();
                    if(i==this->row){
                        // tutaj znajdujemy wiersz i ustawiany getIdtoRemove 
                        getIDfromTable=index(i,0,QModelIndex());
                        getIDtoRemove=getIDfromTable.data();
                    }
                }
            }
        }
    }

    // ale tutaj usuwanie działa nawet wtedy gdy nie znaleziono w/w wiersza !!
    QString strRemoveRow = "DELETE FROM tRodzajAkcesoriow WHERE pIDAkcesoriow = (?)";
    removeRow.prepare(strRemoveRow);
    removeRow.addBindValue(getIDtoRemove.toString(),QSql::In);
    removeRow.exec();
2

No to chyba wiem o co chodzi.
Zmienna row w clasie SqlQueryModelAccessories jest ustawiona defautowo na 0.
Zatem jak nikt jej nie zmieni to zawsze będzie usuwany pierwszy wiersz w bazie.

Trzeba ją ustawić np. na -1.
Oraz blok usuwający rekord zabezpieczyć przed tym, że wiersz nie zostanie znaleziony.

Mam nadzieję, że o to chodziło.

2

@zkubinski: Obsługując sygnał clicked wyciągnij z widoku informacje o tym, który wiersz/wiersze są zaznaczone i przekaż te dane modelowi, który je usunie. Coś w stylu

void WidgetClass::onRemoveClicked()
{
  auto const& selectedIndexes = tableView->selectionModel()->selectedRows();
  if (selectedIndexes.isEmpty()) { return; }
  auto getId = [](auto const& entry) noexcept { return entry.data(columnWithId).toInt(); };
  std::vector<int> ids;
  std::transform(selectedIndexes.cbegin(), selectedIndexes.cend(), std::back_inserter(ids), getId);
  if (!model->removeRecords(ids)) {
    // display error
  }
}

Implementacja Model::removeRecords to już banał: pętla i podstawienie id do zapytania.

0

@tajny_agent:
Twoje rozwiązanie jest dobre ale mam jeden problem. Spójrz na zrzut ID które mam w bazie

screenshot-20220927124226.png

pIDstatusWypoz mam 29, 30, 31, 32... i jak coś usunę i następnie dodam, to te ID się zmieni na zupełnie inne, może być to np 100. Więc jaki jest problem ?

  1. Pierwszy problem jest taki, że napisałem sobie coś takiego
(...)
tblViewLoanStatus->setSelectionBehavior(QAbstractItemView::SelectRows); //to trzeba dodać aby z widoku można było wybierać wiersze
(...)
void LoanStatusWindow::onRemoveClicked()
{
    QModelIndexList setIndexes = tblViewLoanStatus->selectionModel()->selectedRows();

    for(int i=0; i<setIndexes.count(); ++i){
        QModelIndex idx;
        idx = setIndexes.at(i);
        qDebug()<< idx.row();
    }
}

Po napisaniu powyższej funkcji faktycznie pokazuje mi się wskazany wiersz do usunięcia np 0, 1, 2, 3... etc...

Teraz po złożeniu wszystkich informacji w całość, to funkcja onRemoveClicked zwróci mi wiersz do usunięcia np niech będzie to wiersz 3, tyle, że pod wierszem 3 mam pIDstatusWypoz = 32

więc jak to spiąć w całość aby w ogóle to działało prawidłowo ? Bo 3 != 32 i zapytanie z bazy nawet nie usunie tego wiersza.

  1. Drugi problem jest taki, że nie wiem co oznaczają i co robią te linijki twojego kodu (dlatego napisałem swój kod, który rozumiem)
auto getId = [](auto const& entry) noexcept { return entry.data(columnWithId).toInt(); };

oraz

std::transform(selectedIndexes.cbegin(), selectedIndexes.cend(), std::back_inserter(ids), getId);
1

A co się wyświetli jeśli zmodyfikujesz pętlę:

for(int i=0; i<setIndexes.count(); ++i){
        QModelIndex idx;
        idx = setIndexes.at(i);
        qDebug()<< idx.data();
    }

Lambda i std::transform to po prostu przyjaźniejsza forma dla 'surowej' pętli for.

0

A co się wyświetli jeśli zmodyfikujesz pętlę:

idx.data();

Pokazuje faktyczne dane. O to chodziło. Kurde, używałem tyle razy i na to nie wpadłem...

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