Visual Basic, .NET, ASP, VBScript
 

   
 

Михаил Эскин немало сделал для развития русскоязычных VB сайтов. Многие знают его по статьям про ActiveX на VB сайтах, другие читают статьи Михаила уже на его собственном сайте. Михаил родился в Городском роддоме №1 города Астрахани, в “черную пятницу”, ну, так скажем, почти сорок лет назад. По-прежнему живет на Юге, правда теперь уже Германии, в прекрасном городе Мюнхене.

 
     
   
 
     Модули классов хранятся в файлах с расширением CLS и похожи на модули форм за исключением того, что у них нет видимого интерфейса пользователя. Их можно использовать для создания собственных объектов, включая программный код для методов и свойств.

(Microsoft Press)

    Каждый программист написал в своей жизни хотя бы одну игрушку. Стоп. Кажется, это я уже писал. И все-таки начнем с этой строки. Потому что тот пример, который лег в основу данной статьи, относится к созданию игровых программ. Как бы ни хорошо была сделана программа, в итоге пользователь хочет не просто получить результат, но и сравнить его с другими. Для этого обычно используется окно "Лучшие результаты". Каждый программист решает его по-своему, часто "изобретая велосипед заново".

    На основе этого проекта вы познакомитесь созданием коллекций и классов, а также сможете грамотно их использовать в своих программах.

    Шаг 1. Создадим проект Standard EXE. Та форма, которая создается по умолчанию, нам пригодится в будущем, как тестировочная. Поэтому внесем в нее маленькие исправления: переименуем ее в frmTest, свойство AutoRedraw = True (так как мы будем выводить результаты методом Print на саму форму). Изменим также шрифт, установим его равным "Courier New Cyr" и кегль = 10. Внизу формы расположим кнопку:

Name= cmdPrint
Caption="Print"

    Шаг 2. Теперь займемся непосредственно созданием нашего класса. Откройте Class Builder Utility. Сделать это можно несколькими способами: Меню Project/Add Class Module и в диалоговом окне выберите VB Class Builder; или Меню Add-Ins/Add-In Manager, выберите VB6 Class Builder Utility, нажмите ОК и еще раз Меню Add-Ins/Class Builder Utility. Представленный Add-In, значительно облегчит вам жизнь при построении классов и коллекций, избавив вас от рутинной работы - написания однотипных кодов. Прежде чем мы начнем строить, давайте определимся со структурой нашего класса. Во-первых, мы должны иметь возможность добавлять и удалять записи, знать их количество в коллекции и иметь возможность обращаться к каждой конкретной записи для чтения или изменения ее. Для этого в коллекции существуют стандартные свойства и методы, которые будут сгенерированы нам автоматически. Каждая запись (в нашем примере) будет состоять из трех полей: Player (строковый тип), CurDate (тип дата/время), Result (тип длинное целое).

NB! В дальнейшем Вы, поняв правила построения классов, можете добавить или убрать дополнительные поля, или изменить их типы.

    Шаг 3. Итак, строим. В визарде выберем меню File/New/Collection и в диалоговом окне в поле Name изменим имя, данное по умолчанию на Resultats. Справа определим, на каком классе будет базироваться данная коллекция, выберем New Class и в поле переназовем его на Resultat. Нажмем кнопку ОК. Если мы сейчас выделим коллекцию, то увидим, что автоматически созданы следующие методы и свойства: Add, Remove, Item, Count, NewEnum. В окне слева щелкнем на крестике, раскрывая коллекцию – там будет находиться класс, на котором данная коллекция базируется, то есть Resultat. Добавим в него наши свойства (Player, CurDate, Result), с вышеуказанными типами. Закроем данное приложение, не забыв подтвердить Update нашего проекта.

    Шаг 4. Займемся исследованием и исправлением полученного с помощью визарда. В классе, помимо заказанных нами свойств, автоматически создается открытая переменная Key. Толку от открытых переменных, как мы знаем, не много, кроме того, в данной ситуации мы это свойство и не заказывали. Поэтому просто-напросто удалим данную строку. Каждое свойство, созданное визардом по нашей просьбе, состоит из двух частей: Let (на запись) и Get (на чтение). Этим самым обуславливается закрытость доступа к нашим свойствам.

NB! Если бы мы использовали в качестве одного из свойств объект, то вместо процедуры Let необходимо было бы использовать процедуру Set.

    Переходим в коллекцию. Открытая переменная Key там завязана только в одном методе, а именно методе Add. Удалим ее из объявления в заглавии метода. Кроме того, удаляем строку objNewMember.Key=Key, и вместо цикла If Then … Else запишем всего одну строку: mCol.Add objNewMember. Вчерне мы сделали вполне работоспособную коллекцию для работы с данными.

    Шаг 5. Для того чтобы отследить, как все это работает, в коллекцию добавим метод PrintCls. Добавить его можно, написав код вручную или с помощью того же Class Builder Utility.

Лирическое отступление 1. Данный метод мы будем использовать на тестировочной форме для получения и обработки результатов. В дальнейшем для своих приложений вы можете написать форму с другими параметрами и исправить данный метод (или вообще его убрать) "под себя".

    В данном методе мы вначале очистим подложку, затем соберем в виде строк все значения нашей коллекции и, наконец, методом Print напечатаем. Именно поэтому мы объявляем подложку как Object (т.е. на печать мы можем выводить как на саму форму, так, например, и на PictureBox).

obj.Cls
For i = 1 To Me.Count
    str = str & Me.Item(i).Player & " | " & Me.Item(i).CurDate & " | " & Me.Item(i).Result & vbCrLf
Next
obj.Print str

NB! В цикле For ... Next мы проверяем наши компоненты, начиная с номера 1. Так как коллекции такого типа всегда базируются на 1, а не на 0.

    Шаг 6. Переходим в форму. Вначале, в разделе деклараций, объявляем переменную R (или с другим именем, как вам захочется) с типом нашей коллекции. Затем в процедуре Form_Load озвучим ее, создав новый образец.

Set R = New Resultats

    И здесь же, как говорится, "не отходя от кассы", сделаем уничтожение нашего класса, тем самым освобождая память. B Form_Unload присвоим нашему объекту состояние Nothing.

Set R = Nothing

NB! То же самое мы могли сделать в одну строку в разделе деклараций:

Private R As New Resultats

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

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

    После того, как мы озвучили нашу переменную как новый класс, добавим несколько записей в него, согласно запрашиваемой структуре. А в обработку нажатия кнопки заносим метод PrintCls. Вот теперь можно запустить приложение и, нажав кнопку Print, посмотреть, как работает вновь созданный нами класс.

   Шаг 7. Когда пользователь достигает какого-либо результата, то это должно заноситься в массив уже существующих значений. Для реализации этого в разделе деклараций коллекции объявим переменную NewResult с типом Result. А в методе Add в самом конце озвучим ее, приравняв ее значение к последнему значению коллекции.

Set NewResult = Me.Item(Me.Count)

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

Sort NewResult.Player, NewResult.CurDate, NewResult.Result

    Она будет состоять из цикла For … Next, внутри которого последовательно будет сверяться соответствие уровня последнего значения с каждым из имеющихся и устанавливаться на соответствующую ему позицию, отодвигая вниз меньшие (худшие) результаты.

For i = 1 To Me.Count
    If NewResult.Result > Me.Item(i).Result Then
        For j = (Me.Count - 1) To i Step -1
            Me.Item(j + 1).Player = Me.Item(j).Player
            Me.Item(j + 1).CurDate = Me.Item(j).CurDate
            Me.Item(j + 1).Result = Me.Item(j).Result
        Next
        Me.Item(i).Player = Pl
        Me.Item(i).CurDate = Dat
        Me.Item(i).Result = Res
        Exit For
    End If
Next

    На тестируемую форму добавим 3 текстовых поля, кнопку cmdAdd, которой присвоим метод Add, считывающий значения из этих 3 текстовых полей. Запустим программу на выполнение. Каждый раз, нажав кнопку Add, мы добавляем новую запись в коллекцию, обновление которой можно посмотреть, нажав кнопку Print.

    Шаг 8. Тестируя программу на данном уровне, вы, наверно заметили, что наращивание нашей коллекции может происходить достаточно долго, в чем нет необходимости для конкретного приложения. Обычно в играх ограничиваются 10-20 лучшими результатами. Поэтому давайте создадим свойство Max, отвечающее за максимальное количество записей в коллекции. Данное свойство проще всего создать с помощью все той же Class Builder Utility. Добавив в коллекцию это свойство, необходимо задействовать его в процедуре Sort для отсечения лишних записей.

If Me.Count > Me.Max Then
    Me.Remove Me.Count
End If

А в форме объявить его сразу же после создания нашего класса. Ограничимся 10 записями.

R.Max = 10

    Шаг 9. Добавим в коллекцию метод Clear, очищающий всю коллекцию от записей, последовательно удаляя каждую из них. (Пользователь нажал "Очистить все результаты").

For i = Me.Count To 1 Step -1
    Me.Remove i
Next

NB! Здесь мы используем цикл For … Next с отрицательным шагом для избежания выдачи сообщения об ошибке ("отсутствие необходимого количества элементов").

    Шаг 10. Зайдем в класс Resultat и сделаем исправления в свойстве Player для ограничения вводимого количества знаков. Допустим, ограничим данную строку 10 знаками. В случае большего значения – обрезаем, в случае меньшего – наращиваем пробелами.

Select Case Len(vData)
    Case Is > 10
        vData = Left(vData, 10)
    Case Is < 10
        Do Until Len(vData) = 10
            vData = vData & " "
        Loop
End Select

    Запустим программу на исполнение и увидим выровненные колонки результатов.

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

NB! Если вы внимательно просмотрели код, то заметили, что, находясь внутри класса (коллекции) я обращаюсь к их свойствам и методам, используя ключевое слово Ме. Делать это совсем не обязательно, так как класс сам "знает", что в него входит. Здесь я использовал это ключевое слово умышленно (откуда что берется), для облегчения восприятия, читающих эту статью.

 
     

   
   
     
  VBNet рекомендует