QSQLITE: QSqlDatabase mit QSqlTableModel verbinden



  • Guten Tag,

    ich befasse mich momentan mit Datenbanken und stehe vor einem Verständlichkeitsproblem. Es funktioniert alles wie es soll, nur verstehe ich etwas nicht.

    Und zwar habe ich zwei Formulare. Ein Hauptformular welches eine Datenbankverbindung aufbaut und ein Formular zum Anlegen neuer Einträge.

    Nun frage ich mich, wie die Klasse QSqlDatabase im Hauptformular eine Verbindung zur Klasse QSqlTableModel im zweiten Formular eine Verbindung aufbaut.

    Im Hauptformular wird die Verbindung zur Datenbank wie folgt hergestellt:

        datenbank = QSqlDatabase::addDatabase("QSQLITE");
        datenbank.setDatabaseName("c:/sqlite/meinedb.db");
    

    Und im zweiten Formular wird mit folgendem Code eine Verbindung zur Tabelle hergestellt:

        modell = new QSqlTableModel();
        modell->setTable("adressen");
    

    Doch wie wird diese Verbindung hergestellt? Die Instanz "modell" der Klasse QSqlTableModel befindet sich doch in einem anderen Formular/Klasse als die Instanz "datenbank" der Klasse QSqlDatabase.

    Hier einmal der Code:
    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QtSql>
    
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
        bool dbVerbunden;
       QSqlDatabase datenbank;
    
    
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
            bool dbVerbinden(); //stellt die Verbindung zur Datenbank her
    
    private slots:
        void on_btnListenanzeige_clicked();
    
        void on_btnEinzelanzeige_clicked();
    
        void on_btnNeuerEintrag_clicked();
    
        void on_btnBeenden_clicked();
    
        void closeEvent(QCloseEvent *event);
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    
    

    mainwindow.cpp:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "neuereintrag.h"   //die Header-Datei für das Formular
    #include <QMessageBox>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        dbVerbunden = dbVerbinden();
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_btnListenanzeige_clicked()
    {
        this->close();
    }
    
    void MainWindow::on_btnEinzelanzeige_clicked()
    {
    
    }
    
    void MainWindow::on_btnNeuerEintrag_clicked()
    {
        if(dbVerbunden == true) //wenn eine Verbindung zur Datenbank besteht...
        {
            neuerEintrag *formNeu = new neuerEintrag();
            formNeu->show();
        }
    }
    
    void MainWindow::on_btnBeenden_clicked()
    {
        datenbank.close();
        this->close();
    }
    
    bool MainWindow::dbVerbinden()
    {
        bool gelungen = true;
    
        //Verbindung zur Datenbank herstellen
        datenbank = QSqlDatabase::addDatabase("QSQLITE");
        datenbank.setDatabaseName("c:/sqlite/meinedb.db");
    
        if(datenbank.open() == false)
        {
            QString fehler = datenbank.lastError().text();
            QMessageBox::critical(this, "Fehler", "Die Datenbank konnte nicht geöffnet werden.\nGrund: " + fehler);
            gelungen = false;
        }
        return gelungen;
    }
    
    void MainWindow::closeEvent(QCloseEvent *event)
    {
        datenbank.close();
    }
    
    

    neuereintrag.h:

    #ifndef NEUEREINTRAG_H
    #define NEUEREINTRAG_H
    
    #include <QWidget>
    #include <QtSql>
    
    namespace Ui {
    class neuerEintrag;
    }
    
    class neuerEintrag : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit neuerEintrag(QWidget *parent = nullptr);
        ~neuerEintrag();
    
    public slots:
        void on_btnOK_clicked();
    
        void on_btnBeenden_clicked();
    
    private:
        Ui::neuerEintrag *ui;
        QSqlTableModel *modell;
    };
    
    #endif // NEUEREINTRAG_H
    
    

    neuereintrag.cpp:

    #include "neuereintrag.h"
    #include "ui_neuereintrag.h"
    #include <QMessageBox>
    
    neuerEintrag::neuerEintrag(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::neuerEintrag)
    {
        ui->setupUi(this);
    
        modell = new QSqlTableModel();
        modell->setTable("adressen");
    }
    
    neuerEintrag::~neuerEintrag()
    {
        delete ui;
    }
    
    void neuerEintrag::on_btnOK_clicked()
    {
        int zeile;
    
        //eine neue leere Zeile an das Ende der Datenbank erstellen
        zeile = modell->rowCount(); //wie viele Datensätze sind bereits vorhanden?
        modell->insertRow(zeile);   //die Position für die neue Zeile angeben
    
        //die Daten aus dem Formular übernehmen. Das erste Argument der Methode  index()  steht
        //für die Zeile, und das zweite für die Spalte.
        modell->setData(modell->index(zeile, 1), ui->txtVorname->text());
        modell->setData(modell->index(zeile, 2), ui->txtName->text());
        modell->setData(modell->index(zeile, 3), ui->txtStrasse->text());
        modell->setData(modell->index(zeile, 4), ui->txtPLZ->text());
        modell->setData(modell->index(zeile, 5), ui->txtOrt->text());
        modell->setData(modell->index(zeile, 6), ui->txtTelefon->text());
    
        //die Änderunen übernehmen
        modell->submitAll();
    
        QMessageBox::information(this, "Info", "Die Daten wurden übernommen.");
    
        //und alle Felder wieder leeren
        ui->txtVorname->clear();
        ui->txtName->clear();
        ui->txtStrasse->clear();
        ui->txtPLZ->clear();
        ui->txtOrt->clear();
        ui->txtTelefon->clear();
    
    }
    
    void neuerEintrag::on_btnBeenden_clicked()
    {
        this->close();
    }
    
    

    P.S. Damit das ganze funktioniert, muss vorher eine Datenbank und die Tabelle per hand erstellt werden.

    Vielleicht kann mir da ja jemand auf die Sprünge helfen. Viele Dank!



  • Dies liegt daran, daß du bei addDatabase keinen Namen für die Verbindung angegeben hast, dann wird die Defaultverbindung benutzt (und diese wird dann bei allen anderen Datenbankaufrufen verwendet), s.a. QSqlDatabase unter "Detailed Description").

    Etwas genauer ist es auch in QtSql Module: Connecting to Databases beschrieben.

    Da ich außerdem jetzt noch wissen wollte, was genau hinter `defaultConnection´steht, habe ich mal die Sourcen rausgesucht: QSqlDatabase::defaultConnection

    const char *QSqlDatabase::defaultConnection = const_cast<char *>("qt_sql_default_connection");



  • Hey,
    danke für die rasche Antwort!

    Das mit der Standardverbindung habe ich nicht begriffen. Ich finde auch nirgendwo etwas erklärendes dazu.

    Ich hänge seit Tagen an dem Problem, vielleicht bin ich nur zu doof.



  • Und ich versteh nicht, was man daran nicht verstehen kann.

    Solange du bei den anderen Datenbankzugriffen (z.B. bei QSqlTableModel keine Datenbank als weiteren Parameter angibst, dann wird eben diese eine Standardverbindung genutzt (Qt speichert dazu alle Datenbankverbindungen in einer Liste bzw. Map).

    Würdest du mehrere Datenbanken in deinem Programm (zeitgleich) verwenden wollen, so müßtest du jeweils die zu verwendende Datenbank explizit angeben.



  • @Th69, ahh, jetzt ich verstehe. Also wird in diesem Fall, immer mit der Datenbank "meinedb.db" gearbeitet, da explizit nichts anderes angegeben wird.

    Danke nochmal für die Erläuterung.

    ***NACHTRAG:
    Dennoch ist nicht klar, wie die Verbindung von QSqlTableModel zu QSqlDatabase hergestellt wird. Ich sehe keine Verbindung der zwei Klassen, es muss aber eine Vorhanden sein, sonst würde der Zugriff der Standardverbindung ja scheitern, denn die eine Klasse (QSqlTableModel) greift ja auf die andere Klasse (QSqlDatabase) zu.

    Es sei denn, beim Anlegen eines QSqlTableModel-Objekts überprüft die Klasse QSqlTableModel intern automatisch, ob eine Instanz der Klasse QSqlDatabase existiert und diese eine Standardverbindung besitzt mit die er sich verbinden kann. Dieser interne Zugriff wäre mir aber neu, denn eigentlich muss man immer eine Verbindung selber über entsprechende Methoden herstellen wie z.B. in dem "Pseudocode":

    modell.connect(datenbank);
    

    Dann weiß nämlich die Instanz "modell" der Klasse QSqlTableModel, OK, ich bin nun mit der Instanz "datenbank" der Klasse QSqlDatabase verbunden, ich nutze jetzt die Standardverbindung der Instanz "datenbank".

    Vielleicht habe ich mein Anliegen zu Anfang nur zu undeutlich geschildert, ich hoffe mein Problem ist jetzt klarer.



  • Auch das kannst du direkt im Source sehen: QSqlTableModel

    Wenn die übergebene Datenbank nicht valide ist (d.h. z.B. leer), dann wird QSqlDatabase::database() benutzt, und diese gibt eben die Verbindung zu der Standarddatenbank zurück (da defaultConnection der übergebene Standardparameter ist).