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

2 семестр / vba_2002

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

Еще один подход к решению этой задачи — использовать для представления диапазонов переменные объектов, как показано в следующем примере.

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

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