Создание списка с переменной шириной столбцов. |
Автор Андрей Кравченко | |||||||||||||
27.05.2002 г. | |||||||||||||
Андрей Кравченко
Access является очень удачным инструментом, но как любое средство разработки не лишен ряда недостатков. Главный из них - скудость набора компонентов. Несмотря на то, что в основном они удовлетворяют интерфейсные потребности приложений СУБД, но время на месте не стоит, пользователь избалован богатством лакокрасочных покрытий в интерфейсах новых программ и систем. Даже апологеты серых форм в Microsoft сдались и выпустили "Luna" (это в Windows XP интерфейс так называется...). А вот в Access уже в очередной XP (или 2002) версии никакого интерфейсного прогресса не наблюдается. И выглядит такое Access-приложение посреди крикливого интерфейса Luna, как наша серая советская действительность, или как большая рваная дыра (даю возможность выбрать сравнение по вкусу). В общем, если Microsoft не идет к программеру, программер ... да не идет он к Microsoft, чего туда ходить, чего он там не видел... В магазин он идет, Кока-колу покупать. Потом садится, дудлит воду и думает, как жить дальше. О том, что убожество компонентов Access в скором времени станет мешать дышать, я предвидел, поэтому прорабатывал различные варианты. Один из них - переход на чистый, классический Visual Basic, при всех преимуществах имеет большой недостаток - порядочный размер готовой программы, которую в Большую сеть засунуть еще кое-как можно, а вот простым пользователям с трещащими как сорока каналами выкачать это добро сложновато. Они ведь своими кровными за закачку расплачиваются, да и нервная система у русского человека изрядно проржавела. Отпадает пока этот вариант. Но привлекателен он все же одной вещью - использованием компонентов фирмы Apex, называются они Apex True DBList (спискок и выпадающий список) и Apex True DBGrid (таблица или grid в английском просторечье). Компоненты просто роскошные, и красить их можно и по строкам и каждую ячейку в отдельности, все о чем только можно мечтать там есть, будьте спокойны. Забрать их можно отсюда - http://www.componentone.com/, я сам несколько дней потратил, пока нашел. Но вот беда с Access корректно не работают (Access просто рушится через какое-то время), несмотря на все заявления Microsoft о полной поддержке ActiveX в Access. Да и сами компоненты весят 4-5 МБ, их надо загружать, а еще возможные проблемы с регистрацией компонентов на машинах пользователей. Если бы не эти проблемы, купил бы я эти компоненты, несмотря на достаточно кусючую цену. Но что поделать, отложим до лучших времен. Другие компоненты имеют достаточно ограниченный набор возможностей, да и надежность их оставляет желать лучшего. Не могу я доверить свое приложение этим компонентам, пользователи ведь в меня кидать камни начнут, и все мои жалкие тыкания пальцем на настоящего виновника проблемы утонут в гуле возмущения. Спасение утопающих - дело рук самих утопающих. Начинаем спасаться. Произведем инвентаризацию имеющегося арсенала. 1. Мы умеем отслеживать положение указателя мыши во время перемещения по объекту формы. Объекты могут быть разными. Это может быть голая поверхность самой формы. Может быть поле, надпись, кнопка, и т.д. 2. Мы знаем такое свойство списка как ColumnWidths. Задается с помощью строки, которая содержит ширины столбцов, разделенные точкой с запятой в единицах твип. Присваивая новые значения этому свойству списка можно изменять ширину столбцов. 3. Еще у нас есть такой интересный объект - Screen. Интересен он тем, что позволяет менять изображение курсора мыши. Одно из изображений - изменение размера по горизонтали. А вот это для нас настоящая удача. Начнем с простого. Имеем список на основе стандартного запроса, использующего связку нескольких таблиц. Вот он, наш запрос. А вот и наш список. Идея заключается в следующем. Когда мы проводим курсором мыши в области заголовков столбцов, курсор будет изменять свой вид на "изменение размера по горизонтали" в тех местах, где проходят границы столбцов списка. Если в это время мы нажимаем левую кнопку мыши, то граница будет двигаться за курсором, влево или вправо, в итоге мы увидим стандартное изменение ширины столбцов. Так же, как, например, в Проводнике Windows. На первом этапе попробуем менять курсор мыши на границе столбцов. Главная проблема на этом этапе в том, что ширина столбцов списка задается с помощью свойства ColumnWidths в виде строки, где значения разделены точкой с запятой, причем последнее значение точкой с запятой не отделяется. Например, если у списка свойство ColumnWidths возвращает значение "1200;2000;320", то это говорит нам о том, что у списка 3 столбца и ширина у них равна 1200 твип для первого, 2000 и 320 твип для второго и третьего соответственно. Поскольку хотим мы того или нет, но нам придется иметь дело с числовыми ширинами столбцов. Очевидно, что нам понадобится функция, которая преобразует строку ColumnWidths в набор числовых значений. В нашем примере имеется 4 столбца, следовательно размерность массива значений будет равна 4. Массив будет единым для всего модуля класса данной формы, поэтому описываем его в области общих параметров, в самом верху модуля "Dim dx(4) As Long". Назовем нашу функцию dx_former. Сама функция будет иметь вид :
Функция особо сложных решений не содержит. Ищем точки с запятыми, все что между ними - это и есть значения. Проблема была с последним значением, после которого точка с запятой не стоит. Пришлось выискивать хвост строки после точки с запятой и находить в нем значение. Но уже когда статью писал, пришла в голову мысль, простая как двери. Если точки с запятой в конце нет, то почему бы ее туда самим не добавить. Добавили, и все стало совсем красиво. Изменять мы будем значения столбцов сначала в массиве dx, а затем формировать текстовую строку из этих значений для запоминания в свойстве ColumnWidths нашего списка. Нужна функция обратная от функции dx_former. Назовем ее c_w_former, то есть формирователь ColumnWidths. Функция достаточно простая и тянет на упражнение при изучении работы со строками. Вот ее текст:
Когда мы двигаем курсор мыши, то мы должны отследить, попадаем ли мы курсором на границу между двумя столбцами. Во время перемещения курсора над списком, для нашего списка возникает событие "перемещение указателя" и можно вызвать процедуру обработки события. В эту процедуру передаются координаты курсора внутри списка и состояние кнопок мыши, то есть нажаты они в данный момент или нет. Вся проблема на данном этапе заключается в том, что у нас есть значения ширины столбцов, но нет координат границ этих столбцов. Довольно нетрудно выполнить преобразование этих значений. Для этого создаем функцию, которая на основе данных о ширинах столбцов вернет нам координаты правой границы заданного столбца. Назовем ее dx_pos.
Функция работает на основе данных из массива dx, в качестве параметра указываем номер требуемого столбца. Теперь, зная правую границу каждого столбца, нужно проверить, попадает ли в пределы этой границы курсор мыши. Дело в том, что твип-величина очень маленькая, а руки у нас как известно иногда дрожат. Тут без допусков и посадок не обойтись. Опыт показывает, что допуск в + - 30 твип относительно границы столбца оптимальный для этих целей. Впрочем это дело вкуса, можете менять. Это первая проблема. Вторая проблема, вытекающая кстати из первой, заключается в том, что нажав на кнопку мыши для изменения границы, наш курсор не находится точно на этой границе, а в пределах допуска. В момент нажатия надо запомнить разницу между координатами курсора мыши и границей столбца, после чего в течении всего времени перемещения курсора эту разность учитывать. Для этого создаем переменную razn, которая будет хранить значение нашей погрешности. Для того, чтобы мы всегда знали для какого столбца производится перемещение, нужно иметь переменную которая хранит номер изменяемого столбца. Если никакой столбец не меняем, переменную задаем нулевой. Таким образом убиваем двух зайцев. С одной стороны знаем - находимся ли в режиме изменения ширины, а с другой - ширины какого столбца конкретно. Назовем ее sh_but, она кстати тоже должна быть общей для всего модуля. Дело в том, что событие "перемещение указателя возникает столько раз, сколько раз курсор мыши изменяет свои координаты. Пока мы перемещаем курсор, событие возникает непрерывно, получается своего рода цикл, и нам нужно в начале следующего витка помнить, ширину какого столбца мы меняем. Обнулять данную переменную нужно в двух случаях. 1. Если мы отпускаем кнопку 2. Если курсор покинул пределы списка. В результате наша процедура обработки перемещения указателя выглядит так.
Почему функция разбита на 2 куска. Казалось бы, нет ничего проще вставить код изменения ширины столбца прямо в цикл. Нарвались на нужный столбец и меняем его ширину. Я так сразу и сделал, а включил и не заработало. А почему? Потому, что зафиксировать переменную razn нам нужно только один раз в момент нажатия на кнопку мыши. Значит должна отработать некоторая триггерная защелка. Именно внутри цикла она и отрабатывает, а роль триггерной защелки выполняет наша любимая переменная sh_but. До нажатия на кнопку мыши она нулевая. Как только в зоне какого-то столбца мы нажимаем на кнопку, отрабатывает условие и мы фиксируем переменную razn и запоминаем столбец в переменной sh_but. Больше мы внутрь этого условия не попадем, пока не отпустим кнопку. Зато вторая часть процедуры отслеживает работу именно в режиме нажатой кнопки и изменяет ширину столбца согласно нашим неуверенным движениям мышью. Как только мы кнопку мыши отпустили, sh_but становится нулевой, и функция снова готова поймать нас внутрь условия, если мы нажмем кнопку в зоне изменения размера. За отпускание кнопки отвечает процедура обработки события "кнопка вверх".
Вот собственно и все. Архив с рабочим примером вы можете найти на сайте моей конторы Megakot Software http://www.megakot.com/ Загрузить программу с примером (А97) можно отсюда Просмотров: 14026
|