[VB.net] 再談使圖片捲動的「拉霸遊戲機」(三) - 做成獨立的控制項

要做成九個一組的水果盤控制項,首先要把捲動功能做成單一的控制項(Control),然後再用九個拼成新的控制項。
接下來就先把前文的「拉霸遊戲機2」發展成獨立的控制項:
先考量對外至少需要有哪些屬性、方法、事件:
屬性:
1.[停止]  唯寫屬性,設為 True 時可將停止轉動。
2.[忙碌中] 唯讀屬性,控制項轉動中為 True,停止時為 False。
3.[播放速度]讀寫屬性,提供可設定每二次畫格移動的間隔毫秒數。
4.[畫格總數]唯讀屬性,提共外部取得所有圖片的總高度。
5.[結果圖號]唯讀屬性,傳回轉動停止時所在的圖片編號。
6.[捲動方向]讀寫屬性,供讀取或設定轉動的方向。

方法:
1.[啟動]開起始一次畫好的轉動。
2.[停止]停止轉動。
3.[圖片變色]當圖片成為三連線之一時,或其他特定條件下(例如有設 luckey number)用來強化圖片呈現效果。

要做成九個一組的水果盤控制項,首先要把捲動功能做成單一的控制項(Control),然後再用九個拼成新的控制項。

接下來就先把前文的「拉霸遊戲機2」發展成獨立的控制項:

先考量對外至少需要有哪些屬性、方法、事件:

  1. 屬性:
    1. [停止]  唯寫屬性,設為 True 時可將停止轉動。
    2. [忙碌中] 唯讀屬性,控制項轉動中為 True,停止時為 False。
    3. [播放速度]讀寫屬性,提供可設定每二次畫格移動的間隔毫秒數。
    4. [畫格總數]唯讀屬性,提共外部取得所有圖片的總高度。
    5. [結果圖號]唯讀屬性,傳回轉動停止時所在的圖片編號。
    6. [捲動方向]讀寫屬性,供讀取或設定轉動的方向。
  2. 方法:
    1. [啟動]開起始一次畫好的轉動。
    2. [停止]停止轉動。
    3. [圖片變色]當圖片成為三連線之一時,或其他特定條件下(例如有設 luckey number)用來強化圖片呈現效果。
  3. 事件:
    1. [產生結果了]當轉動完全停止時觸發此一事件,回給呼叫端。

 

開始建立程式碼:

  1. 這個控制項完全以圖片為基礎所以不必繼承 UserControl,採用直繼承 PictureBox。
  2. 類別的變數定義區如下:
    #Region "---定義區---"
        Public Enum 捲動方向列舉常數
            向上捲動
            向下捲動
        End Enum
        '---這些預備在未來多個 Control 協同工作時共用,所以規劃成靜態---
        Private Shared _圖片總數 As Integer = 1
        Private Shared _基本暫停毫秒數 As Single = 20
        Private Shared _捲動方向 As 捲動方向列舉常數 = 捲動方向列舉常數.向下捲動
        Private Shared _播放速度 As Single = 0
        Private Shared _現用圖片集合(1) As List(Of Bitmap)   '---當下使用中的圖片(0=一般圖片,1=加強圖片)---
        Private Shared _客戶圖片集合(1) As List(Of Bitmap)   '---使用者指定的圖片(0=一般圖片,1=加強圖片)---
        '---這些是自己獨自擁有的內部變數---
        Private _停止 As Boolean = False
        Private _畫格總數 As Integer = 0
        Private _現用底圖 As Bitmap
        Private _忙碌中 As Boolean = False
        Private _擷取大小 As Size = Me.Size
        Private _當下畫格指標 As Integer = 0
        Private _當下圖號 As Integer = 0
        Private _結果圖號 As Integer = 0
        Private _希望值 As Integer
        Private 加速階段終點列數 As Integer = 0
        Private 減速階段起點列數 As Integer = 0
        Dim 亂數產生器 As Random = New Random
        Dim 畫格寬 As Integer
        Dim 畫格高 As Integer
        '---當轉動停時叵呼的事件---
        Event 產生結果了(ByVal sender As ku_ScrollImage, ByVal n As Integer)
    #End Region
    



  3. 接著是屬性區的程式碼:

    #Region "---屬性---"
        Public WriteOnly Property 停止() As Boolean
            Set(ByVal value As Boolean)
                _停止 = value
            End Set
        End Property
        Public ReadOnly Property 忙碌中() As Boolean
            Get
                Return _忙碌中
            End Get
        End Property
        <Description("設定播放速度 0-50ms"), Browsable(True), Category("行為")> _
        Public Property 播放速度() As Single
            Get
                Return _基本暫停毫秒數
            End Get
            Set(value As Single)
                value = If(value < 0, 0, If(value > 50, 50, _基本暫停毫秒數))
                _基本暫停毫秒數 = value
            End Set
        End Property
        <Description("取得播放畫格總數"), Browsable(True), Category("行為")> _
        Public ReadOnly Property 畫格總數() As Integer
            Get
                Return _畫格總數
            End Get
        End Property
        <Description("取得圖片集合"), Browsable(True), Category("行為")> _
        Public ReadOnly Property 圖片集合() As List(Of Bitmap)
            Get
                Return _現用圖片集合(0)
            End Get
        End Property
        <Description("取得圖片總數"), Browsable(True), Category("行為")> _
        Public Shared ReadOnly Property 圖片總數() As Integer
            Get
                Return _圖片總數
            End Get
        End Property
        <Description("取得目前圖片編號"), Browsable(True), Category("行為")> _
        Public ReadOnly Property 當下圖號() As Integer
            Get
                Return _當下圖號
            End Get
        End Property
        <Description("取得將產生的結果值"), Browsable(True), Category("行為")> _
        Public ReadOnly Property 結果圖號() As Integer
            Get
                Return _結果圖號
            End Get
        End Property
        <Description("設定捲動方向"), Browsable(True), Category("行為")> _
        Public Shared Property 捲動方向() As 捲動方向列舉常數
            Get
                Return _捲動方向
            End Get
            Set(ByVal value As 捲動方向列舉常數)
                _捲動方向 = value
            End Set
        End Property
    #End Region
    


  4. 至於方法部分,基本上和前篇貼文的原始碼相同不需更動。
  5. 只有[捲動圖片]的函式改變較大,因為支援了轉動中[停止]功能和送出事件部分:

        ''' <summary>
        ''' 捲動圖片
        ''' </summary>
        ''' <param name="希望值">預設捲動結果(0 to n-1)</param>
        ''' <remarks></remarks>
        Private Sub 捲動圖片(希望值 As Integer)
            _停止 = False
            Dim 已捲動列數 As Integer = 0
            Dim 應捲動總列數 = 算出應捲動多少格數(希望值, 3, 9)   '---根據「當下圖片、期望圖片、捲動方向」算出應捲動格數---
            Dim 擷圖起點位置 As Integer = 0                       '---記錄每次捲動後擷取圖像的 Top 位置---
            Dim 位移 = 0                                          '---記錄每次捲動的位移量---
            Dim id As Integer = 0
            Dim 當下暫停毫秒數 As Single = 0
            加速階段終點列數 = 畫格高 * 2                         '---定義由慢至快的範圍(最前2張圖片)---
            減速階段起點列數 = 應捲動總列數 - 畫格高 * 9          '---定義由快至慢的範圍(最後9張圖片)---
            Try
                Dim 目的框 As New Rectangle(New Point(0, 0), Me.Size)
                Using ee As Graphics = Me.CreateGraphics
                    Do
                        If _停止 Then
                            '---讓轉動直接跳至一個新位置---
                            Dim 新位置 = 應捲動總列數 - CInt(畫格高 * (Rnd(1) * 20 + 6) / 4)
                            '---根據已捲動列數修飾位移量,使捲動的格數正確銜接不會跳格---
                            If 已捲動列數 < 新位置 Then
                                Dim 差值 = 新位置 - 已捲動列數
                                位移 = 差值
                            End If
                            _停止 = False
                        End If
                        id = 畫格高 * _當下圖號 + 已捲動列數
                        Select Case _捲動方向
                            Case 捲動方向列舉常數.向上捲動 : 擷圖起點位置 = id Mod _畫格總數
                            Case 捲動方向列舉常數.向下捲動 : 擷圖起點位置 = _畫格總數 - (id Mod _畫格總數)
                        End Select
                        ee.CompositingQuality = Drawing2D.CompositingQuality.HighSpeed
                        ee.DrawImage(_現用底圖, 目的框, 0, 擷圖起點位置, 畫格寬, 畫格高, GraphicsUnit.Pixel)
                        ee.ReleaseHdc(ee.GetHdc)
                        已捲動列數 += 位移
                        Select Case 已捲動列數
                            Case Is >= 減速階段起點列數                 '---停止前減速階段---
                                位移 = 2 + (畫格高 / 4) * ((應捲動總列數 - 已捲動列數) / (應捲動總列數 - 減速階段起點列數)) ^ 3
                                當下暫停毫秒數 = _基本暫停毫秒數 / 2
                            Case Is < 加速階段終點列數                  '---啟動後加速階段---
                                位移 = 2 + (畫格高 / 4) * (已捲動列數 / 加速階段終點列數) ^ 1.2
                                當下暫停毫秒數 = _基本暫停毫秒數
                            Case Else                                   '---極速階段---
                                位移 = 畫格高 / 2
                                當下暫停毫秒數 = _基本暫停毫秒數
                        End Select
                        Thread.Sleep(當下暫停毫秒數)
                        Application.DoEvents()
                        id += 位移
                    Loop While 已捲動列數 < 應捲動總列數
                End Using
            Catch ex As Exception
            Finally
                Me.Image = _現用圖片集合(0)(希望值)  '---更新控制項的圖片為最後停駐的圖片---
                _當下圖號 = 希望值                   '---更新當下圖號--- 
                _結果圖號 = 希望值
                Me.Update()
                GC.Collect()                         '---清理垃圾---
                RaiseEvent 產生結果了(Me, 希望值)    '---發出事件---
                _忙碌中 = False                      '---清除忙碌旗號---
            End Try
        End Sub
    
    

  6. 這個控制項的資源裡加入了另一組加強效果的圖片,可以在[圖片變色]時取用。


    image
     
  7. 編輯階段的樣子:

    image
  8. 用一個表單寫一個測試用的 demo 程式:

    Public Class Form2
        Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            pic_幸運圖.SizeMode = PictureBoxSizeMode.StretchImage
            cbx_幸運圖號.SelectedIndex = 5      '---預設幸運數字為5---
            cbx_目的圖號.SelectedIndex = 10     '---預設目的圖號為亂數產生---
        End Sub
        '---用一個按鈕做[啟動]和[停止]兩種動作---
        Private Sub 按一下(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            If sender.text = "啟動" Then
                Dim 目的 = CInt(cbx_目的圖號.SelectedIndex)
                Ku_ScrollImage1.啟動(If(目的 = 10, -1, 目的))
                sender.text = "停止"
            Else
                Ku_ScrollImage1.stop()
                sender.text = "啟動"
            End If
        End Sub
        '---使用者設定幸運數字---
        Private Sub 幸運數字改變了(sender As Object, e As System.EventArgs) Handles _
            cbx_幸運圖號.SelectedIndexChanged, cbx_目的圖號.SelectedIndexChanged
            pic_幸運圖.Image = Ku_ScrollImage1.圖片集合(cbx_幸運圖號.SelectedIndex)
            lbl_提示.Visible = (cbx_目的圖號.SelectedIndex = cbx_幸運圖號.SelectedIndex)
        End Sub
        '---從控制項發出的事件---
        Private Sub 產生結果了(sender As ku_ScrollImage, n As Integer) Handles Ku_ScrollImage1.產生結果了
            Label2.Text = "結果圖號 = " & n
            Button1.Text = "啟動"
            If n = cbx_幸運圖號.SelectedIndex Then Ku_ScrollImage1.圖片變色()
        End Sub
    End Class
    
    

  9. 程式執行畫面:

    image image
  10. 影片:

    拉霸控制項測試程式。

 

下載[拉霸控制項(三)demo.rar

下載[圖片捲動(三)專案原始碼.rar

 

 


ku3