65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 算盘

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (13投票s)

2011年4月1日

CPOL

4分钟阅读

viewsIcon

43186

downloadIcon

1166

一个 WPF 算盘

Screenshot_1.png

引言

WPF Suanpan 只是一个以 XAML 形式存在的算盘。本文的目标不是让你成为珠算的支持者,尽管你可以自由转换,而是让你了解我是如何创建这个应用程序的。

算盘

算盘是一种中国算盘,可用于十进制和十六进制计算。使用算盘,您可以执行加法、减法、乘法、除法、平方根和立方根运算。

算盘分为两部分。上半部分包含称为天珠的珠子,而下半部分,在分隔梁下方,包含称为地珠的珠子。算盘的每一列包含两个天珠和五个地珠。天珠的价值为5,地珠的价值为1

算盘最右边的列代表个位,紧邻其左边的列代表十位,然后是百位千位... 以下截图代表数字 804,

Screenshot_2.png

如果您想了解更多关于算盘的信息,以下资源可能会有所帮助

要求

要运行从上面的下载链接提供的项目,你需要以下之一

  • Visual Studio 2010
  • Expression Blend

如果您使用的是 VS 2008,可以从此处下载源文件。

注意:如果您使用的是 Visual Studio 的 Express 版本,请确保使用Visual Basic Express打开解决方案。

WPF 算盘

工作原理

要移动珠子,请将光标放在珠子上,按住鼠标左键并向上或向下移动珠子。要将所有珠子重置为远离分隔梁,请双击分隔梁。

要拖动WPF Suanpan,请使用“木质”框架。

设计和布局

WPF Suanpan 的框架由抛光玫瑰木制成,天珠由橡木制成...好的,不是这样的。我在 Expression Design 中设计了WPF Suanpan,并在 Expression Blend 中添加了一些额外的元素。

有两个值得关注的内容控件:HeavenGridEarthGrid

Screenshot_3.png

Screenshot_4.png

HeavenGrid 包含十个 CanvasEarthGrid 也包含十个 Canvas

Screenshot_5.png

有两个 UserControlEarthBeadHeavenBead。两者中值得关注的元素是 Thumb 控件,它在两者中都被裁剪,并且 Opacity 设置为零。下图显示了 EarthBead 控件中的 Thumb,其 Opacity 属性为 100%。

Screenshot_6.png

代码

MainWindow Loaded 事件期间,我们将珠子添加到各自的 Canvas 中,

Private Sub MainWindow_Loaded(ByVal sender As Object, _
                              ByVal e As System.Windows.RoutedEventArgs) _
                              Handles Me.Loaded
    LoadEarthBeads()
    LoadHeavenBeads()
End Sub

在上面的事件处理程序中,我们调用 LoadEarthBeads 方法,该方法将 EarthBead 添加到 EarthGridCanvas

Private Sub LoadEarthBeads()
    For Each eCanvas As Canvas In EarthGrid.Children
        Dim y As Double = eCanvas.ActualHeight
        Dim i As Integer = 1
        Do
            Dim eB As New EarthBead()
            y -= eB.Height
            eB.EarthNumber = i
            Canvas.SetLeft(eB, 2)
            Canvas.SetTop(eB, y)
            eCanvas.Children.Add(eB)
            i += 1
        Loop While i < 6
        i = 0
    Next
End Sub

EarthBead 有一个名为 EarthNumber 的变量,在将珠子添加到 Canvas 之前会为其分配一个值。EarthBead 的值将如下所示

Screenshot_7.png

LoadHeavenBeads 方法也在 MainWindow Loaded 事件处理程序中调用,该方法将 HeavenBeads 添加到 HeavenGrid 的相应 Canvas

Private Sub LoadHeavenBeads()
    For Each hCanvas As Canvas In HeavenGrid.Children
        Dim i As Integer
        Dim y As Double = 0
        Do
            Dim hB As New HeavenBead()
            Canvas.SetLeft(hB, 2)
            Canvas.SetTop(hB, y)
            hCanvas.Children.Add(hB)
            y += hB.Height
            i += 1
            hB.HeavenNumber = i
        Loop While i < 2
        i = 0
    Next
End Sub

每个 HeavenBeadHeavenNumber 也被分配了一个值

Screenshot_8.png

EarthBead

要移动 EarthBead,我们会处理其 Thumb 控件的 DragDelta 事件

Private Sub EarthThumb_DragDelta(ByVal sender As Object, _
                                 ByVal e As DragDeltaEventArgs) _
                                 Handles EarthThumb.DragDelta
    ' Check whether movement is vertical.
    If Math.Abs(e.VerticalChange) > Math.Abs(e.HorizontalChange) Then
        If e.VerticalChange < 0 Then
            MoveEarthBeadUp(e)
        Else
            MoveEarthBeadDown(e)
        End If
    Else
        Exit Sub
    End If
End Sub

在上面的事件处理程序中,调用 MoveEarthBeadUp 来向上移动珠子

Private Sub MoveEarthBeadUp(ByVal e As DragDeltaEventArgs)
    Dim y As Double = Canvas.GetTop(Me)
    If (Me.EarthNumber = 5) Then
        If (y > 0) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, 0)
        End If
    ElseIf (Me.EarthNumber = 4) Then
        If (y > Me.Height) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, Me.Height)
        End If
    ElseIf (Me.EarthNumber = 3) Then
        If (y > (Me.Height * 2)) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, (Me.Height * 2))
        End If
    ElseIf (Me.EarthNumber = 2) Then
        If (y > (Me.Height * 3)) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, (Me.Height * 3))
        End If
    ElseIf (Me.EarthNumber = 1) Then
        If (y > (Me.Height * 4)) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, (Me.Height * 4))
        End If
    End If
    MoveBeadsAbove(e)
End Sub

MoveBeadsAbove 方法在上面的方法中被调用,它会将选定珠子在向上移动时与之碰撞的任何珠子向上移动

' Move beads/bead above the bead being moved
' when this bead collides with bead above.
Private Sub MoveBeadsAbove(ByVal e As DragDeltaEventArgs)
    Dim earthCanvas As Canvas = CType(Me.Parent, Canvas)

    For Each eB As EarthBead In earthCanvas.Children
        If (eB.EarthNumber <> Me.EarthNumber) Then
            Dim My_Y As Double = Canvas.GetTop(Me)
            Dim eB_Y As Double = Canvas.GetTop(eB)

            If (eB_Y < My_Y) And (My_Y < (eB_Y + eB.Height)) Then
                eB.EarthThumb_DragDelta(Nothing, e)
            End If
            ' Ensure bead above has stopped at its limit.
            If (eB.EarthNumber = 5) And (eB_Y < 0) Then
                Canvas.SetTop(eB, 0)
            ElseIf (eB.EarthNumber = 4) And (eB_Y < eB.Height) Then
                Canvas.SetTop(eB, eB.Height)
            ElseIf (eB.EarthNumber = 3) And (eB_Y < (eB.Height * 2)) Then
                Canvas.SetTop(eB, (eB.Height * 2))
            ElseIf (eB.EarthNumber = 2) And (eB_Y < (eB.Height * 3)) Then
                Canvas.SetTop(eB, (eB.Height * 3))
            ElseIf (eB.EarthNumber = 1) And (eB_Y < (eB.Height * 4)) Then
                Canvas.SetTop(eB, (eB.Height * 4))
            End If
        End If
    Next
End Sub

EarthThumb DragDelta 事件处理程序中,我们还调用 MoveEarthBeadDown 来向下移动珠子

Private Sub MoveEarthBeadDown(ByVal e As DragDeltaEventArgs)
    Dim y As Double = Canvas.GetTop(Me)
    Dim earthCanvas As Canvas = CType(Me.Parent, Canvas)
    Dim parentHeight As Double = earthCanvas.ActualHeight

    If (Me.EarthNumber = 5) Then
       If (y < (parentHeight - (Me.Height * 5))) Then
            Canvas.SetTop(Me, (y + shift))
       Else
            Canvas.SetTop(Me, (parentHeight - (Me.Height * 5)))
       End If
    ElseIf (Me.EarthNumber = 4) Then
        If (y < (parentHeight - (Me.Height * 4))) Then
            Canvas.SetTop(Me, (y + shift))
        Else
            Canvas.SetTop(Me, (parentHeight - (Me.Height * 4)))
        End If
    ElseIf (Me.EarthNumber = 3) Then
        If (y < (parentHeight - (Me.Height * 3))) Then
            Canvas.SetTop(Me, (y + shift))
        Else
            Canvas.SetTop(Me, (parentHeight - (Me.Height * 3)))
        End If
    ElseIf (Me.EarthNumber = 2) Then
        If (y < (parentHeight - (Me.Height * 2))) Then
            Canvas.SetTop(Me, (y + shift))
        Else
            Canvas.SetTop(Me, (parentHeight - (Me.Height * 2)))
        End If
    ElseIf (Me.EarthNumber = 1) Then
        If (y < (parentHeight - Me.Height)) Then
            Canvas.SetTop(Me, (y + shift))
        Else
            Canvas.SetTop(Me, (parentHeight - Me.Height))
        End If
    End If
    MoveBeadsBelow(e)
End Sub

MoveBeadsBelow 方法会将选定珠子在向下移动时与之碰撞的任何珠子向下移动

Private Sub MoveBeadsBelow(ByVal e As DragDeltaEventArgs)
    Dim earthCanvas As Canvas = CType(Me.Parent, Canvas)
    Dim parentHeight As Double = earthCanvas.ActualHeight

    For Each eB As EarthBead In earthCanvas.Children
        If (eB.EarthNumber <> Me.EarthNumber) Then
            Dim My_Y As Double = Canvas.GetTop(Me)
            Dim eB_Y As Double = Canvas.GetTop(eB)

            If (eB_Y > My_Y) And ((My_Y + Me.Height) > eB_Y) Then
                eB.EarthThumb_DragDelta(Nothing, e)
            End If
            ' Ensure bead below has stopped at its limit.
            If (eB.EarthNumber = 5) And _
            (eB_Y > (parentHeight - (Me.Height * 5))) Then
                Canvas.SetTop(eB, (parentHeight - (Me.Height * 5)))
            ElseIf (eB.EarthNumber = 4) And _
            (eB_Y > (parentHeight - (Me.Height * 4))) Then
                Canvas.SetTop(eB, (parentHeight - (Me.Height * 4)))
            ElseIf (eB.EarthNumber = 3) And _
            (eB_Y > (parentHeight - (Me.Height * 3))) Then
                Canvas.SetTop(eB, (parentHeight - (Me.Height * 3)))
            ElseIf (eB.EarthNumber = 2) And _
            (eB_Y > (parentHeight - (Me.Height * 2))) Then
                Canvas.SetTop(eB, (parentHeight - (Me.Height * 2)))
            ElseIf (eB.EarthNumber = 1) And _
            (eB_Y > (parentHeight - Me.Height)) Then
                Canvas.SetTop(eB, (parentHeight - Me.Height))
            End If
        End If
    Next
End Sub

HeavenBead

要移动 HeavenBead,我们会处理其 Thumb 控件的 DragDelta 事件

Private Sub HeavenThumb_DragDelta(ByVal sender As Object, _
                                  ByVal e As DragDeltaEventArgs) _
                                  Handles HeavenThumb.DragDelta
    ' Check whether movement is vertical.
    If Math.Abs(e.VerticalChange) > Math.Abs(e.HorizontalChange) Then
        If e.VerticalChange < 0 Then
            MoveHeavenBeadUp(e)
        Else
            MoveHeavenBeadDown(e)
        End If
    Else
        Exit Sub
    End If
End Sub

调用 MoveHeavenBeadUp 方法来向上移动珠子

Private Sub MoveHeavenBeadUp(ByVal e As DragDeltaEventArgs)
    Dim y As Double = Canvas.GetTop(Me)

    If (Me.HeavenNumber = 1) Then
        If (y > 0) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, 0)
        End If
    ElseIf (Me.HeavenNumber = 2) Then
        If (y > Me.Height) Then
            Canvas.SetTop(Me, (y - shift))
        Else
            Canvas.SetTop(Me, Me.Height)
        End If
    End If
    MoveBeadAbove(e)
End Sub

调用 MoveBeadAbove 方法来移动选定珠子在向上移动时与之碰撞的珠子

Private Sub MoveBeadAbove(ByVal e As DragDeltaEventArgs)
    Dim heavenCanvas As Canvas = CType(Me.Parent, Canvas)

    For Each hB As HeavenBead In heavenCanvas.Children
        If (hB.HeavenNumber <> Me.HeavenNumber) Then
            Dim My_Y As Double = Canvas.GetTop(Me)
            Dim hB_Y As Double = Canvas.GetTop(hB)

            If (hB_Y < My_Y) And (My_Y < (hB_Y + hB.Height)) Then
                hB.HeavenThumb_DragDelta(Nothing, e)
            End If
            ' Ensure bead above has stopped at its limit.
            If (hB_Y < 0) Then
                Canvas.SetTop(hB, 0)
            End If
        End If
    Next
End Sub

MoveHeavenBeadDown 方法在 HeavenThumbDragDelta 事件处理程序中被调用,它会将珠子向下移动

Private Sub MoveHeavenBeadDown(ByVal e As DragDeltaEventArgs)
    Dim y As Double = Canvas.GetTop(Me)
    Dim heavenCanvas As Canvas = CType(Me.Parent, Canvas)
    Dim parentHeight As Double = heavenCanvas.Height

    If (Me.HeavenNumber = 2) Then
        If (y < (parentHeight - Me.Height)) Then
            Canvas.SetTop(Me, (y + shift))
        Else
            Canvas.SetTop(Me, (parentHeight - Me.Height))
        End If
    ElseIf (Me.HeavenNumber = 1) Then
        If (y < (parentHeight - (Me.Height * 2))) Then
            Canvas.SetTop(Me, (y + shift))
        Else
            Canvas.SetTop(Me, (parentHeight - (Me.Height * 2)))
        End If
    End If
    MoveBeadBelow(e)
End Sub

调用 MoveBeadBelow 方法来移动选定珠子在向下移动时与之碰撞的珠子

Private Sub MoveBeadBelow(ByVal e As DragDeltaEventArgs)
    Dim heavenCanvas As Canvas = CType(Me.Parent, Canvas)
    Dim parentHeight As Double = heavenCanvas.ActualHeight

    For Each hB As HeavenBead In heavenCanvas.Children
        If (hB.HeavenNumber <> Me.HeavenNumber) Then
            Dim My_Y As Double = Canvas.GetTop(Me)
            Dim hB_Y As Double = Canvas.GetTop(hB)

            If (hB_Y > My_Y) And ((My_Y + Me.Height) > hB_Y) Then
                hB.HeavenThumb_DragDelta(Nothing, e)
            End If
            ' Ensure bead below has stopped at its limit.
            If (hB_Y > (parentHeight - hB.Height)) Then
                Canvas.SetTop(hB, (parentHeight - Me.Height))
            End If
        End If
    Next
End Sub

重置 WPF Suanpan

还记得我在工作原理部分解释过,要重置珠子,你需要双击分隔梁。你实际双击的是一个 Opacity 设置为零的按钮

Private Sub ResetButton_MouseDoubleClick(ByVal sender As Object, _
                     ByVal e As System.Windows.Input.MouseButtonEventArgs) _
                     Handles ResetButton.MouseDoubleClick
    ' Clear heaven beads.
    For Each hCanvas As Canvas In HeavenGrid.Children
        hCanvas.Children.Clear()
    Next
    ' Clear earth beads.
    For Each eCanvas As Canvas In EarthGrid.Children
        eCanvas.Children.Clear()
    Next
    ' Reload beads.
    LoadEarthBeads()
    LoadHeavenBeads()
End Sub

结论

就这样。希望您喜欢阅读这篇文章,并且它在某种程度上有所帮助。如果您已被影响,成为珠算的实践者,那么恭喜您。我个人更喜欢按钮算术

历史

  • 2011 年 4 月 1 日:首次发布
© . All rights reserved.