Qt: QTableView nie wyświetla zawartości QSqlTableModel

0

Witam,
Chciałem stworzyć prostego klienta SQLite3 w Qt obsługującego 1 tabelę:

  • aby widok był używany do modyfikowania w locie zawartości tabeli i wyświetlania (widok: obiekt typu QTableView)
  • widok ma być podłączony do obiektu QSqlTableModel

Co działa:

  • tworzenie nowej bazy danych w katalogu domowym użytkownika (/home/nazwa_uzytkownika) jeśli nie istniała
  • dodawnia nowych elementów do bazy danych za pomocą QLineEdit i przycisku

Co nie działa:

  • QTableView dodany za pomocą Qt Creatora nie wyświetla żadnych danych
  • nie wiem czy zawinił model czy widok i nie potrafię tego sprawdzić

Pełen kod źródłowy miniprojektu można pobrać z następującego adresu:
http://www.mediafire.com/?mton4c926cfqrdn

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();
private:
    Ui::MainWindow *ui;
    QSqlTableModel table_model;
    QSqlDatabase db;
    // functions
    void initializeModel(QSqlTableModel *model);
};

#endif // MAINWINDOW_H
#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->actionUsu_baz, SIGNAL(triggered()), SLOT(default_settings_db()));

    // 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;
        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();
    }
    // initialize SQL Table Model
    initializeModel(&table_model);
    table_model.select();

    // bind model to QTableView
    ui->tableView->setModel(&table_model);
    ui->tableView->setVisible(true);
    ui->tableView->show();
}

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

    model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("Surname"));
}

/*
 *  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();
}

void MainWindow::default_settings_db()
{
    QSqlQuery query;
    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);");
}

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

Będę wdzięczny za pomoc bo już jakiś czas nad tym siedzę i nie mogę dojść do tego co jest nie w porządku.

0

select() po initializeModel() zbyteczny,tak samo ui->tableView->setVisible(true) i ui->tableView->show()

A nie widzisz potemu,że startowo nic w tej tabeli nie ma.Weź zmień jej tworzenie po zdropowaniu tak,żeby był z 1 wpis.

0

Dzięki za odpowiedź, ale to nie jest to. Jak manualnie dodam wpisy do SQLite widok wciąż milczy. Zastanawia mnie jedna rzecz: skąd widok wie, z którym obiektem QSqlDatabase pracuje?

Kod po poprawce, problem wciąż występuje:

#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->actionUsu_baz, SIGNAL(triggered()), SLOT(default_settings_db()));

    // 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;
        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();
    }

    /*
     *  Add random record to exising db!
     */
    /*
    QSqlQuery insert;
    QString name = "Testname";
    QString surname = "Testsurname";

    insert.prepare("INSERT INTO studenci (nazwisko, imie)"
                   "VALUES (?, ?)");
    insert.bindValue(0, name);
    insert.bindValue(1, surname);

    if(!insert.exec())
        QMessageBox::information(this, tr("Title"), tr("Insert failed"));
    else
        QMessageBox::information(this, tr("Test"), tr("Insert suceeded"));
    */

    // initialize SQL Table Model
    initializeModel(&table_model);

    // bind model to QTableView
    ui->tableView->setModel(&table_model);

//    ui->tableView->show();
}

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

    model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("Surname"));
}

/*
 *  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();
}

void MainWindow::default_settings_db()
{
    QSqlQuery query;
    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);");
}

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

0

Powinienem był napisać skąd model wie, a nie widok wie (bo widok zajmuje się wyświetlaniem modelu).

0

Hm spróbuj tak:
1.Twórz obiekt QSqlQuery poprzez podanie referencji do bazy danych w konstruktorze,czyli test_query(db);
2.Po utworzeniu tabeli studentów dodaj wpis poprzez

if(!query.exec("insert into studenci values ('1','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);
0

Dodałem referencje (czy to nie jest przypadkiem przekazanie przez wartość?) do zapytania tworzącego w tabeli QSqlQuery test_query(db) w konstruktorze oraz QSqlQuery query(db) w slocie default_settings_db. Nie rozwiązuje to problemu widoku, wciąż wpisy do bazy dodawane są tak samo (tyle, że czasem pojawia się błąd spowodowany tym, że chcemy dodać studenta o ID 1, a to pole ma watość UNIQUE).

Aktualny kod:

#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->actionUsu_baz, SIGNAL(triggered()), SLOT(default_settings_db()));

    // 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);
            }
        }
        if(!test_query.exec("insert into studenci values ('1','Jan','Kowalski')")) QMessageBox::warning(NULL,test_query.lastQuery(),test_query.lastError().text(),QMessageBox::Ok);
        test_query.finish();
    }

    // initialize SQL Table Model
    initializeModel(&table_model);

    // bind model to QTableView
    ui->tableView->setModel(&table_model);

//    ui->tableView->show();
}

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

    model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("Surname"));
}

/*
 *  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();
}

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);");
    if(!query.exec("insert into studenci values ('1','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);
}

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

Działanie widoku bez zmian, czyli pustka.

0

W moim projekcie otwieram bazę poprzez addDatabase("QSQLITE");
Ale reszta wygląda bardzo podobnie to twojego kodu...jedynie klucz główny mam zdefiniowany jako "id integer primary key autoincrement"
Hm,to innaczej.Stwórz nowy,PROSTY projekt którego jedynym zadaniem będzie otworzenie bazy,stworzenie QSqlTableModelu i pokazanie go w widoku,i to na tym projekcie testuj.

0

Skorzystałem z Twojej rady, utworzyłem prostszy projekt ładujący do świeżo utworzonej bazy danych nowe dane. Już wiem, że prawdopodobną przyczyną niewyświetlania danych w widoku jest niepowodzenie operacji select() w inicjalizacji modelu (ponieważ zwraca false).

Teraz pozostaje pytanie: dlaczego?

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

    QSqlTableModel table_model;
    QSqlDatabase db;
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    void initializeModel(QSqlTableModel *model);
};

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

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

    // delete database
    QFile::remove("/home/margor/testowa.db");

    // open db
    db = QSqlDatabase::addDatabase("QSQLITE3");
    db.setDatabaseName("/home/margor/testowa.db");

    if(!db.open()) {
        QMessageBox::information(this, tr("Error"), tr("Nie mozna otworzyc bazy!"));
        exit(1);
    }

    QSqlQuery query(db);
    // create table
    if(!query.exec("CREATE TABLE studenci(nr_albumu integer UNIQUE PRIMARY KEY,Imie text,Nazwisko text);")) {
        QMessageBox::information(this, tr("Error"), tr("Nie mozna utworzyc tabeli!"));
        exit(1);
    }

    // insert data into table
    if(!query.exec("INSERT INTO studenci VALUES ('1','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);
    if(!query.exec("INSERT INTO studenci VALUES ('2','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);
    if(!query.exec("INSERT INTO studenci VALUES ('3','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);

    // set model
    initializeModel(&table_model);

    // set view
    ui->tableView->setModel(&table_model);
}

void MainWindow::initializeModel(QSqlTableModel *model)
{
    model->setTable("studenci");
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // tutaj wyklada sie program!
    if(!model->select()) {
        QMessageBox::information(this, tr("Error"), tr("Nie mozna pobrac danych przez model!"));
        exit(1);
    }

    model->setHeaderData(0, Qt::Horizontal, QObject::tr("nr_albumu"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Imie"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("Nazwisko"));
}

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

Dodam, że zamiana drivera bazy danych na "QSQLITE" też nie zmienia nic.

0

Zmieniłem polecenie:

QMessageBox::information(this, tr("Error"), model->lastError().text());

I widzę:

"unable to find table studenci".

Czyli przyczyna jest znana: model nie widzi tabeli. Jak sprawdzić czy szuka we właściwej bazie danych?

0

Poprawiony i działający kod:

#include <cstdlib>
#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    // delete database
    QFile::remove("/home/margor/testowa.db");

    // open db
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("/home/margor/testowa.db");

    if(!db.open()) {
        QMessageBox::information(this, tr("Error"), tr("Nie mozna otworzyc bazy!"));
        exit(1);
    }

    QSqlQuery query(db);
    // create table
    if(!query.exec("CREATE TABLE studenci(nr_albumu integer UNIQUE PRIMARY KEY,Imie text,Nazwisko text);")) {
        QMessageBox::information(this, tr("Error"), tr("Nie mozna utworzyc tabeli!"));
        exit(1);
    }

    // insert data into table
    if(!query.exec("INSERT INTO studenci VALUES ('1','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);
    if(!query.exec("INSERT INTO studenci VALUES ('2','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);
    if(!query.exec("INSERT INTO studenci VALUES ('3','Jan','Kowalski')")) QMessageBox::warning(NULL,query.lastQuery(),query.lastError().text(),QMessageBox::Ok);

    // set model
    table_model = new QSqlTableModel(this, db);
    initializeModel(table_model);

    // set view
    ui->tableView->setModel(table_model);
}

void MainWindow::initializeModel(QSqlTableModel *model)
{
    model->setTable("studenci");
    model->setEditStrategy(QSqlTableModel::OnFieldChange);
    // tutaj wyklada sie program!
    if(!model->select()) {
        QMessageBox::information(this, tr("Error"), model->lastError().text());
        exit(1);
    }

    model->setHeaderData(0, Qt::Horizontal, QObject::tr("nr_albumu"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Imie"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("Nazwisko"));
}

MainWindow::~MainWindow()
{
    delete ui;
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

    QSqlTableModel* table_model;
    QSqlDatabase db;
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    void initializeModel(QSqlTableModel *model);
};

#endif // MAINWINDOW_H

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