Конференция "Компоненты" » Можно ли в DesignMode узнать местоположение файла проекта? [D6, Win2k, WinXP]
 
  • Валигози2 (13.01.10 14:51) [0]
    Компонента читает/сохраняет некоторые данные в файл, который располагается в каталоге с приложением. В RuntimeMode это элементарно: FileName:=ExtractFilePath(Applicaton.ExeName)+'Base.dat'. Но вот как компонента может узнать месторасположение файла проекта (т.е. например Project1.dpr) в DesignMode? Ну тоесть компонента проверяет, находимся ли мы сейчас в режиме Delphi-редактирования проекта и если да - то должна выяснить месторасполодения файла проекта, чтобы по нему узнать путь в котором читать/сохранять этот самый внеший файл... Вот как это выяснить?
  • DimaBr © (13.01.10 16:30) [1]
    Нужно использовать интерфейсы. Откройте для себя ToolsAPI
    IOTAProject.GetModule(Index).FileName
  • Валигози2 (13.01.10 17:16) [2]
    В этом направлении я и копал :)
    НО, как я понимаю IOTAProject это интерфейс, а где же взять объект, у которого можно вызвать методы этого интерфейса?
  • Игорь Шевченко © (14.01.10 01:27) [3]

    >  а где же взять объект, у которого можно вызвать методы
    > этого интерфейса?


    BorlandIDEServices ?
  • Валигози2 (14.01.10 10:13) [4]

    > Игорь Шевченко ©   (14.01.10 01:27) [3]
    > >  а где же взять объект, у которого можно вызвать методы
    > > этого интерфейса?
    > BorlandIDEServices ?

    Действительно - похоже, что это он и есть. Только интерфейс IOTAProject он почемуто не поддерживает, но зато поддерживает IOTAModuleServices.
    Только как теперь узнать имя проекта? Будет ли корректно, если я перечислю все открытые модули и выберу из них тот, который с расширением '.dpr'? :

    function GetProjectPath: String;
    var
     m: IOTAModuleServices;
     i: Integer;
     FileName: String;
    begin
     Result:='';
     m:=BorlandIDEServices as IOTAModuleServices;
     for i := 0 to m.ModuleCount-1  do
     begin
       FileName:=m.Modules[i].FileName;
       if LowerCase(ExtractFileExt(FileName))='.dpr' then
       begin
         Result:=ExtractFilePath(FileName);
         Break;
       end;
     end;
    end;

  • DimaBr © (14.01.10 12:27) [5]
    function OTAModuleServices: IOTAModuleServices;
    begin
     Result := BorlandIDEServices as IOTAModuleServices;
    end;

    function GetCurrentProjectGroup: IOTAProjectGroup;
    var MS: IOTAModuleServices;
       I: Integer;
    begin
     Result := nil;
     MS := OTAModuleServices;
     if not Assigned(MS) then Exit;
     for I := 0 to MS.ModuleCount - 1 do
       if Supports(MS.Modules[I],IOTAProjectGroup, Result) then Break;
    end;

    function GetCurrentProject: IOTAProject;
    var PG: IOTAProjectGroup;
    begin
     PG := GetCurrentProjectGroup;
     if Assigned(PG)
       then Result := PG.ActiveProject
       else Result := nil;
    end;

  • DimaBr © (14.01.10 12:29) [6]
    > Будет ли корректно, если я перечислю все открытые модули и выберу из них тот, который с расширением '.dpr'?

    Нет, поскольку открыть можно несколько файлов dpr одновременно
  • Валигози2 (14.01.10 13:03) [7]

    > DimaBr ©   (14.01.10 12:29) [6]
    > > Будет ли корректно, если я перечислю все открытые модули
    > и выберу из них тот, который с расширением '.dpr'?
    > Нет, поскольку открыть можно несколько файлов dpr одновременно

    Вот потому и спрашивал, что читал где-то, что в Delphi можно открыть одновременно несколько проектов. Правда у меня никогда не получалось: когда открываю следующий проект - текущий моментом закрывается. Получалось открыть одновременно, разве что один проект (.dpr) и кучу пакетов (.dpk)

    ОК. Допустим получил я таким загадочным способом ссылку на интерфейс IOTAProject. И как теперь получить месторасположение файла проекта? При перечислении в цикле IOTAProject.GetModule(i).FileName его почему-то нет.

    И что вообще подразумевается под термином ActiveProject?
  • Игорь Шевченко © (14.01.10 13:15) [8]
    Чего б тебе не скачать исходники GExperts - там столько всего понаписано...
  • Валигози2 (14.01.10 14:07) [9]

    > И как теперь получить месторасположение файла проекта?

    ОК. Разобрался. Но работает не корректно :(
    Вот я набросал компоненту, небольшую, но вполне работоспособную для экспериментов:
    type
     TMyLabel = class(TCustomLabel)
     private
       function GetPath: String;
       procedure SetPath(const Value: String);
     protected
       procedure Click; override;
     published
       property Path: String read GetPath write SetPath;
     end;

    procedure TMyLabel.Click;
    begin
     Caption:=GetPath;
     inherited;
    end;

    function TMyLabel.GetPath: String;
    var
     pr: IOTAProject;
    begin
     if csDesigning in ComponentState then
     begin
       pr:=GetCurrentProject;
       if Assigned(pr) then Result:=pr.FileName else Result:='';
     end else
     begin
       Result:=Application.ExeName;
     end;
     //Result:=ExtractFilePath(Result);
    end;

    procedure TMyLabel.SetPath(const Value: String);
    begin
    end;


    В RunTime всё элементарно: путь к приложению получаю прочитав свойство Path или просто щёлкнув по компоненте мышкой.
    В DesignTime путь к проекту можно увидеть в инспектрое объектов (в том же свойстве Path). Но вот достаточно (не закрывая проект) открыть пакет (файл с расширением .dpk) и вот уже свойство Path показывает путь к этому пакету, а ведь компонента TMyLabel так и осталась лежать на форме, а вовсе не "переехала" в пакет... :(


    > Игорь Шевченко ©   (14.01.10 13:15) [8]
    > Чего б тебе не скачать исходники GExperts - там столько
    > всего понаписано...

    Я думаю, что разбор исходников GExperts будет интересным и продолжительным занятием (у меня когдато стоял этот пакет экспертов - только экспертов там несколько десятков, представляю сколько там исходного кода...). Но я думаю вряд ли GExperts мне сильно поможет - у моей задачи немного необычная специфика: у меня не эксперт который работает с активным в данный момент проектом, а компонент который лежит на форме, которая "привязана" к проекту, путь к которому и нужно узнать...
  • DimaBr © (14.01.10 14:47) [10]

    >  когда открываю следующий проект - текущий моментом закрывается


    Откройте ProjectGroup, в нём можно открыть несколько проэктов одновременно
  • DimaBr © (14.01.10 14:49) [11]
    Правильно, GetCurrentProject возвращает активный проэкт.
    Когда вы открываете dpk-шку - октивный проэкт становится ваша bpl (откройте ProjectGroup)
  • DimaBr © (14.01.10 14:53) [12]
    Вы определите форму, на которой лежит компонент (Owner), далее найдите к какому из открытых проэтов принадлежит эта форма. Вот вам и будет нужный проэкт, а не активный
  • Валигози2 (14.01.10 16:04) [13]

    > DimaBr ©   (14.01.10 14:53) [12]
    > Вы определите форму, на которой лежит компонент (Owner),
    >  далее найдите к какому из открытых проэтов принадлежит
    > эта форма. Вот вам и будет нужный проэкт, а не активный

    Вот! Чувствую, что дело идёт к развязке. :) Осталось только выяснить самое последнее: как найти к какому проекту принадлежит форма?
  • DimaBr © (14.01.10 16:48) [14]
    1. Получаете SouceEditor
    function GetSourceEditor(Module: IOTAModule = nil): IOTASourceEditor;
    var i: integer;
    begin
     Result := nil;
     if not Assigned(Module) then Module := OTAModuleServices.CurrentModule;
     if not Assigned(Module) then Exit;
     for i := 0 to Module.GetModuleFileCount - 1 do
       if Supports(Module.GetModuleFileEditor(i), IOTASourceEditor, Result) then Break;
    end;


    2. Получаете имя файла IOTASourceEditor.FileName это имя модуля на котором лежит ваш компонент

    3. Получаем ProjectGroup
    4. Перебираем все открытые проэкты
    5. Перебираем файлы в каждом проэкте, сравнивая с текушим файлом
  • Валигози2 (14.01.10 17:49) [15]

    > DimaBr ©   (14.01.10 16:48) [14]
    > 1. Получаете SouceEditor
    > function GetSourceEditor(Module: IOTAModule = nil): IOTASourceEditor;

    А какой параметр передавать в эту функцию? Если nil, то опять же получаю имя файла активного модуля, а не того на котором лежит компонента... :(
  • DimaBr © (15.01.10 09:41) [16]

    function TMyLabel.GetPath: String;
    var F: TCustomForm;
       i, j: integer;
       MS: IOTAModuleServices;
       E: IOTAEditor;
       FE: IOTAFormEditor;
       IC: IOTAComponent;
       C: TComponent;
    begin
     Result:='';
    if csDesigning in ComponentState then begin
      F := GetParentForm(self);
      if not Assigned(F) then Exit;
      MS := OTAModuleServices;;
      if not Assigned(MS) then Exit;
      for i := 0 to MS.ModuleCount - 1 do
        for j := 0 to MS.Modules[i].GetModuleFileCount - 1 do begin
           E := MS.Modules[i].GetModuleFileEditor(j);
           if Supports(E,IOTAFormEditor, FE) then begin
             IC := FE.GetRootComponent;
             C := TComponent(IC.GetComponentHandle);
             if C = F then begin
               Result := E.FileName;
               Exit;
             end;
           end;
        end;
    end
    else begin
      Result:=Application.ExeName;
    end;
    end;

  • DimaBr © (15.01.10 10:35) [17]
    Ой, что-то я совсем зарапортовался, получил расположение файла формы.

    Думаю, что всё таки нужно получиль файл формы, поскольку одна и таже форма может принадлежать разным проэктам, и настройки для них тоже могут быть разные.
  • Валигози2 (15.01.10 11:00) [18]

    > DimaBr ©   (15.01.10 09:41) [16]
    >
    > function TMyLabel.GetPath: String;
    > var F: TCustomForm;
    ....

    Супер! Огромное Спасибо! :)
    Правда путь получается не к файлу проекта, а к файлу формы - но так наверно даже лучше. :)

    Ещё добавлю зачем мне вообще понадобилось встраивать в компонент такую особенность.
    Пишу я проект на котором количество рисунков (TImage) превышает все разумные пределы и в каждый TImage "вихнута" картинка ещё на стадии DesignMode, в результате чего не только результирующий exe-файл получается многомегабайтным но и файл dfm на стадии разработки раздувается до огромных размеров, но что самое главное при сохранении проета можно уснуть (а, в силу привычки, сохраняю я часто - нажимая Ctrl+S). Раньше мне не доводилось писать такие "особенные" проекты, поэтому пришлось изобретать. Решил сделать свой компонент наподобие TImage, но который сохранял бы своё "содержимое" не в dfm-файл (и в результате не в exe-файл), а во внешний файл (типа базы данных) лежащий в папке с проектом или приложением. Естественно с режимом RunTime никаких проблен не возникло, а вот в режиме DesignMode хотелось, чтобы компоненты отображали своё содержимое, а не чтобы в слепую.

    Может, правда, есть какое-то другое решение для такого рода приложений?
  • DimaBr © (15.01.10 11:44) [19]
    Почему бы просто не хранить путь к файлу ?
 
Конференция "Компоненты" » Можно ли в DesignMode узнать местоположение файла проекта? [D6, Win2k, WinXP]
Есть новые Нет новых   [134466   +3][b:0][p:0.002]