Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект VB.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2 Мб
Скачать
☆

Объект.PopupMenu имяменю, флаг, позицияX, позицияY, выделеннаястрока

Объект - необязательный параметр, если опущен, то принимается форма, на которой фокус Имяменю - имя всплявающего меню. Обязательный параметр. Флаг - константа или значение, указывающее расположение и поведение меню. Список констант приведен в таблице ниже. При использовании двух констант (по одной из каждой группы) необходимо между ними ставить логический оператор Or. ПозицияX, позицияY - координаты X и Y, указывающие, где отобразиться окно. Если они опущены, то принимаются координаты мыши. Выделеннаястрока - название элемента всплывающего меню, которое отобразится жирным шрифтом.

Таблица флагов, указывающих позицию и поведение контекстного меню.

Константа

Числовое значение константы

Описание

Размещение

vbPopupMenuLeftAlign

0

По умолчанию. Размещение по x левого края всплывающего меню

VbPopupMenuCenterAlign

4

Центрирование всплывающего меню по x.

VbPopupMenuRightAlign

8

Размещение по x правого края всплывающего меню.

Поведение

vbPopupMenuLeftButton

0

По умолчанию. Элемент на всплывающем меню реагирует только на щелчок левой кнопки мыши.

VbPopupMenuRightButton

8

Элемент на всплывающем меню реагирует на щелчки и левой и правой кнопки мыши.

Контекстное меню.

Теперь, опираясь на метод PopupMenu сделать контекстное меню раз плюнуть. Создадим процедуру, которая срабатывает на щелчок мыши по форме Form_Click и вставим в нее наш новый метод:

Private Sub Form_Click() Form1.PopupMenu mnuPaint, , , , mnuZalit End Sub Как видишь, mnuPaint - это название нашего меню "Заливка", а mnuZalit - имя строки "Залить", оно будет выделяться жирным цветом. Остальные опции мы опускаем, хочешь, пробуй сам. Поскольку теперь меню "Заливка" в старом месте, в верхней строке формы нам не нужна, сделаем ее невидимой. Зайдем в Редактор Меню выделим в окне списка меню строку "Заливка" и поставим галочку у "Видимо". Ну, пока хватит. Если понадобиться исходник, то как всегда, его можно скачать вверху страницы.

Массивы.

Массивы, друзья мои, очень простая и крайне необходимая штука. Простой пример: ты считал из директории 50 имен файлов и тебе необходимо как-то поместить их в памяти, что-бы потом с ними работать. Без использования массива, ты должен объявить пятьдесят переменных и в каждую записать имя файла. Это безумие. Но еще большее безумие потом работать с этими переменными, пытаясь найти в них нужные нужные тебе данные. Иное дело массив. Имея его (в хорошем смысле), можно под одним именем запомнить все твои пятьдесят имен файлов и перебирать их сколько угодно, в любом цикле, меняя лишь индекс члена массива. Т.е., другими словами,

Массив - это сколько угодно значений, объединенных одним именем.

Массив, прежде чем использовать, надо объявить. Объявляется он совершенно также как и переменная. Если ты объявишь его локально в процедуре (здесь можно использовать ключевое слово Static), то он будет доступен только в этой процедуре и нигде больше, если в разделе (General)-(Daclarations) формы (c оператором Dim) - то во всей форме, а если тебе нужно объявить его глобально, так, чтобы он был доступен всему проекту, то в стандартном модуле с ключевым словом Public. Кроме того , массивы бывают статическими и динамическими.

Статические массивы.

Статический массив - это когда ты заранее знаешь, сколько переменных туда нужно будет записать, т.е. если ты объявил массив на 10 членов, то уж туда никак не запихнешь одиннадцать. В форме он объявляется так: Dim Chislo(9) As Long  Что здесь важно. Dim - оператор, который точно также, как и при объявлении переменной, объявляет массив и выделяет для нее память. Chislo - ну это просто имя, придумывается также как и для переменной и отвечает тем же требованиям. (9) - количество элементов в массиве - их 10. Почему так. Дело в том, что элементы массива нумеруются с нуля, а не с единицы, поэтому у нас десять элементов массива c номерами 0, 1, 2, 3, 4, 5, 6, 7, 8 и 9. Если для каких-то целей такой порядок тебя не устраивает, то используется оператор Option Base 1, который прописывается в разделе Declarations и привязывает первый элемент ВСЕХ, повторяю ВСЕХ, массивов в программе к единице. As Long - определение типа данных массива так же как тип обычной переменной. Почти всегда все элементы массива имеют один и тот же тип ( в данном случае длинное число Long). На крайняк, если это не так, или если ты не знаешь какого типа будут данные, можно задать тип Variant, но это нежелательно из-за того, что это занимает значительный объем памяти, особенно если массив большой. Размерность - ее так сразу не заметно, но она здесь присутствует и равна единице, потому, что у на одна циферка (девятка), т.е. наш массив является одномерным - по сути список значений. Теперь создадим массив для хранения результатов, ну скажем таблицы умножения на 8. Поскольку на ноль умножать бесперспективно, привязываем первый элемент массива к единице и объявляем переменную x для организации цикла For...Next.

Option Explicit Option Base 1 Dim Chislo(10) As Long 'так как мы используем оператор Option Base, то элементы массива нумеруются с единицы  Dim x As Long

Положим на форму Text1 с установленными свойствами .MultiLine в True, а .ScrollBars - в 2-Вертикаль, а также кнопку Command1. В процедуре Form_Load напишем цикл, который будет присваивать каждому элементу массива значение, соответствующее его номеру, умноженному на 8.

Private Sub Form_Load() Text1.Text = "" For x = 1 To 10 Chislo(x) = x * 8 Next x End Sub

Как видите, в цикле мы вместо номера элемента просто используем значение x, и таким образом перебираются все элементы массива. Теперь мы выведем значения элементов массива в Text1 в процедуре Command1.

Private Sub Command1_Click() For x = 1 To 10 Text1.Text = Text1.Text & Chislo(x) & vbCrLf Next x End Sub

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

1 элемент

2 элемент

3 элемент

4 элемент

5 элемент

6 элемент

7 элемент

8 элемент

9 элемент

10 элемент

8

16

34

32

40

48

56

64

72

80

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

Option Explicit Option Base 1 Dim Chislo(10, 2) As Long Dim x As Long Private Sub Form_Load() Text1.Text = "" For x = 1 To 10 Chislo(x, 1) = x Chislo(x, 2) = x * 8 Next x Private Sub Command1_Click() For x = 1 To 10 Text1.Text = Text1.Text & "8 x " & Chislo(x, 1) & " = " & Chislo(x, 2) & vbCrLf Next x End Sub

И наш массив будет представлять собой следующее

 

1 элемент

2 элемент

3 элемент

4 элемент

5 элемент

6 элемент

7 элемент

8 элемент

9 элемент

10 элемент

1 элемент

1

2

3

4

5

6

7

8

9

10

2 элемент

8

16

34

32

40

48

56

64

72

80

таким образом элемент массива Chislo (7,2) будет иметь значение 56. Обратите внимание, что размерность массива определяет колиство циферек в объявлении. Массив Chislo (10,5) - тоже двухмерный, только строк в табличке было-бы не две, а пять. А объявление трехмерного массива выглядело бы так Dim(10,5,2).Такую трехмерную таблицу нарисовать мне затруднительно. В принципе VB поддерживает до 64 размерностей массива, но это в голове трудно укладывается. Все, как видите очень просто. Однако статические массивы используются довольно редко. Чаше мы не знаем сколько данных мы будем иметь и потом ведь хочется дописать при необходимости в массив новые данные. Для этого существуют динамические массивы.

Динамические массивы.

Часто возникает ситуация, когда мы не знаем заранее, сколько элементов массива мы будем использовать заранее. Поэтому массив объявляется без размерности, например Dim Mass () as String Но, перед его непосредственным использованием, его надо переобъявить c указанием размерности. Делается это с помощью оператора Redim. Redim Mass (5) as String Вообще-то, у нас два пути использования динамического массива. Первый путь, это года мы узнаем (просчитываем) , сколько элементов массива нам нужно, и после этого объявляем массив небходимого нам размера. Однако мне это путь не очень нравится, поскольку, нам приходится задавать два цикла: один - для просчета необходимого количества элементов, второй - для собственно присваивания массиву значений переменных.  Второй путь, это когда мы в одном цикле при нахождении каждого нового данного переобъявляем массив с увеличением количества его элементов. Но этот способ загружает компьютер и может занимать много времени на обработку, особенно если создается большой массив. Происходит это из-за перераспределения элементов массива в памяти всякий раз при его переобъявлении и добавлении нового члена. Но именно такой способ мы применим при разработке программки Scanfiles, которая будет сканировать файлы в выбранной директории, сортировать их по-возрастанию и выводить в Text1. Хочу сразу заметить, что при переобъявлении массива все записанные в него данные стираются - массив обнуляется. Чтобы этого не происходило, надо использовать ключевое слово Peserve: Redim Preserve Mass (5) as String

Идем дальше. Поместим на форму объекты Dir1 и Text1. Начнем писать код. Обратите внимание, что процедуры Form_Load у нас не будет, так как под это событие обрабатывать нам нечего. Ну-с, фигачим

Option Explicit 'Установим начальную нумерацию массива с единицы, сейчас так удобнее Option Base 1  'объявим переменные Dim OurDir As String 'для директории, где будем искать файлы Dim FileName As String 'для имен находимых файлов Dim X As Long 'просто для цикла 'и, наконец, наш динамический массив, как строковый Dim Files() As String Кроме того, поскольку одни имена - это уж совсем скучно, то мы еще во вторую размерность массива выведем атрибуты файла. Атрибуты, это когда по файлу шлепаешь правой кнопкой мыши и в выпавшем меню выбираешь "Свойства". Тогда снизу окна этих свойств можно увидеть галочки рядом с загадочными словами "Только чтение", "Скрытый" и "Архивный". Именно эти свойства можно устанавливать или получать с помощью оператора SetAttr и функции GetAttr. Весь геморрой в том, что этот атрибут представляет из себя число, получаемое из суммы значений атрибутов, приведенных в таблице ниже, и чтобы понять, какой атрибут все-таки у файла, нужно "с помощью оператора And выполнить поразрядное сравнение значения". Друзья мои. Это цитату из Help5 я привел для того, чтобы можно было почувствовать разницу между "академическим" и "вольным" изложением проблемы. Короче, привожу таблицу этих атрибутов:

Константа

Значение

Описание

vbNormal

0

Обычный.

vbReadOnly

1

Только для чтения.

vbHidden

2

Скрытый.

vbSystem

4

Системный.

vbDirectory

16

Каталог или папка.

vbArchive

32

Архивный.

Из всей этой дребедни нам нужны три константы: vbArchive, vbReadOnly и vbHidden для этого самого "поразрядного сравнения". Делается это так: Чтобы узнать, только для чтения ли этот файл: Переменная = GetAttr("полный путь к файлу") And vbReadOnly Если в Переменной не ноль, то файл - только для чтения. Аналогично для других констант. Чтобы установить аттрибут, например "Архивный" для файла: SetAttr "C:\Andrey\index.htm", vbReadOnly при этом уже установленные атрибуты файла сбрасываются. Если надо установить атрибуты "только для чтения" и "архивный": SetAttr "C:\Andrey\index.htm", vbReadOnly +vbArchive  Все просто, а по сути - издевательство. Про атрибуты - все. Более интересные данные о файлах мы получим, когда начнем использовать FSO. Но об этом не сегодня. Итак, для хранения атрибута (на основании "поразрядного сравнения") продолжаем объявлять переменные (еще две)

Dim Attr As Long 'числовая, для атрибута файла Dim AttributFile As String 'строковая, для записи атрибута в виде слов

Напишем маленькую процедурку для Dir1 на событие Change. Дело в том, что событие Change наступает при двойном клике, а я и хочу, чтобы директория для поиска файлов устанавливалась по двойному клику. В этой процедурке мы очистим Text1 и обнулим переменные, ну и главное, запишем в переменную OurDir полный путь к директории, после чего перейдем к другой поцедуре - ScanDir, где собственно и будем искать файлы и записывать их имена и атрибуты в наш массив Files.

Private Sub Dir1_Change()  Text1.Text = ""  FileName = "" X = 0 OurDir = Dir1.Path  ScanDir 'переходим к процедуре сканирования файлов End Sub

Далее в процедуре ScanDir все, с учетом комментариев, понятно:

Private Sub ScanDir() FileName = Dir(OurDir & "\*.*", 0) 'присваиваем переменной значение функции Dir для всех файлов ReDim Files(2, 1) 'переобъявляем массив с минимальной размерностью, иначе может возникать ошибка Do While FileName <> "" 'запускаем цикл, до тех пор, пока Dir не вернет пустую строку X = X + 1 'счетчик элементов массива ReDim Preserve Files(2, X) 'переобъявляем массив по счетчику, сохраняя уже имеющиеся в нем данные AttributFile = "" 'обнуляем переменные Attr = 0 'проверяем файл на атрибут архивный Attr = GetAttr(OurDir & "\" & FileName) And vbArchive If Attr > 0 Then AttributFile = AttributFile & " Архивный" 'проверяем файл на атрибут только для чтения Attr = GetAttr(OurDir & "\" & FileName) And vbReadOnly If Attr > 0 Then AttributFile = AttributFile & " Только чтение" 'проверяем файл на атрибут скрытый для порядка, Бейсик все равно не видит такие файлы Attr = GetAttr(OurDir & "\" & FileName) And vbHidden If Attr > 0 Then AttributFile = AttributFile & " Скрытый"

Files(1, X) = FileName 'пишем в массив имя файла Files(2, X) = AttributFile 'пишем в массив атрибут файла FileName = Dir() 'запускаем функцию Dir без атрибутов Loop 'и так в цикле, пока файлы в директории не закончатся

If X > 0 Then Sort ' если хоть один файл найден, 'отправляемся к процедуре сортировки Else Text1.Text = "Файлов не найдено" 'в противном случае выводим сообщение. End If End Sub Основная прелесть массивов в том, что с данными, записанными в них, можно что угодно делать: сортировать, разбивать на группы, осуществлять поиск, делать выборки и т.п. Сейчас мы наш массив отсортирум по возрастанию имен файлов. Скажу сразу, что алгоритмы сортировки разработаны и существуют давно. Приводимый в примере был разработан лично мною, а возможное совпадение его с другими алгоритмами совершенно случайно. Но прежде, чем перейти к сортировке, я хочу рассказать вот о чем.  Поскольку количество элементов нашего массива меняется, а для сортировки его с помощью циклов For...Next нам надо точно знать минимальный (нижняя граница) и максимальный (верхняя граница) доступные значения индекса массива, то я использую функции LBound для определения минимального индекса и UBound для определения максимального индекса указанной размерности. Синтаксис их такой

Переменная=LBound(Massive,1) 'возвращает в Переменную минимальный индекс массива Massive по размерности 1. Переменная=UBound(Massive,1) 'возвращает в Переменную максимальный индекс массива Massive по размерности 1.

Надо сказать, что размерность - не обязательный параметр и по-умолчанию принимается за единицу. Теперь перейдем к сортировке массива: Private Sub Sort() 'процедура сортировки Dim K As Long Dim N As Long Dim y As Long 'просто для цикла For...Next Dim Peremen As String 'для временного храненения из массива имени файла Dim Peremen2 As String 'и атрибута файла Dim NomerPerem As String Dim NomerPerem2 As String 'сортировка массива K = LBound(Files, 2) 'присваиваем переменной К начальное значение массива - 1 (нижняя граница) For y = LBound(Files, 2) To UBound(Files, 2) 'просматриваем все строки массива с нижней до верхней границы Peremen = Files(1, y) 'присваиваем каждую строку в переменные Peremen2 = Files(2, y) 'вложенный цикл For N = y To UBound(Files, 2) 'просматриваем строки массива, начиная с той, 'значения которой храняться в переменных Peremen и Peremen2 If Files(1, N) < Peremen Then 'если значение в массиве меньше, чем в переменной Peremen = Files(1, N) 'то присваиваем переменным Peremen и Peremen2 новые, меньшие значения Peremen2 = Files(2, N) K = N 'присваиваем номер найденного элемента массива переменной K End If Next N 'конец вложенного цикла NomerPerem = Files(1, y) 'сохраняем в переменных старые значения строки массива NomerPerem2 = Files(2, y) Files(1, y) = Peremen ' и присваиваем этой строке массива новые Files(2, y) = Peremen2 If K > 0 Then 'если K не ноль, Files(1, K) = NomerPerem 'то строке К присваиваем старые значения из строки y Files(2, K) = NomerPerem2 End If Peremen = "" 'обнуляем переменные Peremen2 = "" K = 0 Next y 'конец сортировки 'просто выводим в Text1 отсортированные значения массива For X = 1 To UBound(Files, 2) Text1.Text = Text1.Text & Files(1, X) & Files(2, X) & vbCrLf Next X End Sub

Исходник программы можно, как всегда, скачать вверху страницы.

Присвоение содержимого одного массива другому.

Можно ли присвоить один массив другому не по отдельному элементу (в цикле), а сразу? Visual Basic 6.0 и версии выше дают возможность проводить операции присваивания с массивами точно также, как с переменными. Теперь нет необходимости создавать цикл For...Next для присваивания одного массива другому по каждому элементу. Достаточно написать такой оператор NewMassive=OldMassive и содержимое массива OldMassive присвоится массиву NewMassive. Однако при этом следут учитывать, что для исключинения ошибок при таком присвоении, желательно соблюдать одинаковую размерность и тип массивов. Хотя при присвоении динамического массива динамическому массиву, массив в левой части оператора изменяется, как бы подстраивается под оператор в правой части. Однако при работе со статическими массивами возможна ошибка компиляции. Кроме того при присвоении, например массива типа Long типу Integer может возникнуть ошибка переполнения (Owerflow). В программе операция присвоения может выглядеть приблизиельно так (на форме должны быть кнопка Command1 и текстбокс Text1):

Option Explicit  Dim OldMassive() As Long Dim NewMassive() As Long

Private Sub Command1_Click() Dim x As Long For x = 0 To 999 'просто заполнение массива цифрами ReDim Preserve OldMassive(x) OldMassive(x) = x Next x NewMassive = OldMassive 'присоение массивов For x = 0 To UBound(NewMassive) ' считывание нового массива в Text1 Text1.Text = Text1.Text & NewMassive(x) & vbCrLf Next x End Sub

Я думаю, особых комментариев здесь не требуется.

Как бы правильно не был бы написан код программы и как бы безошибочно, казалось, программа бы не работала, всегда есть возможность для возникновения непредвиденных ситуаций, когда VB не может выполнить корректно какой-нибудь оператор, что приводит к аварийному завершению программы (фатальный крах). При этом возможна еще и потеря данных, если в это время происходило, например, копирование файла или передача информации. В большинстве своем это ошибки вызваны внешними событиями, например пустой дисковод, когда твоя программа обращается к дискете, отсутствие того файла, который ты пытаешься открыть для, например, чтения, а также ошибки переполнения (когда не хватает памяти для рисунков и ли печати), сетевые сбои, проблемы с буфером обмена и много чего еще. Скажу сразу, что предусмотреть все возможные ситуации практически невозможно, особенно если твоим продуктом будет пользоваться сторонний юзер. Юзера крайне изобретательны. Я не раз сталкивался с возниковением таких ситуаций, спровоцированных юзером, которые у меня, например, в голове не укладываются, и которые потом смоделировать практически невозможно. Видимо по какому-то озарению свыше, юзер может добиться, таких катастрофических результатов, которых я достигнуть при всей внутренней мобилизации сил своего хилого организма не в состоянии. Если поставить перед собой цель создать программу, всегда работающую корректно, можно раздуть код этой программы до безумных размеров и все равно полного успеха не добиться. Microsoft, например, не добился.

Хотя и не все ошибки VB может перехватывать (их полный список можно найти здесь), однако избегать стандартных ошибок, обрабатывать явно возможные ошибки мы просто обязаны. Мне представляется, что для исключения фатальных сбоев надо придерживаться следующей стратегии.

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

Во-вторых, надо стараться избегать возникновения ошибки программно, тогда ее не придется отслеживать и обрабатывать. Ярким примером такой ситуации может служить программа Scandisk, которую мы рассматривали в прошлой, 10-ой главе. Когда мы тыкали мышью в Dir1 по директориям, все было нормально, при этом выполнялся следующий оператор: FileName = Dir(OurDir & "\*.*", 0) 'присваиваем переменной значение функции Dir для всех файлов Если же мы кликали по верхней строке с именем не директории, а диска, возникала ошибка 52 "Неправильное имя файла, или номер". А дело то всего лишь в слеже, который мы поставили в операторе. Дело в том, что функция Dir возвращает имя диска со слежом в конце строки, а имя директории - нет. Если мы его уберем и оператор будет выглядеть так FileName = Dir(OurDir & "*.*", 0) 'присваиваем переменной значение функции Dir для всех файлов вот тогда на диске оператор сработает правильно, зато перестанет читать директории. Можно конечно обработать эту ошибку, о чем мы будем говорить ниже, по ее номеру, но тогда в трех нижних операторах Attr = GetAttr(OurDir & "/" & FileName)... той же причиной будет также вызвана ошибка, но с другим номером - 75 "Ошибка доступа пути или файла". Тогда придется обрабатывать и ее. Это тоже вариант. Но по-моему логичнее сразу записать в переменную Ourdir правильный путь при любом раскладе. И надо-то для этого всего лишь убрать слеж из четырех операторов, где возникает ошибка, а в процедуру Dir1_Change добавить проверку, которая добавляет слеж при его отсутствии: If Right(OurDir, 1) <> "\" Then OurDir = OurDir & "\" 'добавленный оператор для устранения ошибки вот и все дела. Полный исправленный код, если что не понятно, можно скачать здесь.

В-третьих, при обращении к внешним источникам, в том числе к файлам, для получения или вывода информации надо предполагать, что возможно они будут недоступны. Кроме того, надо подумать, какие еще фатальные ситуации могут возникнуть. Вот тут уже надо обрабатывать ошибки конкретно. Давайте создадим новый exe-проект. По мере необходимости на форму будем класть командные кнопки и в их процедуре отлавливать ошибки. Возьмем пример самой распространенной ошибки - нет того файла, который нам как раз крайне необходим. Положим на форму кнопку Command1 (она будет называться Resume Next) и в ее процедуре напишем операторы открытия файла "aaa.txt" для последовательного чтения.

Option Explicit

Private Sub Command1_Click() Open "aaa.txt" For Input As #1 Close #1 End Sub

Поскольку такого файла никто не создавал, то при запуске программы и нажатии кнопки Command1 возникнет ошибка 53, о чем нам любезно сообщит Windows: "Run-time error '53': Файл не найден". Программа аварийно завершится.  Итак, что же нам может предложить VB для предотвращения фатальных ошибок.

Операторы ON ERROR и RESUME (Resume Next).

Перво-наперво, ошибку надо отловить. Сделать это можно с помощью оператора On Error. Однако сам по себе этот оператор работать не будет, это и логично, с отловленной ошибкой ведь надо что-то делать. Самое простой и безбашенный метод (кстати довольно эффективный, когда постоянно возникает ошибка, справиться с ней не можешь и это тебя достало) - присобачить к оператору On Errorоператор Resume Next. Тогда получившийся оператор On Error Resume Next в случае возникновения ошибки возвратится в программу и передаст управление оператору, следующему за тем оператором, где возникла ошибка. Однако следует помнить, что On Error Resume Next действует во всей процедуре, и если процедура большая и сложная, то ошибка может возникнуть совсем в другом операторе, нежели ты ожидаешь. Она все равно будет обработана, VB перескочит на следующий оператор, а ты об этом ничего не узнаешь и будешь дня два ломать голову, почему не работает то-то и то-то, хотя все прописано в коде черным по-белому. Ну, тем не менее исправим наш код с использованием оператора On Error:

Private Sub Command1_Click() On Error Resume Next Open "aaa.txt" For Input As #1 Close #1 Form1.Print "Процедура кое-как завершена" Form1.Print "с помощью On Error Resume Next" Form1.Print "файл не считан, работать не с чем" End Sub

Текст в операторах Form1.Print написан условно, так как ясно, что он будет выводится независимо от того, есть ошибка или нет. Т.е на самом деле пользователь никакой реальной информации об ошибке не получит и поправить ничего не сможет. Иное дело, если мы к нашему On Error попробуем пристроить оператор безусловного перехода GoTo метка. На самом деле он унаследован от старого Бейсика и использовать его нужно крайне осторожно. Этот оператор отсылает ( в нашем случае, если возникла ошибка) к строке, помеченной меткой, но только внутри текущей процедуры. Положим следующую кнопку Command2 (ее назание GoTo метка) и в ней напишем процедуру Private Sub Command2_Click() Dim Msg As String On Error GoTo ErrorMark Open "aaa.txt" For Input As #1 Close #1 Exit Sub ErrorMark: Msg = "Ой, наверно файл куда-то запропал, попробуйте восстановить!?" MsgBox Msg, , "Караул, нет данных!" End Sub Таким образом, при возникновении ошибки оператор GoTo возвращает нас в программу к строке, помеченной меткой ErrorMark. Под ней пишутся операторы, которые выполняются для реакции программы (или юзера) на ошибку. Обратите внимание, чтобы они не выполнялись в случае, когда ошибки нет, перед меткой поставлен оператор Exit Sub, который прерывает выполнение процедуры, не дожидаясь оператора End Sub. В качестве реакции на ошибку у нас выводится MessageBox с советом для юзера. Обратите снова Ваше драгоценное внимание на то, что в сообщении я употребил слово "наверное". Реально при открытии файла могут возникать разные ошибки и я лишь только предполагаю, что у нас ошибка 53.  Как я говорил выше, в сложных и больших процедурах, чтобы не отлавливать ошибки в других операторах оператор GoTo метка. надо выключить. Для этого, после сомнительного оператора, могущего вызвать ошибку, надо вставить строку On Error GoTo 0 Тогда обработчик ошибок прекратит свою работу и ошибки в последующих операторах отслеживаться не будут. Если в подпрограмме обработки ошибок имеется возможность устранить причину ее возникновения, то надо вернуться на тот же оператор и снова его выполнить, уже без ошибки. Для этого подпрограмму обработки ошибок заканчивают оператором Resume. Если же надо перейти к другой строке, помеченной меткой, то программу обработки ошибок надо закончить оператором Resume метка. Ну а теперь перейдем к самому интересному - анализу ошибок.

Объект Err.

Вот как раз с помощью этого объекта мы можем проанализировать, какая ошибка произошла, т.е. по сути, получить ее номер, и в зависимости от ситуации программно решить вопрос об ее устранении или наоборот, заставить юзера производить какие-либо судоржные действия. Основным свойством объекта Err является свойство .Number, которое и возвращает нам номер ошибки. Настолько основным, что .Number можно не писать. Синтаксис будет такой: Переменная=Err.Number или Переменная=Err Это свойство для нас главное. Кроме того (для сведения) имеются еще такие свойства: .Sourse - имя текущего проекта VB . Description - cтрока, соответствующая строке, возвращаемой функцией Error для кода ошибки, указанного в свойстве Number, если такая строка существует .HelpFile - полное имя (включая диск и путь) файла справки Visual Basic. . HelpContext - контекстный идентификатор файла справки Visual Basic, соответствующий ошибке с кодом, указанным в свойстве Number. . LastDLLError - содержит системный код ошибки для последнего вызова DLL (только для 32-разрядных Microsoft Windows)

Положим на форму Text1 со свойством Multiline - True, кнопку Command3 (название - Прочитать файл), а также для того, чтоб нам было удобно создавать, убивать файл, положим еще три кнопкиCommand4, Command5 и Command6, называющиеся соответственно "Создать aaa.txt", "Создать пустой aaa.txt" и "Убить aaa.txt". В процедурах этих трех кнопок напишем: код для создания файла путем открытия и записи туда слов "не пустой" в Command4 Private Sub Command4_Click() 'создать aaa.txt On Error Resume Next Kill (App.Path & "\aaa.txt") Open App.Path & "\aaa.txt" For Output As #1 Print #1, "не пустой" Close #1 Text1.Text = "Создан не пустой файл aaa.txt" End Sub в Command5 создадим пустой файл, т.е. файл не содержащий ни одного символа Private Sub Command5_Click() 'создать пустой aaa.txt On Error Resume Next Kill (App.Path & "\aaa.txt") Open App.Path & "\aaa.txt" For Output As #1 Close #1 Text1.Text = "Создан пустой файл aaa.txt" End Sub и в Command6 - программу для уничтожения файла Private Sub Command6_Click() 'убить aaa.txt On Error Resume Next Kill (App.Path & "\aaa.txt") Text1.Text = "Убит файл aaa.txt" End Sub Обратите внимание, что перед созданием файла, я убиваю старый. Так как старый файл может на тот момент не существовать (в этом случае возникнет ошибка), я использую On Error Resume Next. Теперь создадим коротенькую процедуру загрузки формы для проверки в самом начале, существует ли файл aaa.txt Private Sub Form_Load() Text1.Text = "" If Dir(App.Path & "\aaa.txt") = "" Then Text1.Text = "Файла aaa.txt не существует" End Sub А вот теперь в кнопке Command3 напишем полноразмерный обработчик ошибок. Private Sub Command3_Click() 'объявляем переменную для считывания данных из файла Dim Stroka As String 'использование объекта Err при обработке ошибок On Error GoTo ErrorMark ForOpen: Open App.Path & "\aaa.txt" For Input As #1 Line Input #1, Stroka Text1.Text = Text1.Text & "Файл успешно открыт, содержание файла: " & Stroka & vbCrLf Close #1 Exit Sub ErrorMark: Close #1 'выводим возможные данные об ошибке Text1.Text = "Возникла ошибка # " & Err.Number & vbCrLf Text1.Text = Text1.Text & Err.Description & vbCrLf Text1.Text = Text1.Text & "В " & Err.Source & vbCrLf Text1.Text = Text1.Text & "Полный путь хелпа " & Err.HelpFile & vbCrLf Text1.Text = Text1.Text & "Идентификатор файла спраки VB " & Err.HelpContext & vbCrLf Text1.Text = Text1.Text & "DLL " & Err.LastDllError & vbCrLf 'Ecли файла нет, то создем его If Err = 53 Then Open App.Path & "\aaa.txt" For Output As #1 Print #1, " " Close #1 Text1.Text = Text1.Text & "Создан новый файл aaa.txt" & vbCrLf 'возвращаемся на исходную позицию Resume ForOpen 'если файл пустой дописываем в него пробел ElseIf Err = 62 Then Open App.Path & "\aaa.txt" For Append As #1 Print #1, " " Close #1 Text1.Text = Text1.Text & "Ошибка файла aaa.txt исправлена " & vbCrLf 'возвращаемся на исходную позицию Resume ForOpen Else Text1.Text = Text1.Text & "Не знаю, что делать с ошибкой, файл не открыт " End If End Sub

Теперь, если мы убъем файл кнопкой "Убить aaa.txt" и нажмем кнопку "Прочитать файл", то в Text1 выведется вся доступная информация об ошибке, создастся новый файл и процедура начнет выполнятся по-новой уже с существующим файлом. Аналогичная ситуация возникает при создании пустого файла. При чтении такого файла возникает ошибка 62 - чтение после конца файла. Мы также получаем информацию об ошибке, дописываем в файл пробел и по Resume вновь запускаем процедуру. Если возникает ошибка с номером, который мы не знаем, то просто выводим об этом сообщения вText1.

Замечу, что с операторами Open и Close надо обращаться аккуратно. Все файлы должны своевременно открываться и закрываться. Если путаешься с работой с файлами, посмотри Главу 7. Скачать исходник можешь вверху страницы.

Резюме: Таким образом, обработка ошибки включает в себя: - Обнаружение ошибки On Error. - Переход на подпрограмму обработки GoTo (или, на крайняк, на следующий оператор с помощью Resume Next). - Определение ошибки Err.Number и в зависимости от этого выполнение каких-то действий. - Возврат Resume после устранения ошибки на оператор, вызвавший ошибку.

Для очистки совести скажу еще про функцию Error. Она по номеру ошибки выводит пояснение - что это за ошибка. Синтаксис: Строковая переменная=Error(номер ошибки) Если хотите, положите на форму последнюю кнопку Command7 и для вывода пояснений к ошибкам, например с 52 по 62 напишите такой код и посмотрите, что получится.

Private Sub Command7_Click() Dim ErrorNumber As Long Text1.Text = "" For ErrorNumber = 52 To 64 Text1.Text = Text1.Text & Error(ErrorNumber) & vbCrLf Next ErrorNumber End Sub Совершенно ничего сложного. Ну-с, с этим все.

Что такое ActiveX?

Мой дорогой друг. Когда ты устанавливал на жесткий диск Visual Basic 6.0, то в твой компьютер скачалось много всякого добра, и в том числе некоторые файлы средств управления ActiveX. Эти файлы лежат в c:\Windows\System или c:\Windows\System32 и имеют расширение .ocx. Большинство этих файлов представляют собой отдельные средства ActiveX, но например, тот, что мы будем рассматривать сегодня (Microsoft Windows Common Controls 6.0) включает в себя аж девять средств управления ActiveX. Некоторые средства ActiveX перечислены на странице "Элементы ActiveX". Вот сейчас мы о некоторых и поговорим. Начнем с самых нужных и используемых. Одним из таких средств является индикатор хода выполнения - Progress Bar. Если ты достаточно наблюдателен,то наверняка заметил,что при выполнении длительных процессов (копирование файлов, загрузка программ и т.п.) Windows выводит на экран окошко, где синенькая полосочка (индикатор хода выполнения процесса), постепенно увеличиваясь в длине, показывает, какой объем процесса выполнен, и вообще скорость процесса. Индикатор хода выполнения позволяет юзеру не нервничать и утешаться тем, что процесс худо-бедно идет, что он успеет раза два покурить и что компьютер не завис.

Элемент ActiveX: Индикатор ходы выполнения ProgressBar.

Чтобы приступить к использованию Progress Bar, его надо сперва добавить в панель инструментов нашего нового exe-проекта (по-скольку это средство управления ActiveX храниться в файле mscomctl.ocx). Сделать это - раз плюнуть. Для этого надо создать exe-проект, затем в меню Проект надо щелкнуть по строке Компонеты (Рис.22)   Рисунок 22. Затем, в открывшемся окне списка средств управления найди строку Microsoft Windows Common Controls 6.0 , щелкни в этой строке по полю флажка, поставив галочку и нажми кнопку OK на окне (Рис.23).   Рисунок 23. У тебя в панели инструментов появилось сразу несколько объектов. И в том числе ProgressBar (Рис.24). Аналогично добавляются и другие средства ActiveX из других файлов.   Рисунок 24. Теперь ты можешь перетащить его на форму и начать с ним работать. Он будет называться ProgressBar1. Основными свойствами, которыми мы будем пользоваться являются: .Min - минимальное числовое значение, с которого шкала начнет работать .Max - максимальное числовое значение, на котором шкала дойдет до конца. .Value - текущее числовое значение шкалы кроме того можно использовать .Scrolling - меняет прерывистую шкалу (0-ccScrollingStandard) на непрерывную (1-ccScrillingSmooth)  .Orientation - установка в вертикальное (если приспичило) или горизонтальное положение Кроме того, понятно, что имеются всякие стандартные свойства (типа высота-длина, видимый-невидимый и т.п), о которых и говорить-то нечего.

Вообще использовать ProgressBar имеет смысл только в циклах (любых). Ты задаешь начальное и конечное значение, а значение ProgressBar.Value меняется именно в цикле. Собственно именно оно и заставляет шкалу изменяться. Использование этого объекта рассмотри на примере программы Generator, которая иммитирует игрушки-гадалки. Знаешь такие китайские игрушки: загадаешь желание, крутанешь шарик, а он потом остановится и лампочка зажжется у слова типа "Никогда" или "Скоро". Так вот, у нас у аналогичных слов (они заданы в окне свойств, а не в коде) будет останавливаться шкала ProgressBar со свойством .Scrolling - 1-ccScrillingSmooth (неперывная). Объявим две переменные: первая для хранения сгенерированного случайного числа, вторая - просто для цикла. Dim MyValue As Long Dim x As Long Положим на форму командную кнопку Command1 и в ней напишем процедурку Private Sub Command1_Click() Здесь мы используем генератор случайных чисел. Мы уже использовали генерирование случайных чисел в Главе 3 при создании программы "Однорукий бандит", хоть и без оператора Randomize. Этот оператор просто генерирует число и передает его в качестве опорного в функцию Rnd, которая в свою очередь на основе этого числа генерирует случайное число от 0 до 1.

Randomize ' Инициализирует генератор случайных чисел.

Поскольку, функция Rnd возвращает число, меньшее единицы, мы умножаем его на 10000, а чтобы избежать нулевого значения, прибавляем единицу. Кроме того, получившийся результат округляем до целого числа с помощью функции Int. Эта функция просто отбрасывает дробную часть (а на самом деле не округляет). Синтаксис ее: Int(число). Аналогична ей функция Fix(число), которая работает так же, как и Int, но при округлении отрицательного числа приближает его к числу большему или равному, в то время как Int - к меньшему или равному.

MyValue = Int((10000 * Rnd) + 1) ' Возвращает случайное число от 1 до 10000.

Далее уже задаем начальное (1) и конечное (10000) значение ProgressBar1.

ProgressBar1.Min = 1 ProgressBar1.Max = 10000

Теперь организуем цикл от единицы до полученного нами случайного числа. В нем при каждом его выполнении значение ProgressBar1.Value изменяется, что отображается на изменении шкалы.

For x = 1 To MyValue ProgressBar1.Value = x Next x End Sub

Вот и вся программка. Да, еще хочу сказать, что число 10 000 выбрано для того, чтобы ProgressBar работал достаточно медленно. Скачать исходник можно вверху страницы.

При загрузке файла средств управления общего назначения в панели инструментов появились и другие объекты ActiveX. Обратим наши взоры на средство Slider, которое располагается через один и ниже ProgressBar'а, думаю, найдешь.

Элемент ActiveX: Скользящая шкала Slider.

По сути своей этот элемент очень похож на объект "полоса прокрутки ScrollBar", который мы разбирали в Главе 4. Главными отличиями его являются внешний вид: Slider представляет собой линейку с бегунком и отметками-маркерами (тиками), а также то, что его максимальное значение не ограничено, как у ScrollBar'а значением 32767. Элемент этот простой, я не буду повторять описание его свойств.Min, .Max, .Value и т.п. Если пропустил, посмотри выше на этой странице. Однако у Slider'а есть и другие свойства: .LargeChange - величина, на которую изменится положение бегунка при щелчке мышью по слайдеру .TickFrequency - определяет с какой частотой на слайдере будут располагаться маркеры (тики). Например, если у нас Slider1.Min=0, Slider1.Max=1000, а Slider1.TickFrequency=100, то на всем слайдере будут равномерно располагаться (1000-0)/100+1 = 11 тиков, первый из которых будет обозначать 0, второй - 100 и т.д., до последнего - 1000. Как работать со слайдером, мы разберем примере программки SliderPic (скачать ее можно вверху страницы). Практического применения ей я не вижу, но она иллюстрирует, как с помощью слайдера можно изменять объекты. В нашем случае мы с помощью двух слайдеров - горизонтального и вертикального будем менять, соответственно, ширину и высоту Picture для того, чтобы в нее влезла картинка. Сразу оговорюсь, что поскольку единица измерения размеров объектов в VB принята почему-то в твипах, я все в твипах и оставлю. Если тебе охота перевести в другие единицы, например, в пиксели,- пожалуйста (в Главе 6 мы использовали методы ScaleX и ScaleY для перевода в из одного измерения в другое). Итак, создадим exe-проект, положим на него Picture1 любого размера, но желательно позиционировать его ближе к верхнему левому углу формы (а то куда ж мы его расширять будем), и два слайдера -Slider1 (горизонтальный) и Slider2 (вертикальный). Чтобы Slider2 стал горизонтальным, надо его свойство .Orientation в окне свойств установить в 1-ccOrientationVertical.  Теперь пишем код.

Option Explicit В процедуре загрузки формы привяжем начало каждого слайдера к положению Picture Private Sub Form_Load() Устанавливаем левую границу Slider1 вровень с левой границей Picture1 Slider1.Left = Picture1.Left - 150 Также устанавливаем верхнюю границу Slider2 вровень с верхней границей Picture1 Slider2.Top = Picture1.Top - 150 Как видишь, мы здесь используем свойства .Top и .Left, которые есть практически у всех объектов. Они показывают расстояние от края формы до границы объекта сверху (.Top) и снизу (.Left). Поскольку бегунок слайдера в нулевой позиции отстоит от начала самого слайдера где-то на 150 твипов, я из значения положения картинки вычел это расстояние. Далее загружаем картинку в Picture1. Прошу прощения, за ее пошлость, просто под руку попалась. Picture1.Picture = LoadPicture(App.Path & "\Lopes.jpg") Затем устанавливаем свойства для каждого слайдера. Значения .Max слайдеров я взял от фонаря, исходя из того на сколько можно расширить картинку, чтобы она в экран влезала. Slider1.Min = 0 Slider1.Max = 10215 Slider1.LargeChange = 500 Slider1.Value = Picture1.Width Slider1.TickFrequency = 500

Slider2.Min = 0 Slider2.Max = 6975 Slider2.LargeChange = 500 Slider2.Value = Picture1.Height Slider2.TickFrequency = 500

End Sub

Для каждого слайдера создаем процедурку, где присваиваем значению ширины (или длины) Picture1 значение слайдера. Private Sub Slider1_Click() Picture1.Width = Slider1.Value End Sub

Private Sub Slider2_Click() Picture1.Height = Slider2.Value End Sub

Вот, собственно, и все.

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

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