Version 5.19
ファイル読み込みをブラッシュアップ!
「前回までで、ファイル入出力は、どんなライブラリを使ってても結局は
API を使っている、ってことが分かったと思います」
『うん、かなり分かった。ライブラリは謎な存在じゃないってことよね』
「そゆこと。では話を戻しましょう。ファイル入出力は結局は iostream を
使うのが一番楽」
『確かにね、なんだっけ、書式化って言うんだっけ、数字を文字列に変換し
たりとかしてくれるし、閉じるのも自動的だし』
「というわけで、 Ver 5.10 ( No.075 ) の最後に作ったのがこれ」
void CFileTestDlg::OnBtnShow()
{
int i;
std::ifstream cIFStrm;
cIFStrm.open( "Data.txt" );
if( cIFStrm.fail() )
{
TRACE( "ファイルがない!\n" );
return;
}
while( !cIFStrm.eof() )
{
cIFStrm
>> i;
if( cIFStrm.fail() )
{
TRACE( "整数値じゃないです\n" );
return;
}
char chDest[256];
sprintf( chDest, "%d", i );
m_cDataLstBox.AddString( chDest );
}
}
『これずっととっといたんだもんね』
「で、今回はこれをブラッシュアップします」
『ブラッシュアップって、無駄なとこ取り除いてもっと良くするんだよね。
でもそんな悪いとこある?』
「あるよー。とりあえず実行して、【表示】ボタンを2度押してみて」
『ほいほい。あら、最初のが消えてない』
「 CListBox::AddString() は単に追加するだけだから、前のが残ってるん
だよね」
『あと表示が 100 100 200 200 300 300 ってなってる』
「あー、ソートされてるんだね」
『ソート?』
「フォルダとかは〈名前順〉とかで並べられるでしょ。ああいうふうに並べ
ることを〈ソート〉って言います」
『ほほう。これってソートしない方がいいよね』
「そうだね、ファイルの中身そのまま表示するって仕様にしようか」
『……しゃれ?』
「リソースエディタでダイアログ開いて」
『無視かい。 IDD_FILETEST_DIALOG をダブルクリックっと』
「リストボックスのプロパティを変更して」
『右クリックから【プロパティ】っと』
「【スタイル】のページに」
『【ソート】があった! このチェックを外せばいいんだね』
「そ。……ソートがデフォルトなんだな」
『実行して【表示】を2回、今度は 100 200 300 100 200 300 だね』
「次は2重表示しないようにしましょう。どうすればいいと思う?」
『追加する前にリストボックスの中身、空にしちゃえばいいんじゃない?』
「当たり。そんじゃやってみて」
『げげ! えーっと、リストボックスの操作は m_cDataLstBox のメンバ関
数使えばいいんだよね、 AddString() だってそうなんだから』
「そうそう」
『じゃ、 MSDN で……』
「 m_cDataLstBox は CListBox クラスの変数」
『そうそう、 CListBox クラスメンバを表示して…… ResetContent() と見
た!』
「じゃあ使ってみましょう」
『んーと、追加する前に空にするんだから……最初で呼び出してみようかな。
m_cDataLstBox. ってやって、んでこのメンバ関数の ResetContent っと』
「そして?」
『引数はなし、戻り値なし、だから』
m_cDataLstBox.ResetContent();
『って感じかな。ビルドして実行、【表示】x2、よし2重表示されない!』
「OK! MFC の基本的な使い方は大丈夫みたいだね」
『まかせてよーん』
「さて次。この部分をなんとかしましょう」
TRACE( "ファイルがない!\n" );
『エラー処理の部分だね』
「 TRACE() は Visual C++ のアウトプットウィンドウに表示するだけだか
ら、これは製品じゃ使えないよね」
『つまり〈ファイルがありません〉って……たとえばダイアログとかで?』
「そうだね、やっぱりダイアログで伝えるのが一番楽かな。ダイアログを表
示するにはどうすればいい?」
『なんかメンバ関数使うんだよね……あ、 MessageBox() だ!』
「昔何度も使ったね」
『昔って……』
「とりあえずこの TRACE() を置き換えてみて」
『ほーい。 MSDN で……あれ、どれを選べばいいんだっけ』
「 OnBtnShow() は CFileTestDlg クラスのメンバ関数。 CFileTestDlg の
親クラスは?」
『 CDialog 、だよね。 FileTestDlg.h にそう書いてあるもん。あ、それで
CDialog は CWnd から継承してるから、 CWnd のメンバ関数は全部使えるん
だよね』
「そういうこと。だから CWnd::MessageBox() を使えばいいわけ」
『そゆことね。 MSDN のを見ると、第1引数がその文章だよね、第2引数は
キャプション、ってことはタイトルで、第3引数がアイコンだよね』
「ってゆーか Ver 2.11 ( No.022 ) で使ってるんだから」
『そっか、それ見つつ書くと……』
MessageBox
( "ファイルが見つかりませんでした。"
, "ファイルがありません"
, MB_OK | MB_ICONEXCLAMATION );
『って感じかな。ビルドして実行して【表示】ボタン! ……あれ?』
「ファイル名間違えさせないと」
『そだ。閉じて、 "Data.txt" を "_Data.txt" にして同じよーに【表示】
ボタン! うおダイアログ出た!』
「では次の段階。 " " で囲まれた文字列は直接プログラム上に書いちゃダ
メって言ったの憶えてる?」
『なんとなーく』
「そこで〈ストリングテーブル〉を使います。 Ver 3.16 ( No.041 ) を読
み返して」
『そっか、プログラムに直接書くと見つけにくいとかいろいろ問題あるんだ
ね。えーっと、ストリングテーブルはリソースの String Table ね』
「空欄をダブルクリックして新しく追加して」
『 ID とかどーすんの?』
「 ID は IDS_E_NOFILE=201 、キャプションはもちろん〈ファイルが見つか
りませんでした。〉」
『 IDS_E_NOFILE=201 って?』
「 IDS_E_NOFILE が ID の名前」
『 S は String で E は Error ね』
「で、リソース ID は基本的に単なる整数値。あ、これは見た方が早いか。
resource.h ってファイルを開いてみて」
『メニューの【開く】でっと……あ!』
#define IDM_ABOUTBOX 0x0010
『この #define って定数作るときに使うのだ!』
「そ、 Ver 4.09 ( No.059 ) でやったね。こんなふうに、 ID は全部定数」
『あ、 IDS_E_NOFILE=201 って〈この ID は 201 って定数に〉って設定し
てるんだ』
「そゆこと。 Ver 3.14 ( No.039 ) でもやってるから見てみて」
『んでリソース作って、そしたら CString::LoadString() ってメンバ関数
で読み込むんだね』
「そういうこと。このメンバ関数に ID を渡せばいいわけだから?」
『こんな感じかな』
CString cStr;
cStr.LoadString( IDS_E_NOFILE );
『あう、でも cStr をどう MessageBox() に渡せばいいの?』
「あ、これはそのまま渡しちゃってOK」
MessageBox
( cStr
, "ファイルがありません"
, MB_OK | MB_ICONEXCLAMATION );
『えええっ!?』
「これは近いうちにちゃんとした方がいいかもね。簡単に説明すると、
CString は LPCTSTR にはそのまま渡せるような仕組みになってるから」
『あ、その言い回しは〈クラスの機能〉ってヤツ?』
「そゆこと。 CString はクラスだからそういう便利な機能が付いてるわけ。
んじゃタイトルの方もリソースにしちゃいましょう」
『はーい』
「っと、 ID は IDS_E_NOFILE_C=1201 にして」
『あれ、かなりおっきな数だね』
「こういうふうにすると楽だからね」
const unsigned int iIDOffset = 1000;
CString cStrCap;
cStrCap.LoadString( IDS_E_NOFILE + iIDOffset );
『んんん?』
「 IDS_E_NOFILE だよ、 IDS_E_NOFILE_C じゃないからね」
『あー! さっきの本文の方の ID なんだ、それに 1000 足すとタイトルの
になるようにするのね』
「エラーダイアログの本文とタイトルは一対だからね。別々に指定すると
どっかで間違えちゃうから」
『そーゆーテクニックって必要?』
「必要。趣味でのプログラムならいいけど、公開するならミスしないようで
きるだけ気を付けなきゃいけないからね」
『ま、確かに』
「じゃ、エラー処理の部分はこうなります」
if( cIFStrm.fail() )
{
CString cStr;
cStr.LoadString( IDS_E_NOFILE );
const unsigned int iIDOffset = 1000;
CString cStrCap;
cStrCap.LoadString( IDS_E_NOFILE + iIDOffset );
MessageBox
( cStr, cStrCap
, MB_OK | MB_ICONEXCLAMATION );
return;
}
『うお、なんか長い!』
「というわけで、次回はさらにブラッシュアップします」
/*
Preview Next Story!
*/
『水希ちゃんが教えるのって細々としたテクニック多いよね』
「僕はこれが一番大事だと思うんだけどね」
『一番大事?』
「そう、一番大事。なのに本に書いてあること少ないんだよね……」
『というわけで次回』
< Version 5.20 ファイル読み込みをさらにブラッシュアップ! >
「につづく!」
『細々としたことばっかだから長くなっちゃうのねー』
「大事なことで長くなるならよし!」
『うお強気!』