1.
Imports System.ComponentModel
Public Class pic
Inherits System.Windows.Forms.UserControl
#Region " Windows 窗體設計器生成的代碼 "
'UserControl1 重寫 dispose 以清理組件列表。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Windows 窗體設計器所必需的
Private components As System.ComponentModel.IContainer
'注意:以下過程是 Windows 窗體設計器所必需的
'可以使用 Windows 窗體設計器修改此過程。
'不要使用代碼編輯器修改它。
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
'
'pic
'
Me.Name = "pic"
Me.Size = New System.Drawing.Size(48, 48)
End Sub
#End Region
Public Const m_maxlen As Integer = 48 '固定的寬和高
Public Const m_maxheight As Integer = 48
Public Sub New(ByVal m As image) '主要是用於在piccontrols組件中創建實例時使用
MyBase.New()
'該調用是 Windows 窗體設計器所必需的。
InitializeComponent()
'在 InitializeComponent() 調用之後添加任何初始化
m_image = m
End Sub
Public Sub New()
MyBase.New()
'該調用是 Windows 窗體設計器所必需的。
InitializeComponent()
'在 InitializeComponent() 調用之後添加任何初始化
End Sub
Private m_image As image = image.FromFile("G:/練習/重要的例程/使用問題(在格子中顯示圖片)/Gounda Takeshi.ico")
<Category("grid"), Description("設置卡片的圖片。")> _
Public Property image() As image
Get
Return m_image
End Get
Set(ByVal Value As image)
m_image = Value
Me.Refresh()
End Set
End Property
'繪製邊框和圖象
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim g As Graphics = Me.CreateGraphics
Me.BackColor = Color.White
g.DrawRectangle(System.Drawing.Pens.Black, 0, 0, Me.Width - 1, Me.Height - 1)
Dim ic As Image = CType(m_image, Image)
g.DrawImage(ic, 0, 0)
End Sub
'不允許調整大小
Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
Me.Size = New Size(m_maxlen, m_maxheight)
End Sub
'匹配否標誌
Private m_double As Boolean = False
<Category("grid"), Description("是否匹配的標誌。")> _
Public Property doubles() As Boolean
Get
Return m_double
End Get
Set(ByVal Value As Boolean)
m_double = Value
End Set
End Property
Private m_id As Integer
<Category("grid"), Description("區分是否來自同一圖片的標誌。")> _
Public Property id() As Integer
Get
Return m_id
End Get
Set(ByVal Value As Integer)
m_id = Value
End Set
End Property
End Class
2.
Imports my_namespace
Imports System.ComponentModel
Public Class piccontrols
Inherits System.ComponentModel.Component
#Region " 組件設計器生成的代碼 "
'組件重寫 dispose 以清理組件列表。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'組件設計器所必需的
Private components As System.ComponentModel.IContainer
'注意:以下過程是組件設計器所必需的
'可以使用組件設計器修改此過程。
'不要使用代碼編輯器修改它。
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
End Sub
#End Region
Public Sub New(ByVal Container As System.ComponentModel.IContainer)
MyClass.New()
'Windows.Forms 類撰寫設計器支持所必需的
Container.Add(Me)
changepic() '如果選擇的圖片發生了變化,那麼創建卡片集合也要相應的變化。
End Sub
Public Sub New()
MyBase.New()
'該調用是組件設計器所必需的。
InitializeComponent()
'在 InitializeComponent() 調用之後添加任何初始化
changepic() '如果選擇的圖片發生了變化,那麼創建卡片集合也要相應的變化。
End Sub
'////////////////////////////////////////////////////////////////
Dim m_piccontrols As New System.Collections.ArrayList()
'總數量
<Category("grid"), Description("集合內卡片的總數。")> _
Public ReadOnly Property count() As Integer
Get
Return m_piccontrols.Count
End Get
End Property
'指定位置的卡片(這個對於vb.net是比較特殊的,具有帶參數的屬性)
Default Public ReadOnly Property items(ByVal index As Integer) As pic
Get
If index >= 0 And index < m_piccontrols.Count Then
Return CType(m_piccontrols(index), pic)
End If
End Get
End Property
Public Sub shuffle() ' 混卡片,也就是生成一組隨機的卡片集合。(這裏的算法不錯!)
Dim r As New System.Random()
Dim d As New System.Collections.ArrayList()
Dim p As pic
While (m_piccontrols.Count > 0)
Dim removeindex As Integer = r.Next(0, m_piccontrols.Count - 1)
p = CType(m_piccontrols(removeindex), my_namespace.pic)
m_piccontrols.RemoveAt(removeindex)
d.Add(p)
End While
m_piccontrols = d
End Sub
Private m_image As imagelist
<Category("grid"), Description("選擇相應的imagelist控件。")> _
Public Property imagelist() As imagelist
Get
Return m_image
End Get
Set(ByVal Value As imagelist)
m_image = Value
changepic()
End Set
End Property
'/////////
'這個事件比較重要,主要是根據圖片的變動來生成不同的卡片集合。
Private Sub changepic()
If m_image Is Nothing Then Exit Sub
Dim i As Integer
For i = 0 To m_piccontrols.Count - 1
CType(m_piccontrols(i), pic).Dispose() '注意這裏。
Next
m_piccontrols.Clear()
Dim j As Integer
For i = 0 To m_image.Images.Count - 1
For j = 0 To 3
Dim p As New pic(m_image.Images(i))
p.id = i
m_piccontrols.Add(p)
Next
Next
End Sub
'由於在排列好後,每個在集合中的卡片的doubles屬性都會被設置成true,
'所以要在開始一次新的排序時設置所有的卡片該屬性爲false
Public Sub setfalse()
Dim i As Integer
For i = 0 To m_piccontrols.Count - 1
Dim apic As pic = CType(m_piccontrols(i), pic)
apic.doubles = False
Next
End Sub
End Class
3.
Imports System.ComponentModel
Public Class picshow
Inherits System.Windows.Forms.UserControl
#Region " Windows 窗體設計器生成的代碼 "
Public Sub New()
MyBase.New()
'該調用是 Windows 窗體設計器所必需的。
InitializeComponent()
'在 InitializeComponent() 調用之後添加任何初始化
End Sub
'UserControl 重寫 dispose 以清理組件列表。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Windows 窗體設計器所必需的
Private components As System.ComponentModel.IContainer
'注意:以下過程是 Windows 窗體設計器所必需的
'可以使用 Windows 窗體設計器修改此過程。
'不要使用代碼編輯器修改它。
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
End Sub
#End Region
'// 這個程序的原理 //
'//先做一個pic控件,可以爲其設置相應的圖片,不允許改變大小,要重寫sizechange,onpait事件 //
'//做一個集合組件piccontrols來容納一定數量的pic卡片,但並不顯示它,因爲是組件。只是容器 //
'//最後做一個picshow控件,用於顯示piccontrols.count數量的卡片集合。 //
'//比較重要的地方就是如何對卡片進行隨機混排(piccontrols的shuffle方法)和picshow控件的 //
'//contrains,start方法。尤其注意這裏進行排序的方法:是將卡片在集合裏就弄混(隨機),這樣//
'//我們取得的每個卡片都是隨機的了,然後在picshow控件里根據每個卡片的doubles,id屬性來進行 //
'//排序,把隨機和排序分開了。當然也可以把他們合併寫到picshow控件裏。不過這裏不建議這樣。 //
'//因爲對於piccontrols組件來說,它的集合就是一個隨機產生的卡片集合。這樣比較好理解。 //
Private Const m_spacing As Integer = 10 '間隔設置的常量
Private m_rows As Integer = 2 ' 對於一個陣列來講,2行應該更有意義。
<Category("grid"), Description("矩陣的行。"), DefaultValue(2)> _
Public Property row() As Integer
Get
Return m_rows
End Get
Set(ByVal Value As Integer)
If Value > 0 Then
m_rows = Value
Me.Refresh()
End If
End Set
End Property
Private m_columns As Integer = 2
<Category("grid"), Description("矩陣的列。"), DefaultValue(2)> _
Public Property columns() As Integer
Get
Return m_columns
End Get
Set(ByVal Value As Integer)
If (Value > 0) And (Value Mod 2 = 0) Then
m_columns = Value
Me.Refresh()
Else
Throw New Exception("不是有效的列值!請輸入2的倍數的列值。")
End If
End Set
End Property
Private m_collection As piccontrols
<Category("grid"), Description("指定相應的piccontrols組件。")> _
Public Property getcontrols() As piccontrols
Get
Return m_collection
End Get
Set(ByVal Value As piccontrols)
m_collection = Value
End Set
End Property
'繪製邊框,由於還沒有將卡片加入到me.controls集合,所以只有邊框。
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim height As Integer = my_namespace.pic.m_maxheight
Dim width As Integer = my_namespace.pic.m_maxlen
Me.Width = (width + m_spacing) * m_columns + m_spacing
Me.Height = (height + m_spacing) * m_rows + m_spacing
Dim g As Graphics = Me.CreateGraphics
Dim row, column As Integer
For row = 0 To m_rows - 1
For column = 0 To m_columns - 1
g.DrawRectangle(System.Drawing.Pens.Gray, column * (width + m_spacing) + m_spacing, _
row * (height + m_spacing) + m_spacing, width, height)
Next
Next
End Sub
Private m_double As pic '記錄相同的那個卡片
Private m_last As Integer '記錄格子中的最後一個卡片
'開始排列
Public Sub start()
Me.Controls.Clear() '先清空容器
If Not IsNothing(m_collection) Then '判斷行列之積和卡片數量是否相等
If (m_collection.count <> m_rows * m_columns) Then
Throw New Exception("卡片數量爲:" & CStr(m_collection.count) & "格子數量爲:" & CStr(m_rows * m_columns))
End If
'///////////////////////////////////
m_last = -2 '初始化,因爲從0開始是第一個格子,所以初始值爲-2
m_collection.setfalse() '因爲開始一次排序就會把所有的卡片pic的double屬性全都設置爲true。所以,這裏要全都設置回false
m_collection.shuffle() '將卡片弄混
Dim cardcount As Integer = 0 '卡片指針
Dim row, column As Integer
For row = 0 To m_rows - 1
For column = 0 To m_columns - 1
Dim apic As pic = CType(m_collection(cardcount), pic)
'加入到me的控件集合
Me.Controls.Add(apic)
'控件集合中的原有卡片進行遍歷,看是否有單個的與新加入的同一個圖片的卡片
Dim rint As Integer = contrains(apic)
Select Case rint
Case 0 '匹配排列
apic.Left = m_double.Left + m_spacing + my_namespace.pic.m_maxlen
apic.Top = m_double.Top
Case 1 '沒有匹配項,間隔排列
'行,注意一定要使用int進行轉化,否則會四捨五入。
Dim r As Integer = Int(m_last / (m_rows))
'列
Dim c As Integer = m_last Mod (m_rows)
'取得行列後就可以直接設置位置了。
apic.Left = c * (pic.m_maxlen + m_spacing) + m_spacing
apic.Top = r * (pic.m_maxheight + m_spacing) + m_spacing
End Select
cardcount += 1 '下一個卡片
Next
Next
MessageBox.Show("排序完成!")
End If
End Sub
'排序的函數
Public Function contrains(ByVal p As pic) As Integer
m_double = Nothing '初始值爲空,每次排序前要設置爲空。
Dim apic As pic
Dim i As Integer
Dim count As Integer = Me.Controls.Count - 1
For i = 0 To count - 1 '從0到末尾-1,把自己排除掉,自己和自己不必要去比較
apic = CType(Me.Controls(i), pic)
If (apic.id = p.id) And apic.doubles = False Then 'And i <> count
apic.doubles = True '匹配
p.doubles = True '匹配
m_double = apic
End If
Next
'找到匹配的了
If Not (m_double Is Nothing) Then
Return 0
Else
m_last += 2 '分隔開一個格子( 這裏的格子開始爲0,最後爲m_collection的count-1)
Return 1
End If
End Function
End Class