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

2 Курс Информатика VBA(ЗО) / Книги / В.Д.Хорев - Самоучитель программирования на VBA в Microsoft Office

.pdf
Скачиваний:
2702
Добавлен:
31.05.2015
Размер:
21.66 Mб
Скачать

Генерация клиентского прайс-листа 41

ка1_Щелкнуть”), и щелкнуть на кнопке Правка. На экране раскроется окно кода с заготовкой макроса. Программный код (исходный текст) макросов, связанных с элементами управления, располагается в программных модулях, и, в отличие от знакомых уже по предыдущими разделам процедурам обработки событий, не связан с объектами рабочей книги.

Программный код будет выполняться по щелчку на созданной кнопке с надписью “Копия”. Вначале создадим максимально упрощенный вариант макроса (листинг 1.3).

ЛИСТИНГ 1.3

Sub Кнопка1_Щелкнуть()

Dim NewWS, OldWS As Worksheet

Set OldWS = ActiveSheet

Set NewWS = Worksheets.Add

OldWS.UsedRange.Copy (NewWS.Range("A1"))

End Sub

Анализ процедуры генерации прайса

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

Выражение Dim объявляет две переменные типа Worksheet — такие переменные предназначены для хранения целого рабочего листа Excel. Переменной OldWS присваивается в качестве значения объект ActiveSheet, то есть текущий рабочий лист с внутрифирменным прайсом. А переменная NewWS становится новым рабочим листом при помощи операции Worksheets.Add, которая, выражаясь языком профессиональных программистов, называется вызовом метода Add, принадлежащего семейству Worksheets. Этот метод можно рассматривать, как аналогию ко-

манды Ëèñò из меню Вставка. Переменная NewWS становится новым рабочим листом, который вставляется в книгу Excel. Новый лист получает имя по умолчанию.

Строка

OldWS.UsedRange.Copy (NewWS.Range("A1"))

в переводе на обычный язык означает: скопировать использованный диапазон объекта OldWS (то есть область прайса из старого листа) в буфер обмена и вставить его из буфера в позицию A1 нового листа. Метод Copy аналогичен действию команды Копировать меню Правка. А благодаря тому, что сразу после обращения к этому методу указана цель копирования, то одновременно выполняется и метод вставки аналогичный действию команды Вставить меню Правка.

Рис. 1.28. При попытке вставить область, содержащую в себе именованные ячейки, предупреждение Excel появится столько раз, сколько таких объектов имеется во вставляемой области

В любом случае, при выполнении копирования и вставки именованных ячеек, которые содержит прайс, Excel выдаст предупреждение, показанное на рис. 1.28.

Действительно, ведь копируется все содержимое всей использованной области листа, и в том числе именованные ячейки “КУРС” и “РОЗНИЦА”, а также ячейки с формулами, где эти имена

42 Глава 1. Excel: cоздание прайс-листа

используются. Если два раза щелкнуть на кнопке Äà, то вставка будет завершена успешно (см.

рис. 1.29).

Рис. 1.29. Если позиция и имя нового листа не указаны, то он вставляется перед текущим листом и получает имя по умолчанию. Область прайс-листа вставлена “как есть“

Новый прайс выглядит почти так же, как и исходный лист: содержимое ячеек и их форматирование, скопирована даже командная кнопка “Копия“. Кроме ширины ячеек, которая стала стандартной. Но это легко исправить. Но, если изучить содержимое ячеек, то можно обнаружить, что в столбцах B и C содержатся все те же формулы, но нет именованных ячеек “КУРС” и “РОЗНИЦА”.

Недостатки простейше процедуры генерации прайса

Конечно, в столь примитивном макросе нет никакого смысла.

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

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

Усовершенствования процедуры генерации прайса

Новую процедуру нетрудно усовершенствовать.

Ограничение области копирования ячеек

Прежде всего, ограничим область копирования только прямоугольником 2х43 (предположим, тренировочный прайс занимает 43 строки). Для этого при вызове метода Copy укажем точный диапазон, а саму операцию копирования разобьем на два этапа: копирование и вставка.

Таким образом, заменим строку

OldWS.UsedRange.Copy (NewWS.Range("A1"))

на:

OldWS.Range("A1", "B43").Copy

NewWS.Range("A1").PasteSpecial

Метод PasteSpecial соответствует команде Специальная вставка из меню Правка.

Генерация клиентского прайс-листа 43

Изменение ширины ячеек и столбцов

Далее, чтобы изменить ширину ячеек нового листа, обратимся к свойству ColumnWidth, которое отвечает за ширину ячейки, а значит, и ширину столбца, поскольку все ячейки в столбце имеют одинаковую ширину. Например, ширину ячейки А1 можно получить при помощи ее свойства ColumnWidth, а присваивание значения этому свойству изменит ширину всего столбца А. Обратиться к ячейке А1 можно при помощи выражения Cells(1, 1) — свойство рабочего листа. Таким образом, в данном случае, ширина первого столбца в новом рабочем листе определяется выражением

NewWS.Cells(1, 1).ColumnWidth

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

NewWS.Cells(1, 1).ColumnWidth = OldWS.Cells(1, 1).ColumnWidth

NewWS.Cells(1, 2).ColumnWidth = OldWS.Cells(1, 2).ColumnWidth

Изменение имени рабочего листа Excel

Наконец, еще одно небольшое усовершенствование — пусть новый лист сразу получает имя, соответствующее его назначению:

NewWS.Name = "Расходные материалы"

см. также в этой главе раздел “Исключение повторения имен листов рабочей книги Excel”.

Тестирование работы новой процедуры генерации прайса

В результате процедура приобретет вид, как на листинге 1.4.

ЛИСТИНГ 1.4

Sub Кнопка1_Щелкнуть()

Dim NewWS, OldWS As Worksheet

Set OldWS = ActiveSheet

Set NewWS = Worksheets.Add

NewWS.Name = "Расходные материалы"

NewWS.Cells(1, 1).ColumnWidth = OldWS.Cells(1, 1).ColumnWidth

NewWS.Cells(1, 2).ColumnWidth = OldWS.Cells(1, 2).ColumnWidth

OldWS.Range("A1", "B43").Copy

NewWS.Range("A1").PasteSpecial

End Sub

Введите этот программный код в подготовленную процедуру Кнопка1_Щелкнуть в окне редактора Visual Basic и, вернувшись в Excel, запустите процедуру при помощи кнопки “Копия”. Получится что-то похожее на рис. 1.30.

44 Глава 1. Excel: cоздание прайс-листа

Рис. 1.30. Столбец B по-прежнему содержит формулы

Странно, почему-то все значения в столбце “Цена“ стали равными нулю. Впрочем, ничего странного, ведь столбец по-прежнему содержит формулы, которые ссылаются на значения в столбце C, а он теперь пуст! Если бы выполнить копирование при помощи команды Правка | Специальная вставка, то можно было бы получить аналогичный результат.

Копирование результатов вычислений по формулам и их форматирования

Чтобы скопировать значения, то есть результаты вычислений по формулам вместо самих формул, в группе параметров Вставить диалогового окна Специальная вставка (см. рис. 1.4) необходимо выбрать переключатель значения. При этом форматирование ячеек не будет скопировано, поэтому команду Специальная вставка придется выполнить еще раз, теперь уже с переключателем в положении форматы. В результате клиентский прайс-лист будет “отрезан” от формул в исходной таблице, но сохранит текущие числовые значения. В коде VBA, при обращении к методу PasteSpecial, переключателю Вставить соответствует параметр Paste. Если необходимо

вставить только значения, то надо добавить оператор Paste:=xlPasteValues. Для вставки форматов параметру необходимо присвоить значение xlPasteFormats. В результате операция копирование и вставка преобразуется следующим образом:

OldWS.Range("A1", "B43").Copy

NewWS.Range("A1").PasteSpecial Paste:=xlPasteValues

NewWS.Range("A1").PasteSpecial Paste:=xlPasteFormats

Исключение повторения имен листов рабочей книги Excel

Кроме того, необходимо решить еще одну маленькую проблему: в рабочей книге Excel не может быть двух листов с одинаковыми именами, поэтому повторный вызов макроса приведет к ошибке. Чтобы при каждом вызове макроса имя вставляемого листа изменялось, включим в состав имени количество листов в рабочей книге. Оно будет увеличиваться с каждым новым листом. Для этого достаточно добавить в строку для присваивания имя новому листу выражение Str(Worksheets.Count), которое на языке программистов означает “число объектов в семей-

стве Worksheets, преобразованное в строковое значение”. Итак, макрос в новой редакции будет выглядеть, как на листинге 1.5.

ЛИСТИНГ 1.5

Sub Кнопка1_Щелкнуть()

Генерация клиентского прайс-листа 45

Dim NewWS, OldWS As Worksheet

Set OldWS = ActiveSheet

Set NewWS = Worksheets.Add

NewWS.Name = "Расходные материалы" + Str(Worksheets.Count)

NewWS.Cells(1, 1).ColumnWidth = OldWS.Cells(1, 1).ColumnWidth

NewWS.Cells(1, 2).ColumnWidth = OldWS.Cells(1, 2).ColumnWidth

OldWS.Range("A1", "B43").Copy

NewWS.Range("A1").PasteSpecial Paste:=xlPasteValues

NewWS.Range("A1").PasteSpecial Paste:=xlPasteFormats

End Sub

Теперь, после выполнения нового макроса, в столбце B клиентского прайса останутся результаты вычислений по формулам, но без самих формул.

Полноценный вариант процедуры генерации прайса

Однако, даже усовершенствованный макрос все еще не делает того, ради чего его разрабатывали — не пропускает заштрихованные позиции при копировании их в клиентский прайс-лист. Но теперь все готово, чтобы “его этому научить”.

Необходимо, чтобы макрос применял операцию копирования не ко всей области прайс-листа сразу, а к каждой строке поочередно, анализируя при этом состояние ячейки в столбце A. Для этого потребуются две переменные, способные хранить целочисленные значения. Переменная L будет использована для последовательного перебора номеров всех строк в исходной таблице, а в переменной M будет подсчитываться число строк нового листа — заштрихованные строки будут пропускаться. Для этого используем оператор цикла, который уже был рассмотрен в этой главе.

см. в этой гл. раздел “Автоматическое выделение позиций в прайсе” (Листинг 1.2).

M = 3

For L = 3 To 43

...

M = M + 1

Next L

Переменная L будет автоматически принимать значения от 3 до 43 (от 3, потому что первые две строки пока будут пропущены), а переменная M будет… принимать значения от 3 до 43, если ни одна из строк не заштрихована. Если исходная таблица содержит заштрихованные ячейки, их надо пропустить. Для этого внутрь цикла нужно вставить условный оператор, который должен выявлять заштрихованные ячейки в исходном списке. В случае, если ячейка столбца A не заштрихована, выполняется увеличение значения переменной M и копирование строки в новый прайс. Если ячейка столбца A заштрихована, тогда значение переменной M должно остаться неизменным.

см. также в приложении раздел “Арифметические операции”.

Как проверить, заштрихована ли ячейка, уже было рассмотрено, поэтому сразу можно набросать эскиз цикла:

46 Глава 1. Excel: cоздание прайс-листа

M = 3

For L = 3 To 43

If OldWS.Cells(L, 1).Interior.Pattern <> xlPatternGray25 Then

...

M = M + 1

End If

Next L

см. в этой гл. раздел “Анализ стандартной процедуры обработки события — двойного щелчка мышью на ячейке листа Excel”.

Осталось придумать, как осуществлять копирование строк — ведь в нашем случае копировать строки целиком нельзя. С помощью еще одной переменной, назовем ее N, можем копировать по две ячейки L-строки исходного листа в M-строку нового листа:

For N = 1 To 2

OldWS.Cells(L, N).Copy

NewWS.Cells(M, N).PasteSpecial Paste:=xlPasteValues

NewWS.Cells(M, N).PasteSpecial Paste:=xlPasteFormats

Next N

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

ЛИСТИНГ 1.6

Sub Кнопка1_Щелкнуть()

Dim NewWS, OldWS As Worksheet

Dim L, M, N As Integer

Set OldWS = ActiveSheet

Set NewWS = Worksheets.Add

NewWS.Name = "Расходные материалы" + Str(Worksheets.Count)

NewWS.Cells(1, 1).ColumnWidth = OldWS.Cells(1, 1).ColumnWidth

NewWS.Cells(1, 2).ColumnWidth = OldWS.Cells(1, 2).ColumnWidth

M = 3

For L = 3 To 43

If OldWS.Cells(L, 1).Interior.Pattern <> xlPatternGray25 Then

For N = 1 To 2

OldWS.Cells(L, N).Copy

NewWS.Cells(M, N).PasteSpecial _

Paste:=xlPasteValues

NewWS.Cells(M, N).PasteSpecial _

Paste:=xlPasteFormats

Next N

M = M + 1

Генерация клиентского прайс-листа 47

End If

Next L

End Sub

Недостатки нового варианта процедуры генерации прайса

Наконец-то! Теперь макрос делает то, ради чего он создан. Но о совершенства ему еще далеко.

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

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

Наконец, фиксированную нижнюю границу в 43 строки необходимо заменить выражением OldWS.UsedRange.Rows.Count, которое возвращает нижнюю границу использованного диапазона на исходном листе, поскольку макрос претендует теперь на универсальность.

Окончательный вариант процедуры генерации прайса

Копирование диапазона A1:B2 не представляет никакой трудности, здесь нужно применить тот же самый метод Copy ко всему диапазону, а для группирования данных в новом листе воспользуемся свойством OutlineLevel, в котором содержится уровень группировки той строки, о свойстве

(OutlineLevel) которой идет речь. Достаточно перенести значения из свойства строк OutlineLevel исходной таблицы и новая таблица будет сгруппирована аналогичным образом. Таким образом, в своем окончательном варианте “макрос выборочного копирования строк” приобретает вид, как на листинге 1.7.

ЛИСТИНГ 1.7

Sub Кнопка1_Щелкнуть()

Dim NewWS, OldWS As Worksheet

Dim L, M, N As Integer

Set OldWS = ActiveSheet

Set NewWS = Worksheets.Add

NewWS.Name = "Расходные материалы" + Str(Worksheets.Count)

NewWS.Cells(1, 1).ColumnWidth = OldWS.Cells(1, 1).ColumnWidth

NewWS.Cells(1, 2).ColumnWidth = OldWS.Cells(1, 2).ColumnWidth

M = 3

For L = 3 To OldWS.UsedRange.Rows.Count

If OldWS.Cells(L, 1).Interior.Pattern <> xlPatternGray25 Then

For N = 1 To 2

OldWS.Cells(L, N).Copy

NewWS.Cells(M, N).PasteSpecial Paste:=xlPasteValues

NewWS.Cells(M, N).PasteSpecial Paste:=xlPasteFormats

NewWS.Rows(M).OutlineLevel = OldWS.Rows(L).OutlineLevel

Next N

M = M + 1

End If

48 Глава 1. Excel: cоздание прайс-листа

Next L

OldWS.Range("A1", "B2").Copy

NewWS.Range("A1", "B2").PasteSpecial

End Sub

Что ж, задача решена. Готовый клиентский прайс-лист (рис. 1.31) нетрудно теперь опубликовать в виде Web-документа, отпечатать или передать потенциальным клиентам в виде файла на дискете или вложения в сообщение электронной почты.

Рис. 1.31. Теперь скопированы также заголовок и уровни группировки строк

Глава 2

Excel: прайс-лист для автоматического составления заказа

Постановка задачи

Задача автоматизации прайс-листа, как и любая задача автоматизации многомерна. Достаточно посмотреть на столбцы с товарами и ценами с другой стороны, как бы “примерить” к ним другие практические операции, взятые из повседневной офисной практики, и на ум приходят совершенно другие подходы в использовании прайс-листа.

Назначение прайс-листа, в конечном счете, состоит даже не в том, чтобы его прочитал потенциальный клиент. Конечная цель прайс-листа — обеспечение продаж. Клиент прочитал прайслист, нашел приемлемые для себя позиции, и (внимание, всему персоналу фирмы — не дышать!) хочет сделать заказ. “Выпишите счет, пожалуйста”. И тут начинается…….

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

Хороший пример такого товара — персональный компьютер, который состоит из набора взаимосвязанных частей, каждая из которых существует и предлагается на рынке во многих вариантах. Очень часто, конфигурацию конкретного компьютера клиент заказывает сам, выбирая монитор, тип процессора, емкость и модель жесткого диска, а также многое другое. Выбирает он все это, естественно, из соответствующих разделов прайс-листа. Компьютер можно укомплектовать одним из десятков процессоров, но не всякий процессор подойдет к конкретной материнской плате. Каждое сочетание тут обладает своими особенностями. А какой видеоадаптер выбрать? Ой, что-то дороговато получается, может, сэкономить на ОЗУ или выбрать жесткий диск подешевле? А вот на мониторе не экономят — зрение дороже, но возникает вопрос, достаточен ли этот видеоадаптер для того, чтобы великолепные характеристики монитора не пропадали напрасно? Вопросы и вопросы, варианты и варианты…

За каждым из таких вариантов стоит конкретная цена, и клиенту было бы очень удобно, если бы он мог с легкостью выбирать варианты, как вздумается, все время видеть “вытекающую из варианта” цену компьютера и при этом не попадать на запретную территорию — те сочетания компонентов, которые технически неработоспособны. А раз уж заказ сформирован, то неплохо было бы тут же отпечатать счет….

Что ж, это хорошая задача. Она хороша, во-первых, тем, что конкретно полезна — выбор конфигурации компьютера стал в наше время едва ли не массовым занятием. Во-вторых, принцип решения этой задачи легко распространить на многие сходные случаи, при этом решение не придется усложнять. Наконец, она хороша тем, что легко и естественно вписывается в практически применяемые способы работы — ведь прайсы в форме рабочих листов Excel существуют и используются повсеместно. В том числе речь идет и о прайс-листах фирм, продающих компьютеры с конфигурацией “на заказ”. Таким образом, объект автоматизации уже существует, остается лишь применить к нему инструментальные средства MS Office….

Соседние файлы в папке Книги