C++Builderメモ

フォーム
(ウィンドウ)
タイトルバー以外でフォームをドラッグ1
タイトルバー以外でフォームをドラッグ2
フォームのサイズ変更を制限する
フォームのシステムメニューにメニューを追加する
フォームを完全に表示してから何か処理をする
メインのフォームを非表示で起動する
タスクバーのアイコンを消す
タイトルバーの高さを得る
ドラッグ&ドロップでファイル名を受け取る
コンポーネント
(コントロール)
ラベル、ヒントのCaptionを複数行にする
タブ順にフォーカスを移動
デスクトップからの絶対座標を得る
コントロールの四隅の位置を一度に取得する
コンポーネントの境界プロパティを一度に変更する
マウスでコントロールの位置を移動する
パネル
(Panel)
マウスで位置を移動する
リストボックス
(ListBox)
水平スクロールバーを表示させる
コンボボックス
(ComboBox)
ドロップダウンリストを表示させる
行毎に文字列と数値を扱う
ストリンググリッド
(StringGrid)
リバースカーソルを消す
セルの文字の色を変えてみる
リストビュー
(ListView)
任意の位置にカーソルを移動する
任意の位置を編集状態にする
チェックボックスの変化に対応する
指定行の文字色を変更
ツリービュー
(TreeView)
任意の位置を編集状態にする
キャンバス
(イメージ)
画面(デスクトップ)のキャプチャー
一部分の再描画
ビットマップとJPEGイメージの相互変換
キーボード
マウス
マウスカーソルの表示/非表示
マウスカーソルの移動範囲を制御する
キーバッファやマウスイベントをクリアする
プログラムでキーボードを押したと思わせる
アイコン
HWNDからアイコン(HICON)を取得する
タスクトレイ
タスクトレイにアイコンを表示
タスクトレイに表示したアイコンでマウスイベントを受ける
タスクトレイに表示したアイコンをアニメーションしてみる
クリップボード
文字を転送/取得する
画像を転送/取得する
ファイル名
パスからドライブ名を取得
パスからドライブ名+ディレクトリを取得
パスからファイル名を取得
パスからファイル名の拡張子を取得
ファイル名の拡張子を変更する
パスから拡張子無しのファイル名のみを取得する
その他
二重起動の防止



フォーム(ウィンドウ)タイトルバー以外でフォームをドラッグ1
フォームのMouseDownイベントに記述します。
if( Button == mbLeft ){
  ReleaseCapture( );
  SendMessage( Handle, WM_SYSCOMMAND, SC_MOVE | 2, 0 );
}
PanelのMouseDownに記述すればPanelをドラッグでフォームを移動できます。

フォーム(ウィンドウ)タイトルバー以外でフォームをドラッグ2
ヘッダーの
public: // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
の下あたりに以下の行を追加します。
protected:
  void __fastcall WMLButtonDown(TWMLButtonDown &Msg)
  {
    SendMessage( Handle, WM_SYSCOMMAND, SC_MOVE | 2, 0 );
  }
  BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_LBUTTONDOWN,TWMLButtonDown,WMLButtonDown)
  END_MESSAGE_MAP(TForm)

フォーム(ウィンドウ)フォームのサイズ変更を制限する
ヘッダーーの
public: // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
の下あたりに以下の行を追加します。
protected:
  void __fastcall WMGetMinMaxInfo(TWMGetMinMaxInfo &Msg)
  {
    // 最小サイズ
    Msg.MinMaxInfo->ptMinTrackSize.x= 200;
    Msg.MinMaxInfo->ptMinTrackSize.y= 200;
    // 最大サイズ
    Msg.MinMaxInfo->ptMaxTrackSize.x= 800;
    Msg.MinMaxInfo->ptMaxTrackSize.y= 600;
    // 最大化サイズ
    Msg.MinMaxInfo->ptMaxSize.x= 800;
    Msg.MinMaxInfo->ptMaxSize.y= 600;
  }
  BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_GETMINMAXINFO,TWMGetMinMaxInfo,WMGetMinMaxInfo)
  END_MESSAGE_MAP(TForm)
  ※ Builder5からオブジェクトインスペクタでできます。

フォーム(ウィンドウ)フォームのシステムメニューにメニューを追加する
とりあえずフォームのコンストラクタ辺りに以下の行を追加
HMENU hm = GetSystemMenu( Handle, false );
// メニューの一番上に追加
InsertMenu( hm, SC_RESTORE, MF_BYCOMMAND | MFT_STRING, 10, "めにゅ〜1" );
// 次に追加
InsertMenu( hm, SC_RESTORE, MF_BYCOMMAND | MFT_STRING, 11, "めにゅ〜2" );
// メニューの一番下に追加
AppendMenu( hm, MF_STRING, 12, "めにゅ〜3" );
DrawMenuBar( Handle );
// ※id(10,11,12)は任意の値だが0xF000より小さい値にするらしい

ヘッダーの
public: // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
の下あたりに以下の行を追加します。
protected:
  void __fastcall WMSysCommand( TWMSysCommand Msg )
  {
    HMENU hm = GetSystemMenu( Handle, false );
    switch( Msg.CmdType ){
      case 10: // めにゅ〜1
        if( GetMenuState( hm, Msg.CmdType, MF_BYCOMMAND ) & MFS_CHECKED ){
          // チェックを外す
          CheckMenuItem( hm, Msg.CmdType, MF_BYCOMMAND | MFS_UNCHECKED );
        }
        else{
          // チェックをを付ける
          CheckMenuItem( hm, Msg.CmdType, MF_BYCOMMAND | MFS_CHECKED );
        }
        break;
      case 11: // めにゅ〜2
       break;
      case 12: // めにゅ〜3
       break;
    }
    DefaultHandler( &Msg );
  }
  BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER( WM_SYSCOMMAND, TWMSysCommand, WMSysCommand )
  END_MESSAGE_MAP(TForm)

フォーム(ウィンドウ)フォームを完全に表示してから何か処理をする
コンストラクタ辺りに以下の行を追加
Application->OnIdle = FormIdle;

ヘッダーのprivate辺りに以下の行を追加
private: // ユーザー宣言
  void __fastcall FormIdle(TObject *Sender, bool &Done)
  {
    Application->OnIdle = NULL; // NULLを入れて再突入を防止しとく
    // ここで何かする
  }

フォーム(ウィンドウ)メインのフォームを非表示で起動する
コンストラクタ辺りに以下の行を追加
Application->ShowMainForm = false;

フォーム(ウィンドウ)タスクバーのアイコンを消す
コンストラクタ辺りに以下の行を追加
ShowWindow( Application->Handle, SW_HIDE );

フォーム(ウィンドウ)タイトルバーの高さを得る
int height = GetSystemMetrics( SM_CYCAPTION );

フォーム(ウィンドウ)ドラッグ&ドロップでファイル名を受け取る
コンストラクタ辺りに以下の行を追加。
DragAcceptFiles( Handle, true );

ヘッダーの
public: // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
の下辺りに以下を追加します。
protected:
void __fastcall WMDropFiles( TWMDropFiles &Msg )
{
  int cnt = DragQueryFile( (HDROP)Msg.Drop, 0xFFFFFFFF, NULL, MAX_PATH );
  char buff[MAX_PATH+2];
  for( int i = 0; i < cnt; i ++ ){
    DragQueryFile( (HDROP)Msg.Drop, i, buff, MAX_PATH );
    // buffにファイル名が入ったので、ここで何か処理しましょう
  }
  DragFinish( (HDROP)Msg.Drop );
}
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER( WM_DROPFILES, TWMDropFiles, WMDropFiles )
END_MESSAGE_MAP(TForm)

コンポーネント(コントロール)ラベル、ヒントのCaptionを複数行にする
Caption = "1行目\n2行目";

コンポーネント(コントロール)タブ順にフォーカスを移動
FindNextControl( ActiveControl, true, true, false )->SetFocus( );

コンポーネント(コントロール)デスクトップからの絶対座標を得る
Image1の座標を得る場合は
TPoint p = ClientToScreen( Point(Image1->Left, Image1->Top) );

コンポーネント(コントロール)コントロールの四隅の位置を一度に取得する
BoundsRectを使用します。
Panel1の4隅を取得する場合。
TRect rect = Panel1->BoundsRect;

コンポーネント(コントロール)コンポーネントの境界プロパティを一度に変更する
SetBoundsを使用します。
例えばForm1の大きさを半分にする場合。
TRect r = BoundsRect;
SetBounds( r.Left, r.Top, (r.Right - r.Left) / 2, (r.Bottom - r.Top) / 2 );

コンポーネント(コントロール)マウスでコントロールの位置を移動する
MouseDown、MouseMove、MouseUpイベントを使用します。
ヘッダーのprivate辺りにでも以下を追加
int Sx;
int Sy;
bool Flg;
TImageを動かしてみる場合。
// Image1のMouseDownイベント
void __fastcall TForm1::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
  if( Button != mbLeft ) return;
  Sx = X;
  Sy = Y;
  Flg = true;
}
// Image1のMouseMoveイベント
void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
{
  if( Flg == false ) return;
  Image1->SetBounds( Image1->Left + (X - Sx), Image1->Top + (Y - Sy), Image1->Width, Image1->Height );
}
// Image1のMouseUpイベント
void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
  Flg = false;
}

パネル(Panel)マウスで位置を移動する
コンポーネント(コントロール)のマウスでコントロールの位置を移動するとかぶってますが、こっちは楽です。
void __fastcall TForm1::Panel1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
  ReleaseCapture( );
  dynamic_cast<TPanel *>(Sender)->Perform( WM_SYSCOMMAND, 0xF012, 0 );
}


リストボックス(ListBox)水平スクロールバーを表示させる
int m = 0;
for( int i= 0, w; i < ListBox1->Items->Count; i++ ){
  w = Canvas->TextWidth( ListBox1->Items->Strings[i] );
  m = m < w ? w : m;
}
SendMessage( ListBox1->Handle, LB_SETHORIZONTALEXTENT, m, 0 );
又は
ListBox1->Perform( LB_SETHORIZONTALEXTENT, m, 0 );
どっちでも同じ結果みたいです。
ちなみにm(ピクセル)をそのまま指定しても短いかも知れません。
その場合はm + 10とかして、適当に足して調整して下さい。

コンボボックス(ComboBox)ドロップダウンリストを表示させる
ComboBox1->DroppedDown = true;

コンボボックス(ComboBox)行毎に文字列と数値を扱う
リストを追加
ComboBox1->Items->AddObject( "aaaaaaaaaaa", (TObject *)10 );
ComboBox1->Items->AddObject( "bbbbbbbbbbb", (TObject *)20 );
ComboBox1->Items->AddObject( "ccccccccccc", (TObject *)30 );
参照
Caption = (int)ComboBox1->Items->Objects[ComboBox1->ItemIndex];

ストリンググリッド(StringGrid)リバースカーソルを消す
void __fastcall TForm1::StringGrid1DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
  TStringGrid *sg = dynamic_cast(Sender);
  if( !sg->Focused( ) ){
    if( sg->Row == ARow && sg->Col == ACol ){
      sg->Canvas->Brush->Color = sg->Color;
      sg->Canvas->FillRect( Rect );
      sg->Canvas->Font->Color = sg->Font->Color;
      sg->Canvas->TextOut( Rect.Left + 2, Rect.Top + 2, sg->Cells[ACol][ARow] );
    }
  }
}

ストリンググリッド(StringGrid)セルの文字の色を変えてみる
void __fastcall TForm1::StringGrid1DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
  TStringGrid *sg = dynamic_cast(Sender);
  // 色を指定
  sg->Canvas->Font->Color = clBlue;
  // 文字を書き直す
  sg->Canvas->TextOut( Rect.Left + 2, Rect.Top + 2, sg->Cells[ACol][ARow] );
}
フォントやサイズも変更可能です。
特定のセルで行いたい場合はAColやARowでセルを指定します。

リストビュー(ListView)任意の位置にカーソルを移動する
int sp = 移動したいインデックス
// カーソルを移動
ListView1->Selected = ListView1->Items->Item[sp];
// その場所を表示
ListView1->Items->Item[sp]->MakeVisible( false );

リストビュー(ListView)任意の位置を編集状態にする
int sp = 編集したいインデックス
// 編集状態にする
ListView1->Items->Item[sp]->EditCaption( );

リストビュー(ListView)チェックボックスの変化に対応する
void __fastcall TMain::ListView1Change(TObject *Sender, TListItem *Item, TItemChange Change)
{
  if( (int)Item->Data != (int)Item->Checked ){
    / 変わった
  }
  Item->Data = Pointer( Item->Checked );
}

リストビュー(ListView)指定行の文字色を変更
OnCustomDrawItemイベント内で行います
if( (int)Item->Data == 2 ) Sender->Canvas->Font->Color = clRed;

ツリービュー(TreeView)任意の位置を編集状態にする
int sp = 編集したいインデックス
// カーソルを移動
TreeView1->Selected = TreeView1->Items->Item[sp];
// 編集状態にする
TreeView1->Items->Item[sp]->EditText( );

キャンバス(イメージ)画面(デスクトップ)のキャプチャー
HWND dc = GetDC( 0 );
BitBlt( Image1->Canvas->Handle, 0, 0, Screen->Width, Screen->Height, dc, 0, Screen->Height - Image1->Height, SRCCOPY );
ReleaseDC( 0, dc );

キャンバス(イメージ)一部分の再描画
例えばPaintBox1の左上100x100を再描画させる場合
TRect rect = Rect( 0, 0, 100, 100 );
InvalidateRect( PaintBox1->Parent->Handle, (LPRECT)&rect, true );

キャンバス(イメージ)ビットマップとJPEGイメージの相互変換
Jpeg.hppが無かったらインクルードしときます。

・JPEGをビットマップへ
TJPEGImage *jpg = new TJPEGImage;
jpg->LoadFromFile( "123.jpg" );
Image1->Picture->Bitmap->Assign( jpg );
delete jpg;
Image1->Picture->SaveToFile( "123.bmp" );

・ビットマップをJPEGへ
Image1->Picture->LoadFromFile( "123.bmp" );
TJPEGImage *jpg = new TJPEGImage;
jpg->Assign( Image1->Picture->Bitmap );
jpg->SaveToFile( "123.jpg" );
delete jpg;

キーボード&マウスマウスカーソルの表示/非表示
// 消す
Screen->Cursor = crNone;
// 出す
Screen->Cursor = crDefault;

キーボード&マウスマウスカーソルの移動範囲を制御する
以下はフォームからマウスカーソルを出さないようにしてます。
RECT r = BoundsRect;
ClipCursor( &r );

※ 上の例ではフォームを移動したらだめです。
※ 終了時には必ず移動範囲を戻しましょう。

キーボード&マウスキーバッファやマウスイベントをクリアする
MSG msg;
// キーボード
while( PeekMessage( &msg, Handle, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) );
// マウス
while( PeekMessage( &msg, Handle, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ) );

キーボード&マウスプログラムでキーボードを押したと思わせる
// Enterキーを押す
keybd_event( VK_RETURN, 0, 0, 0 );
// Enterキーを放す
keybd_event( VK_RETURN, 0, KEYEVENTF_KEYUP, 0 );

アイコンHWNDからアイコン(HICON)を取得する
以下の関数はスモールアイコンを取得します。
アイコンが取れない場合はNULLが返ると思います。
HICON GetHIcon( const HWND Wnd )
{
  HICON icon = (HICON)GetClassLong( Wnd, GCL_HICONSM );
  if( !icon ) icon = (HICON)SendMessage( Wnd, WM_GETICON, ICON_SMALL, 0 );
  if( !icon ) icon = (HICON)SendMessage( Wnd, WM_GETICON, ICON_BIG, 0 );
  return icon;
}

最後のSendMessageはICON_BIGとなっていますが、これはC++Builder5以前(4は不明)では 取れなかったので、これで取れます。(表示する側で16x16に縮小すると思うので・・・)

タスクトレイタスクトレイにアイコンを表示
ヘッダーの上の方に以下の行を追加。
#define WM_NOTIFY_TASKTRAY  (WM_USER + 1)

ヘッダーのprivate:に以下の行を追加します。
NOTIFYICONDATA  NotifyID;

以下の関数を追加。
void __fastcall TasktrayIcon( NOTIFYICONDATA *Notify )
{
  Notify->hWnd = Handle;
  Notify->uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  Notify->hIcon = Application->Icon->Handle;
  Notify->uCallbackMessage = WM_NOTIFY_TASKTRAY;
  Notify->cbSize = sizeof( NOTIFYICONDATA );
  Notify->uID = 1;
  lstrcpy( Notify->szTip, Application->Title.c_str( ) );
  Shell_NotifyIcon( NIM_ADD, Notify );
}

コンストラクタ辺りに以下の行を追加し、作成した関数を呼びます。
TasktrayIcon( &NotifyID );

Closeイベント辺りに以下の行を追加します。
Shell_NotifyIcon( NIM_DELETE, &NotifyID );

タスクトレイタスクトレイに表示したアイコンでマウスイベントを受ける
ヘッダーの
public: // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
の下あたりに以下の行を追加します。
protected:
void __fastcall WMTrayIcon( TMessage Msg )
{
  switch( Msg.LParam ){
    case WM_LBUTTONDBLCLK:   // 左ボタンダブルクリック
      Visible = Visible == true ? false : true;
      break;
    case WM_RBUTTONUP:      // 右ボタンクリック
      {
        POINT pos;
        GetCursorPos( &pos );
        SetForegroundWindow( Handle );
        PopupMenu1->Popup( pos.x, pos.y );
      }
      break;
    }
}
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER( WM_NOTIFY_TASKTRAY, TMessage, WMTrayIcon )
END_MESSAGE_MAP(TForm)

この例では、左ボタンダブルクリックで表示/非表示を切り替えし、 右ボタンクリックでポップアップメニューを表示してます。

タスクトレイタスクトレイに表示したアイコンをアニメーションしてみる
タスクトレイにアイコンを表示の続きです。
ImageListに表示したいアイコンを追加します。
タイマーイベントで順次アイコンを変更していきます。
まず、ImageListからアイコンをゲット(変数は適当に定義して下さい)します。
ImageList1->GetIcon( IconIndex, Icon );

で、NotifyIDにアイコンをセットします。
NotifyID.hIcon = Icon->Handle;

Shell_NotifyIcon( NIM_MODIFY, &NotifyID );を呼んでアイコンの変更をします。

クリップボード文字を転送/取得する
Clipbrd.hppをインクルードします。

Edit1の内容をクリップボードにコピー
Clipboard()->AsText = Edit1->Text;

クリップボードの内容をEdit1にコピー
if( Clipboard( )->HasFormat( CF_TEXT ) ){
  Edit1->Text = Clipboard( )->AsText;
}

クリップボード画像を転送/取得する
Clipbrd.hppをインクルードします。

Image1の内容をクリップボードにコピー
Clipboard( )->Assign( Image1->Picture );

クリップボードの内容をImage1にコピー
if( Clipboard( )->HasFormat( CF_BITMAP ) == true ){
  Image->Picture->Bitmap->Assign( Clipboard( ) );
}

ファイル名パスからドライブ名を取得
ExtractFileDriveを使います

ファイル名パスからドライブ名+ディレクトリを取得
ExtractFileDir   // 最後に¥が付かない
ExtractFilePath   // 最後に¥が付く

ファイル名パスからファイル名を取得
ExtractFileNameを使います

ファイル名パスからファイル名の拡張子を取得
ExtractFileExtを使います

ファイル名ファイル名の拡張子を変更する
ChangeFileExtを使います

ファイル名パスから拡張子無しのファイル名のみを取得する
// 自分のファイル名のみを取得
ExtractFileName( ChangeFileExt( Application->ExeName, "" ) );

その他二重起動の防止
プロジェクトソースに記述します。
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
  HANDLE mutexhandle = CreateMutex( NULL, false, "My program" );
  if( mutexhandle != NULL && GetLastError( ) == ERROR_ALREADY_EXISTS ){
    Application->MessageBox( "二重起動です", "確認", MB_ICONSTOP );
    CloseHandle( mutexhandle );
    return -1;
  }
  try
  {
    Application->Initialize();
    Application->CreateForm(__classid(TForm1), &Form1);
    Application->Run();
  }
  catch (Exception &exception)
  {
    Application->ShowException(&exception);
  }
  if( mutexhandle != NULL ) CloseHandle( mutexhandle );
  return 0;
}

CreateMutexの第3パラメータは適当に名前を入れます。