トレイアイコンをアニメーション表示してみる

今回は、自分で準備したアイコンイメージを使って、トレイアイコンをアニメーション表示する方法を紹介しましょう。

トレイアイコンのアニメーション

手順としては、アニメーションをするのに必要なだけのアイコンオブジェクトを作成しておき、 Shell_NotifyIcon 関数を繰り返し呼び出して、アイコンを変更していきます。 Shell_NotifyIcon 関数についてはこれまでに使ってきているので、特に説明の必要はないでしょう。

問題となるのはアイコンの作成です。任意のイメージからアイコンを作成するのにはいくつか方法がありますが、今回はイメージリストからアイコンを作成する方法を使ってみることにしましょう。

手順は以下のようになります。

  1. アニメーションに必要なイメージを持ったイメージリストを作成する。
  2. ImageList_GetIcon 関数を呼び出してイメージリストからすべてのイメージのアイコンを作成し、その後イメージリストを破棄する。
  3. 一定時間ごとに Shell_NotifyIcon 関数を呼び出して、トレイアイコンを変更する。
  4. 終了時にアイコンを破棄する。

イメージリストの作成

まずは、トレイアイコンのアニメーションに使用したいイメージをすべて含んだイメージリストを作成します。透明部分を持つアイコンを作成するために、イメージリストはマスク付きで作成しておきましょう。

イメージリストについては、『イメージリストを作成してみる』の項を参照してください。

イメージリストからのアイコンの作成

イメージリストからアイコンを作成するには、 ImageList_GetIcon 関数を呼び出します。

HICON ImageList_GetIcon(
    HIMAGELIST himl,   // イメージリストのハンドル
    int        index,  // イメージのインデックス
    UINT       flags   // 描画スタイル
);

himl パラメータにはイメージリストのハンドルを、 index パラメータにはイメージリスト中におけるイメージのインデックスを指定します。今回はマスク部分を透明化したアイコンを作成したいので、 flags パラメータには 1 (ILD_TRANSPARENT) を指定します。

この関数は、戻り値として作成されたアイコンのハンドルを返します。すべてのイメージのアイコンを作成し、ハンドルを配列変数に格納しておきましょう。

今回は、タスクトレイに表示されたアイコン上でマウスクリックされたときに、ショートカットメニューを表示するようにしてみましょう。

すべてのイメージのアイコンを作成できたら、イメージリストはもう必要なくなります。したがって、 ImageList_Destroy 関数でイメージリストを破棄しておきます。

トレイアイコンの変更

すでにタスクバーのステータスエリアに表示されているアイコンを変更するには、まず、 NOTIFYICONDATA 構造体の uFlags メンバに 2 (NIF_ICON) を指定し、 hIcon メンバに新しいアイコンハンドルを指定します。そして、 Shell_NotifyIcon 関数の第1引数(dwMessage パラメータ)に 1 (NIM_MODIFY) を指定します。

この関数では、アイコンイメージだけでなく、ツールチップ文字列を変更することもできます。この場合には、 NOTIFYICONDATA 構造体の uFlags メンバに 4 (NIF_TIP) を指定し、 szTip メンバには新しいツールチップ文字列を格納しておきます。

サンプルスクリプト

さて、実際にスクリプトを書いてみます。

アイコン用のイメージとして、以下の画像を使用します。このビットマップファイルは、1つのイメージサイズが 16×16 ピクセルで、それを横に4つつなげたものになっています。マスクを生成する色として、白(RGB値は 0xFFFFFF )を指定します。

(iconlist2.bmp)

ビットマップファイルのダウンロード

サンプルスクリプト main.as

    #include "llmod.as"

    #module ;###### ビットマップオブジェクト作成モジュール #########

    ;===============================================================
    ; 描画中ウィンドウのイメージからビットマップオブジェクト(DIB)作成
    ; CreateDIB  p1, p2, p3, p4
    ;     p1 : HSPウィンドウx座標
    ;     p2 : HSPウィンドウy座標
    ;     p3 : 幅
    ;     p4 : 高さ
    ;   stat : ビットマップのハンドルが返る
    ;===============================================================
    #deffunc CreateDIB int, int, int, int
    mref px, 0              ; HSPウィンドウx座標
    mref py, 1              ; HSPウィンドウy座標
    mref sx, 2              ; xサイズ
    mref sy, 3              ; yサイズ
    mref stt, 64            ; stat
    mref bmscr, 67          ; 描画中ウィンドウのBMSCR構造体

    ; DIBセクションオブジェクト作成
    pm = bmscr.4, sx, sy
    dllproc "CreateCompatibleBitmap", pm, 3, D_GDI@
    hbitmap = stat          ; ビットマップオブジェクトのハンドル

    ; メモリデバイスコンテキスト作成
    pm = bmscr.4
    dllproc "CreateCompatibleDC", pm, 1, D_GDI@
    hdcMemory = stat        ; メモリデバイスコンテキストのハンドル

    ; ビットマップをデバイスコンテキストに選択
    pm = hdcMemory, hbitmap
    dllproc "SelectObject", pm, 2, D_GDI@

    ; HSPウィンドウからビットマップにイメージをコピー
    pm = hdcMemory, 0, 0, sx, sy, bmscr.4, px, py, $CC0020
    dllproc "BitBlt", pm, 9, D_GDI@

    ; デバイスコンテキストを削除
    dllproc "DeleteDC", hdcMemory, 1, D_GDI@

    stt = hbitmap           ; ビットマップオブジェクトのハンドル
    return

    #global ;############# モジュール終わり ########################

    #module ;######### イメージリスト操作モジュール ################

    ;===============================================================
    ; イメージリストの作成
    ; CreateImageList  p1, p2, p3, p4
    ;     p1 : イメージの幅
    ;     p2 : イメージの高さ
    ;     p3 : イメージリストのタイプ
    ;     p4 : イメージの数
    ;   stat : イメージリストのハンドルが返る
    ;===============================================================
    #deffunc CreateImageList int, int, int, int
    mref sx, 0              ; イメージの幅
    mref sy, 1              ; イメージの高さ
    mref flags, 2           ; イメージリストのタイプ
    mref num, 3             ; イメージの数

    ; イメージリストの作成
    pm.0 = sx
    pm.1 = sy
    pm.2 = flags
    pm.3 = num
    pm.4 = 0
    dllproc "ImageList_Create", pm, 5, D_COMCTL@
    return

    ;===============================================================
    ; イメージリストに描画中ウィンドウのイメージ追加
    ; AddImageList  p1, p2, p3, p4, p5
    ;     p1 : イメージリストのハンドル
    ;     p2 : HSPウィンドウx座標
    ;     p3 : HSPウィンドウy座標
    ;     p4 : 幅
    ;     p5 : 高さ
    ;     p6 : マスクに用いる色
    ;   stat : イメージのインデックスが返る
    ;===============================================================
    #deffunc AddImageList int, int, int, int, int, int
    mref himl, 0            ; イメージリストのハンドル
    mref cx, 1              ; x座標
    mref cy, 2              ; y座標
    mref sx, 3              ; xサイズ
    mref sy, 4              ; yサイズ
    mref crmask, 5          ; マスク生成に用いる色
    mref stt, 64            ; stat

    ; DIBオブジェクトの作成
    CreateDIB  cx, cy, sx, sy
    hbitmap = stat          ; ビットマップハンドル

    ; ビットマップをイメージリストに追加
    pm.0 = himl
    pm.1 = hbitmap
    pm.2 = crmask
    dllproc "ImageList_AddMasked", pm, 3, D_COMCTL@
    index = stat            ; 最初のイメージのインデックス

    ; ビットマップオブジェクトを削除
    dllproc "DeleteObject", hbitmap, 1, D_GDI@

    stt = index             ; イメージのインデックスをstatに格納
    return

    ;===============================================================
    ; イメージリストの破棄
    ; DestroyImageList  p1
    ;     p1 : イメージリストのハンドル
    ;===============================================================
    #deffunc DestroyImageList int
    mref himl, 0            ; イメージリストのハンドル

    ; イメージリストを破棄
    pm.0 = himl
    dllproc "ImageList_Destroy", pm, 1, D_COMCTL@
    return

    ;===============================================================
    ; イメージリストのイメージからアイコン作成
    ; GetIconImageList  p1, p2
    ;     p1 : イメージリストのハンドル
    ;     p2 : イメージのインデックス
    ;   stat : アイコンハンドルが返る
    ;===============================================================
    #deffunc GetIconImageList int, int
    mref himl, 0            ; イメージリストのハンドル
    mref index, 1           ; イメージのインデックス

    ; アイコン作成
    pm.0 = himl
    pm.1 = index
    pm.2 = 1                ; ILD_TRANSPARENT
    dllproc "ImageList_GetIcon", pm, 3, D_COMCTL@
    return

    #global ;############# モジュール終わり ########################

    ; トレイアイコン用のアイコンID
    #define ID_TRAYICON         1

    ; トレイアイコン用のメッセージコード
    #define MYWM_TRAYICON       0x1000

    #define ICON_SIZE_X 16      ; アイコンイメージの幅
    #define ICON_SIZE_Y 16      ; アイコンイメージの高さ
    #define ICON_NUM    4       ; アイコンイメージの数

    ; ビットマップファイルの読み込み
    buffer 2,,, 0
    picload "iconlist2.bmp"

    ; 24bit DIB イメージリスト作成(マスクあり)
    CreateImageList ICON_SIZE_X, ICON_SIZE_Y, 0x0018 | 0x0001, ICON_NUM
    himl = stat             ; イメージリストのハンドル

    ; イメージをイメージリストに追加(白を透過色に)
    AddImageList himl, 0, 0, ICON_SIZE_X*ICON_NUM, ICON_SIZE_Y, 0xFFFFFF

    ; アイコンハンドルを格納する変数
    dim hicon, ICON_NUM

    ; イメージリストからアイコン作成
    repeat ICON_NUM
        GetIconImageList himl, cnt
        hicon.cnt = stat
    loop

    ; イメージリストの破棄
    DestroyImageList himl

    gsel 0
    mref bmscr, 67              ; ウィンドウのBMSCR構造体
    hwnd = bmscr.13             ; ウィンドウハンドル

    ; NOTIFYICONDATA 構造体
    tooltext = "トレイアイコンのアニメーションのテスト"
    dim  nid, 22
    nid.0 = 88, hwnd, ID_TRAYICON, 1|2|4, MYWM_TRAYICON, hicon.0
    poke nid, 24, tooltext      ; ツールチップ文字列

    ; タスクトレイにアイコンを追加
    pm.0 = 0                    ; NIM_ADD
    getptr pm.1, nid            ; NOTIFYICONDATA 構造体アドレス
    dllproc "Shell_NotifyIconA", pm, 2, D_SHELL

    onexit *onQuit

*mainloop
    wait 10
    if wcnt > 5 {
        ; 次のアイコンに変更する
        gosub *ChangeIcon
        wcnt = 0
    }
    wcnt++
    goto *mainloop

*ChangeIcon
    iconindex++
    if iconindex >= ICON_NUM : iconindex = 0

    ; NOTIFYICONDATA 構造体
    dim  nid, 22
    nid.0 = 88                  ; 構造体サイズ
    nid.1 = hwnd                ; ウィンドウハンドル
    nid.2 = ID_TRAYICON         ; アイコンID
    nid.3 = 2                   ; NIF_ICON
    nid.5 = hicon.iconindex     ; 新しいアイコンのハンドル

    ; タスクトレイのアイコンを変更
    pm.0 = 1                    ; NIM_MODIFY
    getptr pm.1, nid            ; NOTIFYICONDATA 構造体アドレス
    dllproc "Shell_NotifyIconA", pm, 2, D_SHELL
    return

*onQuit
    ; 終了時の処理

    ; NOTIFYICONDATA 構造体(cbSize, uID のみセット)
    dim  nid, 22
    nid.0 = 88                  ; 構造体サイズ(=88)
    nid.1 = hwnd                ; ウィンドウハンドル
    nid.2 = ID_TRAYICON         ; アイコンID

    ; タスクトレイからアイコンを削除
    pm.0 = 2                    ; NIM_DELETE
    getptr pm.1, nid            ; NOTIFYICONDATA 構造体アドレス
    dllproc "Shell_NotifyIconA", pm, 2, D_SHELL

    ; アイコンの破棄
    repeat ICON_NUM
        pm = hicon.cnt
        dllproc "DestroyIcon", hicon, 1, D_USER
    loop

    end