PR

画面上を流れる数字を暗算して正解を求めるアプリを作ろう(その2)

2014年1月28日(火)
薬師寺 国安

このアプリについて

前回に引き続き「動体視力暗算アプリの解説を行います。前回はデザイン画面やXAMLコードの解説がメインでしたが、今回はVBコードの解説がメインになります。前編(その1)と併用して読まれることを希望します。
まずは、「モジュールの設定」から入ります。

モジュールの設定

VS2013メニューの[プロジェクト]−[モジュールの追加]と選択して、全てのプロジェクトから参照できるモジュール変数を宣言します。このアプリは5画面ありますから、どの画面からでも共通にアクセスできるよう、手っ取り早くモジュールで宣言しておきます(リスト1)。モジュール変数を使用すると可読性が悪くなり、バグの温床になる云々がいわれますが、それは使い手の問題であって、臨機応変に使用すれば、なんらモジュール変数を使用しても問題はありません。却って便利なくらいです。

リスト1 Module.vb

Module Module1
‘ 背景色を設定するためのパブリック変数
  Public myBackGroundColor As SolidColorBrush

‘ 背景画像を指定するためのパブリック変数
  Public myBackGroundImage As BitmapImage
  Public backGroundValue As String
  Public backGroundIndex As Integer

‘ レベル値を格納するパブリック変数
  Public myLevel As Integer

‘ 桁数を格納するパブリック変数
  Public keta As Integer = -1
  Public ketaValue As String

‘ スピードを格納するパブリック変数
  Public speed As Integer = -1
  Public speedValue As String

‘ 文字サイズを格納するパブリック変数
  Public mojiSize As Integer = -1
  Public mojiSizeValue As String

‘ 数字の合計を格納するパブリック変数
  Public Total As Integer = 0

‘ DispatcherTimerクラス型のパブリック変数myTimer(タイマーを操作する変数)
  Public myTimer As DispatcherTimer
 
  Public myScore As Integer
  Public SumTotal As Integer = 0
  Public calcNo As Integer = 0
End Module

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

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

リスト2 (MainWindow.xaml.vb)

Imports Windows.UI.Popups

‘ ファイル、フォルダおよびアプリケーションの設定を管理するクラスの含まれる、
‘ Windows.Storage名前空間をインポートします。
Imports Windows.Storage
Public NotInheritable Class MainPage
  Inherits Page

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

新しいDispacherTimerのインスタンスmyTimerオブジェクトを作成します。
SettingPage(設定画面)に遷移します。

  Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
    myTimer = New DispatcherTimer
    myFrame.Navigate(GetType(SettingPage))
    MyBase.OnNavigatedTo(e)
  End Sub

[開始]ボタンがタップされた時の処理

各設定項目が選択されていない場合は、警告メッセージを表示して処理を抜ける。
各設定項目が選択されている場合は、設定した内容で、文字が左から右に流れてくるgoPageに遷移する。

  Private Async Sub playButton_Click(sender As Object, e As RoutedEventArgs) Handles playButton.Click
    If keta < 0 OrElse speed < 0 OrElse mojiSize < 0 Then
      Dim message As New MessageDialog("設定項目を選択してください。")
      Await message.ShowAsync
      Exit Sub
    Else
      backButton.Visibility = Windows.UI.Xaml.Visibility.Visible
      myFrame.Navigate(GetType(goPage))
      playButton.IsEnabled = False
      stopButton.IsEnabled = True
    End If
  End Sub

[停止]ボタンがタップされた時の処理

タイマーを停止します。
[停止]ボタンをタップすると、スコアの計算は、何回文字が流れてきたかによって計算しているので、文字が流れてきた回数をmyScoreで加算します。流れてきた文字の合計をSumTotalで合計します。

  Private Sub stopButton_Click(sender As Object, e As RoutedEventArgs) Handles stopButton.Click
    myTimer.Stop()
    myScore = myScore + 1
    SumTotal = SumTotal + Total
 
    playButton.IsEnabled = True
    resultButton.IsEnabled = True
    stopButton.IsEnabled = False
  End Sub

[設定画面に戻る]アイコンがタップされた時の処理

各変数を0で初期化します。TitleTextBlockに「設定」と表示します。タイマーが実行されている場合は、タイマーを停止します。
タイマーが停止されている場合は、[設定画面に戻る]アイコンを非表示にし、[開始]ボタンを使用可能にします。各項目の設定を行うSettingPageに遷移します。

  Private Sub backButton_Click(sender As Object, e As RoutedEventArgs) Handles backButton.Click
    Total = 0
    SumTotal = 0
    calcNo = 0
    TitleTextBlock.Text = "設定"
    If myTimer.IsEnabled = True Then
       myTimer.Stop()
    Else
      backButton.Visibility = Windows.UI.Xaml.Visibility.Collapsed
      playButton.IsEnabled = True
      resultButton.IsEnabled = False
      stopButton.IsEnabled = False
      myScore = 0
      myFrame.Navigate(GetType(SettingPage))
    End If
  End Sub

[結果]ボタンがタップされた時の処理

タイマーを停止し、[設定画面に戻る]アイコンを表示状態にし、TitleTextBlockに「動体視力暗算」と表示します。答えを入力するInputAnswerPageに遷移します。

  Private Sub resultButton_Click(sender As Object, e As RoutedEventArgs) Handles resultButton.Click
    myTimer.Stop()
    backButton.Visibility = Windows.UI.Xaml.Visibility.Visible
    playButton.IsEnabled = False
    stopButton.IsEnabled = False
    TitleTextBlock.Text = "動体視力暗算"
    myFrame.Navigate(GetType(InputAnswerPage))
  End Sub

[戦績]ボタンをタップした時の処理

ピクチャライブラリ—内のMentalArithmeticXMLフォルダーにアクセスします。フォルダー内のファイルをGetFilesAsyncメソッドで取得して、コレクション変数saveFilesに格納します。
MentalArithmeticXMLフォルダー内にファイルが存在する場合は、戦績を表示するResultShowPageに遷移します。ファイルが存在しない場合はメッセージを表示して処理を抜けます。

  Private Async Sub recordPointButton_Click(sender As Object, e As RoutedEventArgs) Handles recordPointButton.Click
    Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("MentalArithmeticXML", CreationCollisionOption.OpenIfExists)
    Dim saveFiles = Await mySubFolder.GetFilesAsync
    TitleTextBlock.Text = "動体視力暗算"
    If saveFiles.Count > 0 Then
      backButton.Visibility = Windows.UI.Xaml.Visibility.Visible
      playButton.IsEnabled = False
      resultButton.IsEnabled = False
      myFrame.Navigate(GetType(ResultShowPage))
    Else
      Dim message As New MessageDialog("保存されたデータはありません!")
      Await message.ShowAsync
      Exit Sub
    End If
  End Sub
End Class

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

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

リスト3 (SettingPage.xaml.vb)

‘ ユーザーインターフェースに関するクラスの含まれるWindows.UI名前空間をインポートします。

Imports Windows.UI Public NotInheritable Class SettingPage Inherits Page

「桁数」が選択された時の処理

モジュール変数ketaにketaListBoxから選択されたインデックス番号を格納します。
モジュール変数ketaValueにketaListBoxから選択された項目を格納します。

  Private Sub ketaListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ketaListBox.SelectionChanged
    Try
      speedListBox.IsEnabled = True
      keta = ketaListBox.SelectedIndex
      ketaValue = DirectCast(ketaListBox.SelectedItem, ListBoxItem).Content.ToString
    Catch
      Exit Sub
    End Try
  End Sub

「スピード」が選択された時の処理

モジュール変数speedにspeedListBoxから選択されたインデックス番号を格納します。
モジュール変数speedValueにspeedListBoxから選択された項目を格納します。

  Private Sub speedListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles speedListBox.SelectionChanged
    Try
      mojiSizeListBox.IsEnabled = True
      speedListBox.IsEnabled = False
      speed = speedListBox.SelectedIndex
      speedValue = DirectCast(speedListBox.SelectedItem, ListBoxItem).Content.ToString
    Catch
      Exit Sub
    End Try
  End Sub

「文字サイズ」が選択された時の処理

モジュール変数myLevelに、「桁数」のListBoxから選択されたインデックスに1を加算した値と、「スピード」のListBoxより選択されたインデックスに1を加算した値、「文字サイズ」のListBoxより選択されたインデックスに1を加算した値、これら3つの値を乗算して格納しておきます。
モジュール変数mojiSizeValueにmojiSizeListBoxより選択された項目を格納しておきます。
mojiSizeListBoxより選択されたインデックスで条件分岐を行い、モジュール変数mojiSizeに値を格納します。「大」を選択した場合は、文字サイズは「72」、「小」を選択すれば文字サイズは「18」となります。

  Private Sub mojiSizeListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles mojiSizeListBox.SelectionChanged
    Try
      speedListBox.IsEnabled = False
      mojiSizeListBox.IsEnabled = False
      settingResetButton.IsEnabled = True
      myLevel = (ketaListBox.SelectedIndex + 1) * (speedListBox.SelectedIndex + 1) * (mojiSizeListBox.SelectedIndex + 1)
      levelTextBlock.Text = myLevel
      mojiSizeValue = DirectCast(mojiSizeListBox.SelectedItem, ListBoxItem).Content.ToString
      Select Case mojiSizeListBox.SelectedIndex
        Case 0
          mojiSize = 72
        Case 1
          mojiSize = 36
        Case 2
          mojiSize = 18
        End Select
      Catch
        Exit Sub
      End Try
    End Sub

[設定やり直し]ボタンをタップした時の処理

「桁数」のListBoxを選択可能にし、レベルの表示されていた領域をクリアし、ketaListBox、speedListBox、mojiSizeListBoxの選択を解除します。[設定やり直し]ボタンの使用を不可とします。

  Private Sub settingResetButton_Click(sender As Object, e As RoutedEventArgs) Handles settingResetButton.Click
    ketaListBox.IsEnabled = True
    levelTextBlock.Text = String.Empty
    ketaListBox.SelectedIndex = -1
    speedListBox.SelectedIndex = -1
    mojiSizeListBox.SelectedIndex = -1
    settingResetButton.IsEnabled = False
  End Sub

「背景」が選択された時の処理

モジュール変数backGroudValueにbackgroundListBoxより選択された項目を格納します。
モジュール変数backGroundIndexにbackgroundListBoxより選択されたインデックスを格納し、そのインデックス番号で条件分岐を行います。インデックスが0と1の時は背景色を変化させます。そのほかのインデックスの場合は背景画像が変化しますので、その処理は後述します。

  Private Sub backgroundListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles backgroundListBox.SelectionChanged
    backGroundValue = DirectCast(backgroundListBox.SelectedItem, ListBoxItem).Content.ToString
    backGroundIndex = backgroundListBox.SelectedIndex
    Select Case backGroundIndex
      Case 0
        myBackGroundColor = New SolidColorBrush(Colors.White)
        Exit Select
      Case 1
        myBackGroundColor = New SolidColorBrush(Colors.Gray)
        Exit Select
      End Select
    End Sub
  End Class
Think IT会員限定特典
  • 動体視力暗算アプリ

    『Windows 8.1+Visual Studio 2013によるWindows ストア・アプリ開発実例集』 第4回のサンプルプログラムです。
薬師寺国安事務所

薬師寺国安事務所代表。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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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