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

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

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

Сравнительный анализ прайс-листов 123

не наступит. Исходный текст макроса в этом случае можно поместить в обработчик события рабочей книги Open (процедура обработки этого события должна называться Workbook_Open) — тогда макрос будет выполняться при открытии рабочей книги. Чтобы создать обработчик этого события, необходимо выбрать двойным щелчком в окне проекта Visual Basic элемент ThisWorkbook, а в списках окна кода — элементы Workbook и Open.

см. также в приложении раздел “Как открыть файл (оператор Open)”.

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

Итак, создав тем или иным образом заготовку процедуры, приступим к разработке исходного текста макроса, который должен формировать сводный прайс-лист на основе прайсов “А” и “Б”.

Создание процедуры Сводка()

Вначале необходимо объявить объектные переменные, которые будут содержать в себе прайслисты “А” и “Б”, а также сводный прайс-лист. Назовем их, соответственно, PriceA, PriceB и PriceSvod. Объявить их необходимо как Worksheet, поскольку речь идет о рабочих листах.

Целочисленные переменные A, B и SvodCount будут использованы в качестве счетчиковуказателей строк для соответствующих листов — их также необходимо предварительно объявить как Integer.

Первый шаг состоит в том, чтобы создать переменные-объекты, заключающие в себе рабочие листы Excel, которые и будут обрабатываться. Поскольку предполагается, что рабочий лист сводного прайса является текущим, можно обратиться к нему, как к объекту ActiveSheet:

Set PriceSvod = ActiveSheet

Будем считать, что подлежащие анализу прайсы “А” и “Б” размещены на рабочих листах “Прайс-А” и “Прайс-Б”, которые находятся в книгах PriceA.xls и PriceB.xls, которые, в свою очередь, находятся в корневом каталоге диска C:. В этом случае можно создать переменные PriceA и PriceB следующим образом:

Set PriceA = Workbooks.Open("C:\PriceA.xls").Worksheets("Прайс-А")

Set PriceB = Workbooks.Open("C:\PriceB.xls").Worksheets("Прайс-Б")

Вызовом метода Open семейства рабочих книг (Workbooks) в это семейство добавляется книга, содержащаяся в указанном файле. И уже в семействе рабочих листов открытой книги (Worksheets) оператор Set найдет необходимый лист и присвоит его в качестве значения соответствующей переменной.

Счетчик строк сводного прайса необходимо установить на строку 2, чтобы пропустить заголовок:

SvodCount = 2

Теперь все готово для просмотра прайс-листа “А” и сопоставления его с прайс-листом “Б”. Чтобы просмотреть все строки диапазона “Наименование” в листе “А”, используем цикл For:

For A = 1 To PriceA.Range("Наименование").Rows.Count

...

Next A

Свойство Count семейства строк диапазона (Rows) задает верхнюю границу просмотра, поскольку в нем содержится количество строк в диапазоне (это число может меняться при вставке и удалении строк, и потому заранее неизвестно).

124 Глава 4. Практикум программирования на VBA для Excel и Word

Первое, что следует сделать при просмотре очередной строки прайса “А”, это скопировать ее в соответствующую позицию сводного прайса, поскольку в одном из анализируемых прайс-листов эта позиция уже встретилась:

PriceSvod.Cells(SvodCount, 1) = _

PriceA.Range("Наименование").Cells(A, 1)

PriceSvod.Cells(SvodCount, 2) = PriceA.Range("Цена").Cells(A, 1)

Копирование осуществляется в 1 и 2 столбцы SvodCount-й строки, то есть в столбцы, соответствующие наименованию товара и его цене по прайсу “А”.

Тут же, не покидая SvodCount-й строки сводного прайс-листа, необходимо просмотреть прайс “Б”: а нет ли там такой же позиции?

Если наименование одной из позиций прайса “Б” совпало с текущей позицией прайса “А”, то соответствующее ей значение цены необходимо добавить в сводный прайс-лист, теперь уже в 3-й столбец, который соответствует ценам прайса “Б”:

For B = 1 To PriceB.Range("Наименование").Rows.Count

If PriceB.Range("Наименование").Cells(B, 1) = _

PriceA.Range("Наименование").Cells(A, 1) _

Then

PriceSvod.Cells(SvodCount, 3) = _

PriceB.Range("Цена").Cells(B, 1)

PriceB.Range("Наименование").Cells(B, 1).Value = ""

End If

Next B

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

Если бы сравнительному анализу подвергались не два, а три или более прайс-листов, то в этом месте необходимо было бы выполнить аналогичные действия для прайсов “В”, “Г” и т.д.

Наконец, нужно передвинуть счетчик-указатель строки сводного листа на следующую строку:

SvodCount = SvodCount + 1

После того, как переменная A “дойдет” до конца диапазона “Наименование” прайс-листа “А”, на рабочем листе сводного прайса будет сформирован список всех позиций “А”, причем для тех из них, которые обладают “двойником” в листе “Б”, в 3-м столбце будет указана цена прайса “Б”. Но задача еще не решена! В прайсе “Б” могут найтись позиции, которых не было в прайсе “А”. Чтобы обнаружить таковые, нужно просмотреть теперь весь диапазон “Наименование” в прайсе “Б”.

В этом случае пригодится проявленная ранее предусмотрительность: все уже помещенные в сводку позиции из прайса “Б” исключены (для них в столбец “Наименование” была записана пустая строка), поэтому нет необходимости в дополнительных проверках — просто можно просмотреть лист “Б” точно так же, как это было сделано с листом “А”. Единственная особенность, которую необходимо здесь учесть, состоит в том, что вначале необходимо проверить, существуют ли очередная позиция. Иными словами, не “вычеркнута“ ли она из рассмотрения по той причине, что она встретилась при просмотре листа “А” и уже помещена в сводный прайс-лист. Таким образом, конструкцию цикла For необходимо дополнить наложением условия “ячейка в столбце наименования не пуста”:

For B = 1 To PriceB.Range("Наименование").Rows.Count

If PriceB.Range("Наименование").Cells(B, 1) <> "" Then

Сравнительный анализ прайс-листов 125

...

End If

Next B

Точно таким же образом в этом цикле в сводный прайс будет занесена любая встретившаяся непустая позиция:

PriceSvod.Cells(SvodCount, 1) = _

PriceB.Range("Наименование").Cells(B, 1)

PriceSvod.Cells(SvodCount, 3) = PriceB.Range("Цена").Cells(B, 1)

Затем, по логике копирования, необходимо проверить, нет ли такой позиции в прайсе “А”:

For A = 1 To PriceA.Range("Наименование").Rows.Count

If PriceA.Range("Наименование").Cells(A, 1) = _

PriceB.Range("Наименование").Cells(B, 1) _

Then

PriceSvod.Cells(SvodCount, 2) = _

PriceA.Range("Цена").Cells(A, 1)

End If

Next A

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

Завершаться каждый проход этого цикла должен очередным шагом счетчика-указателя строк в сводном прайс-листе:

SvodCount = SvodCount + 1

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

чения цены, выполнить проверку и изменить свойство Bold объекта Font, принадлежащего соответствующей ячейке. Например, это можно было бы сделать следующим образом:

If PriceSvod.Cells(SvodCount, 2) < PriceSvod.Cells(SvodCount, 3) Then

PriceSvod.Cells(SvodCount, 2).Font.Bold = True

Else

PriceSvod.Cells(SvodCount, 3).Font.Bold = True

End If

Автоматическое закрытие файла с отменой сделанных в нем изменений

Наконец, необходимо закрыть использованные рабочие листы и сделать текущим сводный прайс-лист. Проблема заключается в том, что такой объект, как рабочий лист закрыть нельзя. Закрыть можно рабочую книгу, где он содержится. Ссылка на “свою” рабочую книгу у каждого лис-

та Excel доступна через свойство Parent:

PriceA.Parent.Close SaveChanges:=False

PriceB.Parent.Close SaveChanges:=False

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

126 Глава 4. Практикум программирования на VBA для Excel и Word

см. также в приложении раздел “Закрытие файлов (операторы Reset, Close)”.

Кроме этого, следует присвоить объектным переменным значение Nothing, чтобы освободить занятую ими память:

Set PriceA = Nothing

Set PriceB = Nothing

см. также в гл. 3 раздел “Освобождение системной памяти компьютера”.

И вот, макрос готов. Полный его исходный текст представлен в листинге 4.4.

ЛИСТИНГ 4.4

Sub Сводка()

Dim PriceA As Worksheet

Dim PriceB As Worksheet Dim PriceSvod As Worksheet

Dim A, B, SvodCount As Integer

Set PriceSvod = ActiveSheet

Set PriceA = Workbooks.Open("C:\PriceA.xls").Worksheets("Прайс-А")

Set PriceB = Workbooks.Open("C:\PriceB.xls").Worksheets("Прайс-Б")

SvodCount = 2

For A = 1 To PriceA.Range("Наименование").Rows.Count

PriceSvod.Cells(SvodCount, 1) = _

PriceA.Range("Наименование").Cells(A, 1)

PriceSvod.Cells(SvodCount, 2) = _

PriceA.Range("Цена").Cells(A, 1)

For B = 1 To PriceB.Range("Наименование").Rows.Count

If PriceB.Range("Наименование").Cells(B, 1) = _

PriceA.Range("Наименование").Cells(A, 1) _

Then

PriceSvod.Cells(SvodCount, 3) = _

PriceB.Range("Цена").Cells(B, 1)

PriceB.Range("Наименование").Cells(B, 1).Value = ""

End If

Next B

If PriceSvod.Cells(SvodCount, 2) < PriceSvod.Cells(SvodCount, 3) Then

PriceSvod.Cells(SvodCount, 2).Font.Bold = True

Else

PriceSvod.Cells(SvodCount, 3).Font.Bold = True

End If

SvodCount = SvodCount + 1

Next A

For B = 1 To PriceB.Range("Наименование").Rows.Count

Сравнительный анализ прайс-листов 127

If PriceB.Range("Наименование").Cells(B, 1) <> "" Then

PriceSvod.Cells(SvodCount, 1) = _

PriceB.Range("Наименование").Cells(B, 1)

PriceSvod.Cells(SvodCount, 3) = _

PriceB.Range("Цена").Cells(B, 1)

For A = 1 To _

PriceA.Range("Наименование").Rows.Count

If PriceA.Range("Наименование").Cells(A, 1) = _

PriceB.Range("Наименование").Cells(B, 1) _

Then

PriceSvod.Cells(SvodCount, 2) = _

PriceA.Range("Цена").Cells(A, 1)

End If

Next A

If PriceSvod.Cells(SvodCount, 2) < _

PriceSvod.Cells(SvodCount, 3) _

Then

PriceSvod.Cells(SvodCount, 2).Font.Bold = True

Else

PriceSvod.Cells(SvodCount, 3).Font.Bold = True

End If

SvodCount = SvodCount + 1

End If

Next B

PriceA.Parent.Close SaveChanges:=False

PriceB.Parent.Close SaveChanges:=False

Set PriceA = Nothing

Set PriceB = Nothing

PriceSvod.Activate

End Sub

Чтобы проверить макрос в действии, необходимо открыть сводный прайс-лист и выполнить макрос Сводка при помощи команды Сервис | Макрос | Макросы. Результат выполнения макроса изображен на рис. 4.8.

128 Глава 4. Практикум программирования на VBA для Excel и Word

Рис. 4.8. Сводный прайс-лист автоматически сформирован на основе данных прайс-листов “А“ и “Б“

Особенности исходных данных из сравниваемых прайс листов

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

Вообще говоря, для каждой подобной особенности в исходных данных потребуется специальное решение. В данном случае, например, можно воспользоваться тем фактом, что техническое наименование находится повсюду в одной и той же позиции строки общего наименования. Поэтому, при сравнении строковых значений можно применить функцию Mid, извлекая из сравниваемой строки 7 символов начиная с 16-го — это и будет в данном случае сопоставляемое наименование картриджа с наименованиями из других прайсов:

If Mid(PriceB.Range("Наименование").Cells(B, 1), 16, 7)= _

PriceA.Range("Наименование").Cells(A, 1) _

...

Сравнительный анализ прайс-листов 129

Рис. 4.9. Вариант прайс-листа, в котором технические подробности о товаре находятся в одной ячейке с его наименованием

Глава 5

Access: создание офисной базы данных

В этой главе будет рассмотрена работа с самым профессиональным приложением MS Office — системе управления базами данных (СУБД) MS Access. Конечно, эта программа предназначена для работы с базами данных не более чем офисного масштаба, но все же MS Access менее всех других приложений Office пригоден для непрофессиональных пользователей. Сказанное, однако, не означает, что только профессиональным программистам принадлежит монополия на работу в среде Access. Достаточно опытный пользователь, как вскоре можно будет убедиться, в состоянии многое сделать при помощи тех средств MS Access, которые не требуют знания теории баз данных и наличия серьезных навыков программирования.

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

Создание базы данных MS Access

Вначале создадим небольшую и несложную базу данных, а затем займемся автоматизацией работы с этой базой данных при помощи VBA.

Первый, самый простой шаг, состоит в создании пустой базы данных, с которой затем и предполагается дальше работать. После запуска MS Access на экране появится диалоговое окно, позволяющее выполнить одно из следующих действий:

открыть один из существующих файлов с базой данных — переключатель Открыть базу данных;

создать базу данных с помощью мастера или на основе готового проекта — переключатель

Мастера, страницы и проекты баз данных;

создать пустую базу данных “без изысков” — переключатель Новая база данных.

Для нашего примера нужна пустая база данных. Для этого установите переключатель Новая база данных и щелкните на кнопке ÎÊ.

В открывшемся диалоговом окне задайте имя файла новой базы данных, — например, пусть он называется MyOffice.mdb, и щелкните на кнопке ÎÊ.

Первый шаг на пути освоения MS Access сделан. Теперь можно приступать к упражнениям.

Создание таблиц

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

132 Глава 5. Access: создание офисной базы данных

ПРИМЕЧАНИЕ

Программа MS Access из пакета Office 2000 в больше отличается от своих предшественников, чем Word или Excel. Также изменения коснулись основ работы с Visual Basic для приложений — теперь в Access есть явный доступ к редактору Visual Basic. Формат базы данных Access претерпел серьезные изменения — вплоть до полной несовместимости с предыдущими версиями. Наконец, существенно изменился сам вид окна базы данных.

В левой части окна базы данных расположена панель инструментов с кнопками, переключающими вкладки окна. Обратимся к вкладке Таблицы — именно с создания таблиц начнем работу с базой данных (рис. 5.1).

Рис. 5.1. Окно базы данных

Вспомогательные таблицысправочники

Создааемая здесь простейшая база данных будет состоять из двух основных таблиц. В первой, назовем ее “Клиенты”, будут накапливаться сведения о клиентах фирмы. Вторая таблица будет содержать данные о приходных и расходных операциях, связанных с этими клиентами. Но прежде, чем приступить к созданию сравнительно сложных основных таблиц, необходимо подготовить несколько простых таблиц-справочников. Эти справочники будут использованы затем при создании основных таблиц.

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

Например, будем подразделять клиентов на несколько категорий и для каждой записи в таблице “Клиенты” укажем одну из категорий. Допустим, среди клиентов надо различать “реализаторов”, “постоянных покупателей” и “случайных клиентов” — для каждого предусмотрим отличающиеся условия (например, разные величины скидок). Чтобы можно было впоследствии без труда дополнять и модифицировать набор категорий в соответствии с текущими нуждами офиса, вынесем этот набор в отдельную таблицу-справочник. С этого и начнем.

Как создать таблицу в режиме конструктора

1.Щелкните на кнопке Таблицы в панели инструментов окна базы данных.

2.Выберите двойным щелчком в окне базы данных значок Создание таблицы в режиме Кон-

структора. В результате откроется окно конструктора таблиц.

3.В первой ячейке столбца Имя поля введите строку “КодТипа”, а в соответствующей (то есть первой) ячейке столбца Тип данных разверните список и выберите Счетчик.

4.Командой Правка | Ключевое поле сделайте это поле ключевым (аналогичного результата

можно достичь, щелкнув правой кнопкой мыши на первой строке и выбрав команду Ключевое поле в контекстном меню).

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