From ad0d38876b11e4986ff6a337501c59cc7959c537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20W=C3=B3jtowicz?= Date: Fri, 1 Sep 2017 22:53:26 +0200 Subject: [PATCH] Added project files --- .gitignore | 41 ++++ README.md | 9 + config.ini | 9 + qt-sql-example.pro | 22 ++ res/database.ico | Bin 0 -> 112640 bytes res/failure.ico | Bin 0 -> 99678 bytes res/icons.qrc | 7 + res/readme.txt | 5 + res/success.ico | Bin 0 -> 99678 bytes screenshot.png | Bin 0 -> 17942 bytes src/db_controller.cpp | 139 +++++++++++ src/db_controller.h | 42 ++++ src/main.cpp | 21 ++ src/mainwindow.cpp | 288 ++++++++++++++++++++++ src/mainwindow.h | 49 ++++ src/mainwindow.ui | 556 ++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 1188 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config.ini create mode 100644 qt-sql-example.pro create mode 100644 res/database.ico create mode 100644 res/failure.ico create mode 100644 res/icons.qrc create mode 100644 res/readme.txt create mode 100644 res/success.ico create mode 100644 screenshot.png create mode 100644 src/db_controller.cpp create mode 100644 src/db_controller.h create mode 100644 src/main.cpp create mode 100644 src/mainwindow.cpp create mode 100644 src/mainwindow.h create mode 100644 src/mainwindow.ui diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cab62ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# C++ objects and libs + +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es + +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +Makefile* +*build-* + +build/* + +# QtCreator + +*.autosave + +# QtCtreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCtreator CMake +CMakeLists.txt.user* + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c021689 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# QT SQL Example + +An exemplary Qt app that connects to SQL server and displays a table from a database. The program was made for educational purposes. + +![](screenshot.png) + +The program was tested on: + * client: Windows 10, Qt 5.9.1, + * servers: MySQL Server 5.5.57, Microsoft SQL Server 2008 R2 SP3. diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..dde3b15 --- /dev/null +++ b/config.ini @@ -0,0 +1,9 @@ +[sql] +engine=mssql +driver=SQL Server +address=localhost\\SQLEXPRESS +port=1433 +authentication=server +login=user +password=password +database=db diff --git a/qt-sql-example.pro b/qt-sql-example.pro new file mode 100644 index 0000000..cc93e9c --- /dev/null +++ b/qt-sql-example.pro @@ -0,0 +1,22 @@ +VERSION = 1.0 +QMAKE_TARGET_DESCRIPTION = "Qt app that displays SQL table; for educational purposes" +QMAKE_TARGET_COPYRIGHT = "Andrzej Wojtowicz, Adam Mickiewicz University in Poznan" +QMAKE_TARGET_PRODUCT = "Qt SQL Example" + +QT += core gui sql widgets + +TARGET = qt-sql-example +TEMPLATE = app + +SOURCES += src/main.cpp\ + src/mainwindow.cpp \ + src/db_controller.cpp + +HEADERS += src/mainwindow.h \ + src/db_controller.h + +FORMS += src/mainwindow.ui + +RESOURCES += res/icons.qrc + +win32:RC_ICONS += res/database.ico diff --git a/res/database.ico b/res/database.ico new file mode 100644 index 0000000000000000000000000000000000000000..f17d6e7e3b076c0deb8336b2ce34499b5a98a89c GIT binary patch literal 112640 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

pE5^oqBcCGK;N}ZR0Qd4c=Xt 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 A&;S4c literal 0 HcmV?d00001 diff --git a/res/icons.qrc b/res/icons.qrc new file mode 100644 index 0000000..4e5b607 --- /dev/null +++ b/res/icons.qrc @@ -0,0 +1,7 @@ + + + database.ico + failure.ico + success.ico + + diff --git a/res/readme.txt b/res/readme.txt new file mode 100644 index 0000000..fb529d0 --- /dev/null +++ b/res/readme.txt @@ -0,0 +1,5 @@ +database.ico: +- author: http://barrymieny.deviantart.com +- license: Creative Commons Attribution Non-commercial Share Alike (by-nc-sa) +success.ico & failure.ico +- author: https://www.iconfinder.com/iconpack \ No newline at end of file diff --git a/res/success.ico b/res/success.ico new file mode 100644 index 0000000000000000000000000000000000000000..fb219e3c105b2e5380b153f076d22cee05d1bbd8 GIT binary patch literal 99678 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 literal 0 HcmV?d00001 diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..9062ae5050c36902eefb4f73b2ca2f0392d57ff5 GIT binary patch literal 17942 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"SELECT * FROM " + name, db); + + return model; +} + +QSqlError DbController::getLastError() +{ + return db.lastError(); +} + +const QString DbController::connection_string_sqlauth = + QString("DRIVER={%1};SERVER=%2;PORT=%3;DATABASE=%4;UID=%5;PWD=%6"); + +const QString DbController::connection_string_winauth = + QString("DRIVER={%1};SERVER=%2;PORT=%3;DATABASE=%4"); diff --git a/src/db_controller.h b/src/db_controller.h new file mode 100644 index 0000000..6ab257e --- /dev/null +++ b/src/db_controller.h @@ -0,0 +1,42 @@ +#ifndef DB_CONTROLLER_H +#define DB_CONTROLLER_H + +#include +#include + +class DbController : public QObject +{ + Q_OBJECT +public: + explicit DbController(QObject*); + ~DbController(); + bool checkIfTableExists(QString); + bool checkIfConnected(); + +public slots: + void connectToServerRequested(QString, QString, QString, int, QString, QString, QString, bool); + void disconnectFromServerRequested(); + void selectTableRequested(QString); + void getTablesNamesRequested(); + +signals: + void serverConnected(); + void serverErrorWithConnection(QString); + void serverDisconnected(); + void tableSelected(QSqlQueryModel*); + void gotTablesNames(QStringList); + +private: + bool connectToServerMSSQL(QString, QString, int, QString, QString, QString); + bool connectToServerMSSQL(QString, QString, int, QString); + bool connectToServerMySQL(QString, int, QString, QString, QString); + void disconnectFromServer(); + QSqlQueryModel* selectTable(QString); + QSqlError getLastError(); + + QSqlDatabase db; + static const QString connection_string_sqlauth; + static const QString connection_string_winauth; +}; + +#endif // DB_CONTROLLER_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..cecf3d1 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,21 @@ +#include "db_controller.h" +#include "mainwindow.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + DbController db_controller(0); + QThread db_thread; + + db_controller.moveToThread(&db_thread); + db_thread.start(); + + MainWindow window(0, &db_controller, &db_thread); + window.show(); + + return app.exec(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..585198d --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,288 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget* parent, DbController* dbc, QThread* dbt) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + db_controller = dbc; + db_thread = dbt; + + // check Qt SQL drivers + + QStringList sql_drivers = QSqlDatabase::drivers(); + ui->label_qmysql_icon->setPixmap( + QPixmap(":/icons/" + QString(sql_drivers.contains("QMYSQL") ? "success" : "failure") + ".ico")); + ui->label_qodbc_icon->setPixmap( + QPixmap(":/icons/" + QString(sql_drivers.contains("QODBC") ? "success" : "failure") + ".ico")); + + ui->radio_mysql->setEnabled(sql_drivers.contains("QMYSQL")); + ui->radio_mssql->setEnabled(sql_drivers.contains("QODBC")); + + if (!sql_drivers.contains("QMYSQL") && !sql_drivers.contains("QODBC")) + ui->groupBox_sql_connect->setEnabled(false); + + // connect signals with slots + + // ui => ui + + connect(ui->button_connect, SIGNAL(clicked()), this, SLOT(connectToServerRequested())); + connect(ui->radio_mssql, SIGNAL(clicked()), this, SLOT(engineChanged())); + connect(ui->radio_mysql, SIGNAL(clicked()), this, SLOT(engineChanged())); + connect(ui->radio_sql_authentication, SIGNAL(clicked()), this, SLOT(authenticationMethodChanged())); + connect(ui->radio_windows_authentication, SIGNAL(clicked()), this, SLOT(authenticationMethodChanged())); + connect(ui->button_show_table, SIGNAL(clicked()), this, SLOT(showTableRequested())); + + // ui => db_controller + + connect(this, SIGNAL(connectToServer(QString,QString,QString,int,QString,QString,QString,bool)), + db_controller, SLOT(connectToServerRequested(QString,QString,QString,int,QString,QString,QString,bool))); + connect(this, SIGNAL(disconnectFromServer()), db_controller, SLOT(disconnectFromServerRequested())); + connect(this, SIGNAL(selectTable(QString)), db_controller, SLOT(selectTableRequested(QString))); + connect(this, SIGNAL(getTablesNames()), db_controller, SLOT(getTablesNamesRequested())); + + // db_controller => ui + + connect(db_controller, SIGNAL(serverConnected()), this, SLOT(serverConnected())); + connect(db_controller, SIGNAL(serverErrorWithConnection(QString)), + this, SLOT(serverErrorWithConnection(QString))); + connect(db_controller, SIGNAL(serverDisconnected()), this, SLOT(serverDisconnected())); + connect(db_controller, SIGNAL(tableSelected(QSqlQueryModel*)), this, SLOT(displayTable(QSqlQueryModel*))); + connect(db_controller, SIGNAL(gotTablesNames(QStringList)), this, SLOT(fillTablesNames(QStringList))); + + // load settings + + QString inifile("config.ini"); + QFileInfo check_file(inifile); + if (check_file.exists() && check_file.isFile()) + { + QSettings settings(inifile, QSettings::Format::IniFormat); + + QString engine = settings.value("sql/engine", "").toString(); + if (engine == "mysql") + { + ui->radio_mysql->setChecked(true); + ui->radio_windows_authentication->setEnabled(false); + ui->lineEdit_driver->setEnabled(false); + } + else if (engine == "mssql") + { + ui->radio_mssql->setChecked(true); + } + + ui->lineEdit_driver->setText(settings.value("sql/driver", "").toString()); + ui->lineEdit_server_address->setText(settings.value("sql/address", "").toString()); + ui->spinBox_server_port->setValue(settings.value("sql/port", 0).toInt()); + QString auth = settings.value("sql/authentication", "").toString(); + ui->radio_sql_authentication->setChecked(auth == "server" && (engine == "mssql" || engine == "mysql")); + ui->radio_windows_authentication->setChecked(auth == "windows" && engine == "mssql"); + ui->lineEdit_login->setText(settings.value("sql/login", "").toString()); + ui->lineEdit_password->setText(settings.value("sql/password", "").toString()); // plain text, so secure... + ui->lineEdit_database_name->setText(settings.value("sql/database", "").toString()); + + ui->statusBar->showMessage("Settings file config.ini loaded", 3000); + } + else + { + ui->statusBar->showMessage("Settings file config.ini does not exist", 5000); + } + + +} + +MainWindow::~MainWindow() +{ + db_thread->exit(); + db_thread->wait(); + delete ui; +} + +void MainWindow::connectToServerRequested() +{ + QString engine; + if (ui->radio_mysql->isChecked()) + engine = "mysql"; + else if (ui->radio_mssql->isChecked()) + engine = "mssql"; + else + { + QMessageBox::information(this, + "Invalid Engine", + "Choose database engine", + QMessageBox::Ok); + return; + } + + QString driver = ui->lineEdit_driver->text(), + server = ui->lineEdit_server_address->text(), + database = ui->lineEdit_database_name->text(), + login = ui->lineEdit_login->text(), + password = ui->lineEdit_password->text(); + int port = ui->spinBox_server_port->value(); + + if (server == "") + { + QMessageBox::information(this, + "Invalid Connection Data", + "Insert server address to connect", + QMessageBox::Ok); + return; + } + + bool is_sql_authentication = ui->radio_sql_authentication->isChecked(); + + if (is_sql_authentication && login == "") + { + QMessageBox::information(this, + "Invalid Connection Data", + "Insert login to connect", + QMessageBox::Ok); + return; + } + + if (database == "") + { + QMessageBox::information(this, + "Invalid Connection Data", + "Insert database name to connect", + QMessageBox::Ok); + return; + } + + ui->button_connect->setEnabled(false); + ui->statusBar->showMessage("Connecting..."); + + emit connectToServer(engine, driver, server, port, database, login, password, is_sql_authentication); +} + +void MainWindow::disconnectFromServerRequested() +{ + ui->button_connect->setEnabled(false); + + emit disconnectFromServer(); +} + +void MainWindow::authenticationMethodChanged() +{ + bool is_sql_authentication = ui->radio_sql_authentication->isChecked(); + + ui->lineEdit_login->setEnabled(is_sql_authentication); + ui->lineEdit_password->setEnabled(is_sql_authentication); +} + +void MainWindow::engineChanged() +{ + bool is_mssql_engine = ui->radio_mssql->isChecked(); + + ui->lineEdit_driver->setEnabled(is_mssql_engine); + ui->radio_windows_authentication->setEnabled(is_mssql_engine); + + ui->spinBox_server_port->setValue(is_mssql_engine ? 1433 : 3306); + + if (!is_mssql_engine) + { + ui->radio_sql_authentication->setChecked(true); + emit authenticationMethodChanged(); + } +} + +void MainWindow::showTableRequested() +{ + ui->button_show_table->setEnabled(false); + + QString table_name = ui->comboBox_table_name->currentText(); + + emit selectTable(table_name); +} + +void MainWindow::serverConnected() +{ + ui->button_connect->setEnabled(true); + + disconnect(ui->button_connect, SIGNAL(clicked()), this, SLOT(connectToServerRequested())); + connect(ui->button_connect, SIGNAL(clicked()), this, SLOT(disconnectFromServerRequested())); + + ui->button_connect->setText("Disconnect"); + ui->groupBox_database_browser->setEnabled(true); + + ui->statusBar->showMessage("Connected", 3000); + + emit getTablesNames(); +} + +void MainWindow::fillTablesNames(QStringList tables_names) +{ + if (tables_names.length() == 0) + QMessageBox::warning(this, + "Tables", + "There are no tables to display in the database", + QMessageBox::Ok); + else + { + ui->comboBox_table_name->addItems(tables_names); + + ui->comboBox_table_name->setEnabled(true); + ui->comboBox_table_name->setFocus(); + } +} + +void MainWindow::serverErrorWithConnection(QString message) +{ + QMessageBox::critical(this, + "Connection failed", + message, + QMessageBox::Ok); + + ui->button_connect->setEnabled(true); + + ui->statusBar->showMessage("Connection failed", 3000); +} + +void MainWindow::serverDisconnected() +{ + disconnect(ui->button_connect, SIGNAL(clicked()), this, SLOT(disconnectFromServerRequested())); + connect(ui->button_connect, SIGNAL(clicked()), this, SLOT(connectToServerRequested())); + + ui->tableView_database_table->setModel(NULL); + + ui->button_connect->setEnabled(true); + ui->button_connect->setText("Connect"); + + ui->comboBox_table_name->clear(); + ui->comboBox_table_name->setEnabled(false); + + ui->groupBox_database_browser->setEnabled(false); + ui->button_connect->setFocus(); +} + +void MainWindow::displayTable(QSqlQueryModel* model) +{ + if (!model->lastError().isValid()) + ui->tableView_database_table->setModel(model); + else + QMessageBox::critical(this, + "Select failed", + model->lastError().databaseText(), + QMessageBox::Ok); + + ui->button_show_table->setEnabled(true); + ui->comboBox_table_name->setFocus(); +} + +void MainWindow::keyPressEvent(QKeyEvent* pe) +{ + if (pe->key() == Qt::Key_Enter || pe->key() == Qt::Key_Return) + { + if (!db_controller->checkIfConnected()) + emit connectToServerRequested(); + else if (ui->comboBox_table_name->isEnabled() && ui->comboBox_table_name->hasFocus()) + emit showTableRequested(); + } +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..796c5ea --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,49 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "db_controller.h" + +#include + +namespace Ui +{ + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget* parent, DbController* dbc, QThread* dbt); + ~MainWindow(); + +public slots: + void connectToServerRequested(); + void disconnectFromServerRequested(); + void engineChanged(); + void authenticationMethodChanged(); + void showTableRequested(); + + void serverConnected(); + void serverErrorWithConnection(QString); + void serverDisconnected(); + void displayTable(QSqlQueryModel*); + void fillTablesNames(QStringList); + +signals: + void connectToServer(QString, QString, QString, int, QString, QString, QString, bool); + void disconnectFromServer(); + void selectTable(QString); + void getTablesNames(); + +private: + Ui::MainWindow* ui; + DbController* db_controller; + QThread* db_thread; + +protected: + virtual void keyPressEvent(QKeyEvent*); +}; + +#endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui new file mode 100644 index 0000000..082b840 --- /dev/null +++ b/src/mainwindow.ui @@ -0,0 +1,556 @@ + + + MainWindow + + + + 0 + 0 + 690 + 483 + + + + + 0 + 0 + + + + + 690 + 483 + + + + Qt SQL Example + + + + :/icons/database.ico:/icons/database.ico + + + + + + + + + + 0 + 0 + + + + + 250 + 45 + + + + Qt SQL database drivers + + + + + 53 + 23 + 13 + 13 + + + + + + + :/icons/failure.ico + + + + + + 143 + 23 + 13 + 13 + + + + + + + :/icons/failure.ico + + + + + + 73 + 22 + 47 + 13 + + + + QMYSQL + + + + + + 163 + 22 + 47 + 13 + + + + QODBC + + + + + + + + + 0 + 0 + + + + + 250 + 390 + + + + + 50 + false + + + + Connect to server + + + false + + + false + + + + + 10 + 175 + 231 + 141 + + + + Authentication + + + + true + + + + 90 + 54 + 131 + 21 + + + + + + + + + + 10 + 24 + 151 + 17 + + + + + 0 + 0 + + + + SQL Server authentication + + + true + + + + + + 10 + 114 + 141 + 17 + + + + + 0 + 0 + + + + Windows authentication + + + false + + + + + true + + + + 90 + 84 + 131 + 20 + + + + + + + QLineEdit::Password + + + + + + 30 + 54 + 51 + 16 + + + + login: + + + + + + 30 + 84 + 61 + 16 + + + + password: + + + lineEdit_login + radio_sql_authentication + radio_windows_authentication + lineEdit_password + label + label_2 + groupBox_sql_drivers + + + + + 88 + 356 + 75 + 23 + + + + Connect + + + true + + + + + + 10 + 115 + 41 + 21 + + + + server: + + + + + + 100 + 115 + 141 + 20 + + + + + + + + + + 100 + 326 + 141 + 20 + + + + + + + + + + 10 + 326 + 81 + 20 + + + + database name: + + + + + + 10 + 145 + 51 + 20 + + + + port: + + + + + + 100 + 145 + 61 + 22 + + + + Default: MySQL 3306; MSSQL 1433 + + + 65535 + + + 0 + + + + + + 10 + 85 + 41 + 21 + + + + driver: + + + + + + 100 + 85 + 141 + 20 + + + + For ODBC/MSSQL: "SQL Server" (Windows), "ODBC Driver 13 for SQL Server", "FreeTDS" (unix), etc. + + + + + + + + + 10 + 20 + 231 + 51 + + + + Engine + + + + + 135 + 20 + 82 + 17 + + + + MSSQL + + + + + + 45 + 20 + 82 + 17 + + + + MySQL + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + false + + + + 0 + 0 + + + + + 300 + 300 + + + + Database browser + + + + + + + 0 + 0 + + + + + 130 + 0 + + + + + 130 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Show + + + true + + + + + + + table: + + + + + + + + + + + + + + + + radio_mysql + radio_mssql + lineEdit_driver + lineEdit_server_address + spinBox_server_port + radio_sql_authentication + lineEdit_login + lineEdit_password + radio_windows_authentication + lineEdit_database_name + button_connect + comboBox_table_name + button_show_table + tableView_database_table + + + + + +