-
Компонента читает/сохраняет некоторые данные в файл, который располагается в каталоге с приложением. В RuntimeMode это элементарно: FileName:=ExtractFilePath(Applicaton.ExeName)+'Base.dat'. Но вот как компонента может узнать месторасположение файла проекта (т.е. например Project1.dpr) в DesignMode? Ну тоесть компонента проверяет, находимся ли мы сейчас в режиме Delphi-редактирования проекта и если да - то должна выяснить месторасполодения файла проекта, чтобы по нему узнать путь в котором читать/сохранять этот самый внеший файл... Вот как это выяснить?
-
Нужно использовать интерфейсы. Откройте для себя ToolsAPI IOTAProject.GetModule(Index).FileName
-
В этом направлении я и копал :) НО, как я понимаю IOTAProject это интерфейс, а где же взять объект, у которого можно вызвать методы этого интерфейса?
-
> а где же взять объект, у которого можно вызвать методы > этого интерфейса?
BorlandIDEServices ?
-
> Игорь Шевченко © (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;
-
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;
-
> Будет ли корректно, если я перечислю все открытые модули и выберу из них тот, который с расширением '.dpr'?
Нет, поскольку открыть можно несколько файлов dpr одновременно
-
> DimaBr © (14.01.10 12:29) [6] > > Будет ли корректно, если я перечислю все открытые модули > и выберу из них тот, который с расширением '.dpr'? > Нет, поскольку открыть можно несколько файлов dpr одновременно
Вот потому и спрашивал, что читал где-то, что в Delphi можно открыть одновременно несколько проектов. Правда у меня никогда не получалось: когда открываю следующий проект - текущий моментом закрывается. Получалось открыть одновременно, разве что один проект (.dpr) и кучу пакетов (.dpk)
ОК. Допустим получил я таким загадочным способом ссылку на интерфейс IOTAProject. И как теперь получить месторасположение файла проекта? При перечислении в цикле IOTAProject.GetModule(i).FileName его почему-то нет.
И что вообще подразумевается под термином ActiveProject?
-
Чего б тебе не скачать исходники GExperts - там столько всего понаписано...
-
> И как теперь получить месторасположение файла проекта?
ОК. Разобрался. Но работает не корректно :( Вот я набросал компоненту, небольшую, но вполне работоспособную для экспериментов: 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;
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 мне сильно поможет - у моей задачи немного необычная специфика: у меня не эксперт который работает с активным в данный момент проектом, а компонент который лежит на форме, которая "привязана" к проекту, путь к которому и нужно узнать...
-
> когда открываю следующий проект - текущий моментом закрывается
Откройте ProjectGroup, в нём можно открыть несколько проэктов одновременно
-
Правильно, GetCurrentProject возвращает активный проэкт. Когда вы открываете dpk-шку - октивный проэкт становится ваша bpl (откройте ProjectGroup)
-
Вы определите форму, на которой лежит компонент (Owner), далее найдите к какому из открытых проэтов принадлежит эта форма. Вот вам и будет нужный проэкт, а не активный
-
> DimaBr © (14.01.10 14:53) [12] > Вы определите форму, на которой лежит компонент (Owner), > далее найдите к какому из открытых проэтов принадлежит > эта форма. Вот вам и будет нужный проэкт, а не активный
Вот! Чувствую, что дело идёт к развязке. :) Осталось только выяснить самое последнее: как найти к какому проекту принадлежит форма?
-
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. Перебираем файлы в каждом проэкте, сравнивая с текушим файлом
-
> DimaBr © (14.01.10 16:48) [14] > 1. Получаете SouceEditor > function GetSourceEditor(Module: IOTAModule = nil): IOTASourceEditor;
А какой параметр передавать в эту функцию? Если nil, то опять же получаю имя файла активного модуля, а не того на котором лежит компонента... :(
-
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 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] > Почему бы просто не хранить путь к файлу ?
Такая мысль у меня тоже была, но у неё всё таки много недостатков. Либо этот путь будет жёстко "зашит" в exe-файле, либо нужно, например, на FormCreate проходиться по всем компонентам и заменять путь, на путь с которого запущено приложение (тогда может сложиться ситуация, что в DesignTime и RunTime будут использоваться разные файлы). Кроме того, нужно в каждом компоненте, при добавлении его на форму, прописывать один и тот же путь (что будет утомительно), либо же изобретать методы глобализации этого пути. Вобщем хочется меньше лишней ручной работы - это не только сократит время разработки, но и уменьшит вероятность ошибок. Ещё у меня была идея использовать базу данных BDE, тогда достаточно было бы на компьютере прописать алиас к базе и не думать о том, что сейчас, DesignMode или RuntimeMode. Но мне не сильно нравится BDE (уже, по возможности, стараюсь отходить от её использования) да и не хотелось, чтобы приложение требовало для своей работы кучу дополнительного установленного софта.
-
Тогда проще хранить картинки в базе
-
> DimaBr © (15.01.10 13:18) [21] > Тогда проще хранить картинки в базе
Тогда движок базы должен быть установлен на компьютере где будет запускаться приложение. Тоесть это будет дополнительным требованием для нормальной работы приложения, чего я и пытаюсь избежать.
|