2009-03-17 5 views
1

J'essaye de créer un composant comme TButtonedEdit de Delphi 2009. C'est un TEdit personnalisé qui a 2 boutons dans la gauche et la droite.Mon crash de composant (TCustomEdit descendant)

Dans ma version, j'utilise 2 objets TSpeedButton pour les boutons gauche et droit.

S'il vous plaît jeter un oeil mon code simple ci-dessous.

Il est autorisé de l'installer et je peux le voir dans la palette de composants. Mais, pour une raison inconnue, je ne peux pas enregistrer mon application. Dès que j'ai ajouté le composant et que j'ai commencé à changer des propriétés ou à écrire un événement, Delphi va immédiatement se fermer (crashé?).

Je ne sais pas ce qui ne va pas ... mais c'est mon premier composant dont je ne suis pas sûr.

Pourriez-vous s'il vous plaît savoir quels sont les problèmes?

Il semble que Delphi 7.0 rencontre des problèmes lors de l'enregistrement du fichier .dfm si j'utilise ce composant.

Lorsque j'ai ajouté ce composant à un formulaire, enregistrez-le, Delphi demandera d'enregistrer "Unit1.pas", puis immédiatement quitter.

Merci.

unit MyButtonedEdit; 

interface 

uses 
    Windows, Buttons, Classes, Controls, Forms, Graphics, Messages, StdCtrls; 

type 
    TMyCustomButtonedEdit = class(TCustomEdit) 
    private 
    FLeftButton: TSpeedButton; 
    FRightButton: TSpeedButton; 

    procedure LeftButtonClick(Sender: TObject); 
    procedure RightButtonClick(Sender: TObject); 

    function GetLeftGlyph: TBitmap; 
    function GetRightGlyph: TBitmap; 

    procedure SetLeftGlyph(const g: TBitmap); 
    procedure SetRightGlyph(const g: TBitmap); 

    protected 
    procedure CreateParams(var Params: TCreateParams); override; 
    procedure DoLeftButtonClick; virtual; abstract; 
    procedure DoRightButtonClick; virtual; abstract; 
    function GetEnabled: boolean; override; 
    procedure SetEnabled(e: boolean); override; 
    procedure WMSize(var Message: TWMSize); message WM_SIZE; 
    property LeftButton: TSpeedButton read FLeftButton write FLeftButton; 
    property RightButton: TSpeedButton read FRightButton write FRightButton; 
    property Enabled: boolean read GetEnabled write SetEnabled; 
    property LeftGlyph: TBitmap read GetLeftGlyph write SetLeftGlyph; 
    property RightGlyph: TBitmap read GetRightGlyph write SetRightGlyph; 

    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    published 
    end; 


    TMyButtonedEdit = class(TMyCustomButtonedEdit) 
    private 
    FOnLeftButtonClick: TNotifyEvent; 
    FOnRightButtonClick: TNotifyEvent; 
    protected 
    procedure DoLeftButtonClick; override; 
    procedure DoRightButtonClick; override; 
    public 
    published 
    property LeftButton; 
    property RightButton; 
    property AutoSelect; 
    property BorderStyle; 
    property Color; 
    property Ctl3d; 
    property DragCursor; 
    property DragMode; 
    property Enabled; 
    property Font; 
    property LeftGlyph; 
    property RightGlyph; 
    property HideSelection; 
    property ParentColor; 
    property ParentCtl3D; 
    property ParentFont; 
    property ParentShowHint; 
    property PopupMenu; 
    property ReadOnly; 
    property ShowHint; 
    property TabOrder; 
    property Text; 
    property Visible; 
    property OnLeftButtonClick: TNotifyEvent read FOnLeftButtonClick write FOnLeftButtonClick; 
    property OnRightButtonClick: TNotifyEvent read FOnRightButtonClick write FOnRightButtonClick;  
    property OnChange; 
    property OnClick; 
    property OnDblClick; 
    property OnDragDrop; 
    property OnDragOver; 
    property OnEndDrag; 
    property OnEnter; 
    property OnExit; 
    property OnKeyDown; 
    property OnKeyPress; 
    property OnKeyUp; 
    property OnMouseDown; 
    property OnMouseMove; 
    property OnMouseUp; 
    property OnStartDrag; 
    end; 

procedure Register; 

implementation 

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

{ TMyCustomButtonedEdit } 

constructor TMyCustomButtonedEdit.Create(AOwner: TComponent); 
begin 
    inherited; 
    ControlStyle := ControlStyle - [csSetCaption]; 

    FLeftButton := TSpeedButton.Create(self); 
    with FLeftButton do begin 
    Parent := self; 
    TabStop := false; 
    Visible := true; 
    OnClick := LeftButtonClick; 
    end; 

    FRightButton := TSpeedButton.Create(self); 
    with FRightButton do begin 
    Parent := self; 
    TabStop := false; 
    Visible := true; 
    OnClick := RightButtonClick; 
    end; 
end; 

destructor TMyCustomButtonedEdit.Destroy; 
begin 
    FLeftButton.Free; 
    FRightButton.Free; 
    inherited; 
end; 

procedure TMyCustomButtonedEdit.CreateParams(var Params: TCreateParams); 
begin 
    inherited CreateParams(Params); 
    Params.Style := Params.Style or WS_CLIPCHILDREN; 
end; 

function TMyCustomButtonedEdit.GetEnabled: boolean; 
begin 
    result := inherited Enabled; 
end; 

function TMyCustomButtonedEdit.GetLeftGlyph: TBitmap; 
begin 
    result := FLeftButton.Glyph; 
end; 

function TMyCustomButtonedEdit.GetRightGlyph: TBitmap; 
begin 
    result := FRightButton.Glyph; 
end; 

procedure TMyCustomButtonedEdit.LeftButtonClick(Sender: TObject); 
begin 
    DoLeftButtonClick; 
    SetFocus; 
end; 

procedure TMyCustomButtonedEdit.RightButtonClick(Sender: TObject); 
begin 
    DoRightButtonClick; 
    SetFocus; 
end; 

procedure TMyCustomButtonedEdit.SetEnabled(e: boolean); 
begin 
    inherited Enabled := e; 
    FLeftButton.Enabled := e; 
    FRightButton.Enabled := e; 
end; 

procedure TMyCustomButtonedEdit.SetLeftGlyph(const g: TBitmap); 
begin 
    FLeftButton.Glyph := g; 
end; 

procedure TMyCustomButtonedEdit.SetRightGlyph(const g: TBitmap); 
begin 
    FRightButton.Glyph := g; 
end; 

procedure TMyCustomButtonedEdit.WMSize(var Message: TWMSize); 
var 
    b: integer; 
begin 
    if (BorderStyle = bsSingle) and not Ctl3d then 
    b := 1 
    else 
    b := 0; 
    FLeftButton.Top := b; 
    FLeftButton.Height := ClientHeight - b * 2; 
    FLeftButton.Width := FLeftButton.Height; 
    FLeftButton.Left := b; 

    FRightButton.Top := b; 
    FRightButton.Height := ClientHeight - b * 2; 
    FRightButton.Width := FRightButton.Height; 
    FRightButton.Left := ClientWidth - FRightButton.Width - b; 
end; 

{ TMyButtonedEdit } 

procedure TMyButtonedEdit.DoLeftButtonClick; 
begin 
    inherited; 
    if Assigned(FOnLeftButtonClick) then 
    FOnLeftButtonClick(Self); 
end; 

procedure TMyButtonedEdit.DoRightButtonClick; 
begin 
    inherited; 
    if Assigned(FOnRightButtonClick) then 
    FOnRightButtonClick(Self); 
end; 

end. 

Répondre

0

Il y a longtemps que je l'ai fait tout le développement de composants, mais je crois me souvenir que le propriétaire d'un composant doit normalement être le propriétaire de parent, pas le parent lui-même, si

FLeftButton := TSpeedButton.Create(self); 

devrait être:

FLeftButton := TSpeedButton.Create(AOwner); 
+0

Non compris dans les composants composites.Ce que vous décrivez sont des composants collés à un formulaire au moment du design, ce qui est le comportement IDE de Delphi. Mais même dans les composants composites de la VCL, le composite est le propriétaire des composants enfants - en d'autres termes, le composite. –

7

Votre problème est que vous appelez pour obtenir activé. À juste titre l'erreur que vous RECEVOIR réellement avant l'accident est

Project Project1a.exe raised exception class EStackOverflow with message 
'Stack overflow'. Process stopped. Use Step or Run to continue. 

Vous avez vous-même dans une boucle infinie. Pour déboguer des composants, la meilleure chose à faire est de les créer lors de l'exécution. C'est beaucoup plus facile à déboguer que d'essayer au moment du design. Pour déboguer à l'exécution j'ai fait ceci. Lorsque j'ai créé votre contrôle, il m'a fallu beaucoup de temps pour obtenir l'erreur stackoverflow, ce qui signifie généralement une boucle infinie. Je n'ai toujours pas compris pourquoi, mais je travaille là-dessus.

Solution.

Vous ne pouvez pas hériter des propriétés (bien que vous pouvez - voir les commentaires), de sorte que votre appel

inherited Enabled; 

lui-même était en fait appellent. ce que vous devez faire est

inherited GetEnabled; 

Merci pour l'entraînement mental.

+0

Idem pour SetEnabled –

+0

En fait, vous pouvez appeler des propriétés héritées. C'est la seule façon de le faire parfois si l'accesseur est privé, non protégé. Dans ce cas, le problème est que l'accesseur est virtuel. (Heureusement, vous ne pouvez pas avoir de méthodes virtuelles privées, ou cela pourrait être un vrai gâchis ...);) –