Emre Acikgoz
Emre Acikgoz

Reputation: 93

Delphi installing components in their own package

I have developed two unit files (.pas) and i have 2 different components the first one is MyPCButton and second is MyPanel

MyPCButton.pas uses MyPanel.pas

The Problem is when i try to put them in seperate packages, when i install the MyPCButton component which is using MyPanel.pas, the package installs both of them in the same package, if i install the MyPanel.pas first then MyPCButton package refuses the install and says "couldn't create output file for MyPanel.bpl in the package output directory"

I have placed MyPanel in interface section and i have placed it in implementation section but i still get the same error,

What i wanna do is install them sepeerately in their own packages

MyPCButton.pas :

unit MyPCButton;

interface

uses
 Winapi.Windows,Winapi.Messages,System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls,
 Vcl.Imaging.PngImage,Vcl.Graphics,Types,cxGraphics;


type
  TMyPCButton=class (TCustomControl)
  private
    FCaption:TCaption;
    FIcon:TPngImage;
    FIconIndex:integer;
    FIconList:TcxImageList;
    FIconWidth:integer;
    FIconLeftMargin,FIconRightMargin:integer;
    FCloseIconList:TcxImageList;
    FCloseIconWidth:integer;
    FCloseIconLeftMargin,FCloseIconRightMargin:integer;
    FFont:TFont;
    FColorDefault,FColorDefaultFont:TColor;
    FColorHover,FColorHoverFont:TColor;
    FColorActive,FColorActiveFont:TColor;
    FCaptionWidth:integer;
    FMaximumCaptionWidth:integer;
    FState:Byte;
    FCurCloseIconState:integer;
    FActive: Boolean;

    FBuffer: TBitmap;
    R3:TRect;
    FOnClick,FOnCloseClick: TNotifyEvent;
    FOnActivate,FOnDeactivate:TNotifyEvent;

    FFocused:Boolean;
    FGroupNo: integer;
    procedure SetIconIndex(const Value:Integer);
    procedure SetIconList(const Value:TcxImageList);

    procedure SetCaption(const Value: TCaption);
    procedure SetCloseIconList(const Value: TcxImageList);

    procedure SetAutoSize;

    procedure WndProc(var Message: TMessage); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
    procedure SetActive(const Value: Boolean);
    procedure SwapBuffers;
    procedure CheckGroupNo;
  protected
    procedure Paint; override;
    property Canvas;
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyDown(Sender: TObject; var Key: Word;Shift: TShiftState);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function GetTotalWidth:integer;
    function GetLeftSpace:integer;
    function GetRightSpace:integer;
    procedure SetPositionInPanel;
    procedure SetActiveAfterClose;
  published
    property Caption:TCaption read FCaption write SetCaption;
    property IconIndex:integer Read FIconIndex write SetIconIndex;
    property IconList:TcxImageList Read FIconList write SetIconList;
    property CloseIconList:TcxImageList Read FCloseIconList write SetCloseIconList;
    property Active:Boolean read FActive write SetActive;
    property OnClick: TNotifyEvent read FOnClick write FOnClick;
    property OnCloseClick: TNotifyEvent read FOnCloseClick write FOnCloseClick;
    property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
    property OnDeActivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
    property GroupNo:integer read FGroupNo write FGroupNo;
    property TabStop;
    property Align;
end;

procedure Register;

implementation
uses Math,pvalues,pfunctions,MyPanel;

function IsIntInInterval(x, xmin, xmax: integer): boolean; inline;
begin
  IsIntInInterval := (xmin <= x) and (x <= xmax);
end;

function PointInRect(const Point: TPoint; const Rect: TRect): boolean; inline;
begin
  PointInRect := IsIntInInterval(Point.X, Rect.Left, Rect.Right) and
                 IsIntInInterval(Point.Y, Rect.Top, Rect.Bottom);
end;

procedure Register;
begin
  RegisterComponents('MyComponents', [TMyPCButton]);
end;

procedure TMyPCButton.CheckGroupNo;
var
i:integer;
begin
  for i:=0 to Parent.ControlCount-1 do
    begin
      if (Parent.Controls[i] is TMyPCButton) then
        begin
          if ((Parent.Controls[i] as TMyPCButton).Active) and
             ((Parent.Controls[i] as TMyPCButton).Name<>Self.Name) and
             ((Parent.Controls[i] as TMyPCButton).GroupNo=Self.GroupNo)
             then
              (Parent.Controls[i] as TMyPCButton).Active:=False;
        end;
    end;
end;

constructor TMyPCButton.Create(AOwner: TComponent);
begin
  inherited;
  if _V_RegValuesInitated=false then
    _P_RegValuesInitate;

  FFocused:=false;
  FBuffer := TBitmap.Create;
  Height:=30;
  Width:=50;

  FFont:=TFont.Create;
  FFont.Assign(R_BtnTB.VFont);
  FBuffer.Canvas.Font.Assign(FFont);

  FState:=0;
  FCurCloseIconState:=-1;
  FIconIndex:=-1;
  FIconWidth:=16;
  FIconLeftMargin:=5;
  FIconRightMargin:=5;

  FCloseIconWidth:=17;
  FCloseIconLeftMargin:=16;
  FCloseIconRightMargin:=6;
  FCaptionWidth:=0;
  FMaximumCaptionWidth:=160;

  OnKeyDown:=KeyDown;
end;

destructor TMyPCButton.Destroy;
begin
  inherited;
  FreeAndNil(FIcon);
  FreeAndNil(FBuffer);
end;

procedure TMyPCButton.DoEnter;
begin
  inherited;
  if FActive=false then
    FState:=1;
  FFocused:=true;
  paint;
end;

procedure TMyPCButton.DoExit;
begin
  inherited;
  if FActive=false then
    FState:=0
  else
    FState:=2;
  FFocused:=false;
  paint;
end;

function TMyPCButton.GetLeftSpace: integer;
begin
  Result:=Parent.Left;
end;

function TMyPCButton.GetRightSpace: integer;
begin
  Result:=GetTotalWidth-Parent.Width;
end;

function TMyPCButton.GetTotalWidth: integer;
begin
  Result:=Self.Left+Self.Width;
end;

procedure TMyPCButton.SetPositionInPanel;
var
TotalWidth,LeftSpace,RightSpace:integer;
begin
  if (Owner is TMyPanel) then
    begin
    if (Owner as TMyPanel).Parent is TMyPanel then
      begin
        LeftSpace:=GetLeftSpace;
        if LeftSpace<0 then
          LeftSpace:=LeftSpace*-1;
        RightSpace:=GetRightSpace;
        TotalWidth:=GetTotalWidth;
        if (TotalWidth-LeftSpace)<Self.Width then
          Parent.Left:=Parent.Left+(((TotalWidth-LeftSpace)-Self.Width)*-1)
        else
        if TotalWidth-LeftSpace>(Parent).Parent.Width then
          begin
            Parent.Left:=Parent.Left-(TotalWidth-LeftSpace-(Parent).Parent.Width);
          end;
      end;
    end;
end;

procedure TMyPCButton.SetActiveAfterClose;
var
VControlCount,VPosition:integer;
begin
  if (Parent is TMyPanel) then
    begin
      VControlCount:=Parent.ControlCount;
      if VControlCount>1 then
        begin
          for VPosition:=0 to VControlCount-1 do
            begin
              if (Parent.Controls[VPosition] as TMyPCButton).Name=Self.Name then
                break;
            end;
          if VPosition+1=Parent.ControlCount then
            (Parent.Controls[VPosition-1] as TMyPCButton).Active:=true
          else
            (Parent.Controls[VPosition+1] as TMyPCButton).Active:=true;
        end;
    end;
end;

procedure TMyPCButton.KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if FActive=false then
    SetActive(True);
  if (Key=13) and (Assigned(FOnClick)) then FOnClick(Self);
  paint;
end;

procedure TMyPCButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
SelfWidth:integer;
begin
  inherited;
  if (FActive=false) and PointInRect(point(X,Y),R3)=false then
    begin
      FState:=2;
      SetActive(True);
      paint;
    end;
  if PointInRect(point(X,Y),R3) then
    begin
      if (Assigned(FOnCloseClick)) then FOnCloseClick(Self);
      SelfWidth:=Self.Width;
      Width:=0;
      Parent.Width:=Parent.Width-SelfWidth;
      if FActive then
        SetActiveAfterClose;
      Self.Destroy;
    end
  else
    begin
      if (Assigned(FOnClick)) then FOnClick(Self);
    end;
end;

procedure TMyPCButton.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PointInRect(point(X,Y),R3)=false then
    begin
      if FState-1<>FCurCloseIconState then
        begin
          FCurCloseIconState:=FState-1;
          paint;
        end;
    end
  else
    begin
      if FState+1<>FCurCloseIconState then
        begin
          FCurCloseIconState:=FState+1;
          paint;
        end;
    end;
end;

procedure TMyPCButton.Paint;
var
R2,R4:TRect;
ColorBackground,ColorFont:TColor;
begin
  inherited;
  if FBuffer.Canvas.Font.Name<>R_BtnTB.VFont.Name then
    begin
      FBuffer.Canvas.Font.Name:=R_BtnTB.VFont.Name;
    end;
  if FBuffer.Canvas.Font.Size<>R_BtnTB.VFont.Size then
    begin
      FBuffer.Canvas.Font.Size:=R_BtnTB.VFont.Size;
    end;
  if FBuffer.Canvas.Font.Quality<>R_BtnTB.VFont.Quality then
    begin
      FBuffer.Canvas.Font.Quality:=R_BtnTB.VFont.Quality;
    end;

  FBuffer.SetSize(Width,Height);

  if FState=0 then
    begin
      ColorBackground:=R_BtnTB.DefaultColor;
      ColorFont:=R_BtnTB.DefaultFontColor
    end;
  if FState=1 then
    begin
      ColorBackground:=R_BtnTB.HoverColor;
      ColorFont:=R_BtnTB.HoverFontColor
    end;
  if FState=2 then
    begin
     ColorBackground:=R_BtnTB.ActiveColor;
     ColorFont:=R_BtnTB.ActiveFontColor
    end;

  FBuffer.Canvas.Brush.Color:=ColorBackground;
  FBuffer.Canvas.Font.Color:=ColorFont;
  FBuffer.Canvas.FillRect(ClientRect);

  if ((Assigned(FIconList)) and (FIconIndex>-1)) then
    begin
      FIconList.Draw(FBuffer.Canvas,FIconLeftMargin,(ClientHeight div 2)-(FIconList.Height div 2),FIconIndex);
    end;
  R2.Top:=(ClientHeight div 2)-(FBuffer.Canvas.TextHeight(FCaption) div 2);
  R2.Height:=ClientHeight;
  R2.Left:=FIconLeftMargin+FIconWidth+FIconRightMargin;
  R2.Width:=FCaptionWidth;
  DrawText(FBuffer.Canvas.Handle, PChar(FCaption), -1, R2,DT_LEFT);

  if Assigned(FCloseIconList) then
    begin
      R3.Top:=0;
      R3.Left:=ClientWidth-FCloseIconWidth;
      R3.Height:=ClientHeight;
      R3.Width:=FCloseIconWidth;
      FCloseIconList.Draw(FBuffer.Canvas,R3.Left+(FCloseIconList.Width div 2),(R3.Height div 2)-(FCloseIconList.Height div 2),FCurCloseIconState);
    end;

  if FFocused then
    begin
      R4.Top:=1;
      R4.Left:=1;
      R4.Width:=ClientWidth-2;
      R4.Height:=ClientHeight-2;
      DrawFocusRect(FBuffer.Canvas.Handle,R4);
    end;

  SwapBuffers;
end;

procedure TMyPCButton.SetActive(const Value: Boolean);
var
MyPoint:TPoint;
begin
  if FActive<>Value then
    begin
      FActive := Value;
      if FActive then
        begin
          CheckGroupNo;
          FState:=2;
          SetPositionInPanel;
          if Assigned(FOnActivate) then FOnActivate(Self);
        end
      else
        begin
          MyPoint := ScreenToClient(Mouse.CursorPos);
          if PtInRect(ClientRect, MyPoint) then
            FState:=1
          else
            FState:=0;
          if Assigned(FOnDeactivate) then FOnDeactivate(Self);
        end;
      paint;
    end;
end;

procedure TMyPCButton.SetAutoSize;
begin
  FCaptionWidth:=FBuffer.Canvas.TextWidth(FCaption);
  if FCaptionWidth>160 then
    FCaptionWidth:=FMaximumCaptionWidth;
  Width:=FIconLeftMargin+FIconWidth+FIconRightMargin+FCaptionWidth+FCloseIconLeftMargin+FCloseIconWidth-12+FCloseIconRightMargin;
end;

procedure TMyPCButton.SetCaption(const Value: TCaption);
begin
  inherited;
    FCaption := Value;
    SetAutoSize;
    paint;
end;

procedure TMyPCButton.SetCloseIconList(const Value: TcxImageList);
begin
   FCloseIconList := Value;
   paint;
end;

procedure TMyPCButton.SetIconIndex(const Value: Integer);
begin
  FIconIndex:=Value;
  paint;
end;

procedure TMyPCButton.SetIconList(const Value: TcxImageList);
begin
  FIconList:=Value;
  paint;
end;

procedure TMyPCButton.WndProc(var Message: TMessage);
begin
  inherited;
  case Message.Msg of
    CM_MOUSEENTER:
      begin
        if FActive=False then
          begin
            FState:=1;
            Paint;
          end;
      end;
    CM_MOUSELEAVE:
      begin
        if FActive=False then
          begin
            FState:=0;
            FCurCloseIconState:=-1;
            Paint;
          end
        else
          begin
            FState:=2;
            FCurCloseIconState:=-1;
            Paint;
          end;
      end;
    WM_ERASEBKGND:
      Message.Result := 1;
  end;
end;

procedure TMyPCButton.SwapBuffers;
begin
  BitBlt(Canvas.Handle, 0, 0, Width, Height, FBuffer.Canvas.Handle, 0, 0, SRCCOPY);
end;

end.

MyPanel.pas

unit MyPanel;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls;

type
  TMyPanel = class(TPanel)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MyComponents', [TMyPanel]);
end;

constructor TMyPanel.Create(AOwner: TComponent);
begin
  inherited;
end;

destructor TMyPanel.Destroy;
begin
  inherited;
end;

end.

Upvotes: 1

Views: 251

Answers (2)

Deltics
Deltics

Reputation: 23052

There is nothing particularly special about what you are trying to do but your implementation and the way you describe installing pas files into packages suggests that you are perhaps not clear on how to go about it.

First of all, it has long been considered bad practice to combine components and IDE registration in the same package.

You should implement your components in a Runtime-only Package (or packages). You then have a Design-Time Package which includes the corresponding Runtime package in it's requires list.

The Design-Time Package also contains (typically) a single unit which uses the units containing your components and implements the Register function.

You then install the Design-Time Package into the IDE, which will load the Runtime Packages as needed to register the components.

Within that overall approach, you still have a number of options for how to organise your packages.

You could have separate runtime packages for each control and separate designtime packages to install each control separately, but it sounds like you will then have a lot of dependencies between your packages which can quickly become problematic to unravel and create dependencies in the order in which you build and install your packages.

In your case since your two components have this dependency on each other, it sounds like it would make most sense to keep those components in one single runtime package and have a single designtime package to install all the components from that runtime package.

If you really wanted to you could still have separate design-time packages to install each control individually from that single runtime package, but I really don't see any advantage in doing that in your case (unless there are further complications or consideration which are not apparent from your question).

Upvotes: 2

Emre Acikgoz
Emre Acikgoz

Reputation: 93

it was my mistake

i had changed the default dcp output directory and apparently i had to add the new path in library path, so now i am able to put/install the .pas files in their own packages

Upvotes: 0

Related Questions