WPFでニコニコ動画のコメント風表示

投稿日 : 2008年3月21日 13: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 を使用して応答性の高いアプリケーションを構築するが参考になります。

フィードバック

# re: WPFでニコニコ動画のコメント風表示

2008/03/21 13:25 by 中吉
(月末が楽しみだ...ニヤリ)

# re: WPFでニコニコ動画のコメント風表示

2008/03/21 13:47 by ぽぴ王子
> UIの操作をする場合UIのメインスレッドからしなくてはいけない。
これはWindowsFormもそうなんですよねー
Windowsのシステム的な制限なのかな?なんて思ってみたり。

あとはIRCから取ってくる部分はできているから、特定のキーワードの時だけ叫ぶようにするとかいう処理があるといいでしょうか。
(なんでもかんでも画面に出されると内緒話ができない(笑))

無駄に叫ぶ人多数と予測。自重。
「ろくしんがったーい!」とか「マジンガーぜーーーーっと!」とか。
「ゴルディオンハンマーーーー!!!」とかとか。

# re: WPFでニコニコ動画のコメント風表示

2008/03/21 14:07 by JZ5
コメントありがとうございます。

中吉さん
中吉ってちゅきさんかww
> 月末が楽しみだ
ええー!

ぽぴ王子さん
> これはWindowsFormもそうなんですよねー
ですねー。というかPowerPointのアドインでも一応そうしていました。Invokeメソッドが用意されていないのでめんどいですが、WPFでは用意されているてかつチェック機構があるので開発者に優しいといえば優しいですね。

> あとはIRCから取ってくる部分はできているから
いやいやいやww

> 特定のキーワードの時だけ叫ぶようにするとかいう処理
機能を考えるときりないでかもw プレゼンで使用する場合、発表者中心の考えがいいかなーと思ってます。発表者のタイミングでメッセージが出せるみたいな。表示のオン・オフ。フィルタリングなど。

# re: WPFでニコニコ動画のコメント風表示

2008/03/21 15:23 by 凪瀬
いくつかコマンドは欲しいですよね。
色とか文字の大きさとか、名前のON/OFFとか、絶対座標指定とか。

# re: WPFでニコニコ動画のコメント風表示

2008/03/21 21:34 by とっちゃん
ベータテストは来週末ですか?w

>Windowsのシステム的な制限なのかな?
です。STA やらMTAやらにも関与してきますが(こっちは、COM)、そもそもの根っこはWindowsメッセージキュー(MSMQではないw)と、HWNDのひもづけなので、ここが変わらない限り(変えようもないという話もあるがw)、変わらんですねw

>色とか文字の大きさとか
で、画面いっぱいに、ドーン!(バックの指と、吹き出しもw)と出せるようになるとw<おい!

# re: WPFでニコニコ動画のコメント風表示

2008/03/22 11:34 by JZ5
コメントありがとうございます。

凪瀬さん
> 色とか文字の大きさとか
IRCユーザ側
・IRCの色設定
・IRCで太字→フォント大
発表者側
・フォント普通と大に使用される大きさ指定

> 名前のON/OFFとか
発表者側
・ON/OFF指定

> 絶対座標指定とか
IRCユーザ側
・職人

私の中では以上という感じでしょうか。

とっちゃん
> ベータテストは来週末ですか?w
さーできるのかなーw

> です。
流石ですね! WPFではSTAなんちゃらって例外が出てたんだっけかなー。別スレッドの操作でどんな不具合があるのかイマイチわかんないです。あきらかに複数スレッドで同時に操作する場合を除いて。

> 画面いっぱいに、ドーン!
永遠に未実装です。

# re: WPFでニコニコ動画のコメント風表示

2009/03/22 2:04 by 夢曲
いつも拝見させていただいております。
夢曲と申します。よろしくお願いします。

試させていただいたのですが
animation.To = -label.ActualWidth
ここのところで
-label.ActualWidth
が実際に描画されている長さより短く設定されているためか
枠(Canvas)からはみ出す前にとまってしまいます。

また、枠からはみ出した部分は描画されないようにするにはどうしたら
よいのでしょうか?
教えていただければ幸いです。

# re: WPFでニコニコ動画のコメント風表示

2009/03/23 1:08 by JZ5
夢曲さん
コメントありがとうございます。

うーん。
実際にLabelの幅がActualWidthより長いか調べてみてください。そうでなければ他に原因がありそうです。
特に調べずに書きますが、CanvasにMargin等がついていて、Canvasからは外にでているけども見えている状態というのもあるかも。はみだした部分が見えているということは、そういうことでしょうか?
少し手前でアニメが終了するということであれば、一番簡単な(てけとーな)方法はアニメ終了位置を多めに設定しておくことでしょうね。
CanvasにMarginがあり、一部分だけはみだした部分のコントロールを表示しないということであれば、他のコントロールを上に置くとかしないとダメだと思います。

また、コードにはないですがアニメ終了したコントロールは破棄する必要があります。

# re: WPFでニコニコ動画のコメント風表示

2009/03/23 21:26 by 夢曲
返信ありがとうございます。
早速、試してみます。
コメントの入力
タイトル
 
名前
 
Url
コメント