Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Как все таки сабклассить Access.Form? / 8 сообщений из 8, страница 1 из 1
20.12.2004, 16:07:54
    #32835279
MKV
MKV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
0) Мотивация

Захотелось мне сделать много форм, которые во многом между собою похожи. Ну к примеру, хочу чтобы во всех формах при даблклике на текстбоксе вылезал MsgBox "DblClick". Неужели мне нужно повсюду вставлять похожий код, различающийся в основном именами?! Нет, наверняка MS Access лучше :)
Наследованием VBA не богат, ну ладно, пытаемся обойтись подручными средствами - ведь есть события, и это дает надежду. Если это прочтет Иван FXS он поймет меня :), я думаю что и многие другие люди использующие Access испытывали подобные чувства. Так в чем же тут истина? Может быть пытаться осуществлять сабклассинг, и превращать Access.Form в нечто типа VB.Form - это дохлый номер, и что-то против ветра? Но зачем же, зачем же, зачем же тогда MS события сделал у аксес-форм (да и у аксес-контролов зачем), если слушать эти события имеет смысл лишь тем же самым формам? Вобщем решил я попробовать на досуге. Результат пока такой - сабклассить себе дороже, тут вам не С++ и даже не VB, а это Access.Form - великий и не мой...

И все же я решил посоветоваться с более опытными в аксесе товарищами - так что вот мои рассуждения, по шагам. Если же вам все мои шаги не очень интересны, то гляньте пункт 6 - там основной вопрос который меня гложит. Ну или пункт 7 где я грязно ругаюсь. Заранее прошу простить за длинный топик. И за очепятки/ошибки в исходниках тоже конечно простите.

1) Постановка задачи - "как мы давно мечтали но так и не смогли" :)

Я хочу написать 1 класс, и чтобы он настраивал много форм в рантайме. А еще я не хочу использовать OpenArgs т.к. это очень неудобно - паковать разные параметры в строку, распаковывать и вообще ужасно извращаться. А как было бы хорошо написать что-то типа

Код: plaintext
1.
2.
3.
4.
5.
6.
Dim fc As MyFormController
Set fc = New MyFormController
fc.Init MyData1, MyData2, MyData3
If fc.DoModal = True Then
    Dim ro As MyResultObject
    Set ro = fc.ResultObject
End If

Итак я хочу сделать класс-менеджер формы к которому применим указанный код.

2) Нулевой шаг - разные глупости

Создаю форму MyDialog. Совсем пустую. То есть почти совсемю
Потому что я форум то немного почитал, да и MSDN, и не то чтоб уж совсем-то по-чайниковски :). Я знаю, что на самом деле формы акцесса склонны мухлевать а не честно работать. Не зря у них так много строковых свойств типа OnLoad - если в них не напишешь "[Event Procedure]" то никому событий не пошлют. Также обански себя ведут и аксесовские контролы (кстати а что им жалко чтоли всегда ивент тригерить, а, это что сколько нибудь затратно?) И еще если не сделать модуль формы то тоже ничего не получится. Дурка
конечно, но ладно, это еще терпимо. Делаю пустой модуль формы и в окне свойств везде где надо ставлю "[Event Procedure]". В крайнем случае, если все получится, то "[Event Procedure]" можно задать и в рантайме, так что потом это не будет напрягать. (кстати - вопрос: это что подстава такая что текст "[Event Procedure]" не заложен ни в какую константу или функцию Access или есть такая константа?)

3) Первый шаг - на грабли

Создаю модуль класса и
В простоте душевной пишу

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
...
Private WithEvents m_Form As Form 'через этот базовый класс я буду получать события
Private m_Dialog As Form_MyDialog 'а это для работы с финальным классом (формой MyDialog)
...
Public Sub CreateForm
      Set m_Form = New Form_MyDialog 'вот тут все и происходит
      Set m_Dialog = m_Form
End Sub
...

Private Sub m_Form_Open(Cancel As Integer)
    Debug.Print "Open"
    DoCmd.Maximize
    m_Form.Visible = True
End Sub

Но это все не работает. То есть не все, но почти все, т.к. в итоге в m_Form_Open мы не попаадем. А все потому, что прямо по ходу выполнения конструктора (New Form_MyDialog) происходит куча событий!!! Проходят Open, Load, Resize и Current, причем Open и Load так больше и не произойдут ведь. А до окончания конструктора присвоение (Set m_Form =) не происходит, так что событий этих я не слушаю. Я могу отлично подключиться к Close или DblClick - но не к Open и Load! Во как...

4) Второй шаг - первые извраты

Ах вы так?! А мы тогда вот что. Мы поступимся немного принципами и все-таки какой-никакой код в форму добавим. А именно добавим код в обработку Open. И сделаем так, чтобы форма в этом методе делала нечто, в результате чего все слушатели к ней подключаться еще до окончания конструктора.
Опуская кое-какие подробности, приведу код из формы

Код: plaintext
1.
2.
Private Sub Form_Open(Cancel As Integer)
    m_MyApplication.SubclassForm Me, Cancel
End Sub

и код из моего модуля класса

Код: plaintext
1.
2.
3.
4.
Private WithEvents m_Application As MyApplicatoin
Private Sub m_Application_OnFormOpen(frm As Form, Cancel As Integer)
    Set m_Form = frm
    m_Form_Open Cancel
End Sub

Здесь TheApplication - это глобальное свойство, возвращающее некий мой глобальный объект, к которому также подключен как слушатель мой классик. Конечно я мухлюю немного, вызываю сам внутри класса m_Form_Open Cancel, но ничего. Теперь я получаю все-все события формы, ура, ура! но...

5) Рано радоваться

А если я создам текстбокс, на который первым попадет фокус, то его события (Enter) понесуться раньше конца конструктора. Ну ладно, если я хочу к этому эдиту тоже подключиться, я могу впихнуть это в мой чудо-метод m_Application_OnFormOpen. Но вот если я создам субформу, все ее события произойдут раньше событий формы, и раньше чем мой классик их поймает. Выходит с субформой надо отдельно мучиться чтобы ее на прослушку поставить. Можно конечно Open и Load не слушать вовсе, но так нарушается стройность концепции :)
(Если же стройностью пренебречь, то тогда можно принять что мы всегда пропускаем у субформы события Open и Load, а зато делаем ей какой-нибудь метод открытый типа LoadRealy, который сами же и вызываем, и для которого что-нибудь реализуем в субформе)

6) А в чем проблема то?

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

7) Если бы я был начальником

То тогда бы я сделал Access.Form гораздо более похожей на VB.Form. Чтобы форма не в конструкторе становилась окном, и начинала кидаться сообщениями, хотя ее еще в принципе почти никто услышать и не может, а только когда у нее вызовут метод Show. Ну как же мне поверить что формы аля Access.Form сделаны такими шустрыми для моего же дескать блага, чтоб мне было легче программировать, если я везде как бобик должен писать "[Event Procedure]" и потом еще смириться с тем что все равно я не все получу что они кидают? (как с субформой) Конечно мне было бы в 100 000 раз проще один лишний раз написать frm.Show чем совершать все эти прыжки и гримасы, не говоря уже о тошнотворном синтаксисе DoCmd.OpenForm со строковым параметром OpenArgs.
(прим. Все это сильно напомнило мне Clipper если кто помнит такое чудо. там тоже все время хотели как лучше, а вышло как всегда. Потому что считали что лучше - это когда проще делать простое, хотя ежу понятно - лучше это когда проще делать сложное)

8) И какой из всего этого следует вывод?

Да вот хотел тут небольшую базенку сварганить для себя же самого, ну и думал на аксесс заложиться. Рассчитывал что так будет сподручнее и проще всего. Но теперь 100 раз подумаю - может все таки не париться и сделать клиента на VB6? Или наступлю себе на горло и буду изо всех сил нажимать копи-пейст, размазывая код по модулям форм. Или - о чудо! - придет человек опытный и расскажет мне, что есть возможность легко ( "[Event Procedure]" не в счет) ловить все события всех форм...
...
Рейтинг: 0 / 0
20.12.2004, 16:46:34
    #32835415
Программист-Любитель
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
Не претендуя на глобальное решение проблемы, для которой Аксесс плохо предназначен, я в похожих ситуациях поступаю таким образом.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
Делаю свой FormManager. 
В нем WithEvent frm as Form

В нем метод:
Sub BindToForm(frm as Form)
    frm.OnCurrent="[Event Procedure]"
    frm.OnBeforeUpdate="[Event Procedure]"
    ...
End Sub

Далее код для универсальных Current, BeforeUpdate, ... класса FormManager.

В форме:
Dim fm as FormManager

В событии Form_Load:
    Set fm = new FormManager
    fm.BindToForm Me

Не очень глубоко научно но многие практические вещи решает.
...
Рейтинг: 0 / 0
20.12.2004, 18:13:29
    #32835669
MKV
MKV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
Спасибо. В принципе решение тоже что у меня - глобальный объект, к которому лезет наша форма. Я бы только вместо Load делал это в Open, т.к. Open приходит первым, но в принципе не очень важно. А как обойти проблему с субформой? Например хотелось бы, чтобы от субформы события тоже до форм-менеджера доходили. А к моменту когда происходит первый Current субформы, мы при таком подходе не будем "готовы" (у главной формы еще никаких событий не прошло). Мне самому приходит только 1 способ - в момент биндинга надо сделать все то же, что при Current в субформе, т.к. этот current точно уже был, но это ж натяжки какие то сплошные... я бы назвал это (если без матерщины) "вынужденно кривым кодом", а что поделаешь, уж тут не до научности... И что ничего иного сделать нельзя? Все таки до начала прохождения событий в экземпляре формы никак нельзя получить ссылку на этот экземпляр? Неужели Вас это не травмирует интеллектуально?
...
Рейтинг: 0 / 0
20.12.2004, 19:42:47
    #32835833
Программист-Любитель
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
А у меня в Load'е подчиненной формы тоже свой экземпляр FormManager'а стоит...
...
Рейтинг: 0 / 0
20.12.2004, 21:54:18
    #32835915
Latuk
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
Мастера Access могут делать формы
причем могут делать их по шаблону
причем форму можно открыть в режиме конструктора из кода
и манипулировать содержимым програмно

мне кажется для организации псевдо наследования
надо идти путем самастийного перекалбашивания метаданных

1)посмотреть как работают мастера (где то мелькало на форуме как форму мастера посмотреть)
2)сделать класс который програмно сможет собрать форму по кусочкам
используя в качестве шаблона другую форму
3)продвинуть методы этого класса чтобы он мог добавлять к результату
дополнительные прибабахи

На входе форма шаблон + доп свойства
на выходе новая форма инкапсулирующая доп свойство

Работать правда такая штука в MDE и ADE не будет
но генератор форм может получится

Но на практике (Hammer рассказывал) гораздо проще использовать
для этого VS внедряя его формы в аксесовский проект.
...
Рейтинг: 0 / 0
21.12.2004, 01:11:09
    #32836016
MKV
MKV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
Программист-Любитель:
Извините, я не вчитался достаточно внимательно в Ваше первое сообщение. Вы размещаете менеджер формы внутри формы, а не идете к глобальному объекту как я предлагал. Ваш подход мне больше нравится. Я-то преследовал
цель передать реальное управление в ту точку программы, откуда форму открывают, чтоб сконфигурировать ее там и вообще в целом начать ей управлять. Но пусть лучше вся эта логика будет сокрыта во внутреннем форм
менеджере, так грамотнее как Вы делаете. Это получается самое
реальное сабклассирование - замена наследования на агрегирование,
классика жанра. Так что пойду по Вашим стопам, (если все же не решусь
вообще делать на VB) большое спасибо.


А насчет подчиненных форм я тоже был не прав. Я то хотел получить форму в таком состоянии, когда она, и все дерево ее подформ, уже созданы как объекты, но еще не получили ни одного события. Но задача то эта невыполнима, как же я сразу не понял! Дело то все в том что,
такого состояния просто не бывает в общем случае. И как раз потому, что часть событий (Open, Load и др) тригерится из конструктора. Действительно, если алгоритм конструирования выглядит так
конструирование(форма) = создание_объекта(форма);конструирование(подчиненные_формы);события(форма)
то очевидно что в общем случае состояния, когда все созданы, а событий еще не было, может вообще не наступать (а будет оно наступать только если везде не более 1 подчиненной).


Так что нечего морочиться, халявы нету, все субформы надо сабклассить своим объектом, да и красивее так код получается.
Так что спасибо большое, Ваш подход похоже наиболее симпатичный.

Latuk:

Может я не уловил, но по-моему в результате у нас получится много форм,
код которых написан по одному образцу. Если бы я хотел такого, то я бы конечно не стал связываться ни с каким визардом а сделал бы следующее. Создал бы форму "Мой идеал" (или набор "идеал_1", "идеал_2") и потом бы делал save as и вносил небольшие коррективы. Если коррективы пришлось делать большие - сохранил бы под именем "идеал_3" на будущее. Мог бы пойти чуть дальше, и разместить это все в отдельном mdb, назвать его "мои шаблоны форм" и импортить оттуда по необходимости. Если бы понравился такой подход глядишь бы со временем сделал свой просиотровщик этих заготовок, с возможностью даже что-то типа параметров задать - и вот бы был уже почти визард, но только эта вся развлекушка вряд ли бы понравилась мне. Ведь какое же это наследование? Тут нет повторного использования одного и того же кода, а есть только копирование текста, что совсем даже не есть хорошо. Или Вы другое имели в виду?
А в плане привлечения VS - речь ведь идет не об отдельных фичах, а об основном составе GUI. И с учетом этого, если говорить о VS, то уж проще совсем на VS перейти, и сделать там все GUI, зачем мне тогда аксессовские штучки?
Не, вот подход с размещением класса внутри, который заменяет предка, (то что выше представил Программист-Любитель) это по сути полноценное наследование, от настоящего отличается только меньшей изящностью кода, но таков уж бейсик.
...
Рейтинг: 0 / 0
21.12.2004, 08:08:34
    #32836102
Latuk
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
Форма шаблон+Класс инкапсулирующий методы изменения форм в конструкторе+описание изменений(метаданные) => новая форма
разве это не наследование?
правда реализованное не средствами языка
а на уровне манипулирования метаданными.
и никто не заставляет хранить промежуточные варианты в виде копий готовых форм
их можно и удалять после использования.
...
Рейтинг: 0 / 0
21.12.2004, 09:05:46
    #32836134
Программист-Любитель
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как все таки сабклассить Access.Form?
2 MKV:

Все таки аксесс достаточно специфический инструмент программирования. Одну "конкретную" форму сделать очень просто. Большой набор согласованных друг с другом форм и с интерфейсом пользователя как хочется вам, а не предусмотрено в нем самом очень трудно. Судя по вашим запросам вам прямая дорога в VS, Delphi и прочая.
...
Рейтинг: 0 / 0
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Как все таки сабклассить Access.Form? / 8 сообщений из 8, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]