2008年3月21日

 WPFを使ってニコニコ動画のコメントのようにデスクトップ上にメッセージを表示する試み。WPFプログラミング経験は皆無だったのだけど、わからないなりに調べたら結構できちゃうもんですね。まずは結果からどうぞ。

デスクトップ

 きちんと上から順に詰めて、隙間があればそこにメッセージを入れるようにまでした。

アニメーション

 メッセージのアニメーションはWPFの機能を使ってます。メッセージを追加する部分は次のような感じになってます。Labelを生成してBeginAnimationメソッドを呼び出しています。後で登場するXAMLも併せて参考に。

Private Sub AddFlowingMessage(ByVal message As String)
    Const TotalTime As Double = 3.5

    Dim label = New Label
    label.Content = message
    label.FontSize = 80

    ' (MainCanvasという名前の)Canvasに追加
    MainCanvas.Children.Add(label)

    ' Canvasに追加してUpdateLayoutしないとlabel.AcutualWidthが0.0
    label.UpdateLayout()

    Dim rect As New Rect( _
        Me.ActualWidth, _
        0.0, _
        label.ActualWidth, _
        label.ActualHeight)

    ' (GetNewMessageTopはメッセージのTop値を求める自作関数)
    Canvas.SetTop(label, GetNewMessageTop(label, rect))

    Dim animation = New DoubleAnimation
    animation.From = Me.ActualWidth   ' Windowsの右端から
    animation.To = -label.ActualWidth ' Labelが隠れるまで
    animation.Duration = New Duration(TimeSpan.FromSeconds(TotalTime))

    ' アニメーション終了時のイベントを関連付け
    AddHandler animation.Completed, AddressOf Animation_Completed

    ' アニメーション開始
    label.BeginAnimation(Canvas.LeftProperty, animation)

End Sub

 Windows.Formsなんかと違う点は……。Canvasは中の要素をTopやLeft値で位置を設定できるコンテナらしい。中のLabelのTop値を変更するには Canvas.SetTop なんてのを使う。ぐへぇ。

 あと、Labelの幅と高さ取得にはActualWidthとActualHeightを使う。Canvasに追加してUpdateLayoutメソッドを呼んでおかないと0.0になっちゃう。

 アニメーションの終わりをイベントとして知ることができるのだけどsenderオブジェクトはClockオブジェクトらしい。何のアニメーションが終わったかどうかは、わからない感じ?

透明なウィンドウ

 ウィンドウを透明にするには、こんなXAMLになる。WindowのWindowStyle、AllowsTransparency、Backgroundがポイント。AllowsTransparencyがTrueの場合、WindowStyleはNoneにしないとエラーになった。

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" 
    WindowStyle="None" AllowsTransparency="True" Background="Transparent"
    Topmost="True" WindowState="Maximized">
    <Grid>
        <Canvas x:Name="MainCanvas">
            <Button Click="Button_Click" Width="75" Height="30" Content="Click" />
        </Canvas>
    </Grid>
</Window>

 Buttonはデバッグ用です。非矩形にする方法は青柳さんのBlogからのリンクが参考になるかも。試してませんが。

枠付きの文字

 さて、上の例ではLabelを使っていたけど、文字に枠が付いていないから文字とバックの境界がわかり辛い。ニコニコ動画でも文字に外枠が付いている。これについてはMSDNライブラリの方法 : 中抜きの文字列を作成するがそのまんま参考になる。サンプルをダウンロードしてoutlinetextcontrol.csの内容をそのまんま頂けばOK。テキストからGeometryオブジェクトに変換すれば良いらしい。ClearTypeでなくなるのが少し難点。

WPFでスレッド

 メッセージを追加するメソッドはサブスレッドから呼ばれることを想定している。UIの操作をする場合UIのメインスレッドからしなくてはいけない。テスト用にとサブスレッドからUI操作するコードを書いたら怒られた。きちんとチェックしてあるんですねー。スレッドについては、Dispatcher を使用して応答性の高いアプリケーションを構築するが参考になります。

posted @ 13:21 | Feedback (357)

 ニコニコ動画のコメント風にメッセージを表示するPowerPointアドインを考えるより。もう少し手を加えてみたところ重大な問題が……。

 メッセージのアニメーションはPowerPointのアニメーション機能を使用していました。アニメーション中に新たなアニメーション付きラベルと追加すると、アニメーションが始めに戻ってしまうようです。考えてみたらアニメーションのタイミングを直前の動作と同時に設定しているので、PowerPointに求められる動作としてはそうなりますね。

 しかたないのでラベルのLeft値を変化させて自らアニメーションさせてみるコードも書いてみましたが、ものすごい処理がもたつく。表示がカクカクです。また、スライドの内容(テキストが多いとかテキストのスタイルとか)にもかなり影響されますね。さらに、スライド中の本来のアニメーション設定と相性が悪いようできちんとアニメーション表示できませんでした。

 Left値を使ったアニメーションは、編集中の画面でもラベルが動くのでその様子は楽しいですが上記によりPowerPointアドインでニコニコのコメント風表示は無理そうです。WPFの出番か……。続く。

posted @ 0:22 | Feedback (205)