MFCで在庫管理システム作成 4

前回までの記事。

MFCで在庫管理システム作成 3
前回までの記事。メイン画面 コントロール配置さて、メイン画面に必要なコントロールを置いていきます。今回必要なのは、・リストコントロール・カテゴリー用のコンボボックス・編集ボタン・履歴ボタン・コンボボックス用チェックボックス・ログイン情報用ス...

在庫編集画面

作るモノ

前回、編集選択画面を作成しました。

今回は、選択状況に応じて在庫状況を編集します。

必要なコントロールは、
・ラベルスタティックテキスト×6
・商品ID、商品名、単価、在庫数、在庫アラートのエディットボックス
・カテゴリーのコンボボックス

更に少し追加です。
在庫数の箇所にラジオボタンを設置。
入庫なのか、出庫なのか、です。
これは「編集」を押されたときに表示します。

後、在庫推移用のスタティックテキスト。
どんな感じかは下記参照

また、「編集」では商品名、在庫数、在庫アラートは非活性、
「削除」では在庫数も非活性にします。
文字を入力できるのは商品IDだけ。

え、じゃあカテゴリーを変更したいときどうするの?

それは…

新し商品ID新規作成してください。

そういう仕様です( ̄▽ ̄)

ダイアログ作成

ひとまず、いつも通り新しい画面を作ります。

リソースの追加から、新規作成。
新しいダイアログの完成です。

ID名は、IDD_DIALOG_EDIT_MAINに。

コントロールを配置します…。

🍵でも飲みながらゆっくり…

出来上がったのがこんな感じ。

同じ位置に配置しているので隠れてますが、
入庫ラジオボタンの下に「在庫数」ラベルがあります。

商品名以外のエディットボックスは「数字」をTrueにしてます。

コンボボックスは、ドロップダウンリストにして、
後前回やらかした、並べ替えをFalseに。

コードだとこんな感じです。

IDD_DIALOG_EDIT_MAIN DIALOGEX 0, 0, 178, 189
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,30,165,50,14
    PUSHBUTTON      "キャンセル",IDCANCEL,100,165,50,14
    LTEXT           "商品ID",IDC_STATIC_EDITMAIN_PRODUCT_ID,20,20,23,8
    EDITTEXT        IDC_EDIT_EDITMAIN_PRODUCT_ID,60,20,100,14,ES_AUTOHSCROLL | ES_NUMBER
    LTEXT           "商品名",IDC_STATIC_EDITMAIN_PRODUCT_NAME,20,40,22,8
    EDITTEXT        IDC_EDIT_EDITMAIN_PRODUCT_NAME,60,40,100,14,ES_AUTOHSCROLL
    LTEXT           "カテゴリー",IDC_STATIC_EDITMAIN_CATEGORY,20,60,26,8
    COMBOBOX        IDC_COMBO_EDITMAIN_CATEGORY,60,60,100,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
    LTEXT           "単価",IDC_STATIC_EDITMAIN_UP,20,80,15,8
    EDITTEXT        IDC_EDIT_EDITMAIN_UP,60,80,100,14,ES_AUTOHSCROLL | ES_NUMBER
    LTEXT           "在庫数",IDC_STATIC_EDITMAIN_PRODUCT_COUNT,20,100,22,8
    EDITTEXT        IDC_EDIT_EDITMAIN_PRODUCT_COUNT,60,100,100,14,ES_AUTOHSCROLL | ES_NUMBER
    LTEXT           "在庫アラート",IDC_STATIC_EDITMAIN_PRODUCT_ALERT,20,140,36,8
    EDITTEXT        IDC_EDIT_EDITMAIN_PRODUCT_ALERT,60,140,100,14,ES_AUTOHSCROLL | ES_NUMBER
    CONTROL         "入庫",IDC_RADIO_EDITMAIN_NYUKO,"Button",BS_AUTORADIOBUTTON,20,100,30,10
    CONTROL         "出庫",IDC_RADIO_EDITMAIN_SHUKKO,"Button",BS_AUTORADIOBUTTON,20,120,30,10
    LTEXT           "現在XXXXX⇒変更後XXXXX",IDC_STATIC_EDITMAIN_COUNT_TRANSITION,60,120,100,8
END

クラス作成

OKボタンでもダブルクリックして、
クラス作成画面を出します。

クラス名はCEditMain。

これでOK。

一番最初に、クラスビューからCEditMainを選択し、
プロパティのオーバーライドからOnInitDialogを追加します。

後最初に自動で追加しておきたいのは、
OKボタンが押されたときの関数。
これはリソースビューから開いたダイアログで
該当ボタンをダブルクリックするとOnBnClickedOkが出来上がります。

それともう一つ。
「在庫数」エディットボックスをキルフォーカスした際、
在庫推移スタティックテキストを更新したいので、
キルフォーカス処理を入れます。

エディットボックスをダブルクリックしちゃうと、
別の関数が自動で追加されちゃうため、少しひと手間。

在庫数エディットボックスを選択し、
右クリックでイベントハンドラーの追加を選択。

クラスはCEditMain、
メッセージの種類は、「EN_KILLFOCUS」に。

注意すべきは、
デフォルトではクラスが最初CAboutDlgになってますので、
変更を忘れずに。

これでOKを押すと、
キルフォーカス関数が追加されます。

同じことを、商品IDエディットボックスでも実施します。

4つ追加したので、こんな感じになってます。

処理記述

用意ができましたので、処理を書いていきます。

まずはヘッダー。

インクルード

MySQLManager.hをインクルードします。
これも今回はEditMain.hへ。

#pragma once
#include "afxdialogex.h"
#include "MySQLManager.h"

3行目に追加です。

変数追加

コントロールの数が多いので、その分変数も多くなってしまいますが。
ヘッダーに追加します。

後、操作可否を設定する関数も用意。

ひとまず、初期初期表示処理に必要なモノだけ。

class CEditMain : public CDialogEx
{
	// 略

private:
	EditSelectMode m_enMode;	// 選択画面で選択された処理

	CString m_strProductID;		// 商品ID
	CString m_strProductName;	// 商品名
	CString m_strUnitPrice;		// 単価
	CString m_strProductCount;	// 在庫数
	CString m_strProductAlert;	// 在庫アラート

	CEdit m_ctrlEditProductID;		// 商品IDエディットボックス
	CEdit m_ctrlEditProductName;	// 商品名エディットボックス
	CComboBox m_ctrlComboCategory;	// カテゴリーコンボボックス
	CEdit m_ctrlEditUnitPrice;		// 単価エディットボックス
	CEdit m_ctrlEditProductCount;	// 在庫数エディットボックス
	CEdit m_ctrlEditProductAlert;	// 在庫アラートエディットボックス
	CButton m_ctrlRadioNyuko;		// 入庫ラジオボタン
	CButton m_ctrlRadioShukko;		// 出庫ラジオボタン
	CStatic m_ctrlStaticCountLavel;	// 「在庫数」ラベル
	CStatic m_ctrlStaticTransition;	// 在庫推移スタティック

private:
	void ControlOperation();	// 各コントロール制御関数

public:
	void SetEditSelectMode(EditSelectMode enMode) { m_enMode = enMode; }
};

6行目は編集選択画面で選択されたモード、
それを29行目の関数で設定します。

8~12行目はエディットボックスに入るテキスト。
他はコントロールに関する変数です。

26行目の関数をOnInitDialogで呼び、操作制御をかけます。

コンストラクタ

ここからはEditMain.cppに移ります。

コンストラクタで、変数初期化。

CEditMain::CEditMain(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG_EDIT_MAIN, pParent)
{
	m_enMode = enCreate;

	m_strProductID = _T("");
	m_strProductName = _T("");
	m_strUnitPrice = _T("");
	m_strProductCount = _T("");
	m_strProductAlert = _T("");
}

DoDataExchange

コントロールIDと、各変数を紐づけます。

void CEditMain::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);

	DDX_Text(pDX, IDC_EDIT_EDITMAIN_PRODUCT_ID, m_strProductID);
	DDX_Text(pDX, IDC_EDIT_EDITMAIN_PRODUCT_NAME, m_strProductName);
	DDX_Text(pDX, IDC_EDIT_EDITMAIN_UP, m_strUnitPrice);
	DDX_Text(pDX, IDC_EDIT_EDITMAIN_PRODUCT_COUNT, m_strProductCount);
	DDX_Text(pDX, IDC_EDIT_EDITMAIN_PRODUCT_ALERT, m_strProductAlert);

	DDX_Control(pDX, IDC_EDIT_EDITMAIN_PRODUCT_ID, m_ctrlEditProductID);
	DDX_Control(pDX, IDC_EDIT_EDITMAIN_PRODUCT_NAME, m_ctrlEditProductName);
	DDX_Control(pDX, IDC_COMBO_EDITMAIN_CATEGORY, m_ctrlComboCategory);
	DDX_Control(pDX, IDC_EDIT_EDITMAIN_UP, m_ctrlEditUnitPrice);
	DDX_Control(pDX, IDC_EDIT_EDITMAIN_PRODUCT_COUNT, m_ctrlEditProductCount);
	DDX_Control(pDX, IDC_EDIT_EDITMAIN_PRODUCT_ALERT, m_ctrlEditProductAlert);
	DDX_Control(pDX, IDC_RADIO_EDITMAIN_NYUKO, m_ctrlRadioNyuko);
	DDX_Control(pDX, IDC_RADIO_EDITMAIN_SHUKKO, m_ctrlRadioShukko);

	DDX_Control(pDX, IDC_STATIC_EDITMAIN_PRODUCT_COUNT, m_ctrlStaticCountLavel);
	DDX_Control(pDX, IDC_STATIC_EDITMAIN_COUNT_TRANSITION, m_ctrlStaticTransition);
}

OnInitDialog

初期化処理。
これは、関数を呼応するだけです。

BOOL CEditMain::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO: ここに初期化を追加してください
	ControlOperation();

	return TRUE;  // return TRUE unless you set the focus to a control
	// 例外 : OCX プロパティ ページは必ず FALSE を返します。
}

6行目を追加です。

制御関数

ControlOperationの処理を書いていきます。

選択モードにより、操作できるコントロールが違いますね。

/**
 * @fn
 * @brief	各コントロール制御関数
 * @param	なし
 * @return	なし
 */
void CEditMain::ControlOperation()
{
	switch (m_enMode)
	{
	case enCreate:	// 作成の時
		SetWindowText(_T("作成画面"));	// キャプション
		// 作成の場合はラジオボタン、推移テキストは表示しない
		m_ctrlRadioNyuko.ShowWindow(SW_HIDE);		// 入庫ラジオ非表示
		m_ctrlRadioShukko.ShowWindow(SW_HIDE);		// 出庫ラジオ非表示
		m_ctrlStaticTransition.ShowWindow(SW_HIDE);	// 推移スタティック非表示
		m_ctrlStaticCountLavel.ShowWindow(SW_SHOW);	// 在庫ラベル表示
		//そのほかはすべて操作可能
		m_ctrlEditProductID.EnableWindow(TRUE);
		m_ctrlEditProductName.EnableWindow(TRUE);
		m_ctrlComboCategory.EnableWindow(TRUE);
		m_ctrlEditUnitPrice.EnableWindow(TRUE);
		m_ctrlEditProductCount.EnableWindow(TRUE);
		m_ctrlEditProductAlert.EnableWindow(TRUE);
		break;
	case enEdit:	// 編集の時
		SetWindowText(_T("編集画面"));	// キャプション
		// 編集の場合はラジオボタン、推移テキストは表示させる
		m_ctrlRadioNyuko.ShowWindow(SW_SHOW);		// 入庫ラジオ非表示
		m_ctrlRadioShukko.ShowWindow(SW_SHOW);		// 出庫ラジオ非表示
		m_ctrlStaticTransition.ShowWindow(SW_SHOW);	// 推移スタティック非表示
		m_ctrlStaticCountLavel.ShowWindow(SW_HIDE);	// 在庫ラベル非表示
		//IDと在庫数だけ操作可能
		m_ctrlEditProductID.EnableWindow(TRUE);
		m_ctrlEditProductName.EnableWindow(FALSE);
		m_ctrlComboCategory.EnableWindow(FALSE);
		m_ctrlEditUnitPrice.EnableWindow(FALSE);
		m_ctrlEditProductCount.EnableWindow(TRUE);
		m_ctrlEditProductAlert.EnableWindow(FALSE);

		//ラジオボタンは入庫にセット...
		m_ctrlRadioNyuko.SetCheck(BST_CHECKED);
		break;
	case enDelete:	// 削除の時
		SetWindowText(_T("削除画面"));	// キャプション
		// 削除の場合はラジオボタン、推移テキストは表示しない
		m_ctrlRadioNyuko.ShowWindow(SW_HIDE);		// 入庫ラジオ非表示
		m_ctrlRadioShukko.ShowWindow(SW_HIDE);		// 出庫ラジオ非表示
		m_ctrlStaticTransition.ShowWindow(SW_HIDE);	// 推移スタティック非表示
		m_ctrlStaticCountLavel.ShowWindow(SW_SHOW);	// 在庫ラベル表示
		//IDだけ操作可能
		m_ctrlEditProductID.EnableWindow(TRUE);
		m_ctrlEditProductName.EnableWindow(FALSE);
		m_ctrlComboCategory.EnableWindow(FALSE);
		m_ctrlEditUnitPrice.EnableWindow(FALSE);
		m_ctrlEditProductCount.EnableWindow(FALSE);
		m_ctrlEditProductAlert.EnableWindow(FALSE);
		break;
	default:
		// ないけどね
		break;
	}

	UpdateData(FALSE);
}

やってることは、
ShowWindowで表示・非表示の切り替え、
EnableWindowで操作可能・不可能の切り替えだけです。

ダイアログ呼び出し

ひとまずこれを動かしてみます。

最後に、InventoryManagementSystemDlg.cppへ移動します。

ヘッダーをインクルード

//略
#include "MySQLManager.h"	// MySQL使用
#include "EditSelect.h"		// 編集選択画面
#include "EditMain.h"		// 編集画面

4行目のヘッダー追加。

そして前回修正した、
編集ボタンが押されたときの関数を再修正。

/**
 * @fn
 * @brief	編集ボタンが押された
 * @param	なし
 * @return	なし
 */
void CInventoryManagementSystemDlg::OnBnClickedButtonMainEdit()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	BOOL bSelectOK = FALSE;					// 選択画面でOKを押された?
	EditSelectMode enSelectMode= enCreate;	// 選択状態初期化

	CEditSelect dlgEditSelect;
	if (dlgEditSelect.DoModal() == IDOK)
	{
		bSelectOK = TRUE;	// OKが押された
		enSelectMode = dlgEditSelect.enGetSelectMode();	// 向こうのメンバ変数を取ってくる
	}

	if (bSelectOK == TRUE)
	{
		// 編集画面を表示させる
		CEditMain dlgEditMain;
		dlgEditMain.SetEditSelectMode(enSelectMode);	// モードを設定
		dlgEditMain.DoModal();
	}
}

20行目以降を追加です。

選択画面でOKを押されると、
編集ダイアログが表示されます。

ひとまずビルド。

動作確認

一気に紹介。
左から順に、作成、編集、削除、を選択された状態でOKボタンを押してみました。

Windows11になってから、
エディットボックスの非活性ってすごい見にくくなった気がするんですがね。

でもまぁ、やりたい制御はできました。

少し修正

コンボボックスに項目を入れます。

制御関数、少し長くなるので、
分割だけしときます。

そんな大したことしてるわけではないので、
軽く流してもらえれば。

ヘッダーに3種関数追加。

private:
	void ControlOperationCreate();	// 作成画面コントロール制御関数
	void ControlOperationEdit();	// 編集画面コントロール制御関数
	void ControlOperationDelete();	// 削除画面コントロール制御関数

続いてcppに処理修正。

/**
 * @fn
 * @brief	各コントロール制御関数を呼応
 * @param	なし
 * @return	なし
 */
void CEditMain::ControlOperation()
{
	// コンボボックスに項目セット
	CInventoryManagementSystemApp* pApp = static_cast<CInventoryManagementSystemApp*>(AfxGetApp());
	for (int iComboID = 0; iComboID < pApp->iGetCategoryCnt(); iComboID++)
	{
		m_ctrlComboCategory.AddString(pApp->strGetCategory(iComboID));
	}

	switch (m_enMode)
	{
	case enCreate:	// 作成の時
		ControlOperationCreate();
		break;
	case enEdit:	// 編集の時
		ControlOperationEdit();
		break;
	case enDelete:	// 削除の時
		ControlOperationDelete();
		break;
	default:
		// ないけどね
		break;
	}

	UpdateData(FALSE);
}

/**
 * @fn
 * @brief	作成画面コントロール制御関数
 * @param	なし
 * @return	なし
 */
void CEditMain::ControlOperationCreate()
{
	switch (m_enMode)
	{
	case enCreate:	// 作成のみ前に進める
		break;
	default:		// すなわちプログラムミス
		return;
	}

	SetWindowText(_T("作成画面"));	// キャプション

	// 作成の場合はラジオボタン、推移テキストは表示しない
	m_ctrlRadioNyuko.ShowWindow(SW_HIDE);		// 入庫ラジオ非表示
	m_ctrlRadioShukko.ShowWindow(SW_HIDE);		// 出庫ラジオ非表示
	m_ctrlStaticTransition.ShowWindow(SW_HIDE);	// 推移スタティック非表示
	m_ctrlStaticCountLavel.ShowWindow(SW_SHOW);	// 在庫ラベル表示
	//そのほかはすべて操作可能
	m_ctrlEditProductID.EnableWindow(TRUE);
	m_ctrlEditProductName.EnableWindow(TRUE);
	m_ctrlComboCategory.EnableWindow(TRUE);
	m_ctrlEditUnitPrice.EnableWindow(TRUE);
	m_ctrlEditProductCount.EnableWindow(TRUE);
	m_ctrlEditProductAlert.EnableWindow(TRUE);

	//コンボボックスは0番目にセット
	m_ctrlComboCategory.SetCurSel(0);
	// 在庫アラートは、デフォルトで10
	m_strProductAlert = _T("10");
}

/**
 * @fn
 * @brief	編集画面コントロール制御関数
 * @param	なし
 * @return	なし
 */
void CEditMain::ControlOperationEdit()
{
	switch (m_enMode)
	{
	case enEdit:	// 編集のみ前に進める
		break;
	default:		// すなわちプログラムミス
		return;
	}

	SetWindowText(_T("編集画面"));	// キャプション

	// 作成の場合はラジオボタン、推移テキストは表示させる
	m_ctrlRadioNyuko.ShowWindow(SW_SHOW);		// 入庫ラジオ非表示
	m_ctrlRadioShukko.ShowWindow(SW_SHOW);		// 出庫ラジオ非表示
	m_ctrlStaticTransition.ShowWindow(SW_SHOW);	// 推移スタティック非表示
	m_ctrlStaticCountLavel.ShowWindow(SW_HIDE);	// 在庫ラベル非表示
	//IDと在庫数だけ操作可能
	m_ctrlEditProductID.EnableWindow(TRUE);
	m_ctrlEditProductName.EnableWindow(FALSE);
	m_ctrlComboCategory.EnableWindow(FALSE);
	m_ctrlEditUnitPrice.EnableWindow(FALSE);
	m_ctrlEditProductCount.EnableWindow(TRUE);
	m_ctrlEditProductAlert.EnableWindow(FALSE);

	//ラジオボタンは入庫にセット...
	m_ctrlRadioNyuko.SetCheck(BST_CHECKED);
	//コンボボックスは何もセットされていない状態
	m_ctrlComboCategory.SetCurSel(-1);
}

/**
 * @fn
 * @brief	削除画面コントロール制御関数
 * @param	なし
 * @return	なし
 */
void CEditMain::ControlOperationDelete()
{
	switch (m_enMode)
	{
	case enDelete:	// 削除のみ前に進める
		break;
	default:		// すなわちプログラムミス
		return;
	}

	SetWindowText(_T("削除画面"));	// キャプション

	// 作成の場合はラジオボタン、推移テキストは表示しない
	m_ctrlRadioNyuko.ShowWindow(SW_HIDE);		// 入庫ラジオ非表示
	m_ctrlRadioShukko.ShowWindow(SW_HIDE);		// 出庫ラジオ非表示
	m_ctrlStaticTransition.ShowWindow(SW_HIDE);	// 推移スタティック非表示
	m_ctrlStaticCountLavel.ShowWindow(SW_SHOW);	// 在庫ラベル表示
	//IDだけ操作可能
	m_ctrlEditProductID.EnableWindow(TRUE);
	m_ctrlEditProductName.EnableWindow(FALSE);
	m_ctrlComboCategory.EnableWindow(FALSE);
	m_ctrlEditUnitPrice.EnableWindow(FALSE);
	m_ctrlEditProductCount.EnableWindow(FALSE);
	m_ctrlEditProductAlert.EnableWindow(FALSE);

	//コンボボックスは何もセットされていない状態
	m_ctrlComboCategory.SetCurSel(-1);
}

SQL処理作成 (作成画面)

まずは作成時の処理。

チェック処理

OKボタンを押されたとき、少々チェックを行います。
・項目が全部埋まっているか
・IDは5桁か
・在庫数は1以上か
・在庫数が在庫アラートより下回る場合、メッセージを出す

この4種くらいです。
1、2番目は作成・編集・削除共通ですが、
3、4番目は作成のみチェックしたいので、そこだけ分岐を入れます。

EditMain.hに関数定義。

private:
	BOOL bInutCheck();				// 入力チェック

EditMain.cppに処理を書きます。

/**
 * @fn
 * @brief	入力チェック
 * @param	なし
 * @return	なし
 */
BOOL CEditMain::bInutCheck()
{
	// メンバ変数更新
	UpdateData(TRUE);

	if (m_strProductID == _T("") || m_strProductName == _T("") || m_strUnitPrice == _T("") || m_strProductCount == _T("") || m_strProductAlert == _T(""))
	{
		AfxMessageBox(_T("未入力項目があります。"), MB_ICONERROR);
		return FALSE;
	}

	if (m_strProductID.GetLength() != 5)
	{
		AfxMessageBox(_T("Idが5桁ではありません。"), MB_ICONERROR);
		return FALSE;
	}

	if (m_enMode == enCreate)
	{
		if (_ttoi(m_strProductCount) < 1)
		{
			AfxMessageBox(_T("在庫数は1以上入力してください。"), MB_ICONERROR);
			return FALSE;
		}

		if (_ttoi(m_strProductCount) <= _ttoi(m_strProductAlert))
		{
			CString strMessage = _T("在庫数が在庫アラートよりも下回ります。\r\nよろしいですか?");
			int iResponse = AfxMessageBox(strMessage, MB_YESNO | MB_ICONQUESTION);
			if (iResponse == IDNO)
			{
				//「いいえ」が押された
				return FALSE;
			}
		}
	}

	return TRUE;
}

_ttoi(CString型文字列)で、int型に変更できます。

SQL作成

MySQLManager.hに移り、関数定義を行います。
どうせ後で色々つけ足すので、今のうち併せて一気に。

public:
	// 商品テーブル 作成
	BOOL bProductTableCreate(CString strProductID, CString strProductName, CString strCategory, 
								CString strUnitPrice, CString strProductCount, CString strProductAlert);

	// 商品テーブル 編集
	BOOL bProductTableEdit(CString strProductID, CString strProductCount, BOOL bNyuko);

	// 商品テーブル 削除
	BOOL bProductTableDelete(CString strProductID);

	// 履歴テーブル更新
	BOOL bLogTableInsert(CString strProductID, CString strOperation);

今回作成するのはbProductTableCreate、
そして履歴テーブルも操作するのでLogTableInsertも。

MySQLManager.cppを開き、処理を書きます。

/**
 * @fn
 * @brief	商品テーブル 作成関数
 * @param	CString         strProductID    商品ID
 * @param   CString         strProductName  商品名
 * @param   CString         strCategory     カテゴリー
 * @param   CString         strUnitPrice    単価
 * @param   CString         strProductCount 商品在庫数
 * @param   CString         strProductAlert 在庫アラート
 * @return	BOOL    TRUE    登録成功
 *                  FALSE   登録失敗
 */
BOOL CMySQLManager::bProductTableCreate(CString strProductID, CString strProductName, CString strCategory,
                                        CString strUnitPrice, CString strProductCount, CString strProductAlert)
{
    try
    {
        // スキーマセット
        m_con->setSchema(SCHEMA);

        sql::SQLString sqlStrId = strConverter(strProductID);
        sql::SQLString sqlStrName = strConverter(strProductName);
        sql::SQLString sqlStrCategory = strConverter(strCategory);
        sql::SQLString sqlStrUP = strConverter(strUnitPrice);
        sql::SQLString sqlStrCount = strConverter(strProductCount);
        sql::SQLString sqlStrAlert = strConverter(strProductAlert);

        // 既に存在するIDじゃないかチェック
        sql::SQLString strSqlQuery = "SELECT * FROM " + TABLE_PRODUCT + " WHERE " + COL_PRODUCT_ID + " = '" + sqlStrId + "'";
        // SELECT * FROM product WHERE product_id = '番号'

        //クエリ実行
        std::unique_ptr<sql::PreparedStatement> pstmtSearch(m_con->prepareStatement(strSqlQuery));
        std::unique_ptr<sql::ResultSet> res(pstmtSearch->executeQuery());

        if (res->next())
        {
            // 存在しちゃった
            AfxMessageBox(_T("このIDは既に使用されています。"), MB_ICONERROR);
            return FALSE;
        }

        //INSERT文を作る
        strSqlQuery = 
            "INSERT INTO " + TABLE_PRODUCT +
            " ( " + COL_PRODUCT_ID + ", " + COL_PRODUCT_NAME + ", " + COL_PRODUCT_CATEGORY + ", " + COL_PRODUCT_UP + ", " + COL_PRODUCT_COUNT + ", " + COL_PRODUCT_ALERT + ")" +
            " VALUES " +
            "( '" + sqlStrId + "', '" + sqlStrName + "', '" + sqlStrCategory + "', " + sqlStrUP + ", " + sqlStrCount + ", " + sqlStrAlert + " )";

        //クエリ実行
        std::unique_ptr<sql::PreparedStatement> pstmt(m_con->prepareStatement(strSqlQuery));
        pstmt->executeUpdate();

        // ここまで処理が来たら、登録成功している
        // 履歴テーブル登録


    }
    catch (sql::SQLException& e)
    {
        ErrSQLException(e);
        return FALSE;
    }

    return TRUE;
}

29~41行目、IDが存在しないかチェックです。

存在していなければ、INSERT処理発動。

56行目以降に履歴テーブル登録関数を作りますが、ひとまず後回し。

SQL関数呼応

EditMain.cppに戻って、先の関数を呼びます。

OKボタンが押されたタイミングで、
まずはチェック処理を走らせ、
合格したらSQLを実行。

/**
 * @fn
 * @brief	OKボタンが押されると呼応される
 * @param	なし
 * @return	なし
 */
void CEditMain::OnBnClickedOk()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	if (bInutCheck() == TRUE)
	{
		CString strCategory = _T("");
		GetDlgItemText(IDC_COMBO_EDITMAIN_CATEGORY, strCategory);	// カテゴリーにセットされている文字列取得

		CMySQLManager Manager;
		Manager.GetConnection();
		if (m_enMode == enCreate)
		{
			// 作成
			if (Manager.bProductTableCreate(m_strProductID, m_strProductName, strCategory, m_strUnitPrice, m_strProductCount, m_strProductAlert))
			{
				CDialogEx::OnOK();
			}
			else
			{
				// 失敗した
				return;
			}
			
		}
		
	}
	
}

ひとまず、「作成」だけ。
13行目で、カテゴリーを取得できます。

動作確認

一度ビルド。

まずは、エラーチェックの確認。

今更ですが、
商品名は半角文字でお願いします。

実は全角で打つと文字化けするの、
直ってないんですよねー。
修正関数(方法)考えなければ。

4種まとめて。

縦長とはいえ、横に4つ画像並べるのやめた方がいいか…。

エラーチェックはちゃんと働いていました。

さぁ、いよいよINSERT。

こんな条件で登録します。

OKを押すと。

エラーがなくメイン画面に戻りました。

テーブルを見て見ます。

よぅし!
できてます( ´∀`)b

毎度SQL処理書くとき、
当然気を付けてはいるのですが、基本syntaxエラーが起こるんですよね。
で、ちまちま直しながら仕上げる、と。

今回1発でクリアできました(∩´∀`)∩
しかもSELECTとINSERT2つも書いたのに。

最後の確認。

この状態で、もう一度ID=11111で登録するとどうなるか。

こっちのチェックも大丈夫でした。

終わりに

今回は編集画面を作成し、
商品テーブルへ登録を行いました。

中途半端ですが、今回はここまで。

次回は履歴テーブル登録、編集&削除処理追加します。

画面作成はしないかな。

あのタスクが入ると
それだけで結構分量取っちゃう。

MFCで在庫管理システム作成 5
前回までの記事。テーブル変更今回、履歴テーブルにデータを追加する処理を追加するのですが、ここで1点。履歴テーブルに列を増やします。履歴で、どれだけの数が増減して操作後は在庫数いくらになるか、という情報を表示したいためです。設計甘々なので、ご...

コメント

タイトルとURLをコピーしました