タブレットPCの加速度センサーを使って目的の画像を直感的に探せるプログラムを作る

2013年9月30日(月)
薬師寺 国安

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト2のコードを記述します。

ロジックコードを記述する

リスト2 (MainWindow.xaml.vb)

サポートされているセンサーの種類と関連するモーションデータにアクセスできるようにするクラスの含まれる、Windows.Devices.Sensors名前空間をインポートします。

Imports Windows.Devices.Sensors

コンテキストメニューおよびメッセージダイアログのサポートを提供するクラスの含まれる、Windows.UI.Popups名前空間をインポートします。

Imports Windows.UI.Popups

アプリケーションウインドウやウインドウ対話を作成し管理するサポートと、ウィンドウ上の入力イベントを処理するサポートを提供する、Windows.UI.Core名前空間をインポートします。

Imports Windows.UI.Core

ウインドウのUIに関する機能を提供するWindows.UI名前空間をインポートします。

Imports Windows.UI

Public NotInheritable Class MainPage
  Inherits Page

タイマーを表すDispatcherTimerクラスのメンバ変数myTimerを宣言します。

  Dim myTimer As DispatcherTimer

加速度センサーを表すAccelerometerクラスのメンバ変数myAccelerometerを宣言します。

  Dim myAccelerometer As Accelerometer
  
  Dim no As Integer = 0
  Dim myCount As Integer = 0

加速度計の読み取り結果を表すAccelerometerReadingクラスのメンバ変数myValueを宣言しNothingで初期化しておきます。

  Dim myValue As AccelerometerReading = Nothing

ページがアクティブになった時の処理

新しいDispacherTimerのインスタンスmyTimerオブジェクトを作成します。
Intervalプロパティに1000ミリセコンド(1秒)を指定します。
AddHandlerステートメントで、指定したタイマーの間隔が経過し、タイマーが有効である場合に発生するTickイベントにmyTimer_Tickイベントハンドラを追加します。Startメソッドでタイマーを開始します。
Accelerometer.GetDefaultメソッドで、加速度センサーを既定の加速度計とします。
既定の加速度計が装備されていない場合は、警告メッセージを出して、処理を抜けます。装備されている場合は、AddHandlerステートメントで、加速度計が新しいセンサー読み取り結果を報告するたびに発生する、ReadingChangedイベントに、myAccelerometer_ReadingChangedイベントハンドラを追加します。
ピクチャライブラリにアクセスします。GetFilesAsyncメソッドでファイルを取得し、コレクション変数myPicturesに格納します。Countプロパティでファイルの個数を取得し、ファイルが無い場合は警告メッセージを発して処理を抜けます。ファイルがある場合は以下の処理を行います。
コレクション変数myPictures内のファイルを変数resultに格納しながら、以下の処理を繰り返します。
新しいBimapImageのインスタンスbmpオブジェクトを作成し、SetSourceメソッドに、
Await result.OpenSequentialReadAsync
と指定して、OpenSequentialReadAsyncメソッドで、ファイルの内容を読むために、現在のファイルの順次アクセスストリームを開き、BitmapSourceのソースイメージに設定します。
新しいImageのインスタンスmyImageオブジェクトを作成します。Stretch(コンテンツのサイズを変更して、割り当てられている領域を埋める方法)にNoneを指定し、Sourceプロパティにbmpオブジェクトを追加します。
新しいTextBlockのインスタンスfileNameTextBlockオブジェクトを作成します。
パディングに5、文字サイズに24、文字色にGold、Textプロパティに、GetFileNameメソッドでファイル名と拡張子の付いたファイル名を指定します。Result.Nameでフルパス付きのファイル名を取得しますので、GetFileNameメソッドを使って、ファイル名と拡張子だけのファイル名を取得しています。文字を中央揃えとします。
新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。
AddメソッドでmyImage、fileNameTextBlockオブジェクトを追加します。このmyStackPanelオブジェクトをFlipView1にAddメソッドで追加していきます。PageTextBlock内に何枚中何枚目という表示を1/10・・・5/10といった形式で表示します。

  Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    myTimer = New DispatcherTimer
    myTimer.Interval = TimeSpan.FromMilliseconds(1000)
    AddHandler myTimer.Tick, AddressOf myTimer_Tick
    myTimer.Start()
    myAccelerometer = Accelerometer.GetDefault
    If myAccelerometer Is Nothing = True Then
      Dim message As New MessageDialog("加速度センサーに対応しておりません。")
      Await message.ShowAsync
      Exit Sub
    Else
      AddHandler myAccelerometer.ReadingChanged, AddressOf myAccelerometer_ReadingChanged
    End If
 
    Dim myFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim myPictures = Await myFolder.GetFilesAsync
    myCount = myPictures.Count
 
    If myCount = 0 Then
      Dim message As New MessageDialog("ピクチャライブラリ内に表示する画像がありません。")
      Await message.ShowAsync
      Exit Sub
    End If
 
    For Each result In myPictures
      Dim bmp As New BitmapImage
      bmp.SetSource(Await result.OpenSequentialReadAsync)
      Dim myImage As New Image
      myImage.Stretch = Stretch.None
      myImage.Source = bmp
      
      Dim fileNameTextBlock As New TextBlock
      With fileNameTextBlock
        .Padding = New Thickness(5)
        .FontSize = 24
        .Foreground = New SolidColorBrush(Colors.Gold)
        .Text = Path.GetFileName(result.Name)
        .HorizontalAlignment = Xaml.HorizontalAlignment.Center
      End With
 
      Dim myStackPanel As New StackPanel
      myStackPanel.Children.Add(myImage)
      myStackPanel.Children.Add(fileNameTextBlock)
      FlipView1.Items.Add(myStackPanel)
 
    Next
    PageTextBlock.Text = (no + 1).ToString & "/" & myCount
  End Sub

加速度計が新しいセンサー読み取り結果を報告するたびに発生するイベント

最新の加速度計の読み取りを取得して、メンバ変数myValueで参照しておきます。

  Private Sub myAccelerometer_ReadingChanged(sender As Accelerometer, e As AccelerometerReadingChangedEventArgs)
  myValue = e.Reading
End Sub

指定したタイマーの間隔が経過し、タイマーが有効である場合に発生するイベント

加速度計に最新の値が無い場合は処理を抜けます。それ以外の場合は、以下の処理を行います。
x軸に沿った重力アクセラレータの絶対値が、y軸に沿った重力アクセラレータより小さい場合は処理を抜けます。つまりタブレットPCが水平に置かれた場合は処理を抜けるということです。
x軸に沿った重力アクセラレータの値が0より大きい場合、つまりタブレットPCが右に傾けられた場合の処理です。メンバ変数noの値が、ピクチャフォルダー内にあるファイルの個数より大きい場合は、メンバ変数noの値をmyCount-1で初期化して処理を抜けます。メンバ変数myCountにはピクチャフォルダー内の画像ファイルの個数が格納されています。メンバ変数noの値が、ピクチャフォルダー内にあるファイルの個数より小さい場合は、メンバ変数noの値を1ずつ増加させて、その値をFlipView1のSelectedIndexの値に指定します。これで、タブレットPCを右に傾けると、順次画像が表示されていき、最後まで表示されるとそこで止まります。
x軸に沿った重力アクセラレータの値が0より小さい場合、つまりタブレットPCが左に傾けられた場合の処理です。
メンバ変数noの値が0か0より小さい場合は、メンバ変数noの値を0で初期化し処理を抜けます。それ以外の場合は、メンバ変数noの値を1ずつ減算し、その値をFlipView1のSelectedIndexの値に指定します。前の画像が順次表示されていき、先頭の画像になったら表示を止めます。
pageTextBlock内に何枚目中何枚目の画像であるということを、1/10・・・・5/10の形式で表示します。

  Private Sub myTimer_Tick(sender As Object, e As Object)
    If myValue Is Nothing = True Then
      Exit Sub
    Else
      If Math.Abs(myValue.AccelerationX) < Math.Abs(myValue.AccelerationY) Then
        Exit Sub
      Else
        If myValue.AccelerationX > 0 Then
          If no >= myCount - 1 Then
             no = myCount - 1
             Exit Sub
          Else
             no += 1
             FlipView1.SelectedIndex = no
          End If
        Else
          If no <= 0 Then
             no = 0
             Exit Sub
          Else
             no -= 1
             FlipView1.SelectedIndex = no
          End If
        End If
      End If
    End If
    PageTextBlock.Text = (no + 1).ToString & "/" & myCount
  End Sub
End Class

アイコンの作成

詳細については、「自分の現在位置を取得して表示するサンプルプログラム」の記事を参照してください。

今回でWindows ストア・アプリのサンプル解説は一応終了です。長い間おつきあいありがとうございました。今回の連載が、皆様にとって、Windows ストア・アプリ作成のヒントとアイデアを生み出す要因になれば筆者としては嬉しいです。

では、またの機会にお会いしましょう。ありがとうございました。

  • タブレットPCを傾けて写真を直感的に探せるプログラム

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています