Кнопки навигации на форме
Стандартный модуль mFormRecordButtons
Создай обычный стандартный модуль:
Создание → Модуль
Имя модуля:
mFormRecordButtons
И вставь туда код:
Option Compare Database
Option Explicit
' ============================================================
' УНИВЕРСАЛЬНЫЙ МОДУЛЬ УПРАВЛЕНИЯ ЗАПИСЯМИ ФОРМЫ
'
' Назначение:
' Универсальные процедуры для кнопок:
'
' - Сохранить
' - Создать
' - Удалить
' - Далее
' - Назад
' - переход на последнюю существующую запись
' - счетчик записей вида "5 из 35"
'
' Основные ограничения, которые учитываются:
'
' 1. Кнопка "Далее" НЕ переходит на пустую новую запись.
' Если текущая запись последняя — форма остается на последней записи.
'
' 2. Кнопка "Назад" НЕ вызывает ошибку на первой записи.
' Если текущая запись первая — форма остается на первой записи.
'
' 3. При удалении первой записи форма корректно переходит
' на новую первую запись.
'
' 4. При удалении последней записи форма корректно переходит
' на новую последнюю запись.
'
' 5. При удалении единственной записи форма остается без записей,
' без ошибки перехода.
'
' 6. Во время служебных операций используется флаг
' gFormRecordOperationBusy, чтобы Form_Current не обновлял
' счетчик в промежуточном состоянии формы.
'
' Пример использования в форме:
'
' Call SaveCurrentFormRecord(Me)
' Call CreateNewFormRecord(Me)
' Call DeleteCurrentFormRecord(Me)
' Call MoveToNextExistingRecord(Me)
' Call MoveToPreviousExistingRecord(Me)
' Call GoToLastExistingRecord(Me)
'
' Me.Нумерация = GetFormRecordPositionText(Me)
'
' Для подчиненной формы:
'
' Call MoveToNextExistingRecord(Me!ИмяПодчиненнойФормы.Form)
'
' ============================================================
' ------------------------------------------------------------
' Глобальный флаг служебной операции.
'
' Используется в Form_Current:
'
' If gFormRecordOperationBusy = True Then Exit Sub
'
' Это нужно, чтобы при удалении/переходах счетчик не обновлялся
' в промежуточном состоянии формы.
' ------------------------------------------------------------
Public gFormRecordOperationBusy As Boolean
' ------------------------------------------------------------
' Сохранить текущую запись формы
' ------------------------------------------------------------
Public Function SaveCurrentFormRecord( _
ByVal frm As Access.Form, _
Optional ByVal ShowSuccessMessage As Boolean = False, _
Optional ByVal SuccessMessage As String = "Запись сохранена.", _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
SaveCurrentFormRecord = False
If frm Is Nothing Then Exit Function
' Если запись изменена — сохраняем её
If frm.Dirty Then
frm.Dirty = False
End If
If ShowSuccessMessage = True Then
MsgBox SuccessMessage, vbInformation, "Сохранение"
End If
SaveCurrentFormRecord = True
Exit Function
ErrHandler:
If ShowErrors = True Then
MsgBox "Ошибка при сохранении записи:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Сохранение записи"
End If
SaveCurrentFormRecord = False
End Function
' ------------------------------------------------------------
' Создать новую запись
'
' Важно:
' Используется DoCmd.GoToRecord acNewRec.
' Если процедура вызывается из самой формы — работает штатно.
'
' Если кнопка находится на родительской форме и управляет
' подчиненной формой, перед вызовом лучше поставить фокус
' на элемент подчиненной формы.
' ------------------------------------------------------------
Public Function CreateNewFormRecord( _
ByVal frm As Access.Form, _
Optional ByVal SaveCurrentBeforeCreate As Boolean = True, _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
CreateNewFormRecord = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
' Проверяем, разрешено ли добавление записей
If frm.AllowAdditions = False Then
MsgBox "Добавление новых записей для этой формы запрещено.", _
vbExclamation, "Создание записи"
GoTo ExitHere
End If
' Сохраняем текущую запись перед созданием новой
If SaveCurrentBeforeCreate = True Then
If SaveCurrentFormRecord(frm, False, , ShowErrors) = False Then
GoTo ExitHere
End If
End If
' Пытаемся установить фокус на форму
On Error Resume Next
frm.SetFocus
On Error GoTo ErrHandler
' Переходим на новую запись
DoCmd.GoToRecord , , acNewRec
CreateNewFormRecord = True
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при создании новой записи:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Создание записи"
End If
CreateNewFormRecord = False
End Function
' ------------------------------------------------------------
' Удалить текущую запись формы
'
' Удаление выполняется через RecordsetClone и Bookmark,
' поэтому процедура корректно работает:
' - при удалении первой записи;
' - при удалении последней записи;
' - при удалении единственной записи;
' - с обычными формами;
' - с подчиненными формами.
' ------------------------------------------------------------
Public Function DeleteCurrentFormRecord( _
ByVal frm As Access.Form, _
Optional ByVal ConfirmDelete As Boolean = True, _
Optional ByVal ConfirmText As String = "Удалить текущую запись?", _
Optional ByVal ConfirmTitle As String = "Удаление записи", _
Optional ByVal ShowSuccessMessage As Boolean = False, _
Optional ByVal SuccessMessage As String = "Запись удалена.", _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
Dim answer As VbMsgBoxResult
Dim currentPosition As Long
Dim recordsBeforeDelete As Long
Dim recordsAfterDelete As Long
Dim rs As Object
DeleteCurrentFormRecord = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
' Новую несохраненную запись не удаляем
If frm.NewRecord Then
MsgBox "Новая запись ещё не сохранена. Удалять нечего.", _
vbInformation, "Удаление записи"
GoTo ExitHere
End If
' Проверяем, разрешено ли удаление
If frm.AllowDeletions = False Then
MsgBox "Удаление записей для этой формы запрещено.", _
vbExclamation, "Удаление записи"
GoTo ExitHere
End If
' Считаем записи до удаления
recordsBeforeDelete = GetFormRecordCount(frm)
If recordsBeforeDelete = 0 Then
MsgBox "Нет записей для удаления.", _
vbInformation, "Удаление записи"
GoTo ExitHere
End If
' Если запись изменена — сначала сохраняем её
If SaveCurrentFormRecord(frm, False, , ShowErrors) = False Then
GoTo ExitHere
End If
' Запоминаем текущую позицию.
' После удаления вернемся примерно на это же место.
currentPosition = GetFormCurrentRecordNumber(frm)
If currentPosition < 1 Then
currentPosition = 1
End If
' Подтверждение удаления
If ConfirmDelete = True Then
answer = MsgBox( _
ConfirmText, _
vbQuestion + vbYesNo + vbDefaultButton2, _
ConfirmTitle _
)
If answer <> vbYes Then GoTo ExitHere
End If
' Удаляем текущую запись через RecordsetClone
Set rs = frm.RecordsetClone
rs.Bookmark = frm.Bookmark
rs.Delete
rs.Close
Set rs = Nothing
' Обновляем форму после удаления
frm.Requery
' Считаем записи после удаления
recordsAfterDelete = GetFormRecordCount(frm)
' Если записи ещё остались — переходим на корректную позицию
If recordsAfterDelete > 0 Then
' Если удалили последнюю запись,
' текущая позиция станет больше количества оставшихся записей.
' Тогда переходим на новую последнюю запись.
If currentPosition > recordsAfterDelete Then
currentPosition = recordsAfterDelete
End If
If currentPosition < 1 Then
currentPosition = 1
End If
Call MoveToRecordNumberCore(frm, currentPosition)
End If
If ShowSuccessMessage = True Then
MsgBox SuccessMessage, vbInformation, "Удаление записи"
End If
DeleteCurrentFormRecord = True
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при удалении записи:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Удаление записи"
End If
DeleteCurrentFormRecord = False
End Function
' ------------------------------------------------------------
' Переход к следующей существующей записи
'
' Главное отличие от DoCmd.GoToRecord acNext:
' процедура НЕ переходит на новую пустую запись.
'
' Если текущая запись последняя — остаемся на ней.
' ------------------------------------------------------------
Public Function MoveToNextExistingRecord( _
ByVal frm As Access.Form, _
Optional ByVal SaveBeforeMove As Boolean = True, _
Optional ByVal ShowBoundaryMessage As Boolean = False, _
Optional ByVal BoundaryMessage As String = "Это последняя запись.", _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
Dim rs As Object
Dim recordsCount As Long
MoveToNextExistingRecord = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
recordsCount = GetFormRecordCount(frm)
If recordsCount = 0 Then
If ShowBoundaryMessage = True Then
MsgBox "Нет записей.", vbInformation, "Переход по записям"
End If
GoTo ExitHere
End If
' Перед переходом сохраняем текущую запись
If SaveBeforeMove = True Then
If SaveCurrentFormRecord(frm, False, , ShowErrors) = False Then
GoTo ExitHere
End If
End If
' Если сейчас новая запись, не идём дальше в новую.
' Возвращаемся на последнюю существующую запись.
If frm.NewRecord Then
Call MoveToRecordNumberCore(frm, recordsCount)
GoTo ExitHere
End If
Set rs = frm.RecordsetClone
rs.Bookmark = frm.Bookmark
rs.MoveNext
If rs.EOF Then
' Это последняя запись.
' Никуда не переходим.
If ShowBoundaryMessage = True Then
MsgBox BoundaryMessage, vbInformation, "Переход по записям"
End If
Else
frm.Bookmark = rs.Bookmark
MoveToNextExistingRecord = True
End If
rs.Close
Set rs = Nothing
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при переходе к следующей записи:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Переход по записям"
End If
MoveToNextExistingRecord = False
End Function
' ------------------------------------------------------------
' Переход к предыдущей существующей записи
'
' Если текущая запись первая — остаемся на первой записи.
' Ошибку "начальная запись - 1" не получаем.
' ------------------------------------------------------------
Public Function MoveToPreviousExistingRecord( _
ByVal frm As Access.Form, _
Optional ByVal SaveBeforeMove As Boolean = True, _
Optional ByVal ShowBoundaryMessage As Boolean = False, _
Optional ByVal BoundaryMessage As String = "Это первая запись.", _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
Dim rs As Object
Dim recordsCount As Long
MoveToPreviousExistingRecord = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
recordsCount = GetFormRecordCount(frm)
If recordsCount = 0 Then
If ShowBoundaryMessage = True Then
MsgBox "Нет записей.", vbInformation, "Переход по записям"
End If
GoTo ExitHere
End If
' Перед переходом сохраняем текущую запись
If SaveBeforeMove = True Then
If SaveCurrentFormRecord(frm, False, , ShowErrors) = False Then
GoTo ExitHere
End If
End If
' Если сейчас новая запись — возвращаемся на последнюю существующую
If frm.NewRecord Then
MoveToPreviousExistingRecord = MoveToRecordNumberCore(frm, recordsCount)
GoTo ExitHere
End If
Set rs = frm.RecordsetClone
rs.Bookmark = frm.Bookmark
rs.MovePrevious
If rs.BOF Then
' Это первая запись.
' Никуда не переходим.
If ShowBoundaryMessage = True Then
MsgBox BoundaryMessage, vbInformation, "Переход по записям"
End If
Else
frm.Bookmark = rs.Bookmark
MoveToPreviousExistingRecord = True
End If
rs.Close
Set rs = Nothing
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при переходе к предыдущей записи:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Переход по записям"
End If
MoveToPreviousExistingRecord = False
End Function
' ------------------------------------------------------------
' Перейти на последнюю существующую запись
'
' Используется, например, при загрузке формы.
' Не переходит на новую пустую запись.
' ------------------------------------------------------------
Public Function GoToLastExistingRecord( _
ByVal frm As Access.Form, _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
Dim recordsCount As Long
GoToLastExistingRecord = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
recordsCount = GetFormRecordCount(frm)
If recordsCount = 0 Then GoTo ExitHere
GoToLastExistingRecord = MoveToRecordNumberCore(frm, recordsCount)
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при переходе на последнюю запись:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Переход по записям"
End If
GoToLastExistingRecord = False
End Function
' ------------------------------------------------------------
' Перейти на первую существующую запись
' ------------------------------------------------------------
Public Function GoToFirstExistingRecord( _
ByVal frm As Access.Form, _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
Dim recordsCount As Long
GoToFirstExistingRecord = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
recordsCount = GetFormRecordCount(frm)
If recordsCount = 0 Then GoTo ExitHere
GoToFirstExistingRecord = MoveToRecordNumberCore(frm, 1)
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при переходе на первую запись:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbCritical, "Переход по записям"
End If
GoToFirstExistingRecord = False
End Function
' ------------------------------------------------------------
' Получить текст позиции записи
'
' По умолчанию возвращает:
' "5 из 35"
'
' Для новой записи:
' "Новая запись"
'
' Если записей нет:
' "0 из 0"
' ------------------------------------------------------------
Public Function GetFormRecordPositionText( _
ByVal frm As Access.Form, _
Optional ByVal SeparatorText As String = " из ", _
Optional ByVal EmptyText As String = "0 из 0", _
Optional ByVal NewRecordText As String = "Новая запись") As String
On Error GoTo ErrHandler
Dim recordsCount As Long
Dim currentNumber As Long
GetFormRecordPositionText = EmptyText
If frm Is Nothing Then Exit Function
recordsCount = GetFormRecordCount(frm)
If recordsCount = 0 Then
If frm.NewRecord Then
GetFormRecordPositionText = NewRecordText
Else
GetFormRecordPositionText = EmptyText
End If
Exit Function
End If
If frm.NewRecord Then
GetFormRecordPositionText = NewRecordText
Exit Function
End If
currentNumber = GetFormCurrentRecordNumber(frm)
If currentNumber < 1 Then currentNumber = 1
If currentNumber > recordsCount Then currentNumber = recordsCount
GetFormRecordPositionText = CStr(currentNumber) & SeparatorText & CStr(recordsCount)
Exit Function
ErrHandler:
GetFormRecordPositionText = EmptyText
End Function
' ------------------------------------------------------------
' Обновить счетчик записей в элементе управления
'
' CounterControlName:
' имя поля/надписи на форме.
'
' Поддерживает:
' - текстовое поле;
' - надпись.
' ------------------------------------------------------------
Public Sub UpdateFormRecordCounter( _
ByVal targetFrm As Access.Form, _
ByVal CounterControlName As String, _
Optional ByVal uiFrm As Access.Form = Nothing, _
Optional ByVal SeparatorText As String = " из ", _
Optional ByVal EmptyText As String = "0 из 0", _
Optional ByVal NewRecordText As String = "Новая запись", _
Optional ByVal ShowErrors As Boolean = True)
On Error GoTo ErrHandler
Dim counterText As String
If targetFrm Is Nothing Then Exit Sub
If Len(Trim(CounterControlName)) = 0 Then Exit Sub
If uiFrm Is Nothing Then
Set uiFrm = targetFrm
End If
counterText = GetFormRecordPositionText( _
frm:=targetFrm, _
SeparatorText:=SeparatorText, _
EmptyText:=EmptyText, _
NewRecordText:=NewRecordText _
)
Call SetControlText(uiFrm.Controls(CounterControlName), counterText)
Exit Sub
ErrHandler:
If ShowErrors = True Then
MsgBox "Ошибка при обновлении счетчика записей:" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbExclamation, "Счетчик записей"
End If
End Sub
' ------------------------------------------------------------
' Обновить счетчик и состояние кнопок
'
' targetFrm:
' форма, по записям которой работаем.
'
' uiFrm:
' форма, на которой находятся кнопки и счетчик.
'
' Если кнопки находятся на той же форме, что и записи,
' uiFrm можно не указывать.
'
' Если кнопки находятся на родительской форме,
' а управляют подчиненной формой:
'
' targetFrm := Me!ПодчиненнаяФорма.Form
' uiFrm := Me
' ------------------------------------------------------------
Public Sub RefreshFormRecordNavigationUi( _
ByVal targetFrm As Access.Form, _
Optional ByVal uiFrm As Access.Form = Nothing, _
Optional ByVal CounterControlName As String = "", _
Optional ByVal ButtonSaveName As String = "", _
Optional ByVal ButtonCreateName As String = "", _
Optional ByVal ButtonDeleteName As String = "", _
Optional ByVal ButtonNextName As String = "", _
Optional ByVal ButtonPreviousName As String = "", _
Optional ByVal SeparatorText As String = " из ", _
Optional ByVal EmptyText As String = "0 из 0", _
Optional ByVal NewRecordText As String = "Новая запись")
On Error Resume Next
Dim recordsCount As Long
Dim currentNumber As Long
If targetFrm Is Nothing Then Exit Sub
If uiFrm Is Nothing Then
Set uiFrm = targetFrm
End If
recordsCount = GetFormRecordCount(targetFrm)
currentNumber = GetFormCurrentRecordNumber(targetFrm)
' Счетчик записей
If Len(Trim(CounterControlName)) > 0 Then
Call UpdateFormRecordCounter( _
targetFrm:=targetFrm, _
CounterControlName:=CounterControlName, _
uiFrm:=uiFrm, _
SeparatorText:=SeparatorText, _
EmptyText:=EmptyText, _
NewRecordText:=NewRecordText, _
ShowErrors:=False _
)
End If
' Кнопка "Сохранить"
If Len(Trim(ButtonSaveName)) > 0 Then
Call SetControlEnabled( _
uiFrm.Controls(ButtonSaveName), _
(targetFrm.AllowEdits = True Or targetFrm.AllowAdditions = True) _
)
End If
' Кнопка "Создать"
If Len(Trim(ButtonCreateName)) > 0 Then
Call SetControlEnabled( _
uiFrm.Controls(ButtonCreateName), _
targetFrm.AllowAdditions _
)
End If
' Кнопка "Удалить"
If Len(Trim(ButtonDeleteName)) > 0 Then
Call SetControlEnabled( _
uiFrm.Controls(ButtonDeleteName), _
(recordsCount > 0 And targetFrm.NewRecord = False And targetFrm.AllowDeletions = True) _
)
End If
' Кнопка "Назад"
If Len(Trim(ButtonPreviousName)) > 0 Then
Call SetControlEnabled( _
uiFrm.Controls(ButtonPreviousName), _
(recordsCount > 0 And ((targetFrm.NewRecord = True) Or (currentNumber > 1))) _
)
End If
' Кнопка "Далее"
If Len(Trim(ButtonNextName)) > 0 Then
Call SetControlEnabled( _
uiFrm.Controls(ButtonNextName), _
(recordsCount > 0 And targetFrm.NewRecord = False And currentNumber < recordsCount) _
)
End If
End Sub
' ------------------------------------------------------------
' Получить количество текущих записей формы
'
' Учитывает:
' - источник записей формы;
' - текущий фильтр;
' - текущий набор записей.
' ------------------------------------------------------------
Public Function GetFormRecordCount(ByVal frm As Access.Form) As Long
On Error GoTo ErrHandler
Dim rs As Object
GetFormRecordCount = 0
If frm Is Nothing Then Exit Function
Set rs = frm.RecordsetClone
If rs.BOF And rs.EOF Then
GetFormRecordCount = 0
Else
rs.MoveLast
GetFormRecordCount = rs.RecordCount
End If
rs.Close
Set rs = Nothing
Exit Function
ErrHandler:
GetFormRecordCount = 0
End Function
' ------------------------------------------------------------
' Получить номер текущей записи
'
' Для обычной записи используется frm.CurrentRecord.
' Для новой записи возвращается Count + 1.
' ------------------------------------------------------------
Public Function GetFormCurrentRecordNumber(ByVal frm As Access.Form) As Long
On Error GoTo ErrHandler
If frm Is Nothing Then
GetFormCurrentRecordNumber = 0
ElseIf frm.NewRecord Then
GetFormCurrentRecordNumber = GetFormRecordCount(frm) + 1
Else
GetFormCurrentRecordNumber = frm.CurrentRecord
End If
Exit Function
ErrHandler:
GetFormCurrentRecordNumber = 0
End Function
' ------------------------------------------------------------
' Публичный переход к записи по номеру
'
' recordNumber:
' 1 — первая запись;
' 2 — вторая запись;
' и т.д.
' ------------------------------------------------------------
Public Function MoveToFormRecordNumber( _
ByVal frm As Access.Form, _
ByVal recordNumber As Long, _
Optional ByVal ShowErrors As Boolean = True) As Boolean
On Error GoTo ErrHandler
MoveToFormRecordNumber = False
gFormRecordOperationBusy = True
If frm Is Nothing Then GoTo ExitHere
MoveToFormRecordNumber = MoveToRecordNumberCore(frm, recordNumber)
ExitHere:
gFormRecordOperationBusy = False
Exit Function
ErrHandler:
gFormRecordOperationBusy = False
If ShowErrors = True Then
MsgBox "Ошибка при переходе к записи №" & recordNumber & ":" & vbCrLf & _
Err.Number & " - " & Err.Description, _
vbExclamation, "Переход к записи"
End If
MoveToFormRecordNumber = False
End Function
' ------------------------------------------------------------
' Внутренняя функция перехода к записи по номеру
'
' Не управляет gFormRecordOperationBusy.
' Используется внутри других процедур модуля.
' ------------------------------------------------------------
Private Function MoveToRecordNumberCore( _
ByVal frm As Access.Form, _
ByVal recordNumber As Long) As Boolean
On Error GoTo ErrHandler
Dim rs As Object
Dim recordsCount As Long
MoveToRecordNumberCore = False
If frm Is Nothing Then Exit Function
recordsCount = GetFormRecordCount(frm)
If recordsCount = 0 Then Exit Function
If recordNumber < 1 Then
recordNumber = 1
End If
If recordNumber > recordsCount Then
recordNumber = recordsCount
End If
Set rs = frm.RecordsetClone
rs.MoveFirst
If recordNumber > 1 Then
rs.Move recordNumber - 1
End If
frm.Bookmark = rs.Bookmark
rs.Close
Set rs = Nothing
MoveToRecordNumberCore = True
Exit Function
ErrHandler:
MoveToRecordNumberCore = False
End Function
' ------------------------------------------------------------
' Внутренняя процедура:
' записать текст в элемент управления
'
' Поддерживает:
' - Label / Надпись через Caption;
' - TextBox и прочие элементы через Value.
' ------------------------------------------------------------
Private Sub SetControlText( _
ByVal ctl As Access.Control, _
ByVal textValue As String)
On Error Resume Next
If ctl Is Nothing Then Exit Sub
Select Case ctl.ControlType
Case acLabel
ctl.Caption = textValue
Case Else
ctl.Value = textValue
End Select
End Sub
' ------------------------------------------------------------
' Внутренняя процедура:
' включить/отключить элемент управления
' ------------------------------------------------------------
Private Sub SetControlEnabled( _
ByVal ctl As Access.Control, _
ByVal enabledValue As Boolean)
On Error Resume Next
If ctl Is Nothing Then Exit Sub
ctl.Enabled = enabledValue
End Sub
Минимальный код в форме
В форме, где стоят кнопки Сохранить, Создать, Удалить, Далее, Назад и поле/надпись Нумерация, оставляешь такой код:
Option Compare Database
Option Explicit
' ------------------------------------------------------------
' При загрузке формы открываем последнюю существующую запись
' ------------------------------------------------------------
Private Sub Form_Load()
Call GoToLastExistingRecord(Me)
Me.Нумерация = GetFormRecordPositionText(Me)
End Sub
' ------------------------------------------------------------
' При переходе между записями обновляем счетчик
' ------------------------------------------------------------
Private Sub Form_Current()
' Если сейчас выполняется служебная операция удаления/перехода,
' не обновляем счетчик в промежуточном состоянии формы
If gFormRecordOperationBusy = True Then Exit Sub
Me.Нумерация = GetFormRecordPositionText(Me)
End Sub
' ------------------------------------------------------------
' После добавления записи обновляем счетчик
' ------------------------------------------------------------
Private Sub Form_AfterInsert()
Me.Нумерация = GetFormRecordPositionText(Me)
End Sub
' ------------------------------------------------------------
' После удаления записи обновляем счетчик
' ------------------------------------------------------------
Private Sub Form_AfterDelConfirm(Status As Integer)
Me.Нумерация = GetFormRecordPositionText(Me)
End Sub
' ------------------------------------------------------------
' Кнопка "Сохранить"
' ------------------------------------------------------------
Private Sub Сохранить_Click()
If SaveCurrentFormRecord(Me) = True Then
Me.Нумерация = GetFormRecordPositionText(Me)
End If
End Sub
' ------------------------------------------------------------
' Кнопка "Создать"
' ------------------------------------------------------------
Private Sub Создать_Click()
If CreateNewFormRecord(Me) = True Then
Me.Нумерация = GetFormRecordPositionText(Me)
End If
End Sub
' ------------------------------------------------------------
' Кнопка "Удалить"
' ------------------------------------------------------------
Private Sub Удалить_Click()
If DeleteCurrentFormRecord(Me) = True Then
Me.Нумерация = GetFormRecordPositionText(Me)
End If
End Sub
' ------------------------------------------------------------
' Кнопка "Далее"
' ------------------------------------------------------------
Private Sub Далее_Click()
Call MoveToNextExistingRecord(Me)
Me.Нумерация = GetFormRecordPositionText(Me)
End Sub
' ------------------------------------------------------------
' Кнопка "Назад"
' ------------------------------------------------------------
Private Sub Назад_Click()
Call MoveToPreviousExistingRecord(Me)
Me.Нумерация = GetFormRecordPositionText(Me)
End Sub
Вариант с автоматическим включением/отключением кнопок
Если хочешь, чтобы кнопка Далее отключалась на последней записи, Назад на первой, а Удалить отключалась на новой записи, вместо прямого обновления Me.Нумерация = ... можно сделать локальную процедуру:
Private Sub RefreshRecordUi()
Call RefreshFormRecordNavigationUi( _
targetFrm:=Me, _
CounterControlName:="Нумерация", _
ButtonSaveName:="Сохранить", _
ButtonCreateName:="Создать", _
ButtonDeleteName:="Удалить", _
ButtonNextName:="Далее", _
ButtonPreviousName:="Назад" _
)
End Sub
И тогда в событиях вызывать:
Call RefreshRecordUi
Например:
Private Sub Form_Current()
If gFormRecordOperationBusy = True Then Exit Sub
Call RefreshRecordUi
End Sub
А в кнопках:
Private Sub Далее_Click()
Call MoveToNextExistingRecord(Me)
Call RefreshRecordUi
End Sub
В этой версии логика из твоего старого кода сохранена: нет ухода на новую пустую запись через Далее, нет ошибки на первой записи через Назад, удаление первой/последней/единственной записи обрабатывается отдельно через позицию записи и RecordsetClone.