ここは、実際にプログラミングをしていて、なかなか解決しなかったことや、これは便利だと思ったことなどいつでも参照できるように書き留めておくページです。
中には、おかしな記述や誤った記述があるかもしれないので、何か気づいた方は
こちらにメールしていただけると大変助かります。

- フォルダ選択のダイアログを使うには
<初1997,9/27,Sat>
- ショートファイル名からロングファイル名を得るには
<初1997,9/27,Sat><新1997,9/30,Tue>
- フォームのどこをクリックしても移動できるようにするには
<初1997,9/27,Sat>
- メモのタブ幅をかえるには
<初1997,9/27,Sat>
- タスクバーの表示を消すには
<初1997,9/27,Sat><新1997,10/18,Sat>
- メインフォームを非表示にするには
<初1997,9/27,Sat><新1997,10/18,Sat>
- タイトルバーがクリックされたとき処理をするには
<初1997,9/27,Sat>
- 数値を3桁区切りで表示するには
<初1997,9/27,Sat>
- クリックした座標の色を取得するには
<初1997,9/27,Sat>
- 現在出版されている参考書は
<初1997,9/27,Sat><1997,10/5,Sun><新1997,10/28,Tue>
- コマンドライン引数の処理をするには
<初1997,9/27,Sat>
- 文字列を置換するには
<初1997,9/27,Sat>
- 壁紙を変更するには
<初1997,9/27,Sat>
- MemoやRichEditで操作を一つ元に戻すには
<初1997,9/30,Tue>
- MemoやRichEditで内容が変更されているか知るには
<初1997,9/30,Tue>
- ファイルからアイコンを取り出すには
<初1997,9/30,Tue>
- ウインドウのサイズ変更を制限するには
<初1997,9/30,Tue>
- TRichEditで扱えるファイルの大きさを変えるには
<初1997,9/30,Tue>
- ドライブの種類を判別するには
<初1997,9/30,Tue>
- ファイルをフォームへドラッグアンドドロップできるようにするには
<初1997,9/30,Tue>
- AnsiStringを使いこなすには
<初1997,9/30,Tue><新1997,10/12,Sun>
- タイトルバーなしで枠付きのウインドウを作成するには
<初1997,10/5,Sun>
- いろいろな枠を描くには
<初1997,10/5,Sun>
- ディスクトップに文字などを表示するには
<初1997,10/13,Mon>
- タスクトレイにアイコンを置くには
<初1997,10/18,Sat>
- MemoやRichEditで現在のカーソル位置を得るには
<初1997,10/18,Sat>
- Memoの内容をファイルに追加保存するには
<初1997,10/18,Sat>
- DrawGridで個々のセルの色を変えるには
<初1997,10/18,Sat>
- WAVEファイルを手軽に再生するには
<初1997,10/18,Sat>
- 指定した月が何日まであるか調べるには
<初1997,10/20,Mon><新1997,10/21,Tue>
- 指定した日が何曜日か調べるには
<初1997,10/21,Tue>
- 日付を足し引きするには
<初1997,10/22,Wed>
- 時間を足し引きするには
<初1997,10/22,Wed><新1997,10/23,Thu>
- ジョイスティック入力を調べるには
<初1997,10/28,Tue>
- MemoやRichEditでカーソルがある行を一番上の行にするには
<初1997,11/6,Thu>
- 現在のマウスカーソルの位置を得るには
<初1997,11/6,Thu>
- マウスカーソルを移動させるには
<初1997,11/6,Thu>
- マウスカーソルの移動範囲を制限するには
<初1997,11/6,Thu>
- 特別なフォルダのパスを得るには
<初1997,11/6,Thu>
- ドライブの空き容量を得るには
<初1997,11/6,Thu>
- ウインドウを点滅させるには
<初1997,11/10,Mon>

- 今の日時を得るには
<初1997,11/10,Mon>

- 透明なウインドウを作るには(その1)
<初1997,11/10,Mon>

- 透明なウインドウを作るには(その2)
<初1997,11/10,Mon>

- 透明色を指定してビットマップを表示するには
<初1997,11/11,Tue><修1997,11/13,Thu>

- 全角スペースも含めて前後の空白をカットするには
<初1997,11/11,Tue>

- StringGridの文字を右寄せや中央寄せや下寄せ、複数行で表示させるには
<初1997,11/15,Sat>

- StringGridをソートするには
<初1997,11/16,Sun>

参考にしたもの
<初1997,11/6,Thu>

▲フォルダ選択のダイアログを使うには
次の関数を作りボタンが押されたときのイベントなどで
ShowMessage(SelectFolder(Handle));
のようにして使います。
AnsiString SelectFolder( //フォルダのパス、キャンセルされたとき("")
HWND owner) //オーナーウインドウのハンドル
{
AnsiString s;
IMalloc *m; //タスクアロケータ
if(SUCCEEDED(SHGetMalloc(&m)))
{
BROWSEINFO b;
char path[MAX_PATH];
b.hwndOwner= owner; //オーナーウィンドウ
b.pidlRoot= NULL; //ルート
b.pszDisplayName= path; //選択したものの表示名格納場所
b.lpszTitle= "フォルダを選んで下さい"; //表示メッセージ
b.ulFlags= BIF_RETURNONLYFSDIRS; //フォルダのみ選べる
b.lpfn= NULL; //コールバック関数
b.lParam= 0; //コールバック関数に渡される値
b.iImage= 0; //選択したもののイメージ番号
//ダイアログの表示
LPITEMIDLIST id=SHBrowseForFolder(&b);
if(id)
{
//パス名を得る
SHGetPathFromIDList(id, path);
s= path;
m->Free(id);
}
m->Release();
}
return s;
}

▲ショートファイル名からロングファイル名を得るには
次のような関数を作ります。
AnsiString SFileToLFile( //ロングファイル名
AnsiString s) //ショートファイル名
{
AnsiString L;
WIN32_FIND_DATA fd;
//パスも全てロングにする
while(FindFirstFile(s.c_str(),&fd)!=INVALID_HANDLE_VALUE)
{
L.Insert(AnsiString('\\')+fd.cFileName,1);
s= s.SubString(1,s.LastDelimiter('\\')-1);
}
L.Insert(s,1);
return L;
}
[使用例]
たとえばプログラムにファイルをドロップした場合、
ショートファイル名になっているので、
それをロングファイル名(パスも含めて)にして表示するには、次のように書きます。
if(ParamCount()>=1)ShowMessage(SFileToLFile(ParamStr(1));

▲フォームのどこをクリックしても移動できるようにするには
次のコードを書き加えます。
[Unit1.h]
protected:
void __fastcall WMLButtonDown(TWMLButtonDown &Msg);
public:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_LBUTTONDOWN,TWMLButtonDown,WMLButtonDown)
END_MESSAGE_MAP(TForm)
[Unit1.cpp]
void __fastcall TForm1::WMLButtonDown(TWMLButtonDown &Msg)
{
SendMessage(Handle,WM_SYSCOMMAND,SC_MOVE | 2, 0);
}

▲メモのタブ幅をかえるには
次のような関数を作り、MemoTabChange(Memo1,2);というふうに変更したいところに書き加えます。
void MemoTabChange(TMemo *m, //対象となるメモ
int w) //タブ幅
{
long t=w*(GetDialogBaseUnits()&0xffff)/2;
m->Perform(EM_SETTABSTOPS,1,long(&t));
m->Invalidate();
}

▲タスクバーの表示を消すには
ShowWindow(Application->Handle,SW_HIDE);
をApplication->Initialize();の次あたりに書きます。
再び表示するには
ShowWindow(Application->Handle,SW_SHOW);
とします。

▲メインフォームを非表示にするには
実行開始時から表示しない場合は
Application->ShowMainForm= false;
をApplication->CreateForm(__classid(TForm1), &Form1);の前に書きます。
途中で非表示にするには
Hide();
再び表示するには
Show();
とします。

▲タイトルバーがクリックされたとき処理をするには
次のコードを書き加えます。
[Unit1.h]
protected:
void __fastcall WMNCLButtonDown(TWMNCLButtonDown &msg);
public:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_NCLBUTTODOWN,TWMNCLButtonDown,WMNCLButtonDown)
END_MESSAGE_MAP(TForm)
[Unit1.cpp]
void __fastcall TForm1::WMNCLButtonDown(TWMNCLButtonDown &msg)
{
TForm::Dispatch(&msg);
if(msg.HitTest==HTCAPTION)
{
//目的の処理
}
}
※ダブルクリックを検出するにはDownの部分をすべてDblClkにかえればOKです。
※NCLButtonDown->Not Client Left Botton Downと考えれば応用がききます。
[関連するメッセージ]
WM_NCHITTEST
WM_NCLBUTTONDBLCLK
WM_NCLBUTTONDOWN
WM_NCLBUTTONUP
WM_NCMBUTTONDBLCLK
WM_NCMBUTTONDOWN
WM_NCMBUTTONUP
WM_NCMOUSEMOVE
WM_NCRBUTTONDBLCLK
WM_NCRBUTTONDOWN
WM_NCRBUTTONUP

▲数値を3桁区切りで表示するには
次の関数を作り、ShowMessage(Separate(123456789));という風にして使います。
この場合は、123,456,789と表示されます。実数・文字列でもOKです。
AnsiString Separate( //区切った結果
AnsiString n, //数値
int w=3, //区切り幅
char c=',') //区切り文字
{
int p=n.Pos('.');
if(p<=0)p= n.Length()+1;
while((p-=w)>1)n.Insert(c,p);
return n;
}

▲クリックした座標の色を取得するには
次のように書きます。
void __fastcall TForm1::FormMouseDown(TObject *sender,
TMouseButton Buton,TSift Shift,int X,int Y)
{
TColor c=Canvas->Pixels[X][Y];
//好きな処理
}

▲現在出版されている参考書は
- 『Borland C++Builder パワーブック マルチメディアプログラミング』
有馬元嗣 ソフトバンク \2300
3Dダンジョンゲームの作成について書かれています。
- 『無敵のBorland C++Builder』
小出俊夫 秀和システム \2000
ここと同じQ&A方式の本です。(おすすめ)
- 『はじめてのC++Builder』
塚越一雄 ソフトバンク \2000
『はじめてのDelphi』のBuilder版みたいなものです。
- 『C++Builderファースト・プログラミング』
谷尻豊寿/谷尻かおり 技術評論社 \2580
しっかりした内容でサンプルも豊富です。(おすすめ)
- 『C++Builder入門 Vol.1 C++の基礎とC++BuilderのIDE』
ケント・ライスドルフ+ケン・ヘンダーソン著 郡司芳昭訳 トッパン \3200
- 『Borland C++Builder 入門』
藤井等著 ボーランド株式会社監修 アスキー \2800
ボーランド監修なので、ツボをついたテクニックが多くのっています。(おすすめ)
- 『C++Builder 入門』
青山学 ソフトバンク \2400
グラフィックエディタの作り方がのっています。
- 『ゲームプログラミング 遊びのレシピ アルゴリズムとデータ構造』
有馬元嗣 ソフトバンク \2300
「InsideWindows」に連載していたものらしいです。
- 『すぐわかるC++Builder』
塚越一雄 技術評論社 \2480
より効率よくBuilderを使うためのテクニックがのっています。
- 『Boland C++Builder コンポーネント活用ガイド&実践プログラミング』
田中和明・手塚忠則 カットシステム \3800
600ページもあってボリュームのある本です。
- 『C++Builder入門 Vol.2』
ケント・ライスドルフ+ケン・ヘンダーソン著 郡司芳昭訳 トッパン \2400
データベースやDLLなどのかなり深い内容がのっています。
- 『I/O別冊 Borland C++Builder入門』
野戸美江 工学社 \1800
初心者向けで基本的なことがかなり丁寧に書かれています。

▲コマンドライン引数の処理をするには
int ParamCount() 引数の数
AnsiString ParamStr(int index) Index番目の引数(0番目にはプログラム名)
char *CmdLine ParamStrが全てつながったもの
を利用して、
if(ParamCount()>=1)
Memo1->LoadFromFile(ParamStr(1));
のようにして使います。

▲文字列を置換するには
次のような関数を作ります。繰り返し呼べば先頭から順に置き換えていきます。
全て置き換えるには、
while(Replace(s,f,r));
とします。
bool Replace( //置換できたかどうか
AnsiString &s, //検索する文
AnsiString f, //検索文字列
AnsiString r) //置換文字列
{
int p=SourceStr.Pos(f);
if(pos>0)
{
s.Delete(p,f.Length());
s.Insert(r,p);
return true;
}
return false;
}

▲壁紙を変更するには
次のような関数を作り、
if(OpenDialog1->Execute())
WallChange(OpenDialog1->FileName);
というふうにして使います。
//----壁紙を変更する----
bool WallChange( //変更できたかどうか
AnsiString fileName, //ビットマップファイル名
bool tile=true) //タイル状にならべるかどうか
{
try
{
TRegistry *r=new TRegistry;
r->RootKey= HKEY_CURRENT_USER;
//タイリングの指定
if(r->OpenKey("\Control Panel\desktop",false))
r->WriteString("TileWallpaper", tile? '1': '0');
delete r;
//壁紙の変更
SystemParametersInfo(SPI_SETDESKWALLPAPER,0,fileName.c_str(),SPIF_UPDATEINIFILE);
return true;
}
catch(...)
{
return false;
}
}

▲MemoやRichEditで操作を一つ元に戻すには
次のように書きます。
Memo1->Perform(EM_UNDO,0,0);

▲MemoやRichEditで内容が変更されているか知るには
Modifiedプロパティを調べます。
if(Memo1->Modified)
{
//変更されているときの処理
}

▲ファイルからアイコンを取り出すには
ExtractIcon(HInstance,"ファイル名",何番目のアイコンを取り出すか)というAPIを使います。
次の例は指定したファイルに含まれるアイコンをフォーム上に全て表示するものです。
フォームにオープンダイアログを一つ置いて、
フォームのOnClickイベントなどに次のように書いてください。
if(OpenDialog1->Execute())
{
int i,x,y,h;
Canvas->Brush->Color= Color;
Canvas->FillRect(ClientRect);
for(i=x=y=h=0; ; i++)
{
TIcon *icon= new TIcon;
icon->Handle= ExtractIcon(HInstance,OpenDialog1->FileName.c_str(),i);
if(icon->Handle)
{
if(x+icon->Width>ClientWidth)y+= h, x=h=0;
Canvas->Draw(x,y,icon);
x+= icon->Width;
if(hHeight)h= icon->Height;
}
else break;
icon->Free();
}
}

▲ウインドウのサイズ変更を制限するには
次のコードを書き加えます。
[Unit1.h]
protected:
void __fastcall WMGetMinMaxInfo(TWMGetMinMaxInfo &msg);
public:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_GETMINMAXINFO,TWMGetMinMaxInfo,WMGetMinMaxInfo)
END_MESSAGE_MAP(TForm)
[Unit1.cpp]
void __fastcall TForm1::WMGetMinMaxInfo(TWMLButtonDown &msg)
{
//最小サイズ
msg.MinMaxInfo->ptMinTrackSize.x= 320; //適当に変えてください
msg.MinMaxInfo->ptMinTrackSize.y= 200;
//最大サイズ
msg.MinMaxInfo->ptMaxTrackSize.x= 680;
msg.MinMaxInfo->ptMaxTrackSize.y= 400;
//最大化したときのサイズ
msg.MinMaxInfo->ptMaxSize.x= 680;
msg.MinMaxInfo->ptMaxSize.y= 400;
}

▲TRichEditで扱えるファイルの大きさを変えるには
Perform(EM_LIMITTEXT, 0, 扱えるファイルの大きさByte)という関数を使います。
またはMaxLengthプロパティに大きな値をセットします。
[使用例]
RichEdit1->Perform(EM_LIMITTEXT, 0, 10000000) //10MBまでに設定
RichEdit1->MaxLength= 10000000;

▲ドライブの種類を判別するには
GetDriveType(ドライブ名)というAPIを使います。
[使用例]
switch(GetDriveType(NULL)) //カレントドライブを調べる
{
case 0: //ドライブの種類は不明
case 1: //ドライブが存在しない
case DRIVE_REMOVABLE: //リムーバブルディスク
case DRIVE_FIXED: //ハードディスク
case DRIVE_REMOTE: //他のコンピュータのドライブ
case DSRIVE_CDROM: //CD−ROM
case DRIVE_RAMDISK: //RAMディスク
}

▲ファイルをフォームへドラッグアンドドロップできるようにするには
次のコードを書き加えます。
[Unit1.h]
protected:
void __fastcall WMDropFiles(TWMDropFiles &msg);
public:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_DROPFILES, TWMDropFiles, WMDropFiles)
END_MESSAGE_MAP(TForm)
[Unit1.cpp]
#include //DragQueryFile,DragFinish,DragAcceptFilesを使う
void __fastcall TForm1::WMDropFiles(TWMDropFiles &msg)
{
int n=DragQueryFile((HDROP)msg.Drop, -1, NULL, MAX_PATH); //ドラッグされたファイルの数
char fileName[MAX_PATH]; //ドラッグされたファイル名
for(int i=0; iLines->Add(fileName);
}
DragFinish((HDROP)msg.Drop);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
//ドラッグアンドドロップの許可
DragAcceptFiles(Handle,true);
}

▲AnsiStringを使いこなすには
AnsiString s=" abc_ABC_z ";(前後にスペースが一つずつ入っています)
に対して、次のような操作ができます。
・n番目の文字を取り出す(ただし、s[1]が一番前の文字)
s[2] → "a"
・大文字小文字を区別して比較する
s.AnsiCompare(" abc_abc_z ") → 1(大きい。小さいときは-1、等しいときは0)
・大文字小文字を区別せずに比較する
s.AnsiCompareIC(" abc_abc_z ") → 0(等しい。大きいときは1、等しいときは0)
・一番最後の文字を取り出す
s.AnsiLastChar() → " "(スペース)
・char *へ代入する
char *str=s.c_str();
・一部分を削除する
s.Delete(2,2) → " c_ABC_z "
・間に文字を追加する
s.Insert("XYZ",2) → " XYZabc_ABC_z "
・長さが0かどうか調べる
s.IsEmpty() → false(s=""のときtrueなる)
・n番目の文字がパスの区切り記号(\)かどうか調べる
s.IsPathDelimiter(3) → false("a:\\file"のときtrueになる)
・指定した文字と一致する一番最後の場所を得る
s.LastDelimiter("_") → 9
・長さを得る
s.Length() → 11
・すべて小文字にする
s.LowerCase() → " abc_abc_z "
・指定した文字と一致する一番最初の場所を得る
s.Pos("_") → 5
・長さを決める
s.SetLength(4) → " abc"
・同じ文字をならべる
s.StringOfChar('*',5) → "*****"
・double型に変換する
s.ToDouble() → 変換できずに例外(EConvertError)が起こる
・int型に変換する
s.ToInt() → 変換できずに例外(EConvertError)が起こる
・int型に変換する(変換できなければ指定した数値になる)
s.ToIntDef(-1) → -1
・前の空白を取り除く
s.TrimLeft() → "abc_ABC_z "
・後ろの空白を取り除く
s.TrimRight() → " abc_ABC_z"
・前後の空白を取り除く
s.Trim() → "abc_ABC_z"
・すべて大文字にする
s.UpperCase() → " ABC_ABC_Z "

▲タイトルバーなしで枠付きのウインドウを作成するには
フォームのBorderStyleをbsNoneにして、
次のコードを書き加えます。
[Unit1.h]
protected:
virtual void __fastcall CreateParams(TCreateParams& Params);
[Unit1.cpp]
void __fastcall TForm1::CreateParams(TCreateParams& Params)
{
TForm::CreateParams(Params);
Params.Style|= WS_DLGFRAME; //立体的に表示される(サイズ変更できない)
// Params.Style|= WS_THICKFRAME; //立体的に表示される(サイズ変更できる)
// Params.Style|= WS_BORDER; //枠に黒い線が書かれる(サイズ変更できない)
}

▲いろいろな枠を描くには
DrawEdgeというAPIを使用します。
[例]次のように書けばフォーム上にそれぞれの枠が並んで表示されるので確かめてみてください
RECT r;
//RECT型の値をセットする
SetRect(&r,10,10,30,30);
//フォーカスを得た時の点線の枠を描きます(Canvasの同名のメソッドでも同じように描けます)
DrawFocusRect(Canvas->Handle,&r);
//RECTを右に30ドットずらす
OffsetRect(&r,30,0);
//立体的なボタンを描きます
DrawEdge(Canvas->Handle,&r,EDGE_RAISED,BF_RECT);
//RECTを右に30ドットずらす
OffsetRect(&r,30,0);
//出っ張った枠線を描きます
DrawEdge(Canvas->Handle,&r,EDGE_BUMP,BF_RECT);
//RECTを右に30ドットずらす
OffsetRect(&r,30,0);
//へこんだ枠線を書きます
DrawEdge(Canvas->Handle,&r,EDGE_ETCHED,BF_RECT);
//RECTを右に30ドットずらす
OffsetRect(&r,30,0);
//ボタンが押されてへこんだ状態を描きます
DrawEdge(Canvas->Handle,&r,EDGE_SUNKEN,BF_RECT);
※DrawFocusRect(Canvas->Handle,&r);はもう一度重ねて書くと表示を消すことができます。

▲ディスクトップに文字などを表示するには
次のようにするとCanvasに書き込むことでデスクトップに表示されます。
ただしウインドウなどで一度隠れると消えてしまいます。
TCanvas *c=new TCanvas;
c->Handle= GetDC(0);
//ここから好きな処理をする
c->Font->Size= 100;
c->TextOut(10,10,"いろは");
//ここまで
ReleaseDC(0,c->Handle);
c->Free();

▲タスクトレイにアイコンを置くには
Shell_NotifyIconというAPIを使います。
ポップアップメニューを1つ作り(終了という項目を作って下さい)、
次のように書けばアイコンがタスクトレイに置かれ、
左クリックでメッセージの表示、右クリックでメニューの表示ができます。
[Unit1.h]
private: // ユーザー宣言
enum{ WM_TASKICON=WM_USER+1 };
NOTIFYICONDATA NID;
void __fastcall WMTaskIcon(TMessage &msg);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_TASKICON,TMessage,WMTaskIcon)
END_MESSAGE_MAP(TForm)
[Unit1.cpp]
#include //NOTIFYICONDATA,Shell_NotifyIcon
//---------------------------------------------------------------------------
void __fastcall TForm1::WMTaskIcon(TMessage &msg)
{
switch(msg.LParam)
{
case WM_LBUTTONDOWN: //左ボタンがクリックされたとき
ShowMessage("LeftClicked");
break;
case WM_RBUTTONDOWN: //右ボタンがクリックされたとき
POINT p;
GetCursorPos(&p);
SetForegroundWindow(Application->Handle);
Application->ProcessMessages();
PopupMenu1->Popup(p.x,p.y);
break;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
//タスクトレイにアイコンを置く
NID.cbSize= sizeof(NID);
NID.hWnd= Handle;
NID.uID= 1;
NID.uFlags= NIF_ICON|NIF_MESSAGE|NIF_TIP;
NID.uCallbackMessage= WM_TASKICON;
NID.hIcon= Application->Icon->Handle;
lstrcpy(NID.szTip,Application->Title.c_str());
Shell_NotifyIcon(NIM_ADD, &NID);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
//タスクトレイのアイコンを消す
Shell_NotifyIcon(NIM_DELETE,&NID);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::K1Click(TObject *Sender)
{
Close();
}
[Project1.cpp]
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
//タスクバーからアイコンを消す
ShowWindow(Application->Handle,SW_HIDE);
Application->Title = "タスクアイコン";
//メインフォームを表示しない
Application->ShowMainForm= false;
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}

▲MemoやRichEditで現在のカーソル位置を得るには
mをMemoかRichEditとすると
現在の行位置は
m->Perform(EM_LINEFROMCHAR, m->SelStart, 0);
現在の列位置は
m->SelStart-m->Perform(EM_LINEINDEX, m->Perform(EM_LINEFROMCHAR, m->SelStart, 0), 0);
で得られます。
※両方とも最初の行(列)が0となります。

▲Memoの内容をファイルに追加保存するには
ファイルストリームを使った例を紹介します。
ボタン(Botton1)が押されたとき、
メモ(Memo1)の内容をFile.txtというファイルに追加(なければ作成して)保存します。
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFileStream *fs;
try
{
fs= new TFileStream("file.txt",fmOpenReadWrite);
}
catch(...)
{
fs= new TFileStream("file.txt",fmCreate);
}
fs->Seek(0,soFromEnd);
Memo1->Lines->SaveToStream(fs);
fs->Free();
}

▲DrawGridで個々のセルの色を変えるには
各セルの色情報を持つ配列を作って、OnDrawCellイベントを自作します。
下の例はダブルクリックしたセルの色を
ダイアログを使って自由に変えるプログラムです。
フォームにDrawGridとColorDIalogを置いて次のようにコードを入力してください。
[Unit1.h]
//-----------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE 管理のコンポーネント
TDrawGrid *DrawGrid1;
TColorDialog *ColorDialog1;
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
void __fastcall DrawGrid1DrawCell(TObject *Sender, long Col,
long Row, TRect &Rect, TGridDrawState State);
void __fastcall DrawGrid1DblClick(TObject *Sender);
private: // ユーザー宣言
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
//色情報を保存する配列
TColor *color;
//指定したセルの色を得る
TColor &Color(int c,int r){ return color[c*DrawGrid1->RowCount+r]; }
};
[Unit1.cpp]
//-----------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
//配列の大きさを計算する
int n=DrawGrid1->ColCount*DrawGrid1->RowCount;
//色情報保存用の配列を確保する
color= new TColor[n];
//色の初期設定
while(n--)color[n]= clWindow;
}
//-----------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete color;
}
//-----------------------------------------------------------
void __fastcall TForm1::DrawGrid1DrawCell(TObject *Sender, long Col,
long Row,TRect &Rect, TGridDrawState State)
{
DrawGrid1->Canvas->Brush->Color= Color(Col,Row);
//この部分を好きな処理に置き換えればいろいろできます。
DrawGrid1->Canvas->FillRect(Rect);
}
//-----------------------------------------------------------
void __fastcall TForm1::DrawGrid1DblClick(TObject *Sender)
{
//セルの色をかえる
if(ColorDialog1->Execute())
Color(DrawGrid1->Col,DrawGrid1->Row)= ColorDialog1->Color;
}

▲WAVEファイルを手軽に再生するには
#include
を加えて
sndPlaySound(WAVEファイル名, オプション)という関数を使います。
オプションは次のとおりです(組み合わせて使えます)
SND_LOOP 繰り返して再生する(SND_ASYNCとあわせて使って下さい)
SND_SYNC 再生が終わるまで待つ
SND_ASYNC 再生が終わるまで待たない
SND_NODEFAULT ファイルが見つからない場合、警告音を鳴らさない(普通は警告音がなる)
SND_NOSTOP すでに再生中の場合何もしないでfalseを返す(普通は再生する)
再生中の音を消すには
sndPlaySound(NULL,0);
とします。
※あまりサイズが大きいWAVEファイルはメモリを圧迫するので使用しないほうがいいです。

▲指定した月が何日まであるか調べるには
指定した次の月の1日から1を引けばOKです。関数を作りました。
ShowMessage(LastDay(1997,2)); //2月の日数を調べる
のようにして使います。
int LastDay( //その月の日数(失敗時は0)
int year, //西暦年
int month) //月
{
unsigned short y,m,d=0;
try
{
(TDateTime(short(year),short(month+1),1)-1).DecodeDate(&y,&m,&d);
}
catch(...){}
return d;
}
(1を引くという発想が出ませんでした。>>周波発振器さん)

▲指定した日が何曜日か調べるには
DayOfWeek()やFormatString()メソッドを使います。
1997年2月1日の場合は
TDateTime(1997,2,1).DayOfWeek() //日曜:1〜土曜:7
です。
[例]ShowMessage(TDateTime(1997,2,1).FormatString("dddd")); //?曜日の形で表示される

▲日付を足し引きするには
次のような関数を作ります。
ShowMessage(DateCalc(TDateTime(1997,6,1),0,-10,0)); //10ヶ月前を求める
のようにして使います。
TDateTime DateCalc( //計算結果(失敗時は元の日付)
TDateTime date, //元の日付
int year, //足し引きする年
int month, //足し引きする月(±12以上でもよい)
int day) //足し引きする日(±31以上でもよい)
{
unsigned short y,m,d;
date.DecodeDate(&y,&m,&d);
year+= y;
month+= m;
if(month<0)year+= month/12-1, month= 12-(-month)%12;
else if(month>12)year+= month/12, month%= 12;
try
{
date= TDateTime(short(year),short(month),d)+day;
}
catch(...){}
return date;
}

▲時間を足し引きするには
TDateTime(時,分,秒,ミリ秒)で足し引きすればOKです。
ShowMessage(TDateTime(10,10,50,0)+TDateTime(0,0,33,0)); //33秒後を求める
のようにして使います。

▲ジョイスティック入力を調べるには
joyGetDevCaps, joyGetPosというAPIを使用して調べます。
#include
をソースファイルのはじめのほうに書き加えて下さい。
[joyGetDevCapsについて]
JOYCAPS j;
bool ok=joyGetDevCaps(JOYSTICKID1, &j, sizeof(j))==JOYERR_NOERROR;
とすると次の情報が得られます。
ok //使用できるかどうか
j.szPname //ジョイスティックの名前
j.wNumButtons //ボタンの数
j.wXmin //一番上に倒したときのX座標の値
j.wXmax //一番下に倒したときのX座標の値
j.wYmin //一番左に倒したときのX座標の値
j.wYmax //一番右に倒したときのX座標の値
※APIのヘルプ(Win32.hlp, Win32j.hlp)にもっと詳しく載ってます。
[joyGetPosについて]
JOYINFO j;
bool ok=joyGetPos(JOYSTICKID1,&j)==JOYERR_NOERROR;
とすると次の情報が得られます。
ok //情報が得られたかどうか
j.wXpos //現在のX座標の値
j.wYpos //現在のY座標の値
j.wButtons //現在押されているボタン
※これをタイマーイベントなどで定期的に調べることで、
ジョイスティック対応のプログラムが作れます。
※ジョイスティックから入力方向を得るには次のようにします。
こうすればキーボード、ジョイパッドなどと同じように処理できるようになります。
ヘッダファイルのpublic:のなかに
TRect r;
を加えて、
OnCreateイベントなどで
JOYCAPS j;
if(joyGetDevCaps(JOYSTICKID1,&j,sizeof(j)==JOYERR_NOERROR)
{
r.Left= j.wXmin+(j.wXmax-j.wXmin)/3;
r.Right= j.wXmax-(j.wXmax-j.wXmin)/3;
r.Top= j.wYmin+(j.wYmax-j.wYmin)/3;
r.Bottom= j.wYmax-(j.wYmax-j.wYmin)/3;
}
else
{
//使用できない
}
として上下左右の方向が有効になる座標を計算します。
そのあとタイマーイベントなどで、
JOYINFO j;
if(joyGetPos(JOYSTICKID1,&j)==JOYERR_NOERROR)
{
if(j.wXposr.Right)
{
//右が押されたときの処理
}
if(j.wYposr.Bottom)
{
//下が押されたときの処理
}
}
のようにします。

▲MemoやRichEditでカーソルがある行を一番上の行にするには
次のように書きます。
//フォーカスをあわせる
RichEdit1->SetFocus();
//カーソルのある行位置を得る
int p=RichEdit1->Perform(EM_LINEFROMCHAR,RichEdit1->SelStart,0);
//一番上の行位置を引く
p-= RichEdit1->Perform(EM_GETFIRSTVISIBLELINE,0,0);
//スクロールさせる
RichEdit1->Perform(EM_LINESCROLL,0,p);
※Memoの場合、行数が表示行数より少ないときは一番上にならないようです。

▲現在のマウスカーソルの位置を得るには
GetCursorPos(POINT変数)というAPIを使います。
得られる座標はスクリーン座標なのでウインドウ内の座標にしたい場合は
POINT p;
GetCursorPos(&p);
//ウインドウ内の座標にする
ScreenToClient(p);
のようにします。
※ウインドウ外にマウスカーソルがある場合でも位置を得たい場合は
SetCapture(Handle);
POINT p;
GetCursorPos(&p);
ReleaseCapture();
として下さい。

▲マウスカーソルを移動させるには
SetCursorPos(X座標,Y座標)というAPIを使います。
次の例はマウスカーソルの位置を常にタイトルバーに表示して、
画面の端にカーソルを持っていったときウインドウ内の左上の位置にカーソルを移動させるものです。
[Unit1.h]
(省略)
private: // ユーザー宣言
void __fastcall AppIdle(TObject*,bool &Done);
(省略)
[Unit1.cpp]
(省略)
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
Application->OnIdle= AppIdle;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::AppIdle(TObject*,bool &Done)
{
//カーソル座標を得る
SetCapture(Handle);
POINT p;
GetCursorPos(&p);
Caption= "("+IntToStr(p.x)+","+IntToStr(p.y)+")";
ReleaseCapture();
//画面端にきたとき
if(p.x<=0||p.y<=0||p.x+1>=Screen->Width||p.y+1>=Screen->Height)
{
//カーソルの移動先
POINT q=ClientOrigin;
//少しずつ移動させる
for(int i=0,j=10; iProcessMessages();
}
SetCursorPos(q.x,q.y);
}
//連続してこの関数を呼ぶ
Done= false;
}

▲マウスカーソルの移動範囲を制限するには
ClipCursor(移動範囲RECT)というAPIを使います。
ウインドウ内だけに移動範囲を限定するには
RECT r;
GetWindowRect(Handle,&r);
ClipCursor(&r);
のようにします。
ClipCursor(NULL);
で制限を解除します。
※使用するときは十分注意して、後には必ず制限を解除して下さい。
そうしないとプログラムが終了してもカーソル移動が制限されてしまいます。

▲特別なフォルダのパスを得るには
まず、
char buf[MAX_PATH+1];
と宣言しておきます。
[Windowsフォルダ]
GetWindowsDirectory(buf,MAX_PATH);
[Systemフォルダ]
GetSystemDirectory(buf,MAX_PATH);
[カレントフォルダ]
GetCurrentDirectory(MAX_PATH,buf);
[作業用フォルダ]
GetTempPath(MAX_PATH,buf);
でそれぞれのフォルダのパスがbufに入ります。

▲ドライブの空き容量を得るには
GetDiskFreeSpace(調べるドライブのルートパス,セクタ数,バイト数,使用クラスタ数,全クラスタ数)というAPIを使います。
[例]
DWORD s,b,c,t;
//Aドライブの容量を得る
GetDiskFreeSpace("A:\\",&s,&b,&c,&t);
ShowMessage(IntToStr(s*b*c)+"byteの空き/全"+IntToStr(s*b*t)+"byte");
//カレントドライブの容量を得る
GetDiskFreeSpace(NULL,&s,&b,&c,&t);
ShowMessage(IntToStr(s*b*c)+"byteの空き/全"+IntToStr(s*b*t)+"byte");
※2Gbyte以上容量がある場合はGetDiskFreeSpaceExを使用する必要があります。

▲ウインドウを点滅させるには
FlashWindow(ウインドウハンドル, 点滅させるかどうか)というAPIを使います。
次のようにすればn回点滅します。
int n=3;
for(n+=n; n--; )
{
FlashWindow(Handle,true);
//0.1秒間隔
DWORD t=GetTickCount()+100;
while(GetTickCount()ProcessMessages();
}
※点滅させながら処理を行いたい場合はTimerコンポーネントを使って下さい。

▲今の日時を得るには
Now()関数を使います。
例)ShowMessage(Now().FormatString("yyyy'年'm'月'd'日('ddd') 'h'時'n'分's'秒'"));

▲透明なウインドウを作るには(その1)
重なる他のウインドウやディスクトップ上のアイコンも全て表示しない(壁紙のみを表示する)やり方です。
次のコードを書き加えて下さい。
[Unit1.h]
private: // ユーザー宣言
void __fastcall WMEraseBkgnd(TWMEraseBkgnd &msg);
void __fastcall WMMove(TWMMove &msg);
public: // ユーザー宣言
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_ERASEBKGND,TWMEraseBkgnd,WMEraseBkgnd)
MESSAGE_HANDLER(WM_MOVE,TWMMove,WMMove)
END_MESSAGE_MAP(TForm)
[Unit1.cpp]
//---------------------------------------------------------------------------
void __fastcall TForm1::WMEraseBkgnd(TWMEraseBkgnd &msg)
{
//壁紙だけを表示
DefWindowProc(GetDesktopWindow(),WM_ICONERASEBKGND,(WPARAM)msg.DC,0);
msg.Result= 1;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WMMove(TWMMove &msg)
{
Invalidate();
}

▲透明なウインドウを作には(その2)
重なる他のウインドウやディスクトップ上のアイコンなどを表示するやり方ですが、
起動時の状態を復元するだけなので変化があったとき表示にずれが生じてしまいます。
これを解決する方法をご存知の方はぜひ教えて下さい。
次のコードを書き加えて下さい。
[Unit1.h]
class TForm1 : public TForm
{
__published: // IDE 管理のコンポーネント
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
private: // ユーザー宣言
void __fastcall WMEraseBkgnd(TWMEraseBkgnd &msg);
void __fastcall WMMove(TWMMove &msg);
public: // ユーザー宣言
Graphics::TBitmap *G;
__fastcall TForm1(TComponent* Owner);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_ERASEBKGND,TWMEraseBkgnd,WMEraseBkgnd);
MESSAGE_HANDLER(WM_MOVE,TWMMove,WMMove)
END_MESSAGE_MAP(TForm)
};
[Unit1.cpp]
//---------------------------------------------------------------------------
void __fastcall TForm1::WMEraseBkgnd(TWMEraseBkgnd &msg)
{
POINT p=ClientOrigin;
RECT r=RECT(ClientRect);
OffsetRect(&r,p.x,p.y);
Canvas->CopyRect(ClientRect,G->Canvas,TRect(r));
msg.Result= 1;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WMMove(TWMMove &msg)
{
Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
G= new Graphics::TBitmap;
G->Width= Screen->Width;
G->Height= Screen->Height;
//画面を丸ごとコピー
HDC h=GetDC(0);
BitBlt(G->Canvas->Handle,0,0,G->Width,G->Height,h,0,0,SRCCOPY);
ReleaseDC(0,h);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
G->Free();
}

▲透明色を指定してビットマップを表示するには
最も確実な方法は1ピクセルづつ調べてマスクを作成することですが、
TBitmapのMonochromeプロパティを利用したマスクの作成方法を紹介します。
Monochromeプロパティをtrueにすると、
Brush->Colorの色が白、残りの色が黒のビットマップに変化します。
これを使って、次のような関数を作ってみました。
白を透けさせて表示するには、
DrawTransparentBitmap(Canvas,Bitmap1,clWhite);
絵の左上の点の色を透明色にして表示するには、
DrawTransparentBitmap(Canvas,Bitmap1,Bitmap1->Canvas->Pixels[0][0]);
とします。(Bitmap1にはあらかじめビットマップをセットしておいて下さい)
//-透明色指定でビットマップ表示--------------------------------------------------------------------------
void DrawTransparencyBitmap(
TCanvas *c, //表示先
Graphics::TBitmap *bm, //表示するビットマップ
TColor t) //透明色
{
//作業用ビットマップ
Graphics::TBitmap *b=new Graphics::TBitmap;
Graphics::TBitmap *m=new Graphics::TBitmap;
//設定の保存
long cc=c->CopyMode;
TColor cf=c->Font->Color;
TColor cb=c->Brush->Color;
//マスクの作成
m->Assign(bm);
m->Canvas->Brush->Color= TColor(t|0x2000000);
m->Monochrome= true;
//元の絵のくりぬき
b->Assign(bm);
b->Canvas->CopyMode= cmSrcAnd;
b->Canvas->Font->Color= clWhite;
b->Canvas->Brush->Color= clBlack;
b->Canvas->Draw(0,0,m);
//表示
c->CopyMode= cmSrcAnd;
c->Font->Color= clBlack;
c->Brush->Color= clWhite;
c->Draw(0,0,m);
c->CopyMode= cmSrcPaint;
c->Draw(0,0,b);
//設定の復元
c->CopyMode= cc;
c->Font->Color= cf;
c->Brush->Color= cb;
/作業用ビットマップの破棄
b->Free();
m->Free();
}

▲全角スペースも含めて前後の空白をカットするには
AnsiStringのTrimメソッドでは全角スペースはカットされないので自作の関数を作成しました。
//-前後の空白を除く--------------------------------------------------------------------------
AnsiString Trims(
AnsiString s)
{
char *p=new char[s.Length()+1], *q=p+s.Length()-1;
strcpy(p, s.c_str());
//前の空白
for(; *p; p++)
if(p[0]==" "[0]&&p[1]==" "[1])p++;
else if(BYTE(*p)>' ')break;
//後ろの空白
for(; p' ')break;
if(pq)s= "";
delete []p;
return s;
} //Trims

▲StringGridの文字を右寄せや中央寄せや下寄せ、複数行で表示させるには
DefaultDrawingプロパティをfalseにして
OnDrawCellイベントで表示命令を書きます。
そのときDrawTextというAPIを使えば自由に表示できます。
文字の表示位置以外は元のままにしたい場合は次のようにします。(sgはStringGridです)
void __fastcall TForm1::sgDrawCell(TObject *Sender, long Col, long Row,TRect &Rect, TGridDrawState State)
{
RECT r=RECT(Rect);
//固定セル
if(State.Contains(gdFixed))
sg->Canvas->Brush->Color= sg->FixedColor;
//フォーカスのあるセル
else if(State.Contains(gdFocused))
sg->Canvas->Brush->Color= sg->Options.Contains(goDrawFocusSelected)? clHighlight: sg->Color;
//選択されているセル
else if(State.Contains(gdSelected))
sg->Canvas->Brush->Color= clHighlight;
//普通のセル
else
sg->Canvas->Brush->Color= sg->Color;
//消去
sg->Canvas->FillRect(Rect);
//立体枠の描画
if(State.Contains(gdFixed))
DrawEdge(sg->Canvas->Handle,&r,BDR_RAISEDINNER,BF_RECT);
//フォーカス枠の描画
if(State.Contains(gdSelected))
{
sg->Canvas->Font->Color= clHighlightText;
if(State.Contains(gdFocused))DrawFocusRect(sg->Canvas->Handle,&r);
}
else sg->Canvas->Font->Color= sg->Font->Color;
//テキスト表示領域の設定
InflateRect(&r,-2,-2);
//テキストの表示
DrawText(sg->Canvas->Handle,sg->Cells[Col][Row].c_str(),-1,&r,DT_RIGHT); //右寄せ
// DrawText(sg->Canvas->Handle,sg->Cells[Col][Row].c_str(),-1,&r,DT_CENTER); //中央寄せ(水平)
// DrawText(sg->Canvas->Handle,sg->Cells[Col][Row].c_str(),-1,&r,DT_VCENTER|DT_SINGLELINE); //中央寄せ(垂直)
// DrawText(sg->Canvas->Handle,sg->Cells[Col][Row].c_str(),-1,&r,DT_BOTTOM|DT_SINGLELINE); //下寄せ
// DrawText(sg->Canvas->Handle,sg->Cells[Col][Row].c_str(),-1,&r,DT_CENTER|DT_VCENTER|DT_SINGLELINE); //水平・垂直とも中央寄せ
// DrawText(sg->Canvas->Handle,sg->Cells[Col][Row].c_str(),-1,&r,DT_WORDBREAK); //複数行表示
}

▲StringGridをソートするには
StringGridには一行のデータをTStringsとして取得できるRowsプロパティがあります。
これを使って行単位で入れ替えていけばソートができます。
次のような関数を作って
sgSort(StringGrid1,1); //1列目をキーにソートする
という風に使って下さい。
//-StringGridのソート(選択ソート)-----------
void sgSort(
TStringGrid *sg, //StringGrid
long col, //ソートのキーとなる列
bool desc=false) //false:昇順, true:降順
{
//範囲外の指定
if(col<0||col>=sg->ColCount)return;
for(int i=sg->FixedRows; iRowCount-1; i++)
{
for(int j=i+1; jRowCount; j++)
{
bool b;
//数値として比べてみてだめだったら文字で比べる(8と10などを文字で比べたときに逆転するのを防ぐ)
try
{
b= sg->Cells[col][i].ToDouble()>sg->Cells[col][j].ToDouble();
}
catch(...)
{
b= sg->Cells[col][i]>sg->Cells[col][j];
}
//行の入れ替え
if(desc? !b: b)
{
TStringList *sl=new TStringList;
sl->Assign(sg->Rows[i]);
sg->Rows[i]= sg->Rows[j];
sg->Rows[j]= sl;
sl->Free();
}
}
}
}

▲参考にしたもの
| 無敵のBorland C++Builder | 小出俊夫 |
| 初めてのDelphi | 塚越一雄 |
| Delphi3 Q&A150選 | 大野元久 |
| Delphiでいこう!(TechWin連載) | 服部誠 |


リンクは自由に貼って下さい。また、その際に連絡をいただければうれしいです。
| access(since 1997,9/29,Mon) | Update<1997,11/16,Sun>K.Nakazawa |
ミラーサイト
