時刻とともに、その日の出来事をキャラクターが音声で教えてくれるアプリを作る
次に、ソリューション・エクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト2のコードを記述します。
ロジックコードを記述する
リスト2 (MainWindow.xaml.vb)
‘ アプリケーションがスレッドプールを使用して作業項目を実行できるようにするクラスの含まれる、 ‘ Windows.System.Threading名前空間をインポートします。 Imports Windows.System.Threading Imports Windows.UI ‘ XML ドキュメント オブジェクト モデルのサポートを提供するクラスの含まれる、Windows.Data.Xml.Dom名前空間を ‘ インポートします。 Imports Windows.Data.Xml.Dom ‘ ファイル、フォルダおよびアプリケーションの設定を管理するクラスの含まれる、 ‘ Windows.Storage名前空間をインポートします。 Imports Windows.Storage ‘ シーケンシャルアクセスストリームおよびランダムアクセスストリームに対する読み取りと書きこみをサポートするクラスの含まれる ‘ Windows.Storage.Streams名前空間をインポートします。 Imports Windows.Storage.Streams Imports Windows.UI.Popups ‘ 最新の HTTP アプリケーションのプログラミング インターフェイスを提供するクラスの含まれる、 ‘ System.Net.Http 名前空間をインポートします。
Imports System.Net.Http Public NotInheritable Class MainPage Inherits Page Private myColorInfo As String ‘ 指定した時間の間隔で、指定した優先順位に処理されるDispacherキューに統合されているタイマーを表す、新しい、 ‘ DispatcherTimerクラスのインスタンスである、myTimerメンバー変数を宣言します。
Private myTimer As New DispatcherTimer Private myFont As String ‘ キャラクタが読み上げる内容を格納する文字列型のメンバー変数readingTextを宣言します。
Private readingText As String ‘ 乱数を発生させるRandomクラス型のメンバー変数Rndを宣言します。
Private Rnd As Random Private myMonth As String Private myDate As String
ページがアクティブになった時の処理
メンバー変数myMonthに現在の月を格納しておきます。メンバー変数myDateに現在の日付を格納しておきます。
ピクチャライブラリ—のXMLサブフォルダにアクセスします。
GetFilesAsyncメソッドでフォルダ内のファイルを取得して、コレクション変数myFileに格納します。ファイルの数が0より大きかった場合は、GetFileAsyncメソッドでXMLフォルダ内のmyColor.xmlを取得し、xmldoc変数で参照します。
xmldocで参照しているファイルを、
Await xmldoc.OpenAsync(FileAccessMode.Read)
と記述して読み取り専用で開き、myStreamで参照します。StreamReaderの新しいインスタンスreaderオブジェクトを作成し、myStreamで参照しているファイルと、エンコーディングUTF8で初期化します。Reader.ReadToEndでファイルを最後まで読み取り変数resultに格納します。
XElement.Parseメソッドでresult変数の内容を文字列として読み取ります。
変数_Colorに
_Color変数の値によって条件分岐を行います、RedからSalmonであった場合の処理を記述します。例えば_Colorが「Red」であった場合は、CascadingTextBlock1の文字色を「Red」に指定し、redRadioButtonにチェックを付けます。他の色の場合も同じ処理を行います。
CascadingTextBlock1のTextプロパティに現在の時刻を表示します。
CascadingTextBlock1.Text = DateTime.Now.ToString()
と指定しています、これを
CascadingTextBlock1.Text = DateTime.Now.ToString(“yyyy年MM月dd日HH時mm分ss秒”)
と指定するとエラーになります。CascadingTextBlockが日本語表示に対応していないようです。
CasCadingTextBlockのFontFamilyに_Font変数の値を指定します。myTimerのIntervalに10秒を指定します。
AddHandlerステートメントで、タイマー間隔が経過すると発生するTickイベントにイベントハンドラを指定します。
イベントハンドラ内では以下の処理を行います。
新しいRandomクラスのインスタンスRndを作成します。最少が「1」で最大が「5」のランダムな数字を発生させます。しかし最大値の「5」は含まれませんので、実際には「1~4」のランダムな数字が作成されます。
変数myRndの値で条件分岐を行います。「1~4」の間のランダムな数字に合わせてsyokoImageのSourceプロパティに、ソリューション・エクスプローラー内のImageフォルダに配置していたPNG画像を指定します。
CascadingTextBlock1に現在の時刻を表示し、キャラクタに喋らす内容をメンバー変数readingTextに格納します。
キャラクタが音声を発して喋るsyokoVoiceタスクを実行します。CascadingTextBlock1のAnimatedLoadedにTrueを指定し、
Await CascadingTextBlock1.BeginCascadingTransitionAsync()
と指定しカスケーディングトラジッションを伴って時刻の表示を開始します。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) myMonth = DateTime.Now.Month.ToString myDate = DateTime.Now.Day.ToString Dim result As String Dim _Color As String Dim _Font As String = String.Empty Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("XML", CreationCollisionOption.OpenIfExists) Dim myFile = Await mySubFolder.GetFilesAsync() If myFile.Count > 0 Then Dim xmldoc As StorageFile = Await mySubFolder.GetFileAsync("myColor.xml") Using myStream As IRandomAccessStream = Await xmldoc.OpenAsync(FileAccessMode.Read) Using reader As StreamReader = New StreamReader(myStream.AsStream, System.Text.Encoding.UTF8) result = reader.ReadToEnd End Using End Using Dim doc As XElement = XElement.Parse(result) _Color = doc.Descendants("Color").Value _Font = doc.Descendants("Font").Value Select Case _Color Case "Red" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Red) redRadioButton.IsChecked = True Case "Blue" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Blue) blueRadioButton.IsChecked = True Case "Green" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Green) greenRadioButton.IsChecked = True Case "White" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.White) whiteRadioButton.IsChecked = True Case "Yellow" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Yellow) goldRadioButton.IsChecked = True Case "Pink" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Pink) pinkRadioButton.IsChecked = True Case "Salmon" CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Salmon) salmonRadioButton.IsChecked = True End Select End If CascadingTextBlock1.Text = DateTime.Now.ToString() If _Font <> String.Empty Then CascadingTextBlock1.FontFamily = New FontFamily(_Font) myTimer.Interval = New TimeSpan(0, 0, 10) AddHandler myTimer.Tick, Async Sub() Rnd = New Random Dim myRnd = Rnd.Next(1,5) Select Case myRnd Case 1 syokoImage.Source = New BitmapImage(New Uri("ms-appx:///Image/syoko1.png", UriKind.Absolute)) Exit Select Case 2 syokoImage.Source = New BitmapImage(New Uri("ms-appx:///Image/syoko2.png", UriKind.Absolute)) Exit Select Case 3 syokoImage.Source = New BitmapImage(New Uri("ms-appx:///Image/syoko3.png", UriKind.Absolute)) Exit Select Case 4 syokoImage.Source = New BitmapImage(New Uri("ms-appx:///Image/syoko4.png", UriKind.Absolute)) Exit Select End Select CascadingTextBlock1.Text = DateTime.Now.ToString readingText = DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & "です。" Await syokoVoice() CascadingTextBlock1.AnimateOnLoaded = True Await CascadingTextBlock1.BeginCascadingTransitionAsync() End Sub myTimer.Start() End Sub
ページが非アクティブになった時の処理
タイマーを停止します。
Protected Overrides Sub OnNavigatedFrom(e As Navigation.NavigationEventArgs) myTimer.Stop() MyBase.OnNavigatedFrom(e) End Sub
redRadioButtonがチェックされた時の処理
CascadingTextBlock1の文字色を「Red」に指定します。メンバー変数myColorInfoに「Red」を格納します。
これ以後のpinkRadioButton_Checkedまでの処理も、この処理と同じですので、説明は省略します。
Private Sub redRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles redRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Red) myColorInfo = "Red" End Sub Private Sub blueRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles blueRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Blue) myColorInfo = "Blue" End Sub Private Sub greenRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles greenRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Green) myColorInfo = "Green" End Sub Private Sub whiteRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles whiteRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.White) myColorInfo = "White" End Sub Private Sub goldRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles goldRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Yellow) myColorInfo = "Yellow" End Sub Private Sub salmonRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles salmonRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Salmon) myColorInfo = "Salmon" End Sub Private Sub pinkRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles pinkRadioButton.Checked CascadingTextBlock1.Foreground = New SolidColorBrush(Colors.Pink) myColorInfo = "Pink" End Sub
[保存]アイコンがタップされた時の処理
XElement型の変数colorXmlを宣言し、埋め込み式の構文である を用いて
XElement.ParseメソッドでcolorXml.ToStringの内容を文字列として読み込みます。変数resultにXMLの内容を格納します。
ピクチャライブラリ—内のXMLサブフォルダにアクセスします。CreatFileAsyncメソッドでXMLサブフォルダ内にmyColor.xmlファイルを作成し、myXmlFileで参照します。
OpenAsyncメソッドでmyXmlFileを読み込み書きこみ専用で開き、変数myStreamで参照します。
myStreamオブジェクトで初期化された新しいDataWriterのインスタンスwriterを作成します。DataWriterクラスは、データを出力ストリームに書きこむクラスです。ユニコードにUtf8を指定し、WriteStringメソッドでXMLのデータを格納しているresult変数の内容を書きこみます。StoreAsyncメソッドでパッキングストアにバッファーのデータをコミットします。
保存した旨のメッセージを表示します。
Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click Dim colorXml As XElement = <ColorInfo><Color><%= myColorInfo %></Color><Font><%= myFont %></Font></ColorInfo> Dim xmldoc As XElement = XElement.Parse(colorXml.ToString) Dim result As String = xmldoc.ToString Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("XML", CreationCollisionOption.OpenIfExists) Dim myXmlFile As StorageFile = Await mySubFolder.CreateFileAsync("myColor.xml", CreationCollisionOption.ReplaceExisting) Using myStream As IRandomAccessStream = Await myXmlFile.OpenAsync(FileAccessMode.ReadWrite) Dim writer As DataWriter = New DataWriter(myStream) writer.UnicodeEncoding = UnicodeEncoding.Utf8 writer.WriteString(result) Await writer.StoreAsync End Using Dim message As New MessageDialog("設定を保存しました。") Await message.ShowAsync End Sub
CountDownControlが最後までカウントされた時の処理
syokoImageを表示状態にします。CountDownControlを非表示にします。
Private Sub CountdownControl1_CountdownComplete(sender As Object, e As RoutedEventArgs) Handles CountdownControl1.CountdownComplete syokoImage.Visibility = Xaml.Visibility.Visible CountdownControl1.Visibility = Xaml.Visibility.Collapsed End Sub
フォントを表示しているComboBoxからフォントが選択された時の処理
変数myComboItemにComboBoxから選択された項目名を格納します。
選択された項目名によって、条件分岐を行います。例えば、「文字2」が選択された場合は、メンバー変数myFontにソリューション・エクスプローラー内のFontフォルダにあるフォント名を次のように指定します。
myFont = "Font/YournameS7FinancialFull.ttf#YournameS7FinancialFull"
Fontフォルダの前に”ms-appx:///”の記述はこの場合不要です。あっても問題はありません。「文字5」までに対して同様の処理を行います。
CascadingTextBlock1のFontFamilyにmyFontを指定すると、指定されたフォントで時刻が表示されます。
Private Sub fontComboBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles fontComboBox.SelectionChanged Dim myComboItem = DirectCast(fontComboBox.SelectedItem, ComboBoxItem).Content.ToString Select Case myComboItem Case "文字1" myFont = "Font/meiryob.ttc#meiryob" Exit Select Case "文字2" myFont = "Font/YournameS7FinancialFull.ttf#YournameS7FinancialFull" Exit Select Case "文字3" myFont = "Font/YournameS12Financial.ttf#YournameS12Financial" Exit Select Case "文字4" myFont = "Font/YournameL12SquareRoundFull.ttf#YournameL12SquareRoundFull" Exit Select Case "文字5" myFont = "Font/YournameS7FinancialHalf.ttf#YournameS7FinancialHalf" Exit Select End Select CascadingTextBlock1.FontFamily = New FontFamily(myFont) End Sub
時刻をキャラクタが音声で喋る処理
MediaElement型のmyMedia変数を宣言し、MediaElement1で初期化しておきます。
音声機能へのアクセスを提供する、新しいSpeechSynthesizerのインスタンス、synthオブジェクトを作成します。
SynthesizeTextToStreamAsyncメソッドで、指定した文字列から、音声出力を非同期に生成します。
SetSourceメソッドで、指定されたストリームおよびMIME型を使用してSourceプロパティを設定します。Playメソッドで音声を再生します。
音声にどんな言語で、どのような声で喋らすかは、SpeechSynthesizerのVoiceプロパティで参照できます。下記のURLを参照してください。
> SpeechSynthesizer.Voice | voice property
上記URLを見るとJapanese JA は性別が「Female」で、名前は「Haruka」という女性が読み上げるようです。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
Private Async Function syokoVoice() As Task Dim myMedia As MediaElement = Me.MediaElement1 Dim synth = New Windows.Media.SpeechSynthesis.SpeechSynthesizer Dim stream = Await synth.SynthesizeTextToStreamAsync(readingText) myMedia.SetSource(stream, stream.ContentType) myMedia.Play() End Function
CascadingTextBlockのアニメ—ションが完了した場合の処理
「今日は何の日」APIを使用します。下記のURLを参照してください。
> 「今日は何の日」API
変数whatsDayUriに
String.Format("http://www.mizunotomoaki.com/wikipedia_daytopic/api.cgi/{0}", myMonth & "/" & myDate)
と指定します。引数に現在の月(myMonth)と現在の日(myDate)をスラッシュ(/)で連結して指定します。
新しいHttpClientのインスタンスmyHttpClientオブジェクトを作成します。
GetStringAsyncメソッドで、指定したURIにGET要求を送信し、非同期処理で応答本体を文字列として取得し、変数resultに格納します。
XElement.Parseメソッドで変数resultの値を文字列として読み込みます。
変数queryにインデックスが0番目の
MessageTextBlockにquery変数の内容を表示します。
Private Async Sub CascadingTextBlock1_CascadeCompleted(sender As Object, e As EventArgs) Handles CascadingTextBlock1.CascadeCompleted Dim whatsDayUri = String.Format("http://www.mizunotomoaki.com/wikipedia_daytopic/api.cgi/{0}", myMonth & "/" & myDate) Dim myHttpClient As New HttpClient Dim result = Await myHttpClient.GetStringAsync(whatsDayUri) Dim xmldoc As XElement = XElement.Parse(result) Dim query = xmldoc.Descendants("kinenbi_detail")(0).Elements("item").Elements("description").Value MessageTextBlock.Text = "今日は【" & query & "】の日です。" End Sub End Class
今回はここまでです。また次回の記事でお会いしましょう。
時刻とともに、その日に起こった出来事をキャラクターが教えてくれるアプリ
『Windows 8.1+Visual Studio 2013によるWindows ストア・アプリ開発実例集』 第10回のサンプルプログラムです。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Windows8のストア画面で手軽に時計を表示するサンプル
- 指定した目的地までの距離をキャラクターが教えてくれるアプリを作ろう
- キャラクターが声で天気予報を教えてくれるアプリを作る
- 近くにある病院の場所をキャラクターが音声で教えてくれるアプリを作る
- APIを使って土地の公示価格を調べるプログラムを作る
- Bing Maps上に地震の震源地を表示するプログラムを作る
- 現在位置近くの病院を素早く検索するサンプルプログラム
- フリーハンドで書いた住所を認識してBing Map上に表示する
- 現在位置の近くにある宿を検索するサンプルプログラム
- 画面上を流れる数字を暗算して正解を求めるアプリを作ろう(その2)