« 2007年8月 | トップページ | 2007年10月 »

☆EM_CHARFROMPOSでカーソル位置を取得する。

TRichEditとTEdit、TMemoでは、EM_CHARFROMPOSの仕様が違うことを思い出しました。

// TEditの場合(TMemoも同じ)
procedure TForm1.Edit1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  CursolPos: Integer;
begin
  CursolPos := LoWord(Edit1.Perform(EM_CHARFROMPOS, 0, MakeLParam(X, Y)));
end;

// TRichEditの場合
procedure TForm1.RichEdit1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  Pt:TPoint;
  CursolPos: Integer;
begin
  Pt := Point(X,Y);
  CursolPos := RichEdit1.Perform(EM_CHARFROMPOS, 0, Integer(@Pt));
end;

TEdit、TMemoは、ランタイムテーマが有効時-文字数、無効時-バイト数を返しますが、TRichEditは、常にバイト数で返します。


MSDN
EM_CHARFROMPOS Message
http://msdn2.microsoft.com/en-us/library/ms672066.aspx

|

☆画像ファイルの判別

いろいろな画像形式のファイルが格納されているBlobフィールドから画像ファイルを取り出すとき、その形式を判別する必要がありますね。一つの方法として、登録時、別フィールドに拡張子を保存しておき、その情報を元にして取り出すことも可能ですが、下記サイトのヘッダー判別コードを使えば、拡張子に頼ることなく画像形式を決定することができます。


AWare Systems
Determining the file format from the data
http://www.awaresystems.be/techtalks/001_format_from_data.html

|

☆DBGridのColumn描画

ランタイムテーマを有効にしても、頑なに自分のスタイルを守るコンポーネントがあります。 DBGridもその中の一つで、スクロールバーやPickListのボタンは、いい感じなのにIndicatorやColumnは このように最悪です。

Dbgrid_1

※フォームやツールバーは、Delphi標準のコンポーネントではなく、TMS Software製TMS ToolBar Application Wizardから新規に作成したままの状態です。

そこで、Column部分を描画してみます。 Indicator部分は面倒なので、表示させないようにしています。 Indicatorも描画したいという方は、TCustomDBGrid.DrawCellを参考にして下さい。

宣言部です。
  TMyDBGrid = class(TDBGrid)
  protected
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
      AState: TGridDrawState); override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

実装部です。
uses
  GraphUtil;

constructor TMyDBGrid.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Options := Options - [dgIndicator];
end;

procedure TMyDBGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
  AState: TGridDrawState);
const
  AlignFlags : array [TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
var
  Text: String;
  Flags: LongInt;
begin
  inherited DrawCell(ACol,ARow,ARect,AState);

  if (ARow = 0) and (Columns.Count > ACol) then
  begin
    // 背景の描画
    SetBkMode(Canvas.Handle, TRANSPARENT);
    InflateRect(ARect, +1, +1);
    GradientFillCanvas(Canvas, clWhite, clGradientInactiveCaption,
      ARect, gdVertical);
    // カラム間の線
    Canvas.Pen.Color := clSilver;
    Canvas.MoveTo(ARect.Left +0, ARect.Top +1);
    Canvas.LineTo(ARect.Left +0, ARect.Bottom -1);
    // タイトルの描画
    Canvas.Font.Assign(TitleFont);
    Text := Columns[ACol].Title.Caption;
    Flags := DT_SINGLELINE or DT_VCENTER or AlignFlags[Columns[ACol].Title.Alignment];
    InflateRect(ARect, -2, -2);
    DrawText(Canvas.Handle, PChar(Text), Length(Text), ARect, Flags);
  end;
end;


こんな風になりました(^^;

Dbgrid_2

|

☆ExcelをADOで操作する。

フォームにADOConnection1、ADOTable1、DataSource1、DBGrid1を配置し、いつものように?設定します。

ADOConnection1の設定です。
ADOConnection1.ConnectionString := 
 'Provider=Microsoft.Jet.OLEDB.4.0;' +
 'Data Source=C:\master.xls;' +
 'Extended Properties=EXCEL 8.0';
ADOConnection1.LoginPrompt := False;

次にADOTable1の設定です。ポイントは、TableNameでシート名を[ ]で囲うことです。これをしないと「FROM 句の構文エラーです。」と表示され、ファイルをオープンすることができません。TableNameをオブジェクトインスペクタで選択した場合には、[ ]がないので要注意です。
ADOTable1.Connection := AdoConnection1;
ADOTable1.TableName := '[sheet1$]';
ADOTable1.Active := True;  


これでExcelの内容がDBGridに表示されるようになりました。

Design



ADOConnection1、ADOTable1をクローズします。
そして、実行時にファイルをオープン/クローズする処理を書きます。
procedure TForm1.FormCreate(Sender: TObject);
begin
  ADOTable1.Open;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ADOTable1.Close;
  ADOConnection1.Close; //念のため
end;  



ADOでの操作では追加や編集は可能ですが、行を削除をしようとすると次のようなエラーメッセージが表示されます。

Del_err

ということで、行の削除はできないという仕様らしいです。 又、排他的に開かれているので、このプログラムを実行しているときにはExcel等で開くことはできないです。


[参考にした書籍]

Marco Cantu
Delphi6プログラミングバイブル

|

☆プロジェクトのバージョン番号が設定できない。

次のように、オプションのバージョン情報で 「バージョン番号を含める」設定用チェックボックスが無効になっていました。

Ver


アプリケーションのアイコンの読み込みボタンも無効だったのでリソースの問題かなと思い、 ソースを見てみると、次のようになっていました。
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

ん?何か足りないような・・・?

ということで、新規に作成したものと比較してみます。
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

そう、原因はわからないけど、{$R *.res}が消えていたんですね。
これを書き加えて、無事解決しました。

|

☆TWebBrowserのフォントサイズ変更

TWebBrowserのフォントサイズを実行時にアプリ側から変更するサンプルです。ついでに現在のフォントサイズを取得する処理も書いてみました。フォントサイズについては、よくわからないのですが、下記のサイトで0~4となっていて、IEの「文字のサイズ」が5段階であることから、これに該当すると勝手に判断しています。
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OleCtrls, SHDocVw, StdCtrls;

type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    WebBrowser1: TWebBrowser;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure WebBrowser1DocumentComplete(ASender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);
  private
    F: Boolean;
    function GetFontSize: Integer; 
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  // ComboBox1の設定
  ComboBox1.Items.Clear;
  ComboBox1.Style := csDropDownList;
  ComboBox1.Items.AddObject('最小',TObject(0));
  ComboBox1.Items.AddObject('小'  ,TObject(1));
  ComboBox1.Items.AddObject('中'  ,TObject(2));
  ComboBox1.Items.AddObject('大'  ,TObject(3));
  ComboBox1.Items.AddObject('最大',TObject(4));
  F := False;
  // delphi-fanはサイズの違いがわかりにくいです(^^;
  // 適当に変えて下さい。
  WebBrowser1.Navigate('http://hiderin.air-nifty.com/delphi/');
end;

// 現在のフォントサイズを返します。
function TForm1.GetFontSize: Integer;
var
  Size: OleVariant;
begin
  WebBrowser1.ExecWB(OLECMDID_ZOOM,
    OLECMDEXECOPT_DONTPROMPTUSER, EmptyParam, Size);
  Result := Size;
end;

procedure TForm1.WebBrowser1DocumentComplete(ASender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
begin
  // プログラム起動時に現在のフォントサイズを設定します。
  if not F then
  begin
    ComboBox1.ItemIndex := GetFontSize;
    F := True;
  end;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
var
  Size: OleVariant;
begin
  // フォントサイズを変更します。
  Size := Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]);
  WebBrowser1.ExecWB(OLECMDID_ZOOM,
    OLECMDEXECOPT_DONTPROMPTUSER, Size, EmptyParam);
end;

end.

この処理の問題点としては、TWebBrowserを使う他のアプリケーションにまで、ここで設定したフォントサイズが 影響することです。(IEには、影響しません)
影響を受けていないように見せるためには、アプリケーション毎に INIファイル等で設定を保存する必要がありそうです。ちょっと面倒です(笑)

Microsoft
サポート オンライン
Visual Basic アプリケーション内にホストされた WebBrowser コントロールのフォント サイズを変更する方法
※例によって機械翻訳されたものです。

|

☆TToolButtonの実行時作成&削除

あまり使うことはないと思うのですが、ファイルにキャプション一覧を登録しておき、それを読み込んでToolButtonに設定する処理です。 ポイントは、ToolBarのAutoSizeとShowCaptionを一時的に無効にすることです。この処理により、キャプションの入れ替え時に一瞬ちらつきますが、この処理を入れないと、ボタンが設定されていく様子が見えるぐらい遅くなります。

procedure TForm1.Button1Click(Sender: TObject);
var
  SL: TStringList;
  S: String;
  I: Integer;
  TB: TToolButton;
begin
  ToolBar1.AutoSize := False;
  ToolBar1.ShowCaptions := False;
  try
    // 全てのボタンを削除します。
    for I := ToolBar1.ButtonCount -1 downto 0 do
      ToolBar1.Buttons[I].Free;

    SL := TStringList.Create;
    try
      // キャプション用リストを読み込みます。
      S := ExtractFilePath(Application.Exename) + 'List.txt';
      SL.LoadFromFile(S);
      for I := SL.Count - 1 downto 0 do
      begin
        // TToolButtonの生成
        TB := TToolButton.Create(Self);
        TB.Parent := ToolBar1;
        TB.Caption := SL[I];
        TB.OnClick := nil; // 必要なイベントを設定
      end;
    finally
      SL.Free;
    end;
  finally
    ToolBar1.ShowCaptions := True;
    ToolBar1.AutoSize :=  True;
  end;
end;

|

■RAD Studio 2007 レビュー紹介

iPentecさんがRAD Studio 2007 レビューを載せておられます。
いつもながら早くて、的確なレビューに感心させられるばかりです。
※私はまだ購入していないので、よくわかりませんが(^^;

iPentec
Delphi2007 情報
http://www.ipentec.com/delphi/delphi2007/index.html

|

■イベントが自動作成される位置

■コードエディタが・・・。 で書いていた「ダブルクリックした時に、どこにイベントが自動作成されるのか」という疑問と同じ内容が [borland.public.delphi.non-technical] Code Insertion というツリーで展開されています。
回答として、ランダムな配置ではなく、基本はアルファベット順、そしてアルファベット順が一度崩れてしまうと、ファイルの最後に作成する というようなコメントがあります。 今後どのような話になるのか、注目しています。

|

■Absolute Database v.5.14

☆Paradoxに代わるもの で紹介したAbsolute Databaseがv.5.14になりました。
いくつかの軽微なバグを修正したとのことです。

ComponentAce
http://www.componentace.com/

|

☆よみがなを取得する。

エクセルで作られた名簿をよみがなで五十音順に並べたいと相談を受けました。
「簡単やし、メールしておいて」
そして届いた名簿は・・・なんと漢字の名前が並んでいるだけ・・・。
これだけで、よみがなで並び替えができると思っているなんてすごい(^^;
ということで、よみがな入力から始めることになりました。
とりあえず漢字からよみがなを変換し、それを確認してもらい、無事作業を終了しました。

よみがなを取得する関数です。
uses
  Imm;

function GetYomi(Str: String; var SL: TStringList): Boolean;
var
  IMC: HIMC;
  KL: HKL;
  lpDst: PCandidateList;
  Offset: DWORD;
  I, Size: Integer;
  P: PChar;
  S: String;
  DummyEdit: TEdit;
begin
  DummyEdit := TEdit.Create(nil);
  DummyEdit.Width := 1;
  DummyEdit.Parent := Application.MainForm;
  DummyEdit.Left := 1000;
  DummyEdit.Top := 1000;
  Application.MainForm.ActiveControl := DummyEdit;

  SL.Clear;
  Result := False;

  IMC := ImmGetContext(DummyEdit.Handle);
  try
    if IMC = 0 then Exit;

    KL := GetKeyboardLayout(0);
    Size := ImmGetConversionList(KL, IMC, PChar(Str), nil, 0,
      GCL_REVERSECONVERSION);
    GetMem(lpDst, Size);
    try
      ImmGetConversionList(KL, IMC, PChar(Str), lpDst, Size,
        GCL_REVERSECONVERSION);
      P := PChar(DWORD(lpDst) + lpDst^.dwOffset[1]);

      Offset := 0;
      for I := 0 to lpDst^.dwCount - 1 do
      begin
        P := PChar(DWORD(P) + Offset);
        S := String(P);
        Offset := Length(S) + 1 ;
        // なぜか同じ読みを複数取得するので、同じものは追加させない。
        if SL.IndexOf(S) < 0 then
          SL.Add(S);
      end;
      Result := True;
    finally
      FreeMem(lpDst);
    end;
  finally
    ImmReleaseContext(DummyEdit.Handle, IMC);
    DummyEdit.Free;
  end;
end;


上記関数の使用例です。
procedure TForm1.Button1Click(Sender: TObject);
var
  SL: TStringList;
begin
  SL := TStringList.Create;
  try
    if GetYomi(Edit1.Text, SL) then
      ListBox1.Items.Assign(SL)
    else
      ShowMessage('取得できませんでした');
    Button1.SetFocus;
  finally
    SL.Free;
  end;
end;


[参考にしたサイト]

Programming Library
Delphi Q & A掲示板
漢字からかなへの変換

MSDN
Input Method Editor (IME)

|

☆トランスレーションマネージャーを使ってみる。

第6回 CodeGearデベロッパーキャンプで、株式会社ミガロ 吉原泰介氏が紹介されていた多言語対応機能を試してみました。

メニュー→プロジェクト→言語→追加を選択します。

Trans1


以下の通り、言語の追加、確認、処理完了のダイアログが表示されます。

Trans2_2

今回、英語(米国)を選択します。

Trans3_2

Trans4_2

Trans5_2

Trans6_2

Trans7

Trans8


プロジェクトマネージャーにProject1.ENUが追加されています。

Trans9


Project1.ENUの下のUnit1.dfmをダブルクリックすると、トランスレーションエディタが表示されます。 ここで日本語に対応する英語を入力します。

Trans10


メニュー→プロジェクト→言語→アクティブ言語の設定を選択します。

Trans11_2


日本語のアプリケーションです。

Japan


こちらは英語のアプリケーションです。トランスレーションエディタで&Copyとか入力しているのに、なぜかアクセラレーターキーが設定されていません。

English


私自身、他言語対応など全く縁のない話ですが、いろいろな言語バージョンも結構簡単にできるんだという印象を持ちました。ただ、日本語OS上でコンパイルしたものを、他言語OS上で試していないため、本当に大丈夫なの?って、少し不安に感じますけど(^^;

第6回 CodeGearデベロッパーキャンプ  資料ダウンロード
【T2】Delphiテクニカルセッション
「知って得する!現役ヘルプデスクが答えるDelphiテクニカルエッセンス」
株式会社ミガロ RAD事業部 技術支援課 顧客サポート 吉原泰介
プレゼンテーション資料:PDF(683KB)

|

■Delphi 2007 Handbook

Delphi6プログラミングバイブルの著者 Marco Cantù氏の最新本が発売されました。(英語ですけど)
彼自身の紹介でMastering Delphi seriesのベストセラー作家とありますが、 今回はなぜか自費出版のようです。

Lulu.comというサイトだけで購入可能なようで、Amazon他では取り扱っていないそうです。
自費出版なら、PDFでダウンロード販売とかしてくれないかな。

Delphi 2007 Handbook
http://www.marcocantu.com/dh2007/

|

■RAD Studio Japanese HotFix 1

何気なくスタートメニューにあるアップデートの確認をクリックしてみたら 次のようなダイアログが表示されました。

Hotfix1_1

RAD Studio Japanese HotFix 1なんて、Delphi 2007 for Win 32 Registered User Downloadsにも公開されていないですよね。
日本語版だけsystem.pasが欠落してるの??これって、Update3用?
少し不安に感じながらも、実行させてみました。

system.pasだけが更新されたようです。

Hotfix1_2

|

■履歴マネージャ

昨日、コードを書いてると今まで見たことがない画面が現れました。
リビジョン内容??ん?内容、情報、相違タブって??

初めて、履歴マネージャの存在を知った瞬間でした(笑)

コードとデザインの切り替えには、F12(ショートカット)かツールバーしか使っておらず、 コードエディタ下に履歴なんてタブがあることすら気付かずにいました。
(_Historyフォルダについても、自分できちんとバックアップ取ってるし、こんなフォルダいるのかな? なんて思ってたりして)

ところが今回、偶然、マウスで履歴タブをクリックしたらしく、新たな発見に至ったわけです(^^;
なんとも頼りないDelphi使いです。

|

☆英単語の検索

CodeGearのニュースグループを始め、英文に触れる機会が多いですよね。
わからない英単語を調べるのに私は、英辞郎 on the WEBを利用させて頂いてます。

今回は、英辞郎 on the WEBを利用する処理を考えてみます。
Edit1, WebBrowser1, Button1をフォームに配置し、次の処理をさせます。
uses
  HTTPApp;

procedure TForm1.Button1Click(Sender: TObject);
const
  S1 = 'http://eow.alc.co.jp/';
  S2 = '/UTF-8/';
var
  S: String;
begin
  S := S1 + HTTPEncode(AnsiToUtf8(Edit1.Text)) + S2;
  WebBrowser1.Navigate(S);
end;
これだけで、英和・和英の辞書が完成します。
しかし、不明な単語をいちいちコピーして、貼り付けて、検索させるとなると面倒ですよね。
私は、クリップボードを監視して、コピーされたときに自動で検索させるようにしています。
ぜひ実装してみて下さい。

※英辞郎 on the WEBでは、データの転載は禁じられていますので、ご注意を。
※今後、アドレス変更他の理由により、この処理では利用できなくなることもあります。


SPACE ALC
英辞郎 on the WEB
http://www.alc.co.jp/

Delphi Tips
クリップボードが更新された時のイベントを取得する
http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=10

|

■第7回 CodeGearデベロッパーキャンプ

2007年10月23日、東京・秋葉原コンベンションホールにて、 第7回 CodeGearデベロッパーキャンプが開催されます。

今回は、DelphiプロダクトマネージャのNick Hodges氏が来日されるそうです。

詳細はこちら
第7回 CodeGearデベロッパーキャンプ10月23日に開催、いよいよ申込受付開始!

|

■if~then~elseの表記法

いつもコードを書いてて思うのですが、if~then~elseの表記って何か決まりがあるんでしょうか? Delphiの名前空間のソースを見てても、次のようないろいろな表記法があります。 もしよろしければ、みなさんの表記法を教えて下さいね。[20070921投票を終了しました]

[A]
  if true then
    begin
      a := 1;
      b := 2;
    end
  else
    begin
      a := 3;
      b := 4;
    end;
[B]
  if true then begin
    a := 1;
    b := 2;
  end else begin
    a := 3;
    b := 4;
  end;
[C]
  if true then
  begin
    a := 1;
    b := 2;
  end else
  begin
    a := 3;
    b := 4;
  end;



ちなみに私は[A]派です。以前、[B]派の方から、[A]は冗長な上にソースが読みづらいと いう意見を頂いたこともあります。私は[C]ならいいけど、[B]はちょっと抵抗があります(^^;



[20070921 集計&追記]

投票して頂いたみなさん、どうもありがとうございました。
結果は、[A]9票、[B]9票、[C]4票、[その他]13票となりました。

しかしながら、ここで設問の選択肢が不適切だったことをみなさんにお詫びします。
c-yanさんより、Delphi標準の表記法が選択肢になく、 そのため、多くの方が[その他]を選択せざるを得ないのではないかという意見を頂きました。 そして、そのDelphi標準表記法の根拠として下記のサイトを教えて頂きました。

Object Pascal Style Guide
http://dn.codegear.com/article/10280#8.2.3

確かに選択肢[A]は、インデントがついているためこの表記とは違うものになっており、 この標準表記が選択肢にはありません。今回、みなさんにややこしい質問をしてしまったことを反省しつつも、みなさんの表記法やCodeGearのガイドなど いろんなことを教えて頂き、感謝の気持ちでいっぱいです。
これからもよろしくお願いします。

|

■Delphi 2007 Update3 (ISO版)

ISO版も公開されているようです。
(な、なんと4.16GBもあります)

Delphi 2007 for Win 32 Registered User Downloads
Delphi 2007 for Win32 R2/Update 3 ISO


[20070920追記]
2007年9月19日付 【CodeGearニュースレター号外】によりますと、「ファイルサイズが 4GBを超えるため IE以外のブラウザをお使いください。」と注意事項がありました。4GBを超えるとIEが使えない理由がよくわかりませんが、いろいろあるんですね。

|

☆ADOQueryを使ってImage型に書き込みする。

以前、ADOQueryを使ってImage型を読み書きする。 という記事を書きましたが、その中で「Image型フィールドに書き込みます。」部分は次のような単純な処理でも可能なようです。

procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Edit;
  (ADOQuery1.FieldByName('IMG') as TBlobField).LoadFromFile('c:\aa.jpg');
  ADOQuery1.Post;
end;

[参考]
CodeGear NewsGroup
borland.public.delphi.database.ado
JPEG into BLOB field

|

■CodeGear Developer Network JP Search Engineの紹介

みなさん既にご存知かも知れませんが、某所|避難所のRANさんが
CodeGear Developer Network JP Search Engine
を公開されています。

CodeGearのサイトは、有意義な情報がたくさんあるのに、なかなか見つけ出すことができないんですよね。 活用させて頂きたいと思います。

但し、jpのサイト(*****.codegear.com/jp/*****)と言っても、英語の情報がたくさんあるので、 英単語での検索では日本語以外の情報もヒットします。
くれぐれもJP Search Engineなのに?って、疑問に思わないようにね(笑)


某所|避難所
http://bousyo.blog45.fc2.com/

CodeGear Developer Network JP Search Engine
http://www.google.com/coop/cse?cx=012604726912584965383%3Arnif1xfm3i0&hl=ja

|

☆標準の編集PopupMenuが・・・??

Delphi2007で作成したプログラムを、知人に渡したのですが、 文字入力部分での右クリックで編集メニューがほしいと言われました。

そのプログラムでは、特に何もしていないので、標準のものがあるはずだし、 おかしいなと思いながら、いろいろ試してみると、標準の編集PopupMenuが出てこないようです。

下記の要領で試してみて下さい。
フォームにTMemo、TEditを配置して、そのまま実行します。
右クリックで出てくるはずのPopupMenuが表示されません。

なんで?



[以下、20070917追記]

調べてみるとこの問題について、既にニュースグループで話題になっていました。

解決方法は、
borland.public.delphi.vcl.componens.using.win32
Tmemo in Delphi 2007 Update3ツリーでの
Peter Below(TeamB)氏のコメントをご覧下さい。

但し、私が試したところでは、TEdit、TMemoは、標準のPopupMenuが表示されましたが、RichEditは、メモリアクセス違反が発生しました。


CodeGear
Delphi Newsgroups
http://support.codegear.com/newsgroups/directory/delphi

borland.public.delphi.vcl.componens.using.win32
Tmemo in Delphi 2007 Update3

borland.public.delphi.ide.general
D2007 Upd3: Lost standart Popup menus for TEdits, TMemos, TRichEdit

|

☆フォントの取得・描画

今更ですが、フォントを列挙するだけなら、次の処理で簡単にできます。
procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Assign(Screen.Fonts);
end;

その列挙したフォントをListBoxのDrawItemを使って、自分自身のフォントで描画させます。 このときCharSetを正しく設定しないと、きちんと描画できません。 次の処理では、SHIFTJIS_CHARSET以外はANSI_CHARSETと判断させていますが、正しくは全てのCharSetについて処理が必要です。 CharSetを取得させるため Screen.Fonts ではなくEnumFontFamProc API を使っています。
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure ListBox1MeasureItem(Control: TWinControl; Index: Integer;
      var Height: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    TempFont: TFont;
    procedure GetFontName;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// フォントを列挙する際に利用するアプリケーション定義のコールバック関数
function EnumFontFamProc(var EnumLogFont: TEnumLogFont;
  var NewTextMetric: TNewTextMetric;
  FontType: Integer; LPARAM: Longint): Integer; stdcall; export;
begin
  with Form1 do
  begin
    Result := 1;
    if (EnumLogFont.elfLogFont.lfCharSet = SHIFTJIS_CHARSET) then
      ListBox1.Items.AddObject(EnumLogFont.elfFullName, TObject(0))
    else
      ListBox1.Items.AddObject(EnumLogFont.elfFullName, TObject(1));
  end;
end;

// 初期設定
procedure TForm1.FormCreate(Sender: TObject);
begin
  TempFont := TFont.Create;
  SystemParametersInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, nil, 0);
  ListBox1.Font.Size := 24;
  GetFontName;
end;

// 終了処理
procedure TForm1.FormDestroy(Sender: TObject);
begin
  TempFont.Free;
end;

// フォント名の取得
procedure TForm1.GetFontName;
begin
  ListBox1.Clear;
  EnumFontFamilies(Canvas.Handle, nil, @EnumFontFamProc, 0);
  ListBox1.Refresh;
end;

// フォントの描画
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  S: String;
begin
  // CHARSETの設定
  if (Integer(ListBox1.Items.Objects[Index]) = 1) then
    ListBox1.Canvas.Font.Charset := ANSI_CHARSET
  else
    ListBox1.Canvas.Font.Charset := SHIFTJIS_CHARSET;
    
  // フォント名の設定
  ListBox1.Canvas.Font.Name := ListBox1.Items[Index];
  ListBox1.Canvas.Font.Size := ListBox1.Font.Size;
  ListBox1.Canvas.FillRect(Rect);

  // 描画
  S := ListBox1.Items[Index];
  DrawText(ListBox1.Canvas.Handle, PChar(S), -1, Rect,
    DT_LEFT or DT_SINGLELINE or DT_VCENTER);
end;

// ListBoxアイテムの高さを設定します。
procedure TForm1.ListBox1MeasureItem(Control: TWinControl; Index: Integer;
  var Height: Integer);

  // フォントの高さをピクセルで返します。
  function GetFontHeight(const F: TFont): Integer;
  begin
    Result := Abs(Trunc((-F.Size * F.PixelsPerInch) / 72))
      + (F.Size div  2); // 余白
  end;
begin
  if (Integer(ListBox1.Items.Objects[Index]) = 1) then
    TempFont.Charset := ANSI_CHARSET
  else
    TempFont.Charset := SHIFTJIS_CHARSET;
  TempFont.Name := ListBox1.Items[Index];
  TempFont.Size := ListBox1.Font.Size;
  Height := GetFontHeight(TempFont);
end;

end.


[参考にしたサイト]
MSDN
EnumFontFamProc

|

☆ListBoxのDrawItem No2

前回は、ListBoxのバグをアニメーション表示を無効にすることで回避しましたが、フォームのMouseWheelDown、 MouseWheelUpを使って、次のような処理でも回避できます。
procedure TForm1.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
const
  Value = 1;
begin
  if (ActiveControl is TListBox) and
    ((ActiveControl as TListBox) = ListBox1) then
  begin
    ListBox1.TopIndex := ListBox1.TopIndex + Value;
    Handled := True;
  end;
end;

procedure TForm1.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
const
  Value = -1;
begin
  if (ActiveControl is TListBox) and
    ((ActiveControl as TListBox) = ListBox1) then
  begin
    ListBox1.TopIndex := ListBox1.TopIndex + Value;
    Handled := True;
  end;
end;

Valueの値を変えて、スクロールの移動量も変えたりするようにプログラムを修正することもできますね。

|

☆ListBoxのDrawItem No1

ListBoxにフォントを一覧表示するプログラムを作ってみました。 よくある自分自身のフォントでフォント名を表示させるものです。 しかしマウスをスクロールさせると表示がどうもおかしいです。
マウスを上に回転させても下に回転させても、アニメーションが上からの表示になっています。 しばらく使っていると目が回ってしまいます(笑)

いろいろと調べてみるとMicrosoftのページに、次のようなものがありました。
(2005年1月24日付になっているので、私だけが知らなかったのかも知れませんね)

BUG: ListBox コントロールは、 Windows 2000 または Windows XP で間違った方向にスクロールすることが表示されます。
(機械翻訳なので日本語が変ですね)
[引用]
現象
キーボードを使う、またはスクロール バーを使用する場合、スクロールするとき、
オーナー描画 ListBox コントロールが間違った方向の内容をスクロールすることが 
Microsoft Windows 2000 と Windows XP で表示されます。 
下でスクロールするとき、 smooth-scroll アニメーションが ListBox コントロールの
内容が上にスクロールされることが表示されるのを行います。 ListBox コントロール
が間違った方向にスクロールすることが表示されるものの、 smooth-scroll アニメ
ーションが完了したら、正しい位置にリストアイテムがあります。

回避策としては、アニメーションをさせないということなので、次のような処理をしました。
procedure TForm1.FormCreate(Sender: TObject);
begin
  SystemParametersInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, nil, 0);
  GetFontName;
end;


Microsoft サポートオンライン
BUG: ListBox コントロールは、 Windows 2000 または Windows XP で間違った方向にスクロールすることが表示されます。

|

■Delphi 2007 Update3 (ZIP版)

あちらこちらでUpdate3がインストールができないという話があります。
大きなファイルをインターネットに接続しながらインストールするというスタイルなのでエラーが起こりやすいのかも知れませんね。

CodeGearからフルサイズのUpdate3ファイル(ZIP)をダウンロードできるようになりました。


CodeGear
ID: 25014, Delphi 2007 for Win32 Update 3 - full .zip version

|

☆TComboBoxでの文字化け

Delphi User's Forum で quest さんから教えて頂いたんですが、TComboBoxには、全角文字を適当に入力して、そのままBackSpaceを押すと文字化けするという問題があります。

この現象は、
  「ランタイムテーマを有効」 and 「AutoCompleteを有効
の時に発生します。


回避方法は、
1.「ランタイムテーマを無効」
2.「ランタイムテーマを有効」 and 「AutoCompleteを無効
のいずれかですね。

先日書いたTEditのSelTextと同じようにWindowsAPIの仕様変更の影響を受けているのかも知れませんね。


[情報元はこちら]

Delphi User's Forum
http://fdelphi.com/

|

■サーフィンをする猿が消えました。

GUNGLAって何? で書いてた「サーフィンをする猿」が消え、又、デスクトップ全体にアニメーション表示させていたスタッフの名前が バージョン情報のダイアログ内で普通にロールアップするようになっていますね。 これって、Update3で修正されたのかな?まあ、どうでもいいんですけど(笑)

|

■ナッキーのDelphiはじめて奮戦記

大阪でのデベロッパーキャンプで、高橋智宏氏と話をさせて頂いてたときに
WEBでの『ナッキーの「Turbo Delphiはじめて奮戦記」』を本にするという話を聞いていました。
それがようやく完成したようですね。おめでとうございます。

その時、話をさせて頂いてた価格ですが・・・2800円+税
書籍としては、まあ妥当な価格じゃないでしょうか(^^;


佐竹那月・著
『ナッキーのDelphiはじめて奮戦記』
9月22日頃発売


[情報元はこちら]

Allegro Barbaro
2007年09月13日
技術情報執筆の難しさ、併せて新刊本の紹介

|

☆ファイルを扱うときのテンプレート?

ファイルを開いたり、保存したりという処理の中で、ファイルの内容が変更されている場合は、その処理をユーザーに選択させますよね。 今回、その一連の流れをまとめてみました。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ActnList;

type
  TForm1 = class(TForm)
    ActionList1: TActionList;
    acNew: TAction;
    acSaveAs: TAction;
    acOpen: TAction;
    acSave: TAction;
    procedure FormCreate(Sender: TObject);
    procedure acNewExecute(Sender: TObject);
    procedure acOpenExecute(Sender: TObject);
    procedure acSaveAsExecute(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure acSaveExecute(Sender: TObject);
  private
    FN: String;        // 作業中のファイル名
    Modified: Boolean; // データが更新されたときにTrueに設定する。
    function ConfirmingDialog : Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// 現在作業中のファイルをどうするのかをユーザーに示して処理させます。
function TForm1.ConfirmingDialog : Boolean;
var
  I: Integer;
begin
  Result := True;
  if not Modified then Exit;

  Result := False;

  // 現在のデータが変更されている場合の確認
  I := MessageDlg(Format('%sは変更されています。保存しますか?', [FN]),
          mtConfirmation, [mbYes, mbNo, mbCancel], 0);

  case I of
    id_Yes: begin
              acSaveExecute(Self);
              if Modified then Exit; // 保存されなかった場合
            end;
    id_Cancel: Exit;
    id_No: ;  // id_Noは保存しないという選択なので処理不要です。
  end;
  Modified := False;
  Result := True;
end;



// 初期設定
procedure TForm1.FormCreate(Sender: TObject);
begin
  FN := '';
  Modified := False;
end;



// 新規作成
procedure TForm1.acNewExecute(Sender: TObject);
begin
  if not ConfirmingDialog then Exit;
  FN := '';
  { 処理 }
end;



// 開く
procedure TForm1.acOpenExecute(Sender: TObject);
begin
  if not ConfirmingDialog then Exit;
  FN := '開いたファイル名';
  { 処理 }
end;



// 名前を付けて保存
procedure TForm1.acSaveAsExecute(Sender: TObject);
begin
  if not ConfirmingDialog then Exit;
  FN := '名前を付けたファイル名';
  { 処理 }
end;



// 保存
procedure TForm1.acSaveExecute(Sender: TObject);
begin
  if FN = '' then
  begin
    acSaveAsExecute(Self);
    Exit;
  end;

  { 処理 }
  Modified := False;
end;



// 終了してもよいかどうか
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := ConfirmingDialog;
end;

end.



確認ダイアログが表示されるかどうか確かめるために、次の処理をします。
procedure TForm1.Button1Click(Sender: TObject);
begin
  Modified := True;
  Close;
end;


よく見るこんなダイアログです。

Save

デフォルトのファイル名が空白のため、ファイル名部分が表示されていませんが、 実際のアプリケーションでは「Untitled」や「無題」を設定しています。

|

■コードエディタが・・・。

オブジェクトインスペクタのイベントをダブルクリックすると、宣言部と実現部を自動で作成してくれますよね。 でもDelphi2006頃からだと思うのですが、次のようなことが時々起こります。

オブジェクトインスペクタで、Form1のOnCloseQueryをダブルクリックしたときのものです。

Error1



なんでかな?と思ってコードを調べてみますとこんなことになっていました。

Error2


end.end.の間に挿入されてしまうのです。
あせらなくていいから、落ち着いて処理して!と突っ込みたくなります(笑)


そう言えば、このオブジェクトインスペクタでクリックして自動で実現部を作成してくれる場所について、何か 決まりがあるのでしょうか。 昔のバージョンでは、プログラムの最後に付加されていたように思うのですが、Delphi2006やDelphi2007では どこの行に作成されているのかよくわからないです。

例えば、次のような処理があったとします。
// 新規作成
procedure  TForm1.acNewExecute(Sender: TObject);
begin
  NewNew;
end;

フォームに新しくボタンを配置してダブルクリックすると、 こんなことになってること多くないですか。
せっかく書いたコメントとの間に入ってくるので、ボタンがコメントを横取りしてる感じですね。
// 新規作成
procedure TForm1.Button1Click(Sender: TObject);
begin

end;

procedure  TForm1.acNewExecute(Sender: TObject);
begin
  NewNew;
end;


この「どこに自動作成してくれるのか」という疑問を大阪でのデベロッパーキャンプで、Malcolm Groves氏に直接、いえ、通訳を介して、質問をしたのですが、言葉だけではきちんと伝わらなかったようで 「バグじゃないかな?」という話で終わりました。残念・・・。

|

☆EditコントロールのSelText

前回、書いたものを テーマの有効/無効に関係なく使えるように修正しました。
又、引数をTCustomEditとすることで、TEdit、TMemo、TInplaceEdit等にも対応できるようにしました。

uses Themes;

function GetSelText(CustomEdit: TCustomEdit): String;
var
  S, Str: WideString;
  I, Start, Len: Integer;
begin
  if ThemeServices.ThemesEnabled then   // テーマが有効の時
    begin
      S := WideString(CustomEdit.Text);
      Start := CustomEdit.SelStart + 1;
      Len := Start + CustomEdit.SelLength -1;

      Str := '';
      for I := Start to Len do
        Str := Str + S[I];
      Result := Str;
    end
  else
    Result := CustomEdit.SelText;       // テーマが無効の時
end;

|

☆TMS Advanced ToolBars & Menus v3.0.1.1での質問

以下の件で、再びtmssoftware.comのサポートにメールしました。前回同様、すぐにメールを返して頂きました。(日本語で書いていますが、実際は英語でのやり取りです)

Q.AdvToolBarでCheckBoxを使いたいけど、標準のCheckBoxにはTransparentプロパティがないため、真っ黒になってしまいます。何か解決方法はありますか?

A.Transparentプロパティを持っているTMS TAdvOfficeCheckを使うことをお奨めします。

やっぱりね(^^;

|

■Update3のインストール完了


Update3のファイルサイズ・・・約5.5MB
(でもインストールを開始後、ダウンロードするファイルサイズは半端じゃないです)

ヘルプの修正も結構あるのに小さいファイルサイズだなと思いながらも気にせず、アップデートを開始しました。 すぐ終わるだろうと思い、そのまま席を立ち、約30分後戻ってきましたが、まだ作業中でした。そして開始から1時間以上経ち、画面に「ヘルプファイルをインストールしています。この処理にはしばらく時間がかかります。」と表示されました。 結局、インストール終了まで約1時間半ぐらいかかりました。どんだけ~(笑)

※アップデートする時には、Descriptionの記述もきちんと読んでおきましょうね。>私

Update3のスプラッシュです。画像を入れ忘れてないの?って聞きたくなるぐらいシンプルです。

Sp3

|

■Delphi 2007 for Win32 Update3

Delphi 2007 for Win32 Update3が公開されました。下記のリンクからダウンロードできます。
又、昨日、苦戦していたInstallAware Expressもアップデートがあるのですが、こちらはC++Builder向けのようです。Delphi用とはどこか違うのかな??

CodeGear
ID: 25001, Delphi 2007 for Win32 Update 3
ID: 24997, InstallAware Express CodeGear Edition(For C++Builder)

|

■Tetrisのソースコード

ゲームをほとんどしない(できない?)私ですが、Tetrisぐらいは知っています。 20年程前のゲームらしいですが、どんな処理になっているんでしょうね。 興味ある方は下記サイトをご覧下さい。
DelphiによるTetrisのソースコードのダウンロード先が紹介されています。

About.com:Delphi Programming
Tetris - Delphi Version with Source Code

|

★InstallAware Express6が使えない。

本当は、「InstallAware Express6を使ってみる。」という記事を書いてる途中だったのですが、下記のようなエラーメッセージが表示されて、プロジェクトが実行できなくなってしまいました。
(プロジェクトを全て削除して、再起動しても同じ)

Error


こんな時間までいろいろ調べていたのに、これじゃまるでInstallAware(インストール哀れ)です(笑)
又、後日試してみますが、この様子では無理っぽいですね。


ところで、InstallAware Express6は実行したとき、きちんと日本語で表示されているにもかかわらず、HELPは英語のままですし、又、デフォルトではインストーラーのメッセージも英語です。日本語にするためには、プロジェクトのプロパティでデフォルト言語を日本語にするだけでなく、ローカリゼーション・ウィザードでエクスポートして、それを日本語に翻訳し、再度インポートする必要があるようです。
(私の使い方が間違いだと信じたいです)まあ、どちらにしてもそれぞれのアプリケーション毎にインストーラーに表示する内容も変えないといけないのかも知れませんが・・・。

そうそう、プロジェクトの中身を見てみると、拡張子が.dfmというファイルや.miafというDelphiのif文が書いてあるテキストファイルなどがあり、よくわからないけどDelphiと関係がありそうなインストーラーかも知れないですね。

あと、InstallAware Express CodeGear Edition Hotfixというものを見つけました。
これによりdbExpress関係の問題が解決できるようです。

|

☆GDI+を使う。

ニュースグループ borland.public.delphi.graphics の中でGDI+を使うサンプルが紹介されていました。 私は、GDI+を全く使ったことがなく、そのサンプルをコンパイルするだけでも結構大変でした。
ということで、とりあえずGDI+を使えるようにするための手順をメモしておきます。

1.次のサイトからHenri Gourvest氏のGDIPLUSというユニットをダウンロードします。

  progdigy.com
  http://www.progdigy.com/
  (ModulesのGDI+をクリックするとダウンロードのページに移動します)


2.ダウンロードしたファイルを解凍して、gdiplus\pasフォルダをライブラリパスに設定します。


以上で、GDI+を使える環境が整ったので、デモをコンパイルしてみます。
(gdiplus\demos\Getting Started\Drawing a String\GDDITEST9.dproj)
ファイルを開いてコンパイルすると
[DCC エラー] DirectDraw.pas(358): E2154 'IDirectDrawSurface' 型は終了処理が必要です
 - 構造体の可変部に置くことは許されません
というエラーが表示されました。

なんとなくDelphiのバージョンによるエラーっぽいと思い、いろいろ調べてみました。
結果として、次のような処理でコンパイルすることができました。

jedi.incファイルで次のコメントを検索します。
// VERXXX to COMPILERX, DELPHIX and BCBX mappings
そして次の処理を挿入します。(Delphi2007をDelphi7と認識させます。)
//------------------------------------------------------------------------------
// VERXXX to COMPILERX, DELPHIX and BCBX mappings
//------------------------------------------------------------------------------

{$IFDEF VER180}
  {$DEFINE COMPILER7}
  {$IFDEF BCB}
    {$DEFINE BCB7}
    {$DEFINE BCB}
  {$ELSE}
    {$DEFINE DELPHI7}
    {$DEFINE DELPHI}
  {$ENDIF}
{$ENDIF}


これで、無事コンパイルすることができました。


[参考にしたサイト]

MemoNyanDum
http://junki.lix.jp/
Delphiを使った画像処理では知らない人はいないかも知れませんが、今回お世話になったサイトです。 デザインもとっても素敵です。

progdigy.com
http://www.progdigy.com/

About.com Delphi Programming
Delphi Compiler Version Directives

|

☆Buttonのキャプションを複数行表示にする。

私は、StdCtrlsネームスペースのTButtonControlにWordWrapプロパティがあることを発見してからは、次のような処理で複数行表示をしています。
type
  TDummyButton = class(TButtonControl);

procedure TForm1.FormCreate(Sender: TObject);
begin
  TDummyButton(Button1).WordWrap := True;
  Button1.Caption := 'こんな風に複数行の'+#13#10+
                     'キャプション表示が' +#13#10 +
                     'できます。';
end;


別の方法としてabout.com Delphi Programmingでは、複数のボタンをその親コンポーネントを指定することにより一度に設定する方法が紹介されています。こちらは、SetWindowLongを使った処理になっています。

about.com Delphi Programming
TButton with multiline Caption

|

☆ListViewで選択行を削除する。

次のような処理で簡単に削除できます。
while ListView1.SelCount > 0 do
  ListView1.Selected.Delete;

このとき処理の内容によっては、次のようにOnChangeを無効にしないとエラーになったり、時間がかかったりすることがあります。又、アイテム数によっては、BeginUpdate~EndUpdateを使わないと処理が遅いです。
procedure TForm1.Button1Click(Sender: TObject);
begin
  ListView1.Items.BeginUpdate;
  ListView1.OnChange := nil;
  try
    while ListView1.SelCount > 0 do
      ListView1.Selected.Delete;
  finally
    ListView1.OnChange := ListView1Change;
    ListView1.Items.EndUpdate;
  end;
end;

|

☆パスの一部を省略してファイル名を表示する。

MinimizeName関数を使います。

uses FileCtrl;

procedure TForm1.Button1Click(Sender: TObject);
const
  FileName = 'C:\Documents and Settings\hiderin\デスクトップ\delphi-fan.txt';
begin
  Edit1.Text := MinimizeName(FileName, Canvas, 200);
end;

こんな風に加工されます。
C:\Documents and Settings\hiderin\デスクトップ\delphi-fan.txt
  ↓
C:\...\hiderin\デスクトップ\delphi-fan.txt

メニューで「最近使ったファイルを表示する」等の用途に使えそうですね。

|

☆Paradoxに代わるもの

初めに断っておきますが、前回のデベロッパーキャンプで紹介されていた サードパーティ製コンポーネントAbsolute Databaseの話です。 (RAD Studio 2007の新機能ではありません)
ComponentAce社のAbsolute Databaseは、DBエンジンのインストールやDLLも不要でEXEのみで実行可能です。個人利用であれば、フリーで使えます。次のような登録のお願い?(nag screen)は表示されますけどね。

Abs1

ComponentAceのホームページより

For trial and personal use.
No limitations at runtime when database is used in single-user mode 
(1 database connection). 
On IDE startup a nag screen is shown. 
In multi-user mode (file-server), nag screen is shown outside IDE


CodeGear 高橋智宏氏がいろいろ試した中でも、Paradox同等機能(実際は同等以上)及び移項のしやすさを考えると一番いいんじゃないかと話されておられました。そのAbsolute Databaseについて、Paradoxファイルを変換してDBGridに表示するまでを詳細に書いてみますね。


[インストール]

Absolute Database Personal Editionをダウンロードします。
2007/09/08現在、Product Version 5.14となっています。

ComponentAce ダウンロードのページ

インストール後、ツールパレットには、AbsoluteDBというカテゴリと、次の4つのコンポーネントが追加されました。

Abs2


では、早速使ってみます。
今回使うParadoxファイルは、biolife.dbです。
デフォルトではC:\Program Files\Common Files\CodeGear Shared\Dataにあります。

大切なデータベースなので、変換中に壊れたりすると困るので、c:\biolifeというフォルダを作成し、そこに次のファイルをにコピーします。
biolife.db
biolife.mb
biolife.px 


[Paradox]

まず、このParadoxファイルを表示させてみます。 フォームにTable1、DataSource1、DBGrid1、DBMemo1、DBImage1を配置し、次のように設定します。
[Table1]
Table1.DatabaseName := 'c:\biolife';
Table1.TableNam := 'biolife.db';
Table1.Active := True;

[DataSource1]
DataSource1.DataSet := Table1;

[DBGrid1]
DBGrid1.DataSource := DataSource1;

[DBMemo1]
DBMemo1.DataSource := DataSource1;
DBMemo1.DataField := 'Notes';

[DBImage1]
DBImage1.DataSource := DataSource1;
DBImage1.DataField := 'Graphic';
DBImage1.Stretch := True;

実行させるとこのようになります。

Paradox



[AbsoluteDatabase]

次にAbsoluteDatabaseです。
まず、ParadoxファイルをAbsoluteDatabaseに変換します。 AbsoluteDatabaseには、Paradoxファイルを変換するためのプログラム、DBImportExport.exeというものが用意されていますので、それを実行します。
デフォルトではC:\Program Files\ComponentAce\AbsoluteDatabase\Utils\Binにあります。
インポートするのかエクスポートするのかを選択します。今回はもちろん、インポートです。

Adi1


今回はAliasではなく、フォルダのファイル変換を選択します。

Adi2


変換するファイルを選択します。

Adi3


変換後のデータベース名を入力します。

Adi4


無事変換できました。

Adi5


ABSBiolife.absというファイルができています。今回は、一つのテーブルですが、複数のテーブルやインデックスファイルも一つのファイルにまとめられて管理しやすくなります。

Adi6


Paradoxの表示に使ったフォームに、ABSDatabase1、ABSTable1を配置し下記のように設定します
(貼り付けようとすると例の登録のお願い?が表示されました。気持ちはわかりますが、何度も表示させると逆効果じゃないかな?)
[ABSDatabase1]
ABSDatabase1.DatabaseFileName := 'c:\biolife\ABSbiolife.abs';
ABSDatabase1.DatabaseName := 'FirstABS';

[ABSTable1]
ABSTable1.DatabaseName := 'FirstABS';
ABSTable1.TableName := 'biolife';

[DataSource1]
DataSource1.DataSet := 'ABSTable1';

ここでコンパイルすると
[DCC エラー] Unit1.pas(7): F1026 ファイル 'ABSMain.dcu' が見つかりません
とエラーが表示されました。

オプション→環境オプション→ライブラリ-Win32→ ライブラリパスを確認すると
C:\Program Files\ComponentAce\AbsoluteDatabase\Lib\Delphi 2007 and C++ Builder 2007
あれ登録されてる??

でもコンパイルできないので、プロジェクト→オプション→ディレクトリ/条件→検索パスに
C:\Program Files\ComponentAce\AbsoluteDatabase\Lib\Delphi 2007 and C++ Builder 2007
と入力し、実行しました。

Abs



同じプログラムでABSTableをABSQuery1に変更して、試してみましたが問題なく表示されています。
今回は、導入に当たっての話で終わりますが、、Paradoxの一番の弱点である、共有使用時の更新や5万件以上のデータの扱いについても機会があれば検証してみたいと思います。
(今回のプログラムを複数起動させるには ABSDatabase1.MultiUser := True; とします。)

ComponentAce
http://www.componentace.com/


第6回 CodeGearデベロッパーキャンプ  資料ダウンロード
【T3】C++Builderテクニカルセッション
「C++Builder 2007の新機能と活用のポイント」
CodeGear 高橋智宏 氏
プレゼンテーション資料:PDF(389KB)

|

☆TMS Advanced ToolBars & Menusでの文字化けが解決しました。

以前の記事、TMS Advanced ToolBars & Menus v3.0.1.0での質問で書いてた文字化けですが、v3.0.1.1になって、aaClearTypeもaaAntiAliasも使えるようになっています。
ただ、aaNone以外では、文字が左側に寄ってしまうのが気になります。もう少し使ってみて、問題があるようでしたら、又、報告しますね。

|

■某所|避難所さん

某所|避難所さんが、久しぶりに更新されてますね。
幅広いところから情報を収集して載せておられるので、いつも楽しみに読ませてもらっています。


某所|避難所
http://bousyo.blog45.fc2.com/

|

■TMS Advanced ToolBars & Menusアップデート

TMS Advanced ToolBars & Menus が v3.0.1.0 から v3.0.1.1 にアップデートされました。

メーカーホームページからの引用です。

What's new:

in v3.0.1.1
- New : Autosizing statusbar panels
- New : Configurable stretchpanel in statusbar
- New : design time resizing of statusbar panels
- New : Notes text with NotesFont in TAdvGlowButton
- New : Notes text with NotesFont in TAdvMainMenu, TAdvPopupMenu
- New : Windows Vista color style for TAdvMainMenu, TAdvPopupMenu
- New : Antialiased menu text drawing
- Improved : multimonitor support for TAdvToolBarForm
- Improved : maximize state handling of TAdvToolBarForm
- Improved : painting of TAdvGlowButton, TAdvContainer
- Improved : statusbar painting
- Improved : Windows system menu handling on TAdvToolBarPager Caption
- Fixed : issue with antialiased or cleartype text drawing for non default char sets
- Various smaller fixes & improvements


tmssoftware.com

|

■CodeGear RAD Studio 2007

CodeGear RAD Studio 2007が発表されましたね。


日本語の情報です。
データベースアプリケーション開発に強いWindows®/.NET向け開発ツール
『CodeGear™ RAD Studio 2007』4ヶ国語版同時発売

英語の情報です。
CodeGear RAD Studio 2007

WHAT’S NEW (PDFファイル)
Press Release:
CodeGear RAD Studio 2007 Provides Rapid Application Development

|

■ふと、思いついたこと・・・。

なぜか、ふとイオン化傾向の暗記文が頭に浮かんできて・・・

「仮想かな まああてにするな ひどすぎる ヘルプ」・・・なんてね(笑)

ジョークのつもりでも文章に書いてしまうと、かなりひどい表現になっています。ごめんなさい。
まあ、ユーザーの素直な気持ちではありますけどね。Dee Elling氏の作業は進んでいるのかな?
Delphiユーザーにこんな悲しいこと書かせないように、がんばって頂きたいです。

|

☆ComboBoxでリストの自動ドロップダウン

リストボックスにしたいけど、スペースを取るからComboBoxを使っているような用途の場合、 ComboBoxの自動ドロップダウンは有効ですよね。
(私が作った社内のアプリでも、自動にしてほしいという要望が多いです)

これを実現するためにComboBoxには、AutoDropDownというプロパティが用意されているので、これをTrueするだけで良いように思えます。しかし、この設定では、カーソルがComboBoxに移動しても、ドロップダウンしません。

ヘルプで確認しますと、
<Delphi2007 for Win32 HELPより引用>

TComboBox.AutoDropDown プロパティ

AutoDropDown が true であれば,コンボボックスにフォーカスがあるときに
ユーザーが文字をタイプすれば自動的にリストをドロップダウンします。
これでは少し中途半端ですよね。


このような時には、次のような処理をします。(と書くほどのものではありませんけど)
procedure TForm1.ComboBox1Enter(Sender: TObject);
begin
  ComboBox1.DroppedDown := True;
end;

上の処理では、マウスで▼をクリックしてOnEnterが処理されたとき、一度閉じてしまいますね。
キー操作での処理ばかりしてたので、気付かなかったです。
ということで次の処理を考えてみました。しかしこれでもマウスがクリックされずに▼の上にあって、OnEnterが処理された場合には自動で開きませんけど(^^;
procedure TForm1.ComboBox1Enter(Sender: TObject);
var
  P1,P2: TPoint;
  R1, R2: Boolean;
begin
  GetCursorPos(P1);
  P2 := ComboBox1.ScreenToClient(P1);
  // ボタン幅の取得がわからなかったのでSM_CXHSCROLLを使いました。
  R1 := P2.X > (ComboBox1.Width - GetSystemMetrics(SM_CXHSCROLL));
  R2 := (P2.X < ComboBox1.Width);
  if R1 and R2 then Exit;
  ComboBox1.DroppedDown := True;
end;


でも、ここで一つ気になるのがヘルプの記述です。
<Delphi2007 for Win32 HELPより引用>

TCustomCombo.DroppedDown プロパティ

DroppedDown プロパティを読み出すと,ドロップダウンリストが可視であるか
どうかを判別できます。ドロップダウンリストを開いたり閉じたりするには,
DropDown プロパティを設定します。DroppedDown は,ドロップダウンリストが
開いていれば true,閉じていれば false です。 
私には、この記述は間違っているように思えます。
DroppedDownは読み込み専用プロパティではなく、設定も可能です。
DropDownプロパティは、OnDropDownイベントになりますので、開けたり閉じたりするには、やはりDroppedDownを使うものだと思われます。


又、AutoCloseUpというよくわからないプロパティもあります。
こちらもヘルプで確認してみます。
<Delphi2007 for Win32 HELPより引用>

TComboBox.AutoCloseUp プロパティ

AutoCloseUp が true になっていれば,ユーザーが項目を選択したとき,
自動的にドロップダウンが閉じられます。 
と書いていますが、実際には、このプロパティの設定に関係なく項目を選択すればドロップダウンが閉じられます。 もしかしてOnCloseUpイベントに影響があるのかなと思い、確かめてみましたが、こちらも常に発生するので 関係がないように思います。こうなるとわざわざ存在する理由がわからないですよね。 [2007/09/06 一部訂正しました。]

|

☆リターンキーで移動させる。

なんだっけ?なんだっけ?となかなか思い出せず、過去のプログラムを 調べて、ようやく見つけた出した SelectNext!超、超、超いまさらですが、書いておきますね。

Form1のKeyPreviewをTrueにする必要があります。
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  //リターンキーで移動させる
  if Key = #13 then
  begin
    SelectNext(ActiveControl, True, True);
    Key := #0;
  end;
end;

|

■先日のデベロッパーキャンプの資料

第6回 CodeGearデベロッパーキャンプの資料が公開されました。
下記のリンクをご覧下さい。


第6回 CodeGearデベロッパーキャンプ - 資料ダウンロード

|

☆Edit1.SelTextが・・・。

以前、XPmanを貼り付ける等により、XPテーマを有効にした時には、 SelTextの値がおかしくなると書きました。 (APIの仕様変更によるものらしいですが)

Delphi2007では、XPmanを貼り付けなくても、デフォルトでテーマが有効になっています。
既存のアプリケーションをDelphi2007でコンパイルし直す時には、ご注意を・・・。
(エラーが出ないので、なかなかわかりにくい部分ですよね)

SelText部分を書き直す一例としては、下記のような処理ですね。
// XPテーマ有効時、Editで選択された文字列を返します。
function GetSelText(Edit: TEdit): String;
var
  S, Str: WideString;
  I, Start, Len: Integer;
begin
  S := WideString(Edit.Text);
  Start := Edit.SelStart + 1;
  Len := Start + Edit.SelLength -1;

  Str := '';
  for I := Start to Len do
    Str := Str + S[I];
  Result := Str;
end;

ちなみにDelphi2007の場合、XPテーマを無効にするには、メニューの
プロジェクト→アプリケーション →アプリケーションの設定 ランタイムテーマを有効にする
のチェックを外します。

|

☆多数のEditのテキストを削除する。

TFormは、TComponentから派生されていますので、 ComponentsプロパティやComponentCountプロパティを使えば、 フォーム上のコンポーネントの単純な処理が可能になります。
ここでは、Editのテキストを空白にする処理を行ってみました。

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  // Editの初期化
  for I := 0 to Self.ComponentCount - 1 do
    if Self.Components[I] is TEdit then
      (Self.Components[I] as TEdit).Text := '';
end;

|

■コードエディタでのショートカット

Nick Hodges氏のBlogに、CTRL+SHIFT+ICTRL+SHIFT+U で、選択されたブロックを インデント、アンインデントができることを知ってた?というような記事がありました。
私は、知りませんでした。(多数行のインデントは、マクロで処理してます。)

コードエディタでのショートカットなんて、使っていて発見するぐらいですよね。(私だけ?)
改めてヘルプを見てみますと、驚くほどたくさんのショートカットがあります。
みなさんも一度確認してみて下さい。

Delphi2007 HELP
(目次) RAD Studio→RAD Studio(共通)→リファレンス→キーボードマッピング
     →デフォルトのキーボード ショートカット

Nick Hodges It's all about the Geeks
Did You Know...

|

■Malcolm Groves氏のブログ

CodeGear アジアパシフィック バイスプレジデントのMalcolm Groves氏のブログです。
デザインが、ちょっと・・・いえ、かなり怪しすぎます(笑)


Malcolm Groves - Subtracting From The Sum Of Human Knowledge

|

☆Excelの書式設定を行う。

次のような書式設定を行います。マクロから抜き出して並べているだけですけどね。

Excel


uses ExcelXP;

procedure TForm1.Button1Click(Sender: TObject);
const
  FileName = 'c:\test.xls';
  S1 = 'こんにちは \(^o^)/';
  S2 = 'CodeGear Delphi for Win32';
var
  LCID: Integer;
  ExcelApplication1: TExcelApplication;
  ExcelWorkBook1: TExcelWorkBook;
  Len1, Len2: Integer;
begin
  ExcelApplication1 := TExcelApplication.Create(nil);
  ExcelWorkBook1 := TExcelWorkBook.Create(nil);
  try
    LCID := GetUserDefaultLCID;
    ExcelApplication1.Connect;
    ExcelApplication1.Visible[LCID] :=  False;
    ExcelApplication1.DisplayAlerts[LCID] := False;

    ExcelApplication1.Workbooks.Add(EmptyParam, LCID);
    ExcelWorkBook1.ConnectTo(ExcelApplication1.ActiveWorkBook);

    Len1 := Length(WideString(S1));
    Len2 := Length(WideString(S2));

    // セルを選択
    ExcelApplication1.Range['B5','B5'].Select;
    
    // セルの書式設定--文字の制御--折り返して全体を表示する
    ExcelApplication1.ActiveCell.WrapText := True;

    // セルの書式設定--文字の配置--縦位置--中央揃え
    ExcelApplication1.ActiveCell.VerticalAlignment := xlCenter;

    // 一つのセルに2行に分けて表示
    ExcelApplication1.ActiveCell.FormulaR1C1 := S1 + #10 + S2;

    // 一行目のフォントサイズの設定
    ExcelApplication1.ActiveCell.Characters[1,Len1].Font.Size := 18;

    // 二行目のフォントサイズの設定
    ExcelApplication1.ActiveCell.Characters[Len1+1,Len2+1].Font.Size := 9;

    // セル(カラム)幅の自動設定
    // ※ColumnWidthを設定しないとAutoFitの動作が不安定でした。
    ExcelApplication1.ActiveCell.ColumnWidth := 100; // 数値は適当です。
    ExcelApplication1.ActiveCell.EntireColumn.AutoFit;

    // セル(行)高さの自動設定
    // ※RowHeightを設定しないとAutoFitの動作が不安定でした。
    ExcelApplication1.ActiveCell.RowHeight := 50;  // 数値は適当です。
    ExcelApplication1.ActiveCell.EntireRow.AutoFit;

    // 罫線
    ExcelApplication1.ActiveCell.Borders[xlEdgeLeft].LineStyle := xlContinuous;
    ExcelApplication1.ActiveCell.Borders[xlEdgeTop].LineStyle := xlContinuous;
    ExcelApplication1.ActiveCell.Borders[xlEdgeBottom].LineStyle := xlContinuous;
    ExcelApplication1.ActiveCell.Borders[xlEdgeRight].LineStyle := xlContinuous;    

    // 保存します。
    ExcelWorkBook1.SaveAs(FileName,     //Filename
                  Integer(xlNormal),    //FileFormat
                  EmptyParam,    //Password
                  EmptyParam,    //WriteResPassword
                  False,         //ReadOnlyRecommended
                  False,         //CreateBackup
                  xlNoChange,    //AccessMode
                  EmptyParam,    //ConflictResolution
                  EmptyParam,    //AddToMru
                  EmptyParam,    //TextCodepage
                  EmptyParam,    //TextVisualLayout
                  EmptyParam,    //Local
                  LCID);         //LCID

    ExcelApplication1.Quit;
    ExcelApplication1.Disconnect;
  finally
    ExcelWorkBook1.Free;
    ExcelApplication1.Free;
  end;
end;

カラム幅や行高さは、Cellに対してではなく、ColumnsやRowsで設定しなきゃいけないと思うのですけど、うまくできなかったです。又、機会があれば検討してみますね。

|

☆DBGridでのTopRow設定

ClientDataSetを使ってDBGridにデータを表示させます。
私は、このテーブルに対して検索等を行うには、次のようにクローンを作成して処理させています。
その理由は、レコードを移動させる処理を行うとDBGridの表示が変わってしまうからです。例えば、BookMarkStrで元の位置に戻したとしても、BookMarkではDBGridの中央に指定レコードを表示するため、処理前の表示を再現することができません。
function LocateEx(ClientDataSet: TClientDataSet; const KeyFields: String;
  const KeyValues: Variant; Options: TLocateOptions): Boolean;
var
  CloneCDS: TClientDataSet;
begin
  CloneCDS := TClientDataSet.Create(nil);
  try
    CloneCDS.CloneCursor(ClientDataSet, True);
    Result := CloneCDS.Locate(KeyFields, KeyValues , Options);
    // if Result then
    //   ClientDataSet.GotoCurrent(CloneCDS)
  finally
    CloneCDS.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not LocateEx(ClientDataSet1,'name', Edit1.Text, []) then
    ShowMessage('見つかりません');
end;

では、クローンを作成しないでレコード移動前の表示に戻せないかという質問がありました。
そこで、元の表示のTopRowを保存しておき、レコードを移動した後、TopRowとカレントレコードを戻すというサンプルを作ってみました。
type
  TDummyDBGrid = class(TCustomDBGrid);

procedure TForm1.Button1Click(Sender: TObject);
var
  RowCount, RN: Integer;
  TopRowRecNo, CurrentRowNo: Integer;
begin
  ClientDataSet1.DisableControls;
  try
    // TopRowのRecNoとCurrentRowのRecNoを保存しておきます。   
    CurrentRowNo := TDummyDBGrid(DBGrid1).Row - 1;
    TopRowRecNo := ClientDataSet1.RecNo - CurrentRowNo;

    //レコードを移動させる処理---好きにして~。
    //ClientDataSet1.Locate('name', Edit1.Text,[]);
    //ClientDataSet1.Last;
    //ClientDataSet1.First;
    
    // DBGridの表示を元に戻す処理

    // 指定レコードをTopRowに移動させる処理
    RowCount := TDummyDBGrid(DBGrid1).VisibleRowCount;
    ClientDataSet1.RecNo := TopRowRecNo;
    ClientDataSet1.MoveBy(RowCount);    
    
    while not ClientDataSet1.BOF do
    begin
      RN := ClientDataSet1.RecNo;
      if RN = TopRowRecNo then
        Break
      else
        ClientDataSet1.Prior;
    end;

    // カーソルを元のカレントレコードに移動させる処理
    ClientDataSet1.MoveBy(CurrentRowNo);
  finally
    ClientDataSet1.EnableControls;
  end;
end;

※Delphi User's Forumでコメントした内容をまとめています。

|

☆Serversコンポーネントがない。

Excelの処理をしたいと思い、Serversカテゴリを探したのですが、見つかりませんでした。 インストールされていないのかなと思い、パッケージのインストールで確認してみると、未チェックのOffice2000とOfficeXPの2種類のパッケージがあったので、OfficeXPにチェックを入れてOKボタンを押しました。 これで無事使えるようになりました。

Package

|

« 2007年8月 | トップページ | 2007年10月 »