Поиск…


Квалификационные ссылки

При обращении к worksheet , range или отдельным cells важно полностью квалифицировать ссылку.

Например:

ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy

Не является полностью квалифицированным: ссылки на Cells не имеют рабочей книги и рабочего листа, связанных с ними. Без явной ссылки Cells ссылается на ActiveSheet по умолчанию. Таким образом, этот код не сработает ( ActiveSheet неверные результаты), если ActiveSheet отличным от Sheet1 является текущий ActiveSheet .

Самый простой способ исправить это использовать With утверждением следующим образом :

With ThisWorkbook.Worksheets("Sheet1")
    .Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With

Кроме того, вы можете использовать переменную Worksheet. (Это, скорее всего, будет предпочтительным, если ваш код должен ссылаться на несколько рабочих листов, например, копирование данных с одного листа на другой.)

Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy

Другая частая проблема заключается в ссылке на коллекцию Рабочих таблиц без квалификации рабочей книги. Например:

Worksheets("Sheet1").Copy

Sheet1 не имеет полной квалификации и отсутствует рабочая тетрадь. Это может завершиться неудачей, если в коде ссылаются несколько книг. Вместо этого используйте одно из следующих действий:

ThisWorkbook.Worksheets("Sheet1")       '<--ThisWorkbook refers to the workbook containing 
                                        'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1

Однако не используйте следующее:

ActiveWorkbook.Worksheets("Sheet1")     '<--Valid, but if another workbook is activated
                                        'the reference will be changed

Аналогично для объектов range , если они явно не определены, range будет относиться к текущему активному листу:

Range("a1")

Такой же как:

ActiveSheet.Range("a1")

Удаление строк или столбцов в цикле

Если вы хотите удалить строки (или столбцы) в цикле, вы всегда должны начинать цикл с конца диапазона и перемещаться назад на каждом шаге. В случае использования кода:

Dim i As Long
With Workbooks("Book1").Worksheets("Sheet1")
    For i = 1 To 4
        If IsEmpty(.Cells(i, 1)) Then .Rows(i).Delete
    Next i
End With

Вы пропустите несколько строк. Например, если код удаляет строку 3, то строка 4 становится строкой 3. Однако переменная i изменится на 4. Таким образом, в этом случае код пропустит одну строку и проверит другую, которая ранее не была в диапазоне.

Правильный код будет

Dim i As Long
With Workbooks("Book1").Worksheets("Sheet1")
    For i = 4 To 1 Step -1
        If IsEmpty(.Cells(i, 1)) Then .Rows(i).Delete
    Next i
End With

ActiveWorkbook против ThisWorkbook

ActiveWorkbook и ThisWorkbook иногда становятся взаимозаменяемыми новыми пользователями VBA без полного понимания того, к чему относится каждый объект, что может привести к нежелательному поведению во время выполнения. Оба этих объекта относятся к объекту приложения


Объект ActiveWorkbook относится к ActiveWorkbook которая в настоящее время находится в самом верхнем виде объекта приложения Excel во время выполнения. (например, книгу, которую вы можете видеть и взаимодействовать в момент, когда этот объект ссылается)

Sub ActiveWorkbookExample()

'// Let's assume that 'Other Workbook.xlsx' has "Bar" written in A1.

    ActiveWorkbook.ActiveSheet.Range("A1").Value = "Foo"
    Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Foo"

    Workbooks.Open("C:\Users\BloggsJ\Other Workbook.xlsx")
    Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Bar"

    Workbooks.Add 1
    Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints nothing

End Sub

Объект ThisWorkbook относится к книге, в которой код принадлежит к моменту его выполнения.

Sub ThisWorkbookExample()

'// Let's assume to begin that this code is in the same workbook that is currently active

    ActiveWorkbook.Sheet1.Range("A1").Value = "Foo"
    Workbooks.Add 1
    ActiveWorkbook.ActiveSheet.Range("A1").Value = "Bar"

    Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Bar"
    Debug.Print ThisWorkbook.Sheet1.Range("A1").Value '// Prints "Foo"

End Sub

Интерфейс с одним документом и несколькими документами

Имейте в виду, что Microsoft Excel 2013 (и выше) использует Single Document Interface (SDI), а Excel 2010 (и ниже) использует Multiple Document Interfaces (MDI).

Это означает, что для Excel 2013 (SDI) каждая рабочая тетрадь в одном экземпляре Excel содержит собственный интерфейс ленты:

введите описание изображения здесь

И наоборот, для Excel 2010 каждая рабочая тетрадь в одном экземпляре Excel использовала общий интерфейс (MDI) с лентой: введите описание изображения здесь

Это вызывает некоторые важные проблемы, если вы хотите перенести код VBA (2010 <-> 2013), который взаимодействует с лентой.

Необходимо создать процедуру обновления ленточных элементов управления пользовательского интерфейса в одном и том же состоянии во всех книгах для Excel 2013 и выше.

Обратите внимание, что :

  1. Все методы, события и свойства окна на уровне приложения Excel остаются неизменными. ( Application.ActiveWindow , Application.Windows ...)
  2. В Excel 2013 и выше (SDI) все окна, методы и свойства окна на рабочем столе теперь работают в окне верхнего уровня. Можно получить дескриптор этого окна верхнего уровня с помощью Application.Hwnd

Чтобы получить более подробную информацию, см. Источник этого примера: MSDN .

Это также вызывает некоторые проблемы с немодальными пользовательскими формами. См. Здесь для решения.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow