Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.23;
Скачать: CL | DM;

Вниз

Tools API, написание эксперта   Найти похожие ветки 

 
Meson ©   (2004-12-27 17:01) [0]

Мне необходимо изменить значение свойства у компонента
(пишется эксперт для Delphi6)

  Component: IOTAComponent;



Например, установить свойство DataSet у DataSource.

Я делаю так:
var  
  CurrentForm: IOTAFormEditor;
  DataSetComponent: IOTAComponent;
  DataSourceComponent: IOTAComponent;

begin
  CurrentForm := GxOtaGetFormEditorFromModule(GxOtaGetCurrentModule);

  DataSetComponent := CurrentForm.FindComponent("MyDataSet");
  Assert(Assigned(DataSetComponent));

  DataSourceComponent := CurrentForm.FindComponent("MyDataSource");
  Assert(Assigned(DataSourceComponent));

  ComponentDataSource.SetPropByName("DataSet",
     DataSetComponent);
  // Не работает

  ComponentDataSource.SetPropByName("DataSet",
     "MyDataSet");
  // тоже не работает

А как правильно?


 
Petr V. Abramov ©   (2004-12-27 21:49) [1]

Зачем устанавливать св-во через IOTA? Ну, допустим, просто нужно.
 Что такое GxOtaGetFormEditorFromModule?


 
Meson ©   (2004-12-27 22:33) [2]

to Petr V. Abramov

Вы совершенно правы, я не дал достаточных пояснений.

1. не просто нужно. Пишется эксперт на базе GExperts
  (www.gexprts.net).

2. GxOtaGetCurrentModule - Функция, возвращающая интерфейс
  актульного модуля

3. Мой вопрос адресован к тем, кто знаком с проектом
  www.gexprts.net


 
Meson ©   (2004-12-28 00:21) [3]

Вопрос снят, спасибо


 
Юрий Зотов ©   (2004-12-28 08:22) [4]

> Meson

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

Для этой задачи вовсе не требуется использование расширений IDE типа GExperts и других, все можно сделать стандартными средствами ToolsAPI. Вот пример, перечисляющий компоненты на текущей редактируемой форме, модуле данных или фрейме.

type
 TEnumComponentProc = procedure(AComponent: TComponent);

procedure EnumComponents(Proc: TEnumComponentProc);
var
 Module: IOTAModule;
 FormEditor: IOTAFormEditor;
 Root: INTAComponent;
 i: integer;
begin
 // 1. Получаем текущий модуль
 Module := (BorlandIDEServices as IOTAModuleServices).CurrentModule;
 // 2. Если он содержит форму, модуль данных или фрейм, то
 // получаем ссылку на нее (него) и перечисляем компоненты.
 if (Module <> nil) and
    (Module.CurrentEditor.QueryInterface(IOTAFormEditor, FormEditor) = S_OK) and
    (FormEditor.GetRootComponent.QueryInterface(INTAComponent, Root) = S_OK) then
   with Root.GetComponent do
     for i := 0 to ComponentCount - 1 do
       Proc(Components[i])
end;

Как видим, для каждого компонента вызывается callback-функция. Ну а в ней уже можно хоть свойства менять, хоть что угодно еще делать, это не проблема.


 
Meson ©   (2004-12-29 16:36) [5]

> Юрий Зотов

1. Я очень расчитывал на Ваш ответ. Спасибо.

2. Уточните, пожалуйста, как нужно вызывать функцию EnumComponents.
   И в каком режиме (RunTime или Design)?

   - В RunTime это, по-моему, не имеет смысла (или я ошибаюсь?).
   Однако я попробовал так:

uses  ToolsAPI;

procedure proc(Component: TComponent);
begin
  MessageDlg(Component.Name, mtInformation, [mbOK], 0);
end;


procedure TForm1.btn1Click(Sender: TObject);
begin
  EnumComponents(proc);
end;

   Возникает AccessViolation уже при выполнении
Module := (BorlandIDEServices as IOTAModuleServices).CurrentModule;


   - В Design mode (в моем случае предполагалось именно расширение IDE)?
   Как это сделать без использования эксперта?

3. По существу моего вопроса.
   Я делаю три вещи. (Используется библиотека DOA – www.allroundautomations.com)
   - Добавляю в активную форму компонент dbSession: TOracleSession,
   - настраиваю его на нужную базу данных и
   - всем компонентам формы, имеющим свойство Session,
     устанавливаю значение Session := dbSession.

   Т.е. необходимо изменить свойство, имеющее тип Class.
   Как это делается средствами ToolsAPI?

   Я перечисляю компоненты TComponent.
   Проверяю, не является ли текущий компонент одним из тех, которые я ищу, и

case ComponentKind of
    сkOracleDataSet:
       TOracleDataSet(Comp).Session := TOracleSession(PropertyComp);

    Это решение исправно работает. Мне в нем не нравится то, что
    - приходится выходить за рамки ToolsAPI и
    - использовать перечисляемый тип (сейчас ComponentKind содержит 8 типов,
      а что будет в следующей версии библиотеки - не известно.)
    Иначе говоря – решение является не достаточно общим.


 
Юрий Зотов ©   (2004-12-29 17:29) [6]

> Meson ©   (29.12.04 16:36) [5]

> 2. Уточните, пожалуйста, как нужно вызывать функцию
> EnumComponents.

Вызывать - как Вы и вызываете, просто передав ей callback в параметре. Конечно, только в design-time (переменная BorlandIDEServices инициализируется самой IDE, а в run-time она остается nil - отсюда и Access Violation).

> 3. По существу моего вопроса.

Изменение свойства делается средствами RTTI, а не ToolsAPI. (посмотрите IsPublishedProp и SetObjectProp в модуле TypInfo). Причем делается вполне универсально, никакой собственный перечислимый тип для этого не нужен.

А ToolsAPI здесь требуется только для того, чтобы отловить добавление dbSession на форму. Как это сделать - навскидку не скажу, надо копаться в ToolsAPI. Но есть и гораздо более простой способ, без всяких ToolAPI - объявить свой класс формы, перекрыть у него Notification, поместить в пакет и наследовать рабочие формы от него. Вот в этом Notification все и делается, и даже очень просто.

procedure TMyForm.Notification(AComponent: TComponent; Operation: TOperation);

 procedure SetSession(Target, Value: TOracleSession);
 var
   P: PPropInfo;
 begin
   P := GetPropInfo(Target.ClassInfo, "Session", [tkClass]);
   if P <> nil then
     SetObjectProp(Target, P, Value, True)
 end;

var
 i: integer;
begin
 inherited;
 if Operation = opInsert then
 begin
   if AComponent is TOracleDataSet then
     for i := 0 to ComponentCount - 1 do
       SetSession(Components[i], AComponent)
   else
     for i := 0 to ComponentCount - 1 do
       if Components[i] is TOracleDataSet then
       begin
         SetSession(AComponent, Components[i]);
         Break
       end
 end
end;


 
Юрий Зотов ©   (2004-12-30 01:07) [7]

Сорри, описка вышла. Конечно же, надо так:
procedure SetSession(Target, Value: TComponent);
или так:
procedure SetSession(Target, Value: TObject);


 
Meson ©   (2005-01-02 19:14) [8]

> Юрий Зотов ©   (30.12.04 01:07) [7]

Спасибо огромное за помощь, разобрался.

Всего Вам доброго, Юрий!
Успехов в Новом году.



Страницы: 1 вся ветка

Текущий архив: 2005.10.23;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.047 c
3-1126111521
ser_
2005-09-07 20:45
2005.10.23
Число пользователей


1-1128073872
ponyol
2005-09-30 13:51
2005.10.23
програмное изменение ориентации страницы принтера


4-1124209558
Twister1222
2005-08-16 20:25
2005.10.23
Запрет на запуск


14-1128062530
Карелин Артем
2005-09-30 10:42
2005.10.23
Использование 2-х модемов при выходе в инет.


2-1127653919
Zap
2005-09-25 17:11
2005.10.23
Растягивание имаджа