お花とクラウディアさんを合成して表示するプログラムを作る
※前ページからの続きです。
画面にクラウディアの画像を表示しピンチで拡大縮小、ドラッグをする処理
ファイルを表すメンバ変数claudiaImageにGetFileFromApplicationUriAsyncメソッドを使って、Imageを格納しているフォルダとクラウディアのファイル名を格納しているメンバ変数claudiaImageFileNameを連結した上で、指定した URI のアプリケーションリソースを表す StorageFile オブジェクトを取得します。
新しいBitmapImageクラスのインスタンスmyBmpを作成します。
SetSourceメソッドにAwait claudiaImage.OpenReadAsyncと指定して画像ファイルを開きます。新しいImageクラスのインスタンスmyClaudiaImageを作成します。
WidthとHeightプロパティを指定し、SourceプロパティにmyBmpオブジェクトを指定します。
UIElementの描画位置に影響する変換情報設定するRenderTransformプロパティにオブジェクトに複数の変換操作を適用するCompositeTransformを指定します。
ジェスチャとともにUIElementの動作および操作に使用されるManipulationModeプロパティに、全ての対話モードを有効にする、ManipulationModes.Allを指定します。
CanvasにmyClaudiaImageオブジェクトを追加します。画面一杯にクラウディアの画像が表示されます。
AddHandlerステートメントで、myClaudiaImageオブジェクトの操作中に、入力デバイスが位置を変更した時に発生するManipulationDeltaイベントにイベントハンドラを追加します。
イベントハンドラ内では以下の処理を行います。
TranslateXとTranslateYでx軸とy軸にそって平行移動する距離を設定します。
ScaleXとScaleYでオブジェクトを拡大縮小する値を設定します。
クラウディアの画像一覧が表示されているListBoxの使用を不可とします。
Private Async Sub claudiaShow() claudiaImage = Await StorageFile.GetFileFromApplicationUriAsync(New Uri("ms-appx:///Images/" & claudiaImageFileName)) Dim myBmp As New BitmapImage myBmp.SetSource(Await claudiaImage.OpenReadAsync) myClaudiaImage = New Image With myClaudiaImage .Width = myBmp.PixelWidth .Height = myBmp.PixelHeight .Source = myBmp .RenderTransform = New CompositeTransform .ManipulationMode = ManipulationModes.All End With Canvas1.Children.Add(myClaudiaImage) AddHandler myClaudiaImage.ManipulationDelta, Sub(mySender As Object, myArgs As ManipulationDeltaRoutedEventArgs) myTrans = DirectCast(myClaudiaImage.RenderTransform, CompositeTransform) myTrans.TranslateX = myTrans.TranslateX + myArgs.Delta.Translation.X myTrans.TranslateY = myTrans.TranslateY + myArgs.Delta.Translation.Y myTrans.ScaleX = myTrans.ScaleX * myArgs.Delta.Scale myTrans.ScaleY = myTrans.ScaleY * myArgs.Delta.Scale End Sub claudiaListBox.IsEnabled = False End Sub
画面に花の画像を表示しピンチで拡大縮小、ドラッグをする処理
ファイルを表すメンバ変数flowerImageにGetFileFromApplicationUriAsyncメソッドを使って、Imageを格納しているフォルダと花のファイル名を格納しているメンバ変数FlowerFileを連結し、指定した URI のアプリケーションリソースを表す StorageFile オブジェクトを取得します。
新しいBitmapImageクラスのインスタンスmyBmpを作成します。
SetSourceメソッドにAwait flowerImage.OpenReadAsyncと指定して画像ファイルを開きます。新しいImageクラスのインスタンスmyFlowerImageを作成します。
WidthとHeightプロパティを指定し、SourceプロパティにmyBmpオブジェクトを指定します。
UIElementの描画位置に影響する変換情報設定するRenderTransformプロパティにオブジェクトに複数の変換操作を適用するCompositeTransformを指定します。
ジェスチャとともにUIElementの動作および操作に使用されるManipulationModeプロパティに、全ての対話モードを有効にする、ManipulationModes.Allを指定します。
CanvasにmyFlowerImageオブジェクトを追加します。画面一杯に花の画像が表示されます。
AddHandlerステートメントで、myFlowerImageオブジェクトの操作中に、入力デバイスが位置を変更した時に発生するManipulationDeltaイベントにイベントハンドラを追加します。
イベントハンドラ内では以下の処理を行います。
TranslateXとTranslateYでx軸とy軸にそって平行移動する距離を設定します。
ScaleXとScaleYでオブジェクトを拡大縮小する値を設定します。
花の画像一覧が表示されているListBoxの使用を不可とします。
Private Async Sub FlowerShow() flowerImage = Await StorageFile.GetFileFromApplicationUriAsync(New Uri("ms-appx:///Images/" & FlowerFile)) Dim myBmp As New BitmapImage myBmp.SetSource(Await flowerImage.OpenReadAsync) myFlowerImage = New Image With myFlowerImage .Width = myBmp.PixelWidth .Height = myBmp.PixelHeight .Source = myBmp .RenderTransform = New CompositeTransform .ManipulationMode = ManipulationModes.All End With Canvas1.Children.Add(myFlowerImage) AddHandler myFlowerImage.ManipulationDelta, Sub(mySender As Object, myflowerArgs As ManipulationDeltaRoutedEventArgs) myFlowerTrans = DirectCast(myFlowerImage.RenderTransform, CompositeTransform) myFlowerTrans.TranslateX = myFlowerTrans.TranslateX + myflowerArgs.Delta.Translation.X myFlowerTrans.TranslateY = myFlowerTrans.TranslateY + myflowerArgs.Delta.Translation.Y myFlowerTrans.ScaleX = myFlowerTrans.ScaleX * myflowerArgs.Delta.Scale myFlowerTrans.ScaleY = myFlowerTrans.ScaleY * myflowerArgs.Delta.Scale End Sub flowerListBox.IsEnabled = False End Sub
「クラウディア前面」にチェックが付いた時の処理
メンバ変数Indexを10で初期化、flowerIndexを0で初期化します。
SetValueプロパティでクラウディア画像のZIndexの値を指定します。同様に花のZIndexの値を指定します。
これで、クラウディアが花より前面に表示されます。ZIndex値が大きいほど前面に表示されます。
Private Sub frontClaudiaRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles frontClaudiaRadioButton.Checked Index = 10 flowerIndex = 0 myClaudiaImage.SetValue(Canvas.ZIndexProperty, Index) myFlowerImage.SetValue(Canvas.ZIndexProperty, flowerIndex) End Sub
「クラウディア背面」にチェックが付いた時の処理
メンバ変数Indexを0で初期化、flowerIndexを10で初期化します。
SetValueプロパティでクラウディア画像のZIndexの値を指定します。同様に花のZIndexの値を指定します。
これで、クラウディアが花より背面に表示されます。
Private Sub backClaudiaRadioButton_Checked(sender As Object, e As RoutedEventArgs) Handles backClaudiaRadioButton.Checked Index = 0 flowerIndex = 10 myClaudiaImage.SetValue(Canvas.ZIndexProperty, Index) myFlowerImage.SetValue(Canvas.ZIndexProperty, flowerIndex) End Sub
[Save]アイコンがタップされた時の処理
「クラウディア前面」「クラウディア背面」のどちらも選択されていない場合は警告メッセージを表示して処理を抜けます。
変数flowerWidthに花の幅にX軸の拡大縮小の値myFlowerTrans.ScaleXを乗算して指定します。
変数flowerHeightに花の高さにY軸の拡大縮小の値myFlowerTrans.ScaleYを乗算して指定します。
変数claudiaWidthにクラウディアの幅にX軸の拡大縮小の値myTrans.ScaleXを乗算して指定します。
変数claudiaHeightにクラウディアの高さにY軸の拡大縮小の値myTrans.ScaleYを乗算して指定します。
ピクチャライブラリにアクセスします。CreateFolderAsyncメソッドで、ピクチャライブラリ内にFlowerAndClaudiaというサブフォルダを作成します。
CreationCollisionOption.OpenIfExistsを指定すると、既に同名フォルダが存在する場合はフォルダ名を返し、ない場合は新規に作成します。
Visual Basic の埋め込み式を用いて、ルート要素
属性”Width”にflowerWidth変数の値を指定します。
属性”Height”にflowerHeightの値を指定します。
属性”Top”にはmyFlowerTrans.TranslateY.ToStringの値を、属性”Left”にはmyFlowerTrans.TranslateX.ToStringの値を指定します。
属性”FlowerIndex”にはZIndexの値となる変数flowerIndexの値を指定します。
同じく
属性”Width”にclaudiaWidth変数の値を指定します。
属性”Height”にclaudiaHeightの値を指定します。
属性”Top”にはmyTrans.TranslateY.ToStringの値を、属性”Left”にはmyTrans.TranslateX.ToStringの値を指定します。
属性Index”にはZIndexの値となる変数Indexの値を指定します。
埋め込み式の構文であるを用いています。これは ASP.NET で使用される構文と同じです。作成したXML文書を変数saveXmlに格納します。
XElemet.Parseメソッドで作成したXMLを文字列として読み込みます。読み込んだ結果XMLを変数resultに格納しておきます。
CreateFileAsyncメソッドでピクチャライブラリのFlowerAndClaudiaサブフォルダ内に現在の年月日時分秒.xmlというファイルを作成します。
CreationCollisionOption.ReplaceExistingと指定し、既に同名のファイルがある場合は上書きします。
OpenAsyncメソッドで作成した現在の年月日時分秒.xmlを「読み取り/書き込み」モードで開き、入出力データへの、ランダムアクセスをサポートするIRandomAccessStreamインターフェース型のmyStreamで参照します。
データを出力ストリームに書き込む、新しいDataWriterのインスタンスをmyStreamで初期化し、writerオブジェクトを作成します。
出力ストリームのUnicode文字エンコードを設定する、UnicodeEncodingプロパティにUtf8を指定します。
Writeメソッドで出力ストリームにresult変数の値を書き込みます。StoreAsyncメソッドでバッキングストアにバッファーのデータをコミットします。Canvas内をクリアします。
文字列型のリストであるmyFileListを作成します。
GetFilesAsyncメソッドでFlowerAndClaudiaサブフォルダ内のファイルを取得します。
Countメソッドでファイルの個数を取得し、ファイルが存在した場合は、以下の処理を行います。
- FlowerAndClaudiaサブフォルダ内のファイルのコレクション内を、変数fileResultで反復処理しながら、AddメソッドでmyFileListにファイル名を追加していきます。
- fileResult.Pathで取得されるファイル名は絶対パス付きファイル名になりますので、Path.GetFileNameWithoutExtension(fileResult.Path)として、パスと拡張子を除いたファイル名を取得し、再度拡張子となる”.xml”と連結します。
- fileListBoxのItemsSourceプロパティにmyFileListオブジェクトを追加します。
- これで、ファイルが存在する場合はListBoxに表示されます。
[Save]ボタンの使用を不可とします。
クラウディアの表示されているListBoxの選択状態を解除します。RadioButtonのチェックも外します。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click If frontClaudiaRadioButton.IsChecked = False AndAlso backClaudiaRadioButton.IsChecked = False Then Dim myMessage As New MessageDialog("クラウディアの前面、背面にチェックを付けてください。") Await myMessage.ShowAsync Exit Sub End If Dim flowerWidth = CInt(myFlowerImage.Width * myFlowerTrans.ScaleX) Dim flowerHeight = CInt(myFlowerImage.Height * myFlowerTrans.ScaleY) Dim claudiaWidth = CInt(myClaudiaImage.Width * myTrans.ScaleX) Dim claudiaHeight = CInt(myClaudiaImage.Height * myTrans.ScaleY) Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim SubFolder = Await myFolder.CreateFolderAsync("FlowerAndClaudia", CreationCollisionOption.OpenIfExists) Dim saveXml As XElement = <Claudia><Info><FlowerImage Width=<%= flowerWidth %> Height=<%= flowerHeight %> Top=<%= myFlowerTrans.TranslateY.ToString %> Left=<%= myFlowerTrans.TranslateX.ToString %> FlowerZindex=<%= flowerIndex %>><%= FlowerFile %></FlowerImage><ClaudiaImage Width=<%= claudiaWidth %> Height=<%= claudiaHeight %> Top=<%= myTrans.TranslateY.ToString %> Left=<%= myTrans.TranslateX.ToString %> Zindex=<%= Index.ToString %>><%= claudiaImageFileName %></ClaudiaImage></Info></Claudia> Dim saveXmldoc As XElement = XElement.Parse(saveXml.ToString) Dim result As String = saveXmldoc.ToString Dim myXmlFile As StorageFile = Await SubFolder.CreateFileAsync(DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".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 Canvas1.Children.Clear() Dim myFileList As New List(Of String) Dim myReadXmlFile = Await SubFolder.GetFilesAsync If myReadXmlFile.Count > 0 Then For Each fileResult As StorageFile In myReadXmlFile myFileList.Add(Path.GetFileNameWithoutExtension(fileResult.Path) & ".xml") Next Else fileListBox.Items.Clear() End If fileListBox.ItemsSource = myFileList saveButton.IsEnabled = False claudiaListBox.SelectedIndex = -1 claudiaListBox.IsEnabled = True frontClaudiaRadioButton.IsChecked = False backClaudiaRadioButton.IsChecked = False End Sub
戻る(←)アイコンがタップされた時の処理
Frameを非表示にし、XMLファイルが存在する場合はListBoxにXMLファイルの一覧を表示し、クラウディアや花の画像をListBoxに表示するDataShowプロシージャを実行します。
Private Sub backButton_Click(sender As Object, e As RoutedEventArgs) Handles backButton.Click myFrame.Visibility = Windows.UI.Xaml.Visibility.Collapsed DataShow() End Sub
ファイルが選択された時の処理
Frameを表示状態にします。ListBoxから選択されたファイル名を変数mySelectedFileに格納します。
Navigateメソッドで変数mySelectedFileを引数にDataShowPageに遷移します。
Private Sub fileListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles fileListBox.SelectionChanged Try myFrame.Visibility = Windows.UI.Xaml.Visibility.Visible Dim mySelectedFile As String = fileListBox.SelectedItem.ToString myFrame.Navigate(GetType(DataShowPage), mySelectedFile) Catch myFrame.Visibility = Windows.UI.Xaml.Visibility.Collapsed Exit Sub End Try End Sub End Class
次に、ソリューションエクスプローラー内のDataShowPage.xamlを展開して表示される、DataShowPage.xaml.vbをダブルクリックしてリスト5のコードを記述します。
ロジックコードを記述する
リスト5 (DataShowPage.xaml.vb)
Option Strict On Imports Windows.Storage Imports Windows.Storage.Streams Imports Windows.UI.Popups Public NotInheritable Class DataShowPage Inherits Page Dim mySelectedFile As String
ページがアクティブになった時の処理
MainPage.xamlから送られてきた値はe.Parameterで取得できます。これはObject型であるため、DirectCastでString型に変換して変数mySelectedFileに格納しておきます。選択されたXMLファイルが格納されます。
ピクチャライブラリにアクセスします。
CreateFolderAsyncメソッドで、ピクチャライブラリ内にFlowerAndClaudiaというサブフォルダを作成します。
CreationCollisionOption.OpenIfExistsを指定すると、既に同名フォルダが存在する場合はフォルダ名を返し、ない場合は新規に作成します。
GetFileAsyncメソッドでFlowerAndClaudiaサブフォルダ内のmySelectedFile変数に格納されているファイルを取得します。
OpenAsyncメソッドでXMLファイルを「読み取り」モードで開き、入出力データへの、ランダムアクセスをサポートするIRandomAccessStreamインターフェース型のmyStreamで参照します。
読み込んだXMLファイルと文字コードで初期化された新しいStreamReaderクラスのインスタンスreaderオブジェクトを作成します。
ReadToEndメソッドでXML文書を末尾まで読み込み変数resultに格納します。
XElement.Parseメソッドで変数resultの値を文字列として読み込みます。
読み込んだXMLファイルからクラウディアの画像名、Width、Height、Top、Left、Zindexの値を取得します。
同様に花の画像名、Width、Height、Top、Left、FlowerZindexの値を取得します。
新しいImageクラスのインスタンスflowerImgを作成します。
Width、Height、SourceにXMLから読み込んだ値を指定します。
MarginプロパティにはLeftとTopの値を指定します。
SetValueに花のZIndexの値を指定します。ShowAreaというCanvas内に花の画像を表示します。
新しいImageクラスのインスタンスclaudiaImgを作成します。
Width、Height、SourceにXMLから読み込んだ値を指定します。
MarginプロパティにはLeftとTopの値を指定します。
SetValueにクラウディアのZIndexの値を指定します。
ShowAreaというCanvas内にクラウディアの画像を表示します。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) delTextBlock.Visibility = Windows.UI.Xaml.Visibility.Collapsed mySelectedFile = DirectCast(e.Parameter, String) Dim result As String Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("FlowerAndClaudia", CreationCollisionOption.OpenIfExists) Dim myFile = Await mySubFolder.GetFileAsync(mySelectedFile) Using myStream As IRandomAccessStream = Await myFile.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) Dim myFlowerImage = doc.Descendants("FlowerImage").Value Dim myClaudiaImage = doc.Descendants("ClaudiaImage").Value Dim c_Width = doc.Descendants("ClaudiaImage").Attributes("Width").First Dim c_Height = doc.Descendants("ClaudiaImage").Attributes("Height").First Dim c_Top = doc.Descendants("ClaudiaImage").Attributes("Top").First Dim c_Left = doc.Descendants("ClaudiaImage").Attributes("Left").First Dim c_Zindex = doc.Descendants("ClaudiaImage").Attributes("Zindex").First Dim f_Width = doc.Descendants("FlowerImage").Attributes("Width").First Dim f_Height = doc.Descendants("FlowerImage").Attributes("Height").First Dim f_Top = doc.Descendants("FlowerImage").Attributes("Top").First Dim f_Left = doc.Descendants("FlowerImage").Attributes("Left").First Dim f_Zindex = doc.Descendants("FlowerImage").Attributes("FlowerZindex").First Dim flowerImg As New Image With flowerImg .Width = CDbl(f_Width) .Height = CDbl(f_Height) .Source = New BitmapImage(New Uri("ms-appx:///Images/" & myFlowerImage)) .Margin = New Thickness(CDbl(f_Left), CDbl(f_Top), 0, 0) .SetValue(Canvas.ZIndexProperty, CInt(f_Zindex)) End With ShowArea.Children.Add(flowerImg) Dim claudiaImg As New Image With claudiaImg .Width = CDbl(c_Width) .Height = CDbl(c_Height) .Margin = New Thickness(CDbl(c_Left), CDbl(c_Top), 0, 0) .Source = New BitmapImage(New Uri("ms-appx:///Images/" & myClaudiaImage)) .SetValue(Canvas.ZIndexProperty, CInt(c_Zindex)) End With ShowArea.Children.Add(claudiaImg) End Sub
[Delete]アイコンがタップされた時の処理
ピクチャライブラリにアクセスします。
CreateFolderAsyncメソッドで、ピクチャライブラリ内にFlowerAndClaudiaというサブフォルダを作成します。
CreationCollisionOption.OpenIfExistsを指定すると、既に同名フォルダが存在する場合はフォルダ名を返し、ない場合は新規に作成します。
GetFileAsyncメソッドで変数mySelectedFileに格納されているXMLファイルを取得し、変数myFileで参照します。DeleteAsyncメソッドで、現在のファイルを削除します。
ShowAreaというCanvas内をクリアします。
「削除しました!」と記述しているdelTextBlockを表示します。
[Delete]アイコンの使用を不可とします。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
Private Async Sub delButton_Click(sender As Object, e As RoutedEventArgs) Handles delButton.Click Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("FlowerAndClaudia", CreationCollisionOption.OpenIfExists) Dim myFile = Await mySubFolder.GetFileAsync(mySelectedFile) Await myFile.DeleteAsync() ShowArea.Children.Clear() delTextBlock.Visibility = Windows.UI.Xaml.Visibility.Visible delButton.IsEnabled = False End Sub End Class
今回はここまでです。ありがとうございました。
筆者からのお知らせ
筆者はWindowsストアでアプリを公開しています。チャームの検索からWindowsストアを選択して、検索欄に、kuniyasuまたはYakushijiKuniyasuと入力すると、公開されているアプリの一覧が表示されます。上記はどちらも私のアカウントですので、興味のある方は是非ダウンロードして使ってみてください。
お花とクラウディアさん