Как изменить компонент delphi

Очень часто, нам необходимо расширить какую-то возможность определенного компонента. Я уже не раз встречался с такой проблемой. Самым правильным способом будет создание нового компонента потомка, в котором нужно реализовать необходимые действия. Правильно, но не всегда эффективно. Сегодня мы научимся использовать компоненты не совсем так, как задумывал дядя Борман. Персональный сайт и блог программиста.

Очень часто, нам необходимо расширить какую-то возможность определенного компонента. Я уже не раз встречался с такой проблемой. Самым правильным способом будет создание нового компонента потомка, в котором нужно реализовать необходимые действия. Правильно, но не всегда эффективно. Сегодня мы научимся использовать компоненты не совсем так, как задумывал дядя Борман.

Но иногда можно и даже возникает необходимость отступить от этого правила. Например, у вас в проекте используется 100 кнопок TButton, и вдруг мы захотели наделить эти кнопки новым одинаковым свойством. Если следовать классическому методу решения проблемы, то необходимо будет сначала создать новый компонент, а потом поступить одним из двух способов:

1. Вручную изменить в dfm и pas файле предка для каждого компонента. Когда их 100 штук, процесс изменения может затянуться и будет очень утомительным;

2. Заново создать все кнопки. Старые нужно удалить и создать новые кнопки от нового компонента. Этот процесс будет проходить еще дольше, особенно если ты не используешь действия (TAction) и придется восстанавливать каждое свойство и обработчик события для кнопки.

Намного проще изменить стандартный компонент TButton и больше никаких изменений в проекте делать не надо. Для этого есть два варианта – глобальное изменение и локальное. В любом случае, изменения производятся одинаково, разница только в том, как сделать так, чтобы Delphi компилировал наш вариант нового компонента.

Изменим стандартный компонент

У нас есть возможность изменения стандартных компонентов благодаря тому, что все исходные коды компонентов входят в поставку Delphi. Самое странное, что исходных кодов я не нашел в Delphi 2005. Возможно, это связано с тем, что у меня бета версия и в полной версии исходные коды будут, потому что они действительно необходимы.

В Delphi 7 исходные коды VCL компонентов находятся в директории Delphi7/Sources/Vcl. В последнее время все большую популярность получает Delphi 2005. Тут с исходными кодами напряг :(, Borland явно пожадничал.

Объявление кнопки TButton находится в модуле StdCtrls.pas. Давайте откроем этот файл и отредактируем объект TButton. Я специально выбрал именно этот объект, потому что с ним будет проблем выше крыши при локальном компилировании :).

Итак, найдите описание компонента TButton и добавьте в раздел public новую процедуру:

procedure ShowButtonMessage(sTest:String);

Нам не нужны сложные манипуляции, главное это доказательство изменения работы стандартного компонента. Нажимаем , чтобы Delphi создал шаблон для процедуры. В этой процедуре не будем выпендриваться, а просто вызовем окно с сообщением, которое передается в качестве параметра:

procedure TButtonControl.ShowButtonMessage(sTest: String);
begin
 MessageBox(0, PChar(sTest), 'Тест', 0);
end;

Компилируй правильно

Теперь необходимо, чтобы при компиляции Delphi использовал модифицированную версию файла. Сначала рассмотрим глобальный метод. Выбери меню Tools/Environment Options. Перед нами откроется окно настроек Delphi. Переходим на закладку Library. Здесь в строке Library path показаны пути, где компилятор должен искать модули. Щелкни по кнопке с тремя точками, чтобы было удобнее смотреть и редактировать список путей в специальном окне.

Свойства проекта, закладка Library

Окно настройки директорий для поиска модулей

Обрати внимание на первую строку в окне, где находиться путь $(DELPHI)Lib. Первым делом компилятор будет искать модули в директории lib, в директории, где установлен Delphi. Если нужный dcu или pas файл в этой директории не найден, то будут просматриваться остальные директории в списке. Понятно, к чему я клоню? Если нет, читаем дальше, а дальше будет интереснее.

Наша задача добавить путь к директории с исходными кодами VCL модулей и поставить этот путь первым, чтобы компилятор использовал эту директорию. Для этого выполняем следующие действия:

1. В строку ввода под списком директорий введи путь $(DELPHI)SourceVcl;

2. Нажми кнопку Add, чтобы добавить путь;

3. Выдели только что добавленный путь, и стрелкой вверх переместите его на первую строчку;

4. Сохраняем изменения, нажатиям кнопки ОК.

Теперь можно компилировать проект.

Таким образом, мы глобально изменили настройки, и теперь все модули из директории VCL будут компилироваться. Нет, не «абсолютно» все, а те, что используются в нашем проекте. Но и это, я скажу тебе, не мало. Даже средненький проект использует не менее 20 модулей. Это не очень хорошо, ведь мы изменили только один файл StdCtrls.pas.

Локальная компиляция

Для локального подключения файла StdCtrls.pas, его необходимо скопировать в ту же директорию, где ты хранишь исходный код проекта. В этом случае, в настройках Delphi ничего изменять не надо, потому что директория проекта всегда проверяется первой. Найдя в ней файл StdCtrls.pas, директория lib проверяться не будет, поэтому компилятор использует модифицированную версию компонента TButton.

Попробуйте выполнить локальную компиляцию. Вот тут возникают проблемы. Сначала компилятор укажет на модуль Themes и скажет, что модуль Dialogs скомпилирован с другой версией TButton. В данном случае проблема решается просто. Посмотрите, модуль Themes подключен в uses раздела implementation. Если перенести подключение в uses раздела interface (в начале модуля), то ошибка исчезнет. Такой трюк работает не всегда и скорее исключение из правил. Ниже мы увидим более надежный вариант решения этой проблемы.

Снова попробуем скомпилировать программу, и снова произойдет ошибка. Ты должен увидеть сообщение, что модуль ExtCtrls скомпилирован с другой версией компонента TButton. Почему так произошло? Когда мы подключали измененный файл глобально, то абсолютно все используемые в программе модули из директории SourceVcl перекомпилировались. В данном случае, перекомпилируется только StdCtrls, где TButton модифицированный. Но мы используем в проекте еще и модуль ExtCtrls, который:

  • Берется из директории lib;
  • Использует модуль stdctrls;
  • — Скомпилирован с другой версией TButton.

Два разных компонента с одним и тем же именем не могут существовать в одном проекте. Трюк, который мы провели с модулем Themes уже не пройдет. Тут нужно другое решение. А оно лежит на самой поверхности – перекомпилировать и модуль ExtCtrls. Для этого его тоже скопируйте в директорию с исходным кодом проекта. Теперь этот модуль перекомпилируется, и тоже будет использовать модифицированный TButton.

Чтобы не было больше проблем с компиляцией, скопируйте в директорию с исходным кодом проекта файлы Dialogs.pas и Buttons.pas.

Вот таким не хитрым способом, несколько лет назад я решил одну очень большую проблему. В одной из версий Delphi (точно не помню, но кажется это был Delphi 4) в сетке StringGrid один метод работал не совсем так, как мне надо было. Я модифицировал его и подключил к программе локально.

Используй лучше локальное подключение, потому что нет гарантии, что модифицированная версия компонента понадобится во всех остальных проектах. Да и компилировать все стандартные модули из исходных кодов нет смысла, когда уже есть скомпилированные версии в директории lib.

Использование закрытых методов

Я уже не раз замечал, что разработчики Delphi иногда прячут в области private или protected очень полезные возможности компонентов. Я понимаю, что они запрещают доступ к тем свойствам и методам, неверное обращение с которыми может привести к краху программы. И все же, иногда доступ к запретному плоду просто необходим.

Как получить доступ к переменной или методу, который закрыт? Рассмотрим проблему на примере кнопки. У компонента TButton есть закрытый метод SetButtonStyle. Этот метод объявлен в секции protected. Как обмануть Delphi и получить доступ к этому методу напрямую? Если написать в программе следующий код, то во время компиляции произойдет ошибка:

Button1.SetButtonStyle(true);

У компилятора Delphi есть один недостаток (а может быть преимущество, сказать трудно). Если два объекта объявлены в одном модуле, то все их свойства и методы будут доступны друг другу. При этом не имеет значения, где объявлены эти методы и свойства, открыты они или закрыты. Такие объекты называются дружественными и чисто по братски делятся всеми своими возможностями.

Но этого мало, ведь кнопка и наш проект объявлены в разных модулях, поэтому возможность на первый взгляд бесполезная. Не торопитесь. У объектно-ориентированного программирования есть очень полезное свойство – наследование. При этом потомку может быть назначен любой предок, и код будет работать верно.

Стань другом

Давайте объединим эти две возможности и получим доступ к закрытому методу. Итак, в модуле нашей формы объявляем новый класс, который будет происходить от TButton. Объявление будет следующим (оно должно быть в разделе type):

TMyButton = class(TButton)
end;

Теперь, если в любом месте этого модуля можно использовать закрытые методы кнопки. Допустим, что у нас на форме есть кнопка Button1 типа TButton. Этот объект является предком для TMyButton, поэтому запись TMyButton(Button1) является вполне корректной. А так как класс TMyButton объявлен в этом же модуле, то мы легко можем получить доступ к его закрытым методам и свойствам. Для этого достаточно написать код:

TMyButton(Button1).SetButtonStyle(true);

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

Этот метод хорош, только если вам нужно свойство или метод из раздела protected. Все, что объявлено в разделе private не доступно потомкам, а значит, не переносится в наш модуль.

Сетка DBGrid

Очень часто меня спрашивают, как можно изменить высоту определенной колонки в компоненте TDBGrid. Да, у этого компонента нет свойства, которое отвечало бы за высоту, но среди предков TDBGrid есть объект TCustomGrid, у которого есть свойство RowHeights. Чтобы его использовать, достаточно написать следующую строку:

TCustomGrid (DBGrid).RowHeights[2]:=50;

Но тут хочется предупредить, что Borland не зря закрыло это свойство. Дело в том, что если пролистать сетку DBGrid, то возникнут серьезные проблемы с прорисовкой. В некоторых случаях закрытые свойства и методы предка действительно могут спасти, но могут и нарушить работу программы. В данном случае, мы достаточно просто изменили высоту строки, но теперь придется попотеть, чтобы данные отображались правильно.

Сетка DBGrid, в которой строки имеют разную высоту

Compile Complete

Как видишь, далеко не всегда нужно создавать нового потомка, чтобы наделить компонент новыми возможностями. Можно использовать стандартную реализацию, просто расширяя возможности.

Использование закрытых свойств и методов компонентов должно быть аккуратным. Разработчики Borland не зря закрывают методы, ведь прямой вызов некоторых из них может привести к серьезным проблемам в работе всей программы. Закрытые методы и свойства не документируются в файле помощи, поэтому сложно понять, как они используются. Но если проанализировать исходный код модуля, то можно легко понять, что, когда и как использовать.

Помни, хакерство – это образ мышления, образ жизни и постоянные исследования. Удачи в твоих дальнейших исследованиях.


Исходник Нннннада?

Тут есть еще и исходник, который можно скачать, просто кликни здесь


Внимание!!! Если ты копируешь эту статью себе на сайт, то оставляй ссылку непосредственно на эту страницу. Спасибо за понимание

In a Delphi Form, I would like to replace one visual component with another. Example: I want to replace a Panel component with an ElPanel from a 3rd party package.

I would like all identical properties and events of the first component to be transferred to the new one, and all the components that belong to the first component (e.g. Toolbars, memos,status bars, etc.) to end up placed on the new component exactly where they were on the first one.

Is there a best/easiest way to do this other than adding the new component to the form and meticulously transferring every property, event and component to it one-by-one?

asked Oct 27, 2008 at 1:15

lkessler's user avatar

I do it as following:

  1. Right click on the form and choose (View as Text).
  2. Press Ctrl + F to search for the Component class name like TPanel and replace it with TElPanel
  3. Switch back to back to the form (View as form)
  4. In the interface section replace the TPanel with TElPanel.

if you have many components using GExperts will be more feasible solutions.

answered Oct 27, 2008 at 12:53

Mohammed Nasman's user avatar

Mohammed NasmanMohammed Nasman

11k7 gold badges43 silver badges68 bronze badges

1

You can use GExperts or you can do it by hand.

To do it by hand, open the .dfm in notepad and replace all the class names. (Replace TPanel with TElPanel for example). When you’ve made all your changes, open the .pas file with Notepad, and do the same thing.

Make sure you add the required units to your uses clause.

Then open the form in the IDE and clean up any mismatched events or unknown property problems.

answered Oct 27, 2008 at 2:31

Tim Knipe's user avatar

Tim KnipeTim Knipe

9015 silver badges9 bronze badges

5

If I recall the excellent free GExperts plugin does this. Right click your form and select «Replace Components». http://www.gexperts.org

answered Oct 27, 2008 at 1:21

Osseta's user avatar

OssetaOsseta

7963 silver badges6 bronze badges

IMHO, the big drawback of the Replace component GExpert is that it changes the order of the components in the source code. That is not very VCS friendly. :-)

answered Nov 11, 2008 at 9:01

Uli Gerhardt's user avatar

Uli GerhardtUli Gerhardt

13.6k1 gold badge45 silver badges83 bronze badges

If you have other components inside a container doing this replacement with GExperts will cause some ugly exceptions and possibly unexpected behaviour in the IDE.
So, the best solution is to edit the .dfm file where you want (inside or outside the IDE) and replace manually the types of the components that you want to change. Maybe it will cause some exceptions too, but the IDE will managed them.
If you do it inside the IDE, after switching to design view if you save the .dfm inmediately the IDE will ask you to change the type of the variables related to the components you touched, liberating you to do it.

answered Oct 30, 2008 at 2:34

eKek0's user avatar

eKek0eKek0

22.8k25 gold badges91 silver badges117 bronze badges

To convert between text and binary dfm formats, use the convert.exe tool in the Delphi bin directory. – Tim Knipe (Oct 28 at 4:15)

You can also use the context menu of the form designer — at least with BDS 2006. It’s the last menu item («Text-DFM» in a German IDE).

answered Nov 11, 2008 at 9:05

Uli Gerhardt's user avatar

Uli GerhardtUli Gerhardt

13.6k1 gold badge45 silver badges83 bronze badges

In my project I had to convert few doezens forms from one set of components to another.
I have created small perl script to convert components and its properties and do all neccesary mapings.
The script is quick&dirty solution but it is highly configurable. It scanns all dfm and pas files in project direcotory and convert dfm components definitions according to rules that you should provide in ObjectBeginFound, PropertyFound, ObjectEndFound procedures/events.

DFM files should be in text mode. Tested on Delphi 5 files. I don’t know if it will be compatible with newer versions. Please send posts if you find it out.

USAGE:
perl.exe cxdfm.pl > logfile.txt

DOWNLOAD LINK
http://dl.dropbox.com/u/15887789/cxdfm.pl

answered Feb 8, 2011 at 10:32

Mao73's user avatar

Mao73Mao73

214 bronze badges

In a Delphi Form, I would like to replace one visual component with another. Example: I want to replace a Panel component with an ElPanel from a 3rd party package.

I would like all identical properties and events of the first component to be transferred to the new one, and all the components that belong to the first component (e.g. Toolbars, memos,status bars, etc.) to end up placed on the new component exactly where they were on the first one.

Is there a best/easiest way to do this other than adding the new component to the form and meticulously transferring every property, event and component to it one-by-one?

asked Oct 27, 2008 at 1:15

lkessler's user avatar

I do it as following:

  1. Right click on the form and choose (View as Text).
  2. Press Ctrl + F to search for the Component class name like TPanel and replace it with TElPanel
  3. Switch back to back to the form (View as form)
  4. In the interface section replace the TPanel with TElPanel.

if you have many components using GExperts will be more feasible solutions.

answered Oct 27, 2008 at 12:53

Mohammed Nasman's user avatar

Mohammed NasmanMohammed Nasman

11k7 gold badges43 silver badges68 bronze badges

1

You can use GExperts or you can do it by hand.

To do it by hand, open the .dfm in notepad and replace all the class names. (Replace TPanel with TElPanel for example). When you’ve made all your changes, open the .pas file with Notepad, and do the same thing.

Make sure you add the required units to your uses clause.

Then open the form in the IDE and clean up any mismatched events or unknown property problems.

answered Oct 27, 2008 at 2:31

Tim Knipe's user avatar

Tim KnipeTim Knipe

9015 silver badges9 bronze badges

5

If I recall the excellent free GExperts plugin does this. Right click your form and select «Replace Components». http://www.gexperts.org

answered Oct 27, 2008 at 1:21

Osseta's user avatar

OssetaOsseta

7963 silver badges6 bronze badges

IMHO, the big drawback of the Replace component GExpert is that it changes the order of the components in the source code. That is not very VCS friendly. :-)

answered Nov 11, 2008 at 9:01

Uli Gerhardt's user avatar

Uli GerhardtUli Gerhardt

13.6k1 gold badge45 silver badges83 bronze badges

If you have other components inside a container doing this replacement with GExperts will cause some ugly exceptions and possibly unexpected behaviour in the IDE.
So, the best solution is to edit the .dfm file where you want (inside or outside the IDE) and replace manually the types of the components that you want to change. Maybe it will cause some exceptions too, but the IDE will managed them.
If you do it inside the IDE, after switching to design view if you save the .dfm inmediately the IDE will ask you to change the type of the variables related to the components you touched, liberating you to do it.

answered Oct 30, 2008 at 2:34

eKek0's user avatar

eKek0eKek0

22.8k25 gold badges91 silver badges117 bronze badges

To convert between text and binary dfm formats, use the convert.exe tool in the Delphi bin directory. – Tim Knipe (Oct 28 at 4:15)

You can also use the context menu of the form designer — at least with BDS 2006. It’s the last menu item («Text-DFM» in a German IDE).

answered Nov 11, 2008 at 9:05

Uli Gerhardt's user avatar

Uli GerhardtUli Gerhardt

13.6k1 gold badge45 silver badges83 bronze badges

In my project I had to convert few doezens forms from one set of components to another.
I have created small perl script to convert components and its properties and do all neccesary mapings.
The script is quick&dirty solution but it is highly configurable. It scanns all dfm and pas files in project direcotory and convert dfm components definitions according to rules that you should provide in ObjectBeginFound, PropertyFound, ObjectEndFound procedures/events.

DFM files should be in text mode. Tested on Delphi 5 files. I don’t know if it will be compatible with newer versions. Please send posts if you find it out.

USAGE:
perl.exe cxdfm.pl > logfile.txt

DOWNLOAD LINK
http://dl.dropbox.com/u/15887789/cxdfm.pl

answered Feb 8, 2011 at 10:32

Mao73's user avatar

Mao73Mao73

214 bronze badges

  В этом уроке я расскажу, что такое событие, реакция на событие и мы научимся программно изменять свойство компонентов.
Создаем новый проект, на форму кидаем компонент Button с закладки Standard.
Все свойства, выделенного компонента находятся в Object Inspector на вкладке Events.
Выделяем форму и переходим к списку ее событий.

Events

Список довольно большой и по этому мы рассмотрим самые важные события.

Событие OnClick. Вы уже знакомы с этим событием из прошлых уроков и знаете, что оно происходит тогда, когда мы нажимаем на ЛКМ один раз.

Далее событие OnCreate, оно возникает тогда, когда форма только начинает создаваться. Формы еще нет на экране, а событие уже произошло.

Событие OnDblClick, это событие похоже на OnClick, только нажать на ЛКМ нужно 2 раза (двойной клик).

Событие OnKeyDown. По названию можно понять, что оно происходит, когда пользователь нажимает на клавишу клавиатуры.

Событие OnKeyUp, схоже с событием OnKeyDown, только в этом случае клавиша отпускается.

Событие OnMouseDown, оно происходит при нажатии на левую кнопку мыши, на правую и на колёсико.

Событие OnMouseUp тоже самое что и OnMouseDown, только в этом случае кнопка отпускается.

Следующие событие OnMouseMove, оно происходит тогда, когда мы двигаем мышку в зоне данного компонента.
Давайте попробуем поработать с этим свойством. Для этого нам нужно добавить компонент Label с вкладки Standard на форму и изменить его свойство Caption на 0.
Теперь выделяем компонент Button и находим там свойство OnMouseMove, щелкаем по нему 2 раза и Delphi создаст процедуру Button1MouseMove.
В этой процедуре между ключевыми словами Begin и end пишем код:

label1.Caption:=IntToStr(StrToInt(Label1.Caption)+1);

Объясняю что будет происходить. Когда мы водим мышкой по кнопке, выполняется событие OnMouseMove.
В этом событии мы присваеваем свойству Caption у лейбла значение на единицу больше чем было.
Первоначально у нас в лейбле стоит ноль, когда мы водим по кнопке, то прибавляется к нулю единица, потом дальше шевелим мышку и уже к единице прибавляется еще одна единица и так далее.
Вы наверное заметили, что в коде присутствуют функции IntToStr и ей обратная StrToInt они нужны для того, что бы складывать значения в числовом формате.

Button1MouseMove

Если бы мы их не использовали и прибавляли бы единицу в строковом виде, то получилась бы длинная цепочка из единиц.

Идем далее и следующие свойство формы, которое мы рассмотрим называется OnResize оно возникает при изменении размера формы.
Кликаем по этому событию и заполняем процедуру всё тем же кодом.

label1.Caption:=IntToStr(StrToInt(Label1.Caption)+1);

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

С рассмотрением основных событий мы закончили, теперь давайте научимся изменять свойства компонентов программно.
В событии кнопки OnClick пишем код:

form1.caption:='Programm';

Этот код изменит заголовок формы после нажатия на кнопку.
Как вы видите, сначала пишется имя компонента (в данном случае форма), далее через точку его свойство и через оператор присваивания пишется сам заголовок в кавычках, так как свойство Caption имеет строковый тип.

Далее давайте программно изменим ширину формы, кликом по кнопке.

procedure TForm1.Button1Click(Sender: TObject);
begin
form1.width:=500;
end;

Я думаю вы поняли, как программно изменять свойства компонентов. Экспериментируйте и всё получится :)

Ну вот и всё! Удачи!
Встретимся в следующем уроке!

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить композицию тела
  • Как изменить компилятор cmake
  • Как изменить компас на пдф
  • Как изменить компанию на физ лицо на авито
  • Как изменить компанию доставки на алиэкспресс

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии