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

2 семестр / vba_2002

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

Function FILLCOLOR(cell) As Integer

1

Возвращает целое число, соответствующее

1

цвету фона

ячейки

 

FILLCOLOR =

cell.Rangef"Al").Interior.Colorlndex

End Function

Отображение даты сохранения файла или вывода файла на печать

Рабочая книга Excel содержит несколько встроенных свойств документа, к которым можно получить доступ с помощью свойства B u i l t i n D o c u m e n t P r o p e r t i e s объекта Workbook. Следующая функция возвращает дату и время последнего сохранения рабочей книги.

Function LASTSAVEDO Application.Volatile LAST/SAVED = ThisWorkbook. _

BuiltinDocumentProperties("Last Save Time") End Function

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

Function LASTPRINTED() Application.Volatile LASTPRINTED = ThisWorkbook. _

BuiltinDocumentProperties("Last Print Date") End Function

При использовании этих функций в формуле необходимо вызвать пересчет формул (комбинация клавиш <Ctrl+Alt+F9>), чтобы получить текущие значения данных свойств.

Существует еще несколько встроенных свойств, но Excel их не использует. Например, при попытке получить свойство, указывающее размера файла, будет выведено сообщение об ошибке.

Основы иерархии объектов

Как известно, объектная модель Excel представляет собой определенную структуру: объекты содержатся в других объектах. В верхней части этой иерархии находится объект Application . Excel содержит другие объекты, которые, в свою очередь, содержат вложенные объекты и т.д. Следующая иерархия изображает, как в этой структуре представлен объект Range.

Объект A p p l i c a t i o n Объект Workbook

Объект Worksheet Объект Range

На языке объектно-ориентированного программирования родителем объекта Range (Диапазон) является объект Worksheet (Рабочий лист), в котором он содержится. Родителем объекта Worksheet является объект Workbook (Рабочая книга), содержащий этот рабочий лист, а родителем объекта Workbook является объект A p p l i c a t i o n (приложение, т.е. Excel).

Как можно применить эту информацию на практике? Проанализируем функцию VBA

SheetName, показанную ниже. Данная функция получает один аргумент (диапазон) и воз-

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

свойство Paren t объекта Range. Свойство Paren t

возвращает объект, а именно объект,

содержащий объект Range.

 

Часть HI. VisualBasic forApplications

299

Function SheetName(ref) As String

SheetName = ref . Parent: .Name

End Function

Функция, WorkbookName возвращает название рабочей книги для конкретной ячейки. Обратите внимание, что эта функция использует свойство Parent дважды. Первое свойство Parent возвращает объект Worksheet, а второе свойство Parent возвращает объект Workbook.

Function WorkbookName(ref) As String WorkbookName = ref.Parent.Parent.Name

End Function

Функция AppName, показанная далее, переносит это упражнение на следующий логический уровень, обращаясь к свойству Parent трижды. Эта функция возвращает имя объекта Application для заданной ячейки. Конечно, данная функция всегда будет возвращать значение Microsoft Excel.

Function AppNartiefref} As String

AppName = ref.Parent.Parent.Parent.Name End Function

Подсчет количества ячеек между двумя значениями

Следующая функция с названием COUNTBETWEEN возвращает количество значений в диапазоне (первыйаргумент), которые попадают вобласть, заданную вторым итретьимаргументами.

Function COUNTBETWEEN{InRange, numl, num2) As Long Подсчитывает количество значений между numl и num2 With Application.WorksheetFunction

COUNTBETWEEN = .Count!f(InRange, ">=" & numl) -

.CountIf(InRange, " >" & num2)

End With End Function

Обратите внимание, что эта функция вызывает функцию Excel СЧЕТЕСЛИ (COUNTIF). По существу, функция COUNTBETWEEN является ''упаковкой", которая может упростить формулы.

Нижеприведенпримерформулы,использующейфункциюCOUNTBETWEEN.Формулавозвращает количество ячеек в диапазоне Al:A100, больше или равных 10 и меньше или равных 20.

=COUNTBETWEEN<A1:A100;10;20)

Применяйте эту функцию VBA, чтобы не вводить следующуюдлинную формулу.

*(СЧЕТЕСЛИ(А1:А100; ">=10"))-СЧЕТЕСЛИ(А1:А100; ">=20")}

Подсчет количества видимых ячеек в диапазоне

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

Function COUNTVISIBLE(rng)

1Подсчитывает видимые ячейки Dim CellCount As Long

Dim cell As Range Application.Volatile CellCount = 0

Set rng = Intersect(rng.Parent.UsedRange, rng) For Each cell In rng

300

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

If Not IsEmpty(cell) Then

If Not cell.EntireRow.Hidden And _

Not cell.EntireColumn.Hidden Then _

CellCount = CellCount + 1

End If

Next cell

COUNTVISIBLE = CellCount

End Function

Эта функция циклически просматривает все ячейки диапазона и сначала проверяет, пуста ли ячейка. Если ячейка не пустая, то функция проверят, скрыты ли строка и столбец ячейки. При условии, если либо строка, либо столбец скрыты, переменная C e l l C o u n t увеличивает значение на 1.

Функция COUNTVISIBLE используется при работе с автофильтрами или детализации структуры. В обоих этих случаях часто используются скрытые строки.

 

Функция Excel П Р О М Е Ж У Т О Ч Н Ы Е . и т о г и (с первым аргументом 2 или 3) также мо-

С о в в т

жет быть применена для пересчета видимых ячеек в списке автофильтрации. Од-

 

нако указанная функция не будет работать должным образом, если ячейки скрыты

*в нефильтрованном списке.

Определение последней непустой ячейки

встолбце или строке

Вданном разделе представлены две важные функции: LASTINCOLUMN возвращает содержимое последней непустой ячейки в столбце, a LASTINROW возвращает содержимое последней непустой ячейки в строке. Каждая функция получает один аргумент — диапазон ячеек. Этот диапазон может представлять собой полный столбец (для функции LASTINCOLIMM) или полную строку (для функции LASTINROW). Если аргумент не является полным столбцом или строкой, функция использует столбец или строку левой верхней ячейки в диапазоне. Например, следующая формула возвращает последнее значение в столбце В:

=LASTINCOLUMN(B5)

Представленная далее формула возвращает последнее значение в строке 7: =LASTINROW(C7:D9)

Функция LASTINCOLUMN

Функция LASTINCOLUMN показана ниже.

Function LASTINCOLUMN(rng As Range) Application.Volatile

Set LastCell = rng.Parent.Cells(Rows.Count, rng.Column) _

.End(xlUp)

LASTINCOLUMN = LastCell.Value

If IsEmpty(LastCell) Then LASTINCOLUMN =

If rng.Parent.Cells(Rows.Count, rng.Column) <> "" Then _ LASTINCOLUMN = rng.Parent.Cells{Rows.Count, rng.Column)

End Function

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

Оператор Application.Volatile вызывает выполнение функции всякий раз, когда пересчитываются формулы на рабочем листе.

Часть ///. Visual Basic forApplications

301

Оператор Rows.Count возвращает количество строк на рабочем листе. Используем его, а не жестко заданное значение 6:5536, из соображений совместимости (новые версии Excel могут включать больше строк на-рабочем листе).

rng . Column возвращает номер столбца левой верхней ячейки в аргументе rng.

Благодаря ссылке r n g . Parent функция работает корректно, даже если аргумент rng ссылается на другой лист или рабочую книгу.

Метод End (с аргументом xlup) эквивалентен переходу к последней ячейке столбца и нажатию <End> и клавиши со стрелкой "вверх",

Функция IsEmpty проверяет, пуста пи ячейка. Если ячейка пуста, функция возвращает пустую строку. Без этого оператора пустой ячейке соответствовал бы результат 0.

Последний оператор If проверяет последнюю ячейку в столбце. Если ячейка не пуста, функция возвращает содержимое этой ячейки.

Функция LASTINROW

Функция LASTINROW представлена ниже. Она во многом напоминает функцию

LASTINCOLUMN.

Function LASTINROW(rng As Range) Application.Volatile

Set LastCell = rng.Parent.Cells(rng.Row, Columns.Count) _

.End(xlToLeft) LASTINROW = LastCell.Value

If IsEmpty(LastCell) Then LASTINROW = ""

If rng.Parent.Cells(rng.Row, Columns.Count) <> •• Then _ LASTINROW = rng.Parent.Cells(rng.Row, Columns.Count)

End Function

Соответствует ли строка шаблону?

Функция ISLIKE довольно проста (и очень полезна). Она возвращает ИСТИНА, если строка соответствует заданному шаблону.

Функция ISLIKE показана далее. Как видно, она представляет собой "оболочку", позволяющую использовать в формулах мощный оператор VBA Like.

Function ISLIKE{text As String, pattern As.String) As Boolean

'Возвращает ИСТИНА, если первый аргумент такой, как второй If text Like pattern Then ISLIKE = True _

Else ISLIKE = False End Function

Функция ISLIKE имеет два аргумента:

t e x t — тестовая строка или ссылка на ячейку, содержащую текстовую строку;

p a t t e r n — строка, содержащая групповые символы согласно следующему списку.

Сим вол(ы) в шаблоне

 

Соответствует в тексте

 

?

 

Любой отдельный символ

*

 

Ноль и больше символов

#

 

Любая отдельная цифра (0-9)

[список_символов]

Любой отдельный символ из список_символов

[! список^символов]

Любой отдельный символ, не принадлежащий

 

список_символов

Ж

 

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

Представленная ниже формула возвращает ИСТИНА, так как * соответствует любому количеству символов. Она возвращает ИСТИНА, если первый аргумент — любой текст, начинающийся с д:

= I S L I K E ( " g u i t a r " ; "д*")

Следующая формула возвращает ИСТИНА, так как ? соответствует любому отдельному символу. Если бы первым аргументом функции был "Unit 12", то функция возвращала бы ЛОЖЬ:

=ISLIKE("Unitl"; "Unit?")

Показанная далее формула возвращает ИСТИНА, так как первый аргумент является одним из символов списка во втором аргументе:

=ISLIKE("a"; " ( a e i o u l " )

Следующая формула возвращает ИСТИНА, если ячейка Al содержит один из символов: а, е, i, о, u. A, E, I, О, и. При использовании функции UPPER в аргументе функция становится не чувствительной к регистру:

=ISLIKE(UPPER(A1)I UPPER!"[aeiou]"))

Представленная далее формула возвращает ИСТИНА, если в ячейке Al находится значение, начинающееся с 1 и состоящее ровно из трех цифр (т.е. любое целое число от 100 до 199): =ISLIKE(A1; "1##")

Извлечение из строки п-го элемента

ExtractElement — специальная функция рабочего листа (которую можно также вызвать из процедуры VBA), которая помогает извлечь элемент из текстовой строки. Например, если ячейка содержит следующий текст, вы можете использовать функцию ExtractElement для извлечения любых подстрок между дефисами:

123-456-789-0133-8844

Представленная далее формула, например, возвращает 0133, т.е. четвертый элемент в строке. Дефис (-) используется в строке как разделитель:

=ExtractElement("123-456-789-0133-8844",4,"-")

Функция ExtractElement имеет три аргумента:

Txt — текстовая строка, из которой извлекается подстрока. Это может быть символькая строка или ссылка на ячейку:

п — целое число, представляюшее элемент для извлечения; Separator — отдельный символ, используемый как разделитель.

Если вы зададите в качестве символа-разделителя пробел, то несколько пробелов будут рассматриваться как один, что не всегда соответствует требованиям. Если п превышает количество элементов в строке, функция возвращает пустую строку.

Ниже приведен код VBA функции ExtractElement.

Function ExtractElement(Txt, n, Separator)

As String

' Возвращает п-й элемент текстовой строки,

где

'элементы разделены указанным символом-разделителем.

Dim Txtl As String, TempElenient As String

Dim ElementCount As Integer, i As Integer

ЧастьIII. VisualBasicforApplications

303

Txtl - Txt

'Если разделитель - пробел, убрать лишние пробелы

If Separator = Chr(32) Then Txtl • Application.Trim{Txtl)

1Добавление разделителя в конец строки

If Right{Txtl, Len(Txtl)) <> separator Then _ Txtl = Txtl & Separator

' Инициализация

ElementCount = 0 TempEleraent = ""

1Извлечение каждого элемента For i = 1 To Len(Txtl)

If Mid(Txtl, i, 1) = Separator Then

ElementCount = ElementCount + 1

If ElenientCount = n Then

n-й символ найден, выход

ExtractElement = TempElement

Exit Function

Else

TempElement = ""

End If

Else

TempElement = TempEleaient & Mid (Txtl, i, 1)

End If

Next i

ExtractElement=""

End Function

Множественная функция

В этом примере рассматривается прием, который используется в такой ситуации, когда необходимо, чтобы одна функция рабочего листа работала, как несколько функцийНапример, ниже показан код VBA для специальной функции с названием S t a t F u n c t i o n . Эта функция имеет два аргумента: диапазон (rncf) и операция (ор). В зависимости от значения ор функция возвращает значение, вычисленное с помошью одной из следующих функций Excel: СРЗНАЧ (AVERAGE), СЧЕТ (COUNT), МАКС (МАХ), МЕДИАНА (MEDIAN), МИН (MIN), МОДА (MODE), СТАНДОТКЛОН (STDEV), СУММ (SUM) ИЛИ ДИСП (VAR).

Например, вы можете использовать эту функцию на рабочем листе следующим образом: =STATFUNCTION(В1гВ24;А24)

Результат формулы зависит от содержимого ячейки А24, которое представлено строкой: СРЗНАЧ, СЧЕТ, МАКС и Т.Д. Вы можете применить этот прием в других типах функций.

Function STATFUNCTION(rng, op) Select Case UCase(op)

Case "SUM"

STATFUNCTION = WorksheetFunction.Sumfrng) Case "AVERAGE"

STATFUNCTION = WorksheetFunction.Average(rng) Case "MEDIAN"

 

 

STATFUNCTION = WorksheetFunction.Median(rng)

 

Case

"MODE"

 

 

STATFUNCTION = WorksheetFunction.Mode(rng)

 

Case

"COUNT"

304

 

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

STATFUNCTION = WorksheetFunction.Count(rng)

Case "MAX"

STATFUNCTION = WorksheetFunction.Max(rng)

Case "MIN"

STATFUNCTION = WorksheetFunction.Min(rng)

Case "VAR"

STATFUNCTION = WorksheetFunction.Var(rng)

Case "STDEV"

STATFUNCTION = WorksheetFunction.StDev(rng)

Case Else

STATFUNCTION = CVErr(xlErrNA)

End Select

End Function

Функция SHEETOFFSET: версия 1

Вероятно, вы знаете, что в Excel ограничена поддержка "трехмерных рабочих книг". Например, если требуется сослаться на другой рабочий лист в книге, включите в формулу имя рабочего листа. Данная проблема невелика до тех пор, пока вы не попытаетесь скопировать формулу из одного листа на другой. Скопированные формулы продолжают ссылаться на первоначальное имя рабочего листа, и ссылки на листы не изменяются, как это реализуется н реальной трехмерной рабочей книге.

Пример, рассмотренный в этом разделе, представляет функцию VBA (под названием SHEETOFFSET), которая позволяет обращаться к листам относительным способом. Напричер, вы можете сослаться на ячейку А1 предыдущего рабочего листа с помощью формулы =SHEETOFFSET(-1;А1)

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

Ниже приведен код VBA функции SHEETOFFSET.

Function SHEETOFFSET<offset, Kef) Application.Volatile

SHEETOFFSET = Sheets(Application.Caller.Parent.Index _ + offset).Range(Ref.Address)

End Function

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

Функция SHEETOFFSET: версия 2

 

Ниже показана пересмотренная функция SHEETOFFSET. Эта версия несколько более сложная,

 

но в ней исключается проблема, описанная в предыдущем разделе. Данная версия SHEETOFFSET

 

игнорирует любые листы рабочей книги, которые не являются рабочими.

 

Function SHEETOFFSET2{offset,

Ref)

 

 

Dim WBook As Workbook

 

 

 

Dim WksCount As Integer,

i As Integer

 

 

Dim CallerSheet As String, CallerIndex As Integer

 

 

Application.Volatile

 

 

1

Создание массива, состоящего только из рабочих листов

 

Часть ///. Visual Basic forApplications

305

Set WBook = Application.Caller.Parent.Parent

Dim Wks() As Worksheet

WksCount = 0

For i = 1 To WBook.Sheets.Count

If TypeName(WBook.Sheets(i)) = "Worksheet" Then

WksCount = WkaCount + 1

ReDim Preserve Wks(l To WksCount)

Set Wks{WksCount} = WBook.Sheets(i)

End If

Next i

1Определение позиции листа, вызывающего функцию CallerSheet = Application.Caller.Parent.Name For i = 1 To UBound(Wks)

If CallerSheet = Wks(i).Name Then Callerlndex - i

Next i

'Получение значения

SHEETOFFSET2 = Wks(Callerlndex + _

offset).RangefHef.Address)

End Function

Возвращение максимального значения всехрабочихлистов

Если необходимо определить максимальное значение в ячейке В1 в нескольких рабочих листах, то используется формула =МАКС(Лист!:Лист4!В1)

Эта формула возвращает максимальное значение ячейки В1 для листов Лист1, Лист4 и всех листов между ними.

Что же произойдет, если добавить после листа Лист4 новый лист (Лист5)? Формула не будет автоматически изменена, поэтому ее необходимо отредактировать, чтобы включить ссылку на новый лист:

=МАХ{Лист1:ЛИСТ5!В1)

Функция MAXALLSHEETS, показанная ниже, получает аргумент(одна ячейка) и возвращает максимальное значение в этой ячейке во всех рабочих листах данной книги. Например, следующая формулавозвращает максимальное значение в ячейке В1 для всех листов книги:

=MAXALLSHEETS{В1)

Придобавленииновоголистаредактироватьформулунеобязательно.

Function MAXALLSHEETS(cell)

Dim MaxVal As Double

Dim Addr As

String

Dim wksht As

Object

Application.Volatile

Addr =

cell.Range("Al").Address

MaxVal

= -9.9E+307

For Each Wksht In cell.Parent.Parent.Worksheets

If Wksht.Name = cell.Parent.Name And _

Addr -

Application.Caller.Address Then

'

избежание циклической ссылки

Else

 

306

 

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

If IsNumeric{Wksht.Range(Addr)J Then

If Wksht.Range(Addr) > MaxVal Then _

MaxVal = Wksht.Range<Addr).Value End If

End If Next Wksht

If MaxVal = -9.9E+307 Then MaxVal = 0 MAXALLSHEETS = MaxVal

End Function

Оператор For Each использует для доступа к рабочей книге выражение cell.Parent.Parent.Worksheets

Родителем ячейки является рабочий лист, родителем рабочего листа — рабочая книга. Следовательно, цикл For Each проходит по всем рабочим листам в книге. Первый оператор If внутри цикла выполняет проверку, содержит ли ячейка, которая проверяется в данный момент, функцию. Если это так, то ячейка игнорируется во избежание циклической ссылки.

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

Возвращение массива случайных целых чисел без повторов

Функция RANDOM INTEGERS, представленная в этом разделе, возвращает массив целых чисел без повторов. Она предназначена для применения в формуле массива в нескольких ячейках. На рис. П.П показан рабочий лист, использующий в диапазоне ячеек Al:D10 формулу

{=RANDOMINTEGERS()}

Данная формула введена в весь диапазон с помощью комбинации клавиш <Ctrl+Shift+Ent.;r>. Она возвращает массив целых чисел без повторов, упорядоченных произвольным образом. Так как формулу содержат 40 ячеек, целые числа указываются в диапазоне от 1 до 40.

Рис. 11.11. Формула массива генерирует последовательные целые числа без повторов. Все они упорядоченыпроизвольнымобразом

Часть Ш. Visual Basic forApplications

307

Ниже приведен код функции RANDOMINTEGERS.

Function RANDOMINTEGERS() Dim FuncRange As Range

Dim V() As Variant, ValArray(} As Variant Dim CellCounc As Double

Dim i As Integer, j As Integer

Dim r As Integer, с As Integer

Dim Tempi As Variant, Temp2 Аи Variant Dim RCount As Integer, CCount As Integer Randomize

1Создание объекта Range

Set FuncRange = Application.Caller

'Возвращение ошибки, если диапазон FuncRange слишком большой CellCount = FuncRange.Count

If CellCount > 1000 Then

RANDOMINTEGERS = CVErr(xlErrNA)

Exit Function

End If

'

Присваивание переменных

 

RCount = FuncRange.Rows.Count

 

CCount = FuncRange.Columns.Count

 

ReDim V(l To RCount, 1 To CCount)

 

ReDim ValArrayd To 2, 1 To CellCount)

1

Заполнение массива произвольными номерами

'

и последовательными целыми числами

 

For i = 1 То CellCount

 

ValArrayd, i) = Rnd

 

ValArray<2, i) = i

 

Next i

1Сортировка массива ValArray no произвольным числам For i = 1 To CellCount

For j = i + 1 To CellCount

If ValArrayd, i) > ValArrayd, j) Then Tempi = ValArrayd, j)

Temp2 = ValArray(2, j) ValArrayd, j) = ValArrayd, i) ValArray(2, j) = ValArray(2, i) ValArrayd, i) = Tempi ValArray{2, i) = Temp2

End If Next j

Next i

1Занесение произвольных значений в массив V 1 = 0

For r = 1 То RCount

For с = 1 То CCount i = i + 1

V(r, с) = ValArray(2, i) Next с

Next r RANDOMINTEGERS = V

End Function

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

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