2 семестр / vba_2002
.pdfЕще один подход к решению этой задачи — использовать для представления диапазонов переменные объектов, как показано в следующем примере.
Sub СоруЕапдеЗ()
Set Rngl = Workbooks("Filel.xls"). _ Sheets("Лист1").Range("Al")
Set Rng2 = Workbooks{"File2.xls"). _ Sheets{"Лист2").Range("Al")
Rngl.Copy Rng2 End Sub
Понятно, что копирование не ограничено единственной ячейкой за операцию. Например, следующая процедура копирует большой диапазон. Помните, что адрес места вставки определяется единственной ячейкой (представляющей верхний левый угол вставляемого диапазона):
Sub CopyRange4()
Range("Al:C800").Copy Range("Dl") End Sub
Перемещение диапазона
Инструкции VBA для перемещения диапазона ячеек подобны инструкциям копирования диапазона (см. следующий пример). Разница заключается в том, что вместо метода Сору используется метод Cut. Обратите внимание, что для вставляемого диапазона необходимо задавать только адрес левой верхней ячейки.
Следующий пример перемешает 18 ячеек (в диапазоне А1: с 6) на новое место, начиная с ячейки HI:
Sub MoveRange() Range("Al:C6").Cut Range("HI")
End Sub
Копирование диапазона переменного размера
Во многих случаях необходимо скопировать диапазон ячеек, когда неизвестны точные размеры диапазона (количество столбцов и строк). Например, вы управляете рабочей книгой, в которой фиксируется объем продаж за неделю. Количество строк еженедельно меняется по мере добавления новых данных.
На рис. 11.1 показан стандартный вид рабочего листа. Диапазон состоит из нескольких строк, количество строк изменяется каждую неделю. Так как вы не можете знать точный размер диапазона в определенный момент времени, работа по написанию макроса, копирующего данный диапазон, несколько усложняется.
fwc. //./. Этот диапазон молсет
состоять из любого количества строк
Следующий макрос демонстрирует, как скопировать данный диапазон из листа Лист1 на лист Лист2 (начиная с ячейки А1). В данном случае используется свойство C u r r e n t R e g i o n , возвращающее объект Range, который соответствует прямоугольнику ячеек вокруг заданной ячейки (в данном случае А1).
Часть Ш. Visual Basic forApplications |
269 |
Sub CopyCurrentRegion2i)
Range<nAl").CurrentRegion.Copy „
Sheets("Лист2"J.Range("Al")
End Sub
Использование свойства currsntRegion эквивалентно следующим действиям: выберите команду Правка^Перейти, щелкните на кнопке Выделить, выберите параметр текущую область. Чтобы увидеть принцип работы, включите запись макроса и выполните указанные действия. Как правило, значение свойства CurrentRegion состоит из прямоугольного диапазона ячеек, окруженных одной или более пустыми строками или столбцами.
Выделение или определение типов диапазонов
Зачастую работа, выполняемая в VBA, связана с управлением диапазонами — либо выделением диапазона, либо определением диапазона с целью выполнить определенные действия с ячейками.
В предыдущих версиях Excel запись макроса, выделяющего ячейки (как при нажатии <Ctrt+Shift+> >), происходила достаточно бессистемно. Команда записи макросов в Excel 2002 обрабатывает такие типы выделений намного лучше, чем а предыдущих версиях. Однако рекомендуем тщательно проверять полученный при записи макросов код, чтобы убедиться, что выделение выполняется так, как это необходимо.
Кроме свойства C u r r s n t R e g i o n (описанного выше), вам необходимо научиться управлять методом End объекта Range, Метод End. имеет один аргумент, определяющий направление, в котором увеличивается выделение ячеек. Оператор, представленный ниже, выделяет диапазон от активной ячейки до последней непустой ячейки внизу.
Range(ActiveCell, ActiveCell.End(xlDown)).Select
Как можно догадаться, три остальные константы имитируют комбинации клавиш при выделении в других направлениях: x l u p (вверх), xlToLef t (влево) и x l T o R i g h t (вправо).
Будьте внимательны при использовании метода End. Если активная ячейка находится на границе диапазона или диапазон содержит хотя бы одну пустую ячейку, метод End может не дать желаемых результатов.
На Web-узле издательства находится рабочая книга, в которой содержится несколько популярных типов выделений ячеек. Открыв эту рабочую книгу, вы увидите новое меню — Selection Demo, которое содержит команды, позволяющие пользователю получать различные типы выделений (рис. 11.2).
Рис.11.2.Этоменюдемонстрирует, как выделять диапазоны различной формыспомощьюVBA
270 |
Глава 11. Примеры и методы программирования на VBA |
Приведенный далее макрос взят из этой рабочей книги. Макрос SelectCurrentRegion имитирует нажатие клавиш <Ctrl+Shift+*>:
Sub SelectCurrentRegion() ActiveCell.CurrentRegion.Select
End, Sub
Часто для получения желаемого результата не требуется выделять ячейки. Вместо этого необходимо выполнить над ними определенное действие (например, отформатировать). Процедуры выделения ячеек можно легко изменить. Процедура, показанная ниже, была получена на основе процедуры SelectCurrentRegion— она не выделяет ячейки, а создает объект Range и применяет к этому объекту форматирование. Другие процедуры рабочей книги, представленные на Web-узле, можно модифицировать таким же образом:
Sub FormatCurrentRegion()
Set WorkRange = ActiveCell.CurrentRegion WorkRange.Font.Bold = True
End Sub
Советы по работе с диапазонами
При работе с диапазонами необходимо помнить о следующих моментах. Для управления диапазоном его не требуется выделять в программе.
Если в коде выделяется диапазон, то соответствующий рабочий лист должен быть активным. Чтобы активизировать конкретный лист, используйте метод Activate коллекции Worksheets.
Команда записи макросов не всегда генерирует самый эффективный код. Зачастую после записи макроса код необходимо отредактировать, чтобы сделать его более эффективным.
Используйте в программе VBA именованные диапазоны. Например, лучше применить ссылку Range ("Total"), чем ссылку Range (" D4 5"). Во втором случае при добавлении строки над строкой 45 адрес ячейки изменится. Тогда следует изменить макрос, чтобы в нем использовался правильный адрес ячейки (D46).
Если вы используете код, записанный при выделении диапазонов с помощью комбинации клавиш (например, <Ctrl+Shift+> > для создания выделения до конца строки), то внимательно проверьте код. Иногда Excel использует жесткие ссылки на выделенные ячейки.
Перед выполнением макроса, который управляет каждой ячейкой в текущем диапазоне, рассмотрите ситуацию, когда пользователь выделил столбцы или строки целиком. В большинстве случаев нет необходимости, чтобы макрос просматривал каждую ячейку выделенного диапазона. На этот случай в макросе должен создаваться новый диапазон, который состоит только из непустых ячеек диапазона, выделенного пользователем.
Excel позволяет выделять несколько несмежных диапазонов. Например, можно выделить диапазон, нажать <Ctrl> и выделить еще один диапазон. Такой диапазон можно определить в макросе и назначить для его управления дополнительные действия.
Запрос значения ячейки
Следующая процедура демонстрирует, как запросить у пользователя значение ячейки: и вставить его в ячейку А1 активного рабочего листа:
Sub GetValuel()
Range("Al").Value = InputBox("Введите значение") End Sub
На рис. 11.3 показано диалоговое окно ввода данных. |
|
Часть III. Visual Basic for Applications |
171 |
Рис. }}.3. Функция InputBoxполучает от пользователя значение, которое должнобытьвставленовячейку
Однако в этой процедуре существует одна проблема. Если пользователь щелкнет на кнопке Отмена (Cancel) в окне ввода данных, то процедура удалит данные, которые находились в текущей ячейке. Модифицированная версия адекватно реагирует на щелчок на кнопке Отмена (Cancel) и не выполняет при :этом никаких действий.
Sub GetValue2{)
UserEntry = InputBox("Введите значение")
If UserEntry <> "" Then Range("Al").Value = UserEntry End Sub
Во многих случаях следует проверить корректность данных, введенных пользователем. Например, необходимо обеспечить введение только чисел в диапазоне от I до 12. Далее представлен способ проверки данных, введенных пользователем. В приведенном ниже примере некорректные данные игнорируются, и окно запроса значения отображается снова. Этот цикл повторяется, пока пользователь не введет корректное значение или не щелкнет на кнопке Отмена (Cancel).
Sub GetValue3{)
Dim MinVal As Integer, MaxVal As Integer Dim UserEntry As String
Dim Msg As String
Dim IntEntry As Integer MinVal = 1
MaxVal =12
Msg = "Введите значение от " & MinVal & " до " & MaxVal
Do
UserEntry = InputBox(Msg)
If UserEntry = "" Then Exit Sub If IsNumeric(UserEntry) Then
IntEntry = CInt(UserEntry}
If IntEntry >= MinVal And IntEntry <= MaxVal Then Exit Do
End If End If
Msg = "Вы ввели НЕПРАВИЛЬНОЕ значение." Msg = Msg & vbNewLine
Msg = Msg & "Введите значение от * & _ MinVal & " до " & MaxVal
Loop
ActiveSheet-Range("Aln).Value = UserEntry End Sub
Как видно из рис. 11.4, программа также изменяет отображаемое сообщение, если пользователь вводит некорректные данные.
Рис. 11.4. Проверка корректности данных, введенныхпользователе.»,спомощьюфункции VBA InputBox
272 |
Глава 11. Примеры и методы программирования на VBA |
Ввод значения в следующую пустую ячейку
Достаточно часто требуется ввести значение в следующую пустую ячейку столбца или строки. В представленном далее примере пользователь должен ввести имя и значение, которые добавляются в следующую пустую строку (рис. 11.5).
/*ис. /J.-5". Макрос вставки данных в следующую пустую строкурабочеголиста
Sub GetDatai)
Dim NextRow As Long
Dim Entryl As String, Entry2 As String
Do
NextRow = Range{"A65536").End(xlUp).Row + 1
Entryl = InputBoxf"Введите имя"}
If Entryl = "" Then Exit Sub
Entry2 = InputBox("Введите сумму")
If Entry2 = "" Then Exit Sub
Cells(NextRow, 1) = Entryl
Cells(NextRow, 2) = Entry2
Loop
End Sub
Обратите внимание, что это бесконечный цикл, Для выхода из него (щелкните на кнопке Cancel) использовались операторы E x i t Sub.
Чтобы упростить представленную процедуру, проверка данных не выполнялась.
Обратите внимание на оператор, который определяет значение переменной NextRow. Если вам трудно понять принцип его работы, то постарайтесь проанализировать содержимое ячейки: перейдите в ячейку А65536 (последняя ячейка в столбце А), затем нажмите <End:> и клавишу со стрелкой вверх. При этом будет выделена последняя непустая ячейка в столбце А. Свойство Row возвращает номер этой строки; чтобы получить расположенную под ней строку (следующая пустая строка), к этому номеру прибавляется 1.
Стоит отметить, что в представленном приеме выделения следующей пустой строки существует такой нюанс: если столбец полностью пуст, то следующей пустой строкой будет считаться строка 2.
Часть ///. Visual Basic for Applications |
273 |
Приостановка макроса для получения диапазона, выделенного пользователем
Возможно, вам понадобится создать макрос, который останавливает выполнение кода, чтобы пользователь задал диапазон ячеек. Для этого воспользуйтесь функцией Excel InputBox .
Процедура, представленная ниже, демонстрирует, как приостановить макрос и позволить пользователю выбрать ячейку.
Sub GetUserRange()
Dim, UserRange As Range
Output = 565
Prompt = "Выберите ячейку лля отображения результата." Title = "Выберите ячейку"
' |
Отображение окна для ввода данных |
|||
|
On Error Resume Next |
|
||
|
Set UserRange = Application.InputBox( _ |
|||
|
Prompt:=Prompt, |
_ |
|
|
|
Title:=Title, _ |
|
|
|
|
Default:=ActiveCell.Address, _ |
|||
|
Type:=8) |
'Выделение |
диапазона |
|
|
On Error GoTo 0 |
|
|
|
1 |
Проверка, |
была ли нажата кнопка Отмена |
||
|
If UserRange Is Nothing Then |
|||
|
MsgBox "Действие |
отменено." |
||
|
Else |
|
|
|
|
UserRange.Range("Al") |
= Output |
||
|
End If |
|
|
|
End Sub |
|
|
|
|
|
Окно ввода данных показано на рис, I J..6. |
|||
|
|
|
|
Рис. 11.6. Использование окна ввода |
|
|
|
|
данныхсцельюприостановитьмакрос |
Ключевым моментом в этой процедуре является определение аргумента Туре равным 8. Кроме того, обратите внимание на использование оператора On E r r o r Resume Next . Он игнорирует ошибку, происходящую по вине пользователя, который щелкаег на кнопке Отмена. В таком случае переменная объекта u s e r R a n g e не получает значения. В данном примере отображается окно сообщения с текстом "Действие отменено". Если же пользователь щелкает на кнопке ОК, то макрос продолжается. Строка On E r r o r Resume Next указывает на переход к нормальной обработке ошибки.
|
Проверка корректного выделения диапазона необязательна. Excel позаботится об этом за вас. |
|
Обязательно проверьте, включен ли параметр обновления экрана screenupdating. |
|
В противном случае вы не сможете выбрать ячейку. |
274 |
Глава 11. Примеры и методы программирования на VBA |
Определение количества выделенных ячеек
При работе с макросом, который обрабатывает выделенный диапазон ячеек, можно использовать свойство Count, чтобы определить, сколько ячеек содержится в выделенном диапазоне (или любом другом диапазоне). Например, следующий оператор демонстрирует окно сообщения, которое отображает количество ячеек в текущем выделенном диапазоне:
MsgBox Selection.Count
Если активный лист содержит диапазон с названием data, то следующий оператор присваивает количество ячеек в диапазоне data переменной с названием CellCount: CellCount = Ranget"data"I.Count
Вы можете также определить, сколько строк или столбцов содержится в диапазоне. Следующее выражение вычисляет количество столбцов в выделенном в данный момент диапазоне. Selection.Columns.Count
Для определения количества строк в диапазоне вы также июжете использовать свойство Rows. Следующий оператор пересчитывает количество строк в диапазоне с названием data и присваивает это количество переменной RowCounc.
RowCount = Range("data").Rows.Count
Определение типа выделенного диапазона
Excel поддерживает несколько типов диапазонов.
•Отдельная ячейка.
•Смежный диапазон ячеек.
•Один или несколько полных столбцов.
•Одна или несколько полных строк.
•Весь рабочий лист.
•Комбинация перечисленных выше типов (называемая множественным выделением).
Врезультате, когда процедура VBA обрабатывает выделенный диапазон, нельзя исходить из каких-либо предположений о типе этого диапазона.
Вслучае множественного выделения объект Range включает несмежные области. Чтобы определить, является ли выделение множественным, используется метод Areas, возвращающий коллекцию Areas. Эта коллекция представляет все диапазоны во множественном выделении.
Для определения того, содержатся ли в выделенном диапазоне множественные области, примените выражение, подобное следующему:
NumAreas • Selection.Areas.Count
Если переменная NumAreas содержит значение больше единицы, то выделение является множественным.
Процедура AboutRangeSelection использует функцию ДгеаТуре, показанную ниже:
Function AreaType(RangeArea |
As |
Range) |
As String |
|||
1 |
Возвращает |
тип диапазона |
|
|
||
|
Select Case |
True |
|
|
|
|
|
Case |
RangeArea.Cells.Count = |
1 |
|||
|
|
AreaType = "Cell" |
|
|
||
|
Case |
RangeArea.Count |
- |
Cells.Count |
||
ЧастьIII. VisualBasicforApplications |
275 |
AreaType = "Worksheet"
Case RangeArea.Rows.Count = Cells.Rows.Count
AreaType - "Column"
Case RangeArea.Columns.Count = Cells.Columns.Count
AreaType = "Row"
Case Else
AreaType = "Block"
End Select
End Function
Эта функция получает в качестве аргумента объект Range и возвращает одну из пяти строк, описывающих данную область: ячейка, рабочий лист, столбец, строка или блок. Функция использует конструкцию S e l e c t Case для определения одного из четырех выражений сравнения, которое имеет значение True. Например, если диапазон состоит из одной ячейки, функция возвращает C e l l . Если количество ячеек в диапазоне равно количеству ячеек в рабочем листе, то функция возвращает Worksheet . Если количество строк в диапазоне равно количеству строк в рабочем листе, функция возвращает Column. Если количество столбцов в диапазоне равно количеству столбцов на рабочем листе, функция возвращает Row. Если ни одно из выражений Case не равно True, то функция возвращает строку Block.
Обратите внимание, что в сравнении не используются абсолютные числа. Например, вместо того чтобы использовать число 65536 для определения принадлежности диапазона к столбцу, применяется cells . count . Это обеспечивает корректность выполнения функция даже в Excel 5 и Excel 97 (где лист состоит всего из 16384 строк).
Рабочая книга на Web-узле издательства содержит процедуру (с названием AboutRangeSelection), использующую функцию AreaType ДЛЯ отображения окна сообщения, в котором описан текущий выделенный диапазон (рис. 11.7). Понимание принципов работы этой процедуры позволит вам правильно управлять обьектами Range.
Рис. П.7. Процедура AboutR&ngeSelect ion анализируеттекущийвыделенныйдиапазон
Возможно, вас удивит, что Excel позволяет создавать идентичные множественные выделения. Например, если, удерживая <Ctrl>, щелкнуть пять раз на ячейке А1, ТО выделение будет содержать пять идентичных областей. Это также учтено в процедуре AboutRangeSelection.
Эффективный цикл просмотра выделенного диапазона
Вы можете столкнуться с проблемой, когда необходимо создать макрос, который оценивает каждую ячейку в диапазоне и выполняет определенную операцию, причем ячейка соответствует конкретному критерию. В листинге 11.1 приведен пример такого макроса: процедура
276 |
Глава 11. Примеры и методы программирования на VBA |
SelectiveColorl задает красный фон для всех ячеек, имеющих отрицательное значение. Цвет фона остальных ячеек не указывается.
Листинг 11.1. Красный фон ячеек с отрицательными значениями
Sub SelectiveColorl()
1Задает красный фон для ячейки, если ее значение отрицательно If TypeName(Selection) <> "Range" Then Exit Sub
Const REDINDEX = 3
Application.ScreenUpdating = False For Each cell In Selection
If cell.Value < 0 Then
cell.Interior.Colorlndex = REDINDEX Else
cell.Interior.Colorlndex = xlNone End If
Next cell End Sub
Процедура SelectiveColorl работает, но в ней имеется серьезный недостаток. К примеру, что получается, если выделение состоит из полного столбца? Или десяти столбцов? Или всего рабочего листа? Пользователь, скорее всего, уснет, пока будут оценены все ячейки. Лучшее решение этой задачи (SelectiveColor2) представлено в листинге 11.2.
Листинг 11.2. Улучшение процедуры S e l e c t i v e C o l o r l с учетом более широких диапазонов из нескольких столбцов
Sub SelectiveColor2()
1Задает красный фон для ячейки, если ее значение отрицательно
Dim FormulaCells As Range Dim ConstantCells As Range
Const REDINDEX = 3
' Игнорирует ошибки On Error Resume Next
Application.ScreenUpdating = False
' Создает подмножества первоначального выделения Set FormulaCells = Selection.SpecialCells _
(xlFormulas, xlNumbers)
Set ConstantCells = Selection.SpecialCells _ (xlCons tants, xlNumbers)
1Обработка ячеек с формулами
If Not FormulaCells Is Nothing Then For Each cell In FormulaCells
If cell.Value < 0 Then _
cell.Font.Colorlndex = REDINDEX Next cell
End If
'Обработка ячеек с константами
If Not ConstantCells Is Nothing Then
For Each cell In ConstantCells
If cell.Value < 0 Then
Часть ///. Visual Basic for Applications |
277 |
cell.Interior.ColorIndex = REDINDEX Else
cell.Interior.ColorIndex = xlNone End If
Next cell End If
End Sub
Эта процедура выполняет некоторые дополнительные действия, которые делают ее более эффективной. В ней используется метод S p e c i a l C e l l s для создания двух подмножеств текущего выделения: первое подмножество включает только ячейки с числовыми константами, а второе — только ячейки с формулами. Затем ячейки в этих подмножествах обрабатываются с помощью двух конструкций F o r Each - Next . В итоге оцениваются только непустые ячейки, что значительно ускоряет работу макроса.
Оператор On Error необходим, так как метод SpecialCells генерирует ошибку, если не находит в диапазоне ячеек указанного типа. Этот оператор также учитывает ситуации, когда процедура выполняется при невыделенном диапазоне.
Удаление всех пустых строк
Следующая процедура удаляет все пустые строки в активном рабочем листе. Она достаточно эффективна, так как не проверяет все без исключения строки, а просматривает только строки в так называемом "используемом диапазоне", определяемом с помощью свойства UsedRange объекта Worksheet.
Sub DeleteEmptyRows{) |
|
||
Dim LastRow |
As Long, r As |
Long |
|
LastRow |
- |
ActiveSheet.UsedRange.Rows.Count |
|
LastRow = LastRow + ActiveSheet.UsedRange.Row - 1 |
|||
Application.ScreenUpdating |
= False |
||
For r = LastRow To 1 Step |
-1 |
||
If |
Application.CountAfRows(r)) = 0 Then Rows{r).Delete |
||
Next r |
|
|
|
End Sub |
|
|
|
Первый шаг — определить последнюю используемую строку и присвоить этот номер строки переменной LastRow. Это не так просто, как можно ожидать, поскольку текущий диапазон не обязательно начинается со строки 1. Следовательно, значение LastRow вычисляется таким образом: к найденному количеству строк используемого диапазона прибавляется номер первой строки текущего диапазона и вычитается 1.
В процедуре применена функция Excel СЧЕТЗ (COUNTA) для определения, является ли строка пустой. Если данная функция для конкретной строки возвращает 0, то эта строка пустая. Обратите внимание, что процедура просматривает строки снизу вверх и использует отрицательное значение шага в цикле For-Next. Это необходимо, поскольку при удалении все последующие строки перемещаются "вверх" в рабочем листе. Если бы в цикле просмотр выполнялся сверху вниз, то счетчик цикла после удаления строки становится неправильным.
Определение диапазона, находящегося в другом диапазоне
Функция InRange, показанная ниже, имеет два аргумента, оба — объекты Range. Функция возвращает ИСТИНА, если первый диапазон содержится во втором.
278 Глава 11, Примеры и методы программирования на VBA