Автоматическое изменение размеров форм 1.Постановка задачи Сама задача расчета размера форм не нова. Она описывается и решается, например, в [1]. Можно привести примеры сайтов (например [2], [3]), где постановка задачи и её решения другие. Однако нигде нет достаточно полной постановки задачи. Более полный вариант, с моей точки зрения, должен выглядеть так. Программист или группа программистов, разрабатывая проект на Access, использует для создания форм обязательно одинаковое разрешение экрана. Пояснять это, очевидно, не требуется. Однако, попав к конечному пользователю, проект исполняется, вообще говоря, при других разрешениях. При этом внешний вид форм может сильно измениться: они могут визуально сильно уменьшиться, вплоть до неразличимости текстов, или увеличиться, выходя за рамки окна Access. Отсюда первая задача: видимые размеры форм и их элементов должны изменяться пропорционально изменению разрешения экранов. Так как видимые размеры зависят не только от разрешения экрана, но и от DPI (мелкий, крупный и т.д. шрифт), от конкретных свойств видеоадаптера, то при решении первой задачи должно учитываться и это. Однако этого мало. При больших разрешениях экрана (типа 1600 х ….), характерных для больших мониторов, пользователи часто используют для отображения окна Access не весь экран, а только часть его. При этом они в любой момент могут изменить размер окна Access. Потому возникает вторая задача: видимые размеры форм и их элементов должны так же изменяться пропорционально изменению окна Access. Этот момент, видимо, упущен во всех постановках. Далее, пользователю может не понравиться размер или положение формы на экране, которое предусмотрено программистом. Следует дать ему возможность изменить эти характеристики. А модулю расчета размеров форм необходимо запомнить установленные характеристики формы и воспроизвести их при следующей загрузке формы, пропорционально изменив их, если загрузка произойдет при других внешних условиях (например, при другом разрешении экрана). Это третья задача, которую необходимо решить. Теперь следует уточнить, что понимается под пропорциональностью. Во всех известных мне постановках понимается следующее: если, например, разрешение экрана требует увеличения по ширине на X %, а по высоте на Y %, то это и следует сделать как с формой, так и со всеми её элементами. То есть пропорциональность здесь двойная: независимая по ширине и по высоте. Назовем это линейным режимом изменений формы. Хотя скорее его лучше назвать резиновым - за какую сторону потянем форму, то так же поползут и размеры элементов формы. Однако линейный режим очевидно противоречит интересам пользователя. Пользователь вынужден подгонять размеры формы так, чтобы размеры элементов выглядели нормально. А точнее так, как сделал их программист. Ведь он думал и выверял для каждого элемента формы соотношение ширины и высоты каждого элемента. Наиболее естественно при изменении размеров формы сохранить это соотношение, избавив пользователя от ненужной работы. Назовем изменение формы с сохранением соотношений ширин и высот элементов, заданных программистом, реально пропорциональным режимом или просто пропорциональным режимом. Такое понимание пропорциональности мне не встречалось. Реализация реально пропорционального режима изменения форм является четвертой задачей. Особое внимание следует уделить линейным формам. При увеличении формы по высоте Access сам по себе просто добавляет новые строки. Эту реакцию следует сохранить и при применении пропорционального режима. Однако увеличение по ширине должно не добавлять пустое пространство в форму, как это делает Access, а пропорционально увеличивать элементы формы. Далее следует устанавливать (при возможности) такие размеры формы, чтобы последняя видимая строка не разрезалась границей формы. Это пятая задача. Работа с формами в режиме таблицы по тем принципам, что и с формами в режиме форм, является шестой задачей. В [1] эта задача объявлена неразрешимой. Однако это не так. Далее следует обеспечить обработку всплывающих форм и произвольно вложенных субформ. Естественно, по тем же принципам. Это седьмая и восьмая задачи. Девятая задача – максимальная простота применения модуля расчета форм. Как в новых, так и в старых задачах. 2. Общее описание работы модуля ResizeForm Модуль реально разрабатывался и применялся в практических задачах начиная с 1998 г. И только в конце 2003 г. он, кажется, достиг состояния, соответствующего постановке задачи, данной в п.1. Модуль написан в Access-97, и использует только явно описанные возможности. Версия для Access-2002 получена преобразованием из версии для Access-97. Сам модуль находится в базе ResForm2002.mde. Кроме него базе имеется общий модуль, обеспечивающий функции отключения/включения модуля расчета размеров форм, очистку памяти от запомненных характеристик форм и некоторые другие функции. Решение первой задачи (установки монитора) использует те же методы, которые применяются в [1]. Для решения второй задачи (учет размеров окна Access) применен метод считывания его характеристик по таймеру, так как изменение его размеров никаких событий не порождает. Так же по таймеру обнаруживается изменение размеров и положения формы. Для хранения характеристик форм, установленных пользователем, используются Properties базы ResForm2002.mde. Это позволило обойтись без использования таблиц, а так же без записей в основную базу или в системные области Windows. Методы решения задач четыре-восемь оригинальны, и пока не описываются. Работа с формами (субформами) в виде таблиц имеет свои особенности. Дело в том, что пользователь имеет дополнительные возможности: изменить высоту строки, размер шрифта, размер столбцов, скрыть или переставить их потому как ResForm в демо не учитывает скрытия столбцов. Эти характеристики таблицы модуль запоминает и воспроизводит из при следующем вызове. То есть фактически запоминаются индивидуальные настройки таблиц для каждого компьютера, что обычно делается при помощи специальных программ. Пользователь имеет еще другие возможности: например, изменить цвет фона, шрифта и ряд других. Их тоже можно запоминать, но эта версия программы этого не делает. Следует подчеркнуть отличие файла задачи типа *.mde от *.mdb При файле *.mde изменения, внесенные пользователем, в Access в базе не запоминает. Все сохранение ведет модуль расчета размеров в своих Properties. Если пользователь сбросит память о настройках форм (об этом ниже), то все формы и таблицы вернутся к исходному состоянию, заданному программистом. При файле *.mdb для форм ситуация аналогична файлу *.mde. Но для таблиц это не так. Изменения таблиц Access сразу записывает в базу немедленно (а не при закрытии), в том числе и все изменения, сделанные модулем расчета размеров, например для учета другого разрешения экрана, по сравнению с проектным. Если пользователь работал именно при таких условиях, то сброс памяти модуля о настройках таблицы приведет к тому, что модуль воспримет настройки таблицы, пришедшие из базы как заданные программистом и реально исказит внешний вид таблицы. Отсюда рекомендация: не давать пользователю доступа к сбросу памяти. Он должен применяться только при программировании и только при проектных установках (разрешение экрана и т.д.). При расчете размеров используются все характеристики формы, установленные программистом, включая параметр AutoCenter, который игнорируется в [1]. Допускается загрузка формы в максимизированном состоянии. Основной режим (по умолчанию) расчета размеров форм – пропорциональный. Однако для возможности сравнения с другими программами реализован и линейный режим. Модуль перехватывает только одно событие формы (выгрузка) для определения момента записи характеристик формы. Дополнительные возможности. Если программист намеренно создал форму, выходящую за границы окна Access по вертикали или по горизонтали, то модуль успешно обработает и эту ситуацию. О качестве решения девятой задачи (удобство использования) можно судить на основе анализа демонстрационного примера Demo2002.mdb, и данного ниже описания программирования работы с модулем. 3. Критический обзор свойств модулей FormResize, ControlResize, SectionResize, предложенных в [1] для расчета размеров форм. Расчет размеров форм производится только в линейном режиме, что, как указано выше, весьма неудобно для пользователей – то есть четвертая задача не решена. Первая задача решена. Вторая задача (учет размеров окна Access) не решена. Третья задача(учет изменений характеристик форм, сделанных пользователем) решена не полностью – нет хранения измененных характеристик форм и учета этих характеристик при открытии форм. Само по себе хранение - чисто техническая задача. Но использование этих характеристик для расчета размера формы при открытии - самый сложный блок в ResizeForm. Пятая задача не ставилась и не решалась. Шестая задача объявлена неразрешимой (стр. 512). Седьмая и восьмая задачи решены. Девятая задача решена, за исключением работы с параметром формы AutoCenter. Работу модулей можно посмотреть на примере базы Getz2002.mdb. В работе авторов имеется, с моей точки зрения, серьезная логическая ошибка в расчете коэффициентов изменения элементов формы. Дело в том, что, получив коэффициенты в качестве результатов решения первой задачи, авторы применяют их как к форме, так и к ее элементам. Сами коэффициенты вычисляются с очень высокой точностью, что является специальной заботой авторов. Однако далее совершенно не учитывается то обстоятельство, что в форме, помимо элементов с изменяемыми размерами, есть неизменяемые и отнюдь не маленькие. По ширине это: размеры области границы, области выделения, вертикальной линейки прокрутки. По высоте: область границы, горизонтальная линейка прокрутки, панель навигации. Легко построить пример, показывающий, что отсутствие учета этих элементов приводит к существенным искажениям вида формы. Но разницу можно увидеть на примере формы PeopleList. При вызове её из базы Demo2002.mdb, которую обслуживает модуль ResizeForm, горизонтальной полосы прокрутки нет. А при вызове из Getz2002.mdb она появляется. То есть во втором случае рассчитанные размеры окна формы меньше ширины формы. Исходные формы идентичны (за исключением модуля формы). Проверить это по-другому можно, исключив из модуля формы вызов модуля расчета авторов. Без вызова полосы прокрутки нет. Задача учета размеров неизменяемых элементов оказывается весьма не простой, так как: - размер этих элементов в pic зависит от DPI - размеры не всех элементов можно прочитать с помощью API В модуле ResizeForm эта задача решена. Мелкие замечания. Для построения системы хранения текущей информации о форме авторами используется множество экземпляров модулей классов (например, для каждого элемента формы), строятся различные коллекции. Возможно это сделано в учебных целях, так как массивов вполне достаточно для организации хранения текущей информации. Но в результате программа авторов работает существенно медленнее ResizeForm, занимает больше оперативной памяти. Центрирование форм авторы выполняют только при программном назначении свойству CenterOnOpen значения True. Однако они выполняют его не так как Access. При центрировании по вертикали Access делит свободную часть окна в соотношении 1 : 2. То есть верхний отступ меньше нижнего. Так действительно центрированная форма смотрится лучше. Авторы размещают форму, деля свободную часть в соотношении 1 : 1. То есть действительно по центру. А вид хуже. При расчете групповых элементов (вкладки, переключатели) авторы используют итерационные методы, что так же не ускоряет работу. (Вполне возможно использование только прямых методов). Работа авторов принципиально не переносима в Access-97. 4. Программа Новикова [2] и продаваемая программа [3]. Программа Новикова решает только первую задачу. И то только частично. В ней имеется та же логическая ошибка, что и в [1]. В продаваемой программе полностью закрыт текст даже демонстрационного примера. Поэтому серьезно ее проанализировать невозможно. Лучше ее посмотреть. Отмечу, что в программе реализован только линейный режим, она не реагирует на изменение окна Access, и при некоторых изменениях размеров формы в демонстрационном примере дает программную ошибку. 5. Демонстрационный пример и применение ResizeForm в других задачах. Вообще говоря, разработанный модуль ResizeForm предназначен для продажи. Но конкретный модуль ResizeForm, который находится в демонстрационном примере в базе ResForm2002.mde, можно бесплатно использовать в любой задаче, написанной на А-2002, если она разрабатывалась при следующих установках: - разрешение экрана 800х600 - мелкий шрифт (DPI = 96) - на рабочем столе панель задач установлена (не скрывается), других панелей нет - окно Access максимизировано - в окне Access имеются две панели инструментов и строка состояния 5.1 Подготовка задачи к применению модуля. Подготовка сводится к замене всех шрифтов на тип TrueType. Только этот тип допускает более-менее точное масштабирование. К сожалению, по умолчанию в Access установлен шрифт MS Sans Serif, который не является типом ТТ. Его везде следует заменить на тип ТТ. Рекомендуемые шрифты: Arial, Times New Roman, Courier, Tahoma. Замену шрифтов можно выполнить программным путем. Вот текст программы замены шрифтов: Sub ChangeShrift() Dim frm As Form, ctl As Control Dim FormName As String, n As Long On Error Resume Next 'Перебираем все формы For n = 0 To CurrentDb.Containers("Forms").Documents.Count - 1 FormName = CurrentDb.Containers("Forms").Documents(n).Name SysCmd acSysCmdSetStatus, FormName 'Открываем форму в режиме конструктора DoCmd.OpenForm FormName, acDesign, , , , acHidden Set frm = Forms(FormName) 'Перебор всех управляющих элементов формы For Each ctl In frm.Controls If ctl.FontName = "Старый шрифт" Then ctl.FontName = "Новый шрифт" Next 'следующий элемент 'Закрываем и записываем форму DoCmd.Close acForm, FormName, acSaveYes Next 'следующая форма SysCmd acSysCmdClearStatus MsgBox "Обработано форм: " & n, vbInformation End Sub | Рекомендация 1. Поля надписей следует делать с запасом. Дело не только в том, что шрифты могут иметь только целочисленные размеры. При изменении размера шрифта конкретного текста соотношение длина строки/высота строки меняется в зависимости и от конкретного шрифта, и от содержания строки, если шрифт не равноширинный. Запас размером примерно 25% от длины текста надписи гарантирует правильное ее отображение (без обрубания). Рекомендация 2. При разработке задачи используйте наименьшее возможное разрешение экрана. Дело в том, что при работе задачи на мониторе с большим разрешением, чем было использовано при разработке, формы выглядят достаточно хорошо. А при работе на мониторе с меньшим разрешением внешний вид форм ухудшается. И чем больше разница, тем сильнее. 5.2 Программирование Поместите базу ResForm2002.mde (имя базы можно изменить) в тот же каталог, в котором находится ваш проект. Установите ссылку из вашего проекта на базу ResForm2002.mde. Теперь модуль ResizeForm доступен для ваших программ. Хранение в одном каталоге сохранит работоспособность вашего проекта при перемещениях. Подчеркну, что каждому экземпляру вашего проекта должен соответствовать только одна база ResForm2002.mde. Далее следует обеспечить для каждой формы расчет ее размеров при загрузке и пересчет размеров при изменении пользователем характеристик формы. При исполнении второй части используется таймер. Все программирование следует делать только для основной формы. Для вложенных форм этого не требуется. 5.2.1 Расчет размеров формы при загрузке В общую часть описания модуля формы внесите строку: Dim ResForm As ResizeForm | В этой переменной будет храниться ссылка на конкретный экземпляр модуля класса ResizeForm, обслуживающий именно эту форму. При закрытии формы Access автоматически удалит связанный с ней модуль. В обработку события формы «открытие» или «загрузка» (безразлично) внесите две строки: Set ResForm = New ResizeForm ResForm.Form = Me | Первая строка создает экземпляр модуля, связанный с формой. Вторая строка выполняет расчет размеров формы при загрузке. 5.2.2 Пересчет размеров формы по таймеру. Выполнение пересчета вызывается одной строкой в программе обработки события "таймер": ResForm.SetFormSizeTimer Интервал таймера рекомендуется устанавливать равным 500 (половина секунды.). В демонстрационном примере каждая форма оснащена своим таймером. Это сделано для удобства демонстрации: формы можно вызывать независимо друг от друга. В практической задаче гораздо лучше применять один таймер, связанный с постоянно загруженной формой (обычно загружаемой первой и невидимой). Для реализации такого подхода следует переменную ResForm в общем описании модулей форм объявить как Public. Тогда программа обработки события «таймер» первой формы будет выглядеть так: Private Sub Form_Timer() For n = Forms.Count-1 To 1 Step -1 Forms(n).ResForm.SetFormSizeTimer Next n End Sub | Вызов SetFormSizeTimer пересчитывает размер как видимой формы, так и невидимой. Для минимизации обращений к расчету форм можно использовать значение, возвращаемое функцией SetFormSizeTimer. Оно равно False, если форма не изменилась. Предшествующие формы как будто можно не рассчитывать. Но здесь требуется осторожность – пользователь может изменить характеристики не последней загруженной формы, а любой доступной. Я обычно запускаю пересчет только видимых форм. Если они не изменились, то точно не нужно пересчитывать невидимые. Но все это не так существенно, так как определение неизменности форм выполняется весьма быстро. Если какую-то форму вы решили не рассчитывать (в ней нет переменной ResForm), то проще всего вставить в программу таймера строку: On Error Resume Next. На этом программирование заканчивается. 5.3 Свойства и методы модуля ResizeForm Свойство | Тип | Описание | Form | Form | При присвоении свойству значения проводится анализ структуры формы, создаются дополнительные экземпляры ResizeForm для вложенных форм (в общем случае все экземпляры образуют многоуровневое дерево), фиксируется текущая информация о форме, производится расчет размеров формы при открытии | IsMaximized | Boolean | Только для чтения. True – форма максимизирована | IsMinimized | Boolean | Только для чтения. True – форма минимизирована | IsNormal | Boolean | Только для чтения. True – форма в нормальном состоянии (не максимизирована и не минимизирована) | Linear | Boolean | По умолчанию – False. Если присвоить значение True, то включится режим линейного расчета. Присвоение можно выполнить в любой момент. Возможно обратное присвоение значения False (пропорциональный режим). Переход на другой режим будет выполнен при следующем вызове расчета размеров формы (при открытии или по таймеру) | SetFormSizeTimer | Boolean | Вызов пересчета размеров формы по таймеру. Если возвращаемое значение равно False – реального пересчета не было, то есть пользователь ни окно Access, ни форму не менял | Version | String | Версия программы | Inner… | | Все свойства и методы, название которых начинается с Inner, являются внутренними для модуля ResizeForm. Так как модуль написан на Access-97, то скрыть их невозможно. Обращаться к ним не следует | 5.5 Общие функции общего модуля ResizeFormMain Все перечисленные ниже функции используются только при корректировке программ, так как в это время модуль расчета форм работать не должен. Форму, открытую в конструкторе, модуль никогда не изменяет. При программировании следует обнулить интервал таймера. Работа таймерной программы мешает вводу текстов на VBA. Функция | Тип | Описание | GetResizeFormTurn | Boolean | True – расчет размеров форм включен, | ResizeFormClearMemory | | Сбрасывает память о текущих характеристиках форм. Характеристики записываются при выгрузке формы, если модуль расчета включен. Характеристики хранятся в Properties базы ResForm2002.mde. | ResizeFormTurnOff | | Выключает расчет размеров форм. | ResizeFormTurnOn | | Включает расчет размеров форм. | Inner... | | Все функции и подпрограммы, название которых начинается с Inner, являются служебными. Вызывать их не следует. | Загрузка демонстрационных примеров. http://hiprog.com/index.php?option=com_content&task=view&id=715&Itemid=35 Список ссылок. - Пол Литвин, Кен Гетц, Майк Гунделой, Access 2002, Издательский дом «Питер», Том 1, Глава 7, «Автоматическое изменение размеров форм». База Ch07.mdb из CD, прилагаемого к книге.
- Программа Новикова. http://hiprog.com/index.php?option=com_content&task=blogcategory&id=93&Itemid=133
- Продаваемая программа. http://www.peterssoftware.com/ss.htm
Просмотров: 32256
Ваш коментарий будет первым | | |