Программирование на Visual Basic | Microsoft Access, Excel, Word

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

Microsoft Access. Как напечатать отчет без драйвера Windows

05. Пример показывает использование файла "PRN" из Microsoft Access. Под ним в операционной системе хранится принтер, присоединенный к текущему компьютеру. Эти примеры выгружают данные на принтер, шрифт и т.п. используя разные варианты

Private Sub Report_Open(Cancel As Integer)
Dim ID As Byte
    On Error GoTo 999
    If MsgBox("Распечатать данные ?"  Chr(13)  "/Команды печати закоментированы/", _
              vbOKCancel + vbExclamation, "Печать") = vbOK Then
        MsgBox ("1. Проверка подчеркивания")
        '1. Проверка режима подчеркивания у принтера
        '   При вводе русских символов их надо вести в ДОСовской кодировке
        'ID = FreeFile
        'Open "c:\Epson_test.txt" For Output As #ID
        'Open "c:\Epson_test.txt" For Binary Access Write As #ID
        'Write #ID, Chr(27)  "-"  Chr(1)  "Test-underline"  Chr(27)  "-"  Chr(0)
        'Close #ID
'        FileCopy "Epson_test.txt", "PRN"
        
        MsgBox ("2. Загрузка шрифта")
        '2. Загрузка DOS - драйвера. Возьмите у поставщика или из Интернета
        'FileCopy "c:\Epson_Font_Driver", "PRN"
        
        MsgBox ("3. Печать отчета")
        '3. Настройте принтер на DRAFT-режим через кнопки управления и далее
        '   отпечатайте отчет в ДОСовской кодировке
        'DoCmd.OutputTo acOutputReport, "Пример 5", acFormatTXT, "PRN"
    End If
    Exit Sub
999:
    MsgBox Err.Description
    Err.Clear
End Sub

Microsoft Access. Проверка при закрытии формы

02. Когда пользователь работает с формой, то может возникнуть ситуация, что он не ввел в нее некоторые данные (Страна, Фамилия и т.п.). Этот алгоритм решает такую проблему, пока не будут введены данные в ключевые поля форма не закроется.

' Проверка при выгрузке окна
Private Sub Form_Unload(Cancel As Integer)
    If Nz(Me.Country, "") = "" Then
        Me.Country.Controls(0).ForeColor = RGB(255, 0, 0)
        MsgBox "НЕ заполнено поле Страна!", vbCritical, "Ошибка при вводе данных"
        Cancel = True ' Отменяем закрытие окна
        DoCmd.CancelEvent ' Отменяем последнее событие
        Exit Sub
    End If
    If Nz(Me.City, "") = "" Then
        Me.City.Controls(0).ForeColor = RGB(255, 0, 0)
        MsgBox "НЕ заполнено пол�� Город!", vbCritical, "Ошибка при вводе данных"
        Cancel = True ' Отменяем закрытие окна
        DoCmd.CancelEvent ' Отменяем последнее событие
        Exit Sub
    End If
    ' Запрашиваем закрытие окна
    If MsgBox("Закрыть окно !", vbInformation + vbOKCancel, "Выход из программы")  vbOK Then
        Cancel = True
        DoCmd.CancelEvent
    End If
End Sub

Microsoft Access. Изменить поля в запросах

10. Применяя функции в запросах SQL, можно добиться нужного формата полей в таблицах.

SELECT [Пример 10].Артикул AS Текст, CLng([Артикул]) AS Число1, CDbl([Артикул]) AS Число2 FROM [Пример 10];

Microsoft Access. PrimaryKey и удаление индекса

05. В этом примере, используя запросы SQL можно создать или удалить индекс

Private Sub butExecute_Click()
Dim dbs As Database
    On Error GoTo 999
    Set dbs = CurrentDb
    'Удаляем таблицу
    dbs.Execute "DROP TABLE [Пример 05]"
    
    'Создаем таблицу с индексом
    dbs.Execute "CREATE TABLE [Пример 05] " _
         "(Номер INTEGER CONSTRAINT Ключ1 PRIMARY KEY, " _
         "Книга CHAR(15), Описание CHAR, Сумма MONEY, Дата DATE);"
    
    'Сообщение
    MsgBox "Таблица создана!", vbInformation, "Индексы"
    Exit Sub
999:
    MsgBox Err.Description, vbCritical, "Создание поля"
    Err.Clear
End Sub

'==============================================================
'   Удаление индекса
Private Sub butDelete_Click()
Dim dbs As Database
    On Error GoTo 999
    Set dbs = CurrentDb
    'Удаляем индекс
    dbs.Execute "DROP INDEX Ключ1 ON [Пример 05] "
    'Сообщение
    MsgBox "Индекс Ключ1 удален!", vbInformation, "Индексы"
    Exit Sub
999:
    MsgBox Err.Description, vbCritical, "Создание индекса"
    Err.Clear
End Sub

Microsoft Access. Управление счетчиком таблиц

04. Для управления счетчиком в таблицах можно использовать эти функции

Private Sub butExecute_Click()
Dim idx As Index, fld As Field
        
        On Error Resume Next
        'Удаляем все лишнее
        tdf.Indexes.Delete "PrimaryKey" 'Удаляем индекс
        tdf.Indexes.Refresh 'Сохраняем изменение
        tdf.Fields.Delete "Код" 'Удаляем поле
        tdf.Fields.Refresh 'Изменяем таблицу
        Err.Clear 'Очищаем от ошибки, если нет поля
        
        On Error GoTo 999
       'Создаем поле "Счетчик" с новыми значениями
        Set fld = tdf.CreateField("Код") 'Создание
        fld.Type = dbLong 'Тип поля
        fld.Properties("Attributes") = dbAutoIncrField 'Назначение атрибутов счетчика
        tdf.Fields.Append fld 'Добавить поле
        tdf.Fields.Refresh 'Изменяем таблицу
        
        
        'Создаем индекс
        Set idx = tdf.CreateIndex("МойИндекс") 'Создаем индекс
        idx.Fields.Append idx.CreateField("Код") 'Добавляем поле в индекс
        idx.Name = "PrimaryKey" 'Изменение имени индекса
        idx.Primary = True      'Атрибут ключа
        tdf.Indexes.Append idx  'Добавить индекс
        tdf.Indexes.Refresh     'Сохраняем индекс
        
        'Сообщение
        MsgBox "Создан новый счетчик 'Код'!", vbInformation
    Exit Sub
999:
    MsgBox Err.Description, vbCritical, "Создание поля"
    Err.Clear
End Sub

'==============================================================
'   Удаляем поле и индекс
Private Sub butDelete_Click()
    On Error Resume Next
    tdf.Indexes.Delete "PrimaryKey" 'Удаляем индекс
    tdf.Indexes.Refresh 'Сохраняем изменение
    Err.Clear
    
    MsgBox "Индекс PrimaryKey удален!", vbInformation
End Sub

Microsoft Access. Загружаем данные в форум Dotnetnuke

Форум DNN - хранит сообщения в базе данных Microsoft SQL Server. Этот пример показывает как можно использовать Access для автоматизированной загрузки сообщений в форум. Обратите внимание на dnn_Forum_PostAdd. Application.FileSearch - не работает в Office 2007, используйте другую функцию (Dir) для получения списка файлов

Option Compare Database

' Все объекты объявления в форуме
Public Type tpAdds
    User As String     ' Имя пользователя
    Email As String    ' Имя почты
    AddDate As Date    ' Дата записи
    Subject As String  ' Тело
    Body As String     ' Текст
    Section As String  ' Секция
End Type

Public adds() As tpAdds   ' Объявления на одну тему
Public tags(10) As String ' Список тегов
Public fso                ' Объект файловой системы
Public frmMain As Form    ' Форма для вывода данных

' Читаем все файлы html
Public Function funReadHtml(frm As Form, MaxAdds As Long) ' Максимальное число объявлений, 0 - все загружаем
    Dim fname As String, html, buf, i As Long
    Dim cnn As ADODB.Connection
    
    ' Инициализация тегов для html файла
    Set frmMain = frm
    
    ' Поиск имени
    tags(0) = "size=""2"""
    tags(1) = "br"
    
    ' Поиск Email
    tags(2) = "mailto:"
    tags(3) = """"
    
    ' Поиск даты и времени
    tags(4) = "alt=""Email""/abrbr"
    tags(5) = "br/font"
    
    ' Поиск темы
    tags(6) = "u"
    tags(7) = "/u"
    
    ' Поиск сообщения
    tags(8) = "Сообщение:br"
    tags(9) = "/font/td"

    ' Разбор файлов
    With Application.FileSearch
        .NewSearch
        .LookIn = CurrentProject.Path  "\Data"
        .SearchSubFolders = False
        .fileName = "*.htm"
        If .Execute()  0 Then
            Set cnn = New ADODB.Connection
            cnn.CursorLocation = adUseClient
            If CurrentProject.IsConnected = True Then
                cnn.Open CurrentProject.AccessConnection.ConnectionString
            End If
            If MaxAdds = 0 Then MaxAdds = .FoundFiles.Count
            funPrintStatus " --- Старт: "  Now
            For i = 1 To MaxAdds
                fname = .FoundFiles(i)
                funPrintStatus "Прочитан файл: "  fname  ": "  Now
                ' Читаем файл
                Call fsoReadAllFile(fname, html)
                ' Разбор файла
                If Len(html)  10 Then
                    funWriteHtml cnn, html, fGetFileName(fname)
                    fMoveFile fname, fname  "1"
                End If
            Next i
            funPrintStatus "--- Конец: "  Now
            If CurrentProject.IsConnected = True Then
                cnn.Close
            End If
        Else
            MsgBox "В каталоге: "  .LookIn  " файлы не найдены! Возможно они были переименованы", vbExclamation, "Администратор"
        End If
    End With
End Function

' Сохраняем информацию в массиве объявлений
Public Function funWriteHtml(cnn As ADODB.Connection, html, fileName As String)
Dim i As Long, n As Long, p1 As Long, p2 As Long, k As Long, buffer As String, Sec As String

    ' Поиск границы данных, далее идет форма
    'p2 = InStr(1, html, "!---"  fileName  "---")
    p2 = InStr(1, html, ".htm---")
    buf = Split(Left(html, p2), "tr")
    
    ' Число строк
    n = UBound(buf)
    ' Название секции
    p1 = InStr(1, buf(1), "b  /b")
    p1 = InStr(p1 + 10, buf(1), "b  ") + 6
    p2 = InStr(p1, buf(1), " /b")
    If p2  p1 Then Sec = Mid(buf(1), p1, p2 - p1)
    If InStr(1, Sec, "") Then Sec = ""
    
    If n  2 Then
        ReDim adds(n - 3) ' Пропускаем 3 строки сверху
        For i = 3 To n
            p1 = 1 ' Начало поиска
            adds(i - 3).Section = Sec
            For j = 0 To 4
                ' Начало поиска
                k = InStr(p1, buf(i), tags(j * 2))
                ' Левый тег найден
                If k  0 Then
                    p1 = k + Len(tags(j * 2))
                    p2 = InStr(p1, buf(i), tags(j * 2 + 1))
                    ' Результат поиска правого тега - положительный
                    If p2  p1 Then
                        buffer = Mid(buf(i), p1, p2 - p1)
                        Select Case j
                        Case 0: adds(i - 3).User = buffer
                        Case 1: adds(i - 3).Email = buffer
                        Case 2: adds(i - 3).AddDate = CDate(Replace(buffer, "br", " "))
                        Case 3: adds(i - 3).Subject = buffer
                        Case 4: adds(i - 3).Body = buffer
                        End Select
                        ' Новая позиция поиска
                        p1 = p2 + Len(tags(j * 2 + 1))
                    End If
                End If
            Next
        Next
        ' Добавляем данные в конференцию
        dnn_Forum_PostAdd cnn, fileName
    End If
End Function

' Получаем имя файла
Public Function fGetFileName(strPath As String) As String
Dim fs
    On Error GoTo 999
    Set fs = CreateObject("Scripting.FileSystemObject")
    fGetFileName = fs.GetFileName(strPath)
    Set fs = Nothing
    
    Exit Function
999:
    MsgBox Err.Description, vbCritical, strPath
    Err.Clear
End Function

Public Function fMoveFile(strPath1 As String, strPath2 As String) As Boolean
Dim fs
    On Error GoTo 999
    Set fs = CreateObject("Scripting.FileSystemObject")
    fs.MoveFile strPath1, strPath2
    Set fs = Nothing
    Exit Function
999:
    'MsgBox Err.Description, vbCritical, strPath
    Err.Clear
    fDeleteFile = False
End Function


' Загрузка всего файла в буфер
Public Function fsoReadAllFile(fname, buffer)
Dim f
    ' Создаем файловую систему
     fsoCreateFileSystem
     
    ' Читаем весь файл
    If (fso.FileExists(fname)) Then
        Set f = fso.OpenTextFile(fname, 1, -1)
        buffer = f.ReadAll
        f.Close
        fsoReadAllFile = True
    Else
        fsoReadAllFile = False
    End If
End Function


Public Function fsoCreateFileSystem()
    If IsEmpty(fso) Then
        Set fso = CreateObject("Scripting.FileSystemObject")
    End If
End Function

' Печать информации
Private Sub funPrintStatus(txt As String)
    On Error GoTo 999
    If frmMain.txtStatus.ListCount  500 Then
        frmMain.txtStatus.RowSource = ""
    End If
    
    frmMain.txtStatus.RowSource = txt  ";"  frmMain.txtStatus.RowSource
    DoEvents
    frmMain.Repaint
    Exit Sub
999:
    frmMain.txtStatus.RowSource = ""
End Sub

'
' Добавляем объявления в конференцию Dotnetnuke
' Работает только при подключении к серверу с процедурой: Forum_PostAdd
'
Private Function dnn_Forum_PostAdd(cnn As ADODB.Connection, fileName As String) As Boolean
' Вспомогательные параметры
Dim cmd As New ADODB.Command, i As Long, PostID As Long, cnt As Long
    On Error GoTo 999
    If CurrentProject.IsConnected = False Then
        MsgBox "Необходи��о adp проект связать с базой данных dotnetnuke", vbCritical, "Admin"
        Exit Function
    End If
    PostID = 0
    Set cmd.ActiveConnection = cnn
    cmd.CommandText = "dnn_Forum_PostAdd" ' По умолчанию процедура добавления: Forum_PostAdd
    cmd.CommandType = adCmdStoredProc
    cmd.Parameters.Refresh ' Запрос параметров процедуры
    Dim rst As New ADODB.Recordset
    For i = 0 To UBound(adds)
         ' Инициализируем данные
        cmd.Parameters("@ParentPostID") = PostID
        cmd.Parameters("@ForumID") = 1  ' Access Forum
        cmd.Parameters("@UserID") = 19
        cmd.Parameters("@RemoteAddr") = ""
        cmd.Parameters("@Notify") = 0
        cmd.Parameters("@Subject") = adds(i).Subject
        cmd.Parameters("@Body") = adds(i).Body  "P.S. "  adds(i).Section  "brАвтор: a href=""mailto:"  adds(i).Email  """"  adds(i).User  "/a от "  adds(i).AddDate  " a href=""http://www.leadersoft.ru/rusboard/data/"  fileName  """Источник .../a"
        cmd.Parameters("@IsPinned") = 0
        cmd.Parameters("@PinnedDate") = adds(i).AddDate
        cmd.Parameters("@IsClosed") = 0
        cmd.Parameters("@Image") = ""
        cmd.Parameters("@mediaURL") = ""
        cmd.Parameters("@mediaNAV") = ""
        cmd.Parameters("@ObjectTypeCode") = 0
        cmd.Parameters("@ObjectID") = 0
        cmd.Parameters("@FileAttachmentURL") = ""
        cmd.Execute RecordsAffected:=cnt, options:=adExecuteNoRecords
        If cnt  0 And i = 0 Then
            PostID = DMax("PostID", "dnn_Forum_Posts") ' Запрос последнего добавленного сообщения
        End If
    Next
    Exit Function
999:
    MsgBox Err.Description, vbCritical, "Администратор"
End Function

' Закрыть текущее соединение
Public Function fCloseConnect()
    CurrentProject.OpenConnection "Provider="
End Function

Microsoft Access. Поиск в таблицах, как в Excel

03. С помощью функции GetRow можно организовать поиск в таблицы без применения DAO или ADO. Если таблица небольшая считываем данные в массив и поиск организуем уже в нем. Все работает быстро, т.к. не надо обращаться к функциям чтения записей.

Option Compare Database
Option Explicit
Dim myTable As Variant 'Массив данных из таблицы

'==============================================================
'   Заполнение массива
'   myTable(x,y)
'       х - это поля
'       y - это строки
Private Sub Form_Open(Cancel As Integer)
        myTable = funGetRows 'Заполняем массив
        myColumn_AfterUpdate 'Отображаем данные
End Sub

'==============================================================
'   Обновление строки
Private Sub myRow_AfterUpdate()
    Me.myColumnRow.Caption = "Данные в ячейке ("  _
        Me.myColumn  ","  _
        Me.myRow  "): "  _
        myTable(Me.myColumn, Me.myRow)
End Sub

'==============================================================
'   Обновление поля
Private Sub myColumn_AfterUpdate()
    myRow_AfterUpdate
End Sub

'   Заполнение массива
Public Function funGetRows() As Variant
Dim dbs As Database, rst As Recordset, i As Integer

    Set dbs = CurrentDb
    Set rst = dbs.OpenRecordset("SELECT * FROM [Мои книги] ORDER BY [Книга]")
    If rst.RecordCount  0 Then
        With rst
            .MoveLast 'Заполняем запрос
            .MoveFirst 'Устанавливаем строку
            i = rst.RecordCount 'определяем число записей
            funGetRows = rst.GetRows(i) 'Прочитываем данные
        End With
    End If
    rst.Close 'Закрываем запрос
    Set dbs = Nothing 'Закрываем базу
End Function

Microsoft Access. Как нарисовать объекты - линии в отчете

06. Используя небольшое количество графических функций отчета можно нарисовать линии, окружности и т.п.

'  Нарисовать объект (линию, прямоугольник) из таблицы
Private Sub newObject(rpt As Report, sTable As String)
Dim dbs As Database, rst As Recordset, i As Integer
Const PI = 3.14
    With rpt
        .ScaleMode = 6 'Рисуем в миллиметрах
        .FontName = "Arial" 'Выбираем шрифт
        .FontSize = 8 'Размер шрифта
        .ForeColor = 0 'Цвет объектов
    End With
    Set dbs = CurrentDb 'Текущая база данных
    Set rst = dbs.OpenRecordset(sTable) 'Открываем таблицу
    If rst.RecordCount  0 Then
        rst.MoveLast  'Заполняем запрос
        rst.MoveFirst 'Устанавливаем позицию
        For i = 0 To rst.RecordCount - 1 'Просматриваем запрос
          If rst!B = True Then 'Это прямоугольник
            rpt.Line (rst!x1, rst!y1)-(rst!x2, rst!y2), 0, B
          Else 'Это линия
            rpt.Line (rst!x1, rst!y1)-(rst!x2, rst!y2)
          End If
          rst.MoveNext 'Следующий элемент
        Next
    End If
    rst.Close
    'Рисуем окружность, элипс и дугу в радианах
    rpt.ForeColor = RGB(255, 0, 0) 'Красный цвет
    rpt.Circle (40, 20), 7 'Окружность
    rpt.ForeColor = RGB(0, 255, 0) 'Зеленый цвет
    rpt.Circle (40, 50), 20, , , , 0.5 'Элипс
    rpt.ForeColor = RGB(0, 0, 255) 'Синий цвет
    rpt.Circle (40, 50), 10, , PI / 2 + 0.5, PI, 0.5 'Дуга
End Sub

Microsoft Access. Отмена некоторых записей отчета

08. На этапе форматирования отчета, Вы можете управлять записями изменить их содержание или вообще не печатать. Такой метод позволяет Вам не менять запрос, а полностью перейти на управление отчетом из VBA

Private Sub ОбластьДанных_Format(Cancel As Integer, FormatCount As Integer)
    'Выбираем поле Даты и проверяем значения
    Select Case Me.Section(acDetail).Controls("Дата")
    Case Null 'Если нет даты, то отключаем запись
        Cancel = False
    Case Is = DateValue("31.12.1999") + 1 'Отображаем книги 2000 года
        Cancel = False 'Отключаем оставшиеся записи
    Case Else
        Cancel = True
    End Select
End Sub