как корректно показать контролы из DLL
От: RWolf Россия  
Дата: 10.12.08 22:59
Оценка:
Задача — показать UI настройки плагина (dll) — TPanel с набором размещённых на ней контролов.
Решаю задачу таким образом: в dll размещена невидимая форма, на ней панель с контролами; когда нужно показать UI настройки, приложение меняет свойство Parent панели на свою форму, по завершении работы юзера с UI свойство Parent панели меняется обратно на форму в dll.
Баги:
1) контролы не получают фокус клавишей Tab;
2) при попытке передать фокус компонентам TStringGrid, TDrawGrid, TListView выдаётся ошибка "Cannot focus disabled or invisible window".
Подскажите плз, как исправить ситуацию — или же корректный способ сделать то же самое, не прибегая к размещению плагинов в пакетах.

Цитаты из кода плагина: инициализация, показ/скрытие UI, выгрузка
exports
  InitPlugin,          //вызывается при загрузке плагина
  ShutdownPlugin,      //вызывается до выгрузки DLL
  AttachConfig,        //показать панель настроек
  DetachConfig;        //скрыть панель настроек

var
  //через эту структуру плагину передаётся ссылка на экземпляр Application и Screen приложения
  SharedData:PSharedData;  
  //сохраняемые Application и Screen плагина
  AppSv:TApplication;
  ScrSv:TScreen;

//показать контрол и дочерние
procedure RecurseShowControls(ctrl: TWinControl);
var i:integer;
begin
  ctrl.Show;
  ShowWindow(ctrl.Handle, SW_SHOW);
  for i:=0 to ctrl.ControlCount-1 do
    if ctrl.Controls[i] is TWinControl then 
      RecurseShowControls(ctrl.Controls[i] as TWinControl)
end;

//показать панель настроек поверх контрола
procedure TForm1.ShowOver(ctrl: TControl);
begin
  windows.SetParent(Panel1.Handle, ctrl.Parent.Handle);
  Panel1.Left:=ctrl.Left;
  Panel1.Top :=ctrl.Top;
  Panel1.BringToFront;
  RecurseShowControls(Panel1 as TWinControl);
end;

//скрыть панель настроек
procedure TForm1.Reset;
begin
  windows.SetParent(Panel1.Handle, Handle);
  Panel1.Hide;
end;

///////////////////////////////////////////////////////////////////

procedure DLLHandler(Reason: Integer);
begin
  case Reason of
  DLL_PROCESS_DETACH: begin
    if Form1<>nil then begin
      Form1.Reset;
      FreeAndNil(Form1);
      Application:=AppSv;
      Screen:=ScrSv;
    end;
  end;
  end;//case
end;

///////////////////////////////////////////////////////////////////

procedure InitPlugin(const data:PSharedData);stdcall;
begin
  SharedData:=data;
  AppSv:=Application;
  ScrSv:=Screen;
  Application:=SharedData.app;
  Screen:=SharedData.scr;
  DLLProc:=@DLLHandler;

  Application.CreateForm(TForm1, Form1);
end;

procedure ShutdownPlugin;stdcall;
begin
  if Form1<>nil then begin
    Form1.Reset;
    FreeAndNil(Form1);
    Application:=AppSv;
    Screen:=ScrSv;
  end
end;

procedure AttachConfig(ctrl:TControl);stdcall;
begin
  Form1.ShowOver(ctrl);
end;

procedure DetachConfig;stdcall;
begin
  Form1.Reset;
end;
Re: как корректно показать контролы из DLL
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 11.12.08 08:38
Оценка:
Здравствуйте, RWolf, Вы писали:

RW>Задача — показать UI настройки плагина (dll) — TPanel с набором размещённых на ней контролов.

RW>Решаю задачу таким образом: в dll размещена невидимая форма, на ней панель с контролами; когда нужно показать UI настройки, приложение меняет свойство Parent панели на свою форму, по завершении работы юзера с UI свойство Parent панели меняется обратно на форму в dll.

А что мешает в плагине хранить обычную видимую форму,а не заниматься непонятными мынипуляциями с Parent?

Procedure OpenPluginForm(AppHandle:THandle);
var F:TFormInPlugin;
begin
  Application.Handle:=AppHandle;
  F:=TFormInPlugin.Create(Application);
  try
     if F.ShowModal=mrOK then SomeDo; //  .....
  finally F.Free; end;
end;


и форму плагина звать по кнопке на тулбаре или из меню....
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[2]: как корректно показать контролы из DLL
От: RWolf Россия  
Дата: 11.12.08 14:55
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>А что мешает в плагине хранить обычную видимую форму,а не заниматься непонятными мынипуляциями с Parent?


В моём случае UI должен быть построен примерно так: форма "Настройки", на ней слева — список плагинов, по выбору одного из них на этой же форме появляется панель настроек выбранного плагина.
Т.е. настройки плагина должны быть доступны без открытия лишних окон.
Re[3]: как корректно показать контролы из DLL
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 11.12.08 16:57
Оценка:
Здравствуйте, RWolf, Вы писали:

DM>>А что мешает в плагине хранить обычную видимую форму,а не заниматься непонятными мынипуляциями с Parent?


RW>В моём случае UI должен быть построен примерно так: форма "Настройки", на ней слева — список плагинов, по выбору одного из них на этой же форме появляется панель настроек выбранного плагина.

RW>Т.е. настройки плагина должны быть доступны без открытия лишних окон.

Ну сделай видимую форму (та которая в ДЛЛ), потом присвой ей Border=bsNone, Align=alClient и сделай DLLForm.Parent:=ConfigDialog.PanelForControls...
Примерно так.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[3]: как корректно показать контролы из DLL
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 11.12.08 17:03
Оценка: -1
Здравствуйте, RWolf, Вы писали:

DM>>А что мешает в плагине хранить обычную видимую форму,а не заниматься непонятными мынипуляциями с Parent?


RW>В моём случае UI должен быть построен примерно так: форма "Настройки", на ней слева — список плагинов, по выбору одного из них на этой же форме появляется панель настроек выбранного плагина.

RW>Т.е. настройки плагина должны быть доступны без открытия лишних окон.

Что-то подобное должно получится:

function DoOpenForm(ParentWin:HWND):HWND; stdcall;
var F: TDLLForm;
begin 
  try
    F:=TDLLForm.CreateParented(ParentWin);      
    Application.Handle:=ParentWin;         
    F.Show;
    Application.InsertComponent(F);
    Result:=F.Handle;                       
  except 
    // oops... error!
    Result:=0;
  end;
end;


Где ParentWin == ConfigDialog.PanelForPluginControls.Handle....
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[4]: как корректно показать контролы из DLL
От: RWolf Россия  
Дата: 12.12.08 16:57
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>Что-то подобное должно получится:


Собственно, получается то же самое, обе проблемы моего кода остаются и в этом варианте.
Re[5]: как корректно показать контролы из DLL
От: RWolf Россия  
Дата: 12.12.08 17:08
Оценка:
Ошибся, действительно, контролы стали отображаться правильно. Перемещение фокуса табуляцией не работает в пределах дочерней формы, впрочем, это не критично.
Re: как корректно показать контролы из DLL
От: Leonid Troyanovsky  
Дата: 14.12.08 13:39
Оценка:
Здравствуйте, RWolf, Вы писали:

RW>Задача — показать UI настройки плагина (dll) — TPanel с набором размещённых на ней контролов.


Контролы в длл — MD.
--
С уважением, LVT
Re[6]: как корректно показать контролы из DLL
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 15.12.08 09:01
Оценка:
Здравствуйте, RWolf, Вы писали:

RW>Ошибся, действительно, контролы стали отображаться правильно. Перемещение фокуса табуляцией не работает в пределах дочерней формы, впрочем, это не критично.


Попробуй сделать еще такой "финт ушами" (это действительно финт!): в обработчике TApplication.OnMessage() зови дополнительно еще процедуру, которая будет транслировать сообщение в ДЛЛ а в ДЛЛ у формы вызывай Perform() принудительно (для тех сообщений, которые до твоей формы не доходят). И хорошо бы перехватить хуком разрушение приложения, т.к. объект TApplication в ДЛЛ момент разрушения основного приложения скорее всего оставит без внимания со всеми вытекающими.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[2]: как корректно показать контролы из DLL
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 15.12.08 09:06
Оценка:
Здравствуйте, Leonid Troyanovsky, Вы писали:

RW>>Задача — показать UI настройки плагина (dll) — TPanel с набором размещённых на ней контролов.

LT>Контролы в длл — MD.

С некоторой сноровкой — вполне себя неплохо чувствуют. Пример — тот же Total Commander. Хотя более правильный вариант — это диалоги. Ну и совсем правильный — BPL, но их использование заставляет завязыватся на определенную версию Дельфи, что для плагинописателей ну никак не приемлемо.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.