Visual2000 · Архив статей А.Колесова & О.Павловой

Создание приложения "Календарь наших дел" в среде VB 6.0

Часть 2.1

Андрей Колесов, Ольга Павлова

© Андрей Колесов, Ольга Павлова, 2000
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" N 05/2000, компакт-диск.


IV этап. Модернизация формы для ввода данных

Теперь приступим к "ручной" модернизации формы frmRemindersSet. Для начала изменим свойство Caption у формы на "Формирование памяток".

Шаг 18. Заменим поле текста RemindTime на новый дополнительный элемент управления DateTimePicker, который позволит выполнить ряд специфических операций с данным полем базы данных — датой и временем. В частности, он обеспечивает выбор даты с помощью календаря (рис. 19).

Рис. 19

DateTimePicker реализован в виде файла Mscomct2.ocx, и, чтобы добавить его, выберите команду Components из меню Project, установите флажок Microsoft Windows Common Controls-2 6.0 и щелкните OK. Тогда на панели инструментов VB 6.0 появится соответствующий значок с названием DTPicker.

Замечание. Панель инструментов ToolBox не имеет линейки вертикальной прокрутки, поэтому нельзя догадаться по ее внешнему виду, видите ли вы весь набор элементов управления или только его часть. Так что всегда выбирайте размер панели таким образом, чтобы явно видеть внизу пустую строку (рис. 20).

Рис. 20

Раздвиньте форму вверх, на свободное место поместите элемент управления DateTimePicker и установите его свойство Name как dtpRemindTime. Теперь посмотрите, какие значения установлены для свойств DataSource и DataField у существующего поля текста RemindTime. Они равны datPrimaryRS и RemindTime соответственно. Установите такие же значения для соответствующих полей элемента управления dtpRemindTime.

По умолчанию DateTimePicker работает только с датой. Нам же нужно, чтобы приложение Reminder предоставляло возможность задавать время с точностью до минуты (секунды вряд ли понадобятся в реальной жизни). Создадим достаточно простую маску ввода для dtpRemindTime, установив его свойство CustomFormat как "dd/MM/yyy hh:mm". (Это очень странно, но, чтобы вывести четырехзначное обозначение года, в этом поле требуется указать три буквы "y".) Теперь, чтобы DateTimePicker использовал заданную нами маску ввода, установите свойство Format как 3-dtpCustom.

После этого удалите поле текста RemindTime, находящееся справа от одноименной метки, а на его место переместите элемент управления dtpRemindTime.

Шаг 17. Теперь немного автоматизируем операцию ввода даты пользователем. Для этого дважды щелкните элемент управления ADO Data, находящийся в нижней части формы, в окне кода найдите подпрограмму datPrimaryRS_WillChangeRecord, а в ней — оператор Case adRsnAddNew, после которого напишите следующее:

dtpRemindTime.Value = Format(Now(), "dd/mm/yyyy hh:mm:002)

Данный код обеспечивает то, что dtpRemindTime всегда показывает текущую дату и время (отбрасывая секунды), когда пользователь добавляет новую запись-напоминание. Обратите внимание, что используемая здесь функция Format требует другого формата для даты и времени. Так, здесь требуется писать yyyy, чтобы выводилось четырехзначное значение года, в отличие от элемента управления DateTimePicker, где надо указывать yyy.

Шаг 18. Теперь преобразуем поле текста RemindMemo: установим свойство Name как txtRemindMemo и очистим свойство Index. Чтобы поле стало многострочным, установим MultiLine как True, а ScrollBars — как 2-Vertical. После этого увеличим высоту поля текста.

Шаг 19. И, наконец, последнее — измените свойства Caption оставшихся элементов управления, если хотите, чтобы ваши пользователи работали с русскоязычным приложением. После этого вы получаете уже готовое для использования окно ввода данных. Конечно же, здесь можно все изменить и расположить элементы управления на форме по своему усмотрению. Запустите форму frmRemindersSet на выполнение и убедитесь, что с ее помощью можно работать с базой данных. Кроме того, сейчас подходящий момент для ввода в базу данных нескольких записей о будущих делах (рис. 21). Введите не менее десятка таких записей с разными датами, чтобы потом можно было отладить процедуру их удаления.

Рис. 21

В начало статьи

V этап. Использование элемента управления DataRepeater

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

Вначале создадим пользовательский элемент управления ActiveX, который привяжем через ADO Data к источнику данных, а потом с помощью элемента управления DataRepeater (новинка!) повторим User-компонент необходимое число раз.

Шаг 20. Сохраните наш основной проект Reminder.vbp и создайте новый проект типа ActiveX Control. (Более подробно технология создания и отладки пользовательского элемента управления описана в статье "Как создать элементы управления в среде", КомпьютерПресс N 6/97.)

Разместите на форме элементы управления Label, TextBox и CheckBox и установите их свойства Name как lblRemindTime, txtRemindMemo и chkDeleteMe соответственно. Задайте свойство MultiLine поля текста как True, а свойство ScrollBars — как 2-Vertical. Кроме того, установите свойство Caption флажка как "Удалить". Затем сгруппируйте эти элементы управления таким образом, чтобы между ними оставалось как можно меньше свободного пространства, поскольку создаваемый нами компонент ActiveX будет располагаться в нескольких строках сетки (рис. 22). Установите свойство Name элемента управления User как Memos, а затем выберите команду Properties из меню Project и установите Project Name как Rmemos.

Рис. 22

Теперь напишем процедуры Property Let и Property Get для каждого элемента управления, а также включим вызовы метода PropertyChanged в событиях chkDeleteMe_Click и txtRemindMemo_Change (см. листинг 1).

Здесь нужно обратить внимание на один важный момент. Состояние флажка chkDeleteMe описывается целочисленной переменной, которая может иметь значение 0 или 1. В базе же данных Reminder для хранения этой информации зарезервировано поле типа Boolean, которое также может хранить два значения переменной: False или True. Но дело в том, что этим двум логическим переменным соответствуют целочисленные значения — 0 или -1. Таким образом, мы столкнулись с ситуацией несоответствия типов данных, и именно этим объясняется довольно замысловатый код в процедурах Property Let и Property Get для поля DeleteMe. В этом плане, наверное, было правильнее описать поле DeleteMe в базе данных тоже как целочисленное, чтобы не путаться в подобных преобразованиях.

Чтобы элементы управления, находящиеся в компоненте User, были связаны с источником данных, вызовите команду Procedure Attributes из меню Tools, а затем щелкните кнопку Advanced. Раскрывающийся список Names содержит имена всех элементов управления, входящих в компонент User. Выберите элемент управления RemindTime и установите флажки Property is data bound и Show in DataBindings collection at design time (рис. 23). Повторите то же самое для свойств RemindMemo и DeleteMe, после этого щелкните OK.

Рис. 23

Сохраните элемент управления User и проект как Memos.ctl и Rmemos.vbp соответственно. Затем выберите из меню File команду Make Rmemos.ocx, которая создаст новый элемент управления ActiveX и зарегистрирует его в Регистре Windows под названием Rmemos.Memos (наш OCX-файл содержит один компонент).

Шаг 21. Откройте созданный нами ранее проект Reminder.vbp и добавьте к нему новую форму Form. Установите свойство Name формы как frmRemindersPopup, а свойство Caption — как "Контроль запланированных дел", BorderStyle — 2-Sizable, ControlBox — False и запишите форму на диск как Popup.frm.

Подключите элемент управления DataRepeater к своей панели инструментов (Microsoft DataRepeater Control 6.0 (OLEDB) в окне Components) и поместите его на свою форму.

Установите его размеры таким образом, чтобы внутри мог располагаться элемент управления Rmemos.ocx. В нижней части формы разместите элемент управления ADO Data (в панели инструментов он носит название ADODC). Установите для него свойство ConnectionString равным той же самой строке, которая используется для элемента управления ADO Data в форме frmReminderSet.

Задайте свойство RecordSource как Select * from Reminder Order By RemindTime Desc (данный SQL-оператор запрашивает записи-памятки в порядке их появления на экране — от самой последней до самой ранней). Кроме того, для события Adodc1_MoveComplete введите такую строку кода:

Adodc1.Caption = "Запись: " & _
        CStr(Adodc1.Recordset.AbsolutePosition)

Щелкните элемент управления DataRepeater и установите его свойство Caption как "Что делать", а DataSource — как Adodc1. Щелкните свойство RepeatedControlName, чтобы раскрыть список имеющихся элементов управления, и выберите из них компонент Rmemos.Memos, который мы только что создали. После этого вы должны увидеть его внутри DataRepeater.

Шаг 22. Чтобы связать Rmemos.Memos с источником ADO-данных, щелкните правой кнопкой мыши элемент управления DataRepeater и выберите команду Properties из "быстрого" меню. Щелкните вкладку RepeaterBindings и раскройте список PropertyName. Выделите RemindTime, а затем в раскрывающемся списке DataField выберите поле базы данных, с которым это свойство связано, — для нашего приложения это поле RemindTime. Щелкните кнопку Add, чтобы добавить данную связь к сетке RepeaterBindings. Повторите эти шаги для свойств RemindMemo и DeleteMe (рис. 24).

Рис. 24

Затем щелкните вкладку Format и выделите свойство RemindTime (рис. 25). Установите для него Format Type как Custom, а Format String — как "c" (метод показа даты и времени с помощью одного символа). Для остальных полей оставьте значение Format Type как General. Щелкните OK.

Рис. 25

Шаг 22-a. Установите теперь на время отладки имя формы frmRemindersPopup в списке Starup Objects окна Project Properties|General и запустите ее на выполнение. Убедитесь, что вы можете просматривать все записи, занесенные в базу данных, в порядке возрастания даты (рис. 26).

Рис. 26

В начало статьи

VI этап. Реализация логики окна "Контроль дел"

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

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

Шаг 23. Сразу добавьте к форме все элементы управления, которые понадобятся в дальнейшем. Разместите на ней четыре командные кнопки и установите свойства Name и Caption первой из них как cmdClose и "Закрыть", второй — cmdSleep и "Спрятать", третьей — cmdSnooze и "Убрать на время", четвертой — cmdDeleteMe и "Удалить сделанное". Кроме того, поместите на форму элемент управления Timer (таймер) и установите его свойство Name как timReminders.

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

Private SnoozeTime As Date     ' контрольное время разворота формы
Private UseSnooze As Boolean   ' указатель режима "Убрать на время"
Private ReminderCount As Long  ' число записей перед обновлением

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

Для этого в модуле формы создадим такую подпрограмму формирования необходимого набора данных:

Private Sub AdodcRefreshDate(MyDate As Date)
    ' формирование набора данных с записями на
    ' заданный момент времени ControlDate
    Dim SQL As String, TimeSql$
    ' этот вариант формирования литерала даты
    ' обеспечивает независимость от национальных
    ' установок конкретной системы
    TimeSql$ = Format(MyDate, "MM.dd.yyyy HH:mm")
    Mid(TimeSql$, 3) = "/"
    Mid(TimeSql$, 6) = "/"
    ' последние два оператора можно заменить на
    ' TimeSql$ = Replace(TimeSql$,".","/")
    '
    SQL = "Select * from Reminder Where RemindTime <= #" & _
        TimeSql$ & "#" & " Order By RemindTime Desc"
    Adodc1.RecordSource = SQL
    Adodc1.Refresh
    '
    ' обновляем заголовок списка
    Me.Caption = "Контроль срочных дел: число записей = " & _
        Adodc1.Recordset.RecordCount & " на " & MyDate
End Sub

При загрузке формы нужно выполнить следующие операции инициализации:

Private Sub Form_Load()
    ' формирование списка записей-памяток на заданное время
    Call AdodcRefreshDate(Now)
    ' фиксируем текущее число записей в списке
    ReminderCount = Adodc1.Recordset.RecordCount
    '
    ' устанавливаем период опроса обновлений
    timReminders.Interval = 60000 ' одна минута
    ' запустить таймер
    timReminders.Enabled = True
End Sub

Анализ появления новой информации будет проводиться по таймеру; для этого следует написать такую процедуру:

Private Sub timReminders_Timer()
    ' обновление списка
    Call AdodcRefreshDate(Now())
    '
    If Adodc1.Recordset.RecordCount > ReminderCount Then
        ' появились новые записи в списке
        MsgBox "Появились новые записи!", , _
            "Этим нужно срочно заняться!"
        'фиксируем текущее число записей в списке
        ReminderCount = Adodc1.Recordset.RecordCount
        If WindowState = vbMinimized Then
            ' здесь можно вместо простого сообщения о новых записях
            ' задать вопрос о том, нужно ли открывать форму полностью
            WindowState = vbNormal ' раскрываем окно
        End If
    End If
End Sub

И, наконец, сформируем простую процедуру выключения формы:

Private Sub cmdClose_Click()
    ' запись в базу данных всех обновлений
    Adodc1.Recordset.UpdateBatch adAffectAll
    Unload Me ' выгрузка формы
End Sub

Теперь, после загрузки формы, в ее списке появляются записи о делах, которые нужно выполнить на текущий момент. Этот список постоянно обновляется с периодичностью в 1 минуту, о чем выдается соответствующее сообщение. Запустите форму на выполнение и убедитесь, что все работает именно так.

Шаг 25. Реализуем еще одну функцию — удаление сделанных дел. Для этого для кнопки "Удалить сделанное" напишем такой код:

Private Sub cmdDeleteMe_Click()
    ' удаление всех записей, помеченных как "сделанные"
    Dim SQL As String
    Dim Conn As Connection
    '
    ' запись в базу данных всех обновлений
    Adodc1.Recordset.UpdateBatch adAffectAll
    ' операция удаления
    Set Conn = New Connection
    Conn.ConnectionString = Adodc1.ConnectionString
    Conn.Open
    SQL = "Delete from Reminder Where DeleteMe = True"
    Conn.Execute SQL
    Conn.Close
    ' обновление списка
    Call AdodcRefreshDate(Now)
End Sub

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

Шаг 26. Последние операции с формой — создание кода для кнопок "Спрятать" и "Убрать на время". Первая из них сворачивает форму frmRemindersPopup и помещает ее в виде кнопки на панель задач до тех пор, пока не наступит контрольное время следующей записи. Вторая делает то же самое, но дополнительно обеспечивает автоматическое "развертывание" окна спустя заданный интервал времени (для примера установим его равным 10 минутам). Разумеется, пользователь имеет возможность в любой момент развернуть окно, щелкнув мышью кнопку формы. Напишем такой код для обработки нажатия соответствующих кнопок:

Private Sub cmdSleep_Click()
    UseSnooze = False ' режим Sleep (спрятать)
    WindowState = vbMinimized ' сворачиваем форму
    Visible = True
End Sub
Private Sub cmdSnooze_Click()
    UseSnooze = True
    ' режим Snooze (свернуть на время)
    ' устанавливаем время возврата окна — через 10 минут
    SnoozeTime = DateAdd("n', 10, Now())
    WindowState = vbMinimized
    Visible = True
End Sub

Код, уже сформированный нами в процедуре обработки таймера timReminders_Timer(), вполне годится для обработки режима Sleep, а для режима Snooze перед последним оператором End If нужно добавить такой код:

Else ' новых записей нет, но, может быть,
  ' истекло контрольное время режима Snooze?
  If UseSnooze Then ' режим Snooze
    If WindowState = vbMinimized Then
      'окно закрыто
      If Adodc1.Recordset.RecordCount > 0 Then
        ' есть записи
        If Now >= SnoozeTime Then
          ' время ожидания истекло
          WindowState = vbNormal ' раскрываем окно
        End If
      End If
    End If
  End If

Шаг 27. Мы закончили формирование формы frmRemindersPopup. Запустите ее на выполнение и убедитесь, что все созданные нами функции работают надлежащим образом (рис. 27).

Рис. 27

Продолжение статьи: Часть 2.2.

В начало статьи