5 строк кода

Как писать комерческие приложения на MS Access

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 рассылку или добавить в ЖЖ друзья.

Written by Сергей Скоков

Октябрь 12th, 2009 at 4:23 пп

Posted in решения

Как создать меню в MS Access

Комментариев нет

Всем привет!

Как оказалось очень полезно смотреть ключевые слова, по которым пользователи переходят на мой сайт. В них можно найти новые тему. Например, как эту. Оказывается, у некоторых это вызывает трудности.

Как создать меню
В прошлой статье про меню я забыл дорасказать, как же все же добавляеть новые пункты меню в строку меню. По-этом рекомендую сперва ознакомится с прошлым постом и пеерходить к чтению этого.

Как создать пункты меню
Настройка меню

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

Настройка меню

Теперь все внимание на вкладку “Команды” нового окошка.

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

Пункты меню

В категории “Новое меню” найдете выпадающее меню “Новое меню”. На самом деле это поле с выпадающим списком.

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

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

Панель еню

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

Свойства пункта меню

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

Особенности открытия форм
А теперь давайте таким же образом откроем пункт меню, созданный перетаскиванием пункта из группы “Все формы”, например.

Свойства пункта меню

В свойстве “Параметр” вы обнаружите имя формы. Так вот, если прописать это же имя в пункте меню из группы “File”, то форма не откроется. Вот такой чудесный нюанс.

В следующий раз опишу о программном создании и управлении меню.

До встречи!

(с) Скоков Сергей

Подписаться на: RSS или e-mail рассылку или добавить в ЖЖ друзья.

Written by Сергей Скоков

Июнь 2nd, 2009 at 3:07 пп

Posted in решения

Недостатки 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 рассылку или добавить в ЖЖ друзья.

Written by Сергей Скоков

Май 27th, 2009 at 3:35 пп

Как получить доступ к свойствам диаграммы и других 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 рассылку или добавить в ЖЖ друзья.

Written by Сергей Скоков

Май 6th, 2009 at 12:45 дп

Posted in решения

Как получить значение ключевого поля для добавленной записи

Комментариев нет

Всем привет!

Как оказалось вопросы по этой теме все еще возникают. Рассказываю :-) .

Значение ключевого поля новой записи при помощи библиотеки 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, чтобы найти только что добавленную запись.

До встречи!

(с) Скоков Сергей

Written by Сергей Скоков

Апрель 2nd, 2009 at 3:10 пп

Posted in решения

Как показать первое значение в поле со списком

Комментариев нет

Здравствуйте, уважаемые читатели.

CM_ListSelectFirst

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

Например, на форме списка пользотваль хочет видеть данные за текущий год. Для этого я добавил на форму поле со списком “Год” (Имя элемента управления 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. Эта же функция будет работать для списков :-) .

До встречи!

(с) Скоков Сергей

Written by Сергей Скоков

Март 10th, 2009 at 2:52 дп

Posted in решения

Хитрость печати отчетов

Комментариев нет

Здравствуйте, уважаемые читатели.

Логотип

В одной из программ реализована функциональность печати адресов клиентов на конверты, в результате пользователь получает готовенький документ MS Word. Клиент попросил добавить свой логотип на каждый конверт. Существующая реализация формирования документа в Word не позволяет дублировать картинку для каждой страницы. Переделывать полностью не хотелось. Поэтому я искал как обойтись меньшей кровью.

Идея пришла из ниоткуда. Я мониторил меню Word 2007 в поисках пункта записи макросов (может они и могли мне помочь, но увы :-) ) и наткнулся на создание подложки – “Разметка страницы – Подложка – Настраиваемая подложка” (”Формат – Фон – Подложка” для Word 2003).

Как оказалось это отличная идея. Рисунок располагается на странице за текстом, размер и положение можно изменить в режиме изменения колонтитулов.

Супер. Просто и со вкусом. Пример можно посмотреть тут.

До встречи!

(с) Скоков Сергей

Written by Сергей Скоков

Февраль 28th, 2009 at 1:49 пп

Posted in решения

Округления

2 комментария

Здравствуйте, уважаемые читатели.

До 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

До встречи!

(с) Скоков Сергей

Written by Сергей Скоков

Февраль 26th, 2009 at 12:41 дп

Posted in решения

События

Один комментарий

Здравствуйте, уважаемые читатели.

Поговорим в этом выпуске об очень интересной штуке – события. Я очень мало где видел их использование в 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

Подробности можете увидеть в примере. Чуть позже я расмотрю еще один пример – связные списки.

До скорых встреч!

(с) Скоков Сергей

Written by Сергей Скоков

Октябрь 5th, 2008 at 7:09 пп