
2 семестр / vba_2002
.pdf
еще на три месяца. Если диаграмма создается с помощью кода VBA, в котором "известно" об источнике данных, то диапазон расширить довольно легко. Но если код должен управлять произвольной диаграммой, то использование кода VBA для определения источника данных диаграммы может оказаться непростой задачей.
Рис. 18.6.Какойизспособовопределенияисточ) Q данных диаграммы являетсялучшим?
Объект Series
На наш взгляд, в Excel имеется серьезный недостаток: в программе не существует непосредственного способа определения диапазона данных, которые используются для создания диаграммы. Обратимся к объектной модели диаграммы.
Объект Series содержится внутри объекта Chart. SeriesCollection является коллекцией объектов Series для определенного объекта Chart. Если диаграмма отображает две последовательности данных, в этой коллекции содержится два объекта. Можно ссылаться на определенный объект series по индексу. Следующее выражение создает переменную, представляющую первый объект Series активной диаграммы:
Set MySeries = ActiveChart.SeriesCollection(l)
Объект Series наделен несколькими свойствами, но в данном случае нас интересуют только три из них.
•Formula. Возвращает или задает формулу РЯД для объекта Series. Когда выделяется последовательность диаграммы, формула РЯД отображается на панели формул. Свойство Formula возвращает формулу в виде текстовой строки.
•Values. Возвращает или задает коллекцию всех значений в последовательности. Это может быть диапазон на рабочем листе или массив постоянных значений, но не их комбинация.
•XValues. Возвращает или устанавливает массив значений вдоль оси X для последовательности на диаграмме. Свойство XValues может содержать диапазон на рабочем листе или массив значений, но не их комбинацию.
Поэтому, если код должен оперировать диапазоном данных, который используется конкретной последовательностью на диаграмме, понятно, что необходимо применить свойство
ЧастьV.Совершенныеметодыпрограммирования |
469 |

Values объекта S e r i e s . Свойство XValues также используется для получения диапазона, содержащего значения вдоль оси X (или подписи категорий). Теоретически синтаксис правильный, но на практике он не выполняется. При назначении диапазона с помощью свойства XValues происходит автоматическая установка значений Value для каждой ячейки в диапазоне (т.е. массива значений).
Простая демонстрация
Если вы котите узнать, приводит ли доступ к значению свойства Value к необходимым результатам, начните с создания новой рабочей книги и создайте простую диаграмму, подобную показанной на рис. 18.7. Диаграмма использует диапазон А1:АЗ в качестве значения свойства Values (диапазон XValues отсутствует).
Добавьте модуль VBA и введите код следующей процедуры.
Sub Test 10
Dim DataRange As Range
Set DataRange = ActiveSheet.Range("A1:A2") ActiveSheet.ChartObjects(l). _
Chart.SeriesCollection(l).Values = DataRange End Sub
Puc.IS.7.Воспользуйтесьэтойдиограммойдлятого, чтобы разобраться, почему свойства Values и XValues не работают так, как ожидается
Эта процедура изменяет источник данных для последовательностей диаграммы на А1: А2. Выполните процедуру и обратите внимание на то, что на диаграмме отображается только два
столбца.
После этого запустите приведенную ниже процедуру.
Sub Test2()
Dim DataRange As Range
Set DataRange = Sheets("Лист!").ChartObjects(1). _ Chart.SeriesCollection(1).Values
End Sub
Данная процедура создает объект Range, который называется DataRange. Объект создастся на основе последовательностей диаграммы. При выполнении этой процедуры будет выдано сообщение об ошибке: отсутствует необходимый объект. Проблема заключается в том, что значение Values объекта S e r i e s (члена коллекции S e r i e s C o l l e c t i o n ) всегда возвращает массив — объект Range никогда не возвращается. Если это звучит неубедительно.
470 |
Глава 18. Управление диаграммами |

то выполните оператор, который использует функцию VBA isArray для определения того, является ли массивом ее аргумент:
MsgBox IsArray(Sheets("Лист1"),ChartObjectsШ. _ Chart.SeriesCollection(l).Values)
В частности, свойство Values возвращает массив переменного типа. К сожалению, не существует непосредственного способа получить объект Range на основе объекта Series.
Выполните следующую процедуру:
Sub Test3()
Dim ChartData As Variant
ChartData = Sheets("Лист1") .chartObjects(1) . _ Chart.SeriesCollection(1).Values
For i = 1 To UBound(ChartData} MsgBox ChartData(i)
Next i End Sub
В данном случае ChartData определяется в виде массива переменного типа. Цикл For Next используется для отображения всех элементов этого массива.
Свойству Values объекта Series можно присваивать объект или массив, Но при чтении указанного свойства всегда возвращается массив. Другими словами, массив переменного типа может принять объект, но никогда не сможет возвратить объект.
Создание собственной функции
Убедившись в том, что в Excel имеется серьезная недоработка, можно использовать код VBA для создания собственного решения. Именно по этому пути мы и будем следовать далее. В этом разделе рассматривается функция VBA, которая возвращает объект Range объекта Series.
В следующем разделе рассматривается модуль класса, который упрощает рассматриваемуюдалее процедуру.
Функция, которая называется GetChartRange, принимает три аргумента.
•Cht. Объект Chart.
•series . Целое число, которое соответствует номеру объекта Series в коллекции SeriesCollection,
•ValsOrX. Строка, определяющая тип значения values или xvalues (не чувствительна к регистру).
Представленные ниже операторы демонстрируют использование функции GetChartRange.
Set MyChart = ActiveSheet.ChartObjects(1).Chart
Set DataRange = GetChartRange(MyChart, 1, "values") MsgBox DataRange.Address
Первый из приведенных операторов создает переменную объекта диаграммы. Второй оператор создает объект Range, вызывая процедуру GetChartRange. Возвращаемый функцией DataRange объект Range содержит данные, которые представляются на диаграмме с помощью первого объекта Series. Третий оператор всего лишь отображает адрес диапазона.
Часть V. Совершенные методы программирования |
471 |

Процедура GetChartRange анализирует формулу РЯД, которая представлена текстовой строкой, извлекая из нее адрес диапазона. Процедура GetChartRange обладает одним ограничением: она не применяется к последовательностям диаграммы, которые соответствуют прерывающемуся диапазону. Если последовательность представлена прерывающимся диапазоном, ссылки на этот диапазон в формуле РЯД заключаются в скобки и разделяются точками с запятыми. Процедура GetChartRange анализирует строку формулы только по точкам с запятыми, полностью игнорируя скобки. Если формула РЯД содержит более трех точек с запятыми, то это указывает на использование прерывающегося диапазона. В данном случае приведенный алгоритм анализа не используется.
Описанная функция анализирует формулу SERIES, которая синтаксически не соответствует формуле РЯД русской версии Excel. Соответственно, формула анализируется не по точкам с запятыми, а по запятым (которые разделяют аргументы формул в англоязычной версии Excel). Примите это к сведению при анализе листинга функции. — Прим. ред.
Рабочая книга с функцией GetChartRange находится на Web-узле издательства. Рабочая книга также содержит процедуры, которые демонстрируют использование этой функции (рис, 18.11).
Рис. 18.S. Процедура GetChartRange определяет диапазоны, на основе которых построенадиаграмма
Исходный код процедуры GetChartRange приводится в листинге 18.1.
Листинг 18.1. Анализ формулы РЯД для получения источника данных диаграммы
Function GetChartRange(cht, series, ValOrX) As Range
'cht: объект Chart
' |
series: целое, представляет количество объектов Series |
' |
ValOrX: строка, равная "values" или "xvalues" |
|
Dim Sf As String |
472 |
Глава 18. Управлениедиаграммами |
Dim CommaCnt As Integer
Dim Commas() As Integer
Dim ListSep As String * 1
Pim Temp As String
Dim i As Integer
Set GetChartRange = Nothing
On Error Resume Next
'Получение формулы SERIES
Sf = cht.SeriesCollection(series).Formula
1 |
Проверка непрерывности диапазона по количеству запятых |
1Также определяется расположение каждой запятой CommaCnt = О
ListSep = Chr(44) For i = 1 То Len(Sf)
If Mid{Sf, i, 1) = ListSep Then
CommaCnt = CommaCnt + 1
ReDim preserve Commas{CommaCnt)
Commas(CommaCnt) = i
End If
Next i
If CommaCnt > 3 Then Exit Function
1XValues или Values? Select Case UCase(ValOrX)
Case "XVALUES"
|
Текст между 1-ой and 2-ой запятой в формуле |
|
Temp = Mid(Sf, Commas(l) + 1, Commas(2) - Commas(l) - 1) |
|
Set GetChartRange = Range(Temp) |
|
Case "VALUES" |
1 |
Текст между 2-ой and 3-ей запятой в формуле |
|
Temp = MidfSf, Commas(2) + 1, Commas(3) - Commas(2) - 1) |
|
Set GetChartRange = Range(Temp) |
End |
Select |
End Function
Второй метод определения источника данных для диаграммы
Функция GetChartRange, которая рассматривалась в предыдущем разделе, вам обязательно пригодится в работе, но методика, представленная далее, может оказаться более эффективной. В этой методике используется модуль класса для создания нового класса, который называется ChartSeries. Функция GetChartRange позволяет получить диапазоны, указанные в формуле РЯД (SERIES). Класс ChartSeries является более гибким, поскольку позволяет программно выполнить две задачи: определить диапазоны, которые указаны в формуле SERIES, и изменить эти диапазоны.
Свойства класса ChartSeries
Когда модуль класса ChartSeries применяется в рабочей книге, можно создавать новые объекты ChartSeries и использовать код VBA для получения доступа к следующим их свойствам.
Veen V. Совершенные методыпрограммирования |
473 |

•Chart (чтение/запись);
•ChartSeries (чтение/запись);
•SeriesName (чтение/запись);
•XValues (чтение/запись);
•Values (чтение/запись);
•PlotOrder (чтение/запись);
•SeriesNameType (только чтение);
•XValuesType (только чтение);
•ValuesType (только чтение);
•PlotOrderType (только чтение).
Все эти свойства определены в модуле класса ChartSeries. Обратите внимание на то, что некоторые из них предназначены только для чтения. С такими свойствами вы можете только ознакомиться в коде, но не изменять их значения.
Код класса ChartSeries слишком длинный для того, чтобы приводить его на страницах книги. Рабочая книга, которая демонстрирует использование класса ChartSeries, расположена на Web-узле издательства. Код неплохо документирован, поэтому с ним можно легко ознакомиться. Мы рекомендуем сделать это — таким образом, вы получите представление о принципах его работы. Модуль класса можно скопировать в любую рабочую книгу.
Использование класса ChartSeries
Перед тем, как использовать класс ChartSeries, удостоверьтесь, что модуль класса скопирован в рабочую книгу. Простая процедура, приведенная ниже, демонстрирует принцип использования класса ChartSeries. Предполагается, что первый рабочий лист содержит объект ChartObject.
Sub ChartSeriesDemof)
Dim MySeries As New ChartSeries
MySeries.Chart = Sheets(1).chartObjects(1).Chart MySeries.ChartSeries = 1
If MySeries.ValuesType = "Range" Then
MsgBox MySeries.Values.Address Else
MsgBox MySeries.Values End If
End Sub
Процедура начинается с декларации переменной MySeries, которая имеет тип ChartSeries. Далее первая диаграмма на первом рабочем листе присваивается свойству Chart. Следующий оператор указывает число последовательностей (1) и определяет это число в качестве значения свойства ChartSeries.
Оператор Select Case оценивает значение свойства ValuesType. Это свойство указывает тип данных, который используется в последовательности. Возвращаемая оператором строка равна или Range, или Array. Если в качестве источника применяется диапазон, то окно сообщения отображает адрес этого диапазона. Если в качестве источника данных используется массив, то окно сообщения отображает содержимое этого массива. На рис. 18.9 показан результат выполнения процедуры ChartSeriesDemo.
474 |
Глава 18. Управление диаграммами |

Рис.18.9.Использованиемодуляклассадляопределенияисточникаданных,применяемых в диаграмме
ЕщеодинпримерклассаChartSeries
На рис. 18.10 показана диаграмма, которая является "интерактивной". Диаграмма отображает данные, которые хранятся в столбцах А и В, а кнопки на диаграмме предоставляют пользователю возможность изменять диаграмму так, чтобы на ней отображалось различное количество месяцев или дней. Применение класса C h a r t S e r i e s намного упрощает программирование такого поведения диаграммы.
Рис.18.10.Использованиемодуляклассадляизмененияданных.ото6ражие.чыхнадиаграмм
ЧастьV.Совершенныеметодыпрограммирования |
475 |

Если щелкнуть на кнопке Меньше месяцев, то будетзапушенаследующаяпроцедура.
Private Sub ConnnandButtonl_Click ()
' Отображение данных для меньшего числа месяцев Dim TheChart As Chart
Dim MySeries A3 New ChartSeries
Set TheChart = ActiveSheet.ChaxtObjects(1).Chart With MySeries
'определение диаграммы
.Chart = TheChart
'определение последовательностей
.ChartSeries = 1
'подписи категорий в диапазоне If .XValuesType = "Range" Then
'существует хотя бы одна подпись numrows = .XValues.Rows.Count If numrows <> 1 Then _
Set MewRange « .XValues.Resize(numrows - 1, 1) If numrows > 1 Then .XValues = NewRange
End If
1 значения в диапазоне
If .ValuesType = "Range" Then 'существуем хотя бы одно значение numrows = .Values.Rows.Count
If numrows о 1 Then
Set NewRange = .Values.Resize(numrows - 1, 1) If numrows > 1 Then .Values * NewRange
End If End With
End Sub
Данная процедура создает новый объект C h a r t S e r i e s . Она получает доступ к свойству XValues (которое возвращает объект Range) и переопределяет размер диапазона с использованием метода R e s i z e объекта Range. После того, как диапазон будет уменьшен на одну строку, свойству XValues присваивается новый диапазон. Затем в коде выполняется подобная операция по отношению к свойству V a l u e s объекта C h a r t S e r i e s .
Код отображения большего объема данных подобен рассмотренному ранее. Разница заключается лишь в том, что диапазоны XValues и Values увеличиваются с тем, чтобы включить в себя дополнительные строки.
Обратитесь к главе 29 для получения дополнительной информации о создании и использовании модулей классов.
Отображение подписей для данных на диаграмме
Многие пользователи не удовлетворены несовершенством системы добавления подписей на диаграммы Excel. Например, рассмотрим график, который показан на рис. 18.11. Было бы неплохо отображать подписи для каждой точки данных отображаемого диапазона. Но можно провести в поисках весь день, но так и не найти команды Excel, которая позволит разместить необходимые подписи в области диаграммы (такой команды просто не существует). Подписи к точкам данных ограничены только реальными значениями, если, конечно, не отредактировать каждую точку вручную и не ввести самостоятельно требуемый текст.
476 |
Глава 18. Управление диаграммами |

Рис. 18.И. График безподписей данных
Листинг 18.2 содержит простую процедуру, которая управляет первой диаграммой на активном листе. Она запрашивает у пользователя диапазон и просматривает коллекцию P o i n t s для того, чтобы заменить свойство Tex t каждого элемента коллекции на соответствующийфрагментданных,которыйсодержитсявуказанномдиапазоне.
Листинг 18.2. Получение подписей для точек данных
Sub DataLabelsFromRange()
Dim DLRange As Range
Dim Cht As Chart
Dim i As Integer, Pts As Integer
1Определение диаграммы
Set Cht = ActiveSheet-ChartObjecCs(1).Chart
1Запрос диапазона
On Error Resume Next
Set DLRange = Application.InputBox _ (prompt:="Укажите диапазон с подписями". Type:=8)
If DLRange Is Nothing Then Exit Sub On Error GoTo 0
1Добавление подписей Cht.SeriesCollection{l).ApplyDataLabels _
Type-.^xlDataLabelsShowValue,_ AutoText:=True, _ LegendKey:=False
1Просмотр диапазона и назначение подписей Pts = Cht.SeriesCollection(l).Points,Count For i = 1 To Pts
Cht.SeriesCollection(l). _
Points(i).DataLabel.Text = DLRange(i)
Next i
End Sub
Часть V. Совершенные методы программирования |
477 |

Этот пример доступен на Web-узле издательства.
На рис. 18.12 показана диаграмма после запуска процедуры DataLabelsFromRange и указания в качестве исходных данных диапазона А2 : А9.
Рис. 18.12Эта точечная диаграмма содержит подписи для точек данных(достигаетсяспомощьюдополнительногокодаVBA)
Предыдущая процедура является достаточно грубой. Кроме того, с ее помощью нельзя выполнить глубокую проверку ошибочных состояний. Данная процедура работает только с первым объектом Series, Пакет Power Utility Pak содержит намного более сложный инструмент создания подписей для данных на диаграмме.
Отображение диаграммы в пользовательском диалоговом окне
Вглаве J5 рассмотрен способ отображения диаграммы в пользовательском диалоговом окне. Описанный метод заключается в сохранении диаграммы в виде файла формата GIF, после чего необходимо загрузить последний в элемент управления Image, размещаемый в диалоговом окне UserForm.
Впримере, приведенном в этом разделе, используется такой же подход. Но существует одна особенность: диаграмма создается "на лету" и использует данные строки активной ячейки (рис. 18.13).
Диалоговое окно UserForm этого примера довольно простое. Оно содержит элемент управления Image и элемент управления CommandButton (кнопка Закрыть). Рабочая книга, в которой находятся данные, имеет кнопку, щелчок на которой выполняет следующую процедуру:
Sub ShowChart()
Dim UserRow As Long
Us.erRow = ActiveCell .Row
478 |
Глава 18. Управление диаграммами |