PROGRAMMING WORKSHOP

VSTO|
작업일정관리_7

이제 타입밴드에 융통성을 주도록 하자
앞에 까지는 1일씩 하나의 열을 사용하였다
날짜가 많아지면 현실적이지 못한 작업이 될 것이고
2003버전이하의 열의 갯수의 제한이 된 경우는 더더욱 융통성없는 타임밴드가 된다
이럴때 사용자의 의견을 받아서 처리하는 장치가 필요해진다
사용자의 의도를 받아들이는 장치로서 활용할 것은 너무도 많다
특히..엑셀의 경우는 워크시트자체를 읽고 쓰고 하는것인지라
워크시트를 많이 활용하지만
이것은 좋은 방법이 아닐 것이다
워크시트에 정보를 입력하고 사용하는 것은 수식으로 연결되는
변수로서 활용하는데 그치는 것이 좋을 것이다
사용자 입력장치를 준비하는 것이 좀더 쎄련된 소루션을
만드는 방법이 된다
그래서..Window폼은 그런 입력장치로서도 대단히 좋고
이것을 흉내 내어 주는 것이 UserForm이다
UserForm을 잘활용하면 훌륭한 소루션을 많이 만들수 있다



작업테이블이 만들어지고 기간계산이 된 후
UserForm을 띄워서
UserForm에서는 어떤 기간형식으로 할 것인지만 사용자로 부터 받아서
본래의 프로시져가 있는 모듈시트의 전역변수에 값을
전달하는 것으로 임무끝!!으로 하도록 하여
다음 작업, 타임밴드그리기, 작업에 사용할 정보가 되게 하면된다
프로그래밍에서 어떤 개체에서의 작업범위,
또 다른 작업범위에서의 작업범위를 잘 배정하는 것..그런것이
프로그래밍의 일이다
그러니..사회에 나갈 초년생들이라면
이런 자원의 분배, 프로젝트의 관리등의 연습을
손쉬운 엑셀프로그래밍으로 경험을 해 본다면 실제 현장에서의
복잡한 작업이 낯섫지 않을수도 있겠으나...아쉽다!!
엑셀을 예쁘게 표나 그리는 도구로 알고 있으니..
업무에 들어가서야 엑셀을 손에 잡으니...!!

아마도 여기에서 열공하시는 분들은 엑셀프로그래밍의 지도자급마인드를
갖은 것으로 알고..아무것도 모르는 젊은이들에게 많이
지도 하는 기회들을 갖으시기를..

콤보상자, 텍스트박스, 버튼을 그려 넣고
UserForm이 로딩되면서 아래와 같이 콤보상자를 채우고
사용자가 전체프로젝트의 시작일자와 종료일자 그리고 기간을
알고 시간의 스케일에 참고할 수 있도록 라벨에 뿌려주고
콤보상자에는 각 스케일별로 선택할수 있도록 해주고

Private Sub UserForm_Initialize()
Me.TextBoxDays.Text = "1 일간격"
Me.LabelStatus.Caption = _
        modMain_9.datProjectStart & "~" & _
		modMain_9.datProjectEnd & " | " & _
        DateDiff("d", modMain_9.datProjectStart, _
		modMain_9.datProjectEnd) + 1 & " 일"
With Me.ComboBoxTimeZone
    .AddItem "일자지정"
    .AddItem "주간별"
    .AddItem "월별"
    .AddItem "분기별"
    .AddItem "년도별"
    .ListIndex = 0
End With
Me.Caption = "SET TIME SCALE"
End Sub

그리고 사용자가 선택하게 한후
[적용]버튼을 크릭하면 아래와 같이 본래의 프로시져가 있던
모듈시트의 전역변수게 값을 전달한다

Private Sub CommandButton1_Click()
Dim sType As Variant
sType = Split("d|w|m|q|y", "|")
modMain_9.sUnitType = sType(Me.ComboBoxTimeZone.ListIndex)
If modMain_9.sUnitType = "d" Then
    modMain_9.iDaysInUnit = iif(Me.TextBoxDays.Text="",1, _
	Me.TextBoxDays.Text)
Else
    modMain_9.iDaysInUnit = 0
End If
End Sub

배열을 잘 이해하고 활용하면 위와 같이 간단하게 처리하지만
그렇지 못하면 Select~Case 하여 콤보상자의 선택을 일일이 체크하지 않아도
간결하게 표현된다

UserForm의 역활은 두개의 정보를 얻기 위한 것이였다
하나는 주간,월,분기,년도, 혹은 일자 별인지에 대한 문자열 정보를 받고

Public sUnitType As String

다른 하나는 일자별일 경우 하나의 열에 몇개의 일자간격으로
할 것인지를 받아 들이기 위한 것이다
지금까지 그린 것은 하나의 열에 1일 단위로 하였었다

Public iUnitDays As Integer



위의 그림에서와 같이
sUnitType변수정보에 따라서
datCalendarStart 와 datCalendarEnd 의 값을 만들어 낸다
아래와 같이

Sub setCalendarVariables()
Select Case sUnitType
    Case "d"
        datCalendarStart = datProjectStart
        datCalendarEnd = datProjectEnd
    Case "w"
        datCalendarStart = datProjectStart
        If Weekday(datProjectStart) <> VBA.VbDayOfWeek.vbMonday Then
            Do
                datCalendarStart = DateAdd("d", -1, datCalendarStart)
            Loop Until Weekday(datCalendarStart) = VBA.VbDayOfWeek.vbMonday
        End If
        datCalendarEnd = datProjectEnd
        If Weekday(datProjectEnd) <> VBA.VbDayOfWeek.vbSunday Then
            Do
                datCalendarEnd = DateAdd("d", 1, datCalendarEnd)
            Loop Until Weekday(datCalendarEnd) = VBA.VbDayOfWeek.vbSunday
        End If
    Case "m"
        datCalendarStart = DateSerial(Year(datProjectStart), Month(datProjectStart), 1)
        datCalendarEnd = DateAdd("m", 1, datProjectEnd)
        datCalendarEnd = DateAdd("d", -1, DateSerial(Year(datCalendarEnd), Month(datCalendarEnd), 1))
    Case "q"
        Dim iMon As Integer
        iMon = Choose(Month(datProjectStart), 1, 1, 1, 4, 4, 4, 7, 7, 7, 10, 10, 10)
        datCalendarStart = DateSerial(Year(datProjectStart), iMon, 1)
        iMon = Choose(Month(datProjectEnd), 3, 3, 3, 6, 6, 6, 9, 9, 9, 12, 12, 12)
        datCalendarEnd = DateAdd("d", -1, DateSerial(Year(datProjectEnd), iMon + 1, 1))
    Case "y"
        datCalendarStart = DateSerial(Year(datProjectStart), 1, 1)
        datCalendarEnd = DateSerial(Year(datProjectEnd), 12, 31)
End Select
End Sub

주간단위일 경우
월단위일 경우
분기단위일 경우
년도단위일 경우
해당 날짜의 시작월,시작주,시작분기등의 정보가 필요하게 되는 것
그래서 엔진중의 중요한 엔진을 뒤집어 엎어야 할 것이다
아래가 이전까지 사용하였던 타임유잇개체를 배열에 모으는 프로시져였다
이것은 타임유닛이 1일의 경우에만 적용되었고,
하나의 타임유닛이 경우에 따라서 1일,3일,5일, 혹은 주간,월간,분기등으로
융통성있게 변해야 하는 것으로 바꿔야 하는 것이 이번화일의 과제가 되겠다

Private Sub createTimeUnit()
Dim lDate As Long
Dim oTimeUnit As clsTimeUnit
Dim iIndex As Integer
Dim iAccumDays As Integer
On Error Resume Next
For lDate = datProjectStart To datProjectEnd Step iDaysInUnit
    Set oTimeUnit = New clsTimeUnit
    With oTimeUnit
        Set .rUnitCell = Nothing
        .datStart = lDate
        .datEnd = DateAdd("d", iDaysInUnit, lDate) - 1
        .iYear = Year(.datStart)
        .iMonth = Year(.datEnd)
        .iActualDays = iDaysInUnit
        .iDays = iDaysInUnit
        iAccumDays = iAccumDays + iDaysInUnit
        .iAccumDays = iAccumDays
         setAmountAndTasks oTimeUnit
    End With
    ReDim Preserve oTimeUnits(iIndex)
    Set oTimeUnits(iIndex) = oTimeUnit
    iIndex = iIndex + 1
Next
End Sub

위의 프로시져는 열하나에 1일의 경우였었다
이제 열하나에 정해진 일수나 일주일간이거나
한달이거나 , 하나의 분기이거나 아래의 그림과 같이
UserForm을 통한 사용자가 원하는 스케일의 기간 테이블을
만들도록 하는 것이다



1일 단위로 그린 것이 하나의 Proty Type,표준형,이라고 할수도 있고
하나의 템프릿이라고 할 수 도 있고 이렇게 표준적으로 만든 것에
매개변수를 전달하여 하나의 기본형(표준형)에서 다양한 형태의 것이
만들어지게 하는 것이 좋은 프로그래밍일 것이다
어떻게 하면 기본타입을 유지하면서 간략하게 매개변수 혹은
전역변수의 값을 바꿔주어 경우에 따른 다른 기본형에서 좀더
확장된 다른 형으로 만들어 가느냐의 좋은 문제이다

아래와 같이 경우에 따라 변수값만 다르게 하는 콘트롤프로시져를
만들고 표준형 작업 프로시져(빨강색)를 호출시키는 것이 좋을 것이다

Private Sub createTimeUnit_NEW()
Dim lDate As Long
Dim iIndex As Integer
Dim iAccumDays As Integer
Dim iDayCount As Integer
Dim datLastDayOfUnit As Date
Dim datStartDayOfUnit As Date
On Error Resume Next

For lDate = datCalendarStart To datCalendarEnd
Select Case sUnitType
    Case "d" ' 일자의 경우
        If iDaysInUnit = 1 Then ' 1일 인 경우
            fillTimeUnitForDayAndWeek lDate, iIndex, iAccumDays
        Else' 1일 보다 많은 일수의 경우
            If iDayCount = iDaysInUnit Then
                fillTimeUnitForDayAndWeek lDate, iIndex, iAccumDays
                iDayCount = 0
            End If
            iDayCount = iDayCount + 1
        End If
    Case "w" ' 1 주일인 경우
        If Weekday(lDate) = VBA.VbDayOfWeek.vbMonday Then
            fillTimeUnitForDayAndWeek lDate, iIndex, iAccumDays
        End If
    Case "m"' 1 개월인 경우
        If datLastDayOfUnit = 0 Then
NEW_MONTH:
            datLastDayOfUnit = DateAdd("m", 1, lDate)
            datLastDayOfUnit = DateAdd("d", -1, DateSerial(Year(datLastDayOfUnit), Month(datLastDayOfUnit), 1))
            datStartDayOfUnit = DateSerial(Year(datLastDayOfUnit), Month(datLastDayOfUnit), 1)
            iDaysInUnit = DateDiff("d", datStartDayOfUnit, datLastDayOfUnit) + 1
            
            fillTimeUnitForDayAndWeek lDate, iIndex, iAccumDays

        ElseIf DateDiff("d", datLastDayOfUnit, lDate) = 1 Then
            GoTo NEW_MONTH
            
        End If
    Case "q" '1 분기 씩인 경우
        If datLastDayOfUnit = 0 Then
NEW_QRT:
            Dim iQrt As Integer
            Dim iDaysInQrt As Integer
			
	    iQrt = Choose(Month(lDate), 3, 3, 3, 6, 6, 6, 9, 9, 9, 12, 12, 12)
            datLastDayOfUnit = DateAdd("m", 1, DateSerial(Year(lDate), iQrt, 1))
            datLastDayOfUnit = DateAdd("d", -1, datLastDayOfUnit)
            datStartDayOfUnit = DateAdd("m", -2, datLastDayOfUnit)
            datStartDayOfUnit = DateSerial(Year(datStartDayOfUnit), Month(datStartDayOfUnit), 1)
            iDaysInUnit = DateDiff("d", datStartDayOfUnit, datLastDayOfUnit) + 1
            
            fillTimeUnitForDayAndWeek lDate, iIndex, iAccumDays
            
        ElseIf DateDiff("d", datLastDayOfUnit, lDate) = 1 Then
            GoTo NEW_QRT
        End If
    Case "y" ' 1 년 씩인 경우
         If datLastDayOfUnit = 0 Then
NEW_YEAR:
            datLastDayOfUnit = DateSerial(Year(lDate), 12, 31)
            datStartDayOfUnit = DateSerial(Year(lDate), 1, 1)
            iDaysInUnit = DateDiff("d", datStartDayOfUnit, datLastDayOfUnit) + 1
            
            fillTimeUnitForDayAndWeek lDate, iIndex, iAccumDays
        
        ElseIf DateDiff("d", datLastDayOfUnit, lDate) = 1 Then
            GoTo NEW_YEAR
        End If
End Select
Next
End Sub

타임프레임의 다양화에 따라서
Gantt도형그리기부분도 좀 수정을 하여야 할 것이다
다음 화일에서 이 부분을 수정하도록 하고
아래 화일은 Gantt도형그리기 이전까지 처리된 것임

***[LOG-IN]***