PROGRAMMING WORKSHOP

.Net FrameWork,VB.Net |

Timer | Label | Dispose | Random | EventHandler | AddHandler | AddressOf
Timer는 도구상자에서 마우스로 끌어다가 Design Time에 준비하고 속성창에
Interval속성등을 설정하고 사용하는 것은 모든 콘트롤이 마찬가지다



이렇게 하는 것도 경우에 따라서는 좋겠지만
앞페이지에서와 같이 RunTime에 코딩으로 컨트로를 만들어서 사용하는 것이
편리한 것이다

Timer콘트롤을 사용하여 무엇가를 좀더 해보도록 하자
아래와 같이 실행하면

Public Class Form1
    WithEvents oMyTimer As Timer
    Dim iNum As Integer
    Dim iStart As Integer = 6
    Dim iWidth As Integer = 30
    Dim iHeight As Integer = 20
    Dim iGap As Integer = 3
    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        oMyTimer = New Timer
        oMyTimer.Interval = 500
        oMyTimer.Start()

        Me.AutoSize = True
        Me.Size = New Size(0, 0)
        Me.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink

    End Sub

    Private Sub oMyTimer_Tick(sender As Object, e As System.EventArgs) Handles oMyTimer.Tick


        Dim oLabel As New Label
        oLabel.Text = Format(iNum, "0#")
        oLabel.Size = New Size(iWidth, iHeight)
        oLabel.Font = New Font("맑은 고딕", 10)
        Dim iX As Integer = iStart + (iNum Mod 10) * (iWidth + iGap) - iGap
        Dim iY As Integer = iStart + (iNum \ 10) * (iHeight + iGap) - iGap
        oLabel.Location = New Point(iX, iY)
        oLabel.BorderStyle = BorderStyle.FixedSingle
        oLabel.BackColor = {Color.Yellow, Color.Wheat, Color.SeaShell}(New Random().Next(3))
        AddHandler oLabel.Click, AddressOf labelClick
        Me.Controls.Add(oLabel)

        iNum += 1
        If iNum = 100 Then oMyTimer.Stop() : Exit Sub

    End Sub
      
    Sub labelClick(sender As Object, e As EventArgs)
        Dim oX As Label = sender
        oX.Dispose()
    End Sub
End Class

  



그림과 같이 폼이 뜨면서 0.5초마다 Label콘트롤이 만들어지면서
Form의 Controls집합체에 추가 된다
1)Label이 생성된다...New Label
2)폼은 내용물에 따라서 자동크기가 변한다...Me.AutoSize=True
3)Label의 바탕색은 랜덤으로 바뀐다.. {Color.Yellow, Color.Wheat, Color.SeaShell}(New Random().Next(3))
4)Label을 크릭하면 Label이 사라지게 한다...AddHandler oLabel.Click, AddressOf labelClick
5)Label 100개가 만들어지면 타이머를 중단한다...oMyTimer.Stop

VB.Net에 오면 New 를 사용한 개체생성을 밥먹듯이 한다는 점이 달라진다
oLabel.Left=...
oLabel.Top=...
으로 VBA에서 하던 것을 (물론 이렇게 표현해도 된다)
oLable.Location=New Point(...,...)라고
Point개체를 생성하여 표현한다
oLabel.Width=...
oLabel.Height=...
라고 하던 것도 (이렇게 해도 된다)
oLabel.Size=New Size(...,...) 로 Size개체(엄밀히 따지면 Class가 아닌 Structure)를 생성해서 한다
물론 VBA에서 하던 식으로 해도 된다
하지만 어떤것은 Read Only(쓰기전용속성)이라는 에러가 나기도 하니
해당 개체를 알고 New하여 속성값을 주는 습관을 점점, 키워 나가시는 것이 VB.Net다운 코딩이 된다

WithEvents 로 선언하지 않은 개체의 이벤트프로시져의 사용을 위하여
AddHandler oLabel.Click, AddressOf labelClick

라고 한것도 실은 위의 표현은 아래표현의 축약적 사용이다
AddHandler oLabel.Click, New EventHandler(AddressOf labelClick)

와 같이 EventHandler 라는 개체를 생성하는 것이다

또한 배열의 표현과 배열에서 랜덤으로 요소값을 얻는 것을
VBA에서는,Array함수를 이해하지 못한다
그래서 에러가 난다, 물론 Int(Rnd())*3은 사용해도 되지만
Array(..,..,..,..) 대신에 {..,..,..}와 같이 괄호를 사용하면 배열의 약식표현이다
Array("A","B","C")(Int(Rnd())*3)
또한 Rnd함수(물론 사용해도 되지만)를 사용하는 대신
또다른 개체 Random개체를 생성하고 사용하는 것이 좋다
{Color.Yellow, Color.Wheat, Color.SeaShell}(New Random().Next(3))
New Random().Next(3)의 표현은 0,1,2 즉 3개의 값을 랜덤으로 얻어내라는 것

코드를 보시면서 궁금한 개체나 Structure(이것은VBA에서도 했던 기억이 나실것이다)명 위에
마우스를 항상 올려 놓고 관찰하시는 습관이 좋다
예를 들면 아래의 그림과 같이 아주 친절하게 설명이 항상 나타나니까..



개체를 없애려면, 여기에서는 Label개체를 크릭할때
해당 Label개체가 사라지게 할때
VBA에서는 oShape.Delete 와 같이 대부분의 개체를 삭제하는 Delete메소드를 사용했었다
VB.Net의 개체들은 Delete 메소드대신에 Dispose 라는 단어가 사용된다

***[LOG-IN]***

List(Of T) | System.Speech
아래와 같이 숫자 대신에 알파벳문자가 두개로 된 값을 라벨콘트롤에 써보도록 하자



1)각 라벨에 표기된 값은 랜덤으로 만들어 내고, 중복되는 것이 없어야 한다
2)라벨을 크릭하면 알파벳을 읽어주는 소리가 나게 한다
라는 것을 해보자..
중복되는 것이 없도록 한다!!!
어떻게 하면 좋을까??
VBA에서 했다면 Collection 개체를 생성하여 만들어지는 값을 추가하면서
두번째 매개변수가 중복되는 값이면 에러가 나니까.. 일부러 에러를 유도하여
에러시 바이패스하면서 유일한 값만 추가 되게 하는 편법을 썼었다
그렇지 않으면 모아놓은 Collection개체를 다시 순환하면서 같은 값이 있는지 확인하는
번거로운 짓을 했어야 한다..
하지만 VB.Net에는 System.Collections.Generic 이라는 NameSpace에
List(Of T) 라는 집합체를 다루는 Class가 있다
이것이 요술쟁이이고 , 이것을 대부분 사용하게 된다
언어의 발전은 떼거리 정보를 어떻게 효과적으로 잘 처리할수 있을까?를 궁리하는 것이고
그런 떼거리 정보를 다루기 위하여 VBA의 배열,Collection개체등이 있었지만
VB.Net에서는 System.Collection.Generic 이라는 NameSpace안에 아주 다양한
집합체(떼거리 정보)를 다루는 도구들이 준비 되어 있다
List(Of T)는 그중의 하나일 뿐이고, 대표적으로 많이 사용되는 개체이다
VB.Net에서의 즐거움은 이 떼거리정보를 쉽게 처리하다는 즐거움이 있으니
VBA에서의 Collection 개체는 이곳에서는 잊어 버려도 된다

아래와 같이 해보면 될 것이다
List(Of T)에서 T는 Type의 약자이다 Type 크래스의 다른 표현이다
즉 List(Of String) 혹은 List(Of Integer) 혹은 List(Of Label) 등등...모든 타입의 개체를
List라는 집합체에 담을수 있는 것이다
T는 여러분이 담고자 하는 개체이다
여기에서는 String 개체를 담도록 하자..

전역변수로

Dim oList As List(Of String)

라고 선언하고..
폼이 Load이벤트에서

oList=New List(Of String)

으로 생성한후.
Timer의 Tick 이벤트에서 아래와 같이 Label개체가 생성되면서 Label 개체의 Text값에
사용할 문자를 중복되지 않게 만들어 간다

Dim oRandom As New Random
Do While True
    sLabel = Chr(oRandom.Next(65, 91)) & Chr(oRandom.Next(65, 91))
    If Not oList.Contains(sLabel) Then oLabel.Text = sLabel : oList.Add(sLabel) : Exit Do
Loop

sLabel=Chr(69) & Chr(80)
과 같이 하면 69값의 알파벳과 80값의 알파벳 두개의 문자가 된다
이 값을 랜덤으로 얻기 위하여
Dim oRandom As New Random
하여 Random개체를 만들고 이것은 Next(시작값,종료값) 을 사용하여
시작값,종료값사이의 값을 얻을수 있다
이 값을 얻어서 sLabel에 담았는데..
이것이 이미 만들어진 값인지..아닌지 확인을 해야 한다

중복된 것인지 확인하려면 List(Of T)의 Contains 메소드를 사용하면
된다
말그대로 oList.Contains(sLabel) 은 oList집합체속에 sLabel이라는 문자열
정보가 있나???
없으면 추가하고 있으면 패스하고
편리하다, 이것이 없으면 순환을 하면서 알아보던가 하여야 하니까

집합체는 앞으로 다양하게 이야기가 전개 될 것이고..
이제 라벨을 크릭하면 알파벳을 읽어주는 개체를 하나 갖다 사용해 보자
VB.Net은 참조하는 것을 밥먹듯이 한다고 했다
참조목록을 찾아 보면
System.Speech 라는 NameSpace가 있다
이것을 참조시키고..
AddAddressOf 로 설정한 라벨의 크릭이벤트에...

Sub labelClick(sender As Label, e As EventArgs)
Try
    Dim synth As New System.Speech.Synthesis.SpeechSynthesizer
    synth.Speak(sender.Text)
Catch ex As Exception
    MsgBox(ex.Message)
End Try
End Sub

    

System.Speech.Synthesis라는 NameSpace의 SpeechSynthsizer개체가
알아서 소리를 내어준다..
참 간단하지 않은가..
Try~Catch문은 VBA에서 즐겨쓰던 On Error Resume Next문대신에
항상 사용하는 것이 좋다

그리고 AddAddressOf 로 사용하는 이벤트프로시져의 첫째매개변수는 즉
sender As Label로 구체적인 개체를 사용하면 편리하다
WithEvents로 얻어지는 이벤트프로시져는 sender As Object로 범용개체로 타입이
정해져있지만, 사용자정의로 만드는 것은 이미 사용하려는 개체타입을 알고 있으니
sender As Object를 사용할 필요는 없는 것..

***[LOG-IN]***

Collection, List(Of T)를 좀더 살펴보자
List(Of T) 라는 집합체는 정말 매력적인 것이다
이것을 좀더 살펴가면서 프로그래밍파워를 올려 보자

1)TextBox 콘트롤 2개를 생성하여 폼에 추가해 보고
2)Button 콘트롤을 생성하여 폼에 추가해 보고
3)폼이 로딩되면서 TextBox하나에 정보를 500개정도 랜덤으로 채우고
4)로딩후 버튼을 크릭할때마다,
   첫째 TextBox콘트롤의 내용이 오름차,다시 내림차로 정렬되어 채워지게 해본다



학습하는 것은
List(Of T)집합체에 모아진 정보를 어떻게 쉽게 정렬할수 있는지를 관찰하면
VBA에서 못보던 새로운 파워풀한 기능을 보게 된다
폼의 콘트롤을 생성하여 폼에 올리는 것과 더불어
VB 언어의 언어적측면과 .NetFrameWork에서 제공하는 개체의 파워를 경험하자

Public Class Form1
     
    Dim oItemList As List(Of String)
    Dim oText1 As TextBox
    Dim oText2 As TextBox

    Const DESC As String = "내림차"
    Const ASC As String = "오름차"

    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        oText1 = New TextBox
        Dim oFont As New Font("맑은 고딕", 9)
        oText1.Multiline = True
        oText1.Font = oFont
        oText1.Location = New Point(5, 5)
        oText1.Size = New Size(100, 300)
        oText1.ScrollBars = ScrollBars.Vertical

        oText2 = New TextBox
        oText2.Multiline = True
        oText2.Font = oFont
        oText2.Location = New Point(oText1.Left + oText1.Width + 5, 5)
        oText2.Size = New Size(100, 300)
        oText2.ScrollBars = ScrollBars.Vertical

        Dim oButton As New Button
        oButton.Location = New Point(oText2.Left, oText2.Top + oText2.Height + 5)
        oButton.Font = oFont
        oButton.Text = ASC
        oButton.Size = New Size(100, 25)
        AddHandler oButton.Click, AddressOf clickButton

        Me.Controls.Add(oText1)
        Me.Controls.Add(oText2)
        Me.Controls.Add(oButton)
        Me.ClientSize = New Size(215, 340)

        fillItemList()
        oText1.Text = String.Join(vbNewLine, oItemList)
    End Sub

    Sub fillItemList()
        oItemList = New List(Of String)
        Dim oRandom As New Random
        Dim sItem As String = ""
        For iX As Integer = 1 To 500
            sItem = Chr(oRandom.Next(65, 91)) & Chr(oRandom.Next(65, 91)) & Chr(oRandom.Next(65, 91))
            If Not oItemList.Contains(sItem) Then
                oItemList.Add(sItem)
            End If
        Next
    End Sub
    Sub clickButton(sender As Button, e As EventArgs)
        If sender.Text = ASC Then
            oText2.Text = String.Join(vbNewLine, oItemList.OrderBy(Function(x) x))
            sender.Text = DESC
        Else
            oText2.Text = String.Join(vbNewLine, oItemList.OrderByDescending(Function(x) x))
            sender.Text = ASC
        End If
    End Sub
End Class


 

다른 것은 통상 하는 것이지만, 위의 빨강색부분이 집합체(Enumerable)의 파워이다
VBA에서 정렬을 하려면 워크시트의 정렬기능을 활용하지않으면
배열을 순환하면서 큰값, 작은값 비교하면서 배열요소의 자리바꿈을 하면서
처리했어야 한다
하지만 위의 빨강색은 한줄로 간단하게 처리한다

oItemList.OrderByDescending(Function(x) x))

또 OrderBy나 OrderBy메소드의 매개변수가 듣도 보도 못하던 히안한 것이 들어가 앉아있다
이것이 앞으로 이야기하게 될 것들이고
이런 표현식을 Lambda Expression 이라고 한다
다른 위의 코드에 대한 설명은 아래화일에 주석으로 달아 놓았다
다음 페이지에서 집합체의 파워를 좀더 살펴가면서 윈도우폼의 컨트롤들의
생성요령등을 같이 살펴보도록 하자

***[LOG-IN]***