[Back to DELPHI SWAG index] [Back to Main SWAG index] [Original]

    I notices that the Delphi FAQ has not been updated in over a year.  Since much
    of the information needed to write Delphi components is undocumented I thought
    that maybe there should be a component writing FAQ.

    I have been going through some of my source code to get some of the tricks
    that I have had to use in writing components.  I am going through my mail to
    see what tricks people have sent me and I will attempt to give credit to those
    who have mailed me information.

    Right now this document is short but hopefully it will grow over time.  Some
    of the information enclose has never been published.  If you have
    something to contribute or suggestions then mail them to me.

    So hear goes......

    The Unofficial Delphi Component Writing FAQ

    Maintainer:     John M. Miano   miano@worldnet.att.net
    Version:        1
    Last Updated:   30-Aug-96

    ------------------------------------------------------------------------
    Table of Contents

    Section 1 - Introduction
    1.1. What is the purpose of this document?

    Section 2 - IDE
    2.1. How can I locate problems the result when my component is used in the
    IDE?
    2.2. How do I view assembly langugage the Delphi Generates?
    2.3. I can create my control at run time but it crashes at design time.  What
    is wrong?
    2.4. How can I make my control work only in design mode?

    Section 3 - Using other components within a component
    3.1. How can I add a scroll bar component to my component and have it work at
    in design mode?
    3.2. How do I create a Windows '95-style scroll bar?

    Section 4 - Bound Controls
    4.1. Where is the documentation for the TDataLink class?

    Section 5 - VCL
    5.1. How can I step through the VCL source while debugging

    Section 6 - Other Sources of Information
    6.1. Are there any books one how to write Delphi components?

    Section 7 - Persistant Objects
    7.1. How can I save a complex object containing child objects to the .DFM
    file.

    ------------------------------------------------------------------------
    Section 1 - Introductions

    1.1. What is the purpose of this document?

    The purpose of this document is to answer common or undocumented questions
    related to writing Delphi components.  This information is provided as is.
    There are no guarentee as to its correctness.  If you find error or ommissions
    sent them to the author.

    This document is rather short at the moment but hopefully it will grow over
    time.

    ------------------------------------------------------------------------
    Section 2 - IDE Problems

    2.1. How can I locate problems the result when my component is used in the
    IDE?

    The only solution to locating problems I have found it to:

    1. In Delphi go to Tools/Options then go to the "Library" page.
    Check the "Compile With Debug Info" box.
    2. Rebuild the library.
    3. Run Delphi from within Turbo Debugger.

    If you get a GPF you can use view the stack and get some idea where the
    problem is occuring.

    2.2. How do I view assembly langugage the Delphi Generates?

    From Glen Boyd

    Borland/Delphi/2.0/Debugging add a string value called EnableCPU and set
    its string value to 1.  This add the CPU window to the view menu.  The CPU
    window is
    active at run time for stepping through and stuff like that.

    2.3. I can create my control at run time but it crashes at design time.  What
    is wrong?

    1. You component must descent from TComponent

    2. Your constructory and destructor declarations must look like:

    Constructor Create (AOwner : TComponent) ; Override ;
    Destructor Destroy ; Override ;

    3  You will get an Access Violation/GPF if you component has any published
    properties that do not have a property editor defined.  These include array
    properties and properties of types you create.

    How do I make a component work only in design mode?

    The trick is to use the Register function.  This is only called in design
    mode.  You can
    use it to set a flag that your constructors can check.

    2.4. How can I make my control work only in design mode?

    The Register procedure is only called in design mode.  You can define a flag
    in your module and have your register procedure set that flag.  If that flag
    is clear in your constructor then you are not in design mode.

    ------------------------------------------------------------------------
    Section 3 - Using other components within a component

    3.1. How can I add a scroll bar component to my component and have it work at
    in design mode?

    You need to define your own scroll bar class that intercepts the
    CM_DESIGNHITTEST message.

    TMyScrollBar = class (TScrollBar)
          Procedure CMDesignHitTest (var Message : TCMDesignHitTest) ; Message
    CM_DESIGNHITTEST ;
        End ;

    Procedure TMyScrollBar.CMDesignHitTest (var Message : TCMDesignHitTest) ;
      Begin
      Message.Result := 1 ;
      End ;

    When your component creates one of these scroll bars it needs to use

    TMyScrollBar.Create (Nil)

    rather then

    TMyScrollBar.Create (Self)

    otherwise the scroll bar will display sizing handles when it is click.   This
    means you need to be sure to explicitly free the scroll bar in your
    component's destructor.

    3.2 How do I create a Windows '95-style scroll bar?

    You need to set the page size for the scroll bar.   The following code
    sequence
    illustrates this:

    Procedure SetPageSize (ScrollBar : TScrollBar ; PageSize : Integer) ;
      Var
        ScrollInfo : TScrollInfo ;
      Begin
      ScrollInfo.cbSize := Sizeof (ScrollInfo) ;
      ScrollInfo.fMask := SIF_PAGE ;
      ScrollInfo.nPage := PageSize ;
      SetScrollInfo (ScrollBar.Handle, SB_CTL, ScrollInfo, True) ;
      End ;

    To retrieve the page size use:

    Function GetpageSize (ScrollBar : TScrollBar) ;
      Var
        ScrollInfo : TScrollInfo ;
      Begin
      If HandleAllocated Then
        Begin
        ScrollInfo.cbSize := Sizeof (ScrollInfo) ;
        ScrollInfo.fMask := SIF_PAGE ;
        GetScrollInfo (ScrollBar.Handle, SB_CTL, ScrollInfo) ;
        Result := ScrollInfo.nPage ;
        End ;

    ------------------------------------------------------------------------
    Section 4 - Bound Controls

    4.1. Where is the documentation for the TDataLink class?

    As far as I can tell the only documentation for TDataLink that exists in the
    entire universe is what follows

    Properties:
    ===========

    Property:       Active : Boolean (Read Only)
    ----------------------------------------

    Returns true when the data link is connected to an active datasource.
    The ActiveChanged method is called to give notification when the state
    changes.

    Property:       ActiveRecord: (Read/Write)
    --------------------------------------

    This sets or returns the current record within the TDatalink's buffer window.
    Valid values are
    0..BufferCount - 1.  There appear to be no range checks so assigning values
    outside this range produces unpredictable results.

    Property:       BufferCount: (Read/Write)
    -------------------------------------

    The TDataLink maintains a window of records into the dataset  This property is
    the size of this window and determines the maximum number of row that can be
    view simultaneously.  For most controls you would use a BufferCount of one.
    For controls such as a data grid this value is the number of visible rows.

    Property:       DataSet: TDataSet (Read)
    ------------------------------------

    The dataset the TDataLink is attached to.  This is a shortcut to
    DataSource.DataSet.

    Property:       DataSource: TDataSource (Read/Write)
    ------------------------------------------------

    Sets or returns data source control the TDataLink is attached to.

    Property:       DataSourceFixed: Boolean (Read/WRite)
    -------------------------------------------------

    This property is used to prevent the data source for the TDataLink from being
    changed.  If this property is set to Trye then assigning a value to the
    DataSource property will result in an exception.

    Property:       Editing: Boolean (Read Only)
    ----------------------------------------

    Returns true if the datalink is in edit mode.

    Property:       ReadOnly: Boolean (read/Write)
    ------------------------------------------

    This property determines if the TDataLink is read only.  It does not appear to
    affect the attached datalink
    or dataset.  If this property is set to True the datalink will not go into
    edit mode.

    Property:       RecordCount: Integer (Read)
    ---------------------------------------

    The property returns the approximate number of records in the attached
    dataset.

    Methods:
    ========

    function Edit: Boolean;
    -----------------------

    Puts the TDatalink's attached dataset into edit mode.

    Return Value:
            True => Success
            False => Failure

    procedure UpdateRecord;
    -----------------------

    It appears that this is a function that is intended to be called by other
    parts of the data base interface and should not be called directly.  All it
    does is set a flag and call UpdateData (described below).

    Virtual Methods
    ===============

    The mechanism for having the TDataLink object communicate with a component is
    to override these procedures.

    procedure ActiveChanged
    ------------------------

    This procedure is called whenever the datasource the TDataLink is attached to
    becomes active or
    inactive.  Use the Active property to determine whether or not the link is
    active.

    procedure CheckBrowseMode
    -------------------------

    This method appears to get called before any changes take place to the
    database.

    procedure DataSetChanged;
    -------------------------

    This procedure gets called when the following events occur:

       o  Moving to the start of the dataset
       o Moving to the end of the dataset
       o Inserting or Appending to the dataset
       o Deleting a record from the dataset
       o Canceling the editing of a record
       o Updating a record

    The non-overrident action for this procedure is to call
            RecordChanged (Nil)

    procedure DataSetScrolled(Distance: Integer)
    --------------------------------------------

    This procedure is called whenever the current record in the dataset changes.
    The Distance parameter tells how far the buffer window into the dataset was
    scrolled (This seems to always be in the range -1, 0, 1).

    Use the ActiveRecord to determine which record within the buffer window is the
    current one.

    It is not possible to force a scroll of the buffer window.

    procedure FocusControl(Field: TFieldRef)
    ----------------------------------------

    This appears to get called as a result of Field.FocusControl.

    procedure EditingChanged
    -------------------------

    This procedure is called when the editing state of the TDataLink changes.  Use
    the Editing property to determine if the TDataLink is in edit mode or not.

    procedure LayoutChanged
    -----------------------

    This procedure is called when the layout of the attached dataset changes (e.g.
    column added) .

    procedure RecordChanged(Field: TField)
    --------------------------------------

    This procedure gets called when:

       o The current record is edited
       o The record's text has changed

    If the Field parameter is non-nil then the change occured to the specified
    field.

    procedure UpdateData
    --------------------

    This procedure is called immediately before a record is updated in the
    database.  You can call the Abort procedure to prevent the record from being
    updated.

    ------------------------------------------------------------------------
    Section 5 - VCL
    5.1. How can I step through the VCL source while debugging

    Copy the VCL source modules you are interested in stepping through to your
    project directory then rebuild the VCL library.  You will then be able to step
    through the VCL source modules.

    ------------------------------------------------------------------------
    Section 6 - Other Sources of Information

    6.1. Are there any books one how to write Delphi components?

    I have seen a couple out there but the only one I can recommend is

    "Developing Delphi Components" by Ray Konopka

    ------------------------------------------------------------------------
    Section 7 - Persistant Objects

    7.1. How can I save a complex object containing child objects to the .DFM
    file.

    I have tried all sorts of schemes using DefineProperties and WriteComponents
    and they all failed to work. As far as I can the only way to do this is to use
    Delphi's default mechanism to store your child objects.

    A sequence that does work for saving to a stream is:

    1. Make all of the classes whose objects you want to save descent from
    TComponent.
    2. Make all of the values you want to save published.
    3. Within your Register procedure add a call to RegisterComponents containing
    all of the classes you wish to store.
    4. Each class that owns child classes needs to overload the procedure
    GetChildren.  Within this procedure is needs to call the procedure passed as
    an argument for each child to be stored.

    Getting the objects out of the stream is a little trickier.  Your parent
    object may need to overload the GetChildOwner and GetChildParent functions.
    Otherwise Delphi will try to make the child owned by the form.

    ------------------------------------------------------------------------
    Copyright 1996 - John Miano

    Contributers

    Glen Boyd

[Back to DELPHI SWAG index] [Back to Main SWAG index] [Original]