В случае нажатия пользователем клавиши или изменении текущего элемента компонента ComboBox, вы обратите внимание на досадную задержку, возникающую при генерации события On.
Так как "работа кипит", я хотел бы отреагировать на изменение ItemIndex несколько позднее, например, 100 миллисекунд спустя. Вот что у меня получилось. На простой форме располагаем компоненты ComboBox и Label. Необходимым дополнением является вызов Application.ProcessMessages, позволяющий избежать замедления работы PC, когда очередь сообщений для формы пуста.
Возможно ли создание массива компонентов? Для показа статуса я использую набор LED-компонентов и хотел бы иметь к ним доступ, используя массив.
Прежде всего необходимо объявить массив:
.
.
При необходимости динамического создания LED-компонентов организуйте цикл, пример которого мы приводим ниже:
.
.
.
.
.
.
.
.
Если компоненты уже присутствуют на форме (в режиме проектирования), сделайте их элементами массива, например так:
.
.
.
.
.
.
.
.
.
.
Тем не менее у нас получился массив со случайным расположением LED-компонентов. Я предлагаю назначить свойству Tag каждого LED-компонента порядковый номер его расположения в массиве, а затем заполнить массив, используя это свойство:
.
.
.
.
.
.
.
.
Если вам нужен двухмерный массив, то для формирования индекса понадобится другая хитрость, например, хранение в свойстве Hint информации о времени создания компонентов.
Мне необходимо найти индекс компонента в родительском списке дочерних элементов управления. Я попытался модифицировать prjexp.dll, но без успеха. У кого-нибудь есть идеи?
Есть такая функция. Ищет родителя заданного компонента, перебирает список и возвращает индекс искомого компонента. Функция прошла многочисленные тесты и вполне работоспособна.
Данная проблема решается как минимум двумя путями, о чем и будет рассказано ниже.
Решение 1
Действительно, любой компонент можно создать и без (вне) формы или любого другого дочернего компонента. Для этого я использую параметр nil:
Решение 2
Я привожу некоторый код, касающийся описываемой проблемы: он работал, когда я использовал его в большом приложении. Я не знаю специфического метода создания компонента TTable вне родителей, поэтому я пошел путем создания своего класса от TTable во время инициализации модуля. Удобство такого подхода объясняется наличием под рукой всегда готового к работе экземпляра класса, стоит всего-лишь добавить модуль к вашему приложению.
Конечно, новый класс не должен иметь одиноко выглядящую процедуру со странной технологией фильтрации данных :=))), да и не помешала бы публикация нескольких событий, но этот пример призван все-го лишь продемонстрировать иной подход к решаемой задаче.
Я несколько раз видел в конференциях вопросы типа "как мне добавить элементы управления в TTabbedNotebook или TNotebook во время выполнения программы?". Теперь, когда у меня выдалось несколько свободных минут, я попытаюсь осветить этот вопрос как можно подробнее.
TTabbedNotebook
Добавление элементов управления в TTabbedNotebook во время проектирования - красивая и простая задача. Все, что Вам нужно - это установить свойство PageIndex или ActivePage на необходимую страницу и начать заполнять ее элементами управления.
Добавление элементов управление во время выполнения приложения также очень просто. Тем не менее, в прилагаемой документации по Delphi вы не найдете рецептов типа Что-и-Как. Видимо для того, чтобы окончательно запутать начинающих программистов, фирма-изготовитель даже не удосужилась включить исходный код TTabbedNotebook в VCL-библиотеку. Таким образом, TTabbedNotebook остается для некоторых тайной за семью печатями. К счастью, я имею некоторый опыт, коим и хочу поделиться.
Первым шагом к раскрытию тайны послужит просмотр файла DELPHIDOCTABNOTBK.INT, интерфейсной секции модуля TABNOTBK.PAS, в котором определен класс TTabbedNotebook. Беглый просмотр позволяет обнаружить класс TTabPage, описанный как хранилище элементов управления отдельной страницы TTabbedNotebook.
Вторым шагом в исследовании TTabbedNotebook может стать факт наличия свойством Pages типа TStrings. В связи с этим отметим, что Delphi-классы TStrings и TStringList соорганизуются с двумя свойствами: Strings и Objects. Другими словами, для каждой строки в TStrings есть указатель на соответствующий Objects. Во многих случаях этот дополнительный указатель игнорируется, нам же он очень пригодится.
После небольшого эксперимента выясняем, что свойство Objects указывает на нашу копию TTabPage и ссылается на имя страницы в свойстве Strings. Блестяще! Всегда полезно знать что ищешь. Теперь посмотрим что мы можем сделать:
TNotebook
Операция по заполнению элементами управления компонента TNotebook почти такая же, как и в TTabbedNotebook - разница лишь в типе класса - TPage вместо TTabPage. Тем не менее, если вы заглянете в DELPHIDOCEXTCTRLS.INT, декларацию класса TPage вы там не найдете. По неизвестной причине Borland не включил определение TPage и в DOC-файлы, поставляемые с Delphi. Декларация TPage в EXTCTRLS.PAS (можно найти в библиотеке VCL-исходников), правда, расположена в интерфейсной части модуля. Мы восполним пропущенную информацию о классе TPage:
Теперь, по аналогии с вышеприведенной процедурой, попробуем добавить кнопку на TNotebook. Все, что мы должны сделать - заменить "TTabbedNotebook" на "TNotebook" и "TTabPage" на "TPage". Вот что должно получиться:
У меня есть форма с расположенными на ней компонентами TreeView и Memo. Значение свойства align обоих компонентов позволяет им занимать всю форму. Я хотел бы расположить между ними движок типа Splitter, пропорционально меняющий их размеры (один шире, другой меньше и наоборот). Какой компонент мог бы симитировать поведение Splitter и как это реализовать?
Предположим, Ваш TreeView расположен в левой, а Memo в правой части формы. Вам нужно сделать следующее:
* Установите свойство Align компонента TreeView на alLeft.
* Вырежьте (Ctrl-X) компонент TMemo из вашей формы.
* Добавьте компонент Panel и присвойте его свойству Align значение alClient.
* Внутри панели разместите другой компонент Panel.
* Установите его ширину, равной 8 пикселам, свойству Align присвойте значение alLeft.
* Скопируйте вырезанный компонент TMemo в панель Panel1 и присвойте свойству Align значение alClient.
Код может быть модифицирован для получения горизонтального движка - идея, надеюсь, будет вам понятна.
Panel2 - движок: теперь вам необходимо добавить процедуры, приведенные ниже. Ваш код будет выглядеть приблизительно так:
Примечание: узнать доступные свойства компонента можно непосредственно в инспекторе объектов и (или) в текстовом режиме вашей формы (щелкните на форме правой кнопкой мыши и выберите пункт View as Text)
Иконка компонента является инкапсулированным объектом, требующим для хранения изображения некоторый участок памяти. Следовательно, при замене иконки, память, связанная с первоначальной иконкой, должна возвратиться в кучу, а для новой иконки требуется новое распределение памяти.
По правилам Delphi, этим должен заниматься метод "Assign". Ниже приведен код всей процедуры замены иконки.
Одной и наиболее сильных сторон среды программирования Delphi является ее открытая архитектура, благодаря которой Delphi допускает своего рода метапрограммирование, позволяя “программировать среду программирования”.
Такой подход переводит Delphi на качественно новый уровень систем разработки приложений и позволяет встраивать в этот продукт дополнительные инструментальные средства, поддерживающие практически все этапы создания прикладных систем.
Столь широкий спектр возможностей открывается благодаря реализованной в Delphi концепции так называемых открытых интерфейсов, являющихся связующим звеном между IDE (Integrated Development Environment) и внешними инструментами. Данная статья посвящена открытым интерфейсам Delphi и представляет собой обзор представляемых ими возможностей.
В Delphi определены шесть открытых интерфейсов: Tool Interface, Design Interface, Expert Interface, File Interface, Edit Interface и Version Control Interface. Вряд ли в рамках данной статьи нам удалось бы детально осветить и проиллюстрировать возможности каждого из них.
Более основательно разобраться в рассматриваемых вопросах вам помогут исходные тексты Delphi, благо разработчики снабдили их развернутыми комментариями. Объявления классов, представляющих открытые интерфейсы, содержатся в соответствующих модулях в каталоге ...DelphiSourceToolsAPI.
Design Interface (модуль DsgnIntf.pas) предоставляет средства для создания редакторов свойств и редакторов компонентов. Редакторы свойств и компонентов – это тема, достойная отдельного разговора, поэтому напомним лишь, что редактор свойства контролирует поведение Инспектора Объектов при попытке изменить значение соответствующего свойства, а редактор компонента активизируется при двойном нажатии левой кнопки мыши на изображении помещенного на форму компонента.
Version Control Interface (модуль VCSIntf.pas) предназначен для создания систем контроля версий. Начиная с версии 2.0, Delphi поддерживает интегрированную систему контроля версий Intersolv PVCS, поэтому в большинстве случаев в разработке собственной системы нет необходимости. По этой причине рассмотрение Version Control Interface мы также опустим.
File Interface (модуль FileIntf.pas) позволяет переопределить рабочую файловую систему IDE, что дает возможность выбора собственного способа хранения файлов (в Memo-полях на сервере БД, например).
Edit Interface (модуль EditIntf.pas) предоставляет доступ к буферу исходных текстов, что позволяет проводить анализ кода и выполнять его генерацию, определять и изменять позицию курсора в окне редактора кода, а также управлять синтаксическим выделением исходного текста.
Специальные классы предоставляют интерфейсы к помещенным на форму компонентам (определение типа компонента, получение ссылок на родительский и дочерние компоненты, доступ к свойствам, передача фокуса, удаление и т.д.), к самой форме и к ресурсному файлу проекта.
Также Edit Interface позволяет идентифицировать так называемые модульные нотификаторы, определяющие реакцию на такие события, как изменение исходного текста модуля, модификация формы, переименование компонента, сохранение, переименование или удаление модуля, изменение ресурсного файла проекта и т. д.
Tool Interface (модуль ToolIntf.pas) предоставляет разработчикам средства для получения общей информации о состоянии IDE и выполнения таких действий, как открытие, сохранение и закрытие проектов и отдельных файлов, создание модуля, получение информации о текущем проекте (число модулей и форм, их имена и т. д.), регистрация файловой системы, организация интерфейсов к отдельным модулям и т.д.
В дополнение к модульным нотификаторам Tool Interface определяет add-in нотификаторы, уведомляющие о таких событиях, как открытие/закрытие файлов и проектов, загрузка и сохранение desktop-файла проекта, добавление/исключение модулей проекта, инсталляция/деинсталляция пакетов, компиляция проекта, причем в отличие от модульных нотификаторов add-in нотификаторы позволяют отменить выполнение некоторых событий.
Кроме того, Tool Interface предоставляет средства доступа к главному меню IDE Delphi, позволяя встраивать в него дополнительные пункты.
Expert Interface (модуль ExptIntf.pas) представляет собой основу для создания экспертов — программных модулей, встраиваемых в IDE c целью расширения ее функциональности. В качестве примера эксперта можно привести входящий в Delphi Database Form Wizard, выполняющий генерацию формы для просмотра и изменения содержимого таблицы БД.
Есть ли Win32 API функция, позволяющая не только открыть НО И ЗАКРЫТЬ CD-ROM? Хотелось бы не тянуться ручками к РС, а нажать мышкой на кнопку. Компонентом TMediaPlayer пользоваться не хочу, тем более компакт он может только извлечь.
Для закрытия CD-ROM:
Для открытия CD-ROM:
Не забудьте включить MMSystem в список используемых модулей (uses).
Как через конфигурацию IDAPI получить физический каталог расположения базы данных, зная ее псевдоним? Обратите внимание на метод GetAliasParams класса TSession. Возвращенная строка будет содержать искомый путь.
Приведенный ниже код содержит функцию DuplicateComponents, позволяющую проводить клонирование любых компонентов и их потомков во время выполнения приложения. Действия ее напоминают операцию копирования/вставки (copy/paste) во время разработки приложения.
Новые компоненты при создании получают тех же родителей, владельцев (в случае применения контейнеров) и имена (естественно, несколько отличающихся), что и оригиналы. В данной функции есть вероятность багов, но я пока их не обнаружил. Ошибки и недочеты могут возникнуть из-за редко применяемых специфических методов, которые, вместе с тем, могут помочь программистам, столкнувшимися с аналогичными проблемами.
Данная функция может оказаться весьма полезной в случае наличия нескольких одинаковых областей на форме с необходимостью синхронизации изменений в течение некоторого промежутка времени. Процедура создания дубликата проста до безобразия: разместите на TPanel или на другом родительском компоненте необходимые элементы управления и сделайте: "newpanel := DuplicateComponents(designedpanel)".
Здесь я привожу примеры программ, которые я использую для копирования и удаления таблиц. Необходимые для работы модули: DB, DBTables, DbiProcs,DbiErrs, и DbiTypes.
Вам всего лишь необходимо указать каталог расположения, исходное имя таблицы, каталог назначения и имя таблицы, куда будет скопирована исходная таблица и BDE скопирует таблицу целиком со всеми индексами. Процедура удаления в качестве входных параметров использует каталог расположения и имя таблицы, при этом BDE удаляет как саму таблицу, так и все файлы, связанные с ней (индексы и т.п.).
Для тестирования данные процедуры были помещены в новое приложение и мне пришлось их немного отредактировать, чтобы удалить некоторые зависимости, которые были связаны с главной формой приложения. Теперь процедуры являются полностью автономными и могут быть помещены в отдельный модуль. (Не забудьте включить его в список используемых модулей).
Событие OncalcFields генерится ОЧЕНЬ часто и может быть необязательным и занимать большое количество времени, например, у вас есть таблица с неким вычисляемым полем, и при каждом редактировании таблицы вызывается следующий код:
Теперь, если Вы решили пройти последовательно каждую запись огромной таблицы, вы можете представить, какое количество таких событий будет сгенерировано! Они будут необязательны в случае, если вы сделаете обработку полей в отдельной процедуре.
Мой совет следующий: выключите генерацию события OnCalcFields, обработайте все поля и снова включите генерацию данного события, к примеру так:
.
.
.
.
.
.
.
.
.
.
.
Поля не вычисляются в течение времени обработки, которое может быть достаточно велико, но при наличие громоздких вычислений специфического поля (или даже нескольких полей), все вычисляется за один проход!
Данный метод позволяет исключить необязательный код и может быть использован повсюду, где применяются большие таблицы или сложный алгоритм калькуляции поля. Разница в скорости обработки таблицы довольно ощутима.
Я представляю на Ваш суд утилиту быстрого поиска по базе данных. Данная технология производит поиск по полям, преобразуя их значения в строки (все значения преобразуются в верхний регистр, включая действительные числа).
Данное решение может быть не самым быстрым, однако на поверку оно оказывается быстрее остальных, обнаруженных мною в Интернете (может вам повезет больше). Более того, представьте, что действительное значение какого-либо поля равно 4.509375354, а значение поиска равно 7, в этом случае утилита засчитает "попадание". Утилита удобна также тем, что она за один проход производит поиск более, чем в одном поле.
Это удобно, если у Вас имеются, к примеру, два поля с адресами. Это моя первая "серьезная" разработка, так как первое, с чем я столкнулся, изучая Delphi, стала необходимость включения процедуры поиска в любое приложение, работающее с базой данных. А так как поиск - вещь тоже сугубо специфическая, как и любое приложение, то мне пришлось побороть свой страх перед "крутым программированием" и попробовать написать свой поисковый механизм, удовлетворивший меня (и, надеюсь, других) своей скоростью и возможностью "мульти"-поиска по нескольким полям.
Я надеюсь, что он поможет тем программистам, кто часто сталкивается с подобными задачами. Технология довольно легка для понимания, но если у Вас возникли какие-либо вопросы, пошлите мне письмо электронной почтой, я буду рад Вам помочь. Посмотрев код, можно легко узнать поддерживаемые типы полей (добавить новые не составит проблем).