LiveBindings 覚え書き
Live BindingsのサンプルとかがDBとの連携ばっかりで、自作Classとの連携とかのがあんま無かったので調べた事の覚え書き
フォームにTEdit2個とTCheckBox1個。TButtonを2個配置する。後は、TPrototypeBindSourceを1個配置。
データを保持するクラスとしてTUserDataを定義。
TUserData = class(TObject) private FInputBool: Boolean; FInputString1: string; FInputString2: string; procedure SetInputBool(const Value: Boolean); procedure SetInputString1(const Value: string); procedure SetInputString2(const Value: string); public property InputBool: Boolean read FInputBool write SetInputBool; property InputString1: string read FInputString1 write SetInputString1; property InputString2: string read FInputString2 write SetInputString2; end; { TUserData } procedure TUserData.SetInputBool(const Value: Boolean); begin FInputBool := Value; end; procedure TUserData.SetInputString1(const Value: string); begin FInputString1 := Value; end; procedure TUserData.SetInputString2(const Value: string); begin FInputString2 := Value; end;
TPrototypeBindSource に上記クラスのプロパティと連携する為にstringフィールド2個とBoolフィールドを1個作る。
そして、LiveBingindデザイナを使って関連付けを行う。
TPrototypeBindSource とTUserDataを関連付ける為に、TPrototypeBindSource.OnCreateAdapterでAdapterを作成する。
オブジェクトと関連付ける場合は、TObjectBindSourceAdapterを使う。Listと関連付ける場合はTListBindSourceAdapterを使う。
procedure TForm1.PrototypeBindSource1CreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter); begin ABindSourceAdapter := TObjectBindSourceAdapter<TUserData>.Create(Self, FData, False); end;
こちらによると、TPrototypeBindSource.OnCreateAdapterがFormのOnCreateよりも先に呼ばれる為に、TObjectBindSourceAdapterとかTListBindSourceAdapterに渡すオブジェクトはOnCreateで作成するんじゃなくて、コンストラクタで作成する必要がある模様。
constructor TForm1.Create(AOwner: TComponent); begin // TPrototypeBindSource.OnCreateAdapter が OnCreateForm よりも先に発生する // ので、OnCreateFormではなく、コンストラクタで初期化を行う FData := TUserData.Create; FData.InputBool := True; FData.InputString1 := '1'; FData.InputString2 := '2'; inherited; end;
これで、TPrototypeBindSourceを介してFormのEditやCheckboxとTUserDataが関連付けられました。
TUserDataに変更を行った後や、EditやCheckBoxのOnChangeイベントでTPrototypeBindSource.Refreshを呼ぶ事でフォームの表示とTUserDataの同期が取られます。
接続情報の確認
TFDConnection 接続エディタの情報タブに表示される情報。開発環境なら、TFDConnectionを配置すれば確認出来るんですが、実行環境でも確認出来ないかと調べて見た所
TFDConnection.GetInfoReport で同じ情報が取得出来るようです。
FormにTButtonとTMemoを配置して、Buttonのクリックイベントに下記コードを書けば取得出来ます
procedure TFDReportW.Button1Click(Sender: TObject); begin Memo1.Clear; FDConnection1.Params.DriverID := '*****'; FDConnection1.Params.UserName := '*****'; FDConnection1.Params.Password := '*****'; FDConnection1.Params.Database := '*****'; FDConnection1.Connected := True; FDConnection1.GetInfoReport(Memo1.Lines); FDConnection1.Connected := False; end;
Debug時のエラー
Delphiでプログラムを書いていざデバッグ実行を実行すると、ntdll.dllがどうのってエラーでIDEから落ちちゃってデバッグ不能って事態になったとき、レジストリエディタを起動して
DelphiXE8の場合
HKEY_CURRENT_USER\Software\Embarcadero\BDS\16.0\Debugging\Embarcadero Debuggers\Evaluators\comp32x.dll
の値を確認して、ここが1になっていたら-1に変更してみたらエラーが発生しなくなるかも
XE8以外のバージョンは16.0の部分を読み替えて下さい。
以下、このエラーに関するQP及びQC
Report No: 111022 Status: Closed Exception C0000026, Module ntdll.dll, Appcrash during start of application in debug mode http://qc.embarcadero.com/wc/qcmain.aspx?d=111022 QCWIN:Defect_No=111022
GetItについて
久々の更新。
XE8に追加されたパッケージ管理ツールのGetIt。ワンタッチでパッケージのインストール/アンインストールが出来る中々便利なツールです。
起動してみると判りますが、Delphi用とC++Builder用のそれぞれのパッケージが並んでいるので同じ名前のパッケージが2個ずつ並んでいます。
Delphi/C++Builder 単体で利用してる場合は、それぞれをインストールすれば良いので良いのですがRAD Studioを使ってる場合、両方で使いたいからDelphi用/C++Builder用の両方インストールすれば良いのかなとかって、両方インストールするとインストール自体は出来るんですが再起動とかした時にどちらかのパッケージがロード出来ませんてエラーに遭遇することになります。
RAD Studioの場合は、Delphi用をインストールすればとりあえずC++Builderでも使えるっぽいのでDelphi用のみをインストールしておけば良いのではないかと。
64bitプログラムからのmdbへのアクセス その2
前回Microsoft Access データベース エンジン 2010の32bit版と64bit版の共存は出来なそうという結論で終わっていたのですが、その後FireDACのマニュアルを見てる時にMSAccessへの接続のページでインストーラに/passive オプションを付けてインストールしたら良いという記述を見つけまして。検索してみたらこういうページも発見。
さっそく実験してみた所、32bit版officeがインストールされた私の環境に64bit版のデータベースエンジンをインストールする事が出来ました。
MDBにアクセスするテストプログラムを作って確認してみましたが、32bit/64bitどちらのプログラムからもMDBにアクセスする事が出来ました。
SelectDirectory と特殊フォルダ
タイムラインに「SelectDirectoryでルートをデスクトップからコンピュータに変更したい」ってのが流れてきたので調べた事のメモ。
SelectDirectoryは内部でSHBrowseForFolderを呼んでる。
SHBrowseForFolderのルートの指定は、BROWSEINFO構造体のpidlRootに値を指定します。このpidlRootがNilの場合はデスクトップがルートとして表示されます。
SelectDirectory関数の内部でどういう処理になっているかと言うと引数Rootに値が渡された場合DesktopのIShellFolderインターフェースを取得して、そのParseDisplayNameメソッドに引数Rootを渡してITEMIDLISTを取得しています。
ParseDisplayNameのヘルプによると、引数pszDisplayNameに「::{GUID}」の形で値を渡すことで特殊フォルダのITEMIDLISTを取得出来るようです。
SelectDirectoryの引数RootがpszDisplayNameに渡されるのでRootに「::{GUID}」を渡す事でフォルダ選択ダイアログのルートに特殊フォルダが指定出来るようです。
DelphiXE以降(2010は確認していないので不明)だと、ShlObj.pasにマイコンピュータ等のGUIDが定義されています。という事で下記のようにSelectDirectoryを呼ぶ事でコンピューターをルートとしてフォルダ選択ダイアログが表示されます。その他マイドキュメント(CLSID_MyDocuments)やコントロールパネル(CLSID_ControlPanel)なんかも定義されています。
ルートの指定を文字列でしないとダメなので色々調べましたが、ITEMIDLISTを引数に取るバージョンの関数とかをコピーして作った方が後々便利かもなーとか思いました。
uses FileCtrl, ShlObj; procedure TForm1.Button1Click(Sender: TObject); var SelectDir: String; begin SelectDirectory('', '::' + GUIDToString(CLSID_MyComputer), SelectDir); end;