前回までの話。
管理リスト画面作成
今回はユーザ情報に関する処理を。
ユーザ関連は今回と次回の2回で終了です。
まず、メイン画面を開いてユーザ情報管理画面を押したときに出るダイアログを作ります。
リソースビューのDialogを右クリック→リソースの追加→新規作成です。

ダイアログが新しく作成されるので、
ダイアログIDをIDD_DIALOG_USER_MANAGEにでもしておきます。
今回必要なのは、上部にユーザ情報変更ボタンと、真ん中にリストコントロールです。
デフォルトで存在するOKボタンは今回必要ないので削除します。
キャンセルボタンは戻るボタンとして活用します。

メイン画面作成でも述べましたが、
リストコントロールはプロパティから、ビューをレポートにしておきます。
画像のコントロールIDや配置は以下のようになっています。
IDD_DIALOG_USER_MANAGE DIALOGEX 0, 0, 230, 160
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "戻る",IDCANCEL,160,130,50,14
PUSHBUTTON "ユーザ情報変更",IDC_BUTTON_USERMG_CHG,20,15,50,14
CONTROL "",IDC_LIST_USER,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,20,35,190,90
END続いてクラスやファイルを作成。
なんでもいいのでコントロールをダブルクリック。
今回はこんな感じ。

OKを押すと、hファイルとcppファイルが追加されます。
まずログインダイアログでもしたように、
クラスビューを開いて(Ctrl + Shift + C)、CUserManageを選択。
プロパティからオーバーライドを選択し、
OnInitDialogをAddします。
次に、UserManage.hに、
リストコントロールのメンバ変数とリスト表示関数を用意。
private:
CListCtrl m_listUser; // リストコントロール
private:
void ListUpdate(); // リスト再表示関数
public:
CListCtrl* GetList() { return &m_listUser; } // リストコントロールゲット関数今度はUserManage.cppを開きます。
最初に、MySQLManager.hをインクルード。
#include "MySQLManager.h"DoDataExchange内と、先ほど追加したOnInitDialog内を少し加えます。
void CUserManage::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST_USER, m_listUser);
}
BOOL CUserManage::OnInitDialog()
{
CDialogEx::OnInitDialog();
// TODO: ここに初期化を追加してください
m_listUser.InsertColumn(0, _T("ユーザID"), LVCFMT_LEFT, 100);
m_listUser.InsertColumn(1, _T("ユーザ名"), LVCFMT_LEFT, 200);
m_listUser.InsertColumn(2, _T("ユーザ権限"), LVCFMT_LEFT, 100);
ListUpdate(); //リスト表示
SetWindowText(_T("ユーザリスト"));
return TRUE; // return TRUE unless you set the focus to a control
// 例外 : OCX プロパティ ページは必ず FALSE を返します。
}ListUpdate関数を定義していきます。
/**
* @fn
* @brief ユーザリスト表示関数
* @param なし
* @return TRUE リスト作成成功
* FALSE リスト作成失敗
*/
void CUserManage::ListUpdate()
{
CMySQLManager UserManage;
UserManage.GetConnection(); //接続確立
if (UserManage.bGetUserList(GetList()) == TRUE) // ユーザテーブルからリストをゲット。
{
UpdateData(FALSE);
}
else
{
AfxMessageBox(_T("ユーザリスト取得時にエラーが生じました。"));
}
}今回先走ってますが、
13行目、こんな関数はまだ用意していないので当然エラーが出てきます。
最後に、このダイアログを呼び出すため、
IDD_SUPPLYREQUESTMANAGER_DIALOGから
「ユーザ情報管理」ボタンをダブルクリックし、関数を追加します。
SupplyRequestManagerDlg.cppに、ボタン押下時に呼ばれるの関数が出来上がるので
処理を書きます。
void CSupplyRequestManagerDlg::OnBnClickedButtonMainUserlist()
{
// TODO: ここにコントロール通知ハンドラー コードを追加します。
CUserManage dlgUserManage;
dlgUserManage.DoModal();
}当然このままだとエラーになるので、
#include "UserManage.h"も忘れずに。
ユーザリスト取得
MySQLManager.hを開きます。
まず先ほどの関数を定義。
public:
//ユーザリスト取得
BOOL bGetUserList(CListCtrl* list);MySQLManager.cppに、具体的な処理を書きます。
/**
* @fn
* @brief ユーザリスト取得関数
* @param CString strId ログインID
* CString strPassword ログインパスワード
* @return TRUE 取得成功
* FALSE 取得失敗
*/
BOOL CMySQLManager::bGetUserList(CListCtrl* list)
{
try
{
m_con->setSchema(SCHEMA); // スキーマ選択
sql::SQLString strSqlQuery = "SELECT * FROM " + TABLE_USER; //全選択
// クエリを実行
std::unique_ptr<sql::PreparedStatement> pstmt(m_con->prepareStatement(strSqlQuery));
std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
if (res != nullptr && res->next())
{
int iRow = 0; //行番号
do
{
LVITEM lvItem{};
lvItem.mask = LVIF_TEXT;
lvItem.iItem = iRow;
//ID列
lvItem.iSubItem = 0;
lvItem.pszText = strConvertFromUTF8ToUTF16(res->getString("Id")).GetBuffer();
list->InsertItem(&lvItem);
//Name列
lvItem.iSubItem = 1;
lvItem.pszText = strConvertFromUTF8ToUTF16(res->getString("Name")).GetBuffer();
list->SetItem(&lvItem);
//Authority列
lvItem.iSubItem = 2;
lvItem.pszText = strConvertFromUTF8ToUTF16(res->getString("Authority")).GetBuffer();
list->SetItem(&lvItem);
iRow++;
} while (res->next());
}
else
{
AfxMessageBox(_T("ユーザテーブルに何も登録されていません。"));
return FALSE;
}
}
catch (sql::SQLException& e)
{
// 実行できなかった
ErrSQLException(e);
return FALSE;
}
return TRUE;
}20行目までは今までもやっていることです。
CListCtrlに行を追加するため、LVITEMを使用します。
以下のサイトが参考になりました。
ちょいちょい登場するstrConvertFromUTF8ToUTF16は、
前々回作成した型変換関数です。
これで一度ビルドし、管理者ユーザでログインし、ユーザ情報管理ボタンを押下します。

IDは5桁になってしまいますね。
こんなことならvarcharで定義しておけばよかったと今更公開です(;´・ω・)
問題発生
IDが5桁にならないのはそれはそれで問題ですが、
0補完すればいいだけの話です。
これとは別に問題が発生しています。
実はこの処理、
ユーザリストダイアログを表示させるたびに表示内容が違います。
こんな感じ


ユーザを増やすとさらに大変。


処理に何か所かエラーメッセージボックスを出す処理を書いていますが、
そこには通っていないんですよね。
一応自分の考えとしては
- CListCtrlのポインタを引数に渡していることが駄目。
ハッシュテーブルとかを引数にし、取得後のテーブルからリストを作る。 - 処理が速すぎて列情報の取得が間に合っていない。
ユーザ名が□になるのは、多分中途半端なバイトデータが入っているため。
の、どちらかだとは考えているのですが、
どうも解決策が思い浮かびませんでした。
Sleepで一定時間処理を止めてもみましたが、変わらず(´・ω・)
自分は限界だったので、これはこのまま進めます。
もし真似するようなことがあれば、皆さんこれよりもいい処理を書いてください。
くそーDebugモードで作りてぇ…
0補完
0補完処理だけ作って終わりにします。
先ほどのbGetUserList関数の31~34行目を以下のように変えます。
//ID列
lvItem.iSubItem = 0;
CString strIdTemp = strConvertFromUTF8ToUTF16(res->getString("Id"));
while (strIdTemp.GetLength() < 5)
{
strIdTemp = _T("0") + strIdTemp; // 5桁未満は先頭に0を
}
lvItem.pszText = strIdTemp.GetBuffer(); //ID列取得
list->InsertItem(&lvItem);これでちゃんと補完ができました。

えぇ、全部が表示されるまで何度もこのダイアログを開いたり閉じたりしてます。
そこを除けば問題ないんだけどなぁ。
終わりに
ユーザテーブルからユーザリストを作成しました。
リストを作る際、
各所にAfxMessageBoxでメッセージ出して処理を一時中断させると、
問題なく全部表示できるので、
やっぱり処理が追い付いていない気もするけどなぁ。
自分はよく、バッチ起動させるときにCreateProcessを使って、
バッチ処理が終わるまでC++側の処理を進めない、という方法を使いますが、
これと似たようなことできないか…?
難しいです。
次回はユーザテーブル情報を変更するダイアログと処理の作成を。
今回はここまで。

コメント