- 최초 작성일: 2000-08-23
- 최종 수정일: 2026-09-30
- 조회수: 10 회
- 작성자: 권현욱 (엑셀러)
- 강의 제목: ListBox 항목 및 시트 위치 바꾸기
들어가기 전에
오래 전 엑셀 파일로 진행하던 강의를 웹 글로 복원한 것이라, "버튼을 눌러보세요"처럼 엑셀에서 직접 조작하라는 표현이 남아 있을 수 있습니다. 결과는 본문의 그림이나 표로 확인하실 수 있으며, 현재와 맞지 않는 내용은 보완하되 전반적인 스타일은 당시의 갬성(?)을 유지했습니다.
...엑셀러님의 홈페이쥐를 열심히 구독하며, 감명받고 있는 장OO입니다.
지난번 파워툴의 비밀번호 좀 알려 주셨으면 해서요..
봐도 잘 모르겠지만, 그래도 함 봤으면 해서요..
글구 오늘 재미난 계산기능을 보고 생각했던건데요...
수식이 넘 복잡해서리, 실제 사용자들이 어려워 하지 않을까 생각해 봤습니다.
차리리 데이타 입력부분만 선택 후 데이타-텍스트나누기-구분기호로분리됨- 기타 "
"/"을 사용하면 넘 쉬운데… 물론 엑셀러님의 깊은 뜻을 모르는 바는 아니지만, 이런 방법도 있다는 걸
갈쳐 주는 것도 효과적이라 생각해 봤슴다…
… 중략 …
Excel에 날개달기 VB0036 강좌에서 애드인 프로그램을 보내드리면서 코드를 감추었습니다. 그러면서 메일을 통해 신청하시면 바로 패스워드를 보내드리겠다고 했는데… 생각보다는 적지만 그래도 적지않은 분들이 패스워드 요청 메일을 보내오셨군요. 위의 분도 그 중 한 분입니다.
메일을 보내신 분들 중에서 낯익은 이름을 보면 '아 아직 열심히 하고 계시는구나!' 하는 마음에 무척 반 갑더군요. 가끔 가다가 이렇게 코드 부분을 감추는 것도 나쁘지 않을 것같다는 생각이 드는군요. ^^
J. Walkenbach라는 미국의 Excel 고수가 모니터링 한 결과에 의하면 Excel을 Excel 답게 쓰는 사람은 전체 유저의 5%내외라고 합니다. 물론 이 5%에 들기 위해서는 VBA는 자유자재로 구사해야 겠지요? 아직 망설이시는 분이 있다면 주저없이 요청 메일을 주시기 바랍니다.
그리고 위 메일 내용 중에서…
차리리 데이타 입력부분만 선택 후 데이타-텍스트나누기-구분기호로분리됨- 기타 "
"/"을 사용하면 넘 쉬운데…
라고 하셨는데…
그렇습니다! 서울로 가는 방법은 여러 가지가 있지요.
X0150 강좌의 "응답율" 부분에서 사용한 것처럼 함수를 사용해서 "배부" 부분과 "응답" 부분을 떼어낸 다음 나중에 나누어 주는 방법도 있겠고, 지적하신 것 처럼 "문자열 나누기"를 사용하는 방법도 있을 것입니다. 제가 설명드린 방법은 원본 자료에 대한 어떤 수정이나 부가적인 작업없이, 배열수식과 각종 함수를 조합하면 이렇게도 사용할 수 있다는 것을 보여드리기 위한 것이지요.
좋은 의견에 감사를 드립니다.
ListBox 항목 및 시트 위치 바꾸기
핵심 요약: 항목과 시트 위치를 함께 바꾸기
리스트박스의 인접한 두 항목을 임시 변수로 교환하고, 같은 순서로 시트를 Move하면 화면과 시트 위치가 연동됩니다.
- 1단계: 초기화 때 For Each로 시트 이름을 AddItem합니다.
- 2단계: 위/아래 버튼에서 인접 항목을 교환하고 시트를 Move합니다.
- 3단계: 선택 버튼에서 Application.Goto로 해당 시트로 이동합니다.
Step 1: 결과 미리 보기
오래간만에 ListBox에 대한 것을 또 하나 해 보도록 할까요?(오늘도 강좌 제목이 기나길군요 ^^)
이제 웬만한 리스트 박스 정도는 눈감고도 만드실 수 있을 것입니다. 잊을만 하면 언급하고, 잊을만 하면 하면 다시 설명하고… 도저히 잊을래야 잊을 수가 없도록 만들지요? ^^
그렇다고 과감하게(?) 때려 치우자니 남들은 다 하는데 나만 안하니 뒤쳐지는 것 같아서 불안하고… 이래저래 불안하시지요? ^^ 절대 여러분들에게 스트레스를 드리려고 강좌를 하는 것은 아닙니다. 지금 당장은 잘 이해가 안되고 짜증나더라도 차근차근히 잘 따라오시기 바랍니다. 하다보면 어느 순간에 가서 는 '내가 왜 그때는 이걸 몰랐을까?'하며 무릎을 치는 날이 반드시(!) 옵니다.
공연히 애꿎은 머리 탓하지 마세요! 깨진 독에 물을 채우는 방법! 물이 빠져나가는 것보다 더 빠른 속도로 물을 부어넣으면 결국엔 가득 차게 됩니다. 설령 잊어버린다 해도 계속 부어넣으시기 바랍니다.
날도 더운데 잔소리(?)가 많군요. 오늘 강좌의 예제를 살펴보도록 하지요.
리스트 박스 항목 및 시트 위치 바꾸기가 뭔지 이제 아시겠습니까?
프로그램을 실행하면 일단 유저폼의 리스트 박스 상에 현재 워크북(파일)에 있는 모든 시트의 이름이 리스 팅 됩니다. 여기서 "위로 이동" 또는 "아래로 이동" 버튼을 누르면 클릭할 때마다 리스트 박스 상에서 항목이 위/아래로 변동이 됩니다. 뿐만 아니라 시트의 위치까지도 함께 연동이 되어 변하는 것이지요.
어떤 과정을 거쳐 이 기능을 구현할 것인지 눈감고 30초만 생각을 해 보신 후 진도를 나가도록 하세요.
Step 2: 유저폼 만들기
(1) VB Editor를 연 다음 유저폼을 하나 삽입하고 아래와 같이 컨트롤들을 그려 넣습니다. 사용된 컨트롤은 리스트 박스와 4개의 CommandButton 밖에 없습니다. 각 컨트롤의 속성(들)은 어떻게 바꾸어 주어야 할지는 아시겠지요?(모르면 질문하세요)
Step 3: 코드 작성하기
(1) 위로 이동 버튼
(2) 이제 프로그래밍에 들어갑니다. 먼저 "위로 이동" 버튼을 더블클릭하면 btnUp_Click 이벤트가 생기는 데 여기에 필요한 코드를 작성합니다(물론 커맨드 버튼의 이름을 다르게 주었으면 그 이름_Click 이벤트 가 생기겠지요?).
몇 강좌 전에 버블소트 알고리즘을 이용한 시트 정렬 방법에 대해 소개해 드렸는데 기억이 나시는지? 여기서도 그와 비슷한 방법을 사용해 보았습니다. 하마가 들어있는 냉장고에 코끼리 집어 넣기와 같은 방법 이지요. ^^;
Private Sub btnUp_Click()
Dim intNum As Integer
Dim strTemp As String
With ListBox1
intNum = .ListIndex
If intNum > 0 Then
strTemp = .List(intNum - 1)
.List(intNum - 1) = .List(intNum)
.List(intNum) = strTemp
.ListIndex = .ListIndex - 1
'//바로 이 부분에서 코끼리 냉장고에 넣는 방법(일명 버블소트 알고리즘)이 사용되었습니다.
'//현재 항목의 위로 이동한다는 것은 현재 리스트보다 하나 앞으로 간다는 것과 같은 말입니다.
'//따라서 strTemp라는 임시 변수에다가 현재 리스트 바로 앞의 것을 담아둡니다.
'//그 다음에 이전 리스트에다가 현재 리스트 값으로 대치를 합니다. 이렇게 하면 두 개의 값이
'//서로 바뀌게 되는 것이지요.
'//그런 다음에 현재의 리스트에다가는 strTemp에 저장해 두었던 값을 가져와서 뿌려줍니다.
Sheets(.List(intNum - 1)).Move before:=Sheets(.List(intNum))
'//이 부분은 위에서 지정한 위치로 시트를 이동시켜 주는 과정입니다. 따로 설명드릴 만한 사항은
'//없는 것 같고…
End If
End With
End Sub
(2) 아래로 이동 버튼
(3) Shift + <F7>키를 눌러 유저폼을 호출한 다음, "아래로 이동" 버튼을 더블클릭 합니다. btnDown_Click 이벤트에 다음과 같이 코드를 작성합니다.
Private Sub btnDown_Click()
Dim intNum As Integer
Dim strTemp As String
With ListBox1
intNum = .ListIndex
If intNum < .ListCount - 1 And intNum <> -1 Then
strTemp = .List(intNum + 1)
.List(intNum + 1) = .List(intNum)
.List(intNum) = strTemp
.ListIndex = .ListIndex + 1
'//이 과정은 btnUp_Click 이벤트와 거의 비슷합니다. 다만 코끼리를 먼저 옮기느냐 아니면 하마를
'//먼저 옮기느냐 하는 차이만 있을 뿐입니다.
'//따라서 설명은 생략해도 되겠지요?
Sheets(.List(intNum + 1)).Move after:=Sheets(.List(intNum))
End If
End With
End Sub
(3) 선택 버튼
(4) Shift + <F7>, "선택" 버튼을 차례로 누른 다음, btnSelect_Click 이벤트 코드를 작성합니다. 이것은 "선택" 버튼을 눌렀을 때 해당 시트로 이동하기 위한 코드입니다.
Private Sub btnSelect_Click()
Dim intNum As Integer
Dim Msg As String
With ListBox1
If .ListIndex < 0 Then Exit Sub
intNum = .ListIndex + 1
MsgBox .List(intNum - 1) & "을(를) 선택하셨습니다", vbInformation, ID
Application.Goto Sheets(intNum).Range("a1"), True
'//코드는 별로 어려운 것이 없을 것입니다.
'//"선택"버튼이 눌려지면 MsgBox 하나를 띄워주고 몇 번째 항목이 선택되었는지를 사용자에게
'//알려 줍니다. 그런 다음에 선택된 항목에 해당되는 시트의 a1 셀로 이동을 시켜줍니다.
End With
Unload Me
End Sub
(4) 종료 버튼
(5) 유저폼으로 돌아가서 "종료" 버튼을 클릭하고 유저폼을 종료하는 코드를 작성합니다.
Private Sub btnClose_Click()
Unload Me
End Sub
(5) 초기화 이벤트
(6) 마지막으로 유저폼을 처음 호출했을 때 리스트 박스 내에 현재 워크북의 모든 시트들이 리스팅되도록 하는 코드를 작성해 주어야 겠지요? VB Editor 상에서 유저폼을 화면에 띄운 다음, 컨트롤이 없는 빈 영역을 더블클릭 합니다. 그러면 UserForm_Click 이벤트가 발생되는데 화면 우측 상단의 이벤트 선택 상자에서 초 기화(Initialize) 이벤트를 선택하고 아래의 코드를 입력합니다.
Private Sub UserForm_Initialize()
Dim sht As Worksheet
With ListBox1
.RowSource = ""
For Each sht In Sheets
.AddItem sht.Name
Next sht
'//ListBox1의 RowSource, 즉 초기 영역을 빈 공간으로 지정해 준 다음, 이제는 아주 친근해진
'//For Each~Next 순환문을 사용해서 시트의 이름을 모두 리스팅 시켜 줍니다.
End With
End Sub
(6) 공통 상수와 폼 호출
Const ID As String = "//Exceller"
Sub ShowSheetOrderForm()
UserForm1.Show
End Sub
마무리
이로써 완성되었습니다.
자신의 의지대로 컴퓨터가 움직여 준다는 것, 그것도 내가 해야할 일을 대신 처리해 준다는 것은 참으로 매력적인 것 같습니다. 그 맛에 프로그래머들이 머리카락을 뜯어가며 프로그래램을 짜는 것인지도 모르 지요.
아무리 스타크도 좋고, 디아블로로 좋지만 뭔가 생산적인 일을 하고난 후의 그 기쁨에는 비할바가 못 될 것입니다. 게임 이야기가 나와서 하는 얘긴데 어찌된 것이 나라가 온통 게임에 미쳐(?) 있는 것 같습니다. 某 케이블 TV에서는 스타크래프트, 피파 2000 거기다 최근에는 디아블로2 등의 게임대회를 밤새 중계를 하더군요. 했던거 또하고, 했던 말 또하고 하면서…
시상금 걸어 놓고 VB나 VC 또는 그밖의 랭귀지로 프로그래밍 하는 것을 TV로 실시간 중계를 한다면 머리 팍팍 돌아가는 많은 젊은이들이 여기에 몰두할텐데… 하는 허황된(?) 생각을 잠시 해 보았습니다. ^^
VBA는 게임류와는 분명히 다른 묘한 중독이 있는 것 같습니다. 열심히들 하시기 바랍니다.
오늘은 여기까지…
정리 — 항목 및 시트 이동 핵심
| 구분 | 사용한 코드 | 역할 |
|---|---|---|
| 목록 채우기 | .AddItem sht.Name | 시트 이름 나열 |
| 위로 이동 | .List(intNum - 1) = .List(intNum) | 항목 교환 |
| 시트 이동 | Sheets(...).Move before:=... | 시트 위치 연동 |
| 선택 유지 | .ListIndex = .ListIndex - 1 | 이동한 항목 선택 |
| 시트로 이동 | Application.Goto Sheets(intNum).Range("a1") | 선택한 시트 이동 |
자주 묻는 질문 (FAQ)
Q1. 항목을 서로 바꿀 때 왜 임시 변수가 필요한가요?
한 값을 덮어쓰기 전에 원래 값을 보관해 두어야 두 값을 서로 바꿀 수 있기 때문입니다.
Q2. ListBox 항목과 시트 위치는 어떻게 연동되나요?
항목을 교환한 직후, 같은 두 이름의 시트를 Move 메서드로 이동시켜 순서를 맞춥니다.
Q3. RowSource를 빈 문자열로 지정하는 이유는 무엇인가요?
초기 원본 영역을 비운 뒤 AddItem으로 항목을 직접 추가하기 위해서입니다.
마치며
한 번 이해한 개념도 반복해서 접하다 보면 어느 순간 무릎을 치는 날이 반드시 옵니다.