Archive for the ‘решения’ Category
Как получить значение поля таблицы
Очень часто новички сталкиваются с задачей прочитать значение из поля таблицы. Например, они знают о существовании библиотек DAO или ADO и пишут свою функцию для вычисления этой операции (или не пишут, а идут на форумы спрашивать
). Но ведь есть встроенные. Знакомьтесь:
- DLookUp
- DFirst
- DLast
- DCount
- DMax
- DMin
У всех этих функций одинаковые параметры: имя поля или выражение, таблица, условие отбора. Возвращать они могут Null (кроме DCount), по этому использование nz() не будет лишним.
И напоследок пара примеров использования:
Public Sub test()
Dim stKlient As String
Dim lK_KLIENT As Long
Dim count As Long
lK_KLIENT = 123
stKlient = Nz(DLookup("T_KLIENT", "b_klient", "K_KLIENT = " & lK_KLIENT))
count = DCount("*", "b_klient", "T_KLIENT LIke '" & Left(stKlient, 3) & "*'")
End Sub
До встречи!
(с) Скоков Сергей
Подписаться на: RSS или e-mail рассылку или добавить в ЖЖ друзья.
Как создать меню в MS Access
Всем привет!
Как оказалось очень полезно смотреть ключевые слова, по которым пользователи переходят на мой сайт. В них можно найти новые тему. Например, как эту. Оказывается, у некоторых это вызывает трудности.
Как создать меню
В прошлой статье про меню я забыл дорасказать, как же все же добавляеть новые пункты меню в строку меню. По-этом рекомендую сперва ознакомится с прошлым постом и пеерходить к чтению этого.
Как создать пункты меню

Чтобы сюда попасть можно выбрать пункт меню MS Access “Сервис – Настройка” или кликнуть в пустом месте меню и в контестном меню выбрать пункт “Настройка”.

Теперь все внимание на вкладку “Команды” нового окошка.
В категории “Файл” вы найдете пункт меню “Специальная”. Это рабочая лошадка меню. На самом деле это кнопка.

В категории “Новое меню” найдете выпадающее меню “Новое меню”. На самом деле это поле с выпадающим списком.
Еще в категории “Все формы” и т.п. вы найдете соостветственно готовые пункты меню. У них есть свои особенности. Об этом ниже.
Это все “многообразие” элементов можно при помощи перетаскивания перенести на свою строку меню или панель инструментов (я надеюсь вы прочитали предыдущую статью и знаете как это делать).

Как выполнить действие
Тут самое интересное. Только не закрывайте чудесное окошко “Настройка”. Кликните правой кнопочкой мыши на любом пункте меню (не список!) и в контекстном меню выберете пункт “Свойства”. У вас откроется следующее окошко:

Все поля содержат описание и понятны. При помощи этого пункта меню можно вызвать любую функцию из модуля, написав так =MyFunction(). Чаще всего я использую именно этот способ, т.к. частенько формы открываются с какими-то параметрами.
Особенности открытия форм
А теперь давайте таким же образом откроем пункт меню, созданный перетаскиванием пункта из группы “Все формы”, например.

В свойстве “Параметр” вы обнаружите имя формы. Так вот, если прописать это же имя в пункте меню из группы “File”, то форма не откроется. Вот такой чудесный нюанс.
В следующий раз опишу о программном создании и управлении меню.
До встречи!
(с) Скоков Сергей
Подписаться на: RSS или e-mail рассылку или добавить в ЖЖ друзья.
Недостатки DoCmd.GoToRecord и достоинства CodeContextObject
Пара камней в огород DoCmd
Как-то мне понадобилось перейти к последней записи в подчиненной форме. Перейти к последней записи можно разными способами, простейший – это вот эта команда: DoCmd.GoToRecord , , acLast. Вот с подчиненненными формами есть нюанс – нужно вызывать ее в обработчике события или методе подчиненной формы. В моем случае события не подходили, метод было реализовывать влом и очень хотелось реализовать это на главной форме.
Поэтому пришлось написать свою функцию. Благодаря тому, что функция принимает ссылку на форму, а не имя, то можно ее использовать для любой формы, подчиненной, созданной при помощи DoCmd.OpenForm или оператора New.
Public Sub CM_FormGoToLastRecord(Optional ByRef frm As Form = Nothing)
' перейти на последнюю запись
' frm можно не передавать, в этом случае она будет получена при помощи CodeContextObject
On Error GoTo Err_
If frm Is Nothing Then
Set frm = CodeContextObject
End If
If frm Is Nothing Then Exit Sub
Dim rst As DAO.Recordset
Set rst = frm.RecordsetClone
If Not rst.EOF Then rst.MoveLast
frm.Bookmark = rst.Bookmark
Exit_:
Exit Sub
Err_:
mc_Log.MC_LogErr ("CM_FormGoToLastRecord()")
Resume Exit_:
End Sub
mc_Log.MC_LogErr ("FormGoToLastRecord()") - фукнция, которая логирует ошибку в текстовом файле. О ведении лога я как-нибудь расскажу попозже.
CodeContextObject
В процедуре CM_FormGoToLastRecord() используется такая штука, как CodeContextObject, которое в справке называют свойством. Это свойство позволяет получить ссылку на объект, в рамках которого выполняется данный код. Если вызвать процедуру CM_FormGoToLastRecord() в событии подчиненной формы, то CodeContextObject выдаст ссылку на подчиненную форму. Этот же способ использует DoCmd.GoToRecord, когда не указывается имя объекта.
До встречи!
(с) Скоков Сергей
Подписаться на: RSS или e-mail рассылку или добавить в ЖЖ друзья.
Как получить доступ к свойствам диаграммы и других ActiveX объектов
MS Access поддерживает технологию ActiveX. Но те возможности, которые предоставляет стандартный элемент управления OLE объектами весьма скудны. А иногда бывает необходимо управлять скрытыми свойствами ActiveX объекта. Как же добраться до свойств объектов ActiveX?
Рассмотрим эту задачку на примере диаграмм.
На форму (или отчет) вставим диаграмму с именем “OLE_PRODAZHA_CHART” и изменим название диаграммы программно.
Далее необходимо подключить библиотеку “Microsoft Graph X.0 Object Library”, чтобы тип “Chart” (диаграмма) стал доступен (ниже узнаете зачем он нужен). Увы для диаграмм Access почему-то не добавляет ссылку на библиотеку.
Также добавим на форму кнопку с названием “Изменить название диаграммы”. В обработчике событий разместим следующий код:
Dim obj As Graph.Chart Set obj = Me.OLE_PRODAZHA_CHART.Object obj.ChartTitle.Text = "Мое название"
Весь фокус заключается в типе “Graph.Chart” и свойстве “Object” элемента управления. Свойство “Object” элемента управления возвращает ссылку на созданный объект. Библиотека “Microsoft Graph X.0 Object Library” в коде называется Graph и предоставляет класс типа Chart. Теперь можно пользоваться справкой и просмотреть все свойства и методы класса Graph.Chart.
Как быть с другим ActiveX объектами?
После вставки ActiveX элемента на форму, Access сам добавить Reference на библиотеку типов. Найти библиотеку и тип ActiveX элемента можно найти в Object Browser (в редакторе кода можно нажать кнопку F2).
Чтобы точно определить имя нужной библиотеки и типа ActiveX элемента, давайте посмотрим на свойства уже ранее созданной диаграммы. А именно “Класс” и “Класс OLE”.
Для диаграммы свойства имеют значения:
- Класс = MSGraph.Chart.8
- Класс OLE = Microsoft Graph Chart
“Класс OLE” содержит описание для пользователя. По этому имени можно найти библиотеку типов списке ссылок (Tools->References). “Класс” содежит имя класса, при помощи которого можно создать этот объект.
Возвращаясь к злосчастной диаграмме, в Object Browser имя библиотеки будет Graph, а имя класса Chart.
В примере вы также найдете ActiveX элемент TreeView, посмотрите код в модуле формы. Там добавлена обработка события, которого нет в списке событий в свойствах элемента управления.
До встречи!
(с) Скоков Сергей
Подписаться на: RSS или e-mail рассылку или добавить в ЖЖ друзья.
Как получить значение ключевого поля для добавленной записи
Всем привет!
Как оказалось вопросы по этой теме все еще возникают. Рассказываю
.
Значение ключевого поля новой записи при помощи библиотеки DAO можно получить следующим образом (K_KLIENT – ключевое поле):
Dim rst as DAO.Recordset
Dim lPk as Long
' ....
rst.AddNew
rst("T_KLIENT")="ОАО Рога и копыта"
' ...
А дальше есть несколько вариантов:
- 1-й вариант:
lPk = rst("K_KLIENT")
rst.Update
- 2-й вариант:
rst.Update
rst.Bookmark = rst.LastModified
lPk = rst("K_KLIENT")
1-й вариант работает только с таблицами MS Access, т.к. значение счетчика вычилсяется сразу же после AddNew. На всех остальных нужно проверять. Например, с ODBC таблицами 1-й вариант точно не прокатит, т.к. значение счетчика вычисляет сервер.
C библиотекой ADO получится только 1-й вариант.
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.Open "tbl1", CurrentProject.Connection, adOpenKeyset, adLockOptimistic
rst.AddNew
MsgBox rst("key")
rst.Update
А с серверами БД придется что-то придумывать, например, использовать TimeStamp, чтобы найти только что добавленную запись.
До встречи!
(с) Скоков Сергей
Как показать первое значение в поле со списком
Здравствуйте, уважаемые читатели.
Поделюсь с вами еще одной удобной функцией. У меня часто возникает ситуация, когда при открытии формы в поле со списком необходимо показать первое значение.
Например, на форме списка пользотваль хочет видеть данные за текущий год. Для этого я добавил на форму поле со списком “Год” (Имя элемента управления P_GOD). В нем выводятся года, за которые есть данные в обратном порядке. А при открытии формы вызвал специальную фукнцию:
Call CM_ListSelectFirst( Me.P_GOD_FLT ) '-- мега функция '-- увы при программном изменении значения поля события не происходят, '-- то придется еще вызвать фукнцию соотвествующую фукнцию Call SetFilter()
А вот код той самой функции CM_ListSelectFirst():
Public Sub CM_ListSelectFirst(ByRef ctl As Control)
' Скоков С.А. 2009-02-25
' Выбрать первое значение в поле со списком или списке
With ctl
If Not (.ControlType = acListBox Or .ControlType = acComboBox) Then
Exit Sub
End If
If .ListCount > 0 Then
.Value = Nz(.ItemData(0))
End If
End With
End Sub
P.S. Эта же функция будет работать для списков
.
До встречи!
(с) Скоков Сергей
Хитрость печати отчетов
Здравствуйте, уважаемые читатели.

В одной из программ реализована функциональность печати адресов клиентов на конверты, в результате пользователь получает готовенький документ MS Word. Клиент попросил добавить свой логотип на каждый конверт. Существующая реализация формирования документа в Word не позволяет дублировать картинку для каждой страницы. Переделывать полностью не хотелось. Поэтому я искал как обойтись меньшей кровью.
Идея пришла из ниоткуда. Я мониторил меню Word 2007 в поисках пункта записи макросов (может они и могли мне помочь, но увы
) и наткнулся на создание подложки – “Разметка страницы – Подложка – Настраиваемая подложка” (”Формат – Фон – Подложка” для Word 2003).
Как оказалось это отличная идея. Рисунок располагается на странице за текстом, размер и положение можно изменить в режиме изменения колонтитулов.
Супер. Просто и со вкусом. Пример можно посмотреть тут.
До встречи!
(с) Скоков Сергей
Округления
Здравствуйте, уважаемые читатели.

До Access 2002 (или 2000) встроенной функции округления не было. Поэтому все пользовались самописными. Потом появилась функция Round(). Тут можно было вдохнуть с облегчением и избавится от собственной.
Как-то заказчик прислал мне скриншот с неправильными расчетами. Анализ кода показал, что функция Round() дала сбой и округляла следующим образом (проверял в окне отладки):
9.5 =10
8.5 = 8
7.5 = 8
6.5 = 6
5.5 = 6
4.5 = 4
3.5 = 4
2.5 = 2
1.5 = 2
0.5 = 0
Разбираться было лень. В результате заменил на собственное творение, т.к. это деньги:
Public Function CM_Okrugl(ByVal dbl As Double) As Long
' округляет число dbl до целого
Dim lng As Long
lng = Fix(dbl)
If (dbl - lng) < 0.5 Then
CM_Okrugl = lng
Else
CM_Okrugl = lng + 1
End If
End Function
До встречи!
(с) Скоков Сергей
События
Здравствуйте, уважаемые читатели.
Поговорим в этом выпуске об очень интересной штуке – события. Я очень мало где видел их использование в MS Access. Но они очень сильно облегчают жизнь при работе, особенно с формами. У событий есть маленькое ограничение. Их могут использовать только объекты. Это означает, что их можно объявлять и получать только в модулях пользовательских классов, формах и отчетах.
Чтобы объявить событие необходимо в начале модуля класса (формы, отчета или пользовательского) написать:
Event ИмяСобытия( СписокАргументов )
Для использовании события необходимо объявить в начале модуля ссылку на объект и в списке (левый список, который расположен в редакторе кода) выбрать обявленный атрибут, в правом списке можно выбрать событие, если их несколько. В результате получим следующее:
Dim WithEvents Имя As Тип
Вызвать событие можно так:
RaiseEvent ИмяСобытия( Параметры )
Где это можно применить? Рассмотрим пример из жизни. На форме заказа есть поле клиента. В этом поле отображается, допустим, УНН и название клиента. Рядом с полем кнопка. По нажатию на кнопке отображается еще одна форма – список клиентов. Задача – выбрать клиента.
Одним из решений будет открыть модальное окно и тут возникает куча разных вариантов: записать напрямую с формы списка клиентов в поле формы заказов (очень плохая идея!!!), скрыть форму при нажатии пользователем кнопки “Ок” (Выбрать) и т.д.
При помощи событий получается простое и элегантное решение. Всего-то объявить на форме списка клиентов событие:
Event OnClientSelect(ByVal lId As Long)
На форме заказа это событие обработать:
Dim WithEvents m_frmKlientSepis As Form_frmKlientSpis
'--
Private Sub Kn_KlientSelect_Click()
'-- выбор клиента
'-- можно и так
'-- DoCmd.OpenForm "frmKlientSpis"
'-- Set m_frmKlientSepis = Forms("frmKlientSpis")
'-- но мне нравится этот вариант
Set m_frmKlientSepis = New Form_frmKlientSpis
m_frmKlientSepis.Visible = True
End Sub
Private Sub m_frmKlientSepis_OnClientSelect(ByVal lK_KLIENT As Long)
'-- клиент выбран пользователем
Me.K_KLIENT = lK_KLIENT
Set m_frmKlientSepis = Nothing '-- уничтожаем форму
End Sub
Подробности можете увидеть в примере. Чуть позже я расмотрю еще один пример – связные списки.
До скорых встреч!
(с) Скоков Сергей