QtでMySQL

# はじめに
ちょっと興味を持ちましたので、QtからMySQLに接続し、Tableへのレコード追加/修正/削除をしてみました。
不備もあると思いますが、不備がありましたら、コメントしていただけると嬉しいです。
今回はmainwindow.uiも付加します。(コピペでOK)

本来なら、OpenCVのEdge処理を投稿しようと思いましたが、実装ボリュームが大きくなりそうなので、MySQLを先に投稿させていただきました。
# 環境
## 開発PC
Ubuntu22.04
## MySQL(別のPCにインストール済み)
Basix6.0(Ubuntu22.04)
[こちら](http://simosnet.com/livecd/basix/)
からDLできます。
Basix6.0のインストールやMySQLのインストールは割愛させていただきます。
要望が多ければ、別記事で投稿したいと思います。
と言ってもググれば、いっぱい出てくると思います。
Ubuntu18.04では「apt」コマンドでインストールするとMySQL5系がインストールされてましたが、20.04以降はMySQL8系がインストールされるようです。
20.04でもMySQL5系をインストールすることもできます。
22.04でMySQL5系をインストールすることはまだ試しておりません。
# 仕様
接続用のPushButton
新規用のPushButton
修正用のPushButton
削除用のPushButton
とします。
接続前は、新規、修正、削除のPushButtonはDisableにします。
接続後は、上記をEnableして、接続のPushButtonをDisableにします。
# MySQL関係
## DB名称
qtSampleDb
## Table名称
testTable
## Field詳細
|field|type|
|:---|:---|
|id|int|
|userName|varchar(10)|
# ライブラリ
QtでMySQLを使用できるようにするために、下記を実行してください。
```install command.
sudo apt-get install libqt5sql5-mysql
```
# UI
仕様を基に配置します。(結構適当です)
![Screenshot from 2022-12-20 16-32-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1473918/c484ded6-a134-640e-2d31-87969fae2ee6.png)
※下のほうにある「mainwindow.ui」をコピペしてください。
# イベント
「接続」、「新規」、「修正」、「削除」のイベントを発生させます。
※新規の時に、同じレコードがあるかとか等のチェックはしておりません
# 実装
```mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
// 追加(ここから)
#include <QMessageBox>
#include <QtSql>
#include <QtSql/QSql>
#include <QtSql/QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
// 追加(ここまで)

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pbConnect_clicked();
    void on_pbAdd_clicked();
    void on_pbRep_clicked();
    void on_pbDel_clicked();

private:
    Ui::MainWindow *ui;

// 追加(ここから)
private:
	QSqlDatabase db;
	bool mysqlConnect;
// 追加(ここまで)
};
#endif // MAINWINDOW_H
```
```mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

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

	// 追加(ここから)
	mysqlConnect = false;
	ui->pbAdd->setEnabled(false);					// 接続前はDisable
	ui->pbRep->setEnabled(false);					// 接続前はDisable
	ui->pbDel->setEnabled(false);					// 接続前はDisable
	// 追加(ここまで)
}

MainWindow::~MainWindow()
{
	// 追加(ここから)
	if(mysqlConnect){
		db.close();
	}
	// 追加(ここまで)
	delete ui;
}

void MainWindow::on_pbConnect_clicked()
{
	// 追加(ここから)
	db = QSqlDatabase::addDatabase("QMYSQL");		// MySQLでは、「QMYSQL」と設定
	db.setHostName("xxx.xxx.xxx.xxx");				// 実際の接続するMySQLのIPアドレス
	db.setDatabaseName("qtSampleDb");
	db.setUserName("xxxx");							// 実際のユーザ名
	db.setPassword("xxxx");							// 実際のパスワード
	db.setPort(3306);								// デフォルトでは3306
	if(db.open()){
		mysqlConnect = true;
		ui->pbConnect->setEnabled(false);			// 接続後はDisable
		ui->pbAdd->setEnabled(true);				// 接続後はEnable
		ui->pbRep->setEnabled(true);				// 接続後はEnable
		ui->pbDel->setEnabled(true);				// 接続後はEnable
	} else {
		QMessageBox msgBox(this);
		msgBox.setText(tr("データベースに接続ができませんでした。"));	// メッセージ
		msgBox.setWindowTitle(tr("エラー"));		// タイトル
		msgBox.setStandardButtons(QMessageBox::Yes);// ボタン
		msgBox.setDefaultButton(QMessageBox::Yes);	// デフォルトボタン
		msgBox.setIcon(QMessageBox::Warning);		// アイコン
		msgBox.exec();								// 表示
		exit(0);
	}
	// 追加(ここまで)
}

void MainWindow::on_pbAdd_clicked()
{
	// 追加(ここから)
	QMessageBox msgBox(this);
	QSqlQuery query;

	if(query.prepare("INSERT INTO testTable (id, userName) VALUES (:id, :userName)")){
		query.bindValue(":id", 1);
		query.bindValue(":userName", "MysqlUser");
		if(query.exec()){
			msgBox.setText(tr("登録しました。"));
			msgBox.setWindowTitle(tr("info"));
			msgBox.setStandardButtons(QMessageBox::Yes);
			msgBox.setDefaultButton(QMessageBox::Yes);
			msgBox.setIcon(QMessageBox::Information);
			msgBox.exec();
		} else {
			msgBox.setText(tr("登録できませんでした。"));
			msgBox.setWindowTitle(tr("error"));
			msgBox.setStandardButtons(QMessageBox::Yes);
			msgBox.setDefaultButton(QMessageBox::Yes);
			msgBox.setIcon(QMessageBox::Warning);
			msgBox.exec();
		}
	}
	// 追加(ここまで)
}

void MainWindow::on_pbRep_clicked()
{
	// 追加(ここから)
	QMessageBox msgBox(this);
	QSqlQuery query;

	if(query.prepare("UPDATE testTable SET userName=:userName WHERE id=:id")){
		query.bindValue(":userName", "UserMySQL");
		query.bindValue(":id", 1);
		if(query.exec()){
			msgBox.setText(tr("修正しました。"));
			msgBox.setWindowTitle(tr("info"));
			msgBox.setStandardButtons(QMessageBox::Yes);
			msgBox.setDefaultButton(QMessageBox::Yes);
			msgBox.setIcon(QMessageBox::Information);
			msgBox.exec();
		} else {
			msgBox.setText(tr("修正できませんでした。"));
			msgBox.setWindowTitle(tr("error"));
			msgBox.setStandardButtons(QMessageBox::Yes);
			msgBox.setDefaultButton(QMessageBox::Yes);
			msgBox.setIcon(QMessageBox::Warning);
			msgBox.exec();
		}
	}
	// 追加(ここまで)
}

void MainWindow::on_pbDel_clicked()
{
	// 追加(ここから)
	QMessageBox msgBox(this);
	QSqlQuery query;

	if(query.prepare("DELETE FROM testTable WHERE id=:id")){
		query.bindValue(":id", 1);
		if(query.exec()){
			msgBox.setText(tr("削除しました。"));
			msgBox.setWindowTitle(tr("info"));
			msgBox.setStandardButtons(QMessageBox::Yes);
			msgBox.setDefaultButton(QMessageBox::Yes);
			msgBox.setIcon(QMessageBox::Information);
			msgBox.exec();
		} else {
			msgBox.setText(tr("削除できませんでした。"));
			msgBox.setWindowTitle(tr("error"));
			msgBox.setStandardButtons(QMessageBox::Yes);
			msgBox.setDefaultButton(QMessageBox::Yes);
			msgBox.setIcon(QMessageBox::Warning);
			msgBox.exec();
		}
	}
	// 追加(ここまで)
}
```
```mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="pbConnect">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>30</y>
      <width>80</width>
      <height>26</height>
     </rect>
    </property>
    <property name="text">
     <string>接続</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pbAdd">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>70</y>
      <width>80</width>
      <height>26</height>
     </rect>
    </property>
    <property name="text">
     <string>新規</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pbRep">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>110</y>
      <width>80</width>
      <height>26</height>
     </rect>
    </property>
    <property name="text">
     <string>修正</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pbDel">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>150</y>
      <width>80</width>
      <height>26</height>
     </rect>
    </property>
    <property name="text">
     <string>削除</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
```
```修正前.pro
QT       += core gui
```
```修正後.pro
QT       += core gui sql
```
# MySQLの確認
下記のDB/Table/Fieldとします。
```databaseの一覧.
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| qtSampleDb         |(ターゲットデータベース)
| sys                |
+--------------------+
5 rows in set (0.10 sec)
```
```tableの一覧.
mysql> show tables;
+----------------------+
| Tables_in_qtSampleDb |
+----------------------+
| testTable            |(ターゲットテーブル)
+----------------------+
1 row in set (0.00 sec)
```
```Field詳細.
mysql> DESC testTable;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int         | NO   | PRI | NULL    |       |
| userName | varchar(10) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
```
```tableの中身.
mysql> select * from testTable;
Empty set (0.01 sec)
```
テーブルには何も登録されておりません。
# build&run
実装が完了しましたら、▶をクリックして、build & run します。
## 起動初期後
仕様通り「新規」「修正」「削除」のPushButtonがDisableになっています。
![Screenshot from 2022-12-21 08-46-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1473918/942242bf-dbc6-74b4-0940-b814ae0a75c3.png)
## 接続
「接続」をクリックしました。
「接続」のPushButtonががDisableになり、「新規」「修正」「削除」のPushButtonがEnableになりました。これも仕様通りですね。
![Screenshot from 2022-12-21 08-51-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1473918/7ed9a933-c3e1-9775-9afd-90907ae5cae4.png)
## 新規
「新規」をクリックしました。
![Screenshot from 2022-12-21 08-55-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1473918/a8e9d910-9a55-0274-6dcd-852e2aba4d78.png)
とダイアログが表示しました。
テーブルに登録されているか確認します。
```tableの中身.
mysql> select * from testTable;
+----+-----------+
| id | userName  |
+----+-----------+
|  1 | MysqlUser |
+----+-----------+
1 row in set (0.00 sec)
```
プログラム中に固定ですが、設定した内容が追加させております。
## 修正
「修正」をクリックしました。
![Screenshot from 2022-12-21 08-59-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1473918/97b9a7b0-443e-a90d-f7f4-b6e69e9eab19.png)
とダイアログが表示しました。内容が修正されているか確認します。
```tableの中身.
mysql> select * from testTable;
+----+-----------+
| id | userName  |
+----+-----------+
|  1 | UserMySQL |
+----+-----------+
1 row in set (0.00 sec)
```
プログラム中に固定ですが、設定した内容が登録させております。
## 削除
「削除」をクリックしました。
![Screenshot from 2022-12-21 09-02-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1473918/d14878d0-9409-7f66-da77-634b5a1d97f5.png)
とダイアログが表示しました。テーブルから削除されているか確認します。
```tableの中身.
mysql> select * from testTable;
Empty set (0.00 sec)
```
はい。削除されました。

# まとめ
SQL文は同じMySQLですので、言語、開発OSが異なってもほぼ同じです。
今までは、VisualStudioのVB.netでMySQLへアクセスする実装ばかりで、QtでC++での実装は初めてですが簡単ではありますが実装できました。