Программирование на Visual Basic | Все записи admin

В этом разделе сайта находятся примеры из сборника программ "Архив файлов на Microsoft Access". В нем рассказывается о программировании форм, отчетов, таблиц и других объектов. Используйте этот архив для изучения работы с приложением Microsoft Office Access и программированием на Visual Basic for Application. Файлы исходников можно получить по этой ссылке: Купить и скачать

Microsoft Access. Отображение/скрытие окна приложения

05. Этот пример показывает как с использованием API интерфейса и других действий изменять главное окно Access.

' Константы отображения
Private Const SW_HIDE = 0
Private Const SW_SHOWNORMAL = 1
Private Const SW_NORMAL = 1
Private Const SW_SHOWMINIMIZED = 2
Private Const SW_SHOWMAXIMIZED = 3
Private Const SW_MAXIMIZE = 3
Private Const SW_SHOWNOACTIVATE = 4
Private Const SW_SHOW = 5
Private Const SW_MINIMIZE = 6
Private Const SW_SHOWMINNOACTIVE = 7
Private Const SW_SHOWNA = 8
Private Const SW_RESTORE = 9
Private Const SW_SHOWDEFAULT = 10
Private Const SW_MAX = 10

' Функция управляет отображением окна
Private Declare Function apiShowWindow Lib "user32" Alias "ShowWindow" _
    (ByVal hWnd As Long, _
     ByVal nCmdShow As Long) As Long

' Команды в котором создаются приложения
Dim appAcc As Access.Application

'  Отобразить окно
Private Sub butON_Click()
Dim s As String
    On Error Resume Next
    ' Выход из приложения
    Form_Close
    
    ' Открываем окно
    Set appAcc = New Access.Application
    s = Application.CurrentProject.Path  "\"  "la_form.mdb"
    appAcc.OpenCurrentDatabase (s)
    appAcc.Visible = True
    apiShowWindow appAcc.hWndAccessApp, Me.grShow
End Sub

'  Окно базы данных
Private Sub butWinDataBase_Click()
    DoCmd.SelectObject acForm, "Пример 05", True
    If Me.butWinDataBase = False Then
        DoCmd.RunCommand acCmdWindowHide
    End If
    DoCmd.SelectObject acForm, "Пример 05", False
End Sub

' Выход из системы
Private Sub Form_Close()
    On Error Resume Next
    appAcc.Quit acQuitSaveNone
    Err.Clear
End Sub

Microsoft Access. Вызов таймера с применением AddressOf

07. Этот пример показывает как с использованием API интерфейса запустить таймер для выполнения некоторой программы. При описании программы используется функция AddressOf, возвращающая указатель на внешнюю программу.

Private hTimer As Long ' Указатель на запущенный процесс

Private Const TIME_ONESHOT = 0 ' Событие случается однажды
Private Const TIME_PERIODIC = 1 ' Событие случается через uDelay миллисекунд

' Запуск процесса
Private Declare Function apiTimeSetEvent Lib "winmm.dll" Alias "timeSetEvent" _
 (ByVal uDelay As Long, _
  ByVal uResolution As Long, _
  ByVal lpFunction As Long, _
  ByVal dwUser As Long, _
  ByVal uFlags As Long) As Long

' Уничтожение процесса
Private Declare Function apiTimeKillEvent Lib "winmm.dll" Alias "timeKillEvent" _
 (ByVal uID As Long) As Long


' Функция запуска событий
Private Sub butExec_Click()
Dim uDelay As Long
Dim uResolution As Long
Dim dwUser As Long
Dim fuEvent As Long

   uDelay = Me.uDelay * 1000 ' Число секунд
   uResolution = Me.uResolution
   dwUser = Me.dwUser
   uFlags = Me.uFlags ' uFlags = TIME_PERIODIC
   hTimer = apiTimeSetEvent(uDelay, _
                           uResolution, _
                           AddressOf funTimerProc, _
                           dwUser, _
                           uFlags)
End Sub


' Программа для выполнения процесса таймера
Public Function funTimerProc(ByVal uID As Long, _
                          ByVal uMsg As Long, _
                          ByVal dwUser As Long, _
                          ByVal dw1 As Long, _
                          ByVal dw2 As Long) As Long
Dim frm As Form
    Set frm = Forms("Example 07")
    frm.msg = "Время: "  Format(time, "hh:nn:ss")  _
        ", ID= "  uID  _
        ", Msg="  uMsg  _
        ", User="  dwUser  _
        ", dw1="  dw1  _
        ", dw2="  dw2  vbNewLine  frm.msg
    funTimerProc = 0
'    Debug.Print uID, uMsg, dwUser, dw1, dw2
End Function

Microsoft Access. Бинарный вид файла Access

05. Данный пример показывает бинарный вид файла Access. Когда вы сможете читать файлы Access бинарным способом, то Вам не будут страшны программы взломщики. Например, Вы сохранили в базе данных свойства, которые используются для авторизации. Далее нашли в базе данных смещение и расчитали контрольную сумму этих байт. Используя для проверки авторизации это число, то можно понять как прошла авторизация. Если неправильно (взломщик переписал байты), то можно "аккуратно", не выключая программу, "подать к столу" "отравленные" данные (реверс строки, vbNewLine добавить в текст и т.п.).

'==============================================================
'   Загрузка файла
Public Function funLoadDataBase(strFile As String)
Dim dbs As DAO.Database, rst As DAO.Recordset
Dim j As Long
Dim strСмещение As String
Dim strИсходник As String
Dim strЦифровик As String
Dim ID As Byte, bt As Byte

    'Проверяем файл и читаем его
    If strFile  "" Then
        Me.Parent.Tag = "start"
        ' Удаляем все из таблицы
        Set dbs = CurrentDb
        dbs.Execute "DELETE * FROM [Пример 05]"
        Me.Requery
        On Error GoTo 999
            ID = FreeFile 'Получаем свободный идентификатор файла
            Set rst = dbs.OpenRecordset("SELECT * FROM [Пример 05]")
            Open strFile For Binary As ID 'Открываем файл
            j = 0
            Do While Not EOF(ID)    ' Проверка конца файла
                strСмещение = j 'или hex(j)
                strИсходник = ""
                strЦифровик = ""
                Me.Parent.myTimer.Caption = " Загрузка: "  Format(j, "000000")
                DoEvents
                Do While Not EOF(ID)    ' Проверка конца файла
                    j = j + 1
                    Get #ID, , bt 'Читаем байты
                    strЦифровик = strЦифровик  Format(CLng(bt), "000")  " "
                    If (bt  32) Or (bt  255) Then
                        strИсходник = strИсходник  "."
                    Else
                        strИсходник = strИсходник  Chr(bt)
                    End If
                    If (j \ 16) = (j / 16) Then Exit Do
                Loop
                ' Вставляем строку
                rst.AddNew
                rst!Смещение = strСмещение
                rst!Исходник = strИсходник
                rst!Цифровик = strЦифровик
                rst.Update
                If Me.Parent.Tag = "stop" Then Exit Do
            Loop
            rst.Close
            Me.Parent.myTimer.Caption = " Загрузка завершена"
            Me.Requery
            Close 'Закрываем открытые файлы
    End If
    Exit Function
999:
    MsgBox Err.Description
End Function

Microsoft Access. Управление текстовым буфером

04. Этот пример показывает как с использованием API интерфейса управлять буфером Windows. Используется класс и api интерфейс. Это более надежный способ, чем другие без api интерфейса.

' Функции управления буфером
Private Declare Function IsClipboardFormatAvailable Lib "user32" _
    (ByVal uFormat As Integer) As Integer
Private Declare Function apiOpenClipboard Lib "user32" Alias "OpenClipboard" _
    (ByVal hWnd As Long) As Integer
Private Declare Function apiSetClipboardData Lib "user32" Alias "SetClipboardData" _
    (ByVal uFormat As Integer, _
     ByVal hData As Long) As Long
Private Declare Function apiGetClipboardData Lib "user32" Alias "GetClipboardData" _
    (ByVal uFormat As Integer) As Long
Private Declare Function apiCloseClipboard Lib "user32" Alias "CloseClipboard" _
    () As Integer
Private Declare Function apiEmptyClipboard Lib "user32" Alias "EmptyClipboard" _
    () As Integer

' Функции управления памятью
Private Declare Function apiGlobalAlloc Lib "kernel32" Alias "GlobalAlloc" _
    (ByVal uFlags As Integer, _
     ByVal dwBytes As Long) As Long
Private Declare Function apiGlobalSize Lib "kernel32" Alias "GlobalSize" _
    (ByVal hMem As Long) As Integer
Private Declare Function apiGlobalLock Lib "kernel32" Alias "GlobalLock" _
    (ByVal hMem As Long) As Long
Private Declare Sub apiMoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (ByVal strDest As Any, _
     ByVal lpSource As Any, _
     ByVal Length As Long)
Private Declare Function apiGlobalUnlock Lib "kernel32" Alias "GlobalUnlock" _
    (ByVal hMem As Long) As Integer
Private Declare Function apiGlobalFree Lib "kernel32" Alias "GlobalFree" _
    (ByVal hMem As Long) As Long

' api-Константы памяти
Private Const GMEM_FIXED = H0
Private Const GMEM_MOVEABLE = H2
Private Const GMEM_NOCOMPACT = H10
Private Const GMEM_NODISCARD = H20
Private Const GMEM_ZEROINIT = H40
Private Const GMEM_MODIFY = H80
Private Const GMEM_DISCARDABLE = H100
Private Const GMEM_NOT_BANKED = H1000
Private Const GMEM_SHARE = H2000
Private Const GMEM_DDESHARE = H2000
Private Const GMEM_NOTIFY = H4000
Private Const GMEM_LOWER = GMEM_NOT_BANKED
Private Const GMEM_VALID_FLAGS = H7F72
Private Const GMEM_INVALID_HANDLE = H8000
Private Const GMEM_TEXT = (GMEM_MOVEABLE Or GMEM_DDESHARE)

' api-Форматы буфера
Private Const CF_TEXT = 1
Private Const CF_BITMAP = 2
Private Const CF_METAFILEPICT = 3
Private Const CF_SYLK = 4
Private Const CF_DIF = 5
Private Const CF_TIFF = 6
Private Const CF_OEMTEXT = 7
Private Const CF_DIB = 8
Private Const CF_PALETTE = 9
Private Const CF_PENDATA = 10
Private Const CF_RIFF = 11
Private Const CF_WAVE = 12
Private Const CF_UNICODETEXT = 13
Private Const CF_ENHMETAFILE = 14

'==============================================================
'  Копируем текст в буфер
'
Function CopyText(strText As String) As Variant
Dim hMem As Long
Dim lpMem As Long
Dim l As Long

    ' Выделение памяти
    l = Len(strText) + 1 ' Длина строки с учетом символа \0 (c++)
    hMem = apiGlobalAlloc(GMEM_TEXT, l) ' Память для буфера
    
    ' Управление памятью
    lpMem = apiGlobalLock(hMem) ' Блокируем часть памяти
    Call apiMoveMemory(lpMem, strText, l) ' Копируем строку в память
    Call apiGlobalUnlock(hMem) ' Разблокируем память
    
    ' Управление буфером
    Call apiOpenClipboard(0) ' Открываем буфер
    Call apiEmptyClipboard ' Очищаем буфер
    Call apiSetClipboardData(CF_TEXT, hMem) ' Загружаем текст
    Call apiCloseClipboard ' Закрываем буфер
    
    ' Освобождаем память
    Call apiGlobalFree(hMem)
End Function

'==============================================================
'  Получаем текст из буфера
'
Public Function GetText() As Variant
Dim hMem As Long
Dim lpMem As Long
Dim s As String
Dim l As Long

    ' Проверяем формат буфера
    If Not CBool(IsClipboardFormatAvailable(CF_TEXT)) Then
        Exit Function
    End If
   
    ' Работаем с буфером и памятью
    Call apiOpenClipboard(0) ' Открываем буфер
    hMem = apiGetClipboardData(CF_TEXT) ' Получаем заголовок данных в буфере
    l = apiGlobalSize(hMem) ' Определяем размер строки
    s = Space$(l) ' Выделение памяти для строки
    lpMem = apiGlobalLock(hMem) ' Блокируем память
    Call apiMoveMemory(s, lpMem, l) ' Копируем информацию из буфера в строку
    Call apiGlobalUnlock(hMem) ' Разблокирование памяти
    Call apiCloseClipboard ' Закрываем буфер
    
    ' Возвращаем результат
    GetText = Left$(s, InStr(1, s, Chr$(0)) - 1)
    
End Function

Microsoft Access. Защита открытия от ключа Shift

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

'==============================================================
'Название
'   Пример 3. Установить защиту
Private Sub butProtOn_Click()
    setProtShift False
    MsgBox "Защита установлена!"  Chr(13)  "Перезапустите базу данных!"
End Sub
'==============================================================
'Название
'   Пример 3. Снять защиту
Private Sub butProtOff_Click()
    setProtShift True
    MsgBox "Защита удалена!"  Chr(13)  "Перезапустите базу данных!"
End Sub
'==============================================================
'Название
'   Пример 3. Основная программа
'   если myFlag = True - защита установлена,
'   если myFlag = False - защита снята
Private Sub setProtShift(myFlag As Boolean)
    dbChangeProperty "StartupForm", DB_TEXT, "Автостарт" 'Первая форма
    dbChangeProperty "StartupShowDBWindow", DB_BOOLEAN, myFlag 'Главное окно Базы данных
    dbChangeProperty "StartupShowStatusBar", DB_BOOLEAN, myFlag 'Нижняя полоска экрана
    dbChangeProperty "AllowBuiltinToolbars", DB_BOOLEAN, myFlag 'Панели инструментов
    dbChangeProperty "AllowFullMenus", DB_BOOLEAN, myFlag 'Меню таблиц, форм и т.п.
    dbChangeProperty "AllowBreakIntoCode", DB_BOOLEAN, myFlag 'Ошибки в модуле
    dbChangeProperty "AllowSpecialKeys", DB_BOOLEAN, myFlag 'Специальные ключи (CTRL+BREAK, ...)
    dbChangeProperty "AllowBypassKey", DB_BOOLEAN, myFlag 'Ключ Shift
End Sub

'==============================================================
'Название
'   Пример 3. Изменить/создать свойство базы данных (см. лекции 2е-2f)
'Параметры:
'   strName - имя свойства (Description, Format ...)
'   varType - тип свойства (dbText, dbLong ...)
'   varValue - значение свойства
'
Function dbChangeProperty(strName As String, varType As Variant, varValue As Variant) As Boolean
Dim prp As Variant, dbs As Database
    
    On Error GoTo 999 'Назначаем переход по ошибке
    dbChangeProperty = False 'Возвращаем результат при ошибке
    
    Set dbs = CurrentDb 'Выбираем базу
    dbs.Properties(strName) = varValue 'Присваиваем значение
    
    dbChangeProperty = True 'Возвращаем результат
    Exit Function 'Выходим из программы
999:
    If Err = 3270 Then  'Свойство не найдено
        Set prp = dbs.CreateProperty(strName, varType, varValue) 'Создаем свойство
        dbs.Properties.Append prp 'Добавляем свойство
        Err.Clear 'Очищаем поток от ошибки
        Resume Next 'Возвращаемся к следующему оператору
    End If
    Err.Clear 'Очищаем от незнакомой ошибки
End Function

Microsoft Access. Защита реверсом полей базы данных

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

Private Sub Form_Current()
    Me.Parent.myPhone.Caption = "Правильный телефон: "  Format(StrReverse(Me.Телефон), "@@@-@@-@@")
End Sub

Microsoft Access. Использование серийных номеров дисков

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

'  Получаем информацию о серийных номерах
'
Private Sub Form_Load()
Dim fs, dc, D, s As String
On Error Resume Next
    s = ""
    ' Получаем информацию о файловой системе
    Set fs = CreateObject("Scripting.FileSystemObject")
    Set dc = fs.Drives
    For Each D In dc
        s = s  D.DriveLetter  ": серийный номер: "  D.SerialNumber  ";"
        Err.Clear
    Next D
    Me.myList.RowSource = s
End Sub

Microsoft Access. Рисование объектов в форме.

02. Данный способ позволяет вам нарисовать некоторые объекты в форме, хотя в программе Международный Туризм использовался другой алгоритм для рисования карты. Этот способ может Вам пригодится в некоторых случаях. Рисуются линии, точки, элипсы, многоугольники, т.е. те базовые объекты, которые применяются в api интерфейсе.

' Функция используется для поиска окна
 Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
  (ByVal hWndParent As Long, _
   ByVal hWndChildAfter As Long, _
   ByVal lpClassname As String, _
   ByVal lpWindowName As String) As Long

' Функция возвращает контекст устройства для рисования
Private Declare Function apiGetDC Lib "user32" Alias "GetDC" _
    (ByVal hwnd As Long) _
    As Long
 
' Функция освобождает контекст устройства для других приложений
Private Declare Function apiReleaseDC Lib "user32" Alias "ReleaseDC" _
    (ByVal hwnd As Long, _
    ByVal hDc As Long) _
    As Long

'==============================================================
' Далеее идут, функции управляющие рисованием

' Функция рисует точку на экране
Private Declare Function apiSetPixel Lib "gdi32" Alias "SetPixel" _
    (ByVal hDc As Long, _
     ByVal x As Long, _
     ByVal Y As Long, _
     ByVal crColor As Long) As Long

' Функция рисует линию из текущей позиции "пера" до точки с координатами
' x,y, но не включая ее саму. Линия рисуется с помощью выбранного "пера". Если
' нет ошибки, то текущее положение пера устанавливается в точку с координатами
' (x,y)
Private Declare Function apiLineTo Lib "gdi32" Alias "LineTo" _
    (ByVal hDc As Long, _
    ByVal x As Integer, _
    ByVal Y As Integer) _
    As Long

' Функция рисует дугу элипса с помощью выбранного "пера".
' Дуга рисуется против часовой стрелки.
' (x1,y1  - x2,y2) ограничивающий прямоугольник для дуги.
' (x3,y3) - начальная точка рисования "пером"
' (x4,y4) - конечная точка рисования дуги
Private Declare Function apiArc Lib "gdi32" Alias "Arc" _
    (ByVal hDc As Long, _
    ByVal X1 As Integer, _
    ByVal Y1 As Integer, _
    ByVal X2 As Integer, _
    ByVal Y2 As Integer, _
    ByVal X3 As Integer, _
    ByVal Y3 As Integer, _
    ByVal X4 As Integer, _
    ByVal Y4 As Integer) _
    As Long
' Функция рисует прямоугольник с помощью выбранного "пера".
' (x1,y1) - первый угол
' (x2,y2) - противоположный угол
Private Declare Function apiRectangle Lib "gdi32" Alias "Rectangle" _
    (ByVal hDc As Long, _
    ByVal X1 As Long, _
    ByVal Y1 As Long, _
    ByVal X2 As Long, _
    ByVal Y2 As Long) As Long

' Функция передвигает позицию рисования
' (x,y) - новая точка
' (lpPoint) - предыдущая точка
Private Declare Function apiMoveTo Lib "gdi32" Alias "MoveToEx" _
    (ByVal hDc As Long, _
     ByVal x As Long, _
     ByVal Y As Long, _
     lpPoint As POINTAPI) As Long
' Структура координаты точки
Private Type POINTAPI
    x As Long
    Y As Long
End Type

' Функция рисует элипс с помощью выбранного "пера".
' (x1,y1) - первый угол
' (x2,y2) - противоположный угол
Private Declare Function apiEllipse Lib "gdi32" Alias "Ellipse" _
    (ByVal hDc As Long, _
     ByVal X1 As Long, ByVal Y1 As Long, _
     ByVal X2 As Long, ByVal Y2 As Long) As Long

' Функция рисует ломаную с помощью выбранного "пера"
' lpPoint - массив точек
' nCount - число точек
Private Declare Function apiPolyline Lib "gdi32" Alias "Polyline" _
    (ByVal hDc As Long, _
     lpPoint As POINTAPI, _
     ByVal nCount As Long) As Long

' Функция рисует ломаную с помощью выбранного "пера"
' lpPoint - массив точек
' nCount - число точек
Private Declare Function apiPolygon Lib "gdi32" Alias "Polygon" _
    (ByVal hDc As Long, _
     lpPoint As POINTAPI, _
     ByVal nCount As Long) As Long

' Функция заливает круг с помощью выбранного "пера"
' (x1,y1  - x2,y2) ограничивающий прямоугольник для дуги
' (x3,y3) - начальная точка рисования "пером"
' (x4,y4) - конечная точка рисования дуги
Private Declare Function apiChord Lib "gdi32" Alias "Chord" _
    (ByVal hDc As Long, _
     ByVal X1 As Long, ByVal Y1 As Long, _
     ByVal X2 As Long, ByVal Y2 As Long, _
     ByVal X3 As Long, ByVal Y3 As Long, _
     ByVal X4 As Long, ByVal Y4 As Long) As Long

' Функция заливает круг с помощью выбранного "пера"
' (x1,y1  - x2,y2) ограничивающий прямоугольник для дуги
' (x3,y3) - начальная точка рисования "пером"
' (x4,y4) - конечная точка рисования дуги
Private Declare Function apiPie Lib "gdi32" Alias "Pie" _
    (ByVal hDc As Long, _
     ByVal X1 As Long, ByVal Y1 As Long, _
     ByVal X2 As Long, ByVal Y2 As Long, _
     ByVal X3 As Long, ByVal Y3 As Long, _
     ByVal X4 As Long, ByVal Y4 As Long) As Long

'==============================================================
'  Назначение
'    Нарисовать объекты
'
Private Sub butExecute_Click()
Dim hwnd As Long, hDc As Long 'Окно и контекст рисования
Dim X1 As Long, Y1 As Long, X2 As Long, Y2 As Long
Dim xy(3) As POINTAPI 'Точки рисования
On Error GoTo 999
 
    'Очистить зону рисования
    Me.Refresh
    DoEvents
    
    'Поиск окна для рисования. Это решение предложено
    'Николаем Малютиным г.Якутск: malnik@mail.ru
    hwnd = FindWindowEx(Me.hwnd, FindWindowEx(Me.hwnd, 0, "OFormSub", ""), "OFormSub", "")
    
    'Выбираем контекст устройства
    hDc = apiGetDC(hwnd)
    
    'Координаты зоны рисования
    X1 = 15
    Y1 = 90
    X2 = 180
    Y2 = 250
    
    'Рисуем объекты
    Select Case Me.Объекты
        Case 1: 'Точка - красная
            Call apiSetPixel(hDc, X2 / 2, Y2 / 2, RGB(255, 0, 0))
        Case 2: 'Линия
            Call apiMoveTo(hDc, X1, Y1, xy(0)) 'Передвигаем указатель
            Call apiLineTo(hDc, X2, Y2) 'Рисуем линию
        Case 3: 'Элипс
            Call apiEllipse(hDc, X1, Y1, X2, Y2 / 2)
        Case 4: 'Прямоугольник - закрашенный
            Call apiRectangle(hDc, X1, Y1, X2, Y2)
        Case 5: 'Дуга
            Call apiArc(hDc, X1, Y1, X2, Y2, 50, 100, 150, 150)
        Case 6, 7: 'Ломаная, Заливка
            ' Загружаем координаты
            xy(0).x = X1
            xy(0).Y = Y1
            xy(1).x = X1 + 20
            xy(1).Y = Y2
            xy(2).x = X2
            xy(2).Y = Y2 - 20
            If Me.Объекты = 6 Then 'Ломаная
                Call apiPolyline(hDc, xy(0), UBound(xy))
            Else 'Заливка
                Call apiPolygon(hDc, xy(0), UBound(xy))
            End If
        Case 8: 'Заливка круга до хорды
            Call apiChord(hDc, X1, Y1, X2, Y2, 50, 100, 150, 150)
        Case 9: 'Заливка круга из центра
            Call apiPie(hDc, X1, Y1, X2, Y2, 50, 100, 150, 150)
    End Select
    
    'Освобождаем контекст устройства
    Call apiReleaseDC(hwnd, hDc)
    Exit Sub
999:
    MsgBox Err.Description  'Ошибка
    Err.Clear
End Sub

Microsoft Access. Создание TreeView в Microsoft Access

Данный пример показывает как можно использовать элемент TreeView в Microsoft Access. Не забудьте подключить в новых файлах C:\Windows\System32\mscomctl.ocx

Public WithEvents myTV As MicrosoftTree

'  Управление Microsoft TreeView c демонстрацией событий
Private Sub butCreate_Click()
    If myTV Is Nothing Then
        ' Создание объекта
        Set myTV = New MicrosoftTree
        Set myTV.Tree = Me.myTree.Object
        ' Загружаем узлы дерева
        myTV.Load "SELECT * FROM [TableTreeView] Order By [Index]"
    End If
End Sub

'   Добавим событие-сообщение для нового класса
Public Sub myTV_Progress(myMsg As String)
    If Me.butEvents Then
        Me.myEvents = myMsg  vbNewLine  Me.myEvents
        DoEvents
    End If
End Sub
Private Sub myTree_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Long, ByVal y As Long)
   myTV_Progress "MouseDown"
   myTV.MouseDown Button, Shift, x, y
End Sub
Private Sub butEvents_AfterUpdate()
    Me.myEvents = ""
End Sub

'   Освобождение ресурса
Private Sub Form_Close()
    Set myTV = Nothing
End Sub

' ------------ Класс -----------
'==============================================================
'  Переменные и события

' Объявляем класс Tree
Public WithEvents Tree As TreeView

' Объявляем событие для сообщений
Public Event progress(strMsg As String)

' Переменные для перемещения
Private Type DropDrag
    idxStart As Long ' Начальный узел перемещения
    idxEnd As Long   ' Конечный узел перемещения
End Type

Private drag As DropDrag ' Переменная перемещения

'==============================================================
'  События при создании/уничтожении класса
Private Sub Class_Initialize()
   ' Инициализация
   'funPrintEvent "Class_Initialize"
End Sub
Private Sub Class_Terminate()
   ' Сохраняем данные
   'funPrintEvent "Class_Terminate"
End Sub

'==============================================================
'  События до/после редактирования метки узла
Private Sub Tree_BeforeLabelEdit(Cancel As Integer)
   funPrintEvent "BeforeLabelEdit"
End Sub
Private Sub Tree_AfterLabelEdit(Cancel As Integer, NewString As String)
   funPrintEvent "AfterLabelEdit: "  NewString
   Me.Tree.SelectedItem.ForeColor = 255
End Sub

'==============================================================
'  События при работе с узлами дерева
Private Sub Tree_NodeClick(ByVal node As node)
   funPrintEvent "NodeClick: "  node.Text
End Sub
Private Sub Tree_NodeCheck(ByVal node As node)
   funPrintEvent "NodeCheck: "  node.Text
End Sub
Private Sub Tree_Expand(ByVal node As node)
   funPrintEvent "Expand: "  node.Text
End Sub
Private Sub Tree_Collapse(ByVal node As node)
   funPrintEvent "Collapse: "  node.Text
End Sub

'==============================================================
'  События при управлении левой кнопкой мыши
Private Sub Tree_Click()
    funPrintEvent "Click"
End Sub
Private Sub Tree_DblClick()
    funPrintEvent "DblClick"
End Sub

'==============================================================
'  События клавиатуры
Private Sub Tree_KeyUp(KeyCode As Integer, ByVal Shift As Integer)
    funPrintEvent "KeyUp (KeyCode: "  KeyCode  ", Shift = "  Shift  ")"
End Sub
Private Sub Tree_KeyDown(KeyCode As Integer, ByVal Shift As Integer)
   funPrintEvent "KeyDown (KeyCode: "  KeyCode  ", Shift = "  Shift  ")"
End Sub
Private Sub Tree_KeyPress(KeyAscii As Integer)
   funPrintEvent "KeyPress: "  KeyAscii
End Sub

'==============================================================
' События для перемещения типа DragDrop. Возможны только при
' настройках TreeView. Например,
'        .OLEDragMode = ccOLEDragAutomatic
'        .OLEDropMode = ccOLEDropManual

' Событие. Начало перемещения.
Private Sub Tree_OLEStartDrag(Data As DataObject, AllowedEffects As Long)
    ' AllowedEffects = ccOLEDropEffectCopy ' Доступные режимы
    funPrintEvent "OLEStartDrag"
    Set Me.Tree.DropHighlight = Nothing ' Освобождение ресурса
    drag.idxEnd = -1 ' Освобождение позиции
End Sub

' Событие. Изменение координат мыши x и y.
' Для определения текущего узла используем: DropHighlight, HitTest(X, y)
Private Sub Tree_OLEDragOver(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single, State As Integer)
    funPrintEvent "OLEDragOver: x="  x  ", y="  y
    With Me.Tree
        Set .DropHighlight = .HitTest(x, y)
    End With
End Sub
' Событие - Срабатывает после OLEDragOver
Private Sub Tree_OLEGiveFeedback(Effect As Long, DefaultCursors As Boolean)
    funPrintEvent "OLEGiveFeedback: Effect="  Effect  ", defaultCursors="  DefaultCursors
End Sub
' Событие. Последние событие до завершения перемещения.
Private Sub Tree_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)
   With Me.Tree
        Set .DropHighlight = .HitTest(x, y) ' Узел завершения
        funPrintEvent "OLEDragDrop: "  Nz(.HitTest(x, y))
        If Not .DropHighlight Is Nothing Then
             drag.idxEnd = .HitTest(x, y).Index
        End If
   End With
End Sub

' Событие. Завершение перемещения
' Для определения действий с узлами использем DropHighlight и SelectedItem
Private Sub Tree_OLECompleteDrag(Effect As Long)
Dim strKey As String
    'Me.Tree.MousePointer = ccArrow
    With Me.Tree
        Set .DropHighlight = Nothing ' Освобождаем объект
        If (drag.idxStart = -1) Or _
           (drag.idxEnd = -1) Or _
           (drag.idxStart = drag.idxEnd) Then
             funPrintEvent "OLECompleteDrag: None"
        Else
             funPrintEvent "OLECompleteDrag: "  .Nodes(drag.idxStart).Text  " - "  .Nodes(drag.idxEnd).Text
             ' Функция обработки операции DragDrop
             strKey = "la_"  Time
             ' Добавляем узел красного цвета
             Set .SelectedItem = .Nodes.Add(.Nodes(drag.idxEnd).Key, tvwChild, strKey, "Новый узел")
             .SelectedItem.ForeColor = 255
        End If
    End With
End Sub

' Событие. Установка данных
Private Sub Tree_OLESetData(Data As DataObject, DataFormat As Integer)
    funPrintEvent "OLESetData"
End Sub

' Событие. Обработка нажатия клавиши
Public Sub MouseDown(Button As Integer, Shift As Integer, x As Long, y As Long)
    With Me.Tree
        If .HitTest(x, y) Is Nothing Then
            drag.idxStart = -1
        Else
            Set .SelectedItem = .HitTest(x, y)
            drag.idxStart = .SelectedItem.Index
        End If
    End With
    If Button = acLeftButton Then
        drag.idxEnd = -1 ' Индекс последнего элемента не известен
    End If
End Sub

'==============================================================
'   Собственные свойства класса

Public Function Load(strSQL As String) As Boolean
Dim myУзел As String, myКлюч As String, idx As Long
Dim rst As ADODB.Recordset
    On Error GoTo 999
    
    ' Загрузка дерева
    Set rst = New ADODB.Recordset
    rst.Open strSQL, Application.CurrentProject.Connection
    Me.Tree.Nodes.Clear
    Do Until rst.EOF
        ' Создание узла и его ключей
        myУзел = "la_"  rst!Relative
        myКлюч = "la_"  rst!Key
        If Not IsNull(rst!Relative) Then
             idx = Me.Tree.Nodes.Add(myУзел, tvwChild, myКлюч).Index
        Else
             idx = Me.Tree.Nodes.Add(, , myКлюч).Index
        End If
        ' Изменение нового узла
        With Me.Tree.Nodes(idx)
            .Text = Nz(rst!Text)
            .Selected = True
        End With
        rst.MoveNext
    Loop
    
    ' Настраиваем класс
    With Me.Tree
        ' Разрешаем операцию DragDrop
        .OLEDragMode = ccOLEDragAutomatic
        .OLEDropMode = ccOLEDropManual
        
        ' Настраиваем дерево
        .Style = tvwTreelinesPlusMinusText ' Общий вид дерева
        .LineStyle = tvwRootLines ' Использование корневого узла
        .Indentation = 300 ' Длина штриха узла
        .Checkboxes = True ' Показываем флажки
    End With
    
    Load = True
    
998:
    rst.Close
    Set rst = Nothing
    Err.Clear
    Exit Function
999:
    Load = False
    MsgBox Err.Description
    On Error Resume Next
    Resume 998
End Function

'==============================================================
'   Функция сообщающая о получении событий
Private Function funPrintEvent(myMsg As String)
    RaiseEvent progress(myMsg) ' Генерируем событие для узла
End Function

Microsoft Access. Использование StatusBar в Microsoft Access

Данный пример показывает как можно использовать элементStatusBar в Microsoft Access. Не забудьте подключить в новых файлах C:\Windows\System32\mscomctl.ocx

Private WithEvents sl As Slider ' Скользящая шкала
Dim sb As statusBar ' Строка комментариев
Dim pr As ProgressBar ' Шкала загрузки

'
' Настройка процесса в форме
Private Sub Form_Open(Cancel As Integer)
   
   ' Инициализация
   Set sl = Me.mySlider.Object
   sl.Min = 1
   sl.Max = 50
   sl.Value = 25
   
   ' Инициализация указателя загрузки
   Set pr = Me.myProgressBar.Object
   pr.Min = 1
   pr.Max = 10000
   
   ' Инициализация панелей
   Set sb = Me.myStatusBar.Object
   With sb.Panels
      .Clear ' Удаление всех данных
      .Add 1, "k1", "Загрузка"
      .Add 2, "k2", " "
      .Item(1).MinWidth = 850 ' Ширина панели
   End With
End Sub

'   Запуск процесса
Private Sub butProgress_Click()
Dim i As Long
    Me.Tag = "Start"
    For i = 1 To 10000
        ' Меняем сообщение с определенным шагом
        If (i / sl.Value) = (i \ sl.Value) Then
            pr.Value = i
            sb.Panels(2).Text = "Всего: "  i
            DoEvents ' Надо только для события sl_Change
        End If
        If Me.Tag = "Stop" Then Exit For
    Next i
    pr.Value = 1
    sb.Panels(2).Text = ""
End Sub

'   Определение события Slider
Private Sub sl_Change()
    Me.Tag = "Stop" ' Определяем флаг для выхода из процесса
End Sub

'   Освобождение ресурсов
Private Sub Form_Close()
    Set pr = Nothing
    Set sb = Nothing
End Sub