Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 семестр / vba_2002

.pdf
Скачиваний:
82
Добавлен:
09.04.2015
Размер:
9.9 Mб
Скачать

Function InRange{rngl, rng2) As Boolean

1Возвращает True, если rngl является подмножеством rng2 InRange = False

If rngl.Parent.Parent.Name = rng2.Parent.Parent.Name Then If rngl.Parent.Name - rng2.Parent.Name Then

If Union(rngl, rng2).Address - rng2.Address Then InRange = True

End If End If

End If End Function

Возможно, функция InRange кажется сложнее, чем того требует С1ггуация, поскольку в коде должна быть реализована проверка принадлежности двух диапазонов одной и той же книге и рабочему листу. Обратите внимание, что в процедуре используется свойство Parent . которое возвращает объект-контейнер заданного объекта. Например, следующее выражение возвращает название листа для объекта r n g l :

rngl.Parent.Name

Представленное далее выражение возвращает имя рабочей книги для объекта rngl : rngl . Parent . Parent . Name

Функция VBA I n t e r s e c t i o n возвращает объект Range, представляющий объединение двух объектов Range. Это объединение содержит общие ячейки двух заданных диапазонов. Если объединение двух диапазонов совпадает со вторым диапазоном, то это означает, что первый диапазон полностью содержится во втором,

Определениетипаданныхячейки

Excel имеет ряд встроенных функций, которые могут помочь определить тип данных, содержащихся в ячейке. Это функции ЕНЕТЕКСТ, ЕЛОГИЧ и ЕОШИБКА. Кроме того, VBA поддерживает функции IsEmpty, IsDate и IsNumeric.

Ниже описана функция CellType. которая принимает аргумент-диапазон и возвращает строку (Пусто, Текст, Булево выражение. Ошибка, Дата, Время и Значение), описывающую тип данных левой верхней ячейки этого диапазона. Такую функцию можно использовать в формуле рабочего листа или вызвать из другой процедуры VBA.

Function CellType(Rng)

'Возвращает тип верхней левой ячейки

'Б диапазоне

Application.Volatile

Set Rng = Rng.Range("Al")

Select Case True

Case IsEmpty{Rng)

CellType = "Пусто"

Case WorksheetFunction.IsText(Rng)

CellType = "Текст"

Case WorksheetFunction.IsLogical(Rng)

CellType - "Булево выражение"

Case WorksheetFunction.IsErr(Rng!

CellType - "Ошибка"

Case IsDate(Rng)

CellType =

"Дата"

 

Case InStrd, Rng.Text, ":") <> 0

 

CellType =

"Время"

 

Case IsNumeric(Rng)

 

Часть III. VisualBasic^rJpplications^

279

CellType = "Значение" End Select

End Function

Обратите внимание на использование оператора S e t Rng. Функция C e l l T y p e получает аргумент-диапазон произвольного размера, но этот оператор указывает, что функция оперирует только левой верхней ячейкой диапазона.

Чтение и записьдиапазонов

Многие задачи, выполняемые в электронных таблицах, связаны с переносом значений из массива в диапазон ячеек, или из диапазона в массив. Следует отметить, что Excel получает данные издиапазонов значительно быстрее, чем записывает их. ПроцедураWriteReadRange, показаннаявлистинге11.3,демонстрируетотносительнуюскоростьзаписиичтениядиапазона.

Эта процедура создает массив и затем использует циклы F o r - N e x t для записи данного массива в диапазон и считывания данных обратно в массив. С помощью функции Timer вычисляетсявремя,необходимоедлякаждойоперации.

Листинг 11.3. Тестирование скорости выполнения операций чтения и записи в диапазоне

Sub WriteReadRange()

Dim MyArray()

Dim Timel As Date

Dim NumElements As Long, i As Long

Dim WriteTime As String, ReadTime As String

Dim Msg As String

NumElements = 60000

ReDinv MyArray (1 To NumElements)

'Заполнение массива

For i = 1 To NumElements

MyArray(i> = i Next i

' Запись массива в диапазон Timel = Timer

For i = 1 To NumElements

Cellsfi, 1) = MyArrayli) Next i

WriteTime = Format(Timer - Timel, "00:00")

1Считывание диапазона в массив Timel = Timer

For i = 1 To NumElements

 

MyArray(i) - Cells(i( 1)

 

Next i

 

 

ReadTime = FormatfTimer

- Timel, "00:00")

1

Отображение результатов

 

 

Msg в "Запись: " & WriteTime

 

Msg = Msg & vbCrLf

 

 

Msg = Msg & "Чтение: "

& ReadTime

 

MsgBox Msg, vbOKOnly, NumElements & " элементов"

End Sub

 

280 Глава 11. Примеры и методы программирования на VBA

В моей системе для записи массива из 60000 элементов в диапазон потребовалось 15 секунд, и только 4 секунды ушло на то, чтобы занести этот диапазон обратно в массив.

Более эффективный способ записи в диапазон

Пример из предыдущего раздела использует для перемещения содержимого массива в диапазон цикл F o r - N e x t . В данном разделе показан более эффективный способ выполнения этой операции.

Начнем с примера в листинге 11.4, в котором продемонстрирован наиболее очевидный (но не самый эффективный) способ заполнения диапазона. В этом примере для вставки значений в диапазон используется цикл F o r - N e x t .

Листинг11.4.Прямолинейноезаполнениедиапазона

Sub LoopFillRange()

1Заполнение диапазона в цикле

Dim CellsDown As Long, CellsAcross As Integer Dim CurrRow As Long, CurrCol As Integer

Dim StartTiine As Date Dim CurrVal As Long

1Получение размеров

CellsDown = Val(InputBoxt"Сколько ячеек в высоту?"}) CellsAcross = Val(InputBoxf"Сколько ячеек в шипину?"))

'Запись момента начала StartTime = Timer

'Просмотр ячеек и вставка значений CurrVal = 1

Application.ScreenUpdating = False

For CurrRow = 1 To CellsDown

For CurrCol = 1 To CellsAcross

ActiveCell.Offset(CurrRow - 1, _

CurrCol - 1).Value = CurrVal

CurrVal = CurrVal + 1

Next CurrCol

Next CurrRow

' Отображение времени выполнения операции Application.ScreenUpdating = True

MsgBox Format(Timer - StartTime, "00.00") & " seconds" End Sub

Пример в листинге 11.5 демонстрирует самый способ получения того же результата. Программа вставляет значения в массив и использует всего один оператор для переноса содержимого массива в диапазон.

Листинг11.5. Быстрый переносмассивавдиапазон

Sub ArrayFillRange()

1Заполнение диапазона путем переноса массива Dim CellsDown As Long, CellsAcross As Integer

Часть III. Visual Basic for Applications

281

 

Dim i As Long,

j As Integer

 

Dim StartTime As Date

 

 

Dim TempArrayf)

As Long

 

Dim TheRange As Range

 

 

Dim CurrVal

As

Long

 

1

Получение размеров

 

 

CellsDown = Val(InputBox("Сколько ячеек s высоту?"))

 

CellsAcross = Val(InputBox("Сколько ячеек в ширину"))

1

Запись момента

начала

 

 

StartTime = Timer

 

1

Изменение размерности временного массива

 

ReDim TempArray(l To

CellsDown, I To CellsAcross)

1

Определение

диапазона

на рабочем листе

 

Set TheRange

-

ActiveCell.Range(Cells(1, 1), _

 

Cells{CellsDown,

CellsAcross)}

1Заполнение временного массива CurrVal = О Application.ScreenUpdating = False For i = 1 To CellsDown

 

For j = 1 To CellsAcross

 

TempArray(i, j) = CurrVal + 1

 

CurrVal = CurrVal 4 1

 

Next j

 

Next i

1

Перенос временного массива на рабочий лист

 

TheRange.Value = TempArray

1

Отображение времени выполнения операции

 

Application.ScreenUpdating - True

 

MsgBox Format(Timer - StartTirre, "00.00") & " секунд"

End Sub

Например, в моей системе на заполнение массива размером 500x256 ячеек (12S000 ячеек) методом никла уходит 202.34 секунды. Метод переноса массива потребовал только 0,77 секунды для получения тех же самых результатов — более чш в 250 раз быстрее! Мораль? Если необходимо переносить большие объемы данных лист Excel, по возможности избегайте циклов.

Перенос одномерных массивов

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

При переносе одномерного массива диапазон должен быть горизонтальным— т.е. это должна быть строка с несколькими столбцами. Если же необходимо использовать вертикальный диапазон, сначала следует транспонировать массив. Для этого используйте функцию Excel ТРАНСП (TRANSPOSE). В следующем примере 100-элементный массив вставляется в вертикальный диапазон на рабочем листе {hi :А100).

Range(А1:А100}.Value = _

Application.WorksheetFunction.Transpose(MyArray)

282

Глава 11. Примеры и методы программирования на VBA

Перенос диапазона в массив Variant

В настоящем разделе рассматривается еще один способ управления данными Excel в VI! А. В примере, показанном ниже, диапазон ячеек переносится в двухмерный массив V a r i a n t . Затем в окнах сообщений отображаются верхние границы для каждой размерности массива V a r i a n t .

Sub RangeToVariantf}

Dim x As Variant

x = Range("Al:L60Q")

MsgBox UBound(x, 1)

MsgBox UBoundfx, 2) End Sub

В данном примере в первом окне сообщения отображается 600 (количество строк в первоначальном массиве), а во втором окне сообщения — 12 (количество столбцов). Вы увидите, что перенос данных диапазона в массив V a r i a n t происходит за долю секунды.

Следующий пример считывает диапазон в массив V a r i a n t , выполняет простую операцию умножения над каждым элементом массива и перемещает массив V a r i a n t обратно в диапазон.

Sub RangeToVariant2(}

Dim UserRange As Range Dim x As Variant

Dim r As Long, с As Integer

Set UserRange = Range("Al:L600")

'Чтение данных

x= Range("Al:L50")

1

Просмотр массива

 

For r = 1 To TJBound{x, 1)

 

For с = 1 To UBound{x, 2)

 

Multiply by 2

 

x(r, c) = x(r, c) * 2

 

Next с

 

Next r

1

Перемещение массива обратно на рабочий лист

 

Range("Al:L50") = х

End

Sub

Данная процедура работает очень быстро.

Выделение максимального значения в диапазоне

Процедура GoToMax в листинге 11.6 переходит к ячейке рабочего листа, содержащей максимальное значение. Процедура определяет максимальное значение в выделенном диапазоне; если выделена одна ячейка, то определяется максимальное значение на всем листе. Для определения адреса необходимой ячейки и ее выделения используется метод Fin.d.

Листинг 11.6. Переход кячейке, содержащей наибольшее значение

Sub GoToMax()

Активизирует ячейку с наибольшим значением

Dim WorkRange as Range

Часть III. VisualBasic forApplications

283

 

Dim MaxVal as Double

 

1

Выход, если диапазон не

выбран

 

If TypeName(Selection) <>

"Range" Then Exit Sub

' Если выбрана одна ячейка, поиск по всему листу;

1в противном случае - поиск в Еыделенном диапазоне If Selection.Count = 1 Then

Set Workrange = Cells

Else

Set Workrange = Selection

End If

1 Определение максимального значения MaxVal = Application.Max(Workrange)

1Поиск и выделение ячейки с марссимальным значением On Error Resume Next

Workrange.Find{what:=MaxVal,

After:=Workrange.Range("Al"), _ Lookln:=xlValues, _ LookAt:=xlPart, _ SearchCrder:=xlByRows, _

SearchDirection:=xlNext, MatchCase:=False _ ).Select

If Err <> 0 Then MsgBox "Максимальное значение не найдено: " _ & MaxVal

End Sub

Возможно, вы заметили, что аргументы метода F i n d совпадают с элементами управления в диалоговом окне Excel Найти и заменить.

Выделение всех ячеек с определенным форматированием

Пример данного раздела демонстрирует использование метода F i n d F o r m a t для поиска и выделения всех ячеек на рабочем листе, которые содержат указанное форматирование. Когда эти ячейки выделены, над ними можно выполнить любую операцию — изменить форматирование, удалить и т.п.

Свойство FindFormat впервые появилось в Excel 2002. Следовательно, данная процедура не будет работать в более ранних версиях Excel.

Процедура SelectByForcnat выглядит следующим образом.

Sub

SelectByFormatU

1

Выделяет ячейки на основе их форматирования

1

Используется Excel 2 002 или выше

 

If Val(Application.Version) < 10 Then

 

MsgBox "Необходима Excel 20 02 или выше."

 

Exit Sub

 

End If

 

Dim FirstCell As Range, FoundCell As Range

 

Dim AllCells As Range

284

Глава 11. Примеры и методы программирования на VBA

' Определение форматирования With Application.FindFormat

.Clear

.Interior.Colorlndex = 6 'желтый

.Font.Bold = True End With

1Поиск первой соответствующей ячейки

Set FirstCell = Cells.Find(What:="", SearchFormat:=True)

1Если ячейка не найдена, выход If FirstCell Is Nothing Then

MsgBox "Ячейки указанного формата не найдены.™

Exit Sub

End If

1Инициализация AllCells Set AllCells = FirstCell Set FoundCell = FirstCell

' Просмотр, пока не будет найдена ячейка FirstCell Do

Set FoundCell = Cells.FindNext(After:=FoundCell} Set AllCells = Union(FoundCell, AllCells)

If FoundCell.Address = FirstCell.Address Then Exit Do

Loop

' Выделение найденных ячеек и сообщение пользователю AllCells . Selec t

MsgBox "Найдено ячеек: " & AllCells.Count End Sub

Процедура начинается с задания свойств объекта FindFormat. В данном примере искомое форматирование определяется двумя компонентами: желтый фон и полужирный шрнфт текста. Конечно, вы можете изменить эти настройки в коде на совсем другие.

Метод Find используется для поиска первой ячейки, соответствующей критерию. Аргумент What метода Find вначале содержит пустую строку, так как поиск определяется форматированием, а не содержимым ячейки. Кроме того, аргумент SearchFormat имеет значение True, поскольку действительно выполняется поиск форматирования, а не значения.

Если указанное форматирование не найдено, пользователь получает сообщение, и программа заканчивает свою работу. В противном случае найденная ячейка присваивается переменной объекта A l l C e l l s (где хранятся все найденные ячейки). Цикл использует метод FindNext для продолжения поиска, который останавливается лишь тогда, когда снова будет найдена первая ячейка. Наконец, все найденные ячейки на рабочем листе выделяются, и пользователь получает сообщение о количестве найденных ячеек.

В представленной процедуре не производится поиск ячеек, получающих форматированиеврезультатеприменениякомандыусловногоформатированияExcel.

Управление рабочими книгами и листами

Приводимые в этом разделе примеры демонстрируют различные способы использования VBА для управления рабочими книгами и листами.

Часть ///. Visual Basic for Applications

285

Примеры настоящего раздела содержатся на Web-узле издательства.

Сохранение всех рабочих книг

Следующая процедура циклически просматривает все рабочие книги в коллекции Workbooks и сохраняет каждый файл, который сохранялся ранее.

Public Sub SaveAllWorkbooks() Dim Book As Workbook

For Each Book In Workbooks

If Book.Path <> "" Then Book.Save Next Book

End Sub

Обратите внимание, как используется свойство P a t h . Если для какой-либо рабочей книги свойство P a t h не задано, то это означает, что файл еще не сохранялся (это новая рабочая книга). Данная процедура игнорирует такие рабочие книги и сохраняет только те из них, у которых свойство P a t h имеет значение.

Сохранение и закрытие всех рабочих книг

Следующая процедура циклически просматривает коллекцию Workbooks. Программа сохраняет и закрывает все рабочие книги.

Sub CloseAllWorkbooksO

Dim Book As Workbook

For Each Book In Workbooks

If Book.Name <> ThisWorkbook.Name Then Book,Close savechanges:=True

End If

Next Book

ThisWorkbook.Close savechanges:= True End Sub

Обратите внимание, что процедура использует оператор if для определения, содержит ли данная рабочая книга текущий код, Это необходимо, так как при закрытии рабочей книги, содержащей процедуру, программа автоматически закончит свое выполнение, и остальные рабочие книги не будут сохранены и закрыты.

Доступ к свойствам рабочей книги

Команда Excel Файл^Свойства отображает диалоговое окно, содержащее информацию об активной рабочей книге. Вы можете обратиться к этим свойствам с помощью VBA. Например, представленная д&чее процедура отображает дату и время последнего сохранения активной рабочей книги.

Sub LastSavedf)

Dim SaveTime As String On Error Resume Next

SaveTime = ActiveWorkbook. _ BuiltinDocumentProperties("Last Save Time"}.Value

If SaveTime = "" Then

286

Глава 11. Примеры и методы программирования на VBA

MsgBox ActiveWorkbook.Name & " не была сохранена."

Else

MsgBox "Сохранено: " & SaveTime, , ActiveWorkbook.Name End If

End Sub

Если рабочая книга не сохранена, то при попытке получить доступ к свойству Last Save Time будет получена ошибка. Оператор OnError пропускает ошибку. Структура If-Then-Else проверяет значение переменной SaveTime и отображает соответствующее сообщение. Если переменная пуста, это означает, что файл не был сохранен. На рис. 11.8 показан пример выполнения этой процедуры.

Рис. 11.8. Отображение даты и времени сохранениярабочей книги

Существует еще несколько встроенных свойств, к которым можно обратиться с помощью VBA, но эти немногочисленные свойства не относятся к опциям Excel. Полный список встроенных свойств вы можете найти в справочной системе.

Синхронизация рабочих листов

Если вы работаете с рабочими книгами, состоящими из нескольких листов, то, вероятно, знаете, что Excel не может "синхронизировать" листы в рабочей книге. Другими словами, не существует автоматического способа сделать гак, чтобы все листы имели одинаковые выделенные диапазоны и верхние левые ячейки. Макрос VBA, показанный ниже, берет за основу активный рабочий лист и выполняет следующие действия со всеми остальными рабочими листами в книге.

Выделяет тот же диапазон, что и в активном листе.

Задает ту же левую верхнюю ячейку, что и на активном листе. Нижеприведенлистингданногомакроса.

Sub SynchSheets()

Дублирует активный диапазон и верхнюю левую ячейку

1активного листа во всех рабочих листах

If TypeName(ActiveSheet) <> "Worksheet" Then Exit Sub Dim UserSheet As Worksheet, sht As Worksheet

Dim TopRow As Long, LeftCol As Integer Dim UserSel Аз String

Application.ScreenUpdating = False

1Сохранение текущего листа Set UserSheet = ActiveSheet

1

Сохранение

информации из активного листа

 

TopRow =

ActiveWindow.ScrollRow

 

LeftCol

=

ActiveWindow.ScrollColumn

 

UserSel

=

ActiveWindow.RangeSelection.Address

 

Просмотр

рабочих листов

 

For Each

sht In ActiveWorkbook.Worksheets

If sht.Visible Then 'пропустить скрытые листы sht.Activate

Range{UserSel}.Select

Часть III. Visual Basic for Applications

287

 

ActiveWindow.ScrollRow = TopRow

 

ActiveWindow.ScrollColumn = LeftCol

 

End If

 

Next sht

1

Переход к первоначальной позиции

 

UserSheet.Activate

 

Application.ScreenUpdating = True

End

Sub

Методы программирования на VBA

Примеры в этом разделе иллюстрирую! часто используемые приемы VBA, которые вы можете использовать в собственных проектах.

Примеры, приведенные в данном разделе, можно найти на Web-узле издательства.

ПереключениезначениясвойстваBoolean

Свойство B o o l e a n — это логическое свойство, принимающее одно из двух значений: True (ИСТИНА) или F a l s e (ЛОЖЬ), Самый простой способ изменить логическое свойство — это использовать оператор Not, как показано в следующем примере, в котором активизируется свойство переноса по словам WrapText в выделенном диапазоне ячеек.

Sub ToggleWrapText()

1 Управляет переносом слов в выделенных ячейках If TypeName(Selection) = "Range" Then Selection.WrapText = Not ActiveCell.WrapText End If

End Sub

Обратите внимание, что за основу взята активная ячейка. Когда диапазон выделен, и значения свойств в разных ячейках неодинаковы (например, в некоторых ячейках шрифт полужирный, а в других — нет), то диапазон считается смешанным, и Excel использует в качестве базового значение свойства активной ячейки. Если, например, активная ячейка имеет полужирный шрифт, то начертание текста в выделенных ячейках при щелчке на кнопке Полужирный на панели инструментов станет обычным. Эта простая процедура имитирует поведение инструмента Excel.

Отметьте, что процедура использует функцию TypeName для проверки, является ли выделенный объект диапазоном. Если это не так, то ничего не происходит.

Оператор Not можно использовать для переключения значений многих свойств. Например, для отображения заголовков строк и столбцов в рабочем листе примените следующую команду:

ActiveWindow.DisplayHeadings = Not _ ActiveWindow.Display-Headings

Для отображения линий сетки на активном листе воспользуйтесь таким синтаксисом:

ActiveWindow.DisplayGridlines = Not _ ActiveWindow.DisplayGridlines

288

Глава 11. Примеры и методы программирования на VBA

Соседние файлы в папке 2 семестр