10
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Delphi カスタムコンポーネントを作成・利用したい

Last updated at Posted at 2014-05-20

はじめに

会社で Delphi 使用しているのですが、コンポーネントを作成するという文化が無かった為、この度勉強してみました。

シチュエーションとして、外部への配布は考えず、社内で共用利用する事を想定しています。あ、VCLです。Delphi XE3 での例となります。

手順(長いです)

作成例:「一定時間アニメーションすると、自動でアニメーションが停止するトレイアイコンを作りたい」 (常駐アプリで使用する事を想定)

1.パッケージを新規作成する

Delphiを起動し、ファイル → 新規作成 → パッケージ を選択します。 ![ss1.png](https://qiita-image-store.s3.amazonaws.com/0/33684/c4bf508d-a580-8aa9-dbba-54a934064514.png)

プロジェクトが作られたので、最初に「プロジェクトに名前を付けて保存」を実行します。
ss2.png

ここでは、D:\MyComponent\MyPackage.dproj としました。

2.コンポーネントを新規作成する

プロジェクトマネージャ画面にて、「Contains」を右クリック、新規追加→その他 ![ss3.png](https://qiita-image-store.s3.amazonaws.com/0/33684/3880cfd9-a193-0ac8-ce7e-746d65386825.png)

新規作成ウィザードにて、「コンポーネント」を選択
ss4.png

VLC for Delphi Win32 を選択
ss5.png

継承元コンポーネントで、TCustomTrayIconを選択。
(TTrayIconとどちらを継承元にすべきかは、追加したい機能にて判断する、と自分は解釈しました)
ss6.png

クラス名、パレットページ名、ユニット名をそれぞれ変更しました。
ss7.png

完了すると、まずユニットの保存を要求されますので、「D:\MyComponent\」を選択(直前の設定がデフォルトになる筈?)。
ss8.png

最後に、以下のような確認ダイアログが表示されます。
「はい」で問題無いかと思います。
ss9.png

3.実装する

(何故クラスを2個作っているかと聞かれると、答えられません。VCLの他のコンポーネントの作りに従いました。)
unit AutoStopTrayIcon;

interface

uses
  System.SysUtils, System.Classes, Vcl.ExtCtrls, Winapi.MMSystem;

type
  TAutoStopCustomTrayIcon = class(TCustomTrayIcon)
  private
    FAnimationStartTime:Integer;
    FAnimationLifetime:Integer;
    procedure SetAnimationLifetime(Value:Integer);
    function GetAnimate: Boolean;
  protected
    constructor Create(Owner: TComponent); override;
    procedure DoOnAnimate(Sender: TObject); override;
  public
    procedure DoAnimate;
    property AnimationLifetime:Integer read FAnimationLifetime write SetAnimationLifetime default 1000;
    property Animate:Boolean read GetAnimate;
  end;

  TAutoStopTrayIcon = class(TAutoStopCustomTrayIcon)
  published
    property AnimationLifetime;
    property AnimateInterval;
    property Hint;
    property BalloonHint;
    property BalloonTitle;
    property BalloonTimeout;
    property BalloonFlags;
    property Icon;
    property Icons;
    property IconIndex;
    property PopupMenu;
    property Visible;
    property OnBalloonClick;
    property OnClick;
    property OnDblClick;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseDown;
    property OnAnimate;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MyComponent', [TAutoStopTrayIcon]);
end;

{ TAutoStopCustomTrayIcon }

constructor TAutoStopCustomTrayIcon.Create(Owner: TComponent);
begin
  inherited;
  FAnimationLifetime:= 1000;
end;

procedure TAutoStopCustomTrayIcon.DoAnimate;
begin
  FAnimationStartTime := TimeGetTime;
  SetAnimate(True);
end;

procedure TAutoStopCustomTrayIcon.DoOnAnimate(Sender: TObject);
begin
  inherited;

  if (TimeGetTime > FAnimationStartTime+FAnimationLifetime ) then
    SetAnimate(False);
end;

function TAutoStopCustomTrayIcon.GetAnimate: Boolean;
begin
  Result := inherited Animate;
end;

procedure TAutoStopCustomTrayIcon.SetAnimationLifetime(Value: Integer);
begin
  if (Value < 0) then
    FAnimationLifetime := 0
  else
    FAnimationLifetime := Value;
end;

end.

プロパティのデフォルト値

マジックナンバー「1000」が2回も出てきて気持ち悪いですが、それぞれ役割が違いました。 (interfaceの方)
property AnimationLifetime:Integer read FAnimationLifetime write SetAnimationLifetime default 1000;

これは、(恐らく)DelphiのIDE上で、「プロパティに設定されている値がデフォルト値かどうか」を判定する為に使用されています。
上の例だと、プロパティに1000が設定されていると細字、それ以外の値だと太字強調されるようになります。

(constructorの方)

constructor TAutoStopCustomTrayIcon.Create(Owner: TComponent);
begin
  inherited;
  FAnimationLifetime:= 1000;
end;

こちらは、コンポーネントをフォームに配置した際の「IDEのプロパティにデフォルトで入力されている値」を決めています。
基本、宣言部と同値で良いような気がしました。(別にしておくとこういう使い方が!など有りましたら是非・・)

継承元プロパティの書き込みを防ぐ

今回はアニメーションの停止を自動で行うので、通常のアニメーション状態を制御するAnimateプロパティを読み取り専用とし、アニメ開始時はDoAnimateメソッドを呼び出すように設計してみました。 プロパティを再宣言してあげれば良い様子。デス。

このあたり。

property Animate:Boolean read GetAnimate;
function TAutoStopCustomTrayIcon.GetAnimate: Boolean;
begin
  Result := inherited Animate;
end;

4.使ってみる

コンポーネントのインストール

最初にメニューのプロジェクト → MyPackageのコンパイル を選択します。

特にエラーがなければ、コンポーネントのインストールが可能です。
プロジェクトマネージャ上で、MyPackage.bplを右クリックし、インストールを選択します。
ss10.png

上手く行けば、以下のようなダイアログが出るはず。
キャプチャ-11.png

ライブラリパスの設定

コンポーネントを使用してみる前に、ライブライパスを設定しておきましょう。 メニューの「ツール」→「オプション」を選択し、 ![ss12.png](https://qiita-image-store.s3.amazonaws.com/0/33684/64d750b2-4ba3-4d46-af89-0deaddab204e.png)

ライブラリ・・の・・ライブラリパス・・
ss13.png
こうで!
ss14.png
こう!
ss15.png

テストアプリケーションの作成

疲れてきました。いよいよ大詰めです。 MyPackegeは一旦閉じて、新規にプロジェクトを作ってみましょう。

コンポーネントパレット内にMyPackageが・・居た!!
ss16.png

配置すると、無事プロパティにもデフォルト値が設定されていました。
ss17.png

あとはImageListコンポーネントを配置し、画像を読み込みます。
icon.png(←ペイントで64px*16pxの画像を作った)

ss18.png

AutoStopTrayIcon1のIconsプロパティにImageList1を設定したり、ボタンを配置します。
ss21.png

ボタンクリックイベントかいてー!
procedure TForm1.Button1Click(Sender: TObject);
begin
  AutoStopTrayIcon1.Visible := True;
  AutoStopTrayIcon1.DoAnimate;
end;

こうだ!
ss20.png

で、結果はこう!(地味)
ss19.png

上手く行けば、10秒間、1秒ごとに画像が切り替わります。

終わりに

作ったコンポーネント/パッケージを社内で共有する場合は、 D:\MyConponent 内のファイルをバージョン管理下に置けばよいのかな?と思います。 各自ローカルにチェックアウトして、パッケージのインストール・ライブラリパスの設定が必要になると思います。

こうした方が楽!とか、間違っている点がありましたら、ご指摘いただければと思います。

10
14
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?