2010-03-12 5 views
5

Escribo un componente que debe almacenar cierta información relativa al directorio del proyecto. Cada vez que se cambia una propiedad de mi componente, debe escribir un archivo. Entonces, ¿cómo puede un componente determinar el directorio del proyecto actual en el momento del diseño?Cómo puede un componente en designtime determinar el directorio del proyecto

Gracias de antemano

EDIT:
Quiero generar un archivo fuente delphi cada vez que se cambia una propiedad de mi componente, de manera que siempre me dan la versión más reciente cuando compilo mi código. Piense en ello como una especie de generador de código.

Por el momento establezco la ruta completa y el nombre del archivo donde se almacena la fuente, pero prefiero una ruta relativa al proyecto (o el formulario/módulo de datos que contiene mi componente) para que sea más fácil copiar el proyecto en otro desarrollador máquinas.

Respuesta

3

Gracias por los consejos. Open Tools API es el camino a seguir y es posible utilizar la API Open Tools desde un componente en un formulario en designtime.

Así que aquí está mi solución:

necesito dos unidades, una para el componente y otro para registrar el componente y el código que utilizan la API de herramientas abiertas.

Aquí viene la unidad de componentes:


unit TestLabels; 

interface 

uses 
    SysUtils, Classes, Windows, Controls, StdCtrls; 

type 
    TTestLabel = class(TLabel) 
    private 
    FTestProperty: Boolean; 
    procedure SetTestProperty(const Value: Boolean); 
    procedure Changed; 
    published 
    property TestProperty: Boolean read FTestProperty write SetTestProperty; 
    end; 

var 
    OnGetUnitPath: TFunc; 

implementation 

{ TTestLabel } 

procedure TTestLabel.Changed; 
begin 
    if not (csDesigning in ComponentState) then 
    Exit; // I only need the path at designtime 

    if csLoading in ComponentState then 
    Exit; // at this moment you retrieve the unit path which was current before 

    if not Assigned(OnGetUnitPath) then 
    Exit; 

    // only for demonstration 
    Caption := OnGetUnitPath; 
    MessageBox(0, PChar(ExtractFilePath(OnGetUnitPath)), 'Path of current unit', 0); 
end; 

procedure TTestLabel.SetTestProperty(const Value: Boolean); 
begin 
    if FTestProperty Value then 
    begin 
    FTestProperty := Value; 
    Changed; 
    end; 
end; 

end. 

Aquí es la unidad para registrar el componente y la llamada a la Herramientas API abierta:


unit TestLabelsReg; 

interface 

uses 
    SysUtils, Classes, Controls, StdCtrls, TestLabels; 

procedure register; 

implementation 

uses 
    ToolsAPI; 

function GetCurrentUnitPath: String; 
var 
    ModuleServices: IOTAModuleServices; 
    Module: IOTAModule; 
    SourceEditor: IOTASourceEditor; 
    idx: integer; 

begin 
    Result := ''; 
    SourceEditor := nil; 

    if SysUtils.Supports(BorlandIDEServices, IOTAModuleServices, 
    ModuleServices) then 
    begin 
    Module := ModuleServices.CurrentModule; 

    if System.Assigned(Module) then 
    begin 
     idx := Module.GetModuleFileCount - 1; 

     // Iterate over modules till we find a source editor or list exhausted 
     while (idx >= 0) and not SysUtils.Supports(Module.GetModuleFileEditor(idx), IOTASourceEditor, SourceEditor) do 
     System.Dec(idx); 

     // Success if list wasn't ehausted. 
     if idx >= 0 then 
     Result := ExtractFilePath(SourceEditor.FileName); 
    end; 

    end; 

end; 

procedure register; 
begin 
    RegisterComponents('Samples', [TTestLabel]); 
    TestLabels.OnGetUnitPath := GetCurrentUnitPath; 
end; 

end. 
+0

Estoy bastante seguro de que GetCurrentUnitPath no compila (al menos la expresión booleana para el ciclo while no lo hace) y el ciclo while nunca terminará. Pero la idea es interesante, así que renuncié a tu respuesta. –

+0

@Jeroen: Gracias por señalar esto. El editor stackoverflow.com recortó la línea "while not ((idx <0) o SysUtils.Supports (Module.GetModuleFileEditor (idx), IOTASourceEditor, SourceEditor) do". He ajustado la condición del while-loop para que stackoverflow.com lo muestra correcto. Por cierto, CurrentUnitPath se extrae (con modificaciones) del DUnit wizzard que viene con Delphi. –

1

No creo que pueda. Puede determinar con bastante facilidad el directorio en el que se ejecuta su EXE, pero su componente en tiempo de diseño se ejecuta como parte del IDE. Dudo que haya una forma para que el componente acceda a la información del proyecto a través del IDE.

+0

Eso no es lo que yo quiero escuchar :-) Esperaba poder acceder a la API de diseño de IDE desde mi componente. –

+1

Eche un vistazo a OTAPI, que puede acceder a la API de diseño del IDE, pero no creo que pueda mezclar la funcionalidad OTAPI con los componentes en un formulario. –

+1

@Heinz: no de su componente, como dijo Mason. Puede hacerlo desde un IDE Expert usando Open Tools API (OTAPI). –

2

Un componente no puede acceder a su ruta de origen, porque un componente se coloca en su aplicación y se ejecuta como parte de su aplicación de Delphi IDE.

Si desea tener acceso a la ruta del proyecto, o automatizar cualquier proceso dentro de IDE; tienes que escribir un experto en IDE usando la API de OpenTools, no un componente.

4

A partir de Delphi 7, los define la unidad ToolsAPI una función getActiveProject que devuelve la interfaz IOTAProject del proyecto actual.

La propiedad fileName de IOTAProject devuelve la ruta completa del archivo fuente principal del proyecto (normalmente el archivo .dpr).

Por lo tanto, en muchos casos, es posible utilizar una simple instrucción, tales como:

if csDesigning in componentState then 
    appFolderPath := extractFilePath(getActiveProject.fileName) 
else 
    appFolderPath := extractFilePath(application.exeName); 

(y no hay necesidad de utilizar dos unidades como en el ejemplo de Heinz arriba)

Cuestiones relacionadas