• 최초 작성일: 2000-08-01
  • 최종 수정일: 2026-09-30
  • 조회수: 19 회
  • 작성자: 권현욱 (엑셀러)
  • 강의 제목: 다른 ListBox로부터 Item 추가하기

들어가기 전에

오래 전 엑셀 파일로 진행하던 강의를 웹 글로 복원한 것이라, "버튼을 눌러보세요"처럼 엑셀에서 직접 조작하라는 표현이 남아 있을 수 있습니다. 결과는 본문의 그림이나 표로 확인하실 수 있으며, 현재와 맞지 않는 내용은 보완하되 전반적인 스타일은 당시의 갬성(?)을 유지했습니다.

지난 주의 폭우에 이어 태풍… Exceller의 강좌를 보시는 분들 중에 혹시라도 수해를 당하신 분은 안계신 지 걱정이 되는군요. 혹시 그런 분이 계시더라도 너무 낙담하지 마시기를 바랍니다. 조금만 가물어도 걱정, 반대로 조금만 비가 많이 와도 피해. 비가 많이 오든 오지 않든 거기서 파생되는 피해는 모두 "수해"라는 사실이 좀 아이러니합니다.

올 봄이었는지 작년이었는지 정확히 기억나진 않는데 TV에서 해외토픽으로 중국 양쯔강 유역의 대홍수 에 대해 보도를 하는 중이었는데 어떤 사람이 집은 물에 잠기어 지붕 위로 피신을 간 상태에서 낚시대를 드리우고 있더군요. 그걸 보면서 '아! 저게 바로 대륙적 기질이 아닐까?'하고 생각을 했었습니다.

천재지변을 보면 항상 생각하는 것이지만 인간이란 참으로 보잘 것 없는 존재라는 사실을 새삼스레 하게 됩니다. 과학기술이 아무리 발달하고 인간의 유전자를 완전히 해독하더라도 5분 후에 어떤 일이 생길지 알 수 없는 것이 세상사이지요(말투로만 봐서는 산전수전 공중전 다 겪은 투… 죄송!! ^^)

'주어진 매 순간순간을 까불지(?) 않고 최선을 다해서 진실되게 사는 것이 진정으로 잘 사는 것이다'라는 생각을 다시금 해보게 됩니다.

권현욱(엑셀러)
저자: 권현욱(엑셀러), 아이엑셀러 대표

필자는 Excel 컨설턴트, 작가, 그리고 크리에이터입니다. 현재 Microsoft Excel MVP이며, 『챗GPT+엑셀 업무자동화 정석』을 비롯한 10여 권의 도서를 집필했습니다. Excel 자동화 및 생산성 향상 분야에서 25년 넘는 경력을 보유하고 있습니다.

권현욱(엑셀러) 님의 최신 포스트:
  • 최신 글을 불러오는 중...


26년 경력 Microsoft MVP 권현욱(엑셀러) 대표 직강 1강 무료

🎁 파워툴스 마스터클래스 · 엑셀 바이브 코딩

AI에게 말로 지시해서 '나만의 엑셀 도구'를 만들고 리본에 장착합니다.

  • 코딩 지식 없이 시작 · 코드는 AI가 작성
  • 엑셀 리본에 내 탭과 버튼을 만들고 XLAM으로 공유
  • 1강 무료 수강 가능
수강 신청하기 강의 소개 보기

다른 ListBox로부터 Item 추가하기

핵심 요약: 리스트박스 간 항목 이동

AddItem, RemoveItem과 ListIndex 검사만으로 두 리스트박스 사이의 항목 이동을 만들 수 있습니다.

  • 1단계: 미선택 여부를 ListIndex로 먼저 검사합니다.
  • 2단계: 중복 허용이 아니면 ListBox2 항목과 비교한 뒤 AddItem합니다.
  • 3단계: 삭제는 RemoveItem .ListIndex로 처리합니다.

Step 1: 결과 미리 보기

본론으로 들어가서… 이번 강좌의 제목은 좀 길군요 ^^. 강좌 내용을 한 줄에 함축적으로 나타내려다 보니 그렇게 되었습니다. 어떤 프로그램을 만들든지 가장 먼저 생각해야 할 사항은 철저하게 사용자 위주로 만들 어져야 한다는 사실일 것입니다.

오늘 설명드릴 내용도 바로 그것과 관련이 있는 것입니다. 예제를 살펴보고 오시기 바랍니다.

예제를 실행시켜 보셨지요? 이런 형태는 어디서 볼 수 있느냐 하면, Excel에서는 잘 모르겠고… 억세스에서 Form을 작성할 때 "폼 마법사"에서 테이블 중 필요한 필드를 선택할 때 사용이 되었습니다. 억세스를 사용하 시는 분들은 자세히 한번 살펴보시기 바랍니다.

Step 2: 유저폼 만들기

(1) VB Editor 상태에서(Alt+<F11>) UserForm을 하나 삽입하고 컨트롤들을 적당한 위치에 배치하여 다음과 같은 모양을 만듭니다.

원본 목록과 추가할 목록 리스트박스, 추가/삭제 버튼이 있는 유저폼
아이엑셀러

이제 UserForm만 탁 보면 어떤 어떤 컨트롤들이 사용되었고 대충 무슨 속성(프로퍼티)을 변경했는지 웬만큼은 아시겠지요? 물론 컨트롤에 attach된 코드야 속을 들여다 보아야 알 수 있지만 말이지요. 해서 앞으로는 컨트롤에 대한 설명은 미주알고주알 설명드리지 않아도 되리라 생각하고 그냥 넘어가도 록 하겠습니다. 예고도 없이 바로 설명이 없으면 허전 하니까 오늘까지만 설명을 드리도록 하겠습니다.

이 UserForm에는 4종류, 10개의 컨트롤이 사용되었습니다.

① Label 컨트롤

컨트롤명변경할 속성변경 내용
Label1Caption원본 목록
Label2Caption추가할 목록

② ListBox 컨트롤

컨트롤명변경할 속성변경 내용
ListBox1없음없음(크기는 적당히 조절)
ListBox2없음없음(크기는 적당히 조절)

③ CommandButton 컨트롤

컨트롤명변경할 속성변경 내용
CommandButton1Caption추가하기&gt;&gt;
NamebtnAdd
CommandButton2Caption모두추가&gt;&gt;
NamebtnAddAll
CommandButton3Caption&lt;&lt;삭제하기
NamebtnDelete
CommandButton4Caption확인
NamebtnOK
CommandButton5Caption취소
NamebtnCancel

④ CheckBox 컨트롤

컨트롤명변경할 속성변경 내용
CheckBox1Caption중복 허용
NamechkDuplicate

이로써 기초작업은 끝이 났습니다. 이제부터는 코딩작업에 들어가면 될 것입니다.

Step 3: 코드 작성하기

(1) 추가하기 버튼

(2) "추가하기>>" 버튼을 더블클릭하면 btnAdd_Click() 이벤트가 발생하는데 아래와 같이 코드를 작성 해 줍니다. 이 부분이 오늘 강좌의 핵심이라고 할 수 있습니다.

Private Sub btnAdd_Click()
    Dim i As Integer

    If ListBox1.ListIndex < 0 Then
        MsgBox "아무 것도 선택되지 않았습니다!", , "//Exceller"
        Exit Sub
    End If
    '//이 부분은 에러 검문소입니다. ListBox1, 즉 원본 목록 리스트박스에서 아무 항목도 선택하지 않은
    '//상태에서 "추가하기>>" 버튼을 클릭하면 에러 메시지를 뿌려주고 다시 시작하도록 하는 것이지요.

    If Not chkDuplicate Then
    '//"중복 허용" 체크 박스가 선택되지 않았다면 아래의 구문을 실행하게 되겠지요? 그런데 여기서, 체크
    '//박스가 선택되지 않았다는 것은 무슨 말일까요? 그렇지요! 중복해서 추가하는 것을 허락하지 않겠다
    '//는 의미이지요.

        For i = 0 To ListBox2.ListCount - 1
            If ListBox1.Value = ListBox2.List(i) Then
                MsgBox "이미 선택된 Item입니다!", vbInformation, "//Exceller"
                Exit Sub
            End If
            '//리스트 박스1에서 선택된 항목이 리스트 박스2에 이미 있나없나를 For~Next 반복문을 사용하
            '//여 순차적으로 검색을 합니다. 그래서 같은 항목이 이미 존재한다면 메시지 박스를 띄우고 Exit
            '//Sub 하게 됩니다.
        Next i
    End If
    ListBox2.AddItem ListBox1.Value
    '//그래서 이상이 없는 경우, AddItem 방법(Method)을 사용하여 리스트 박스2에 추가를 해 줍니다.
End Sub

(2) 모두추가 버튼

(3) 유저폼으로 돌아가서(Shift + <F7>), 이번에는 "모두추가>>" 버튼을 더블클릭한 다음 이 버튼의 클릭 이벤트에 다음과 같은 코드를 입력합니다. 말 그대로 ListBox1의 모든 목록을 ListBox2에 고스란히 추가 하는 코드입니다.

Private Sub btnAddAll_Click()
    Dim i As Integer

    If Not chkDuplicate Then
        For i = 0 To ListBox2.ListCount - 1
            If ListBox1.Value = ListBox2.List(i) Then
                MsgBox "이미 선택된 Item이 있습니다!", vbInformation, "//Exceller"
                Exit Sub
            End If
        Next i
    End If
    '//이 부분은 (2)와 같은 부분입니다. 프로그래밍을 할 때 또 한가지 주의할 점은 불필요한 요소, 중복
    '//되는 부분이 없어야 한다는 것입니다. 따라서 (2)에서 썼던 코드를 여기서 또 쓴다는 것은 분명 비효
    '//율적이지요? 시간이 없어서 이대로 두겠습니다. 코드 최적화는 여러분들이 직접 해 보세요.

    For i = 0 To ListBox1.ListCount - 1
        ListBox2.AddItem ListBox1.List(i)
        '//For~Next 반복문을 돌면서 ListBox1에 있는 모든 항목을 ListBox1에 추가하는 것입니다.
    Next i
End Sub

(3) 삭제하기 버튼

(3) Shift + <F7>를 눌러 유저폼으로 가서, "<<삭제하기" 버튼을 더블클릭하고 필요한 코드를 작성합니다.

Private Sub btnDelete_Click()
    With ListBox2
        If .ListIndex < 0 Then Exit Sub
        .RemoveItem .ListIndex
        '//ListBox2에서 지정한 항목을 제거하는 코드도 아주 간단합니다. 보시는 바와 같이 ListIndex가 0
        '//보다 작다는 것은 아무 아이템도 선택되지 않았다는 뜻이므로 이 때에는 아무 작업도 하지 않고,
        '//그렇지 않을 경우, 즉 어떤 항목이 선택되었다면 그 항목을 RemoveItem 메서드(Method)를 써서
        '//말 그대로 Remove하는 것이지요.
    End With
End Sub

(4) 확인 버튼

(4) 유저폼으로 돌아가서 이번에는 "확인"버튼을 선택하고 다음 코드를 입력해 줍니다.

Private Sub btnOK_Click()
    Dim i As Integer
    Dim strTemp As String
    '//변수를 선언해 주었군요. 정수형 변수 I는 순환문을 돌릴 때 사용할 변수이고, strTemp는 프로시저의
    '//마지막 부분에서, 선택된 항목(들)을 메시지 박스에 뿌려줄 때 사용하기 위한 문자열 변수입니다.

    For i = 1 To ListBox2.ListCount
        strTemp = strTemp & ListBox2.List(i - 1) & vbCr
        '//여기에서… 왜 ListBox2.List(I-1)과 같이 I에다가 1을 빼 주었을까요? 그렇습니다! ListBox는 맨
        '//위 항목의 index값이 1이 아닌 0부터 시작되기 때문이지요. 만약 For I=1 To… 가 아니라 For I=0…
        '//으로 되어 있었다면 List(I-1)이 아닌, List(I)라고만 해 주면 될 것입니다.

        '//그러면 애초에 For I=1...이 아니라 For I=0…로 하지 왜 사람을 헷갈리게 합니까? 이것은 여러분을
        '//일부러 애먹이기 위한 것이 아니고 ListIndex의 속성을 다시 한번 생각해 보시도록 하기 위해 일부
        '//러 그렇게 해 본 것입니다(용의주도한 지고! ^^)

    Next i
    MsgBox "추가하신 목록은 " & vbCr & vbCr & _
        strTemp & vbCr & "입니다", , "//Exceller"
    Unload Me
End Sub

(5) 취소 버튼

(5) 다시 유저폼으로 돌아가서 "취소"버튼을 더블클릭하고 아래 코드를 입력합니다.

Private Sub btnCancel_Click()
    Unload Me
End Sub

(6) 초기화 이벤트와 폼 호출

(6) 자, 이제 마지막으로 유저폼의 빈공간(즉 컨트롤이 없는 공간)을 더블클릭하고 이벤트 선택버튼을 눌러 UserForm_Initialize 이벤트를 생성한 후 초기화 이벤트 코드를 입력합니다.

Private Sub UserForm_Initialize()
    ListBox1.RowSource = "cosmetics"
    '//RowSource 속성을 사용하여 리스트 박스 목록의 원본 영역을 지정해 줍니다.
    '//그런데… cosmetics라는 범위명은 어디에 있을까요?
    '//Sheet2의 어딘가에 숨겨 놓았으니 잘 찾아보시기 바랍니다 ^^. 도저히 못 찾겠다 싶으시면
    '//메일 주세요.
End Sub

Sub ShowMetheForm()
    UserForm1.Show
End Sub

마무리

이렇게 해 주시면 됩니다. 코드 자체가 복잡하진 않을 것입니다. 다만 여러 부분부분으로 나뉘어져 있어 한눈에 들어오진 않을지 모르겠습니다만 각 부분간의 유기적인 관계만 잘 파악을 하시면 나머지는 아주 쉽게 해결이 될 것이라 생각됩니다.

오늘은 여기서 접습니다. 한꺼번에 너무 많이하면 머리에 쥐(?)가 날 지도 모르니까…

다음 시간에…

정리 — 항목 이동 핵심

구분 사용한 코드 역할
항목 추가 ListBox2.AddItem ListBox1.Value 선택 항목 추가
중복 검사 If Not chkDuplicate Then 중복 허용 여부
전체 추가 For i = 0 To ListBox1.ListCount - 1 모든 항목 추가
항목 삭제 .RemoveItem .ListIndex 선택 항목 제거
목록 읽기 ListBox2.List(i - 1) 인덱스는 0부터

자주 묻는 질문 (FAQ)

Q1. 중복 허용 체크박스는 어떻게 동작하나요?

체크되지 않았다면 추가하기 전에 ListBox2에 같은 항목이 있는지 검사하여 있으면 메시지를 표시하고 종료합니다.

Q2. ListBox의 인덱스는 몇 번부터 시작하나요?

0부터 시작합니다. 그래서 For i = 1 To ListCount 형태에서는 List(i - 1)로 접근합니다.

Q3. 선택한 항목을 제거하려면 어떻게 하나요?

ListIndex가 0 이상인지 확인한 뒤 RemoveItem 메서드에 ListIndex를 전달합니다.

마치며

여러 부분으로 나뉜 코드이지만 각 부분의 관계만 파악하면 어렵지 않게 응용할 수 있습니다.