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

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

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

Создание приложения Registrator 253

Если при возникновении такой ситуации щелкнуть на кнопке Debug окна сообщения и подвести указатель к переменной CurMsg, то в строке всплывающей подсказки, которая появится спустя несколько секунд, можно увидеть, что переменная CurMsg имеет значение Nothing (рис. 9.18), т.е. что она не была инициализирована.

Дело в том, что в папке отправленных сообщений могут храниться не только обычные сообщения, который в Outlook 2000 представляются объектами класса MailItem, но и уведомления о получении сообщений, которым в объектной модели Outlook соответствует класс ReportItem. Поэтому, естественно, система не сможет, получив из коллекции Items объекта CurFolder ссылку на экземпляр класса ReportItem и присвоить это значение объектной переменной класса MailItem, которая в рассматриваемой процедуре представлена переменной CurMsg.

Рис. 9.18. Система не смогла создать экземпляр объекта класса MailItem

Для того чтобы обойти это ограничение и используется переменная FolderItem класса

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

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

Report.IPM.Note.IPNRN.

Простая проверка позволяет убедиться в том, что ссылку, которая хранится в переменной FolderItem можно присвоить объекту CurMsg. Если же среди элементов коллекции будет обнаружен объект класса ReportItem, его обработка выполняться не будет, а цикл перейдет к следующему элементу.

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

254 Глава 9. Программирование в Outlook: документооборот и электронная почта

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

GoNext).

В том случае, когда сообщение содержит вложения (т.е. свойство CurMsg.Attachments.Count имеет ненулевое значение), выполняется последовательный перебор всех элементов коллекции CurMsg.Attachments. Так как количество вложений и названия файлов могут иметь разную длину, процедура пытается отформатировать текущую ячейку таким образом, чтобы в ней поместилась вся соответствующая информация и чтобы ячейка при этом была достаточно компактной.

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

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

Рис. 9.19. Отчет о сообщениях, полученных и отправленных в период Рождественских каникул 2001 года (значительная часть отчета выходит за пределы экрана)

Подготовив текст процедуры, сохраните проект и попробуйте выполнить тестовый “прогон приложения”. Если не было допущено ошибок, после успешного завершения работы макроса появится результат, подобный приведенному на рис. 9.19.

На этом создание основной части приложения можно считать завершенным. Удалите только что созданный лист и сохраните проект.

Доводка приложения Registration до профессионального уровня

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

Создание приложения Registrator 255

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

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

В листинге 9.16 приведены недостающие процедуры модуля main, обеспечивающие вычисление диапазонов ячеек, в которых содержатся сведения о зарегистрированных входящих и исходящих сообщениях.

ЛИСТИНГ 9.16

Sub CalculateInputRange()

OutputDataRange = ActiveCell.Address

If OutputDataRange <> "$" & sFirstCol & "$4" Then LastInputRow = LTrim(Str(Val(Mid(OutputDataRange, 4, _

Len(OutputDataRange) - 3)) - 2))

InputDataRange = "$" & sFirstCol & "$3:$" & sLastCol & _ "$" & LastInputRow

Else

'*** Нет ни одного входящего сообщения

LastInputRow = "3"

GoNext (misc.sStart): GoNext (sRow): GoNext (sRow) ActiveCell = "За указанный период сообщений не было"

InputDataRange = ActiveCell.Address & ":" GoNext (sRow)

GoNext (sRow) End If

End Sub

Sub CalculateOutputRange()

OutputDataRange = ActiveCell.Address LastInputRow = "$" & sFirstCol & "$" & _

LTrim(Str(Val(LastInputRow) + 4)) If OutputDataRange <> LastInputRow Then

OutputDataRange = LastInputRow & ":$" & sLastCol & "$" & _

LTrim(Str(Val(Mid(OutputDataRange, 4, _ Len(OutputDataRange) - 3)) - 1))

Else

'*** Нет ни одного исходящего сообщения

OutputDataRange = ActiveCell.Address & ":" ActiveCell = "За указанный период сообщений не было"

End If

End Sub

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

256 Глава 9. Программирование в Outlook: документооборот и электронная почта

Рис. 9.20. Отформатированный отчет воспринимается гораздо лучше

ЛИСТИНГ 9.17

Sub MakeReportHeader(sFolderType As String, _

ByVal sHeaderText As String)

Dim sRange, sHeaderRange As String ActiveCell = sHeaderText sRange = ActiveCell.Address

sRange = sRange & sSemicolon & sDollar & sLastCol & _ sDollar & Mid(sRange, 4, Len(sRange) - 3)

sHeaderRange = sRange Range(sRange).Select With Selection

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlBottom

.WrapText = False

.Orientation = 0

.AddIndent = False

.ShrinkToFit = False

.MergeCells = False End With Selection.Merge

Selection.Font.Bold = True

MakeBorder (iTopHeader)

GoNext (sHome): GoNext (sRow)

If sFolderType = sInbox Then

Создание приложения Registrator 257

ActiveCell = "От кого"

Else

ActiveCell = "Кому"

End If: sRange = ActiveCell.Address: GoNext (sCol)

ActiveCell = "Размер": GoNext (sCol)

ActiveCell = "Вложения": GoNext (sCol) ActiveCell = "Дата и время": GoNext (sCol)

ActiveCell = "Тема": GoNext (sCol) ActiveCell = "Учетная запись": GoNext (sCol)

sRange = sRange & sSemicolon & sDollar & sLastCol & _ sDollar & Mid(sRange, 4, Len(sRange) - 3)

Range(sRange).Select MakeGrid (IsOneRow(sRange)) MakeBorder (iBottomHeader) Selection.Font.Size = 8 Selection.Font.Bold = True

Selection.HorizontalAlignment = xlCenter GoNext (sHome)

GoNext (sRow)

End Sub

Sub FormatReport(Selector As String)

If Right(Selector, 1) = sSemicolon Then

Selector = Selector & sDollar & sLastCol & sDollar & _

Mid(Selector, 4, Len(Selector) - 4)

Range(Selector).Select

Selection.Font.Bold = True

Selection.Font.Italic = True

MakeBorder

Else

Range(Selector).Select

Selection.RowHeight = iGoodHeight

MakeGrid (IsOneRow(Selector))

MakeBorder

Selection.Columns.AutoFit

Selection.Sort Key1:=Range(sTimeKey), Order1:=xlAscending, _

Header:=xlNo, OrderCustom:=1, _

MatchCase:=False,Orientation:=xlTopToBottom

Range(sAddressCol).Select

Selection.ColumnWidth = iGoodWidth

Range(sSubjectCol).Select

Selection.ColumnWidth = iGoodWidth

Range(sAttachmentsCol).Select

If MaxAttachmentsLen > iGoodAttachWidth Then _

MaxAttachmentsLen = iGoodAttachWidth

Selection.ColumnWidth = MaxAttachmentsLen / 2

GoNext (sStart)

End If

End Sub

Sub MakeGrid(JustOneRow As Boolean)

Selection.Borders(xlEdgeLeft).LineStyle = xlContinuous Selection.Borders(xlEdgeTop).LineStyle = xlContinuous Selection.Borders(xlEdgeBottom).LineStyle = xlContinuous Selection.Borders(xlEdgeRight).LineStyle = xlContinuous

258 Глава 9. Программирование в Outlook: документооборот и электронная почта

Selection.Borders(xlInsideVertical).LineStyle = xlDouble If Not JustOneRow Then _

Selection.Borders(xlInsideHorizontal).LineStyle = _ xlContinuous

End Sub

Sub MakeBorder(Optional Control As Integer = 0)

With Selection.Borders(xlEdgeLeft)

.LineStyle = xlContinuous

.Weight = xlMedium

End With

With Selection.Borders(xlEdgeTop)

.LineStyle = xlContinuous

If Control = iBottomHeader Then

.Weight = xlThin

Else

.Weight = xlMedium

End If

End With

With Selection.Borders(xlEdgeBottom)

.LineStyle = xlContinuous

If Control = iTopHeader Then

.Weight = xlThin

Else

.Weight = xlMedium

End If

End With

With Selection.Borders(xlEdgeRight)

.LineStyle = xlContinuous

.Weight = xlMedium

End With

End Sub

Function IsOneRow(ByVal sRange As String) As Boolean

Dim SemicolonPosition As Integer

IsOneRow = False

SemicolonPosition = InStr(sRange, ":")

If Len(Left(sRange, SemicolonPosition - 1)) = _

Len(Right(sRange, Len(sRange) - SemicolonPosition)) Then

IsOneRow = StrComp(Mid(sRange, 4, SemicolonPosition - 4), _

Mid(sRange, SemicolonPosition + 4, _

Len(sRange) - SemicolonPosition - 3)) = 0

End If

End Function

Sub FormatHeaderCell()

With Selection

.Borders(xlEdgeLeft).LineStyle = xlContinuous

.Borders(xlEdgeTop).LineStyle = xlContinuous

.Borders(xlEdgeBottom).LineStyle = xlContinuous

.Borders(xlEdgeRight).LineStyle = xlContinuous

.Font.Size = 8

.Font.Bold = True

.HorizontalAlignment = xlCenter End With

Создание приложения Registrator 259

End Sub

Создав указанные процедуры, сохраните проект и запустите приложение. Теперь получаемые с помощью приложения Registrator результаты будут соответствовать тем, которые представлены на рис. 9.20 и 9.21.

Рис. 9.21. Ситуация с отсутствующими сообщениями обрабатывается корректно

Доводка и совершенствование приложения

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

Естественно, руководству очень скоро оказалось этого мало: “А можно ли выводить отчет по определенной учетной записи? А по всем учетным записям? А если нужно получить сведения об объемах пересылаемой почты по месяцам или по кварталам? А нельзя ли создать отчет в цвете для распечатки на цветном принтере? Как насчет идеи сохранения всей регистрационной информации в базе данных Access 2000?…”

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

Приложение

VBA, как язык программирования: данные, синтаксис и функции

Как язык программирования, VBA во всем похож на Visual Basic (об этом говорит уже само название VBA — Visual Basic для приложений). Не следует путать VBA c Visual Basic, поскольку это физически разные вещи — Visual Basic представляет собой самостоятельный пакет для разработки программного обеспечения, не имеющий прямого отношения к пакету MS Office. Программы на языке Visual Basic — это самостоятельные исполняемые файлы, такие же, как MS Word или MS Excel, в то время как VBA-программы “живут” только в рабочей среде документов Office, поскольку VBA — это одно из встроенных инструментальных средств приложений Office.

Однако, с точки зрения программиста — в синтаксическом, и во многих других отношениях — Visual Basic и VBA (Visual Basic для приложений), это одно и то же. Более того, у VB и VBA есть еще третий “брат-близнец”: язык описания Web-сценариев VBScript, который также совместим на уровне синтаксиса с VBA и VB. В этом заключается великая сила и огромное преимущество технологии Visual Basic, которая использует один универсальный язык для решения столь различных задач.

И в этом же заключается главная причина, по которой любому человеку, имеющему дело с компьютерами, стоит хоть немного владеть синтаксисом Visual Basic — никогда не знаешь, где он сможет тебе пригодиться. Язык программирования Visual Basic позволяет заниматься как офисным программированием на VBA, так и созданием Windows-приложений при помощи пакета Visual Basic, а еще можно создавать Web-сценарии на языке VBScript. “Три в одном” — это ли не причина для того, чтобы хоть немного освоить азы языка программирования Visual Basic (особенно, учитывая тот факт, что многие приложения сторонних производителей в наше время снабжаются встроенными языками, очень похожими на Visual Basic)? Как знать, не придется ли нам всем в недалеком будущем программировать новый холодильник или стиральную машину именно на

языке Visual Basic?

Данные VBA: типы данных, переменные и константы

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

В случае Visual Basic дело обстоит и проще, и в то же время сложнее. Никакой “серьезный” язык программирования не позволит использовать переменные, которые не были предварительно объявлены. В Visual Basic разрешено использовать данные без явного или неявного указания их типа. Можно вообще не задумываться о данных, придумывая переменные “на ходу” и тут же используя их в своем коде, как заблагорассудится, объявляя переменную без указания ее типа и используя ее для хранения данных практически любого типа.

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

Но Visual Basic гибок и универсален, и если вы хотите работать серьезно, и создавать скольконибудь сложные программы, то у вас есть возможность обращаться с данными так, как это делают профессиональные программисты.

Данные VBA: типы данных, переменные и константы 263

Переменные и константы

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

Константы

Константы применяют в случаях, когда требуется много раз использовать в программе одно и то же значение. Тогда для того, чтобы изменить это значение, достаточно будет изменить только текст объявления константы. Кроме этого, константы делают текст программы более “прозрачным” и легким для понимания. Например, при вызове многих функций используются предопределенные константы Visual Basic, например:

If MsgBox("Создать письмо?", vbYesNo, "Отрицательное сальдо") = _ vbYes ...

...

Здесь константы vbYes и vbYesNo — это просто числа, запоминать которые нет нужды, поскольку имена констант запомнить гораздо легче. Константа vbYesNo означает, что в окне сообщения должны присутствовать кнопки Yes (Äà) и No (Íåò), а константа vbYes означает, что пользователь выбрал кнопку Yes(Äà). Существует огромное число таких предопределенных констант, при помощи которых задают параметры для функций, свойств и методов объектов, а также используют во многих других случаях.

Объявление констант

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

Public Const Stavka1 As Single = 0.16667

Здесь Stavka1 — это имя константы: далее в программе можно использовать это имя везде, где требуется значение 0.16667. Зарезервированное слово Public означает, что константа будет “видна” во всех модулях и во всех процедурах. Такие данные должны объявляться на уровне модуля, то есть вне текста какой-либо процедуры. Тип числового значения здесь определен, как Single (о типах см. далее). Если вместо Public использовать слово Private, то константу будут “понимать” только те процедуры, которые находятся только в этом же модуле.

Далее можно объявить еще одну константу, используя при этом уже объявленное имя

Stavka1:

Public Const Stavka2 As Single = Stavka1 + 0.007

Иопять надо будет использовать имя Stavka2 везде, где требуется значение 0.16667 + 0.007.

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

Константы, которые используются локально, то есть только в той процедуре, где они объявле-

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

Const ErrorMessage1 As String = "Произошла ошибка 1"

...

Const MaxErrors As Integer = 100

264 Приложение. VBA, как язык программирования: данные, синтаксис и функции

Переменные

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

Объявление переменных

Рассмотрим следующие примеры объявления переменных:

Dim WordRunning As Boolean

Логическая (булева) переменная WordRunning может принимать только значения True (Истина) или False (Ложь).

Dim WordCount, WordPointer As Integer

Целочисленным переменным WordCount и WordPointer отныне разрешено присваивать в качестве значений только целые числа.

А вот хорошо знакомые примеры объявления объектных переменных:

Dim MyParagraph As Paragraph

Dim MyDocument As Document

Если тип переменной явно не указан, по умолчанию будет принят тип Variant (о типе Variant и вообще о типах см. далее).

Инициализация переменных

Автоматически, в момент запуска программы, переменные численных типов инициализируются значением 0, а переменные строковых типов — значением “пустая строка”. Переменные типа Variant инициализируются значением Empty, а переменные объектных типов — значением

Nothing.

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

Зачем объявлять переменные?

Вообще говоря, переменные можно и не объявлять — Visual Basic может, при желании, допускать такую свободу в обращении со своими данными. Можно просто использовать любое имя в левой части оператора присваивания:

SvodCount = 2

И затем, внутри цикла For, использовать и модифицировать значение получившейся перемен-

ной SvodCount:

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

...

SvodCount = SvodCount + 1

...

Next A

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