Qt: Usuwanie zaznaczonych rekordow w bazie danych przez QSqlTableView

0

Witam,

Moim celem bylo stworzenie prostego klienta SQLite, zachowujacego sie w ten sposob:
I. Po zmianie pola w tabeli zmiana w bazie danych (dziala).
II. W widoku zaznacza sie cale wiersze (dziala).
III. Prosty interfejs do wykonywania INSERT. (dziala)
IV. Mozna usuwac zaznaczone rekordy. (todo)
Na potrzeby IV do interfejsu dodalem QButton (ui->dropButton) i powiazalem go ze slotem drop_selected(). Teraz zalezy mi na implementacji odpowiedniej metody.

Zasadnicze pytanie: Jak to zrobic? Zrobilem research i znalazlem nastepujaca kontrolke:

Logika podpowiada, ze trzeba:

  1. Wybrac indeksy zaznaczonych elementow.
  2. Podac elementy usuwane do funkcji operujacej na modelu.

Metoda do wybierania zaznaczonych indeksów:
http://qt-project.org/doc/qt-4.8/qabstractitemview.html#selectedIndexes
Metoda usuwająca dane z modelu:
http://qt-project.org/doc/qt-4.8/qsqltablemodel.html#deleteRowFromTable

Nie jestem pewien czy to najptosza ścieżka, a nie mogę dokopać się do odpowiednich materiałów. Czy te metody to dobry wybór? Jesli nie, jak się za to zabrać?

// mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtGui>
#include <QtSql>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
private slots:
    void addRecord();
    void default_settings_db();
    void drop_selected();
private:
    Ui::MainWindow *ui;
    QSqlTableModel *table_model;
    QSqlDatabase db;
    // functions
    void initializeModel(QSqlTableModel *model);
};

#endif // MAINWINDOW_H
// mainwindow.cpp
#include <cstdlib>
#include "mainwindow.h"
#include "ui_mainwindow.h"

/*
 *  Target OS: Linux.
 */

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // set slots
    connect(ui->dodajButton, SIGNAL(clicked()), SLOT(addRecord()));
    connect(ui->actionUpdate, SIGNAL(triggered()), table_model, SLOT(submitAll()));
    connect(ui->actionUsu_baz, SIGNAL(triggered()), SLOT(default_settings_db()));
    connect(ui->dropButton, SIGNAL(clicked()), SLOT(drop_selected()));

    // create directory of the application (target for Linux)
    QString homepath(QDir::home().path());
    QString app_path = homepath.append("/.studentsdb");
    if(!QDir(app_path).exists()) QDir().mkdir(homepath);
    QString db_path = app_path.append("/studenci.db");

    // connect to database
    db = QSqlDatabase::addDatabase("QSQLITE3");
    db.setDatabaseName(db_path);

    if(!db.open()) {
        // error occurs when: $ chmod 000 ~/.studentsdb/studenci.db
        QMessageBox::critical(this, tr("SQLite connection"), tr("Unable connect to DB, check file permission."));
        exit(1);
    } else {
        QSqlQuery test_query(db);
        if(!test_query.exec("SELECT imie, nazwisko, nr_albumu FROM studenci;")) {
            QMessageBox::critical(this, tr("Table studenci doesn not exist"), tr("Creating new table"));
            test_query.exec("DROP TABLE studenci;");
            if(!test_query.exec("CREATE TABLE studenci(nr_albumu integer UNIQUE PRIMARY KEY,Imie text,Nazwisko text);")) {
                QMessageBox::critical(this, tr("Unable to create example"), tr("Cannot create table"));
                exit(1);
            }
        }
        test_query.finish();
    }

    table_model = new QSqlTableModel(this, db);

    // initialize SQL Table Model
    initializeModel(table_model);

    // bind model to QTableView
    ui->tableView->setModel(table_model);
    ui->tableView->hideColumn(0);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tableView->setSelectionMode(QAbstractItemView::MultiSelection);

}

void MainWindow::initializeModel(QSqlTableModel *model)
{
    model->setTable("studenci");
    model->setEditStrategy(QSqlTableModel::OnFieldChange);
    model->select();
}

/*
 *  Private slot.
 */

void MainWindow::addRecord()
{
    QSqlQuery insert;

    insert.prepare("INSERT INTO studenci (nazwisko, imie)"
                   "VALUES (?, ?)");
    insert.bindValue(0, ui->edit_imie->text());
    insert.bindValue(1, ui->edit_nazwisko->text());

    if(!insert.exec())
        QMessageBox::information(this, tr("Title"), tr("Insert failed"));

    ui->edit_imie->clear();
    ui->edit_nazwisko->clear();
    table_model->select();
}

void MainWindow::default_settings_db()
{
    QSqlQuery query(db);
    QMessageBox::information(this, tr("Info"), tr("Creating new DB."));
    query.exec("DROP TABLE studenci;");
    query.exec("CREATE TABLE studenci(nr_albumu integer UNIQUE PRIMARY KEY,Imie text,Nazwisko text);");
    table_model->select();
    query.finish();
}

void MainWindow::drop_selected()
{
    
}

MainWindow::~MainWindow()
{
    delete ui;
}
0

OK, nie przeglądałem dokładnie Twojego kodu, ale wkleję moje funkcje programu, który kiedyś robiłem na uczelnie (PG), może coś znajdziesz
W klasie MainWindow zdeklarowane posiadam:

    QTableView *tableView;
    QSqlRelationalTableModel *model;

oraz funkcję która obsługuje usuwanie:

 //USUN POLACZENIE
void MainWindow::deletePolaczenie()
{
    int id = (tableView->model()->data      //chcemy dane
                   (tableView->model()->index   //ktore znajdaja sie pod indeksem
                   (tableView->currentIndex().row(), 0))).toInt();  // o takich wspolrzednych
                                                    //0 jako index kolumny id
                                             //index wiersza wczytujemy z currentIndex().row()

    if(!(dbc->deletePolaczenie(id)))
    {
        QMessageBox::critical(this, tr("Blad aplikacji"),
                         tr("Blad bazy danych"));
    }
    showPolaczenia(); //odswieza tableView
}

W oddzielnej klasie do obsługi zapytań sql (w MainWindow reprezentuje go obiekt dbc)

//USUN POLACZENIE
bool DataBaseConnection::deletePolaczenie(int id)
{
    QSqlQuery query;
    query.prepare("DELETE FROM Polaczenia WHERE polaczeniaId = :polaczeniaId");
    query.bindValue(":polaczeniaId", id);

    return query.exec();
}
0

Nie było to dokładnie to czego potrzebowałem, ale bardzo mnie naprowadziłeś za co bardzo dziękuje.

PS. Też jestem z PG, wydział FTiMS.

0

To ma być projekt na bazy danych z 6 semestru?
Jeśli tak to może razem chodzimy na zajęcia z Androida... ale ten świat mały

0

Ehhh...
W dokumentacji apropos tej funkcji deleteRowFromTable() JAK BYK stoi,że w celu usuwania należy użyć removeRow/removeRows,i w zależności od przyjętej strategii edycji modelu zmiany zatwierdzić ręcznie poprzez submit() albo poczekać na automat.

0

Jestem na 4 semestrze, to pomocniczy kod, aby ogarnąć bibliotekę do dodatkowego projektu (bo uczę się dla siebie Qt) na przedmiot OJP II.

Co do rozwiązania MasterBLB bawiłem się tymi funkcjami, ale uznałem że w moim wypadku prościej usuwać po kluczu z bazy danych (bo to jest wartość która jest zawsze stała, a takie coś jak nr kolumny jest stałe). Jeżeli zamroziłbym na czas operacji numery row w modelu to i tymi funkcjami mógłbym to zrobić (ale nie jestem pewien czy tak się da, poleciałem dalej).

Moje rozwiązanie wygląda tak:

void MainWindow::drop_selected()
{
    QList<int> keys;
    // insert table studenci keys to list
    QModelIndexList selection(ui->tableView->selectionModel()->selectedRows(0));
    foreach(const QModelIndex& index, selection)
        keys.append(index.data().toInt());

    // for every key DELETE FROM studenci WHERE nr_albumu = (?);
    QSqlQuery query(db);
    foreach(const int& i, keys) {
        query.prepare("DELETE FROM studenci WHERE nr_albumu = ?;");
        query.bindValue(0, i);
        query.exec();
    }
    query.finish();
    table_model->select();
}

a
Gdyby zadziało mi removeRows to mógłbym przyspieszyć program tzn. nie pobierać jeszcze raz danych do modelu. Ale czy tak rzeczywiście będzie prościej?

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