Skip to content

C++BuilderでTJvFilenameEditとTJvDirectoryEditを使ってみる

C++BuilderでTJvFilenameEditとTJvDirectoryEditを使ってみる。

■TJvFilenameEdit

TJvFilenameEditはファイル選択機能を持つ入力欄です。
入力欄に入力すると、ファイル名の候補が表示されます。
ボタンを押すとファイル選択ダイアログを表示し、ファイルを選択できます。

主なプロパティ

  • AddQuotesプロパティ
    AddQuotesプロパティがtrueのとき、選択されたファイル名は引用符で括られます。

  • AutoCompleteFileOptionsプロパティ
    オートコンプリートの設定を行います。

  • ClickKeyプロパティ
    ダイアログを表示するショートカットキーを選択します。

  • DialogKindプロパティ
    ダイアログの種類を選択します。

  • DialogOptionsプロパティ
    ダイアログの設定を行います。

  • DialogTitleプロパティ
    ダイアログのタイトルを設定します。

  • DirectInputiプロパティ
    入力欄への直接入力の可否を設定します。

  • Filterプロパティ
    ダイアログのファイルの種類を設定します。

主なイベント

  • OnButtonClickイベント
    ファイル選択ボタンが押された時に発生します。

  • OnBeforeDialogイベント
    ファイル選択ダイアログが表示される前に発生します。

    引数ANameを変更することで、ファイル選択ダイアログの初期値を変更することができます。

    引数AActionをfalseにすると、ファイル選択ダイアログは表示されません。

    void __fastcall TForm1::JvFilenameEdit1BeforeDialog(TObject *Sender, UnicodeString &AName,
              bool &AAction)
    {
      //ファイル選択ダイアログの初期値を設定
      AName = "C:\\test.txt";
    }
    
  • OnAfterDialogイベント
    ファイル選択ダイアログを表示した後に発生します。

    引数ANameには、選択されたファイルのファイル名が入ります。
    ANameの値を変更すると、選択されたファイルのファイル名が変更されます。

    引数AActionをfalseにすると、選択結果は反映されません。

    void __fastcall TForm1::JvFilenameEdit1AfterDialog(TObject *Sender, UnicodeString &AName,
              bool &AAction)
    {
      //拡張子が".txt"のときのみ選択を反映する
      AAction = (ExtractFileExt(AName).UpperCase() == ".TXT");
    }
    

■TJvDirectoryEdit

TJvFilenameEditはディレクトリー選択機能を持つ入力欄です。
入力欄に入力すると、ディレクトリー名の候補が表示されます。
ボタンを押すとディレクトリー選択ダイアログを表示し、ディレクトリーを選択できます。

主なプロパティやイベントはTJvFilenameEditと同じです。

■関連するページ

C++BuilderのClientToScreenメソッドでクリックされた画面上の座標を取得する

OnMouseDownイベントでは、コントロール上の座標が引数で渡されます。

ClientToScreenメソッドを使うと、このコントロール上の座標を画面上の座標に変換できます。

画面上の座標は、ScreenToClientメソッドでコントロール上の座標に変換できます。

void __fastcall TForm1::Button1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
  //コントロール上の座標
  Label1->Caption = Format(L"コントロール上の座標 X=%d Y=%d", ARRAYOFCONST((X, Y)));
  //画面上の座標
  TPoint screenPoint = Button1->ClientToScreen(TPoint(X, Y));
  Label2->Caption = Format(L"画面上の座標 X=%d Y=%d", ARRAYOFCONST((screenPoint.X, screenPoint.Y)));
  //フォーム上の座標
  TPoint formPoint = Form1->ScreenToClient(screenPoint);
  Label3->Caption = Format(L"フォーム上の座標 X=%d Y=%d", ARRAYOFCONST((formPoint.X, formPoint.Y)));
}

C++BuilderでTIBExtractコンポーネントを使い、Firebirdのメタデータを取り出す。

TIBExtractコンポーネントを使うと、テーブルやビューなどのメタデータを取り出すことができます。

TIBExtractExtractObjectメソッドで取り出すメタデータを指定します。

//すべてのメタデータを取り出す
IBExtract1->ExtractObject(eoDatabase);

//すべてのテーブルのメタデータを取り出す
IBExtract1->ExtractObject(eoTable);

//テーブル"TBL1"のメタデータを取り出す
IBExtract1->ExtractObject(eoTable, "TBL1");

■テーブルのメタデータを取り出すサンプルプログラム

Firebirdでテーブルを作成します。

CREATE TABLE TBL1 (
  COL1 INTEGER PRIMARY KEY,
  COL2 INTEGER NOT NULL,
  COL3 VARCHAR(100)
);

C++BuilderでTIBDatabase、TIBTransaction、TIBExtract、TMemo、TButtonコンポーネントを配置します。

TButtonコンポーネントのClickイベントを追加します。

//各コンポーネントのDatabaseプロパティとTransactionプロパティを設定します。
IBDatabase1->DefaultTransaction = IBTransaction1;
IBTransaction1->DefaultDatabase = IBDatabase1;
IBExtract1->Database = IBDatabase1;
IBExtract1->Transaction = IBTransaction1;

//Firebirdに接続します。
IBDatabase1->DatabaseName = FileName; //FDBファイルのパス
IBDatabase1->LoginPrompt = false;
IBDatabase1->Params->Clear();
IBDatabase1->Params->Add("user_name=sysdba"); //ユーザー名
IBDatabase1->Params->Add("password=masterkey"); //パスワード
IBDatabase1->Params->Add("lc_ctype=UNICODE_FSS"); //文字コード
IBDatabase1->Connected = true;

//メタデータを取り出し、メモコンポーネントに出力します。
IBExtract1->ExtractObject(eoTable, "TBL1");
Memo1->Lines->Text = IBExtract1->Items->Text;

//切断します。
IBDatabase1->Close();

実行したところ

■テーブルをコピーするサンプルプログラム

取り出したメタデータを編集して、同じフィールドを持つ別名のテーブルを作成します。

Firebird-jp-generalメーリングリストの「Re: テーブルのコピーについて」の投稿を参考にしました。

Firebirdでテーブルを作成します。

CREATE TABLE "TBL1" (
  COL1 INTEGER PRIMARY KEY,
  COL2 INTEGER NOT NULL,
  COL3 VARCHAR(100)
);

C++BuilderでTIBDatabase、TIBTransaction、TIBExtract、TIBSQL、TMemo、TButtonコンポーネントを配置します。

TButtonコンポーネントのClickイベントを追加します。

//各コンポーネントのDatabaseプロパティとTransactionプロパティを設定します。
IBDatabase1->DefaultTransaction = IBTransaction1;
IBTransaction1->DefaultDatabase = IBDatabase1;
IBExtract1->Database = IBDatabase1;
IBExtract1->Transaction = IBTransaction1;
IBSQL1->Database = IBDatabase1;
IBSQL1->Transaction = IBTransaction1;

//Firebirdに接続します。
IBDatabase1->DatabaseName = FileName; //FDBファイルのパス
IBDatabase1->LoginPrompt = false;
IBDatabase1->Params->Clear();
IBDatabase1->Params->Add("user_name=sysdba"); //ユーザー名
IBDatabase1->Params->Add("password=masterkey"); //パスワード
IBDatabase1->Params->Add("lc_ctype=UNICODE_FSS"); //文字コード
IBDatabase1->Connected = true;

//トランザクションを開始します
IBTransaction1->StartTransaction();

UnicodeString OldTable = "TBL1"; //コピー元のテーブル名
UnicodeString NewTable = "TBL2"; //新しいテーブル名

//コピー元のテーブルのメタデータを取得します
IBExtract1->ExtractObject(eoTable, OldTable);

//新しいテーブルを作成するSQLを組み立てます
IBSQL1->SQL->Text = StringReplace(
  IBExtract1->Items->Text, "\"" + OldTable + "\"", "\"" + NewTable + "\"",
  TReplaceFlags() << rfReplaceAll << rfIgnoreCase);

//SQLを実行します
IBSQL1->ExecQuery();

//コミットします
IBTransaction1->Commit();

//作成したテーブルのメタデータを確認します
IBExtract1->ExtractObject(eoTable, NewTable);
Memo1->Lines->Text = IBExtract1->Items->Text;

//切断します。
IBDatabase1->Close();

実行したところ

C++BuilderでをTJvDateEdit使ってみる。

C++BuilderでをTJvDateEdit使ってみる。

TJvDateEditはカレンダーを表示するボタンがついたエディットコントロールです。
ボタンを押すとカレンダーが表示され、日付を選択できます。

■主なプロパティ

  • ButtonFlatプロパティ

    trueのときはボタンを3D表示にします。

    ButtonFlatプロパティ
    falseのとき

  • ButtonHintプロパティ

    ShowHintプロパティがtrueの時に表示するボタンのヒントを指定します。

  • ButtonWidthプロパティ

    ボタンの幅を指定します。

    ButtonWidthプロパティ
    ボタンの幅を広くしたところ

  • CalendarHintsプロパティ

    カレンダーのボタン(前年・前月・翌月・翌年)のヒントを指定します。

    CalendarHintプロパティはTStrings型です。
    最初の文字列は前年、2番目の文字列は前月、3番目の文字列は翌月、4番目の文字列 は翌年のヒントになります。

    CalendarHintsプロパティ

  • CalendarStyleプロパティ

    ポップアップカレンダーの表示方法を指定します。

    csPopupのときはポップアップウィンドウ、csDialogのときはダイアログウィンドウで表示されます。

    CalendarStyleプロパティ
    ダイアログウィンドウで表示したところ

  • CheckOnExitプロパティ

    ユーザーが選択した日付を検証する時はtrueにします。
    trueにしたときは、コントロールがフォーカスを失った時にCheckValidDateメソッドが呼ばれます。
    入力された日付が不正な時はOnInvalidDateイベントが発生します。

    CheckOnExitプロパティ

  • ClickKeyプロパティ

    カレンダーを表示するキーの組み合わせを指定します。

  • Dateプロパティ

    入力されている日付を示します。

    JvDateEdit1->Date = Date();
    
  • DateAutoBetweenプロパティ

    入力された日付がMinDateプロパティとMaxDateプロパティの範囲外の時の動作を指定します。

    trueのときは自動的に範囲内の値に変更されます。
    falseのときは例外を投げます。

  • DateFormatプロパティ

    DateFormatPreferredプロパティがpdCustomまたはpdCustomOnlyのときの日付の書式を指定します。

    JvDateEdit1->DateFormatPreferred = pdCustom;
    JvDateEdit1->DateFormat = "dd/mm/yyyy";
    
  • DateFormatPreferredプロパティ

    どの日付書式形式文字列を使用するか指定します。

  • DefaultTodayプロパティ

    trueのときは日付の初期値に今日の日付を使用します。

  • DialogTitleプロパティ

    CalendarStyleプロパティがcsDialogのときの、ダイアログのタイトルを指定します。

    DialogTitleプロパティ

  • DirectInputプロパティ

    入力欄に直接入力することができるかどうかを指定します。

  • ImageIndexプロパティ

    ボタンの画像のインデックスを指定します。
    画像を使用する時はImageKindプロパティをikCustomにします。

  • ImageKindプロパティ

    ボタンの画像の種類を指定します。


    上から、ikDefault・ikDropDown・ikEllipsisです。

  • MaxDateプロパティ

    入力可能な最大の日付を指定します。

  • MinDateプロパティ

    入力可能な最小の日付を指定します。

    JvDateEdit1->Date = TDate(2012, 1, 15);
    JvDateEdit1->MinDate = TDate(2012, 1, 10);
    JvDateEdit1->MaxDate = TDate(2012, 1, 20);
    

    MaxDateプロパティとMinDateプロパティ

■主なイベント

  • OnAcceptDateイベント

    ユーザーが間レンダーで日付を選択した時に発生します。

    引数Actionの値をfalseにすると、選択された日付は反映されません。

    void __fastcall TForm1::JvDateEdit1AcceptDate(TObject *Sender, TDateTime &ADate, bool &Action)
    {
      //日曜日は選択できない
      Action = (Dateutils::DayOfTheWeek(ADate) != DaySunday);
    }
    
  • InvalidDateイベント

    CheckOnExitプロパティがtrueのとき、コントロールがフォーカスを失った時に入力された日付が不正な日付であれば、発生します。

■関連ページ

C++Builder XEでTThread.CreateAnonymousThreadを使ってみる。

前回の記事(DelphiのTThread.CreateAnonymousThreadと無名メソッドを使うと、簡単なスレッド処理なら手軽にかける)のDelphiのコードと同じ処理を、C++Builder XEで記述してみます。

元のDelphiのコード。

procedure TForm1.Button2Click(Sender: TObject);
begin
  Caption := 'Start';
  TThread.CreateAnonymousThread(
    procedure()
    begin
      Sleep(10000); //時間のかかる処理
      //Synchronizeメソッドを使う
      TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          Caption := 'OK';
        end);
    end).Start;
end;

C++Builder XEのコード。

//スレッドで行う処理
class TSleepFunc : public TCppInterfacedObject<TProc>
{
public:
  TSleepFunc(TForm* Form) : FForm(Form) {}
  virtual void __fastcall Invoke(void) {
    Sleep(10000); //時間のかかる処理
    //Synchronizeメソッドを使う
    TThread::Synchronize(TThread::CurrentThread, UpdateCaption);
  }
  void __fastcall UpdateCaption(void) {
    FForm->Caption = "OK";
  }
private:
  TForm* FForm;
};
void __fastcall TForm1::Button2Click(TObject *Sender)
{
  Caption = "Start";
  TThread::CreateAnonymousThread(new TSleepFunc(this))->Start();
}

無名メソッドの使えないC++Builder XEでは、TThread.CreateAnonymousThreadのメリットをあまり得られないように思いました。

DelphiのTThread.CreateAnonymousThreadと無名メソッドを使うと、簡単なスレッド処理なら手軽にかける

TThread.CreateAnonymousThreadを使うと、簡単なスレッド処理なら手軽に書くことができます。

CreateAnonymousThreadメソッドは引数にスレッドで行う処理を与えます。
処理は無名メソッドを使うと簡潔に記述できます。

class function CreateAnonymousThread(const ThreadProc: TProc): TThread; static;

返値のTThreadは一時停止の状態になっているので、Startメソッドを呼んで実行します。

TThread.CreateAnonymousThread(
  procedure()
  begin
    Sleep(10000); //時間のかかる処理
  end).Start;

次のサンプルプログラムでは、ボタン1はスレッドを使用しない処理、ボタン2ではスレッドを使用した処理になっています。
ボタン1を押すと処理が終わるまで入力できませんが、ボタン2を押すとすぐに入力欄に入力することができます。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption := 'Start';
  Sleep(10000); //時間のかかる処理
  Caption := 'OK';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Caption := 'Start';
  TThread.CreateAnonymousThread(
    procedure()
    begin
      Sleep(10000); //時間のかかる処理
      Caption := 'OK';
    end).Start;
end;


ボタン1を押すとフォームが固まる。
ボタン1は押された状態のまま。


ボタン2を押すとボタンはすぐに戻り、入力欄に入力できる状態になる。

無名メソッドを使っているため、スレッドからフォームのCaptionを簡単に操作できています。

ただし、メインスレッドのオブジェクトを安全に操作するには、Synchronizeメソッドを使う必要があります。

procedure TForm1.Button2Click(Sender: TObject);
begin
  Caption := 'Start';
  TThread.CreateAnonymousThread(
    procedure()
    begin
      Sleep(10000); //時間のかかる処理
      //Synchronizeメソッドを使う
      TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          Caption := 'OK';
        end);
    end).Start;
end;

TThread.CreateAnonymousThreadと無名メソッドを使うと、スレッドの処理を簡単に記述できます。

TThreadを継承したクラスを作成するのが面倒で、スレッドを使わずに手を抜いていたような場面が少なくなりそうです。

FirebirdでSEQUENCEを使う。

SEQUENCEは数値を数えるオブジェクトです。
新しい数値を取得したり、現在の数値を取得することができます。

データを登録時にPRIMARY KEYに新しい値を設定するときに、SEQUENCEがよく使用されます。

SEQUENCEはFirebird 2.0で導入されました。
Firebird 1.0からあったGENERATORと同じ機能を持ちます。

■SEQUENCEを作成する

CREATE SEQUENCE SEQUENCE名

create sequence seqtest

■SEQUENCEの値を変更する

ALTER SEQUENCE SEQUENCE名 RESTART WITH 新しい値

alter sequence seqtest restart with 0

■SEQUENCEを削除する

DROP SEQUENCE sequence-name

drop sequence seqtest

■SEQUENCEの次の値を取得する

NEXT VALUE FOR SEQUENCE名

select next value for seqtest from RDB$DATABASE

登録時にSEQUENCEの次の値を設定する例

insert into table1(field1, field2) values(next value for seqtest, 'test')

※「NEXT VALUE FOR」構文は標準SQLです。

Firebird 1.xではGEN_ID()を使います。

GEN_ID (SEQUENCE名, 増分値)

select GEN_ID(seqtest, 1) from RDB$DATABASE;

■SEQUENCEの現在の値を取得する

GEN_ID(SEQUENCE名, 0)

select GEN_ID(seqtest, 0) from RDB$DATABASE;

■TRIGGERでオートインクリメント

トリガーを使い、登録時にIDに値を設定する例

set term !! ;
CREATE TRIGGER T1_BI FOR T1
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
if (NEW.ID is NULL) then NEW.ID = GEN_ID(GEN_T1_ID, 1);
END!!
set term ; !!

■参考ページ

C++BuilderでTJvCsvDataSetを使ってみた

C++BuilderでTJvCsvDataSetを使ってみました。

TJvCsvDataSetを使うと、CSVファイルをテーブルのように扱うことができます。
VCLのデータベースコンポーネントを使用してCSVファイルの表示や編集が簡単にできました。

※TJvCsvDataSetはJVCLのコンポーネントです。JVCLをインストールすると使用できるようになります。

■CSVファイルの先頭行が列名の時

  1. TJvCsvDataSetコンポーネントをフォームに配置します。

  2. TJvCsvDataSetコンポーネントのFileNameプロパティでCSVファイルのファイル名を設定します。

  3. TDataSourceコンポーネントとDBGridコンポーネントを配置します。

  4. TDataSourceコンポーネントのTDataSetプロパティを設定します。

  5. TDBGridコンポーネントのDataSourceプロパティを設定します。

  6. TJvCsvDataSetコンポーネントのActiveプロパティをTrueに設定します。

    TDBGridコンポーネントにCSVファイルのデータが表示されます。

■CSVファイルの先頭行が列名ではない時

  1. TJvCsvDataSetコンポーネントをフォームに配置します。

  2. TJvCsvDataSetコンポーネントのFileNameプロパティでCSVファイルのファイル名を設定します。

  3. TJvCsvDataSetコンポーネントのHasHeaderRowプロパティをFalseに設定します。

  4. CscFieldDefプロパティの[...]ボタンを押して、CSVファイルの列の型を設定します。

    1. Field Name欄に列名を入力します。頭文字は英字、それ以降は英数字を使用できます。
    2. Field Type欄からデータ型を選択します。
    3. Length欄に列長を入力します。
    4. Modifyボタンを押して列を追加します。
    5. 修正する時はFields欄から列を選択し、入力が終わったらModifyボタンを押して変更を反映します。
    6. すべての列の設定が終わったら、OKボタンを押します。

  5. TDataSourceコンポーネントとDBGridコンポーネントを配置します。

  6. TDataSourceコンポーネントのTDataSetプロパティを設定します。

  7. TDBGridコンポーネントのDataSourceプロパティを設定します。

  8. TJvCsvDataSetコンポーネントのActiveプロパティをTrueに設定します。

    TDBGridコンポーネントにCSVファイルのデータが表示されます。

■データコントロールで編集する

  1. TDBEditコンポーネントを配置します。

  2. DataSourceプロパティとDataFieldプロパティを設定します。

TDBEditコンポーネントに値を入力すると、即座にCSVファイルに反映されます。

■参考

C++BuilderでTJvBrowseForFolderDialogを使ってみる。

TJvBrowseForFolderDialogは、フォルダーを選択するダイアログを表示するコンポーネントです。

※TJvBrowseForFolderDialogはJVCLのコンポーネントです。JVCLをインストールすると使用できるようになります。

■使い方

  1. 選択フォルダーの初期値を指定します。

    JvBrowseForFolderDialog1->Directory = "C:\\Documents and Settings\\yamamoto";
    
  2. ダイアログのルートフォルダーの位置を指定します。

    RootDirectoryプロパティでは、ルートフォルダーの位置をTFromDirectory型で指定します。

    JvBrowseForFolderDialog1->RootDirectory = fdMyComputer;
    

    RootDirectoryPathプロパティでは、ルートフォルダーの位置をパスで指定します。

    JvBrowseForFolderDialog1->RootDirectoryPath = "C:\\test";
    
  3. ダイアログの外観を設定します。

    JvBrowseForFolderDialog1->StatusText = "ステータステキスト";
    JvBrowseForFolderDialog1->Title = "タイトル";
    
  4. そのほかのダイアログの設定を行います。

    Optionsプロパティでダイアログの設定をTOptionsDir型で指定します。

    JvBrowseForFolderDialog1->Options << odEditBox << odIncludeFiles;
    
  5. ダイアログを表示する

    bool ret = JvBrowseForFolderDialog1->Execute();
    
  6. 選択されたフォルダーを取得します。

    //選択されたフォルダーのフォルダー名
    UnicodeString DisplayName = JvBrowseForFolderDialog1->DisplayName;
    //選択されたフォルダーのフルパス
    UnicodeString Directory = JvBrowseForFolderDialog1->Directory;
    

C++Builderで数値を3桁ごとにカンマで区切る

C++Builderで数値を3桁ごとにカンマで区切る方法。

FormatFloat関数にぴったりの指定子が用意されいます。

,(カンマ)
桁区切り記号。 書式文字列に 1 つ以上 ‘,’ 文字が含まれている場合、出力には小数点の左側の 3 桁ごとの各グループの間に桁区切り記号が挿入されます。

書式を次のように指定します。

FormatFloat(",0", 1234567890); //=> 1,234,567,890

実行例

FormatFloat(",0",          1); //=> 1
FormatFloat(",0",         12); //=> 12
FormatFloat(",0",        123); //=> 123
FormatFloat(",0",       1234); //=> 1,234
FormatFloat(",0",      12345); //=> 12,345
FormatFloat(",0",     123456); //=> 123,456
FormatFloat(",0",    1234567); //=> 1,234,567
FormatFloat(",0",   12345678); //=> 12,345,678
FormatFloat(",0",  123456789); //=> 123,456,789
FormatFloat(",0", 1234567890); //=> 1,234,567,890
1 / 13312345...102030...最後 »