Excel VBA에서 Select를 사용하지 않는 방법


537

.SelectExcel VBA에서 이해할 수있는 오해에 대해 많이 들었지만 사용 하지 않는 방법에 대해서는 확실하지 않습니다. Select함수 대신 변수를 사용할 수 있으면 코드를 더 재사용 할 수 있다는 것을 알게되었습니다 . 그러나를 사용하지 않으면 (예 : ActiveCell등) 물건을 참조하는 방법을 잘 모르겠습니다 Select.

내가 발견 한 범위에서이 문서선택 사용하지 않는 이점에이 예제 하지만 아무것도 찾을 수 없습니다 어떻게 ?


14
Select및 / 또는 ActiveSheet기타를 사용할 때 불가피한 경우가 있다는 점에 유의해야합니다 . 내가 찾은 예는 다음과 같습니다. stackoverflow.com/questions/22796286/…
Rick은 Monica를 지원합니다

9
그리고 기본 엑셀 파일이 하나 인 ppt에서 차트 데이터를 편집하는 경우가 있습니다-활성화 또는 선택이 필요한 경우.
brettdj

@brettdj- 여기에 최근 예제가 있습니다. 통합 문서의 모든 시트를 동일한 값으로 설정하려면 .Select / .Selection필요합니다.
BruceWayne

3
같은 QA에서 @bruce은 그렇지 않은 것 같다
크리스 neilsen

답변:


565

선택을 피하는 방법의 몇 가지 예

사용 Dim'D 변수

Dim rng as Range

Set변수를 필요한 범위로 단일 셀 범위를 참조하는 방법에는 여러 가지가 있습니다

Set rng = Range("A1")
Set rng = Cells(1,1)
Set rng = Range("NamedRange")

또는 다중 셀 범위

Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1,1), Cells(10,2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10,2)

당신은 할 수 있습니다 받는 바로 가기를 사용하는 Evaluate방법,하지만이 덜 효율적이며 일반적으로 생산 코드에 피해야한다.

Set rng = [A1]
Set rng = [A1:B10]

위의 모든 예는 활성 시트의 셀을 나타 냅니다. 활성 시트로만 작업하고 싶지 않다면 Worksheet변수 를 흐리게 처리하는 것이 좋습니다

Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1,1)
With ws
    Set rng = .Range(.Cells(1,1), .Cells(2,10))
End With

당신이 경우 않는 작업하려는 ActiveSheet, 명확하게 그것을 명시하는 것이 가장 좋습니다. 그러나 일부 Worksheet방법은 활성 시트를 변경하므로 주의 하십시오.

Set rng = ActiveSheet.Range("A1")

다시 이것은 활성 통합 문서를 나타냅니다 . ActiveWorkbook또는 로만 작업하고 싶지 않으면 변수 ThisWorkbook를 흐리게 처리하는 것이 좋습니다 Workbook.

Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")

당신이 경우 않는 작업하려는 ActiveWorkbook, 명확하게 그것을 명시하는 것이 가장 좋습니다. 그러나 많은 WorkBook방법이 활성화 된 책을 변경하므로 주의 하십시오.

Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")

ThisWorkbook객체를 사용 하여 실행 코드가 포함 된 책을 참조 할 수도 있습니다 .

Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")

일반적인 (나쁜) 코드는 책을 열고 데이터를 얻은 다음 다시 닫는 것입니다.

이것은 나쁘다 :

Sub foo()
    Dim v as Variant
    Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
    Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = ActiveWorkbook.Sheets(1).Range("A1").Value
    Workbooks("SomeAlreadyOpenBook.xlsx").Activate
    ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
    Workbooks(2).Activate
    ActiveWorkbook.Close()
End Sub

그리고 더 좋을 것입니다 :

Sub foo()
    Dim v as Variant
    Dim wb1 as Workbook
    Dim  wb2 as Workbook
    Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
    Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = wb2.Sheets("SomeSheet").Range("A1").Value
    wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
    wb2.Close()
End Sub

범위 변수로 범위를 SubS 및 FunctionS에 전달하십시오.

Sub ClearRange(r as Range)
    r.ClearContents
    '....
End Sub

Sub MyMacro()
    Dim rng as Range
    Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
    ClearRange rng
End Sub

또한 메소드 (예 : FindCopy)를 변수에 적용해야 합니다.

Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2

셀 범위를 반복하는 경우 범위 값을 변형 배열에 먼저 복사하고 반복하는 것이 좋습니다 (빠른).

Dim dat As Variant
Dim rng As Range
Dim i As Long

Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value  ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
    dat(i,1) = dat(i,1) * 10 'or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet

이것은 가능한 것에 대한 작은 맛보기입니다.


7
이 훌륭한 답변에 범위 재기 위해 왼쪽 상단 을 알고있는 한 실제 크기를 알 필요가 없습니다 ... 예를 들어 rng1(12, 12)rng1이 설정되어 있어도 작동 [A1:A10]합니다.
MikeD

3
@chrisneilsen 크리스, 당신은 또한 입력에서 당신을 저장 속기의 셀 참조 표기하기 전에 워크 시트 접두사를 사용할 수 있다고 생각 Range과 같은 : ActiveSheet.[a1:a4]ws.[b6].
로건 리드

3
@AndrewWillems ... 또는 이 게시물에서 48 번이지만 누가 계산하고 있습니까? ☺ ...하지만 심각하게도 객체를 보유하는 변수로 작업 할 때 잊어 버리기 쉽습니다. variant변수는 필요하지 않습니다 Set 때까지 당신이 그것에 객체를 할당합니다. 예를 들어, Dim x: x = 1괜찮지 만 Dim x: x = Sheets("Sheet1")명확히 / 단지 혼동 그러나 오류 438을 생성 Dim x: x = Range("A1")수 없습니다 오류를 생성합니다. 왜? ... 객체 자체에 대한 참조가 아니라 변수에 객체 의 이 할당 되었기 때문에 (와 동일하므로 )Dim x: x = Range("A1").Value
ashleedawg

1
@ user3932000 시트 이름이 자동으로 변경되는 시나리오를 모르겠습니다. 파일 이름의 경우 폴더에 해당 이름의 파일이 이미있는 경우에만 그렇게합니다. 저장 ...을 사용하거나 파일 이름을 하드 코딩하여 문자열로 저장하십시오. 이 문제를 해결할 수없는 경우 의견 대신 별도의 질문을해야합니다.
TylerH

1
@ user3932000 흥미로운 Q를 만들 것입니다. 그것을 처리 할 방법이있을 것입니다 .. 당신은 오래 된 Q에서 주석 스레드를 가로채는 것이 길지 않다는 것을 알기에 충분히 오래되었습니다.
chris neilsen

212

.Select/ .Activate/ Selection/ Activecell/ Activesheet/ Activeworkbook등을 피해야하는 두 가지 주요 이유

  1. 코드 속도가 느려집니다.
  2. 일반적으로 런타임 오류의 주요 원인입니다.

우리는 어떻게 그것을 피합니까?

1) 관련 객체로 직접 작업

이 코드를 고려

Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"

이 코드는 다음과 같이 작성할 수도 있습니다.

With Sheets("Sheet1").Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

2) 필요한 경우 변수를 선언하십시오. 위와 동일한 코드를 작성할 수 있습니다

Dim ws as worksheet

Set ws = Sheets("Sheet1")

With ws.Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

17
좋은 답변이지만이 주제에서 내가 놓친 것은 실제로 Activate가 필요할 때입니다. 모두가 나쁘다고 말하지만 그것을 사용하는 것이 합당한 경우를 설명하는 사람은 없습니다. 예를 들어 2 개의 통합 문서로 작업하고 있었으므로 먼저 통합 문서를 활성화하지 않고 통합 문서 중 하나에서 매크로를 시작할 수 없었습니다. 좀 더 자세히 설명해 주시겠습니까? 또한 예를 들어 한 시트에서 다른 시트로 범위를 복사 할 때 시트를 활성화하지 않으면 프로그램을 실행할 때 어쨌든 각 시트가 암시 적으로 활성화되는 것처럼 보입니다.
user3032689

1
데이터를 붙여 넣거나 필터링 해야하는 경우 때로는 시트를 먼저 활성화해야 할 수도 있습니다. 나는 가능한 한 많은 활성화를 피하는 것이 최선이라고 말하지만 그것을해야 할 경우가 있습니다. 따라서 위의 답변에 따라 계속 활성화하고 선택하십시오.
Nick

7
요점은 사용을 완전히 피하는 것이 아니라 가능한 한 많이하는 것입니다. 통합 문서를 저장하려면 누군가가 열 때 특정 시트의 특정 셀이 선택되면 해당 시트와 셀을 선택해야합니다. 복사 / 붙여 넣기는 나쁜 예입니다. 적어도 값의 경우에는 다음과 같은 코드로 더 빠르게 수행 할 수 있습니다.Sheets(2).[C10:D12].Value = Sheets(1).[A1:B3].Value
robotik

1
@Nick 붙여 넣기 또는 필터링을 위해 시트를 활성화 할 필요는 없습니다. 붙여 넣기 또는 필터 명령에서 시트 개체를 사용하십시오. 연습을 통해 Excel 개체 모델을 배우면 쉬워집니다. .Activate를 사용하는 유일한 시간은 새 시트를 만들 때이지만 코드가 완료되면 원본 시트가 나타나기를 원합니다.
phrebh

3
@phrebh .Activate원본 시트로 이동하는 데 사용할 필요는 없습니다.Application.Goto
GMalc

88

위에서 언급 한 모든 훌륭한 답변에 한 가지 작은 강조점을 추가하겠습니다.

아마도 Select 사용을 피하기 위해 할 수있는 가장 큰 일은 VBA 코드에서 가능한 한 의미있는 변수 이름과 결합 된 명명 된 범위를 사용하는 것 입니다. 이 점은 위에서 언급했지만 조금씩 빛났다. 그러나 특별한주의가 필요합니다.

더 많은 것을 생각할 수는 있지만 명명 된 범위를 자유롭게 사용하는 몇 가지 추가 이유가 있습니다.

명명 된 범위를 사용하면 코드를보다 쉽게 ​​읽고 이해할 수 있습니다.

예:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")
'e.g, "Months" might be a named range referring to A1:A12

Set MonthlySales = Range("MonthlySales")
'e.g, "Monthly Sales" might be a named range referring to B1:B12

Dim Month As Range
For Each Month in Months
    Debug.Print MonthlySales(Month.Row)
Next Month

명명 된 범위 MonthsMonthlySales포함 된 내용 및 절차를 수행하는 것은 매우 분명합니다 .

이것이 왜 중요한가? 그것은 쉽게 부분적으로 있기 때문에 다른 사람들이 그것을 이해하지만하기 위해 혹시 보거나 때문에, 당신은 여전히 명명 된 범위와 좋은 변수 이름을 사용해야 코드를 사용하는 유일한 사람 경우에도 당신이 잊고 당신이 그것으로 할 무엇을 의미하는지 년 후, 그리고 당신은 낭비 당신의 코드가 무엇을하고 있는지 알아내는 30 분.

명명 된 범위는 스프레드 시트의 구성이 변경 될 때 매크로가 깨지지 않도록합니다.

위의 예제가 다음과 같이 작성된 경우를 고려하십시오.

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:A12")
Set rng2 = Range("B1:B12")

Dim rng3 As Range
For Each rng3 in rng1 
    Debug.Print rng2(rng3.Row)
Next rng3

이 코드는 처음에는 잘 작동합니다. 즉, 귀하 또는 미래의 사용자가 "gee wiz, 결정할 때까지 열에 새 열을 추가 할 것입니다 A!"또는 몇 개월과 판매 열을 추가하거나 각 열에 헤더를 추가하십시오. 이제 코드가 깨졌습니다. 그리고 끔찍한 변수 이름을 사용했기 때문에 필요한 것보다 수정하는 방법을 알아내는 데 더 많은 시간이 걸립니다.

명명 된 범위를 사용하여 시작한 경우 MonthsSales열을 원하는대로 이동할 수 있으며 코드는 계속 정상적으로 작동합니다.


6
명명 된 범위가 스프레드 시트 디자인의 우수성인지 나쁜지에 대한 논쟁은 계속되고 있습니다. 내 경험상 오류가 증가합니다 (코드가 필요없는 표준 사용자의 경우).
brettdj


12
나는 당신의 개발 철학에 동의합니다; 그러나 나는 종이가 말도 안된다고 생각한다. 범위 이름으로 스프레드 시트를 디버깅하는 초보자를 혼동 할 수있는 방법에 대해 설명하지만 초보자를 사용하여 복잡한 스프레드 시트를 보는 사람은 누구나 가치가 있습니다! 나는 재무 스프레드 시트를 검토 한 회사에서 일 했었고, 그것이 당신이 초보자에게주는 일이 아니라고 말할 수 있습니다.
DeanOC

8
의미있는 토론은 없습니다. 정의 된 이름에 반대하는 사람은 자신의 결과를 완전히 이해하는 데 시간이 걸리지 않았습니다. 명명 된 수식은 모든 Excel에서 가장 심오하고 유용한 단일 구문 일 수 있습니다.
Excel Hero

10
@brettdj : 당신의 인용은 정확하지만, 그 뒤에 6 개의 "제외 ..."문구 가 있다는 것을 잊어 버렸습니다 . " 매크로 코딩에서 셀 참조의 대체물로 제외 매크로를 생성 할 때 항상 셀 참조의 대체물로 Excel 이름을 사용하십시오. 이는 매크로 코딩이 더 이상 발생하지 않는 추가 행 또는 열 삽입으로 인해 발생하는 오류를 피하기위한 것입니다. 원하는 소스 데이터를 가리 킵니다. "
Marcus Mangelsdorf

47

나는 다른 사람들이 모두 긴 것을 주었으므로 짧은 대답을 할 것입니다.

매크로를 기록하고 재사용 할 때마다 .select 및 .activate가 표시됩니다. 셀이나 시트를 선택하면 활성화됩니다. 그 시점부터는 Range.Value활성 셀과 시트를 사용하는 것처럼 규정되지 않은 참조를 사용할 때마다 . 코드의 위치를 ​​보지 않거나 사용자가 통합 문서를 클릭하는 경우에도 문제가 될 수 있습니다.

따라서 셀을 직접 참조하여 이러한 문제를 제거 할 수 있습니다. 간다 :

'create and set a range
Dim Rng As Excel.Range
Set Rng = Workbooks("Book1").Worksheets("Sheet1").Range("A1")
'OR
Set Rng = Workbooks(1).Worksheets(1).Cells(1, 1)

아니면 당신은 할 수

'Just deal with the cell directly rather than creating a range
'I want to put the string "Hello" in Range A1 of sheet 1
Workbooks("Book1").Worksheets("Sheet1").Range("A1").value = "Hello"
'OR
Workbooks(1).Worksheets(1).Cells(1, 1).value = "Hello"

이러한 방법에는 여러 가지 조합이 있지만 나 같은 초조 한 사람들에게는 가능한 한 빨리 표현되는 일반적인 아이디어가 될 것입니다.


33

"... Select 함수 대신 변수를 사용할 수 있으면 코드를 더 재사용 할 수 있다는 것을 알게되었습니다."

.Select직접 셀 참조보다 더 나은 선택이 될 수있는 격리 된 소수의 상황 이상을 생각할 수는 없지만 , 방어 해야 할 Selection이유는 .Select피해야 할 이유와 같은 이유로 버려서는 안된다는 점입니다.

단축 키 조합에 할당 된 짧고 시간을 절약하는 매크로 서브 루틴을 두 키를 탭하면 많은 시간을 절약 할 수 있습니다. 워크 시트 전체의 데이터 형식을 준수하지 않는 포켓 데이터를 처리 할 때 작업 코드에서 작동하도록 셀 그룹을 선택할 수 있다는 것은 놀라운 일입니다. 셀 그룹을 선택하고 서식 변경을 적용 할 수있는 것과 같은 방식으로 셀 그룹을 선택하여 특수 매크로 코드를 실행하면 시간을 크게 절약 할 수 있습니다.

선택 기반 하위 프레임 워크의 예 :

Public Sub Run_on_Selected()
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Selected_Visible()
    'this is better for selected ranges on filtered data or containing hidden rows/columns
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL.SpecialCells(xlCellTypeVisible)
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Discontiguous_Area()
    'this is better for selected ranges of discontiguous areas
    Dim ara As Range, rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each ara In rSEL.Areas
        Debug.Print ara.Address(0, 0)
        'cell group operational code here
        For Each rng In ara.Areas
            Debug.Print rng.Address(0, 0)
            'cell-by-cell operational code here
        Next rng
    Next ara
    Set rSEL = Nothing
End Sub

처리 할 실제 코드는 한 줄에서 여러 모듈에 이르기까지 모든 것이 될 수 있습니다. 이 방법을 사용하여 외부 통합 문서의 파일 이름을 포함하는 거친 셀 선택에서 장기 실행 루틴을 시작했습니다.

간단히 말해서 and와 Selection밀접한 관련이 있기 때문에 버리지 마십시오 . 워크 시트 속성으로서 다른 많은 목적이 있습니다..SelectActiveCell

(예, 나는이 질문에 관한 .Select것이 Selection아니라 VBA 코더가 추측 할 수있는 오해를 제거하고 싶었습니다.)


13
Selection는 워크 시트에 무엇이든 될 수 있으므로 명시 적으로로 선언 했으므로 객체에 변수를 할당하기 전에 먼저 객체 유형을 테스트해야합니다 Range.
L42

29

다음에서는 Select 접근법 (OP가 피하고 싶은 접근법)과 Range 접근법을 비교하고 있습니다 (이것은 질문에 대한 답변입니다). 따라서 첫 번째 선택이 표시 될 때 읽기를 중단하지 마십시오.

실제로 당신이하려는 일에 달려 있습니다. 어쨌든 간단한 예가 유용 할 수 있습니다. 활성 셀의 값을 "foo"로 설정한다고 가정 해 봅시다. ActiveCell을 사용하면 다음과 같이 작성할 수 있습니다.

Sub Macro1()
    ActiveCell.Value = "foo"
End Sub

활성 셀이 아닌 셀 (예 : "B2")에이 셀을 사용하려면 먼저 다음과 같이 선택해야합니다.

Sub Macro2()
    Range("B2").Select
    Macro1
End Sub

범위를 사용하면 원하는 셀의 값을 원하는대로 설정하는 데 사용할 수있는보다 일반적인 매크로를 작성할 수 있습니다.

Sub SetValue(cellAddress As String, aVal As Variant)
    Range(cellAddress).Value = aVal
End Sub

그런 다음 Macro2를 다음과 같이 다시 작성할 수 있습니다.

Sub Macro2()
    SetCellValue "B2", "foo"
End Sub

그리고 Macro1은 다음과 같습니다.

Sub Macro1()
    SetValue ActiveCell.Address, "foo"
End Sub

이것이 조금 정리하는 데 도움이되기를 바랍니다.


1
매우 빠른 답변을 주셔서 감사합니다. 즉, 일반적으로 범위에 셀을 추가하고 범위의 이름을 지정하고 반복하면 배열 생성으로 바로 넘어 가야합니까?
BiGXERO

무슨 뜻인지 잘 모르겠지만, 단일 명령어 (예 : Range ( "B5 : C14"))로 범위를 만들 수 있으며 한 번에 값을 설정할 수도 있습니다 ( 범위 내의 모든 셀), 예 : Range ( "B5 : C14"). 값 = "abc"
Francesco Baruchelli

29

회피 Select하고 Activate당신을 조금 더 나은 VBA 개발자로 만드는 움직임입니다. 일반적으로, Select그리고 Activate매크로 기록 할 때, 따라서, 사용되는 Parent시트 또는 범위가 항상 활성 상태로 간주된다.

이것은 당신이 피할 수있는 방법입니다 SelectActivate다음과 같은 경우 :


새 워크 시트 추가 및 셀 복사 :

From (매크로 레코더로 생성 된 코드) :

Sub Makro2()
    Range("B2").Select
    Sheets.Add After:=ActiveSheet
    Sheets("Tabelle1").Select
    Sheets("Tabelle1").Name = "NewName"
    ActiveCell.FormulaR1C1 = "12"
    Range("B2").Select
    Selection.Copy
    Range("B3").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
End Sub

에:

Sub TestMe()
    Dim ws As Worksheet
    Set ws = Worksheets.Add
    With ws
        .Name = "NewName"
        .Range("B2") = 12
        .Range("B2").Copy Destination:=.Range("B3")
    End With
End Sub

워크 시트간에 범위를 복사하려는 경우 :

에서:

Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste

에:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")

멋진 명명 된 범위 사용

당신은 그들에 액세스 할 수있는 []다른 방법에 비해, 정말 아름다운이다. 자신을 확인하십시오 :

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")    
Set MonthlySales = Range("MonthlySales")

Set Months =[Months]
Set MonthlySales = [MonthlySales]

위의 예는 다음과 같습니다.

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]

값을 복사하지 않고 가져옵니다.

일반적으로 의향이 있다면 select무엇인가를 복사하고있는 것입니다. 값에만 관심이있는 경우 선택을 피하는 것이 좋습니다.

Range("B1:B6").Value = Range("A1:A6").Value


항상 워크 시트를 참조하십시오

이것은 아마도 가장 흔한 실수 일 것입니다 . 범위를 복사 할 때마다 때때로 워크 시트가 참조되지 않으므로 VBA는 잘못된 시트를 ActiveWorksheet로 간주합니다.

'This will work only if the 2. Worksheet is selected!
Public Sub TestMe()
    Dim rng As Range
    Set rng = Worksheets(2).Range(Cells(1, 1), Cells(2, 2)).Copy
End Sub

'This works always!
Public Sub TestMe2()
    Dim rng As Range
    With Worksheets(2)
        .Range(.Cells(1, 1), .Cells(2, 2)).Copy
    End With
End Sub

나는 절대로 .Select또는 .Activate아무것도 사용하지 않을 수 있습니까 ?

  • 사용을 정당화 할 수있는 시기 .Activate.Select시각적 이유로 특정 워크 시트를 선택해야하는 경우를 보여주는 좋은 예입니다 . 예를 들어, 파일을 닫을 때 어떤 ActiveSheet를 무시했는지에 관계없이 Excel에서 항상 표지 워크 시트를 먼저 선택한 상태로 Excel을 열어야합니다.

따라서 아래 코드와 같은 것이 좋습니다.

Private Sub Workbook_Open()
    Worksheets("Cover").Activate
End Sub

Worksheets.Activate 대신 Application.Goto를 사용할 수 있습니다. 다소 덜 위험합니다.
Geoff Griswald

1
늦은 답변 FYI-필요에 대한 훌륭하고 다소 예상치 못한 예 .Select-내 작업뿐만 아니라 모든 시트에 동일한 정보를 쓰는 방법 -@Vityata :)
TM

1
@ TM-실제로 흥미로운 예이며 아마도 100 + 워크 시트에 몇 밀리 초를 절약 할 수는 있지만 어딘가에 보면 실망하지 않을 것입니다. 어쨌든, 선택은 명시 적으로 쓰여지지 않았지만의 결과이므로 .FillAcrossSheets, 이것은 (적어도 VBA 분류법에 대한 내 생각에는) 사이에 있습니다
Vityata

17

통합 문서, 워크 시트 및 셀 / 범위를 항상 명시하십시오.

예를 들면 다음과 같습니다.

Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)

최종 사용자는 항상 버튼을 클릭하기 때문에 포커스가 통합 문서에서 벗어나 자마자 코드가 작동하기를 원하면 완전히 잘못됩니다.

통합 문서의 색인을 사용하지 마십시오.

Workbooks(1).Worksheets("fred").cells(1,1)

사용자가 코드를 실행할 때 다른 통합 문서가 열려 있는지 알 수 없습니다.


7
워크 시트의 이름도 변경 될 수 있습니다. 대신 코드 이름을 사용하십시오.
Rick은 Monica

워크 시트 이름은 변경 될 수 있습니다. 그러나 코드를 지나치게 복잡하게 만들어 코드를 완화해야한다고 동의하지 않습니다. 사용자가 시트 이름을 변경하고 매크로 작동이 중지되면 그 위에 있습니다. 나는 일반적으로 워크 시트 이름이 동일하다고 가정합니다. 특히 중요한 매크로의 경우, 매크로를 제대로 실행하기 전에 비행 전 검사를 약간 실행하여 찾을 것으로 예상되는 모든 시트가 실제로 있는지 확인하고 누락 된 시트가 있으면 사용자에게 알립니다.
Geoff Griswald

10

이 방법들은 다소 비난을 받으므로 모래에 선을 그리는 것을 위해 @Vityata와 @Jeeped의 선두를 차지합니다.

전화하지 왜 .Activate, .Select, Selection, ActiveSomething방법 / 특성

기본적으로 응용 프로그램 UI를 통해 사용자 입력을 처리하기 위해 주로 호출되기 때문입니다. 사용자가 UI를 통해 객체를 처리 할 때 호출되는 메소드이기 때문에 매크로 레코더에 의해 기록 된 메소드이기 때문에 대부분의 상황에서 객체를 호출하는 것은 취하기 어렵거나 중복되는 이유입니다. Selection바로 다음에 조치를 수행 할 수 있습니다 .

그러나이 정의는 다음과 같은 상황을 해결합니다.

호출 할 때 .Activate, .Select, .Selection, .ActiveSomething방법 / 특성

기본적으로 최종 사용자 가 실행에서 역할을 수행 할 것으로 예상되는 경우 .

개발 중이고 사용자가 코드에서 처리 할 객체 인스턴스를 선택 해야하는 경우 .Selection또는 .ActiveObject적절합니다.

반면에, .Select그리고 .Activate당신이 사용자의 다음 행동을 추론 할 때 사용의 그리고 당신은 아마도 그에게 시간과 마우스 클릭을 저장, 코드가 사용자를 안내합니다. 예를 들어, 코드에서 방금 차트의 새 인스턴스를 만들거나 업데이트 한 경우 사용자는 해당 차트를 확인 .Activate하고 시트 또는 시트를 호출 하여 사용자가 검색하는 시간을 절약 할 수 있습니다. 또는 사용자가 일부 범위 값을 업데이트해야한다는 것을 알고 있으면 프로그래밍 방식으로 해당 범위를 선택할 수 있습니다.


6

의 IMHO 사용은 .select나 같은 매크로를 기록하고 실현하지 않고 코드를 수정을 통해 필요에 의해 VBA를 배우기 시작 명에서 유래 .select이후는 selection단지 불필요한 중간 남자입니다.

.select 이미 게시 된 많은 사람들이 이미 존재하는 객체로 직접 작업하여 피할 수 있습니다. 이는 복잡한 방법으로 i 및 j를 계산 한 다음 셀 (i, j)을 편집하는 등 다양한 간접 참조를 허용합니다.

그렇지 않으면, .select그 자체로 내재적으로 잘못이 없으며 쉽게 사용할 수 있습니다. 예를 들어 날짜가 채워진 스프레드 시트가 있고, 마법을 사용하는 매크로를 활성화하고 별도의 시트에서 허용되는 형식으로 내보내는 매크로 그러나 인접 셀에 대한 최종 수동 (예측 불가능) 입력이 필요합니다. 그래서 여기에 .select추가적인 마우스 움직임과 클릭이 절약됩니다.


2
당신이 옳은 동안 select에는 암묵적으로 잘못된 것이 적어도 하나 있습니다. 느립니다. 매크로에서 발생하는 다른 모든 것에 비해 매우 느립니다.
vacip

4

빠른 답변 :

.Select방법을 사용하지 않으 려면 원하는 속성과 동일한 변수를 설정할 수 있습니다.

► 예를 들어 값을 원하는 경우 Cell A1해당 셀의 값 속성과 같은 변수를 설정할 수 있습니다.

  • valOne = Range("A1").Value

► 예를 들어, 코드 이름 'Sheet3'을 원하는 경우 해당 워크 시트의 codename 속성과 같은 변수를 설정할 수 있습니다.

  • valTwo = Sheets("Sheet3").Codename

도움이 되길 바랍니다. 궁금한 점이 있으면 알려주세요.


3

이 답변 중 어느 것도 .Offset 속성에 대해 언급하지 않았습니다 . 이것은 또한 Select특정 셀을 조작 할 때, 특히 선택된 셀을 참조하여 (OP가 언급 한 바와 같이) 동작을 사용하지 않도록하는 데 사용될 수 있습니다 ActiveCell.

다음은 몇 가지 예입니다.

또한 "ActiveCell"이 J4 라고 가정합니다 .

ActiveCell.Offset(2, 0).Value = 12

  • 이것은 셀 J6을 12의 값으로 변경합니다
  • 빼기 -2는 J2를 참조했을 것입니다

ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)

  • 셀이에 복사 k4됩니다 L4.
  • 필요하지 않은 경우 오프셋 매개 변수에 "0"이 필요하지 않습니다 (, 2).
  • 이전 예제와 유사하게 빼기 1은 i4

ActiveCell.Offset(, -1).EntireColumn.ClearContents

  • 그러면 k 열의 모든 셀에서 값이 지워집니다.

이것들은 위의 옵션보다 "더 나은"것이 아니라 대안을 나열하는 것입니다.


0

부모 기능 사용 이 예제는 하나의 myRng 참조 만 설정하여 .Select, .Activate, .Activecell, .ActiveWorkbook, .ActiveSheet 등없이 전체 환경에 동적으로 액세스하는 방법을 보여줍니다. (일반적인 자식 기능은 없습니다)

Sub ShowParents()
    Dim myRng As Range
    Set myRng = ActiveCell
    Debug.Print myRng.Address                    ' an address of the selected cell
    Debug.Print myRng.Parent.name                ' the name of sheet, where MyRng is in
    Debug.Print myRng.Parent.Parent.name         ' the name of workbook, where MyRng is in
    Debug.Print myRng.Parent.Parent.Parent.name  ' the name of application, where MyRng is in

    ' You may use this feature to set reference to these objects
    Dim mySh    As Worksheet
    Dim myWbk   As Workbook
    Dim myApp   As Application

    Set mySh = myRng.Parent
    Set myWbk = myRng.Parent.Parent
    Set myApp = myRng.Parent.Parent.Parent
    Debug.Print mySh.name, mySh.Cells(10, 1).Value
    Debug.Print myWbk.name, myWbk.Sheets.Count
    Debug.Print myApp.name, myApp.Workbooks.Count

    ' You may use dynamically addressing
    With myRng
        .Copy

       ' pastes in D1 on sheet 2 in the same workbook, where copied cell is
        .Parent.Parent.Sheets(2).Range("D1").PasteSpecial xlValues
    ' or myWbk.Sheets(2).Range("D1").PasteSpecial xlValues

       ' we may dynamically call active application too
        .Parent.Parent.Parent.CutCopyMode = False
    ' or myApp.CutCopyMode = False
    End With
End Sub

매우 훌륭하지만 이것이 OP 질문과 관련이 있는지 확실하지 않습니다. Select 또는 ActiveSheet를 사용하지 않고 VBA에서 작업하기 위해 "부모"가 전혀 필요하지 않습니다
Geoff Griswald

0

Select 또는 Activesheet를 사용하지 않는 주된 이유는 대부분의 사람들이 매크로를 실행할 때 적어도 몇 개의 통합 문서가 열리거나 (수십 개) 매크로가 실행되는 동안 시트에서 멀어지고 다른 클릭이 있기 때문입니다. 책을 연 다음 "Activesheet"가 변경되고 규정되지 않은 "Select"명령의 대상 통합 문서도 변경됩니다.

기껏해야 매크로가 충돌하고 최악의 경우 값을 "실행 취소"하지 않고 잘못된 통합 문서에서 값을 쓰거나 셀을 변경할 수 있습니다.

다음과 같은 간단한 황금 규칙이 있습니다. 통합 문서 개체 및 워크 시트 개체에 "wb"및 "ws"라는 변수를 추가하고 항상이 변수를 사용하여 내 매크로 북을 참조하십시오. 둘 이상의 책 또는 둘 이상의 시트를 참조해야하는 경우 변수를 더 추가합니다.

예를 들어

Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")

"Set wb = ThisWorkbook"명령은 절대적으로 중요합니다. "ThisWorkbook"은 Excel에서 특별한 값이며 VBA 코드가 현재 실행중인 통합 문서를 의미합니다 . 통합 문서 변수를 설정하는 데 유용한 바로 가기입니다.

Sub 상단에서 작업을 완료 한 후에는 더 간단하게 사용할 수 없습니다. "Selection"을 사용할 때마다 사용하십시오.

따라서 "출력"의 "A1"셀 값을 "Hello"로 변경하려면 다음을 수행하십시오.

Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"

우리는 이제 이것을 할 수 있습니다 :

ws.Range("A1").Value = "Hello"

사용자가 여러 스프레드 시트로 작업하는 경우 훨씬 더 안정적 일뿐 아니라 충돌이 적을뿐만 아니라 훨씬 짧고 빠르며 쓰기도 쉽습니다.

추가로, 항상 변수 이름을 "wb"와 "ws"로 지정하면 한 책에서 다른 책으로 코드를 복사하여 붙여 넣을 수 있으며 필요한 경우 최소한의 변경만으로도 작동합니다.


1
내 downvote는 아니지만 기존 답변에서 이미 제안 된 내용에 새로운 내용이 추가되는지 확실하지 않습니다.
BigBen

예, 내 대답은 약간 중복되어 있지만 다른 대답은 너무 길고 불필요한 내용이 너무 많으며 아무도이 Workbook을 사용하여 워크 시트 변수를 미리 설정하지 않았다고 언급하지 않았습니다. VBA에 처음으로 발가락을 떨어 뜨렸을 때 누군가 내게 보여준 경우, 매우 도움이 될 것입니다. 다른 사람들은 워크 시트 변수 사용에 대해 언급했지만 실제로 그 이유를 잘 설명하지 않으며 워크 시트 및 통합 문서 변수를 사용하거나 사용하지 않는 코드 예제를 제공하지 않습니다.
Geoff Griswald

그러나 받아 들여진 대답은 분명히 토론합니다 ThisWorkbook... 나는 당신의 의견이 정확한지 확실하지 않습니다.
BigBen

그렇습니다, 당신은 틀리지 않습니다. 그러나 통합 문서 변수를 설정하고 앞으로 통합 문서 변수를 사용하거나 워크 북 변수를 사용하여 워크 시트 변수를 설정하는 것과 관련하여 제안하지는 않습니다. 제 답변은 초보자가 수용 한 답변보다 더 짧고 간단하며 더 접근하기 쉽습니다.
Geoff Griswald

-3

셀 "A1"의 내용을 지우는 예제입니다 (선택 유형이 xllastcell 등인 경우 이상). 셀을 선택할 필요없이 모두 완료되었습니다.

Application.GoTo Reference:=Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1")
Range(Selection,selection(selectiontype)).clearcontents 

나는 이것이 누군가를 돕기를 바랍니다.


1
아니요, 죄송합니다. 그것은 당신이 전혀 한 일이 아닙니다. 실제로 한 것은 "Application.GoTo"명령을 사용하여 "A1"셀을 선택하는 것입니다.이 명령은 "Select"를 실제로 사용하는 것과 다르지 않으며 선택한 내용에 clearcontents를 사용합니다. 셀을 선택하지 않고 그렇게하는 방법 Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1").ClearContents은 두 줄이 아닌 한 줄이며 실제로 셀을 선택하지 않고 작동합니다.
Geoff Griswald
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.