Я несколько раз видел в конференциях вопросы типа "как мне добавить элементы управления в 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)
Приведенный ниже код содержит функцию DuplicateComponents, позволяющую проводить клонирование любых компонентов и их потомков во время выполнения приложения. Действия ее напоминают операцию копирования/вставки (copy/paste) во время разработки приложения.
Новые компоненты при создании получают тех же родителей, владельцев (в случае применения контейнеров) и имена (естественно, несколько отличающихся), что и оригиналы. В данной функции есть вероятность багов, но я пока их не обнаружил. Ошибки и недочеты могут возникнуть из-за редко применяемых специфических методов, которые, вместе с тем, могут помочь программистам, столкнувшимися с аналогичными проблемами.
Данная функция может оказаться весьма полезной в случае наличия нескольких одинаковых областей на форме с необходимостью синхронизации изменений в течение некоторого промежутка времени. Процедура создания дубликата проста до безобразия: разместите на TPanel или на другом родительском компоненте необходимые элементы управления и сделайте: "newpanel := DuplicateComponents(designedpanel)".
Событие OncalcFields генерится ОЧЕНЬ часто и может быть необязательным и занимать большое количество времени, например, у вас есть таблица с неким вычисляемым полем, и при каждом редактировании таблицы вызывается следующий код:
Теперь, если Вы решили пройти последовательно каждую запись огромной таблицы, вы можете представить, какое количество таких событий будет сгенерировано! Они будут необязательны в случае, если вы сделаете обработку полей в отдельной процедуре.
Мой совет следующий: выключите генерацию события OnCalcFields, обработайте все поля и снова включите генерацию данного события, к примеру так:
.
.
.
.
.
.
.
.
.
.
.
Поля не вычисляются в течение времени обработки, которое может быть достаточно велико, но при наличие громоздких вычислений специфического поля (или даже нескольких полей), все вычисляется за один проход!
Данный метод позволяет исключить необязательный код и может быть использован повсюду, где применяются большие таблицы или сложный алгоритм калькуляции поля. Разница в скорости обработки таблицы довольно ощутима.
Каким способом можно производить поиск подходящих величин в момент ввода? Табличный курсор (визуально) должен перемещаться к наиболее подходящему значению при добавлении пользователем новых символов водимой величины.
Для поиска величины таблица держится открытой. Индекс должен, естественно, принадлежать полю, используемому элементом управления EditBox. В случае изменения содержимого EditBox, новое значение используется для вызова стандартной функции FindNearest таблицы TTable. Возвращаемая величина снова присваивается свойcтву Text элемента EditBox.
Я привел лишь общее решение задачи. Фактически во время изменения значения я включал таймер на период 1/3 секунды и в обработчике события OnTimer проводил операцию поиска (с выключением таймера). Это позволяло пользователю набирать без задержки нужный текст без необходимости производить поиск в расчете на вновь введенный символ (поиск проводился только при возникновении задержки в 1/3 секунды).
Вам также может понадобиться специальный обработчик нажатия клавиши backspace или добавления символа в любое место строки.
Вместо возвращения результатов элементу EditBox (который перезаписывает введенное пользователем значение), вы можете передавать результаты другому элементу управления, например компоненту ListBox. Вы также можете отобразить несколько наиболее подходящих значений, к примеру так:
Вот несколько функций для операций с двухмерными массивами. Самый простой путь для создания собственной библиотеки. Процедуры SetV и GetV позволяют читать и сохранять элементы массива VArray (его Вы можете объявить как угодно).
Например:
Самый простой путь - создать массив динамически
сделайте функцию fetch_num типа
и затем вместо myarray[2,3] напишите
Вот способ создания одно- и двухмерных динамических массивов:
У меня есть неотложная задача: в настоящее время я разрабатываю проект, где я должен проверять достоверность введенных дат с применением маски __/__/____, например 12/12/2007.
Некоторое время назад я делал простой шифратор/дешифратор дат, проверяющий достоверность даты.
Сегодня речь пойдет о том, как преобразовать иконку в растровое изображение и о том, как из растрового изображения сделать иконку. Описанные ниже методы помогут вам разобраться с реализацией данного вопроса.
Решение 1
Решение 2
Способ преобразования изображения размером 32x32 в иконку.
В этой статье будут рассмотрены некоторые функции для работы с окнами.
Функция FindWindow
Синтаксис function FindWindow(className,WindowName : PChar) : HWND;
Функция возвращает дескриптор окна, удовлетворяющий запросу (0 - если такого окна не найдено).
ClassName - Имя класса, по которому призводится поиск среди ВСЕХ окон системы.
WindowName - Заголовок окна
Один из параметров может быть равен nil, тогда поиск ведется по другому параметру.
Функция GetWindow
Синтаксис function GetWindow(Wnd : HWND; Param) : HWND
Функция возвращает дескриптор окна удовлетворяющий запросу.
Wnd - Дескриптор какого-либо начального окна
Param - Принимает одно из следующих значений-констант:
gw_Owner - Возвращается дескриптор окна-предка (0 - если нет предка).
gwHWNDFirst - Возвращает дескриптор первого окна (относительно Wnd).
gw_HWNDNext - Возвращает дескриптор следующего окна (окна перебираются без повторений, т.е. если вы не меняли параметр Wnd функции, повторно дескрипторы не возвращаются)
gw_Child - Возвращает дескриптор первого дочернего окна.
Функция GetWindowText
Синтаксис function GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer;
Функция возвращает текст окна. Для формы это будет заголовок, для кнопки - надпись на кнопке.
hWnd - Дескриптор того окна, текст которого нужно получить.
lpString - Переменная, в которую будет помещен результат
nMaxCount - Максимальная длина текста, если текст длиннее, то он обрезается.
Функция SetWindowText
Синтаксис function SetWindowText(hWnd: HWND; lpString: PChar): BOOL;
Устанавливает текст окна.
hWnd - дескриптор того окна, текст которого нужно установить
X, Y, nWidth, nHeight - Соответственно: новые координаты X,Y; новая ширина, высота.
bRepaint - Булево значение, показывающее будет ли окно перерисовано заново.
Функция IsWindowVisible
Синтаксис function IsWindowVisible(hWnd: HWND): BOOL;
Возвращает True если данное окно видимо.
hWnd - дескриптор окна.
Функция EnableWindow
Синтаксис function EnableWindow(hWnd: HWND; bEnable: BOOL): BOOL;
Устанавливает доступность окна(окно недоступно, если оно не отвечает на события мыши, клавиатуры и т.д.). Аналог в Delphi свойство Enabled компонентов. EnableWindow возвращает True, если всё прошло успешно и False в противном случае.