31章:チュートリアル30:WPF計算クイズの作成

    作成2013.04.03

     ここでは、Windowsフォームアプリケーション用サンプルコードをWPFアプリケーション用コードに変換しま す。フォームアプリケーションからWPFアプリケーションへの変化が最近の主流のようです。

  1. 参照元情報
    「計算クイズの作成」にジャンプする
    「WPF - Windows フォーム用のコントロールを使う」にジャンプする
     作成方法の詳細は上記を参照願います。


  2. フォームアプリケーションからWPFアプリケーションへの変更
     若干の変更でフォームアプリケーションからWPFアプリケーションへの変更ができます。
     完成ファイルは以下からダウンロードできます。
     ダウンロード後は解凍してから使用してください。
      WPF計算クイズの作成]をダウンロードする。
     解凍すると「31WpfMathQuiz」フォルダーがあります。
    注(1)「31WpfMathQuiz」フォルダーの「WpfMathQuiz.sln」ファイルをダブルクリックすると「Microsoft Visual Basic 2010 Express」が起動します。
    注(2)メニューの「ウインド」_「ウインドレイアウトのリセット」で標準に戻ります。
    注(3)「ソリューションエクスプローラ」ウインドウ内の「MainWindow.xaml」をダブルクリックすると「デザイン」と「XAML」が表示されます。
    注(4)メニューの「表示」_「コード」を選択するとコードが表示されます。
    注(5)「WpfMathQuiz.sln」の動作確認は「デバッグ」_「デバッグ開始」で実行します。デバッグ機能を用いて動作確認を行います。


  3. WpfMathQuiz.slnの実行
    (1)「Microsoft Visual Basic 2010 Express」のデバッグ機能を使用します。
    (2)「デバッグ」_「デバッグ開始」を選択します。
    (3)クイズスタート前の画面が表示されます。
    (4)Start the quizボタンを押すと問題と残り時間が表示されます。
    (5)+解答欄にカーソルを移し、値をキーボード入力して、リターンします。
    (6)次に-、×、÷の順で解答します。
    (7)制限時間内の全問正解すれば成功です。
    (8)クローズボックスでプログラムを終了します。


  4. プロジェクトの構成
    (1)UserControl1.vbの構成
    ・Timer1を配置します。

    (2)XAMLコードの構成
    ・UserControl1を配置します。
    ・LabelとTextBoxとButtonを配置します。

    注:Timer1がフォームアプリケーション用のツールとなります。


  5. XAMLの全コード
    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 
        xmlns:self="clr-namespace:WpfMathQuiz"
        Title="MainWindow" Height="350" Width="525">
        <Grid >
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
    
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            
            
            <Label Content="Time Left" Grid.Column="2"  HorizontalAlignment="Center" Name="Label1" VerticalAlignment="Center" />
            <Label Content="" HorizontalAlignment="Center"  Name="timeLabel" VerticalAlignment="Center" Grid.Column="3" Grid.ColumnSpan="2" MinWidth="150" />
            <Label Content="?" HorizontalAlignment="Center" Name="plusLeftLabel" VerticalAlignment="Center" Grid.Row="1" />
            <Label Content="+" HorizontalAlignment="Center" Name="Label4" VerticalAlignment="Center" Grid.Column="1" Grid.Row="1" />
            <Label Content="?" HorizontalAlignment="Center" Name="plusRightLabel" VerticalAlignment="Center" Grid.Column="2" Grid.Row="1" />
            <Label Content="=" HorizontalAlignment="Center" Name="Label6" VerticalAlignment="Center" Grid.Column="3" Grid.Row="1" />
            <Label Content="?" HorizontalAlignment="Center" Name="minusLeftLabel" VerticalAlignment="Center" Grid.Row="2" />
            <Label Content="-" HorizontalAlignment="Center" Name="Label8" VerticalAlignment="Center" Grid.Column="1" Grid.Row="2" />
            <Label Content="?" HorizontalAlignment="Center" Name="minusRightLabel" VerticalAlignment="Center" Grid.Column="2" Grid.Row="2" />
            <Label Content="=" HorizontalAlignment="Center" Name="Label10" VerticalAlignment="Center" Grid.Column="3" Grid.Row="2" />
            <Label Content="?" HorizontalAlignment="Center" Name="timesLeftLabel" VerticalAlignment="Center" Grid.Row="3" />
            <Label Content="×" HorizontalAlignment="Center" Name="Label12" VerticalAlignment="Center" Grid.Column="1" Grid.Row="3" />
            <Label Content="?" HorizontalAlignment="Center" Name="timesRightLabel" VerticalAlignment="Center" Grid.Column="2" Grid.Row="3" />
            <Label Content="=" HorizontalAlignment="Center" Name="Label14" VerticalAlignment="Center" Grid.Column="3" Grid.Row="3" />
            <Label Content="?" HorizontalAlignment="Center" Name="dividedLeftLabel" VerticalAlignment="Center" Grid.Row="4" />
            <Label Content="÷" HorizontalAlignment="Center" Name="Label16" VerticalAlignment="Center" Grid.Column="1" Grid.Row="4" />
            <Label Content="?" HorizontalAlignment="Center" Name="dividedRightLabel" VerticalAlignment="Center" Grid.Column="2" Grid.Row="4" />
            <Label Content="=" HorizontalAlignment="Center" Name="Label18" VerticalAlignment="Center" Grid.Column="3" Grid.Row="4" />
            <TextBox Grid.Column="4" Grid.Row="1" Height="24" HorizontalAlignment="Center" Name="sum" VerticalAlignment="Center" MinWidth="60" />
            <TextBox Grid.Column="4" Grid.Row="2" Height="24" HorizontalAlignment="Center" Name="difference" VerticalAlignment="Center" MinWidth="60" />
            <TextBox Grid.Column="4" Grid.Row="3" Height="24" HorizontalAlignment="Center" Name="product" VerticalAlignment="Center" MinWidth="60" />
            <TextBox Grid.Column="4" Grid.Row="4" Height="24" HorizontalAlignment="Center" Name="quotient" VerticalAlignment="Center" MinWidth="60" />
            <Button Content="Start the quiz" Grid.Column="2" Grid.Row="5"  HorizontalAlignment="Center" Name="startButton" VerticalAlignment="Center"  />
            <WindowsFormsHost   Name="WindowsFormsHost1">
                <self:UserControl1 x:Name="myControl"  />
            </WindowsFormsHost> 
        </Grid>
    </Window>
    


  6. XAMLのポイント
    (1)<Window>階層1:クラス:以下の記載が特別です。
     xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
     上記の記載はUserControlを使用するための記載です。
     xmlns:self="clr-namespace:WpfMaze"
     上記の記載はWpfMazeソリューションを使用するための記載です。
    (2) <WindowsFormsHost x:Name="wfHost" Grid.Row="0">
    <self:UserControl1 x:Name="myControl" />
    </WindowsFormsHost>
     上記の記載でUserControl1の使用条件を設定します。名前は"myControl" となります。
    (3)Grid機能を使用してLabelとTextBoxとButtonを配置します。


  7. Class MainWindowクラスの全コード
    Class MainWindow 
        Dim randomizer As New Random
        Dim addend1 As Integer
        Dim addend2 As Integer
        Dim minuend As Integer
        Dim subtrahend As Integer
        Dim multiplicand As Integer
        Dim multiplier As Integer
        Dim dividend As Integer
        Dim divisor As Integer
        Dim timeLeft As Integer
    
        Private Sub startButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles startButton.Click
            startButton.IsEnabled = False
            StartTheQuiz()
            myControl.UC = Me
        End Sub
    
        Public Sub StartTheQuiz()
            ' Fill in the addition problem.
            addend1 = randomizer.Next(51)
            addend2 = randomizer.Next(51)
            plusLeftLabel.Content = addend1.ToString
            plusRightLabel.Content = addend2.ToString
            sum.Text = "0"
    
            ' Fill in the subtraction problem.
            minuend = randomizer.Next(1, 101)
            subtrahend = randomizer.Next(1, minuend)
            minusLeftLabel.Content = minuend.ToString
            minusRightLabel.Content = subtrahend.ToString
            difference.Text = "0"
            ' Fill in the multiplication problem.
            multiplicand = randomizer.Next(2, 11)
            multiplier = randomizer.Next(2, 11)
            timesLeftLabel.Content = multiplicand.ToString
            timesRightLabel.Content = multiplier.ToString
            product.Text = "0"
            ' Fill in the division problem.
            divisor = randomizer.Next(2, 11)
            Dim temporaryQuotient As Integer = randomizer.Next(2, 11)
            dividend = divisor * temporaryQuotient
            dividedLeftLabel.Content = dividend.ToString
            dividedRightLabel.Content = divisor.ToString
            quotient.Text = "0"
            ' Start the timer.
            timeLeft = 30
            timeLabel.Content = "30 seconds"
            myControl.Timer1.Start()
        End Sub
    
        Public Function CheckTheAnswer() As Boolean
            If ((addend1 + addend2 = Val(sum.Text)) AndAlso (minuend - subtrahend = Val(difference.Text)) AndAlso (multiplicand * multiplier = Val(product.Text)) AndAlso (dividend / divisor = Val(quotient.Text))) Then
                Return True
            Else
                Return False
            End If
        End Function
    
        Public Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            If CheckTheAnswer() Then
                myControl.Timer1.Stop()
                MessageBox.Show("You got all of the answers right!", "Congratulations!")
                startButton.IsEnabled = True
            ElseIf timeLeft > 0 Then
                timeLeft = timeLeft - 1
                timeLabel.Content = timeLeft & " seconds"
            Else
                myControl.Timer1.Stop()
                timeLabel.Content = "Time's up!"
                MessageBox.Show("You didn't finish in time.", "Sorry")
                sum.Text = Str(addend1 + addend2)
                difference.Text = Str(minuend - subtrahend)
                product.Text = Str(multiplicand * multiplier)
                quotient.Text = Str(dividend / divisor)
                startButton.IsEnabled = True
            End If
        End Sub
    End Class
    


  8. Class MainWindowクラスのコード解説
    (1)myControl.UC = Meは特別なコードです。UserControl1クラスで Public UC As MainWindowとし、変数UCをMainWindow型で生成します。
      MeはMainWindowの実体であり、UserControl1クラスにMainWindowの実体を渡します。
    (2) Public Sub Timer_TickはUserControl1クラスから呼び出されます。
    (3)sum.Value = 0→ sum.Text = "0"はテキストボックスに変更したための変更です。
    (4)addend1 + addend2 = sum.Value→addend1 + addend2 = Val(sum.Text)もテキストボックスに変更したための変更です。


  9. Public Class UserControl1クラスのコード
    Public Class UserControl1
        Public UC As MainWindow
        Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
            UC.Timer_Tick(sender, e)
        End Sub
    End Class
    


  10. Public Class UserControl1クラスのコード解説
    (1)Private Sub Timer1_Tickは自動的にUserControl1クラスに設定されます。
    (2)主要コードはMainWindowクラスに集中させる都合上、MainWindowクラスのTimer_Tickを呼び出す必要があります。


    感想:
    (1)レイアウトはGrid機能を使用するとやりやすいです。
    (2)UserControl1クラスにタイマーを設定すると、Timer1_Tickは自動的にUserControl1クラスに設定されます。このためどうしてもUserControl1クラスからMainWindowクラスを呼びだす必要が生じました。
    (3)こんなとき、Meが重要な役割を果たします。






32章:チュートリアル31:WPF絵合わせゲームの作成に行く。

トップページに戻る。