Edited at
DelphiDay 25

クリスマスプレゼント(ねこのデスクトップアクセサリ)


ねこです

クソアプリアドベントカレンダーの「猫に仕事を邪魔されてみたかったので技術で実現した」が話題ですね。

可愛い猫1がブラウザ中を駆け回る…!かわいい!

そんな訳で僕も作りたくなったので、Delphi で作ってみました。

ちなみに、Windows, macOS の両方で動きます。

実行ファイル:https://bitbucket.org/freeonterminate/nekodesu/downloads/

ソース一式:https://bitbucket.org/freeonterminate/nekodesu/

完全無料の Delphi Community Edition でもビルド出来ると思うので是非試して見てください。


起動

起動すると可愛い猫ちゃんが画面を右から左に駆け抜けていきます。

タスクトレイ上にアイコンも追加されます。

neko.gif


終了

終了時はタスクトレイ上のポップアップメニューで「終了」を選びます。

終了させると絶望から身体の色が変化するようですね。

neko4.gif


ドラッグ

ドラッグすると身体を赤から青に発光させて不満を表しているみたい。

neko4.gif


解説

デスクトップアクセサリを作るテクニックとして「FireMonkey で Window Drag」と「Delphi + FireMonkey で TaskTray / StatusBar にアイコンとメニューを実装する」を以前に解説しました。

今回はその2つを組み合わせて実際に可愛い猫ちゃんのデスクトップアクセサリを作りました。


アニメーション

FireMonkey のアニメーションはノーコーディングで実装出来るため非常に楽ちんです。

ですが、今回の猫ちゃんのアニメーションでは FireMonkey の仕組みを使いませんでした。


FMX アニメーションの仕組み

FireMonkey の Animation コンポーネントは構造ツリー上の親のプロパティ値を変更することでアニメーションさせています。

そのため Animation コンポーネントは親のプロパティを自動的に認識します。

たとえば、TFloatAnimation は浮動小数点型のプロパティを、TColorAnimationTAlphaColor 型のプロパティを、といった具合です。

animation.png


BitmapListAnimation

当初は TBitmapListAnimation を使おうと思っていました。

TBitmapListAnimation は1枚の絵からアニメーションを作り出してくれる便利なコンポーネントです。

下は DocWiki から持ってきた図ですが、このように同じサイズの画像を1枚にしたものからアニメーションを作成してくれます。

Sprint.png

TBitmapListAnimation が認識するのは TBitmap 型のプロパティで、 TBitmap 型のプロパティを持つ TImageControl と組み合わせて使うのが一般的なようです。

しかし、TImageControl はデフォルト(Style を作らないと)だと背景があるため Form に透過 PNG を適用できません。

一方、Form に透過 PNG を適用して Form の形を変更してくれる TImage の Bitmap プロパティは Published になっておらず、TBitmapListAnimation からは存在が見えません。

そのため、今回は TBitmapListAnimation を使うのを諦め、TTimer を使う方法にしました。


ImageList によるアニメーション

下記の3枚の画像を TImageList に保存して、時間が来たら自分で画像を取り出して TImage に割り当てています。

nekos.png

imglst.png

TImageList からビットマップを取り出す具体的な方法は以下の通りです。

// Bmp の解放は ImageList がやるので解放するとエラーになる!

var Bmp :=
ImageList.Bitmap(
TSizeF.Create(240, 360), // 取り出すビットマップのサイズ
0 // ImageList の何番目の画像かを指定(アニメーションさせる場合はここを変更していく)
);

Image1.Bitmap.Assign(Bmp); // TImage の Bitmap は public では存在する

この処理を周期的に呼べば、アニメーションされます。


ColorAnimation

今回ドラッグしている時にねこちゃんの周りを光らせようと思って、GlowEffect の下に TColorAnimation を付けました。

color.png

ColorAnimation は設定した GlowColor を1秒(Duration)かけて赤(StartValue)から青(StopValue)に変更します。

また AutoReverse プロパティを True にしたので、次の1秒では逆に青から赤に変更します。

さらに、Loop プロパティが True なので、このアニメーションを何度も繰り返します。


エフェクト

終了時のエフェクトには少しだけテクニックを使いました。

エフェクトは TInvertEffectTGlowEffecct の2つを掛けています。

ですが、FireMonkey のエフェクトは1つのコントロールにつき1つしか適用できません。

しかし、TLayout を上手く使うとエフェクトを多重に掛けられるようになります。

エフェクトが必要な数だけ TLayout を作り、多重の親子構造にしてしまう、という方法です。

下図は Layout の5段重ね+Image で、6個のエフェクトを同時に掛けた例です。

effect2.png

ということで、ここでは GlowEffect を Layout に、InvertEffect を Image に適用しています。

その様子が下図です。

layout.png

これを適用するとこんな感じで、発光しつつ色が反転します。

nekoend.png


マルチプラットフォーム

Delphi なので、何も変更せずに macOS でも動作します。

mac.png


ライブラリ

TrayIcon ライブラリは「Delphi + FireMonkey で TaskTray / StatusBar にアイコンとメニューを実装する」で既に紹介しました。

リポジトリの Lib/Utils ディレクトリにいくつかライブラリが入っています。

この中で、PK.Utils.Application を紹介します。


PK.Utils.Application

このライブラリは TApplication に機能を追加する Class Helper です。

以下の5つのメソッド・プロパティを追加します。

procedure ShowTaskBar;

procedure HideTaskBar;
function Path: String; // Path Only
function ExeName: String; // Full Path with FileName
property Version: String read GetVersion;

ShowTaskBar / HideTaskBar は Windows であればタスクバーに表示されるアプリケーションのバー、macOS であればドックに表示されるアイコンの表示と非表示を制御します。

今回のようなデスクトップアクセサリではタスクバーにアプリケーションが表示されていると邪魔なので、このメソッドで表示を消しています。

ExeName メソッドは VCL の TApplication にあった ExeNameFMX の TApplication に付加する物です。

この ExeName から Path だけを取り出すために Path メソッドもあります。

macOS のアプリケーションは .app という拡張子をもつディレクトリになっているため、その直前までのパスを取り出すのが少し面倒ですが、このメソッドで簡単に取り出せます。

最後に Version ですが、実行ファイルに結びついた Version 情報を Windows / macOS で統一的に扱えるようにしています。

バージョン画面で表示されるのは、この Version プロパティを使った値です。

version.png


まとめ

か、かわ、kわいい、ねこちゃん、かわいiね.:∴∵tanasinn∵∴∵∴





  1. 出典:http://ja.scp-wiki.net/scp-040-jp, CC BY-SA 3.0