Excel 노가다작업의 자동화!

회사 일을 하다 보니 Excel 프로그램을 통한 단순 반복 노동 작업이 있었다.
2주 정도 단순 반복 노동을 하다가 너무 지겹고 잠만 쏟아지길래
프로그램으로 자동화를 시켜보았다.

우선 Excel과 호환성이 좋은 Visual Basic으로 언어를 선택하였고,
간단히 코드를 구성해서 돌려보았더니 나름 의도한 대로? 잘 실행되었다 ㅋㅋ
CSV 파일의 내용을 읽어와서 xlsx 파일에 붙여넣는 형식인데….
자세히 설명하긴 의미 없고 소스 코드를 첨부하겠다.

'제   목 : 단순반복노동으로 지친 당신을 위한 VB Program
'기   능 : 미팅자료에다가 CVS 파일 내용 붙여넣어줌
'파일이름 : VBA_EXCEL
'수정날짜 : 2023-01-13
'작 성 자 : 김영진

Imports System.CodeDom
Imports System.Net.NetworkInformation
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Excel

Public Class Form1

    Public Structure mystructure1 '미팅자료에서 취득한 데이터를 저장하는 구조체
        Public judge As String '판정
        Public defect_name As String '불량명
        Public grid As String '그리드
        Public defect_form As String '불량형태
        Public Panel_ID As String 'TFT PNL
        Public _Date As String '검사 완료 시간
        Public Machine As String 'Machine
        Public judge2 As String '판정
        Public Adhesive_type As String '합착 Type
        Public Gate As String '검출 GATE 좌표
        Public Data As String '검출 DATA 좌표
        Public Grid_AP As Char 'GRID 좌표 AP1 //Grid는 앞의 알파벳만 따오기 위해서 char를 사용.
        Public defect_classification As String '불량대분류
        Public form As String '형태
    End Structure

    Public Structure mystructure2 'CSV 내용을 저장하는 구조체
        Public Panel_ID As String 'Panel ID
        Public _Date As String 'Date
        Public Time As String
        Public PatternType As String
        Public DefectType As String
        Public DefectColor As String
        Public LineMode As String
        Public ReAlign As String
        Public PinMiss As String
        Public Data As String
        Public Data_3 As String
        Public Gate As String
        Public ImageX As String
        Public ImageY As String
        Public Area As String
        Public Width As String
        Public Height As String
        Public AspectRatio As String
        Public Extend As String
        Public Solidity As String
        Public EquivalentDiameter As String
        Public Orientation As String
        Public fEllipseWidth As String
        Public fEllipseHeight As String
        Public fBoundinBoxWidth As String
        Public fBoundinBoxHeight As String
        Public nMaxGv As String
        Public nMinGv As String
        Public fMeanGv As String
        Public fSd As String
        Public fVariance As String
        Public fContourPerimeter As String
        Public fContrast As String
        Public ptConVexHull As String
        Public ptContour As String
        Public Path As String
        Public PathSum As String
        Public StainLevel As String
        Public StainFigures As String
        Public StainType As String
        Public StainColor As String
        Public StainTypeOrg As String
        Public StainDiffAvr As String
        Public StainDiffHL As String
        Public StainDiffH As String
        Public StainDiffL As String
        Public StainDiffSd As String
        Public Grid As String
        Public Cam As String
        Public OriginPdArea As String
        Public OriginPdAvr As String
        Public RelativePdArea As String
        Public RelativePdAvr As String
        Public PdDistX As String
        Public PdDistY As String
        Public PdDistD As String
        Public PdSd As String
    End Structure

    'Panel 정보를 담는 구조체 2개 생성
    Dim meeting As mystructure1
    Dim CSV As mystructure2

    'Excel 파일 입출력을 위한 Object 생성
    Dim cell As Object
    Dim cell_file As Object

    Dim i As Integer 'Panel 갯수만큼 반복
    Dim j As Integer 'CSV 파일 안에서 검색기능을 위한 반복문 변수

    Dim raw_data_path As String '검색경로 저장을 위한 변수
    Dim Year As String '연 월 일 검색경로 설정에서 사용되는 변수
    Dim Month As String
    Dim Day As String
    Dim path_date As String '연월일을 조합해서 경로를 설정하는데 사용되는 변수

    Dim Start_Point As Integer '반복문 시작지점 i 에서 사용
    Dim _End_Point As Integer '반복문 종료지점 i 에서 사용
    Dim Sheet As Integer '몇 번째 Sheet에서 Panel ID를 받아오고 작업을 진행할 것인지에 대해 사용되는 변수

    Dim Search As Boolean '검색 성공여부를 확인하기 위한 변수
    Dim Data As Boolean 'Data 취득여부를 확인하기 위한 변수
    Dim Miss_Cnt As Integer '데이터 복사에 실패한 패널 갯수를 카운트하는 용도

    Private Sub Run_Click(sender As Object, e As EventArgs) Handles Run.Click
        Sheet = Sheet_TextBox.Text 'Sheet 번째 시트에서
        Start_Point = Start_Point_TextBox.Text 'Start_Point 행부터
        _End_Point = End_Point_TextBox.Text '_End_Point 행까지 작업한다.
        Miss_Cnt = 0 '데이터 복사에 실패한 패널 갯수 시작은 0

        For i = Start_Point To _End_Point
            Data = False 'Data 취득여부 Default 값 False
            Search = False '검색결과 여부 Default 값 False

            Meeting_Cell_Read() '미팅자료에서 Panel 정보를 읽어온다.
            Search_Path_Set() '검색 경로를 설정한다.

            Panel_ID.Text = meeting.Panel_ID '취득한 Panel ID 를 출력한다.
            Grid.Text = meeting.Grid_AP '취득한 Grid 를 출력한다.
            Search_path.Text = raw_data_path '검색 경로를 출력한다.

            Search_CSV() 'CSV 파일에서 조건과 일치하는 Panel 정보를 Copy
            '위 함수에서 나왔을 때 검색에 성공했다면 Search = True 가 된다.

            If Search = False Then '검색에 실패했을 때 경로 재설정
                raw_data_path = CAM2_path.Text & path_date '경로를 CAM2 으로 재설정
                Search_CSV() '재탐색
            End If

            If Data = True Then 'Data 취득여부가 True 일 때
                Meeting_Cell_Save() '미팅자료에 집어넣고 저장함!
            Else
                Miss_Cnt += 1
            End If
            Progress.Text = i & " 번째 행 작업 완료"
        Next i
        MessageBox.Show("Complete!")
        MessageBox.Show(Miss_Cnt & " 개의 데이터 취득에 실패했습니다.")
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        cell = CreateObject("excel.application")
    End Sub

    Public Sub Copy_CSV()
        CSV.Panel_ID = cell_file.sheets(1).Cells(j, 1).value
        CSV._Date = cell_file.sheets(1).Cells(j, 2).value
        CSV.Time = cell_file.sheets(1).Cells(j, 3).value
        CSV.PatternType = cell_file.sheets(1).Cells(j, 4).value
        CSV.DefectType = cell_file.sheets(1).Cells(j, 5).value
        CSV.DefectColor = cell_file.sheets(1).Cells(j, 6).value
        CSV.LineMode = cell_file.sheets(1).Cells(j, 7).value
        CSV.ReAlign = cell_file.sheets(1).Cells(j, 8).value
        CSV.PinMiss = cell_file.sheets(1).Cells(j, 9).value
        CSV.Data = cell_file.sheets(1).Cells(j, 10).value
        CSV.Data_3 = cell_file.sheets(1).Cells(j, 11).value
        CSV.Gate = cell_file.sheets(1).Cells(j, 12).value
        CSV.ImageX = cell_file.sheets(1).Cells(j, 13).value
        CSV.ImageY = cell_file.sheets(1).Cells(j, 14).value
        CSV.Area = cell_file.sheets(1).Cells(j, 15).value
        CSV.Width = cell_file.sheets(1).Cells(j, 16).value
        CSV.Height = cell_file.sheets(1).Cells(j, 17).value
        CSV.AspectRatio = cell_file.sheets(1).Cells(j, 18).value
        CSV.Extend = cell_file.sheets(1).Cells(j, 19).value
        CSV.Solidity = cell_file.sheets(1).Cells(j, 20).value
        CSV.EquivalentDiameter = cell_file.sheets(1).Cells(j, 21).value
        CSV.Orientation = cell_file.sheets(1).Cells(j, 22).value
        CSV.fEllipseWidth = cell_file.sheets(1).Cells(j, 23).value
        CSV.fEllipseHeight = cell_file.sheets(1).Cells(j, 24).value
        CSV.fBoundinBoxWidth = cell_file.sheets(1).Cells(j, 25).value
        CSV.fBoundinBoxHeight = cell_file.sheets(1).Cells(j, 26).value
        CSV.nMaxGv = cell_file.sheets(1).Cells(j, 27).value
        CSV.nMinGv = cell_file.sheets(1).Cells(j, 28).value
        CSV.fMeanGv = cell_file.sheets(1).Cells(j, 29).value
        CSV.fSd = cell_file.sheets(1).Cells(j, 30).value
        CSV.fVariance = cell_file.sheets(1).Cells(j, 31).value
        CSV.fContourPerimeter = cell_file.sheets(1).Cells(j, 32).value
        CSV.fContrast = cell_file.sheets(1).Cells(j, 33).value
        CSV.ptConVexHull = cell_file.sheets(1).Cells(j, 34).value
        CSV.ptContour = cell_file.sheets(1).Cells(j, 35).value
        CSV.Path = cell_file.sheets(1).Cells(j, 36).value
        CSV.PathSum = cell_file.sheets(1).Cells(j, 37).value
        CSV.StainLevel = cell_file.sheets(1).Cells(j, 38).value
        CSV.StainFigures = cell_file.sheets(1).Cells(j, 39).value
        CSV.StainType = cell_file.sheets(1).Cells(j, 40).value
        CSV.StainColor = cell_file.sheets(1).Cells(j, 41).value
        CSV.StainTypeOrg = cell_file.sheets(1).Cells(j, 42).value
        CSV.StainDiffAvr = cell_file.sheets(1).Cells(j, 43).value
        CSV.StainDiffHL = cell_file.sheets(1).Cells(j, 44).value
        CSV.StainDiffH = cell_file.sheets(1).Cells(j, 45).value
        CSV.StainDiffL = cell_file.sheets(1).Cells(j, 46).value
        CSV.StainDiffSd = cell_file.sheets(1).Cells(j, 47).value
        CSV.Grid = cell_file.sheets(1).Cells(j, 48).value
        CSV.Cam = cell_file.sheets(1).Cells(j, 49).value
        CSV.OriginPdArea = cell_file.sheets(1).Cells(j, 50).value
        CSV.OriginPdAvr = cell_file.sheets(1).Cells(j, 51).value
        CSV.RelativePdArea = cell_file.sheets(1).Cells(j, 52).value
        CSV.RelativePdAvr = cell_file.sheets(1).Cells(j, 53).value
        CSV.PdDistX = cell_file.sheets(1).Cells(j, 54).value
        CSV.PdDistY = cell_file.sheets(1).Cells(j, 55).value
        CSV.PdDistD = cell_file.sheets(1).Cells(j, 56).value
        CSV.PdSd = cell_file.sheets(1).Cells(j, 57).value
        Data = True 'Data 취득 완료
    End Sub
    Public Sub Search_CSV()
        cell_file = cell.Workbooks.Open(raw_data_path)
        For j = 2 To 100
            'CSV 에서는 기본적으로 1번째 Sheet에서 데이터를 취득하도록 되어있다.
            If cell_file.sheets(1).cells(j, 1).value = "" Then
                '반복문을 100회로 설정해두었지만, CSV에 내용이 없을 때 시간허비를 최소화하기위한 조건문.
                Exit For
            End If
            If cell_file.sheets(1).Cells(j, 4).value = "BLACK" And 'Pattern 이 BLACK 이고
                    cell_file.sheets(1).Cells(j, 11).value = meeting.Data And 'Data 좌표와
                    cell_file.sheets(1).Cells(j, 12).value = meeting.Gate And 'Gate 좌표가 일치하며
                    cell_file.sheets(1).Cells(j, 6).value = "Bright" Then 'DefectColor 가 Bright 일 때
                Search = True
                Copy_CSV() 'CSV 파일에 있는 정보를 Copy 해온다.
                Exit For
            End If
        Next j
        cell_file.close()
    End Sub
    Public Sub Meeting_Cell_Save()
        '취득한 Data를 미팅자료에 기입한다.
        cell_file = cell.Workbooks.Open(meeting_path.Text)
        cell_file.sheets(Sheet).Cells(i, 19).value = CSV.Panel_ID
        cell_file.sheets(Sheet).Cells(i, 20).value = CSV._Date
        cell_file.sheets(Sheet).Cells(i, 21).value = CSV.Time
        cell_file.sheets(Sheet).Cells(i, 22).value = CSV.PatternType
        cell_file.sheets(Sheet).Cells(i, 23).value = CSV.DefectType
        cell_file.sheets(Sheet).Cells(i, 24).value = CSV.DefectColor
        cell_file.sheets(Sheet).Cells(i, 25).value = CSV.LineMode
        cell_file.sheets(Sheet).Cells(i, 26).value = CSV.ReAlign
        cell_file.sheets(Sheet).Cells(i, 27).value = CSV.PinMiss
        cell_file.sheets(Sheet).Cells(i, 28).value = CSV.Data
        cell_file.sheets(Sheet).Cells(i, 29).value = CSV.Data_3
        cell_file.sheets(Sheet).Cells(i, 30).value = CSV.Gate
        cell_file.sheets(Sheet).Cells(i, 31).value = CSV.ImageX
        cell_file.sheets(Sheet).Cells(i, 32).value = CSV.ImageY
        cell_file.sheets(Sheet).Cells(i, 33).value = CSV.Area
        cell_file.sheets(Sheet).Cells(i, 34).value = CSV.Width
        cell_file.sheets(Sheet).Cells(i, 35).value = CSV.Height
        cell_file.sheets(Sheet).Cells(i, 36).value = CSV.AspectRatio
        cell_file.sheets(Sheet).Cells(i, 37).value = CSV.Extend
        cell_file.sheets(Sheet).Cells(i, 38).value = CSV.Solidity
        cell_file.sheets(Sheet).Cells(i, 39).value = CSV.EquivalentDiameter
        cell_file.sheets(Sheet).Cells(i, 40).value = CSV.Orientation
        cell_file.sheets(Sheet).Cells(i, 41).value = CSV.fEllipseWidth
        cell_file.sheets(Sheet).Cells(i, 42).value = CSV.fEllipseHeight
        cell_file.sheets(Sheet).Cells(i, 43).value = CSV.fBoundinBoxWidth
        cell_file.sheets(Sheet).Cells(i, 44).value = CSV.fEllipseHeight
        cell_file.sheets(Sheet).Cells(i, 45).value = CSV.nMaxGv
        cell_file.sheets(Sheet).Cells(i, 46).value = CSV.nMinGv
        cell_file.sheets(Sheet).Cells(i, 47).value = CSV.fMeanGv
        cell_file.sheets(Sheet).Cells(i, 48).value = CSV.fSd
        cell_file.sheets(Sheet).Cells(i, 49).value = CSV.fVariance
        cell_file.sheets(Sheet).Cells(i, 50).value = CSV.fContourPerimeter
        cell_file.sheets(Sheet).Cells(i, 51).value = CSV.fContrast
        cell_file.sheets(Sheet).Cells(i, 52).value = CSV.ptConVexHull
        cell_file.sheets(Sheet).Cells(i, 53).value = CSV.ptContour
        cell_file.sheets(Sheet).Cells(i, 54).value = CSV.Path
        cell_file.sheets(Sheet).Cells(i, 55).value = CSV.PathSum
        cell_file.sheets(Sheet).Cells(i, 56).value = CSV.StainLevel
        cell_file.sheets(Sheet).Cells(i, 57).value = CSV.StainFigures
        cell_file.sheets(Sheet).Cells(i, 58).value = CSV.StainType
        cell_file.sheets(Sheet).Cells(i, 59).value = CSV.StainColor
        cell_file.sheets(Sheet).Cells(i, 60).value = CSV.StainTypeOrg
        cell_file.sheets(Sheet).Cells(i, 61).value = CSV.StainDiffAvr
        cell_file.sheets(Sheet).Cells(i, 62).value = CSV.StainDiffHL
        cell_file.sheets(Sheet).Cells(i, 63).value = CSV.StainDiffH
        cell_file.sheets(Sheet).Cells(i, 64).value = CSV.StainDiffL
        cell_file.sheets(Sheet).Cells(i, 65).value = CSV.StainDiffSd
        cell_file.sheets(Sheet).Cells(i, 66).value = CSV.Grid
        cell_file.sheets(Sheet).Cells(i, 67).value = CSV.Cam
        cell_file.sheets(Sheet).Cells(i, 68).value = CSV.OriginPdArea
        cell_file.sheets(Sheet).Cells(i, 69).value = CSV.OriginPdAvr
        cell_file.sheets(Sheet).Cells(i, 70).value = CSV.RelativePdArea
        cell_file.sheets(Sheet).Cells(i, 71).value = CSV.RelativePdAvr
        cell_file.sheets(Sheet).Cells(i, 72).value = CSV.PdDistX
        cell_file.sheets(Sheet).Cells(i, 73).value = CSV.PdDistY
        cell_file.sheets(Sheet).Cells(i, 74).value = CSV.PdDistD
        cell_file.sheets(Sheet).Cells(i, 75).value = CSV.PdSd
        cell_file.save() '저장
        cell_file.saved = True '저장저장
        cell_file.Close() '종료!
    End Sub

    Public Sub Search_Path_Set()
        '미팅자료에서 취득한 Date로 부터 연/월/일 을 구분한다.
        'CSV path 경로설정에서 사용된다.
        Year = Mid(meeting._Date, 1, 4)
        Month = Mid(meeting._Date, 6, 2)
        Day = Mid(meeting._Date, 9, 2)
        '연/월/일 을 조합해서 csv 경로를 설정한다.
        path_date = "\" & Year & "\" & Month & "\" & Day & "\PANEL\CSV_" & meeting.Panel_ID & ".csv"

        If meeting.Grid_AP = "A" Or 'A~E
            meeting.Grid_AP = "B" Or
                meeting.Grid_AP = "C" Or
                meeting.Grid_AP = "D" Or
                meeting.Grid_AP = "E" Or
                meeting.Grid_AP = "F" Then
            If CAM1_RadioButton.Checked = True Then 'A0 위치가 CAM1 일 때
                raw_data_path = CAM1_path.Text & path_date 'A~F 를 CAM1 경로에서 찾는다.
            ElseIf CAM3_RadioButton.Checked = True Then 'A0 위치가 CAM3 일 때
                raw_data_path = CAM3_path.Text & path_date 'A~F 를 CAM3 경로에서 찾는다.
            End If
        ElseIf meeting.Grid_AP = "G" Or '2번 CAM은 Radio Button Checked 유무와 상관없이
                meeting.Grid_AP = "H" Or '2번 경로로 고정
                meeting.Grid_AP = "I" Or
                meeting.Grid_AP = "J" Then
            raw_data_path = CAM2_path.Text & path_date
        ElseIf meeting.Grid_AP = "K" Or
                meeting.Grid_AP = "L" Or
                meeting.Grid_AP = "M" Or
                meeting.Grid_AP = "N" Or
                meeting.Grid_AP = "O" Or
                meeting.Grid_AP = "P" Then
            If CAM1_RadioButton.Checked = True Then 'A0 위치가 CAM1 일 때
                raw_data_path = CAM3_path.Text & path_date 'K~P 위치를 CAM3 경로에서 찾는다.
            ElseIf CAM3_RadioButton.Checked = True Then 'A0 위치가 CAM3 일 때
                raw_data_path = CAM1_path.Text & path_date 'K~P 위치를 CAM1 경로에서 찾는다.
            End If
        End If
    End Sub

    Public Sub Meeting_Cell_Read()
        '미팅자료 xlsx 파일을 열어 Panel info 를 읽어온다.
        cell_file = cell.Workbooks.Open(meeting_path.Text)
        meeting.judge = cell_file.sheets(Sheet).cells(i, 1).value
        meeting.defect_name = cell_file.sheets(Sheet).cells(i, 2).value
        meeting.grid = cell_file.sheets(Sheet).cells(i, 3).value
        meeting.defect_form = cell_file.sheets(Sheet).cells(i, 4).value
        meeting.Panel_ID = cell_file.sheets(Sheet).cells(i, 5).value
        meeting._Date = cell_file.sheets(Sheet).cells(i, 6).value
        meeting.Machine = cell_file.sheets(Sheet).cells(i, 7).value
        meeting.judge2 = cell_file.sheets(Sheet).cells(i, 8).value
        meeting.Adhesive_type = cell_file.sheets(Sheet).cells(i, 9).value
        meeting.Gate = cell_file.sheets(Sheet).cells(i, 10).value
        meeting.Data = cell_file.sheets(Sheet).cells(i, 11).value
        meeting.Grid_AP = cell_file.sheets(Sheet).cells(i, 12).value
        meeting.defect_classification = cell_file.sheets(Sheet).cells(i, 13).value
        meeting.form = cell_file.sheets(Sheet).cells(i, 14).value
        cell_file.Close()
    End Sub
End Class

소스 코드는 위와 같고…. 프로그램의 실행 화면은

image-20230429075504372

이렇게 생겼다 조금 허접?하다ㅎㅎ

사용 방법은

  1. 첫 번째 텍스트 박스에는 xlsx 파일의 경로를 입력한다.
  2. 두 번째 ~ 네 번째 텍스트 박스에는 각각의 CSV 파일을 읽어올 경로를 입력한다.
  3. A0의 위치를 라디오 버튼을 통해 선택한다.
  4. 작업 범위를 설정해준다.
  5. Run 버튼을 클릭한다.

이렇게 설정해주고 나면 다음과 같이 실행된다.

image-20230429080219948

현재 작업 중인 구간을 UI로 확인할 수 있게 설정해놓았고…
작업이 완료되면 메세지 박스가 발생하도록 했다.
그러나 멀티스레드를 돌리진 않아서 작업 중일 땐 프로그램을 컨트롤할 수 없다 ㅋㅋ

끝!

댓글남기기